// 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 System.Data.SQLite;
namespace Spludlow.Data
{
///
/// SQLite DAL Implimentaion - Fairly well implimented, not tested much
///
/// http://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki
///
/// Using static, requires the seperate SQLite.Interop.dll
///
/// No other dependancies
///
/// Used sqlite-netFx46-static-binary-x64-2015-1.0.112.0
///
///
public class DALSQLite : Spludlow.Data.IDAL
{
private SQLiteConnection Connection;
private SQLiteTransaction Transaction;
private string CacheKeyPrefix;
private Dictionary ConvertDataTypes;
private string QuoteOpen = "[";
private string QuoteClose = "]";
public DALSQLite()
{
}
public DALSQLite(string connectionString)
{
this.Initialize(connectionString);
}
public void Initialize(string connectionString)
{
if (connectionString == null || connectionString.Length == 0) // For use with utility methods
{
return;
}
if (connectionString.StartsWith("@") == true)
connectionString = Spludlow.Config.ConnectionString(connectionString.Substring(1));
// Short hand: FILENAME
if (connectionString.Contains("=") == false && connectionString.Contains(";") == false)
connectionString = MakeConnectionString(connectionString);
this.Connection = new SQLiteConnection(connectionString);
this.CacheKeyPrefix = "DALSQLite-Schemas-" + this.Connection.ConnectionString; //.DataSource(); // + "-";
this.ConvertDataTypes = new Dictionary();
string[] convertLookups = new string[]
{
"integer bigint",
"counter bigint",
"autoincrement bigint",
"identity bigint",
"long bigint",
"yesno bit",
"logical bit",
"bool bit",
"boolean bit",
"currency money",
"numeric decimal",
"real double",
"float double",
"smalldate datetime", // Guessed them from here !!!!!!!!!!!!!!!!!
"timestamp datetime",
"uniqueidentifier guid",
"image blob",
"general blob",
"oleobject blob",
"memo text",
"longtext text",
"note text",
"string text",
};
foreach (string convertLookup in convertLookups)
{
string[] words = Spludlow.Text.Split(convertLookup, '\t', true, false);
this.ConvertDataTypes.Add(words[0], words[1]);
}
//this.ExecuteNonQuery("PRAGMA foreign_keys = 1");
}
public static string MakeConnectionString(string filename)
{
string connectionString = @"Data Source='@Filename';";
connectionString = connectionString.Replace("@Filename", filename);
connectionString += "datetimeformat=CurrentCulture;";
return connectionString;
}
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();
}
//
// Open / Close
//
private void Open()
{
this.Connection.Open();
}
private void Close()
{
this.Connection.Close();
}
public string DataSource()
{
return ""; // this.Connection.DataSource; !!!!!!!!!!!!!!!
}
public void CommandTimeout(int minutes)
{
}
//
// Transactions
//
public void Begin()
{
if (this.Transaction != null)
throw new ApplicationException("DALSQLite: 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("DALSQLite: Commit Transaction not present.");
try
{
this.Transaction.Commit();
this.Transaction = null;
}
finally
{
this.Close();
}
}
public void Rollback()
{
if (this.Transaction == null)
throw new ApplicationException("DALSQLite: Rollback Transaction not present.");
try
{
this.Transaction.Rollback();
this.Transaction = null;
}
finally
{
this.Close();
}
}
//
// Schema
//
// dataSet = database.SelectDS("PRAGMA table_info(tuningdetail)");
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;
}
public DataSet Schema()
{
DataSet schema = (DataSet)Spludlow.Caching.Get(this.CacheKeyPrefix);
if (schema != null)
return schema;
schema = new DataSet();
DataSet schemaReader = this.SchemaReader();
DataSet schemaNative = this.SchemaNative();
DataSet schemaConnection = this.SchemaConnection();
foreach (string tableName in this.TableList())
{
this.SchemaColumns(schema, tableName, schemaReader);
this.SchemaKeys(schema, tableName, schemaReader, schemaNative, schemaConnection);
}
//Spludlow.Data.Schemas.FixForiegnKeys(schema); // seen Int64 on PK and Int32 on FK
Spludlow.Caching.Set(this.CacheKeyPrefix, schema);
return schema;
}
private void SchemaColumns(DataSet schema, string tableName, DataSet schemaReader)
{
DataTable schemaTable = Spludlow.Data.Schemas.NewSchemaColumnsTable(tableName);
foreach (DataRow readerRow in schemaReader.Tables[tableName].Rows)
{
string columnName = (string)readerRow["ColumnName"];
int columnSize = (int)readerRow["ColumnSize"];
string typeName = ((string)readerRow["DataTypeName"]).ToLower();
if (this.ConvertDataTypes.ContainsKey(typeName) == true)
typeName = this.ConvertDataTypes[typeName];
if (typeName.ToLower().EndsWith("identity") == true) // ?????? using AutoIncrement now ???
{
typeName = typeName.Substring(0, typeName.Length - 8).Trim();
readerRow["IsAutoIncrement"] = true;
}
if (columnSize == 0x7FFFFFFF && typeName.EndsWith("char") == true)
{
switch (typeName)
{
case "char":
case "varchar":
typeName = "text";
break;
case "nchar":
case "nvarchar":
typeName = "ntext";
break;
default:
throw new ApplicationException("DAL SQLite, SchemaColumns; Unkown long char datatype:" + typeName);
}
}
DataRow schemaRow = schemaTable.NewRow();
schemaRow["ColumnName"] = columnName;
schemaRow["Ordinal"] = (int)readerRow["ColumnOrdinal"];
schemaRow["DataTypeId"] = Spludlow.Data.Schemas.NativeToCommon(typeName, "SQLite");
schemaRow["MaxLength"] = columnSize;
if (readerRow.IsNull("NumericPrecision") == false)
schemaRow["Precision"] = (int)readerRow["NumericPrecision"];
if (readerRow.IsNull("NumericScale") == false)
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)
{
DataTable keysTable = Spludlow.Data.Schemas.NewSchemaKeysTable(tableName);
foreach (DataRow indexRow in schemaConnection.Tables["Indexes"].Select("TABLE_NAME = '" + tableName + "'"))
{
string indexName = (string)indexRow["INDEX_NAME"];
string keyType = "I";
if ((bool)indexRow["PRIMARY_KEY"] == true)
{
keyType = "P";
}
else
{
if ((bool)indexRow["UNIQUE"] == true)
keyType = "U";
}
foreach (DataRow indexColumnRow in schemaConnection.Tables["IndexColumns"].Select("TABLE_NAME = '" + tableName + "' AND INDEX_NAME = '" + indexName + "'", "ORDINAL_POSITION"))
{
string columnName = (string)indexColumnRow["COLUMN_NAME"];
int ordinal = (int)indexColumnRow["ORDINAL_POSITION"];
bool descending = false;
if ((string)indexColumnRow["SORT_MODE"] != "ASC")
descending = true;
keysTable.Rows.Add(new object[] { indexName, keyType, ordinal, descending, columnName, null, null });
}
}
List parentTables = new List();
foreach (DataRow keyRow in schemaConnection.Tables["ForeignKeys"].Select("TABLE_NAME = '" + tableName + "'"))
{
string parentTable = (string)keyRow["FKEY_TO_TABLE"];
if (parentTables.Contains(parentTable) == false)
parentTables.Add(parentTable);
}
foreach (string parentTable in parentTables)
{
string keyName = "FK_" + tableName + "_" + parentTable;
foreach (DataRow keyRow in schemaConnection.Tables["ForeignKeys"].Select("TABLE_NAME = '" + tableName + "' AND FKEY_TO_TABLE = '" + parentTable + "'", "FKEY_FROM_ORDINAL_POSITION"))
{
int ordinal = (int)keyRow["FKEY_FROM_ORDINAL_POSITION"];
string columnName = (string)keyRow["FKEY_FROM_COLUMN"];
string parentColumn = (string)keyRow["FKEY_TO_COLUMN"];
bool descending = false; // Should look up from parent primary key !!!
keysTable.Rows.Add(new object[] { keyName, "F", ordinal, descending, columnName, parentTable, parentColumn });
}
}
schema.Tables.Add(keysTable);
}
public DataSet SchemaNative()
{
DataSet dataSet = new DataSet();
// https://www.sqlite.org/fileformat2.html 2.6
string[] systemTables = new string[]
{
"sqlite_master",
//"sqlite_sequence", No allways present
};
foreach (string systemTableName in systemTables)
{
this.Fill(dataSet, "SELECT * FROM " + systemTableName);
Spludlow.Data.ADO.NameLastTable(dataSet, systemTableName);
}
return dataSet;
}
public DataSet SchemaConnection()
{
DataSet schema;
if (this.Transaction == null)
this.Open();
try
{
schema = Spludlow.Data.DALCommon.SchemaConnection(this.Connection);
}
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"] }; // Same in all DALS ?? !!!
return schema;
}
public DataSet SchemaReader()
{
string[] tableNames = this.TableList();
if (this.Transaction == null)
this.Open();
try
{
return Spludlow.Data.DALCommon.SchemaReader(this.Connection, this.Transaction, tableNames, "\"", "\"");
}
finally
{
if (this.Transaction == null)
this.Close();
}
}
public DataSet SchemaANSI()
{
DataSet schema = new DataSet();
return schema;
}
public void SchemaRefresh()
{
string databaseName = this.CurrentDatabase();
if (databaseName == null)
throw new ApplicationException("DAL SQLite; To Refresh the schema you must have a current database");
string key = this.CacheKeyPrefix; // + databaseName;
Spludlow.Caching.Remove(key);
}
//
// Databases
//
public string[] DatabaseList()
{
return new string[0];
}
public void ChangeDatabase(string databaseName)
{
this.Initialize(databaseName);
}
public string CurrentDatabase()
{
string[] parts = Spludlow.Text.Split(this.Connection.ConnectionString, ';', true, false);
foreach (string part in parts)
{
if (part.ToLower().StartsWith("data source") == false)
continue;
return part.Trim(new char[] { ' ', '=', '\'' });
}
return "";
}
public void DatabaseCreate(string databaseName)
{
if (File.Exists(databaseName) == true)
throw new ApplicationException("DAL SQLite; Creating database that already exists: " + databaseName);
File.WriteAllText(databaseName, "");
//this.RunScript(databaseName, ".databases" + Environment.NewLine + ".quit"); // Can just create empty file!
}
public void DatabaseCreate(string databaseName, DataSet schema) // SQLite adds all keys when DB is created
{
this.DatabaseCreate(databaseName);
this.ChangeDatabase(databaseName);
string[] tableNames = Spludlow.Data.Schemas.TableNamesInOrder(schema);
foreach (string tableName in tableNames)
{
this.TableCreate(tableName, schema);
this.TableAddKeys(tableName, schema, "UI");
}
}
public void DatabaseDelete(string databaseName)
{
File.Delete(databaseName);
}
public bool DatabaseExists(string databaseName)
{
return File.Exists(databaseName);
}
//
// Tables
//
public string[] TableList()
{
List tableNames = new List();
DataTable table = this.Select("SELECT name from sqlite_master WHERE type = 'table'");
foreach (DataRow row in table.Rows)
{
string tableName = (string)row[0];
if (tableName.StartsWith("sqlite_") == false)
tableNames.Add(tableName);
}
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 SQL; To create a table you must have a current database");
Spludlow.Data.DALCommon.CreateTableInfo info = new DALCommon.CreateTableInfo();
info.DatabaseType = "SQLite";
info.QuoteOpen = "[";
info.QuoteClose = "]";
info.AllowNull = "NULL";
info.DontAllowNull = "NOT NULL";
info.Identity = "__AUTOINCREMENT__"; // Assumes is single column Primary key int (should be Int64)
info.ColumnLine = "@ColumnName @DataType @Identity @Null";
info.PrimaryLine = "CONSTRAINT @KeyName PRIMARY KEY (@Columns)"; // Set in main table defintion
//info.UniqueLine = "CONSTRAINT @KeyName UNIQUE INDEX (@Columns)";
info.ForeignLine = "CONSTRAINT @KeyName FOREIGN KEY (@Columns) REFERENCES @ParentTable (@ParentColumns)"; // Have to create with table
//info.IndexLine = "CONSTRAINT @KeyName INDEX (@Columns)";
// Indexes have to be added afterwards !!!!
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)
{
// [LogId] INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
if (line.Contains(info.Identity) == true)
{
//if (line.Contains(" bigint ") == false)
// Spludlow.Log.Warning("DAL SQLite; PRIMARY KEY AUTOINCREMENT is not Int64 table: " + tableName);
int index = line.IndexOf("]");
line = line.Substring(0, index + 1) + " INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,";
result.AppendLine(line);
continue;
}
// CONSTRAINT [PK_Logs] PRIMARY KEY ([LogId])
if (line.Contains("CONSTRAINT") == true && line.Contains("PRIMARY KEY") == true)
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();
}
this.ExecuteNonQuery(commandText);
}
public void TableDelete(string tableName)
{
this.ExecuteNonQuery("DROP TABLE [" + tableName + "]");
}
public bool TableExists(string tableName)
{
object obj = this.ExecuteScalar("SELECT name FROM sqlite_master WHERE type='table' AND name='" + tableName + "'");
if (obj == null || obj is DBNull)
return false;
return true;
}
public void TableClear(string tableName)
{
this.ExecuteNonQuery("DELETE FROM [" + tableName + "]"); // SQLite don't care about foriegn keys (may leave DB with orphans!)
this.ExecuteNonQuery("VACUUM");
}
public void TableAddKeys(DataSet schema, string keyTypesPUIF)
{
string[] tableNames = Spludlow.Data.Schemas.TableNames(schema);
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)
{
// SQLite cant do P or F has to be done when creating table U and I must be done seperate to creating table
string commandTextUnique = "CREATE UNIQUE INDEX [@KeyName] ON @TableName (@Columns)";
string commandTextIndex = "CREATE INDEX [@KeyName] ON @TableName (@Columns)";
foreach (string tableName in tableNames)
{
foreach (char keyType in keyTypesPUIF)
{
DataTable keysTable = schema.Tables[tableName + "_Keys"];
List keyNames = new List();
foreach (DataRow schemaKeyRow in keysTable.Select("KeyType = '" + keyType + "'"))
{
string keyName = (string)schemaKeyRow["KeyName"];
if (keyNames.Contains(keyName) == false)
keyNames.Add(keyName);
}
foreach (string keyName in keyNames)
{
Spludlow.SysTables.SchemaKeysRow[] keyRows = (Spludlow.SysTables.SchemaKeysRow[])keysTable.Select("KeyName = '" + keyName + "'");
StringBuilder commandText = new StringBuilder();
switch (keyType)
{
case 'U':
commandText.Append(commandTextUnique);
break;
case 'I':
commandText.Append(commandTextIndex);
break;
}
commandText.Replace("@KeyName", keyName);
commandText.Replace("@TableName", DALCommon.QuoteTableName(tableName, this.QuoteOpen, this.QuoteClose));
commandText.Replace("@Columns", DALCommon.ColumnNames(keyRows, "ColumnName", this.QuoteOpen, this.QuoteClose));
this.ExecuteNonQuery(commandText.ToString());
}
}
}
}
//
// Logins (All do nothing for this database type)
//
public void LoginCreate(string loginName, bool administrator)
{
}
public void LoginCreate(string loginName, string password, bool administrator)
{
}
public void LoginDelete(string loginName)
{
}
public bool LoginExists(string loginName)
{
return true;
}
public string[] LoginList()
{
return new string[0];
}
//
// Users (All do nothing for this database type)
//
public string[] UserList()
{
return new string[0];
}
public void UserCreate(string userName, string loginName, bool administrator)
{
}
public void UserDelete(string userName)
{
}
public bool UserExists(string userName)
{
return true;
}
//
// Backup, Restore, Script, Operation
//
public void Backup(string serverFilename)
{
string liveFilename = this.CurrentDatabase();
if (liveFilename == null || liveFilename.Length == 0)
throw new ApplicationException("DAL SQLite; Backup no current database.");
if (File.Exists(liveFilename) == false)
throw new ApplicationException("DAL SQLite; Backup Live database file does not exist: " + liveFilename);
if (File.Exists(serverFilename) == true)
File.Delete(serverFilename);
File.Copy(liveFilename, serverFilename); // Lock File ???
}
public void Restore(string serverFilename)
{
string liveFilename = this.CurrentDatabase();
if (liveFilename == null || liveFilename.Length == 0)
throw new ApplicationException("DAL SQLite; Backup no current database.");
if (File.Exists(liveFilename) == false) // Lock and overwrite ???
File.Delete(liveFilename);
File.Copy(serverFilename, liveFilename);
}
public string RunScript(string localFilename, string server, string database)
{
return this.RunScript(localFilename, server, database, null, null);
}
public string RunScript(string localFilename, string server, string database, string userName, string password)
{
string script = File.ReadAllText(localFilename); // Encoding ? Maybe if no backslashes in start (ie not filename) then use passed text (or @#? at start???)
return this.RunScript(database, script);
}
private string RunScript(string arguments, string input)
{
string programPath = this.FindCommandPath(); // @"C:\Program Files (x86)\sqlite-tools-win32-x86-3170000\sqlite3.exe"; //
Spludlow.Log.Info("DAL SQLite; Running Script: " + programPath + " " + arguments);
Spludlow.SpawnProcess.ProcessExitInfo exitInfo = Spludlow.SpawnProcess.Run(programPath, arguments, 0, input); // No timeout !!!!
if (exitInfo.StandardError.Length > 0)
Spludlow.Log.Error("DAL SQLite; RunScript, Error in output", exitInfo.StandardError);
if (exitInfo.ExitCode != 0)
throw new ApplicationException("DAL SQLite; RunScript, Bad Exit Code: " + exitInfo.ExitCode);
return exitInfo.StandardOutput;
}
private string FindCommandPath()
{
string path;
path = Spludlow.Config.Get("Spludlow.DatabaseCommandPath.SQLite", true);
if (path != null)
return path;
string name = "sqlite3.exe";
if (File.Exists(name) == true)
return Path.GetFullPath(name);
string found = null;
foreach (string programFilesDirectory in new string[] { @"C:\Program Files", @"C:\Program Files (x86)" })
{
string[] directories = Directory.GetDirectories(programFilesDirectory, "sqlite-tools*");
foreach (string directory in directories)
{
path = directory + @"\sqlite3.exe";
if (File.Exists(path) == true)
{
if (found == null)
found = path;
else
Spludlow.Log.Warning("SQLite; Multiple paths to sqlite3.exe found: " + path);
}
}
}
if (found == null)
throw new ApplicationException("SQLite; Unable to find sqlite3.exe");
return found;
}
public void Operation(string details)
{
Spludlow.Log.Warning("SQLite; Operation, doing nothing: " + details);
}
public string PageCommandText(string commandText, int pageIndex, int pageSize)
{
int offset = pageIndex * pageSize;
StringBuilder text = new StringBuilder(commandText);
text.Append(" LIMIT @PageSize OFFSET @Offset");
text.Replace("@Offset", offset.ToString());
text.Replace("@PageSize", pageSize.ToString());
return text.ToString();
}
//
// Make Command
//
private void SetDataType(DAL.CommandInfo info, DataRow columnRow, int index)
{
string dataTypeId = (string)columnRow["DataTypeId"];
string nativeType = Spludlow.Data.Schemas.CommonToNative(dataTypeId, "DbType"); // There is no SQLiteDbType
DbType dbType = (DbType)Enum.Parse(typeof(DbType), 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);
}
public DbCommand MakeCommand(string commandText)
{
SQLiteCommand command = new SQLiteCommand(commandText, this.Connection, this.Transaction);
return command;
}
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);
SQLiteCommand command = new SQLiteCommand(commandInfo.CommandText, this.Connection, this.Transaction);
for (int index = 0; index < commandInfo.ParameterNames.Length; ++index)
{
string paramterName = commandInfo.ParameterNames[index];
DbType dbType = (DbType)commandInfo.ParameterTypes[index];
int maxLength = commandInfo.ParameterMaxLengths[index];
SQLiteParameter parameter = command.CreateParameter();
parameter.ParameterName = paramterName;
if ((int)dbType != -1)
parameter.DbType = dbType; // parameter.TypeName ???
//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 (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandText))
return this.ExecuteScalar(command);
}
public object ExecuteScalar(string commandText, object[] parameterValues)
{
using (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandText, parameterValues))
return this.ExecuteScalar(command);
}
public object ExecuteScalar(string commandText, string[] parameterNames, object[] parameterValues)
{
using (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandText, parameterNames, parameterValues))
return this.ExecuteScalar(command);
}
public object ExecuteScalar(DAL.CommandInfo commandInfo, object[] parameterValues)
{
using (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandInfo, parameterValues))
return this.ExecuteScalar(command);
}
public object ExecuteScalar(DbCommand command)
{
return this.ExecuteScalar((SQLiteCommand)command);
}
private object ExecuteScalar(SQLiteCommand command)
{
if (this.Transaction != null)
return command.ExecuteScalar();
this.Open();
try
{
return command.ExecuteScalar();
}
finally
{
this.Close();
}
}
//
// ExecuteNonQuery
//
public int ExecuteNonQuery(string commandText)
{
using (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandText))
return this.ExecuteNonQuery(command);
}
public int ExecuteNonQuery(string commandText, object[] parameterValues)
{
using (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandText, parameterValues))
return this.ExecuteNonQuery(command);
}
public int ExecuteNonQuery(string commandText, string[] parameterNames, object[] parameterValues)
{
using (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandText, parameterNames, parameterValues))
return this.ExecuteNonQuery(command);
}
public int ExecuteNonQuery(DAL.CommandInfo commandInfo, object[] parameterValues)
{
using (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandInfo, parameterValues))
return this.ExecuteNonQuery(command);
}
public int ExecuteNonQuery(DbCommand command)
{
return this.ExecuteNonQuery((SQLiteCommand)command);
}
private int ExecuteNonQuery(SQLiteCommand command)
{
if (this.Transaction != null)
return command.ExecuteNonQuery();
this.Open();
try
{
return command.ExecuteNonQuery();
}
finally
{
this.Close();
}
}
//
// Fill
//
public void Fill(DataSet dataSet, string commandText)
{
using (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandText))
this.Fill(dataSet, command);
}
public void Fill(DataSet dataSet, string commandText, object[] parameterValues)
{
using (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandText, parameterValues))
this.Fill(dataSet, command);
}
public void Fill(DataSet dataSet, string commandText, string[] parameterNames, object[] parameterValues)
{
using (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandText, parameterNames, parameterValues))
this.Fill(dataSet, command);
}
public void Fill(DataSet dataSet, DAL.CommandInfo commandInfo, object[] parameterValues)
{
using (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandInfo, parameterValues))
this.Fill(dataSet, command);
}
public void Fill(DataSet dataSet, DbCommand command)
{
this.Fill(dataSet, (SQLiteCommand)command);
}
private void Fill(DataSet dataSet, SQLiteCommand command)
{
this.ExecuteAdapter(command, dataSet, null);
}
public void Fill(DataTable table, string commandText)
{
using (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandText))
this.Fill(table, command);
}
public void Fill(DataTable table, string commandText, object[] parameterValues)
{
using (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandText, parameterValues))
this.Fill(table, command);
}
public void Fill(DataTable table, string commandText, string[] parameterNames, object[] parameterValues)
{
using (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandText, parameterNames, parameterValues))
this.Fill(table, command);
}
public void Fill(DataTable table, DAL.CommandInfo commandInfo, object[] parameterValues)
{
using (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandInfo, parameterValues))
this.Fill(table, command);
}
public void Fill(DataTable table, DbCommand command)
{
this.Fill(table, (SQLiteCommand)command);
}
private void Fill(DataTable table, SQLiteCommand command)
{
this.ExecuteAdapter(command, null, table);
}
//
// Select
//
public DataTable Select(string commandText)
{
using (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandText))
return this.Select(command);
}
public DataTable Select(string commandText, object[] parameterValues)
{
using (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandText, parameterValues))
return this.Select(command);
}
public DataTable Select(string commandText, string[] parameterNames, object[] parameterValues)
{
using (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandText, parameterNames, parameterValues))
return this.Select(command);
}
public DataTable Select(DAL.CommandInfo commandInfo, object[] parameterValues)
{
using (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandInfo, parameterValues))
return this.Select(command);
}
public DataTable Select(DbCommand command)
{
return this.Select((SQLiteCommand)command);
}
private DataTable Select(SQLiteCommand command)
{
DataSet dataSet = this.SelectDS(command);
DataTable table = dataSet.Tables[0];
dataSet.Tables.Remove(table);
return table;
}
public DataSet SelectDS(string commandText)
{
using (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandText))
return this.SelectDS(command);
}
public DataSet SelectDS(string commandText, object[] parameterValues)
{
using (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandText, parameterValues))
return this.SelectDS(command);
}
public DataSet SelectDS(string commandText, string[] parameterNames, object[] parameterValues)
{
using (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandText, parameterNames, parameterValues))
return this.SelectDS(command);
}
public DataSet SelectDS(DAL.CommandInfo commandInfo, object[] parameterValues)
{
using (SQLiteCommand command = (SQLiteCommand)this.MakeCommand(commandInfo, parameterValues))
return this.SelectDS(command);
}
public DataSet SelectDS(DbCommand command)
{
return this.SelectDS((SQLiteCommand)command);
}
private DataSet SelectDS(SQLiteCommand command)
{
DataSet dataSet = new DataSet();
this.ExecuteAdapter(command, dataSet, null);
return dataSet;
}
private void ExecuteAdapter(SQLiteCommand command, DataSet dataSet, DataTable table)
{
if (this.Transaction == null)
this.Open();
try
{
using (SQLiteDataAdapter adapter = new SQLiteDataAdapter(command))
{
if (dataSet != null)
adapter.Fill(dataSet);
if (table != null)
adapter.Fill(table);
}
}
finally
{
if (this.Transaction == null)
this.Close();
}
}
//
// Inserter
//
public DAL.CommandInfo MakeInserter(string tableName)
{
return DALCommon.MakeInserter(this, tableName, "; SELECT last_insert_rowid()");
}
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 (SQLiteCommand command = (SQLiteCommand)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 SQLite Insert; Identity object is null.");
if (obj is Int64)
return (long)((Int64)obj);
throw new ApplicationException("DAL SQLite 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 (SQLiteCommand command = (SQLiteCommand)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)
{
Spludlow.Data.Schemas.DisableAutoIncrement(this.Schema(), tableName);
DAL.CommandInfo inserter = this.MakeInserter(tableName);
// Doing in a transaction as it's faster
this.CommandTimeout(60); // The Commit may take a while
this.Begin();
try
{
foreach (DataRow row in table.Rows)
this.Insert(inserter, row);
this.Commit();
}
catch
{
this.Rollback();
throw;
}
finally
{
this.SchemaRefresh();
}
}
}
}