// Spludlow Software
// Copyright © Samuel P. Ludlow 2020 All Rights Reserved
// Distributed under the terms of the GNU General Public License version 3
// Distributed WITHOUT ANY WARRANTY; without implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE
// https://www.spludlow.co.uk/LICENCE.TXT
// The Spludlow logo is a registered trademark of Samuel P. Ludlow and may not be used without permission
// v1.14
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Data;
using System.Data.Common;
using Npgsql;
namespace Spludlow.Data
{
///
/// PostgreSQL DAL Implimentation - Fairly impliented, not tested much
///
/// http://www.npgsql.org/
/// Npgsql.dll
/// System.Threading.Tasks.Extensions.dll (refernced by Npgsql.dll should get automatically copied to bin)
///
/// C:\Program Files\PostgreSQL\9.5\data\pg_hba.conf needs configering on server to allow client access
///
///
public class DALPostgreSQL : Spludlow.Data.IDAL
{
private NpgsqlConnection Connection;
private NpgsqlTransaction Transaction = null;
private string ChangedDatabase = null;
private string CurrentDatabaseCache = null;
private string CacheKeyPrefix;
private Dictionary ConvertDataTypes;
private string QuoteOpen = "\"";
private string QuoteClose = "\"";
private List SystemDatabaseNames = new List(new string[]
{
// "sys",
});
public DALPostgreSQL()
{
}
public DALPostgreSQL(string connectionString)
{
this.Initialize(connectionString);
}
public void Initialize(string connectionString)
{
if (connectionString == null || connectionString.Length == 0)
return;
if (connectionString.StartsWith("@") == true)
connectionString = Spludlow.Config.ConnectionString(connectionString.Substring(1));
this.Connection = new NpgsqlConnection(connectionString);
this.CacheKeyPrefix = "DALPostgreSQL-Schemas-" + this.DataSource() + "-";
this.ConvertDataTypes = new Dictionary();
string[] convertLookups = new string[]
{
"bool boolean",
"int2 smallint",
"int integer",
"int4 integer",
"int8 bigint",
"decimal numeric",
"bpchar character",
"char character",
"varchar character varying",
"float4 real",
"float8 double precision",
"serial4 serial",
"serial8 bigserial",
};
foreach (string convertLookup in convertLookups)
{
string[] words = Spludlow.Text.Split(convertLookup, '\t', true, false);
this.ConvertDataTypes.Add(words[0], words[1]);
}
this.ChangeDatabase(null);
}
public string Quotes(string commandText)
{
return this.Quotes(commandText, "[", "]");
}
public string Quotes(string commandText, string replaceOpen, string replaceClose)
{
StringBuilder result = new StringBuilder(commandText);
result.Replace(replaceOpen, this.QuoteOpen);
result.Replace(replaceClose, this.QuoteClose);
return result.ToString();
}
public static string MakeConnectionString(string host, string database, string userName, string password)
{
string[] names = new string[] { "Server", "Database", "User Id", "Password" };
string[] values = new string[] { host, database, userName, password };
StringBuilder connectionString = new StringBuilder();
for (int index = 0; index < values.Length; ++index)
{
string value = values[index];
if (value == null)
continue;
connectionString.Append(names[index]);
connectionString.Append("='");
connectionString.Append(value);
connectionString.Append("';");
}
if (userName == null)
connectionString.Append("Integrated Security=true;");
return connectionString.ToString();
}
private void Open()
{
this.Connection.Open();
if (this.ChangedDatabase != null)
{
try
{
string database = this.ChangedDatabase;
if (database == "")
database = "postgres";
this.Connection.ChangeDatabase(database);
}
catch
{
this.Connection.Close();
throw;
}
}
}
private void Close()
{
this.Connection.Close();
}
public string DataSource()
{
return this.Connection.DataSource;
}
public void CommandTimeout(int minutes)
{
}
//
// Current
//
public string CurrentDatabase()
{
return this.CurrentDatabaseCache;
}
public void ChangeDatabase(string databaseName)
{
this.ChangedDatabase = databaseName;
object result = this.ExecuteScalar("SELECT current_database();");
if (result == null || result is DBNull)
databaseName = null;
else
databaseName = (string)result;
if (databaseName == "postgres")
databaseName = null;
this.CurrentDatabaseCache = databaseName;
}
//
// Transactions
//
public void Begin()
{
if (this.Transaction != null)
throw new ApplicationException("DAL PostgreSQL: Begin Transaction already present.");
this.Open();
try
{
this.Transaction = this.Connection.BeginTransaction();
}
catch
{
this.Close();
throw;
}
}
public void Commit()
{
if (this.Transaction == null)
throw new ApplicationException("DAL PostgreSQL: Commit Transaction not present.");
try
{
this.Transaction.Commit();
this.Transaction = null;
}
finally
{
this.Close();
}
}
public void Rollback()
{
if (this.Transaction == null)
throw new ApplicationException("DAL PostgreSQL: Rollback Transaction not present.");
try
{
this.Transaction.Rollback();
this.Transaction = null;
}
finally
{
this.Close();
}
}
//
// Schema
//
//public static void ReportDataTypes()
//{
// List list = new List();
// foreach (string name in Enum.GetNames(typeof(NpgsqlTypes.NpgsqlDbType)))
// list.Add(name);
// Spludlow.Log.Report("ReportDataTypes", list.ToArray());
//}
public DataSet Schema()
{
string databaseName = this.CurrentDatabase();
if (databaseName == null)
throw new ApplicationException("DAL MySql; To get the schema you must have a current database");
string key = this.CacheKeyPrefix + databaseName;
DataSet schema = (DataSet)Spludlow.Caching.Get(key);
if (schema != null)
return schema;
schema = new DataSet();
DataSet schemaReader = this.SchemaReader();
DataSet schemaNative = this.SchemaNative();
DataSet schemaConnection = this.SchemaConnection();
DataSet schemaANSI = this.SchemaANSI();
foreach (string tableName in this.TableList())
{
this.SchemaColumns(schema, tableName, schemaReader, schemaNative, schemaConnection);
this.SchemaKeys(schema, tableName, schemaReader, schemaNative, schemaConnection, schemaANSI);
}
Spludlow.Caching.Set(key, schema);
return schema;
}
public DataSet Schema(string tableName)
{
return this.Schema(new string[] { tableName });
}
public DataSet Schema(string[] tableNames)
{
DataSet fullSchema = this.Schema();
DataSet partSchema = new DataSet();
foreach (string tableName in tableNames)
{
foreach (string suffix in new string[] { "_Columns", "_Keys" })
partSchema.Tables.Add(fullSchema.Tables[tableName + suffix].Copy());
}
return partSchema;
}
private void SchemaColumns(DataSet schema, string tableName, DataSet schemaReader, DataSet schemaNative, DataSet schemaConnection)
{
SysTables.SchemaColumnsDataTable schemaTable = Spludlow.Data.Schemas.NewSchemaColumnsTable(tableName);
foreach (DataRow readerRow in schemaReader.Tables[tableName].Rows)
{
string columnName = (string)readerRow["ColumnName"];
int columnSize = (int)readerRow["ColumnSize"];
DataRow connectionRow = schemaConnection.Tables["Columns"].Rows.Find(new object[] { tableName, columnName });
if (connectionRow == null)
throw new ApplicationException("DAL PostgrSQL Schema; Can not find Connection Schema row for column: " + tableName + "." + columnName);
string nativeDataType = (string)connectionRow["data_type"];
if (this.ConvertDataTypes.ContainsKey(nativeDataType) == true)
nativeDataType = this.ConvertDataTypes[nativeDataType];
//if (typeName == "tinyint" && columnSize == 1)
// typeName += "(1)";
//string columnType = (string)nativeRow["COLUMN_TYPE"];
//if (columnType.Contains("unsigned") == true)
// typeName += " unsigned";
SysTables.SchemaColumnsRow schemaRow = schemaTable.NewSchemaColumnsRow();
schemaRow.ColumnName = columnName;
schemaRow.Ordinal = (int)readerRow["ColumnOrdinal"];
schemaRow.DataTypeId = Spludlow.Data.Schemas.NativeToCommon(nativeDataType, "PostgreSQL");
schemaRow.MaxLength = columnSize;
schemaRow.Precision = (int)readerRow["NumericPrecision"];
schemaRow.Scale = (int)readerRow["NumericScale"];
schemaRow.PrimaryKey = (bool)readerRow["IsKey"];
schemaRow.AllowDBNull = (bool)readerRow["AllowDBNull"];
schemaRow.AutoIncrement = (bool)readerRow["IsAutoIncrement"];
schemaRow.Longest = 0;
schemaTable.Rows.Add(schemaRow);
}
Spludlow.Data.Schemas.TidySchemaTable(schemaTable);
schema.Tables.Add(schemaTable);
}
private void SchemaKeys(DataSet schema, string tableName, DataSet schemaReader, DataSet schemaNative, DataSet schemaConnection, DataSet schemaANSI)
{
SysTables.SchemaKeysDataTable keysTable = Spludlow.Data.Schemas.NewSchemaKeysTable(tableName);
DataRow[] rows;
//// DESC ?
// PK
rows = schemaANSI.Tables["table_constraints"].Select("constraint_schema = 'public' AND constraint_type = 'PRIMARY KEY' AND table_name = '" + tableName + "'");
if (rows.Length > 1)
throw new ApplicationException("DAL PostgreSQL Schema Keys; More than one PK for table:" + tableName);
if (rows.Length == 1)
{
string keyName = (string)rows[0]["constraint_name"];
rows = schemaANSI.Tables["key_column_usage"].Select("constraint_schema = 'public' AND constraint_name = '" + keyName + "' AND table_name = '" + tableName + "'", "ordinal_position");
if (rows.Length == 0)
throw new ApplicationException("DAL PostgreSQL Schema Keys; Nothing in key_column_usage on PK for table:" + tableName + ", keyname:" + keyName);
foreach (DataRow row in rows)
{
string columnName = (string)row["column_name"];
int ordinal = (int)row["ordinal_position"];
keysTable.Rows.Add(new object[] { keyName, "P", ordinal, false, columnName, null, null });
}
}
// Indexes
// Get Table Id
rows = schemaNative.Tables["pg_class"].Select("relname = '" + tableName + "' AND relkind = 'r'");
if (rows.Length != 1)
throw new ApplicationException("DAL PostgreSQL Schema Keys; Did not find one row in pg_class for table:" + tableName);
uint tableId = (uint)rows[0]["oid"];
// Indexes for table
foreach (DataRow indexRow in schemaNative.Tables["pg_index"].Select("indrelid = " + tableId))
{
if ((bool)indexRow["indisprimary"] == true) // Already have from above
continue;
string keyType = "I";
if ((bool)indexRow["indisunique"] == true)
keyType = "U";
uint indexId = (uint)indexRow["indexrelid"];
// Get Index name
rows = schemaNative.Tables["pg_class"].Select("oid = " + indexId + " AND relkind = 'i'");
if (rows.Length != 1)
throw new ApplicationException("DAL PostgreSQL Schema Keys; Did not find one row in pg_class for index:" + tableName + ", indexId:" + indexId);
string indexName = (string)rows[0]["relname"];
// Index Columns
foreach (DataRow indexColumnRow in schemaNative.Tables["pg_attribute"].Select("attrelid = " + indexId, "attnum"))
{
string columnName = (string)indexColumnRow["attname"];
int ordinal = (Int16)indexColumnRow["attnum"];
keysTable.Rows.Add(new object[] { indexName, keyType, ordinal, false, columnName, null, null });
}
}
// FKs
foreach (DataRow keyRow in schemaANSI.Tables["table_constraints"].Select("constraint_schema = 'public' AND constraint_type = 'FOREIGN KEY' AND table_name = '" + tableName + "'"))
{
// Key Name
string keyName = (string)keyRow["constraint_name"];
// Parent PK Name
rows = schemaANSI.Tables["referential_constraints"].Select("constraint_schema = 'public' AND constraint_name = '" + keyName + "'");
if (rows.Length != 1)
throw new ApplicationException("DAL PostgreSQL Schema Keys; Did not find 1 row in referential_constraints on FK for table:" + tableName + ", keyname:" + keyName + ", rows:" + rows.Length);
string parentPrimaryKeyName = (string)rows[0]["unique_constraint_name"];
// Key Columns
DataRow[] keyColmnRows = schemaANSI.Tables["key_column_usage"].Select("constraint_schema = 'public' AND constraint_name = '" + keyName + "' AND table_name = '" + tableName + "'", "ordinal_position");
if (keyColmnRows.Length == 0)
throw new ApplicationException("DAL PostgreSQL Schema Keys; Nothing in key_column_usage on FK for table:" + tableName + ", keyname:" + keyName);
foreach (DataRow keyColumnRow in keyColmnRows)
{
string columnName = (string)keyColumnRow["column_name"];
int ordinal = (int)keyColumnRow["ordinal_position"];
// Parent PK Column rows
DataRow[] parentPrimaryKeyRows = schemaANSI.Tables["key_column_usage"].Select("constraint_schema = 'public' AND constraint_name = '" + parentPrimaryKeyName + "' AND ordinal_position = " + ordinal); // dup key names accross tables?
if (parentPrimaryKeyRows.Length != 1)
throw new ApplicationException("DAL PostgreSQL Schema Keys; Din not find one parent PK column for FK for table:" + tableName + ", keyname:" + keyName + ", ParentPK: " + parentPrimaryKeyName + ", rows:" + parentPrimaryKeyRows.Length);
string parentTableName = (string)parentPrimaryKeyRows[0]["table_name"];
string parentColumnName = (string)parentPrimaryKeyRows[0]["column_name"];
keysTable.Rows.Add(new object[] { keyName, "F", ordinal, false, columnName, parentTableName, parentColumnName });
}
}
schema.Tables.Add(keysTable);
}
public DataSet SchemaNative()
{
string databaseName = this.CurrentDatabase();
if (databaseName == null)
throw new ApplicationException("DAL PostgreSQL; To get the Native schema you must have a current database");
DataSet dataSet = new DataSet();
string[] names = new string[]
{
"pg_attribute",
"pg_class",
"pg_index",
"pg_namespace",
"pg_indexes",
"pg_tables",
};
foreach (string name in names)
{
string selectColumns = "*";
if (name == "pg_attribute")
selectColumns = "attrelid, attname, atttypid, attstattarget, attlen, attnum, attndims, attcacheoff, atttypmod, attbyval, attstorage, attalign, attnotnull, atthasdef, attisdropped, attislocal, attinhcount, attcollation, attoptions, attfdwoptions";
if (name == "pg_class")
selectColumns = "oid, relname, relnamespace, reltype, reloftype, relowner, relam, relfilenode, reltablespace, relpages, reltuples, relallvisible, reltoastrelid, relhasindex, relisshared, relpersistence, relkind, relnatts, relchecks, relhasoids, relhaspkey, relhasrules, relhastriggers, relhassubclass, relrowsecurity, relforcerowsecurity, relispopulated, relreplident, relfrozenxid, relminmxid, reloptions";
if (name == "pg_namespace")
selectColumns = "oid, nspname, nspowner";
DataTable table = this.Select("SELECT " + selectColumns + " FROM pg_catalog." + name);
List columnNames = new List();
foreach (DataColumn column in table.Columns)
{
if (column.DataType.IsArray == true || column.DataType == typeof(Array))
columnNames.Add(column.ColumnName);
}
foreach (string columnName in columnNames)
table.Columns.Remove(table.Columns[columnName]);
table.TableName = name;
dataSet.Tables.Add(table);
}
DataRow[] rows;
rows = dataSet.Tables["pg_namespace"].Select("nspname = 'public'");
if (rows.Length != 1)
throw new ApplicationException("DAL PostgreSQL; Can not find publicNamespaceId in native Schema");
uint publicNamespaceId = (uint)rows[0]["oid"];
// Remove classes not in public namespace
rows = dataSet.Tables["pg_class"].Select("relnamespace <> " + publicNamespaceId);
foreach (DataRow row in rows)
row.Delete();
dataSet.Tables["pg_class"].AcceptChanges();
// Remove attributes not in classes
List classIds = new List();
foreach (DataRow row in dataSet.Tables["pg_class"].Rows)
classIds.Add((uint)row["oid"]);
List deleteList = new List();
foreach (DataRow row in dataSet.Tables["pg_attribute"].Rows)
{
uint attrelid = (uint)row["attrelid"];
if (classIds.Contains(attrelid) == false)
row.Delete();
}
dataSet.Tables["pg_attribute"].AcceptChanges();
return dataSet;
}
public DataSet SchemaReader()
{
string[] tableNames = this.TableList();
DataSet schema;
if (this.Transaction == null)
this.Open();
try
{
schema = Spludlow.Data.DALCommon.SchemaReader(this.Connection, this.Transaction, tableNames, this.QuoteOpen, this.QuoteClose);
}
finally
{
if (this.Transaction == null)
this.Close();
}
return schema;
}
public DataSet SchemaConnection()
{
string databaseName = this.CurrentDatabase();
if (databaseName == null)
throw new ApplicationException("DAL PostgreSQL; To get the Standard schema you must have a current database");
DataSet schema;
if (this.Transaction == null)
this.Open();
try
{
schema = Spludlow.Data.DALCommon.SchemaConnection(this.Connection, "Schema", "public");
}
finally
{
if (this.Transaction == null)
this.Close();
}
DataTable table;
table = schema.Tables["Columns"];
table.PrimaryKey = new DataColumn[] { table.Columns["table_name"], table.Columns["column_name"] };
return schema;
}
public void SchemaRefresh()
{
string databaseName = this.CurrentDatabase();
if (databaseName == null)
throw new ApplicationException("DAL PostgreSQL; To Refresh the schema you must have a current database");
string key = this.CacheKeyPrefix + databaseName;
Spludlow.Caching.Remove(key);
}
public DataSet SchemaANSI()
{
string[] viewNames = new string[]
{
"columns",
"constraint_column_usage",
"constraint_table_usage",
"key_column_usage",
"schemata",
"referential_constraints",
"table_constraints",
"tables",
};
DataSet dataSet = new DataSet();
foreach (string viewName in viewNames)
{
DataTable table = this.Select("SELECT * FROM INFORMATION_SCHEMA." + viewName);
table.TableName = viewName;
dataSet.Tables.Add(table);
}
return dataSet;
}
//
// Databases
//
public string[] DatabaseList()
{
DataTable table = this.Select("SELECT datname FROM pg_catalog.pg_database WHERE (datistemplate = FALSE AND datname <> 'postgres')");
List databases = new List();
foreach (DataRow row in table.Rows)
{
string name = (string)row[0];
if (SystemDatabaseNames.Contains(name) == false)
databases.Add(name);
}
return databases.ToArray();
}
public bool DatabaseExists(string databaseName)
{
string commandText = "SELECT datname FROM pg_catalog.pg_database WHERE datname = '" + databaseName + "'";
object result = this.ExecuteScalar(commandText);
if (result == null || result is DBNull)
return false;
return true;
}
public void DatabaseCreate(string databaseName)
{
this.ExecuteNonQuery("CREATE DATABASE \"" + databaseName + "\"");
}
public void DatabaseCreate(string databaseName, DataSet schema)
{
Spludlow.Data.DALCommon.DatabaseCreate(this, databaseName, schema);
}
public void DatabaseDelete(string databaseName)
{
this.ExecuteNonQuery("DROP DATABASE \"" + databaseName + "\"");
}
//
// Tables
//
public string[] TableList()
{
string database = this.CurrentDatabase();
if (database == null)
throw new ApplicationException("DAL PostgreSQL; To list tables you must have a current database");
DataTable table = this.Select("SELECT table_name FROM information_schema.tables WHERE table_schema='public';");
List tableNames = new List();
foreach (DataRow row in table.Rows)
tableNames.Add((string)row[0]);
return tableNames.ToArray();
}
public void TableCreate(string tableName, DataSet schema)
{
this.TableCreate(tableName, schema.Tables[tableName + "_Columns"], schema.Tables[tableName + "_Keys"]);
}
public void TableCreate(string tableName, DataTable schemaColumns, DataTable schemaKeys)
{
string databaseName = this.CurrentDatabase();
if (databaseName == null)
throw new ApplicationException("DAL PostgrSQL; To create a table you must have a current database");
Spludlow.Data.DALCommon.CreateTableInfo info = new DALCommon.CreateTableInfo();
info.DatabaseType = "PostgreSQL";
info.QuoteOpen = "\"";
info.QuoteClose = "\"";
info.AllowNull = "DEFAULT NULL";
info.DontAllowNull = "NOT NULL";
info.Identity = "__SERIAL__";
info.ColumnLine = "@ColumnName @DataType @Null @Identity";
info.PrimaryLine = "CONSTRAINT @KeyName PRIMARY KEY (@Columns)";
string commandText = Spludlow.Data.DALCommon.MakeCreateTableCommandText(tableName, schemaColumns, schemaKeys, info);
// Fix AUTOINCREMENT - Bodge job!!!
if (commandText.Contains(info.Identity) == true)
{
StringBuilder result = new StringBuilder();
using (StringReader reader = new StringReader(commandText))
{
string line;
while ((line = reader.ReadLine()) != null)
{
if (line.Contains(info.Identity) == true)
{
string dataType = "SERIAL";
if (line.Contains(" bigint ") == true)
dataType = "BIGSERIAL";
int index = line.IndexOf("\"", 1);
line = line.Substring(0, index + 1) + " " + dataType + ",";
result.AppendLine(line);
continue;
}
result.AppendLine(line);
}
}
result.Replace("," + Environment.NewLine + ")" + Environment.NewLine, Environment.NewLine + ")" + Environment.NewLine); // If ends with a comma, sort it out
commandText = result.ToString();
}
Spludlow.Log.Report("DAL; PostgrSQL Creating Table: " + tableName, new object[] { schemaColumns, schemaKeys, commandText });
this.ExecuteNonQuery(commandText);
}
public void TableAddKeys(DataSet schema, string keyTypesPUIF)
{
string[] tableNames = Spludlow.Data.Schemas.OrderTablesOnAncestors(this.TableList(), schema); // Need ?
this.TableAddKeys(tableNames, schema, keyTypesPUIF);
}
public void TableAddKeys(string tableName, DataSet schema, string keyTypesPUIF)
{
this.TableAddKeys(new string[] { tableName }, schema, keyTypesPUIF);
}
public void TableAddKeys(string[] tableNames, DataSet schema, string keyTypesPUIF)
{
string commandTextPrimary = "ALTER TABLE \"@TableName\" ADD CONSTRAINT \"@KeyName\" PRIMARY KEY (@Columns)";
string commandTextUnique = "CREATE UNIQUE INDEX \"@KeyName\" ON \"@TableName\" (@Columns)";
string commandTextIndex = "CREATE INDEX \"@KeyName\" ON \"@TableName\" (@Columns)";
string commandTextForeign = "ALTER TABLE \"@TableName\" ADD CONSTRAINT \"@KeyName\" FOREIGN KEY (@Columns) REFERENCES \"@ParentTable\" (@ParentColumns)";
foreach (string commandText in DALCommon.TableAddKeysCommandText(tableNames, schema, keyTypesPUIF, commandTextPrimary, commandTextUnique, commandTextIndex, commandTextForeign, this.QuoteOpen, this.QuoteClose))
this.ExecuteNonQuery(commandText);
}
public void TableClear(string tableName)
{
this.ExecuteNonQuery("TRUNCATE TABLE \"" + tableName + "\"");
}
public void TableDelete(string tableName)
{
string databaseName = this.CurrentDatabase();
if (databaseName == null)
throw new ApplicationException("DAL PostgrSQL; To delete a table you must have a current database");
string commandText = "DROP TABLE \"" + tableName + "\"";
this.ExecuteNonQuery(commandText);
}
public bool TableExists(string tableName)
{
string databaseName = this.CurrentDatabase();
if (databaseName == null)
throw new ApplicationException("DAL PostgrSQL; To perform a TableExists you must have a current database");
string commandText = "SELECT table_name FROM information_schema.tables WHERE (table_schema = 'public' AND table_name = @TableName)";
object result = this.ExecuteScalar(commandText, new object[] { tableName });
if (result == null || result is DBNull)
return false;
return true;
}
//
// Login
//
public void LoginCreate(string loginName, bool administrator)
{
LoginCreate(loginName, null, administrator);
}
public void LoginCreate(string loginName, string password, bool administrator)
{
}
public void LoginDelete(string loginName)
{
throw new NotImplementedException();
}
public bool LoginExists(string loginName)
{
throw new NotImplementedException();
}
public string[] LoginList()
{
throw new NotImplementedException();
}
//
// User
//
public void UserCreate(string userName, string loginName, bool administrator)
{
throw new NotImplementedException();
}
public void UserDelete(string userName)
{
throw new NotImplementedException();
}
public bool UserExists(string userName)
{
throw new NotImplementedException();
}
public string[] UserList()
{
throw new NotImplementedException();
}
//
// Backup, Restore, Script, Operation
//
public void Backup(string serverFilename)
{
throw new NotImplementedException();
}
public void Restore(string serverFilename)
{
throw new NotImplementedException();
}
public string RunScript(string localFilename, string server, string database)
{
throw new NotImplementedException();
}
public string RunScript(string localFilename, string server, string database, string userName, string password)
{
throw new NotImplementedException();
}
public void Operation(string details)
{
throw new NotImplementedException();
}
public string PageCommandText(string commandText, int pageIndex, int pageSize)
{
throw new NotImplementedException();
}
//
// Command
//
private void SetDataType(DAL.CommandInfo info, DataRow columnRow, int index)
{
string dataTypeId = (string)columnRow["DataTypeId"];
string nativeType = Spludlow.Data.Schemas.CommonToNative(dataTypeId, "NpgsqlDbType");
NpgsqlTypes.NpgsqlDbType dbType = (NpgsqlTypes.NpgsqlDbType)Enum.Parse(typeof(NpgsqlTypes.NpgsqlDbType), nativeType);
info.ParameterTypes[index] = (int)dbType;
info.ParameterMaxLengths[index] = (int)columnRow["MaxLength"];
}
public DAL.CommandInfo MakeCommandInfo(string commandText)
{
return MakeCommandInfo(commandText, DALCommon.ExtractParameterNames(commandText));
}
public DAL.CommandInfo MakeCommandInfo(string commandText, string[] parameterNames)
{
return Spludlow.Data.DALCommon.MakeCommandInfo(commandText, parameterNames, this.Schema(), this.SetDataType);
}
private NpgsqlCommand MakeCommandNative(string commandText)
{
NpgsqlCommand command = new NpgsqlCommand(commandText, this.Connection, this.Transaction);
// The time in seconds to wait for the command to execute. The default is 30 seconds.
//command.CommandTimeout = 20 * 60;
return command;
}
public DbCommand MakeCommand(string commandText)
{
return this.MakeCommandNative(commandText);
}
public DbCommand MakeCommand(string commandText, object[] parameterValues)
{
DAL.CommandInfo commandInfo = this.MakeCommandInfo(commandText);
return this.MakeCommand(commandInfo, parameterValues);
}
public DbCommand MakeCommand(string commandText, string[] parameterNames, object[] parameterValues)
{
DAL.CommandInfo commandInfo = this.MakeCommandInfo(commandText, parameterNames);
return this.MakeCommand(commandInfo, parameterValues);
}
public DbCommand MakeCommand(DAL.CommandInfo commandInfo, object[] parameterValues)
{
if (commandInfo.ParameterNames.Length != parameterValues.Length)
throw new ApplicationException("Making Command with different parameterNames and parameterValues counts: " + commandInfo.ParameterNames.Length + ", " + parameterValues.Length);
NpgsqlCommand command = this.MakeCommandNative(commandInfo.CommandText);
for (int index = 0; index < commandInfo.ParameterNames.Length; ++index)
{
string paramterName = commandInfo.ParameterNames[index];
NpgsqlTypes.NpgsqlDbType dbType = (NpgsqlTypes.NpgsqlDbType)commandInfo.ParameterTypes[index];
int maxLength = commandInfo.ParameterMaxLengths[index];
NpgsqlParameter parameter = command.CreateParameter();
parameter.ParameterName = paramterName;
if ((int)dbType != -1)
parameter.NpgsqlDbType = dbType; // seems to make slightly slower ???????????????????????????????? try differnt DALs
//if (maxLength > 0)
// parameter.Size = maxLength; // using Size seems to slow things down big time on Insert DAL Test using dummpy Logs and bodies. Maybe becasue using max size? Do more tests !!!!!!!!!!!!!!
parameter.Value = parameterValues[index];
command.Parameters.Add(parameter);
}
return command;
}
//
// ExecuteScalar
//
public object ExecuteScalar(string commandText)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandText))
return this.ExecuteScalar(command);
}
public object ExecuteScalar(string commandText, object[] parameterValues)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandText, parameterValues))
return this.ExecuteScalar(command);
}
public object ExecuteScalar(string commandText, string[] parameterNames, object[] parameterValues)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandText, parameterNames, parameterValues))
return this.ExecuteScalar(command);
}
public object ExecuteScalar(DAL.CommandInfo commandInfo, object[] parameterValues)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandInfo, parameterValues))
return this.ExecuteScalar(command);
}
public object ExecuteScalar(DbCommand command)
{
return this.ExecuteScalar((NpgsqlCommand)command);
}
private object ExecuteScalar(NpgsqlCommand command)
{
if (this.Transaction != null)
return command.ExecuteScalar();
this.Open();
try
{
return command.ExecuteScalar();
}
finally
{
this.Close();
}
}
//
// ExecuteNonQuery
//
public int ExecuteNonQuery(string commandText)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandText))
return this.ExecuteNonQuery(command);
}
public int ExecuteNonQuery(string commandText, object[] parameterValues)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandText, parameterValues))
return this.ExecuteNonQuery(command);
}
public int ExecuteNonQuery(string commandText, string[] parameterNames, object[] parameterValues)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandText, parameterNames, parameterValues))
return this.ExecuteNonQuery(command);
}
public int ExecuteNonQuery(DAL.CommandInfo commandInfo, object[] parameterValues)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandInfo, parameterValues))
return this.ExecuteNonQuery(command);
}
public int ExecuteNonQuery(DbCommand command)
{
return this.ExecuteNonQuery((NpgsqlCommand)command);
}
private int ExecuteNonQuery(NpgsqlCommand command)
{
if (this.Transaction != null)
return command.ExecuteNonQuery();
this.Open();
try
{
return command.ExecuteNonQuery();
}
finally
{
this.Close();
}
}
//
// Fill
//
private void ExecuteAdapter(NpgsqlCommand command, DataSet dataSet, DataTable table)
{
if (this.Transaction == null)
this.Open();
try
{
using (NpgsqlDataAdapter adapter = new NpgsqlDataAdapter(command))
{
if (dataSet != null)
adapter.Fill(dataSet);
if (table != null)
adapter.Fill(table);
}
}
finally
{
if (this.Transaction == null)
this.Close();
}
}
public void Fill(DataSet dataSet, string commandText)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandText))
this.Fill(dataSet, command);
}
public void Fill(DataSet dataSet, string commandText, object[] parameterValues)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandText, parameterValues))
this.Fill(dataSet, command);
}
public void Fill(DataSet dataSet, string commandText, string[] parameterNames, object[] parameterValues)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandText, parameterNames, parameterValues))
this.Fill(dataSet, command);
}
public void Fill(DataSet dataSet, DAL.CommandInfo commandInfo, object[] parameterValues)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandInfo, parameterValues))
this.Fill(dataSet, command);
}
public void Fill(DataSet dataSet, DbCommand command)
{
this.Fill(dataSet, (NpgsqlCommand)command);
}
private void Fill(DataSet dataSet, NpgsqlCommand command)
{
this.ExecuteAdapter(command, dataSet, null);
}
public void Fill(DataTable table, string commandText)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandText))
this.Fill(table, command);
}
public void Fill(DataTable table, string commandText, object[] parameterValues)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandText, parameterValues))
this.Fill(table, command);
}
public void Fill(DataTable table, string commandText, string[] parameterNames, object[] parameterValues)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandText, parameterNames, parameterValues))
this.Fill(table, command);
}
public void Fill(DataTable table, DAL.CommandInfo commandInfo, object[] parameterValues)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandInfo, parameterValues))
this.Fill(table, command);
}
public void Fill(DataTable table, DbCommand command)
{
this.Fill(table, (NpgsqlCommand)command);
}
private void Fill(DataTable table, NpgsqlCommand command)
{
this.ExecuteAdapter(command, null, table);
}
//
// Select
//
public DataTable Select(string commandText)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandText))
return this.Select(command);
}
public DataTable Select(string commandText, object[] parameterValues)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandText, parameterValues))
return this.Select(command);
}
public DataTable Select(string commandText, string[] parameterNames, object[] parameterValues)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandText, parameterNames, parameterValues))
return this.Select(command);
}
public DataTable Select(DAL.CommandInfo commandInfo, object[] parameterValues)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandInfo, parameterValues))
return this.Select(command);
}
public DataTable Select(DbCommand command)
{
return this.Select((NpgsqlCommand)command);
}
private DataTable Select(NpgsqlCommand command)
{
DataSet dataSet = this.SelectDS(command);
DataTable table = dataSet.Tables[0];
dataSet.Tables.Remove(table);
return table;
}
public DataSet SelectDS(string commandText)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandText))
return this.SelectDS(command);
}
public DataSet SelectDS(string commandText, object[] parameterValues)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandText, parameterValues))
return this.SelectDS(command);
}
public DataSet SelectDS(string commandText, string[] parameterNames, object[] parameterValues)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandText, parameterNames, parameterValues))
return this.SelectDS(command);
}
public DataSet SelectDS(DAL.CommandInfo commandInfo, object[] parameterValues)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(commandInfo, parameterValues))
return this.SelectDS(command);
}
public DataSet SelectDS(DbCommand command)
{
return this.SelectDS((NpgsqlCommand)command);
}
private DataSet SelectDS(NpgsqlCommand command)
{
DataSet dataSet = new DataSet();
this.ExecuteAdapter(command, dataSet, null);
return dataSet;
}
//
// Inserter
//
public DAL.CommandInfo MakeInserter(string tableName)
{
string identityColumn = "";
DataRow[] rows = this.Schema().Tables[tableName + "_Columns"].Select("AutoIncrement = 1");
if (rows.Length > 1)
throw new ApplicationException("DAL PostgrSQL, MakeInserter; More than 1 AutoIncrement column not supported for table: " + tableName);
if (rows.Length == 1)
identityColumn = (string)rows[0]["ColumnName"];
return DALCommon.MakeInserter(this, tableName, " RETURNING \"" + identityColumn + "\"");
}
public long Insert(DataRow row)
{
return Insert(row.Table.TableName, row);
}
public long Insert(string tableName, DataRow row)
{
DAL.CommandInfo insertInfo = this.MakeInserter(tableName);
return Insert(insertInfo, row);
}
public long Insert(DAL.CommandInfo insertInfo, DataRow row)
{
object[] objectRow = DALCommon.ObjectsFromRow(row, insertInfo);
return Insert(insertInfo, objectRow);
}
public long Insert(string tableName, object[] row)
{
DAL.CommandInfo insertInfo = this.MakeInserter(tableName);
return Insert(insertInfo, row);
}
public long Insert(DAL.CommandInfo insertInfo, object[] row)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(insertInfo, row))
{
if (insertInfo.Identity == false)
{
this.ExecuteNonQuery(command);
return 0;
}
else
{
object obj = this.ExecuteScalar(command);
if (obj == null)
throw new ApplicationException("DAL Insert; Identity object is null.");
if (obj is Int64)
return (long)((Int64)obj);
throw new ApplicationException("DAL Insert; Identity object bad type:\t" + obj.GetType().Name);
}
}
}
//
// Update
//
public DAL.CommandInfo MakeUpdater(string tableName)
{
return MakeUpdater(tableName, new string[0]);
}
public DAL.CommandInfo MakeUpdater(string tableName, string[] updateColumns)
{
return DALCommon.MakeUpdater(this, this.Schema(), tableName, updateColumns);
}
public int Update(DataRow row)
{
return this.Update(row.Table.TableName, row);
}
public int Update(string tableName, DataRow row)
{
DAL.CommandInfo updateInfo = this.MakeUpdater(tableName);
return this.Update(updateInfo, row);
}
public int Update(string tableName, string[] columns, DataRow row)
{
DAL.CommandInfo updateInfo = this.MakeUpdater(tableName, columns);
return this.Update(updateInfo, row);
}
public int Update(DAL.CommandInfo info, DataRow row)
{
object[] objectRow = DALCommon.ObjectsFromRow(row, info);
return this.Update(info, objectRow);
}
public int Update(string tableName, object[] row)
{
DAL.CommandInfo updateInfo = this.MakeUpdater(tableName);
return this.Update(updateInfo, row);
}
public int Update(string tableName, string[] columns, object[] row)
{
DAL.CommandInfo updateInfo = this.MakeUpdater(tableName, columns);
return this.Update(updateInfo, row);
}
public int Update(DAL.CommandInfo updateInfo, object[] row)
{
using (NpgsqlCommand command = (NpgsqlCommand)this.MakeCommand(updateInfo, row))
{
return this.ExecuteNonQuery(command);
}
}
public long InsertOrUpdate(DataRow row)
{
return InsertOrUpdate(row.Table.TableName, row);
}
public long InsertOrUpdate(string tableName, DataRow row)
{
return DALCommon.InsertOrUpdate(row, tableName, this);
}
public void BulkInsert(DataTable table, string tableName, string tempDirectory)
{
throw new NotImplementedException();
}
}
}