From 44df45020b765dadcdf851168cae1288e0617940 Mon Sep 17 00:00:00 2001 From: Alex Norman Date: Fri, 18 Oct 2019 09:49:41 -0700 Subject: [PATCH 01/14] WIP abstracting prepared statement into its own class --- src/SQLite.cs | 401 ++++++++++++++++++++++++++++---------------------- 1 file changed, 228 insertions(+), 173 deletions(-) diff --git a/src/SQLite.cs b/src/SQLite.cs index cc6689e9..6e2d1204 100644 --- a/src/SQLite.cs +++ b/src/SQLite.cs @@ -2593,6 +2593,230 @@ public static bool IsMarkedNotNull (MemberInfo p) } } + public class SQLitePreparedStatement : IDisposable { + Sqlite3Statement Statement; + SQLiteConnection Connection { get; set; } + Sqlite3DatabaseHandle Handle => Connection.Handle; + + public SQLitePreparedStatement(SQLiteConnection conn, string sql) + { + Connection = conn; + Statement = SQLite3.Prepare2(Handle, sql); + } + + public IEnumerable ExecuteDeferredQuery (params object[] args) + { + //ResetAndBind(args); + var cols = new SQLite.TableMapping.Column[SQLite3.ColumnCount(Statement)]; + + var map = new TableMapping(typeof(T), CreateFlags.None); + + for (int i = 0; i < cols.Length; i++) { + var name = SQLite3.ColumnName16(Statement, i); + cols[i] = map.FindColumn(name); + } + + while (SQLite3.Step(Statement) == SQLite3.Result.Row) { + var obj = Activator.CreateInstance(typeof(T)); + for (int i = 0; i < cols.Length; i++) { + if (cols[i] == null) + continue; + var colType = SQLite3.ColumnType(Statement, i); + var val = ReadCol(Statement, i, colType, cols[i].ColumnType, Connection.StoreDateTimeAsTicks); + cols[i].SetValue(obj, val); + } + yield return (T)obj; + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + bool disposed = false; + protected virtual void Dispose(bool disposing) + { + if (disposed) + return; + if (disposing) { + SQLite3.Finalize(Statement); + } + disposed = true; + } + + static IntPtr NegativePointer = new IntPtr (-1); + + const string DateTimeExactStoreFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff"; + + internal static void BindParameter (Sqlite3Statement stmt, int index, object value, bool storeDateTimeAsTicks) + { + if (value == null) { + SQLite3.BindNull (stmt, index); + } + else { + if (value is Int32) { + SQLite3.BindInt (stmt, index, (int)value); + } + else if (value is String) { + SQLite3.BindText (stmt, index, (string)value, -1, NegativePointer); + } + else if (value is Byte || value is UInt16 || value is SByte || value is Int16) { + SQLite3.BindInt (stmt, index, Convert.ToInt32 (value)); + } + else if (value is Boolean) { + SQLite3.BindInt (stmt, index, (bool)value ? 1 : 0); + } + else if (value is UInt32 || value is Int64) { + SQLite3.BindInt64 (stmt, index, Convert.ToInt64 (value)); + } + else if (value is Single || value is Double || value is Decimal) { + SQLite3.BindDouble (stmt, index, Convert.ToDouble (value)); + } + else if (value is TimeSpan) { + SQLite3.BindInt64 (stmt, index, ((TimeSpan)value).Ticks); + } + else if (value is DateTime) { + if (storeDateTimeAsTicks) { + SQLite3.BindInt64 (stmt, index, ((DateTime)value).Ticks); + } + else { + SQLite3.BindText (stmt, index, ((DateTime)value).ToString (DateTimeExactStoreFormat, System.Globalization.CultureInfo.InvariantCulture), -1, NegativePointer); + } + } + else if (value is DateTimeOffset) { + SQLite3.BindInt64 (stmt, index, ((DateTimeOffset)value).UtcTicks); + } + else if (value is byte[]) { + SQLite3.BindBlob (stmt, index, (byte[])value, ((byte[])value).Length, NegativePointer); + } + else if (value is Guid) { + SQLite3.BindText (stmt, index, ((Guid)value).ToString (), 72, NegativePointer); + } + else if (value is Uri) { + SQLite3.BindText (stmt, index, ((Uri)value).ToString (), -1, NegativePointer); + } + else if (value is StringBuilder) { + SQLite3.BindText (stmt, index, ((StringBuilder)value).ToString (), -1, NegativePointer); + } + else if (value is UriBuilder) { + SQLite3.BindText (stmt, index, ((UriBuilder)value).ToString (), -1, NegativePointer); + } + else { + // Now we could possibly get an enum, retrieve cached info + var valueType = value.GetType (); + var enumInfo = EnumCache.GetInfo (valueType); + if (enumInfo.IsEnum) { + var enumIntValue = Convert.ToInt32 (value); + if (enumInfo.StoreAsText) + SQLite3.BindText (stmt, index, enumInfo.EnumValues[enumIntValue], -1, NegativePointer); + else + SQLite3.BindInt (stmt, index, enumIntValue); + } + else { + throw new NotSupportedException ("Cannot store type: " + Orm.GetType (value)); + } + } + } + } + + internal static object ReadCol (Sqlite3Statement stmt, int index, SQLite3.ColType type, Type clrType, bool storeDateTimeAsTicks) + { + if (type == SQLite3.ColType.Null) { + return null; + } + else { + var clrTypeInfo = clrType.GetTypeInfo (); + if (clrType == typeof (String)) { + return SQLite3.ColumnString (stmt, index); + } + else if (clrType == typeof (Int32)) { + return (int)SQLite3.ColumnInt (stmt, index); + } + else if (clrType == typeof (Boolean)) { + return SQLite3.ColumnInt (stmt, index) == 1; + } + else if (clrType == typeof (double)) { + return SQLite3.ColumnDouble (stmt, index); + } + else if (clrType == typeof (float)) { + return (float)SQLite3.ColumnDouble (stmt, index); + } + else if (clrType == typeof (TimeSpan)) { + return new TimeSpan (SQLite3.ColumnInt64 (stmt, index)); + } + else if (clrType == typeof (DateTime)) { + if (storeDateTimeAsTicks) { + return new DateTime (SQLite3.ColumnInt64 (stmt, index)); + } + else { + var text = SQLite3.ColumnString (stmt, index); + DateTime resultDate; + if (!DateTime.TryParseExact (text, DateTimeExactStoreFormat, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out resultDate)) { + resultDate = DateTime.Parse (text); + } + return resultDate; + } + } + else if (clrType == typeof (DateTimeOffset)) { + return new DateTimeOffset (SQLite3.ColumnInt64 (stmt, index), TimeSpan.Zero); + } + else if (clrTypeInfo.IsEnum) { + if (type == SQLite3.ColType.Text) { + var value = SQLite3.ColumnString (stmt, index); + return Enum.Parse (clrType, value.ToString (), true); + } + else + return SQLite3.ColumnInt (stmt, index); + } + else if (clrType == typeof (Int64)) { + return SQLite3.ColumnInt64 (stmt, index); + } + else if (clrType == typeof (UInt32)) { + return (uint)SQLite3.ColumnInt64 (stmt, index); + } + else if (clrType == typeof (decimal)) { + return (decimal)SQLite3.ColumnDouble (stmt, index); + } + else if (clrType == typeof (Byte)) { + return (byte)SQLite3.ColumnInt (stmt, index); + } + else if (clrType == typeof (UInt16)) { + return (ushort)SQLite3.ColumnInt (stmt, index); + } + else if (clrType == typeof (Int16)) { + return (short)SQLite3.ColumnInt (stmt, index); + } + else if (clrType == typeof (sbyte)) { + return (sbyte)SQLite3.ColumnInt (stmt, index); + } + else if (clrType == typeof (byte[])) { + return SQLite3.ColumnByteArray (stmt, index); + } + else if (clrType == typeof (Guid)) { + var text = SQLite3.ColumnString (stmt, index); + return new Guid (text); + } + else if (clrType == typeof(Uri)) { + var text = SQLite3.ColumnString(stmt, index); + return new Uri(text); + } + else if (clrType == typeof (StringBuilder)) { + var text = SQLite3.ColumnString (stmt, index); + return new StringBuilder (text); + } + else if (clrType == typeof(UriBuilder)) { + var text = SQLite3.ColumnString(stmt, index); + return new UriBuilder(text); + } + else { + throw new NotSupportedException ("Don't know how to read " + clrType); + } + } + } + } + public partial class SQLiteCommand { SQLiteConnection _conn; @@ -2685,7 +2909,7 @@ public IEnumerable ExecuteDeferredQuery (TableMapping map) if (cols[i] == null) continue; var colType = SQLite3.ColumnType (stmt, i); - var val = ReadCol (stmt, i, colType, cols[i].ColumnType); + var val = SQLitePreparedStatement.ReadCol (stmt, i, colType, cols[i].ColumnType, _conn.StoreDateTimeAsTicks); cols[i].SetValue (obj, val); } OnInstanceCreated (obj); @@ -2711,7 +2935,7 @@ public T ExecuteScalar () var r = SQLite3.Step (stmt); if (r == SQLite3.Result.Row) { var colType = SQLite3.ColumnType (stmt, 0); - val = (T)ReadCol (stmt, 0, colType, typeof (T)); + val = (T)SQLitePreparedStatement.ReadCol (stmt, 0, colType, typeof (T), _conn.StoreDateTimeAsTicks); } else if (r == SQLite3.Result.Done) { } @@ -2774,82 +2998,7 @@ void BindAll (Sqlite3Statement stmt) b.Index = nextIdx++; } - BindParameter (stmt, b.Index, b.Value, _conn.StoreDateTimeAsTicks); - } - } - - static IntPtr NegativePointer = new IntPtr (-1); - - const string DateTimeExactStoreFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff"; - - internal static void BindParameter (Sqlite3Statement stmt, int index, object value, bool storeDateTimeAsTicks) - { - if (value == null) { - SQLite3.BindNull (stmt, index); - } - else { - if (value is Int32) { - SQLite3.BindInt (stmt, index, (int)value); - } - else if (value is String) { - SQLite3.BindText (stmt, index, (string)value, -1, NegativePointer); - } - else if (value is Byte || value is UInt16 || value is SByte || value is Int16) { - SQLite3.BindInt (stmt, index, Convert.ToInt32 (value)); - } - else if (value is Boolean) { - SQLite3.BindInt (stmt, index, (bool)value ? 1 : 0); - } - else if (value is UInt32 || value is Int64) { - SQLite3.BindInt64 (stmt, index, Convert.ToInt64 (value)); - } - else if (value is Single || value is Double || value is Decimal) { - SQLite3.BindDouble (stmt, index, Convert.ToDouble (value)); - } - else if (value is TimeSpan) { - SQLite3.BindInt64 (stmt, index, ((TimeSpan)value).Ticks); - } - else if (value is DateTime) { - if (storeDateTimeAsTicks) { - SQLite3.BindInt64 (stmt, index, ((DateTime)value).Ticks); - } - else { - SQLite3.BindText (stmt, index, ((DateTime)value).ToString (DateTimeExactStoreFormat, System.Globalization.CultureInfo.InvariantCulture), -1, NegativePointer); - } - } - else if (value is DateTimeOffset) { - SQLite3.BindInt64 (stmt, index, ((DateTimeOffset)value).UtcTicks); - } - else if (value is byte[]) { - SQLite3.BindBlob (stmt, index, (byte[])value, ((byte[])value).Length, NegativePointer); - } - else if (value is Guid) { - SQLite3.BindText (stmt, index, ((Guid)value).ToString (), 72, NegativePointer); - } - else if (value is Uri) { - SQLite3.BindText (stmt, index, ((Uri)value).ToString (), -1, NegativePointer); - } - else if (value is StringBuilder) { - SQLite3.BindText (stmt, index, ((StringBuilder)value).ToString (), -1, NegativePointer); - } - else if (value is UriBuilder) { - SQLite3.BindText (stmt, index, ((UriBuilder)value).ToString (), -1, NegativePointer); - } - else { - // Now we could possibly get an enum, retrieve cached info - var valueType = value.GetType (); - var enumInfo = EnumCache.GetInfo (valueType); - if (enumInfo.IsEnum) { - var enumIntValue = Convert.ToInt32 (value); - if (enumInfo.StoreAsText) - SQLite3.BindText (stmt, index, enumInfo.EnumValues[enumIntValue], -1, NegativePointer); - else - SQLite3.BindInt (stmt, index, enumIntValue); - } - else { - throw new NotSupportedException ("Cannot store type: " + Orm.GetType (value)); - } - } + SQLitePreparedStatement.BindParameter (stmt, b.Index, b.Value, _conn.StoreDateTimeAsTicks); } } @@ -2862,100 +3011,6 @@ class Binding public int Index { get; set; } } - object ReadCol (Sqlite3Statement stmt, int index, SQLite3.ColType type, Type clrType) - { - if (type == SQLite3.ColType.Null) { - return null; - } - else { - var clrTypeInfo = clrType.GetTypeInfo (); - if (clrType == typeof (String)) { - return SQLite3.ColumnString (stmt, index); - } - else if (clrType == typeof (Int32)) { - return (int)SQLite3.ColumnInt (stmt, index); - } - else if (clrType == typeof (Boolean)) { - return SQLite3.ColumnInt (stmt, index) == 1; - } - else if (clrType == typeof (double)) { - return SQLite3.ColumnDouble (stmt, index); - } - else if (clrType == typeof (float)) { - return (float)SQLite3.ColumnDouble (stmt, index); - } - else if (clrType == typeof (TimeSpan)) { - return new TimeSpan (SQLite3.ColumnInt64 (stmt, index)); - } - else if (clrType == typeof (DateTime)) { - if (_conn.StoreDateTimeAsTicks) { - return new DateTime (SQLite3.ColumnInt64 (stmt, index)); - } - else { - var text = SQLite3.ColumnString (stmt, index); - DateTime resultDate; - if (!DateTime.TryParseExact (text, DateTimeExactStoreFormat, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out resultDate)) { - resultDate = DateTime.Parse (text); - } - return resultDate; - } - } - else if (clrType == typeof (DateTimeOffset)) { - return new DateTimeOffset (SQLite3.ColumnInt64 (stmt, index), TimeSpan.Zero); - } - else if (clrTypeInfo.IsEnum) { - if (type == SQLite3.ColType.Text) { - var value = SQLite3.ColumnString (stmt, index); - return Enum.Parse (clrType, value.ToString (), true); - } - else - return SQLite3.ColumnInt (stmt, index); - } - else if (clrType == typeof (Int64)) { - return SQLite3.ColumnInt64 (stmt, index); - } - else if (clrType == typeof (UInt32)) { - return (uint)SQLite3.ColumnInt64 (stmt, index); - } - else if (clrType == typeof (decimal)) { - return (decimal)SQLite3.ColumnDouble (stmt, index); - } - else if (clrType == typeof (Byte)) { - return (byte)SQLite3.ColumnInt (stmt, index); - } - else if (clrType == typeof (UInt16)) { - return (ushort)SQLite3.ColumnInt (stmt, index); - } - else if (clrType == typeof (Int16)) { - return (short)SQLite3.ColumnInt (stmt, index); - } - else if (clrType == typeof (sbyte)) { - return (sbyte)SQLite3.ColumnInt (stmt, index); - } - else if (clrType == typeof (byte[])) { - return SQLite3.ColumnByteArray (stmt, index); - } - else if (clrType == typeof (Guid)) { - var text = SQLite3.ColumnString (stmt, index); - return new Guid (text); - } - else if (clrType == typeof(Uri)) { - var text = SQLite3.ColumnString(stmt, index); - return new Uri(text); - } - else if (clrType == typeof (StringBuilder)) { - var text = SQLite3.ColumnString (stmt, index); - return new StringBuilder (text); - } - else if (clrType == typeof(UriBuilder)) { - var text = SQLite3.ColumnString(stmt, index); - return new UriBuilder(text); - } - else { - throw new NotSupportedException ("Don't know how to read " + clrType); - } - } - } } /// @@ -2998,7 +3053,7 @@ public int ExecuteNonQuery (object[] source) //bind the values. if (source != null) { for (int i = 0; i < source.Length; i++) { - SQLiteCommand.BindParameter (Statement, i + 1, source[i], Connection.StoreDateTimeAsTicks); + SQLitePreparedStatement.BindParameter (Statement, i + 1, source[i], Connection.StoreDateTimeAsTicks); } } r = SQLite3.Step (Statement); From 1834ea801d44df98decaadd98c7e6a577cbbfc27 Mon Sep 17 00:00:00 2001 From: Alex Norman Date: Fri, 18 Oct 2019 10:01:20 -0700 Subject: [PATCH 02/14] add additional methods, reset and bind --- src/SQLite.cs | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/src/SQLite.cs b/src/SQLite.cs index 6e2d1204..f23c617a 100644 --- a/src/SQLite.cs +++ b/src/SQLite.cs @@ -2604,9 +2604,37 @@ public SQLitePreparedStatement(SQLiteConnection conn, string sql) Statement = SQLite3.Prepare2(Handle, sql); } + public int ExecuteNonQuery (params object[] args) + { + ResetAndBind(args); + if (Connection.Trace) { + Connection.Tracer?.Invoke ("Executing: " + this); + } + + var r = SQLite3.Result.OK; + r = SQLite3.Step (Statement); + if (r == SQLite3.Result.Done) { + int rowsAffected = SQLite3.Changes (Handle); + return rowsAffected; + } + else if (r == SQLite3.Result.Error) { + string msg = SQLite3.GetErrmsg (Handle); + throw SQLiteException.New (r, msg); + } + else if (r == SQLite3.Result.Constraint) { + if (SQLite3.ExtendedErrCode (Handle) == SQLite3.ExtendedResult.ConstraintNotNull) { + throw NotNullConstraintViolationException.New (r, SQLite3.GetErrmsg (Handle)); + } + } + throw SQLiteException.New (r, r.ToString ()); + } + public IEnumerable ExecuteDeferredQuery (params object[] args) { - //ResetAndBind(args); + ResetAndBind(args); + if (Connection.Trace) { + Connection.Tracer?.Invoke ("Executing Query: " + this); + } var cols = new SQLite.TableMapping.Column[SQLite3.ColumnCount(Statement)]; var map = new TableMapping(typeof(T), CreateFlags.None); @@ -2629,6 +2657,29 @@ public IEnumerable ExecuteDeferredQuery (params object[] args) } } + public T ExecuteScalar (params object[] args) + { + ResetAndBind(args); + if (Connection.Trace) { + Connection.Tracer?.Invoke ("Executing Query: " + this); + } + + T val = default (T); + + var r = SQLite3.Step (Statement); + if (r == SQLite3.Result.Row) { + var colType = SQLite3.ColumnType (Statement, 0); + val = (T)SQLitePreparedStatement.ReadCol (Statement, 0, colType, typeof (T), Connection.StoreDateTimeAsTicks); + } + else if (r == SQLite3.Result.Done) { + } + else { + throw SQLiteException.New (r, SQLite3.GetErrmsg (Handle)); + } + + return val; + } + public void Dispose() { Dispose(true); @@ -2646,6 +2697,13 @@ protected virtual void Dispose(bool disposing) disposed = true; } + void ResetAndBind(params object[] args) { + SQLite3.Reset(Statement); + for (int i = 0; i < args.Length; i++) { + BindParameter(Statement, i + 1, args[i], Connection.StoreDateTimeAsTicks); + } + } + static IntPtr NegativePointer = new IntPtr (-1); const string DateTimeExactStoreFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff"; From b77daed0253c8460c7cc509a90faa7507b4b0b49 Mon Sep 17 00:00:00 2001 From: Alex Norman Date: Fri, 18 Oct 2019 10:24:01 -0700 Subject: [PATCH 03/14] store command text, impl destructor, impl ToString with args, fix dispose --- src/SQLite.cs | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/SQLite.cs b/src/SQLite.cs index f23c617a..162ec798 100644 --- a/src/SQLite.cs +++ b/src/SQLite.cs @@ -2597,18 +2597,24 @@ public class SQLitePreparedStatement : IDisposable { Sqlite3Statement Statement; SQLiteConnection Connection { get; set; } Sqlite3DatabaseHandle Handle => Connection.Handle; + public string CommandText { get; private set; } public SQLitePreparedStatement(SQLiteConnection conn, string sql) { + CommandText = sql; Connection = conn; - Statement = SQLite3.Prepare2(Handle, sql); + Statement = SQLite3.Prepare2(Handle, CommandText); + } + + ~SQLitePreparedStatement() { + Dispose(false); } public int ExecuteNonQuery (params object[] args) { ResetAndBind(args); if (Connection.Trace) { - Connection.Tracer?.Invoke ("Executing: " + this); + Connection.Tracer?.Invoke ("Executing: " + ToString(args)); } var r = SQLite3.Result.OK; @@ -2633,7 +2639,7 @@ public IEnumerable ExecuteDeferredQuery (params object[] args) { ResetAndBind(args); if (Connection.Trace) { - Connection.Tracer?.Invoke ("Executing Query: " + this); + Connection.Tracer?.Invoke ("Executing Query: " + ToString(args)); } var cols = new SQLite.TableMapping.Column[SQLite3.ColumnCount(Statement)]; @@ -2661,7 +2667,7 @@ public T ExecuteScalar (params object[] args) { ResetAndBind(args); if (Connection.Trace) { - Connection.Tracer?.Invoke ("Executing Query: " + this); + Connection.Tracer?.Invoke ("Executing Query: " + ToString(args)); } T val = default (T); @@ -2687,13 +2693,11 @@ public void Dispose() } bool disposed = false; - protected virtual void Dispose(bool disposing) + protected virtual void Dispose(bool _disposing) { if (disposed) return; - if (disposing) { - SQLite3.Finalize(Statement); - } + SQLite3.Finalize(Statement); disposed = true; } @@ -2873,6 +2877,18 @@ internal static object ReadCol (Sqlite3Statement stmt, int index, SQLite3.ColTyp } } } + + public string ToString (params object[] args) + { + var parts = new string[1 + args.Count()]; + parts[0] = CommandText; + var i = 1; + foreach (var b in args) { + parts[i] = string.Format (" {0}: {1}", i - 1, b); + i++; + } + return string.Join (Environment.NewLine, parts); + } } public partial class SQLiteCommand From fdf7269ac31d58fbd2372b7e7e18fa5c6ddb0abc Mon Sep 17 00:00:00 2001 From: Alex Norman Date: Fri, 18 Oct 2019 11:07:03 -0700 Subject: [PATCH 04/14] intial work for async prepared statement wrapper --- src/SQLiteAsync.cs | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/SQLiteAsync.cs b/src/SQLiteAsync.cs index e7e827e6..ced6e0eb 100644 --- a/src/SQLiteAsync.cs +++ b/src/SQLiteAsync.cs @@ -1426,5 +1426,57 @@ public void Dispose () } } } + + /// + /// Async wrapper for prepared statements. + /// + public class SQLiteAsyncPreparedStatement : IDisposable { + SQLiteAsyncConnection Connection { get; set; } + SQLitePreparedStatement Statement { get; set; } + + /// + /// Initializes a new instance of the class. + /// + /// The Connection. + /// The sql to prepare. + public SQLiteAsyncPreparedStatement(SQLiteAsyncConnection conn, string sql) + { + Connection = conn; + Statement = new SQLitePreparedStatement(conn.GetConnection() as SQLiteConnection, sql); + } + + /// + /// Dispose + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + bool disposed = false; + /// + /// Dispose + /// + protected virtual void Dispose(bool disposing) + { + if (disposed) + return; + if (disposing) { + Statement.Dispose(); + } + disposed = true; + } + + Task WriteAsync (Func exe) + { + return Task.Factory.StartNew (() => { + var conn = Connection.GetConnection(); + using (conn.Lock ()) { + return exe (conn); + } + }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); + } + } } From 3cbcdd274c6ccd26df3432fbf9935eb758faece0 Mon Sep 17 00:00:00 2001 From: Alex Norman Date: Fri, 18 Oct 2019 13:08:19 -0700 Subject: [PATCH 05/14] impl async wrapped prepared statement methods --- src/SQLiteAsync.cs | 73 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 10 deletions(-) diff --git a/src/SQLiteAsync.cs b/src/SQLiteAsync.cs index ced6e0eb..bf980cac 100644 --- a/src/SQLiteAsync.cs +++ b/src/SQLiteAsync.cs @@ -1435,14 +1435,67 @@ public class SQLiteAsyncPreparedStatement : IDisposable { SQLitePreparedStatement Statement { get; set; } /// - /// Initializes a new instance of the class. + /// Creates a prepared statement given the command text (SQL) with arguments. Place a '?' + /// in the command text for each of the arguments and then executes that command. + /// Use this method when return primitive values. + /// You can set the Trace or TimeExecution properties of the connection + /// to profile execution. /// /// The Connection. - /// The sql to prepare. - public SQLiteAsyncPreparedStatement(SQLiteAsyncConnection conn, string sql) + /// + /// The fully escaped SQL. + /// + public SQLiteAsyncPreparedStatement(SQLiteAsyncConnection conn, string query) { Connection = conn; - Statement = new SQLitePreparedStatement(conn.GetConnection() as SQLiteConnection, sql); + Statement = new SQLitePreparedStatement(conn.GetConnection() as SQLiteConnection, query); + } + + /// + /// Executes a prepared statement. + /// + /// + /// Arguments to substitute for the occurences of '?' in the query. + /// + /// + /// The number of rows modified in the database as a result of this execution. + /// + public Task ExecuteNonQueryAsync (params object[] args) + { + return WrapAsync(() => Statement.ExecuteNonQuery(args)); + } + + /// + /// Executes a prepared statement. + /// It returns each row of the result using the mapping automatically generated for + /// the given type. + /// + /// + /// Arguments to substitute for the occurences of '?' in the query. + /// + /// + /// An enumerable with one result for each row returned by the query. + /// The enumerator (retrieved by calling GetEnumerator() on the result of this method) + /// will call sqlite3_step on each call to MoveNext, so the database + /// connection must remain open for the lifetime of the enumerator. + /// + public Task> ExecuteDeferredQueryAsync (params object[] args) + { + return WrapAsync>(() => Statement.ExecuteDeferredQuery(args).ToList()); + } + + /// + /// Executes a prepared statement. + /// + /// + /// Arguments to substitute for the occurences of '?' in the query. + /// + /// + /// The resultant object of this execution. + /// + public Task ExecuteScalarAsync (params object[] args) + { + return WrapAsync(() => Statement.ExecuteScalar(args)); } /// @@ -1468,14 +1521,14 @@ protected virtual void Dispose(bool disposing) disposed = true; } - Task WriteAsync (Func exe) + Task WrapAsync (Func exe) { return Task.Factory.StartNew (() => { - var conn = Connection.GetConnection(); - using (conn.Lock ()) { - return exe (conn); - } - }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); + var conn = Connection.GetConnection(); + using (conn.Lock ()) { + return exe(); + } + }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); } } } From 582bc8c31a98fa044b2aa1d20f47a39a9f4a6171 Mon Sep 17 00:00:00 2001 From: Alex Norman Date: Fri, 18 Oct 2019 15:04:38 -0700 Subject: [PATCH 06/14] expose inner, use connection with lock --- src/SQLiteAsync.cs | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/SQLiteAsync.cs b/src/SQLiteAsync.cs index bf980cac..df8ac5b6 100644 --- a/src/SQLiteAsync.cs +++ b/src/SQLiteAsync.cs @@ -1431,8 +1431,23 @@ public void Dispose () /// Async wrapper for prepared statements. /// public class SQLiteAsyncPreparedStatement : IDisposable { - SQLiteAsyncConnection Connection { get; set; } - SQLitePreparedStatement Statement { get; set; } + SQLiteConnectionWithLock Connection { get; set; } + + /// Get the inner, synchronous, statement; + public SQLitePreparedStatement Inner { get; private set; } + + /// + /// Creates a prepared statement given the command text (SQL) with arguments. Place a '?' + /// in the command text for each of the arguments and then executes that command. + /// Use this method when return primitive values. + /// You can set the Trace or TimeExecution properties of the connection + /// to profile execution. + /// + /// The Connection. + /// + /// The fully escaped SQL. + /// + public SQLiteAsyncPreparedStatement(SQLiteAsyncConnection conn, string query) : this(conn.GetConnection(), query) { } /// /// Creates a prepared statement given the command text (SQL) with arguments. Place a '?' @@ -1445,10 +1460,10 @@ public class SQLiteAsyncPreparedStatement : IDisposable { /// /// The fully escaped SQL. /// - public SQLiteAsyncPreparedStatement(SQLiteAsyncConnection conn, string query) + public SQLiteAsyncPreparedStatement(SQLiteConnectionWithLock conn, string query) { Connection = conn; - Statement = new SQLitePreparedStatement(conn.GetConnection() as SQLiteConnection, query); + Inner = new SQLitePreparedStatement(Connection as SQLiteConnection, query); } /// @@ -1462,7 +1477,7 @@ public SQLiteAsyncPreparedStatement(SQLiteAsyncConnection conn, string query) /// public Task ExecuteNonQueryAsync (params object[] args) { - return WrapAsync(() => Statement.ExecuteNonQuery(args)); + return WrapAsync(() => Inner.ExecuteNonQuery(args)); } /// @@ -1481,7 +1496,7 @@ public Task ExecuteNonQueryAsync (params object[] args) /// public Task> ExecuteDeferredQueryAsync (params object[] args) { - return WrapAsync>(() => Statement.ExecuteDeferredQuery(args).ToList()); + return WrapAsync>(() => Inner.ExecuteDeferredQuery(args).ToList()); } /// @@ -1495,7 +1510,7 @@ public Task> ExecuteDeferredQueryAsync (params object[] args) /// public Task ExecuteScalarAsync (params object[] args) { - return WrapAsync(() => Statement.ExecuteScalar(args)); + return WrapAsync(() => Inner.ExecuteScalar(args)); } /// @@ -1516,7 +1531,7 @@ protected virtual void Dispose(bool disposing) if (disposed) return; if (disposing) { - Statement.Dispose(); + Inner.Dispose(); } disposed = true; } @@ -1524,8 +1539,7 @@ protected virtual void Dispose(bool disposing) Task WrapAsync (Func exe) { return Task.Factory.StartNew (() => { - var conn = Connection.GetConnection(); - using (conn.Lock ()) { + using (Connection.Lock ()) { return exe(); } }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); From a5dc5ead898908e2b3ec4c7548bb9d56ee61e0f3 Mon Sep 17 00:00:00 2001 From: Alex Norman Date: Tue, 22 Oct 2019 09:28:13 -0700 Subject: [PATCH 07/14] no need for prefix --- src/SQLite.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SQLite.cs b/src/SQLite.cs index 162ec798..da5f09b5 100644 --- a/src/SQLite.cs +++ b/src/SQLite.cs @@ -2675,7 +2675,7 @@ public T ExecuteScalar (params object[] args) var r = SQLite3.Step (Statement); if (r == SQLite3.Result.Row) { var colType = SQLite3.ColumnType (Statement, 0); - val = (T)SQLitePreparedStatement.ReadCol (Statement, 0, colType, typeof (T), Connection.StoreDateTimeAsTicks); + val = (T)ReadCol (Statement, 0, colType, typeof (T), Connection.StoreDateTimeAsTicks); } else if (r == SQLite3.Result.Done) { } From 8669edfeae7971a4330d2d385eb50eb4c1aa22fc Mon Sep 17 00:00:00 2001 From: Alex Norman Date: Thu, 24 Oct 2019 13:43:32 -0700 Subject: [PATCH 08/14] expose clear bindings, clear before bind prepared --- src/SQLite.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/SQLite.cs b/src/SQLite.cs index da5f09b5..71d4d95e 100644 --- a/src/SQLite.cs +++ b/src/SQLite.cs @@ -2703,6 +2703,7 @@ protected virtual void Dispose(bool _disposing) void ResetAndBind(params object[] args) { SQLite3.Reset(Statement); + SQLite3.ClearBindings(Statement); for (int i = 0; i < args.Length; i++) { BindParameter(Statement, i + 1, args[i], Connection.StoreDateTimeAsTicks); } @@ -4018,6 +4019,9 @@ public static IntPtr Prepare2 (IntPtr db, string query) [DllImport(LibraryPath, EntryPoint = "sqlite3_finalize", CallingConvention=CallingConvention.Cdecl)] public static extern Result Finalize (IntPtr stmt); + [DllImport(LibraryPath, EntryPoint = "sqlite3_clear_bindings", CallingConvention=CallingConvention.Cdecl)] + public static extern int ClearBindings (IntPtr stmt); + [DllImport(LibraryPath, EntryPoint = "sqlite3_last_insert_rowid", CallingConvention=CallingConvention.Cdecl)] public static extern long LastInsertRowid (IntPtr db); @@ -4171,6 +4175,11 @@ public static Result Finalize (Sqlite3Statement stmt) return (Result)Sqlite3.sqlite3_finalize (stmt); } + public static Result ClearBindings (Sqlite3Statement stmt) + { + return (Result)Sqlite3.sqlite3_clear_bindings (stmt); + } + public static long LastInsertRowid (Sqlite3DatabaseHandle db) { return Sqlite3.sqlite3_last_insert_rowid (db); From 59eee5ad7267ea2d17268da4e4bf83fc7b8e4104 Mon Sep 17 00:00:00 2001 From: Andrew Galante Date: Mon, 11 Nov 2019 13:15:13 -0800 Subject: [PATCH 09/14] use new prepared statement internally --- src/SQLite.cs | 166 ++++++++++++-------------------------------------- 1 file changed, 39 insertions(+), 127 deletions(-) diff --git a/src/SQLite.cs b/src/SQLite.cs index 71d4d95e..ab784dd8 100644 --- a/src/SQLite.cs +++ b/src/SQLite.cs @@ -2042,16 +2042,16 @@ public class SQLiteConnectionString #if NETFX_CORE static readonly string MetroStyleDataPath = Windows.Storage.ApplicationData.Current.LocalFolder.Path; - public static readonly string[] InMemoryDbPaths = new[] - { - ":memory:", - "file::memory:" - }; - - public static bool IsInMemoryPath(string databasePath) - { - return InMemoryDbPaths.Any(i => i.Equals(databasePath, StringComparison.OrdinalIgnoreCase)); - } + public static readonly string[] InMemoryDbPaths = new[] + { + ":memory:", + "file::memory:" + }; + + public static bool IsInMemoryPath(string databasePath) + { + return InMemoryDbPaths.Any(i => i.Equals(databasePath, StringComparison.OrdinalIgnoreCase)); + } #endif @@ -2062,9 +2062,9 @@ public SQLiteConnectionString (string databasePath, bool storeDateTimeAsTicks, o Key = key; #if NETFX_CORE - DatabasePath = IsInMemoryPath(databasePath) - ? databasePath - : System.IO.Path.Combine(MetroStyleDataPath, databasePath); + DatabasePath = IsInMemoryPath(databasePath) + ? databasePath + : System.IO.Path.Combine(MetroStyleDataPath, databasePath); #else DatabasePath = databasePath; @@ -2635,7 +2635,7 @@ public int ExecuteNonQuery (params object[] args) throw SQLiteException.New (r, r.ToString ()); } - public IEnumerable ExecuteDeferredQuery (params object[] args) + public IEnumerable ExecuteDeferredQuery (TableMapping map, params object[] args) { ResetAndBind(args); if (Connection.Trace) { @@ -2643,8 +2643,6 @@ public IEnumerable ExecuteDeferredQuery (params object[] args) } var cols = new SQLite.TableMapping.Column[SQLite3.ColumnCount(Statement)]; - var map = new TableMapping(typeof(T), CreateFlags.None); - for (int i = 0; i < cols.Length; i++) { var name = SQLite3.ColumnName16(Statement, i); cols[i] = map.FindColumn(name); @@ -2663,6 +2661,12 @@ public IEnumerable ExecuteDeferredQuery (params object[] args) } } + public IEnumerable ExecuteDeferredQuery (params object[] args) + { + var map = new TableMapping(typeof(T), CreateFlags.None); + return ExecuteDeferredQuery(map, args); + } + public T ExecuteScalar (params object[] args) { ResetAndBind(args); @@ -2908,29 +2912,9 @@ public SQLiteCommand (SQLiteConnection conn) public int ExecuteNonQuery () { - if (_conn.Trace) { - _conn.Tracer?.Invoke ("Executing: " + this); - } - - var r = SQLite3.Result.OK; - var stmt = Prepare (); - r = SQLite3.Step (stmt); - Finalize (stmt); - if (r == SQLite3.Result.Done) { - int rowsAffected = SQLite3.Changes (_conn.Handle); - return rowsAffected; - } - else if (r == SQLite3.Result.Error) { - string msg = SQLite3.GetErrmsg (_conn.Handle); - throw SQLiteException.New (r, msg); - } - else if (r == SQLite3.Result.Constraint) { - if (SQLite3.ExtendedErrCode (_conn.Handle) == SQLite3.ExtendedResult.ConstraintNotNull) { - throw NotNullConstraintViolationException.New (r, SQLite3.GetErrmsg (_conn.Handle)); - } + using (var stmt = new SQLitePreparedStatement(_conn, CommandText)) { + return stmt.ExecuteNonQuery(_bindings); } - - throw SQLiteException.New (r, r.ToString ()); } public IEnumerable ExecuteDeferredQuery () @@ -2965,64 +2949,19 @@ protected virtual void OnInstanceCreated (object obj) public IEnumerable ExecuteDeferredQuery (TableMapping map) { - if (_conn.Trace) { - _conn.Tracer?.Invoke ("Executing Query: " + this); - } - - var stmt = Prepare (); - try { - var cols = new TableMapping.Column[SQLite3.ColumnCount (stmt)]; - - for (int i = 0; i < cols.Length; i++) { - var name = SQLite3.ColumnName16 (stmt, i); - cols[i] = map.FindColumn (name); - } - - while (SQLite3.Step (stmt) == SQLite3.Result.Row) { - var obj = Activator.CreateInstance (map.MappedType); - for (int i = 0; i < cols.Length; i++) { - if (cols[i] == null) - continue; - var colType = SQLite3.ColumnType (stmt, i); - var val = SQLitePreparedStatement.ReadCol (stmt, i, colType, cols[i].ColumnType, _conn.StoreDateTimeAsTicks); - cols[i].SetValue (obj, val); - } - OnInstanceCreated (obj); - yield return (T)obj; - } - } - finally { - SQLite3.Finalize (stmt); + using (var stmt = new SQLitePreparedStatement(_conn, CommandText)) { + return stmt.ExecuteDeferredQuery(map, _bindings).Select(obj => { + OnInstanceCreated(obj); + return obj; + }); } } public T ExecuteScalar () { - if (_conn.Trace) { - _conn.Tracer?.Invoke ("Executing Query: " + this); - } - - T val = default (T); - - var stmt = Prepare (); - - try { - var r = SQLite3.Step (stmt); - if (r == SQLite3.Result.Row) { - var colType = SQLite3.ColumnType (stmt, 0); - val = (T)SQLitePreparedStatement.ReadCol (stmt, 0, colType, typeof (T), _conn.StoreDateTimeAsTicks); - } - else if (r == SQLite3.Result.Done) { - } - else { - throw SQLiteException.New (r, SQLite3.GetErrmsg (_conn.Handle)); - } - } - finally { - Finalize (stmt); + using (var stmt = new SQLitePreparedStatement(_conn, CommandText)) { + return stmt.ExecuteScalar(_bindings); } - - return val; } public void Bind (string name, object val) @@ -3050,33 +2989,6 @@ public override string ToString () return string.Join (Environment.NewLine, parts); } - Sqlite3Statement Prepare () - { - var stmt = SQLite3.Prepare2 (_conn.Handle, CommandText); - BindAll (stmt); - return stmt; - } - - void Finalize (Sqlite3Statement stmt) - { - SQLite3.Finalize (stmt); - } - - void BindAll (Sqlite3Statement stmt) - { - int nextIdx = 1; - foreach (var b in _bindings) { - if (b.Name != null) { - b.Index = SQLite3.BindParameterIndex (stmt, b.Name); - } - else { - b.Index = nextIdx++; - } - - SQLitePreparedStatement.BindParameter (stmt, b.Index, b.Value, _conn.StoreDateTimeAsTicks); - } - } - class Binding { public string Name { get; set; } @@ -3720,13 +3632,13 @@ private string CompileNullBinaryExpression (BinaryExpression expression, Compile if (expression.NodeType == ExpressionType.Equal) return "(" + parameter.CommandText + " is ?)"; else if (expression.NodeType == ExpressionType.NotEqual) - return "(" + parameter.CommandText + " is not ?)"; - else if (expression.NodeType == ExpressionType.GreaterThan - || expression.NodeType == ExpressionType.GreaterThanOrEqual - || expression.NodeType == ExpressionType.LessThan - || expression.NodeType == ExpressionType.LessThanOrEqual) - return "(" + parameter.CommandText + " < ?)"; // always false - else + return "(" + parameter.CommandText + " is not ?)"; + else if (expression.NodeType == ExpressionType.GreaterThan + || expression.NodeType == ExpressionType.GreaterThanOrEqual + || expression.NodeType == ExpressionType.LessThan + || expression.NodeType == ExpressionType.LessThanOrEqual) + return "(" + parameter.CommandText + " < ?)"; // always false + else throw new NotSupportedException ("Cannot compile Null-BinaryExpression with type " + expression.NodeType.ToString ()); } @@ -4298,10 +4210,10 @@ public static string ColumnString (Sqlite3Statement stmt, int index) } public static byte[] ColumnByteArray (Sqlite3Statement stmt, int index) - { + { int length = ColumnBytes (stmt, index); - if (length > 0) { - return ColumnBlob (stmt, index); + if (length > 0) { + return ColumnBlob (stmt, index); } return new byte[0]; } From 8a03c25fe6d300cd9ea289ed0ebc48418da887d4 Mon Sep 17 00:00:00 2001 From: Andrew Galante Date: Mon, 11 Nov 2019 13:15:50 -0800 Subject: [PATCH 10/14] oops, params need to be an array --- src/SQLite.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/SQLite.cs b/src/SQLite.cs index ab784dd8..e61e8c97 100644 --- a/src/SQLite.cs +++ b/src/SQLite.cs @@ -2913,7 +2913,7 @@ public SQLiteCommand (SQLiteConnection conn) public int ExecuteNonQuery () { using (var stmt = new SQLitePreparedStatement(_conn, CommandText)) { - return stmt.ExecuteNonQuery(_bindings); + return stmt.ExecuteNonQuery(_bindings.ToArray()); } } @@ -2950,7 +2950,7 @@ protected virtual void OnInstanceCreated (object obj) public IEnumerable ExecuteDeferredQuery (TableMapping map) { using (var stmt = new SQLitePreparedStatement(_conn, CommandText)) { - return stmt.ExecuteDeferredQuery(map, _bindings).Select(obj => { + return stmt.ExecuteDeferredQuery(map, _bindings.ToArray()).Select(obj => { OnInstanceCreated(obj); return obj; }); @@ -2960,7 +2960,7 @@ public IEnumerable ExecuteDeferredQuery (TableMapping map) public T ExecuteScalar () { using (var stmt = new SQLitePreparedStatement(_conn, CommandText)) { - return stmt.ExecuteScalar(_bindings); + return stmt.ExecuteScalar(_bindings.ToArray()); } } From 0f3796ef4bafbcae73882d61dc1816a7e4d3244e Mon Sep 17 00:00:00 2001 From: Alex Norman Date: Tue, 22 Oct 2019 10:30:11 -0700 Subject: [PATCH 11/14] only pass value of binding, wrap enumerable inside statement block --- src/SQLite.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/SQLite.cs b/src/SQLite.cs index e61e8c97..7a706c68 100644 --- a/src/SQLite.cs +++ b/src/SQLite.cs @@ -2900,6 +2900,7 @@ public partial class SQLiteCommand { SQLiteConnection _conn; private List _bindings; + object[] BindingParams => _bindings.Select(b => b.Value).ToArray(); public string CommandText { get; set; } @@ -2913,7 +2914,7 @@ public SQLiteCommand (SQLiteConnection conn) public int ExecuteNonQuery () { using (var stmt = new SQLitePreparedStatement(_conn, CommandText)) { - return stmt.ExecuteNonQuery(_bindings.ToArray()); + return stmt.ExecuteNonQuery(BindingParams); } } @@ -2950,17 +2951,17 @@ protected virtual void OnInstanceCreated (object obj) public IEnumerable ExecuteDeferredQuery (TableMapping map) { using (var stmt = new SQLitePreparedStatement(_conn, CommandText)) { - return stmt.ExecuteDeferredQuery(map, _bindings.ToArray()).Select(obj => { + foreach (var obj in stmt.ExecuteDeferredQuery(map, BindingParams)) { OnInstanceCreated(obj); - return obj; - }); + yield return obj; + } } } public T ExecuteScalar () { using (var stmt = new SQLitePreparedStatement(_conn, CommandText)) { - return stmt.ExecuteScalar(_bindings.ToArray()); + return stmt.ExecuteScalar(BindingParams); } } From 26cc98d26a9e53666aa5eb00ed0ac63675df09aa Mon Sep 17 00:00:00 2001 From: Alex Norman Date: Tue, 22 Oct 2019 15:39:25 -0700 Subject: [PATCH 12/14] just call inner dispose --- src/SQLiteAsync.cs | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/src/SQLiteAsync.cs b/src/SQLiteAsync.cs index df8ac5b6..e172921d 100644 --- a/src/SQLiteAsync.cs +++ b/src/SQLiteAsync.cs @@ -1516,25 +1516,7 @@ public Task ExecuteScalarAsync (params object[] args) /// /// Dispose /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - bool disposed = false; - /// - /// Dispose - /// - protected virtual void Dispose(bool disposing) - { - if (disposed) - return; - if (disposing) { - Inner.Dispose(); - } - disposed = true; - } + public void Dispose() => Inner.Dispose(); Task WrapAsync (Func exe) { From 6085a27972a3aef2ecf5e3021d182a2613e252ac Mon Sep 17 00:00:00 2001 From: Alex Norman Date: Tue, 22 Oct 2019 15:42:16 -0700 Subject: [PATCH 13/14] simplify dispose --- src/SQLite.cs | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/src/SQLite.cs b/src/SQLite.cs index 7a706c68..739228b2 100644 --- a/src/SQLite.cs +++ b/src/SQLite.cs @@ -2595,7 +2595,7 @@ public static bool IsMarkedNotNull (MemberInfo p) public class SQLitePreparedStatement : IDisposable { Sqlite3Statement Statement; - SQLiteConnection Connection { get; set; } + SQLiteConnection Connection { get; set; } Sqlite3DatabaseHandle Handle => Connection.Handle; public string CommandText { get; private set; } @@ -2605,9 +2605,14 @@ public SQLitePreparedStatement(SQLiteConnection conn, string sql) Connection = conn; Statement = SQLite3.Prepare2(Handle, CommandText); } - - ~SQLitePreparedStatement() { - Dispose(false); + + bool disposed = false; + public void Dispose() + { + if (disposed) + return; + disposed = true; + SQLite3.Finalize(Statement); } public int ExecuteNonQuery (params object[] args) @@ -2690,21 +2695,6 @@ public T ExecuteScalar (params object[] args) return val; } - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - bool disposed = false; - protected virtual void Dispose(bool _disposing) - { - if (disposed) - return; - SQLite3.Finalize(Statement); - disposed = true; - } - void ResetAndBind(params object[] args) { SQLite3.Reset(Statement); SQLite3.ClearBindings(Statement); From a1737b0df7b560e99a38c5804603b4077bb04196 Mon Sep 17 00:00:00 2001 From: Andrew Galante Date: Mon, 11 Nov 2019 14:00:31 -0800 Subject: [PATCH 14/14] Fix merge errors --- src/SQLite.cs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/SQLite.cs b/src/SQLite.cs index 6167d07a..c4fc2313 100644 --- a/src/SQLite.cs +++ b/src/SQLite.cs @@ -2841,7 +2841,7 @@ public IEnumerable ExecuteDeferredQuery (TableMapping map, params object[] if (cols[i] == null) continue; var colType = SQLite3.ColumnType(Statement, i); - var val = ReadCol(Statement, i, colType, cols[i].ColumnType, Connection.StoreDateTimeAsTicks); + var val = ReadCol(Statement, i, colType, cols[i].ColumnType, Connection); cols[i].SetValue(obj, val); } yield return (T)obj; @@ -2866,7 +2866,7 @@ public T ExecuteScalar (params object[] args) var r = SQLite3.Step (Statement); if (r == SQLite3.Result.Row) { var colType = SQLite3.ColumnType (Statement, 0); - val = (T)ReadCol (Statement, 0, colType, typeof (T), Connection.StoreDateTimeAsTicks); + val = (T)ReadCol (Statement, 0, colType, typeof (T), Connection); } else if (r == SQLite3.Result.Done) { } @@ -2881,13 +2881,13 @@ void ResetAndBind(params object[] args) { SQLite3.Reset(Statement); SQLite3.ClearBindings(Statement); for (int i = 0; i < args.Length; i++) { - BindParameter(Statement, i + 1, args[i], Connection.StoreDateTimeAsTicks, Connection.DateTimeStringFormat, Connection.StoreTimeSpanAsTicks); + BindParameter(Statement, i + 1, args[i], Connection); } } static IntPtr NegativePointer = new IntPtr (-1); - internal static void BindParameter (Sqlite3Statement stmt, int index, object value, bool storeDateTimeAsTicks, string dateTimeStringFormat, bool storeTimeSpanAsTicks) + internal static void BindParameter (Sqlite3Statement stmt, int index, object value, SQLiteConnection connection) { if (value == null) { SQLite3.BindNull (stmt, index); @@ -2912,7 +2912,7 @@ internal static void BindParameter (Sqlite3Statement stmt, int index, object val SQLite3.BindDouble (stmt, index, Convert.ToDouble (value)); } else if (value is TimeSpan) { - if (storeTimeSpanAsTicks) { + if (connection.StoreTimeSpanAsTicks) { SQLite3.BindInt64 (stmt, index, ((TimeSpan)value).Ticks); } else { @@ -2920,11 +2920,11 @@ internal static void BindParameter (Sqlite3Statement stmt, int index, object val } } else if (value is DateTime) { - if (storeDateTimeAsTicks) { + if (connection.StoreDateTimeAsTicks) { SQLite3.BindInt64 (stmt, index, ((DateTime)value).Ticks); } else { - SQLite3.BindText (stmt, index, ((DateTime)value).ToString (dateTimeStringFormat, System.Globalization.CultureInfo.InvariantCulture), -1, NegativePointer); + SQLite3.BindText (stmt, index, ((DateTime)value).ToString (connection.DateTimeStringFormat, System.Globalization.CultureInfo.InvariantCulture), -1, NegativePointer); } } else if (value is DateTimeOffset) { @@ -2963,7 +2963,7 @@ internal static void BindParameter (Sqlite3Statement stmt, int index, object val } } - internal static object ReadCol (Sqlite3Statement stmt, int index, SQLite3.ColType type, Type clrType, bool storeDateTimeAsTicks) + internal static object ReadCol (Sqlite3Statement stmt, int index, SQLite3.ColType type, Type clrType, SQLiteConnection connection) { if (type == SQLite3.ColType.Null) { return null; @@ -2991,7 +2991,7 @@ internal static object ReadCol (Sqlite3Statement stmt, int index, SQLite3.ColTyp return (float)SQLite3.ColumnDouble (stmt, index); } else if (clrType == typeof (TimeSpan)) { - if (_conn.StoreTimeSpanAsTicks) { + if (connection.StoreTimeSpanAsTicks) { return new TimeSpan (SQLite3.ColumnInt64 (stmt, index)); } else { @@ -3004,13 +3004,13 @@ internal static object ReadCol (Sqlite3Statement stmt, int index, SQLite3.ColTyp } } else if (clrType == typeof (DateTime)) { - if (storeDateTimeAsTicks) { + if (connection.StoreDateTimeAsTicks) { return new DateTime (SQLite3.ColumnInt64 (stmt, index)); } else { var text = SQLite3.ColumnString (stmt, index); DateTime resultDate; - if (!DateTime.TryParseExact (text, _conn.DateTimeStringFormat, System.Globalization.CultureInfo.InvariantCulture, _conn.DateTimeStyle, out resultDate)) { + if (!DateTime.TryParseExact (text, connection.DateTimeStringFormat, System.Globalization.CultureInfo.InvariantCulture, connection.DateTimeStyle, out resultDate)) { resultDate = DateTime.Parse (text); } return resultDate; @@ -3231,7 +3231,7 @@ public int ExecuteNonQuery (object[] source) //bind the values. if (source != null) { for (int i = 0; i < source.Length; i++) { - SQLitePreparedStatement.BindParameter (Statement, i + 1, source[i], Connection.StoreDateTimeAsTicks, Connection.DateTimeStringFormat, Connection.StoreTimeSpanAsTicks); + SQLitePreparedStatement.BindParameter (Statement, i + 1, source[i], Connection); } } r = SQLite3.Step (Statement);