From f7a9962aa1012810751f394f2c0d848ea0afde2f Mon Sep 17 00:00:00 2001 From: gilzoide Date: Tue, 14 Jan 2025 18:25:18 -0300 Subject: [PATCH] Update SQLite-net to v1.9.172 --- Plugins/sqlite-net~ | 2 +- README.md | 2 +- Runtime/sqlite-net/SQLite.cs | 152 ++++++++++++++++++++++++++++-- Runtime/sqlite-net/SQLiteAsync.cs | 122 +++++++++++++++++++++++- 4 files changed, 263 insertions(+), 15 deletions(-) diff --git a/Plugins/sqlite-net~ b/Plugins/sqlite-net~ index 0b23275..5f72241 160000 --- a/Plugins/sqlite-net~ +++ b/Plugins/sqlite-net~ @@ -1 +1 @@ -Subproject commit 0b23275b085febba7cac53f076898ac58e99ac25 +Subproject commit 5f72241035dd48f4305a7c811eba8e7c955e9840 diff --git a/README.md b/README.md index 06e5211..826e1f4 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ This package provides the excelent [SQLite-net](https://github.com/praeclarum/sq ## Features -- [SQLite-net v1.8.116](https://github.com/praeclarum/sqlite-net/tree/v1.8.116) +- [SQLite-net v1.9.172](https://github.com/praeclarum/sqlite-net/tree/v1.9.172) + Both synchronous and asynchronous APIs are available + `SQLiteConnection.Serialize` extension method for serializing a database to `byte[]` (reference: [SQLite Serialization](https://www.sqlite.org/c3ref/serialize.html)). + `SQLiteConnection.Deserialize` extension method for deserializing memory (`byte[]`, `NativeArray` or `ReadOnlySpan`) into an open database (reference: [SQLite Deserialization](https://www.sqlite.org/c3ref/deserialize.html)). diff --git a/Runtime/sqlite-net/SQLite.cs b/Runtime/sqlite-net/SQLite.cs index df11428..e4e950f 100644 --- a/Runtime/sqlite-net/SQLite.cs +++ b/Runtime/sqlite-net/SQLite.cs @@ -1,5 +1,5 @@ // -// Copyright (c) 2009-2021 Krueger Systems, Inc. +// Copyright (c) 2009-2024 Krueger Systems, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -114,6 +114,7 @@ public static NotNullConstraintViolationException New (SQLiteException exception public enum SQLiteOpenFlags { ReadOnly = 1, ReadWrite = 2, Create = 4, + Uri = 0x40, Memory = 0x80, NoMutex = 0x8000, FullMutex = 0x10000, SharedCache = 0x20000, PrivateCache = 0x40000, ProtectionComplete = 0x00100000, @@ -159,11 +160,109 @@ public enum CreateFlags FullTextSearch4 = 0x200 } + public interface ISQLiteConnection : IDisposable + { + Sqlite3DatabaseHandle Handle { get; } + string DatabasePath { get; } + int LibVersionNumber { get; } + bool TimeExecution { get; set; } + bool Trace { get; set; } + Action Tracer { get; set; } + bool StoreDateTimeAsTicks { get; } + bool StoreTimeSpanAsTicks { get; } + string DateTimeStringFormat { get; } + TimeSpan BusyTimeout { get; set; } + IEnumerable TableMappings { get; } + bool IsInTransaction { get; } + + event EventHandler TableChanged; + + void Backup (string destinationDatabasePath, string databaseName = "main"); + void BeginTransaction (); + void Close (); + void Commit (); + SQLiteCommand CreateCommand (string cmdText, params object[] ps); + SQLiteCommand CreateCommand (string cmdText, Dictionary args); + int CreateIndex (string indexName, string tableName, string[] columnNames, bool unique = false); + int CreateIndex (string indexName, string tableName, string columnName, bool unique = false); + int CreateIndex (string tableName, string columnName, bool unique = false); + int CreateIndex (string tableName, string[] columnNames, bool unique = false); + int CreateIndex (Expression> property, bool unique = false); + CreateTableResult CreateTable (CreateFlags createFlags = CreateFlags.None); + CreateTableResult CreateTable (Type ty, CreateFlags createFlags = CreateFlags.None); + CreateTablesResult CreateTables (CreateFlags createFlags = CreateFlags.None) + where T : new() + where T2 : new(); + CreateTablesResult CreateTables (CreateFlags createFlags = CreateFlags.None) + where T : new() + where T2 : new() + where T3 : new(); + CreateTablesResult CreateTables (CreateFlags createFlags = CreateFlags.None) + where T : new() + where T2 : new() + where T3 : new() + where T4 : new(); + CreateTablesResult CreateTables (CreateFlags createFlags = CreateFlags.None) + where T : new() + where T2 : new() + where T3 : new() + where T4 : new() + where T5 : new(); + CreateTablesResult CreateTables (CreateFlags createFlags = CreateFlags.None, params Type[] types); + IEnumerable DeferredQuery (string query, params object[] args) where T : new(); + IEnumerable DeferredQuery (TableMapping map, string query, params object[] args); + int Delete (object objectToDelete); + int Delete (object primaryKey); + int Delete (object primaryKey, TableMapping map); + int DeleteAll (); + int DeleteAll (TableMapping map); + int DropTable (); + int DropTable (TableMapping map); + void EnableLoadExtension (bool enabled); + void EnableWriteAheadLogging (); + int Execute (string query, params object[] args); + T ExecuteScalar (string query, params object[] args); + T Find (object pk) where T : new(); + object Find (object pk, TableMapping map); + T Find (Expression> predicate) where T : new(); + T FindWithQuery (string query, params object[] args) where T : new(); + object FindWithQuery (TableMapping map, string query, params object[] args); + T Get (object pk) where T : new(); + object Get (object pk, TableMapping map); + T Get (Expression> predicate) where T : new(); + TableMapping GetMapping (Type type, CreateFlags createFlags = CreateFlags.None); + TableMapping GetMapping (CreateFlags createFlags = CreateFlags.None); + List GetTableInfo (string tableName); + int Insert (object obj); + int Insert (object obj, Type objType); + int Insert (object obj, string extra); + int Insert (object obj, string extra, Type objType); + int InsertAll (IEnumerable objects, bool runInTransaction = true); + int InsertAll (IEnumerable objects, string extra, bool runInTransaction = true); + int InsertAll (IEnumerable objects, Type objType, bool runInTransaction = true); + int InsertOrReplace (object obj); + int InsertOrReplace (object obj, Type objType); + List Query (string query, params object[] args) where T : new(); + List Query (TableMapping map, string query, params object[] args); + List QueryScalars (string query, params object[] args); + void ReKey (string key); + void ReKey (byte[] key); + void Release (string savepoint); + void Rollback (); + void RollbackTo (string savepoint); + void RunInTransaction (Action action); + string SaveTransactionPoint (); + TableQuery Table () where T : new(); + int Update (object obj); + int Update (object obj, Type objType); + int UpdateAll (IEnumerable objects, bool runInTransaction = true); + } + /// /// An open connection to a SQLite database. /// [Preserve (AllMembers = true)] - public partial class SQLiteConnection : IDisposable + public partial class SQLiteConnection : ISQLiteConnection { private bool _open; private TimeSpan _busyTimeout; @@ -364,7 +463,7 @@ public static string Quote (string unsafeString) /// if your database is encrypted. /// This only has an effect if you are using the SQLCipher nuget package. /// - /// Ecryption key plain text that is converted to the real encryption key using PBKDF2 key derivation + /// Encryption key plain text that is converted to the real encryption key using PBKDF2 key derivation void SetKey (string key) { if (key == null) @@ -379,7 +478,7 @@ void SetKey (string key) /// if your database is encrypted. /// This only has an effect if you are using the SQLCipher nuget package. /// - /// 256-bit (32 byte) ecryption key data + /// 256-bit (32 byte) encryption key data void SetKey (byte[] key) { if (key == null) @@ -390,6 +489,32 @@ void SetKey (byte[] key) ExecuteScalar ("pragma key = \"x'" + s + "'\""); } + /// + /// Change the encryption key for a SQLCipher database with "pragma rekey = ...". + /// + /// Encryption key plain text that is converted to the real encryption key using PBKDF2 key derivation + public void ReKey (string key) + { + if (key == null) + throw new ArgumentNullException(nameof(key)); + var q = Quote(key); + ExecuteScalar("pragma rekey = " + q); + } + + /// + /// Change the encryption key for a SQLCipher database. + /// + /// 256-bit (32 byte) or 384-bit (48 bytes) encryption key data + public void ReKey (byte[] key) + { + if (key == null) + throw new ArgumentNullException(nameof(key)); + if (key.Length != 32 && key.Length != 48) + throw new ArgumentException ("Key must be 32 bytes (256-bit) or 48 bytes (384-bit)", nameof (key)); + var s = String.Join("", key.Select(x => x.ToString("X2"))); + ExecuteScalar("pragma rekey = \"x'" + s + "'\""); + } + /// /// Enable or disable extension loading. /// @@ -1894,7 +2019,7 @@ public int Update (object obj, Type objType) } ps.Add (pk.GetValue (obj)); var q = string.Format ("update \"{0}\" set {1} where \"{2}\" = ? ", map.TableName, string.Join (",", (from c in cols - select "\"" + c.Name + "\" = ? ").ToArray ()), pk.Name); + select "\"" + c.Name + "\" = ? ").ToArray ()), pk.Name); try { rowsAffected = Execute (q, ps.ToArray ()); @@ -1905,7 +2030,7 @@ public int Update (object obj, Type objType) throw NotNullConstraintViolationException.New (ex, map, obj); } - throw ex; + throw; } if (rowsAffected > 0) @@ -2349,7 +2474,7 @@ public class AutoIncrementAttribute : Attribute { } - [AttributeUsage (AttributeTargets.Property)] + [AttributeUsage (AttributeTargets.Property, AllowMultiple = true)] public class IndexedAttribute : Attribute { public string Name { get; set; } @@ -2786,7 +2911,7 @@ public static string SqlDecl (TableMapping.Column p, bool storeDateTimeAsTicks, public static string SqlType (TableMapping.Column p, bool storeDateTimeAsTicks, bool storeTimeSpanAsTicks) { var clrType = p.ColumnType; - if (clrType == typeof (Boolean) || clrType == typeof (Byte) || clrType == typeof (UInt16) || clrType == typeof (SByte) || clrType == typeof (Int16) || clrType == typeof (Int32) || clrType == typeof (UInt32) || clrType == typeof (Int64)) { + if (clrType == typeof (Boolean) || clrType == typeof (Byte) || clrType == typeof (UInt16) || clrType == typeof (SByte) || clrType == typeof (Int16) || clrType == typeof (Int32) || clrType == typeof (UInt32) || clrType == typeof (Int64) || clrType == typeof (UInt64)) { return "integer"; } else if (clrType == typeof (Single) || clrType == typeof (Double) || clrType == typeof (Decimal)) { @@ -3185,7 +3310,7 @@ internal static void BindParameter (Sqlite3Statement stmt, int index, object val else if (value is Boolean) { SQLite3.BindInt (stmt, index, (bool)value ? 1 : 0); } - else if (value is UInt32 || value is Int64) { + else if (value is UInt32 || value is Int64 || value is UInt64) { SQLite3.BindInt64 (stmt, index, Convert.ToInt64 (value)); } else if (value is Single || value is Double || value is Decimal) { @@ -3319,6 +3444,9 @@ object ReadCol (Sqlite3Statement stmt, int index, SQLite3.ColType type, Type clr else if (clrType == typeof (Int64)) { return SQLite3.ColumnInt64 (stmt, index); } + else if (clrType == typeof (UInt64)) { + return (ulong)SQLite3.ColumnInt64 (stmt, index); + } else if (clrType == typeof (UInt32)) { return (uint)SQLite3.ColumnInt64 (stmt, index); } @@ -3463,6 +3591,12 @@ internal static Action GetFastSetter (SQLiteCo return SQLite3.ColumnInt64 (stmt, index); }); } + else if (clrType == typeof(UInt64)) + { + fastSetter = CreateNullableTypedSetterDelegate(column, (stmt, index) => { + return (ulong)SQLite3.ColumnInt64(stmt, index); + }); + } else if (clrType == typeof (UInt32)) { fastSetter = CreateNullableTypedSetterDelegate (column, (stmt, index) => { return (uint)SQLite3.ColumnInt64 (stmt, index); diff --git a/Runtime/sqlite-net/SQLiteAsync.cs b/Runtime/sqlite-net/SQLiteAsync.cs index d297d61..8c102a6 100644 --- a/Runtime/sqlite-net/SQLiteAsync.cs +++ b/Runtime/sqlite-net/SQLiteAsync.cs @@ -1,5 +1,5 @@ // -// Copyright (c) 2012-2021 Krueger Systems, Inc. +// Copyright (c) 2012-2024 Krueger Systems, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -28,12 +28,102 @@ using System.Threading; using System.Threading.Tasks; +#pragma warning disable 1591 // XML Doc Comments + namespace SQLite { + public interface ISQLiteAsyncConnection + { + string DatabasePath { get; } + int LibVersionNumber { get; } + string DateTimeStringFormat { get; } + bool StoreDateTimeAsTicks { get; } + bool StoreTimeSpanAsTicks { get; } + bool Trace { get; set; } + Action Tracer { get; set; } + bool TimeExecution { get; set; } + IEnumerable TableMappings { get; } + + Task BackupAsync (string destinationDatabasePath, string databaseName = "main"); + Task CloseAsync (); + Task CreateIndexAsync (string tableName, string columnName, bool unique = false); + Task CreateIndexAsync (string indexName, string tableName, string columnName, bool unique = false); + Task CreateIndexAsync (string tableName, string[] columnNames, bool unique = false); + Task CreateIndexAsync (string indexName, string tableName, string[] columnNames, bool unique = false); + Task CreateIndexAsync (Expression> property, bool unique = false); + Task CreateTableAsync (CreateFlags createFlags = CreateFlags.None) where T : new(); + Task CreateTableAsync (Type ty, CreateFlags createFlags = CreateFlags.None); + Task CreateTablesAsync (CreateFlags createFlags = CreateFlags.None) + where T : new() + where T2 : new(); + Task CreateTablesAsync (CreateFlags createFlags = CreateFlags.None) + where T : new() + where T2 : new() + where T3 : new(); + Task CreateTablesAsync (CreateFlags createFlags = CreateFlags.None) + where T : new() + where T2 : new() + where T3 : new() + where T4 : new(); + Task CreateTablesAsync (CreateFlags createFlags = CreateFlags.None) + where T : new() + where T2 : new() + where T3 : new() + where T4 : new() + where T5 : new(); + Task CreateTablesAsync (CreateFlags createFlags = CreateFlags.None, params Type[] types); + Task> DeferredQueryAsync (string query, params object[] args) where T : new(); + Task> DeferredQueryAsync (TableMapping map, string query, params object[] args); + Task DeleteAllAsync (); + Task DeleteAllAsync (TableMapping map); + Task DeleteAsync (object objectToDelete); + Task DeleteAsync (object primaryKey); + Task DeleteAsync (object primaryKey, TableMapping map); + Task DropTableAsync () where T : new(); + Task DropTableAsync (TableMapping map); + Task EnableLoadExtensionAsync (bool enabled); + Task EnableWriteAheadLoggingAsync (); + Task ExecuteAsync (string query, params object[] args); + Task ExecuteScalarAsync (string query, params object[] args); + Task FindAsync (object pk) where T : new(); + Task FindAsync (object pk, TableMapping map); + Task FindAsync (Expression> predicate) where T : new(); + Task FindWithQueryAsync (string query, params object[] args) where T : new(); + Task FindWithQueryAsync (TableMapping map, string query, params object[] args); + Task GetAsync (object pk) where T : new(); + Task GetAsync (object pk, TableMapping map); + Task GetAsync (Expression> predicate) where T : new(); + TimeSpan GetBusyTimeout (); + SQLiteConnectionWithLock GetConnection (); + Task GetMappingAsync (Type type, CreateFlags createFlags = CreateFlags.None); + Task GetMappingAsync (CreateFlags createFlags = CreateFlags.None) where T : new(); + Task> GetTableInfoAsync (string tableName); + Task InsertAllAsync (IEnumerable objects, bool runInTransaction = true); + Task InsertAllAsync (IEnumerable objects, string extra, bool runInTransaction = true); + Task InsertAllAsync (IEnumerable objects, Type objType, bool runInTransaction = true); + Task InsertAsync (object obj); + Task InsertAsync (object obj, Type objType); + Task InsertAsync (object obj, string extra); + Task InsertAsync (object obj, string extra, Type objType); + Task InsertOrReplaceAsync (object obj); + Task InsertOrReplaceAsync (object obj, Type objType); + Task> QueryAsync (string query, params object[] args) where T : new(); + Task> QueryAsync (TableMapping map, string query, params object[] args); + Task> QueryScalarsAsync (string query, params object[] args); + Task ReKeyAsync (string key); + Task ReKeyAsync (byte[] key); + Task RunInTransactionAsync (Action action); + Task SetBusyTimeoutAsync (TimeSpan value); + AsyncTableQuery Table () where T : new(); + Task UpdateAllAsync (IEnumerable objects, bool runInTransaction = true); + Task UpdateAsync (object obj); + Task UpdateAsync (object obj, Type objType); + } + /// /// A pooled asynchronous connection to a SQLite database. /// - public partial class SQLiteAsyncConnection + public partial class SQLiteAsyncConnection : ISQLiteAsyncConnection { readonly SQLiteConnectionString _connectionString; @@ -143,7 +233,7 @@ public Task EnableWriteAheadLoggingAsync () /// Whether to store DateTime properties as ticks (true) or strings (false). /// public bool StoreDateTimeAsTicks => GetConnection ().StoreDateTimeAsTicks; - + /// /// Whether to store TimeSpan properties as ticks (true) or strings (false). /// @@ -460,7 +550,7 @@ public Task CreateIndexAsync (Expression> property, bool } /// - /// Inserts the given object and (and updates its + /// Inserts the given object and (and updates its /// auto incremented primary key if it has one). /// /// @@ -1176,6 +1266,30 @@ public Task> DeferredQueryAsync (TableMapping map, string qu { return ReadAsync (conn => (IEnumerable)conn.DeferredQuery (map, query, args).ToList ()); } + + /// + /// Change the encryption key for a SQLCipher database with "pragma rekey = ...". + /// + /// Encryption key plain text that is converted to the real encryption key using PBKDF2 key derivation + public Task ReKeyAsync (string key) + { + return WriteAsync (conn => { + conn.ReKey (key); + return null; + }); + } + + /// + /// Change the encryption key for a SQLCipher database. + /// + /// 256-bit (32 byte) or 384-bit (48 bytes) encryption key data + public Task ReKeyAsync (byte[] key) + { + return WriteAsync (conn => { + conn.ReKey (key); + return null; + }); + } } ///