diff --git a/src/SQLitePCLRaw.core/isqlite3.cs b/src/SQLitePCLRaw.core/isqlite3.cs index 2caa3f86..3f2208d7 100644 --- a/src/SQLitePCLRaw.core/isqlite3.cs +++ b/src/SQLitePCLRaw.core/isqlite3.cs @@ -100,6 +100,8 @@ public interface ISQLite3Provider utf8z sqlite3_sourceid(); long sqlite3_memory_used(); long sqlite3_memory_highwater(int resetFlag); + long sqlite3_soft_heap_limit64(long n); + long sqlite3_hard_heap_limit64(long n); int sqlite3_status(int op, out int current, out int highwater, int resetFlag); int sqlite3_db_readonly(sqlite3 db, utf8z dbName); @@ -253,10 +255,17 @@ public interface ISQLite3Provider int sqlite3_initialize(); int sqlite3_shutdown(); + int sqlite3_limit(sqlite3 db, int id, int newVal); + // sqlite3_config() takes a variable argument list int sqlite3_config(int op); int sqlite3_config(int op, int val); + // sqlite3_db_config() takes a variable argument list + int sqlite3_db_config(sqlite3 db, int op, utf8z val); + int sqlite3_db_config(sqlite3 db, int op, int val, out int result); + int sqlite3_db_config(sqlite3 db, int op, IntPtr ptr, int int0, int int1); + int sqlite3_enable_load_extension(sqlite3 db, int enable); diff --git a/src/SQLitePCLRaw.core/raw.cs b/src/SQLitePCLRaw.core/raw.cs index cc4d6bd9..46b8792a 100644 --- a/src/SQLitePCLRaw.core/raw.cs +++ b/src/SQLitePCLRaw.core/raw.cs @@ -91,6 +91,19 @@ static public string GetNativeLibraryName() public const int SQLITE_DETERMINISTIC = 0x800; + public const int SQLITE_LIMIT_LENGTH = 0; + public const int SQLITE_LIMIT_SQL_LENGTH = 1; + public const int SQLITE_LIMIT_COLUMN = 2; + public const int SQLITE_LIMIT_EXPR_DEPTH = 3; + public const int SQLITE_LIMIT_COMPOUND_SELECT = 4; + public const int SQLITE_LIMIT_VDBE_OP = 5; + public const int SQLITE_LIMIT_FUNCTION_ARG = 6; + public const int SQLITE_LIMIT_ATTACHED = 7; + public const int SQLITE_LIMIT_LIKE_PATTERN_LENGTH = 8; + public const int SQLITE_LIMIT_VARIABLE_NUMBER = 9; + public const int SQLITE_LIMIT_TRIGGER_DEPTH = 10; + public const int SQLITE_LIMIT_WORKER_THREADS = 11; + public const int SQLITE_CONFIG_SINGLETHREAD = 1; /* nil */ public const int SQLITE_CONFIG_MULTITHREAD = 2; /* nil */ public const int SQLITE_CONFIG_SERIALIZED = 3; /* nil */ @@ -113,6 +126,26 @@ static public string GetNativeLibraryName() public const int SQLITE_CONFIG_COVERING_INDEX_SCAN = 20; /* int */ public const int SQLITE_CONFIG_SQLLOG = 21; /* xSqllog, void* */ + public const int SQLITE_DBCONFIG_MAINDBNAME = 1000; /* const char* */ + public const int SQLITE_DBCONFIG_LOOKASIDE = 1001; /* void* int int */ + public const int SQLITE_DBCONFIG_ENABLE_FKEY = 1002; /* int int* */ + public const int SQLITE_DBCONFIG_ENABLE_TRIGGER = 1003; /* int int* */ + public const int SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER = 1004; /* int int* */ + public const int SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION = 1005; /* int int* */ + public const int SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE = 1006; /* int int* */ + public const int SQLITE_DBCONFIG_ENABLE_QPSG = 1007; /* int int* */ + public const int SQLITE_DBCONFIG_TRIGGER_EQP = 1008; /* int int* */ + public const int SQLITE_DBCONFIG_RESET_DATABASE = 1009; /* int int* */ + public const int SQLITE_DBCONFIG_DEFENSIVE = 1010; /* int int* */ + public const int SQLITE_DBCONFIG_WRITABLE_SCHEMA = 1011; /* int int* */ + public const int SQLITE_DBCONFIG_LEGACY_ALTER_TABLE = 1012; /* int int* */ + public const int SQLITE_DBCONFIG_DQS_DML = 1013; /* int int* */ + public const int SQLITE_DBCONFIG_DQS_DDL = 1014; /* int int* */ + public const int SQLITE_DBCONFIG_ENABLE_VIEW = 1015; /* int int* */ + public const int SQLITE_DBCONFIG_LEGACY_FILE_FORMAT = 1016; /* int int* */ + public const int SQLITE_DBCONFIG_TRUSTED_SCHEMA = 1017; /* int int* */ + public const int SQLITE_DBCONFIG_MAX = 1017; /* Largest DBCONFIG */ + public const int SQLITE_OPEN_READONLY = 0x00000001; /* Ok for sqlite3_open_v2() */ public const int SQLITE_OPEN_READWRITE = 0x00000002; /* Ok for sqlite3_open_v2() */ public const int SQLITE_OPEN_CREATE = 0x00000004; /* Ok for sqlite3_open_v2() */ @@ -613,6 +646,11 @@ static public int sqlite3_shutdown() return Provider.sqlite3_shutdown(); } + static public int sqlite3_limit(sqlite3 db, int id, int newVal) + { + return Provider.sqlite3_limit(db, id, newVal); + } + static public int sqlite3_config(int op) { return Provider.sqlite3_config(op); @@ -623,6 +661,21 @@ static public int sqlite3_config(int op, int val) return Provider.sqlite3_config(op, val); } + static public int sqlite3_db_config(sqlite3 db, int op, utf8z val) + { + return Provider.sqlite3_db_config(db, op, val); + } + + static public int sqlite3_db_config(sqlite3 db, int op, int val, out int result) + { + return Provider.sqlite3_db_config(db, op, val, out result); + } + + static public int sqlite3_db_config(sqlite3 db, int op, IntPtr ptr, int int0, int int1) + { + return Provider.sqlite3_db_config(db, op, ptr, int0, int1); + } + static public int sqlite3_enable_load_extension(sqlite3 db, int onoff) { return Provider.sqlite3_enable_load_extension(db, onoff); @@ -643,6 +696,16 @@ static public long sqlite3_memory_highwater(int resetFlag) return Provider.sqlite3_memory_highwater(resetFlag); } + static public long sqlite3_soft_heap_limit64(long n) + { + return Provider.sqlite3_soft_heap_limit64(n); + } + + static public long sqlite3_hard_heap_limit64(long n) + { + return Provider.sqlite3_hard_heap_limit64(n); + } + static public int sqlite3_status(int op, out int current, out int highwater, int resetFlag) { return Provider.sqlite3_status(op, out current, out highwater, resetFlag); diff --git a/src/common/tests_xunit.cs b/src/common/tests_xunit.cs index 45863271..078a756e 100644 --- a/src/common/tests_xunit.cs +++ b/src/common/tests_xunit.cs @@ -74,6 +74,23 @@ public void test_call_sqlite3_enable_load_extension() } } + [Fact] + public void test_call_sqlite3_limit() + { + using (sqlite3 db = ugly.open(":memory:")) + { + var query = raw.sqlite3_limit(db, raw.SQLITE_LIMIT_LENGTH, -1); + Assert.True(query >= 0); + + const int limit = 10240; + var current = raw.sqlite3_limit(db, raw.SQLITE_LIMIT_LENGTH, limit); + Assert.Equal(query, current); + + query = raw.sqlite3_limit(db, raw.SQLITE_LIMIT_LENGTH, -1); + Assert.Equal(limit, query); + } + } + [Fact] public void test_authorizer_with_unregister() { @@ -771,12 +788,44 @@ public void test_sqlite3_memory() { long memory_used = raw.sqlite3_memory_used(); long memory_highwater = raw.sqlite3_memory_highwater(0); -#if not + #if not // these asserts fail on the iOS builtin sqlite. not sure // why. not sure the asserts are worth doing anyway. Assert.True(memory_used > 0); Assert.True(memory_highwater >= memory_used); -#endif + #endif + } + + [Fact] + public void test_sqlite3_soft_heap_limit64() + { + var query = raw.sqlite3_soft_heap_limit64(-1); + Assert.True(query >= 0); + + var limit = query + 10L * 1024 * 1024; + var current = raw.sqlite3_soft_heap_limit64(limit); + Assert.Equal(query, current); + + query = raw.sqlite3_soft_heap_limit64(-1); + Assert.Equal(limit, query); + } + + [Fact] + public void sqlite3_hard_heap_limit64() + { + var version = raw.sqlite3_libversion_number(); + + if (version < 3031001) return; // Added in 3.31.1: https://sqlite.org/releaselog/3_31_1.html + + var query = raw.sqlite3_hard_heap_limit64(-1); + Assert.True(query >= 0); + + var limit = query + 10L * 1024 * 1024; + var current = raw.sqlite3_hard_heap_limit64(limit); + Assert.Equal(query, current); + + query = raw.sqlite3_hard_heap_limit64(-1); + Assert.Equal(limit, query); } [Fact] @@ -1346,7 +1395,7 @@ public void test_create_table_explicit_close() [Fact] public void test_create_table_explicit_close_v2() { -#if not + #if not // maybe we should just let this fail so we can // see the differences between running against the built-in // sqlite vs a recent version? @@ -1354,7 +1403,7 @@ public void test_create_table_explicit_close_v2() { return; } -#endif + #endif sqlite3 db = ugly.open(":memory:"); db.exec("CREATE TABLE foo (x int);"); db.close_v2(); @@ -1486,7 +1535,7 @@ public void test_stmt_isexplain() Assert.Equal(0, stmt.stmt_isexplain()); } - + sql = "EXPLAIN SELECT x FROM foo"; using (sqlite3_stmt stmt = db.prepare(sql)) { @@ -1494,7 +1543,7 @@ public void test_stmt_isexplain() Assert.Equal(1, stmt.stmt_isexplain()); } - + sql = "EXPLAIN QUERY PLAN SELECT x FROM foo"; using (sqlite3_stmt stmt = db.prepare(sql)) { @@ -1645,12 +1694,12 @@ public void test_column_origin() db.exec("CREATE TABLE foo (x int, v int, t text, d real, b blob, q blob);"); byte[] blob = db.query_scalar("SELECT randomblob(5);"); db.exec("INSERT INTO foo (x,v,t,d,b,q) VALUES (?,?,?,?,?,?)", 32, 44, "hello", 3.14, blob, null); -#if not + #if not // maybe we should just let this fail so we can // see the differences between running against the built-in // sqlite vs a recent version? if (1 == raw.sqlite3_compileoption_used("ENABLE_COLUMN_METADATA")) -#endif + #endif { using (sqlite3_stmt stmt = db.prepare("SELECT x AS mario FROM foo;")) { @@ -1696,7 +1745,7 @@ public void test_wal() Assert.Equal(2, logSize); Assert.Equal(2, framesCheckPointed); - // Set autocheckpoint to 1 so that regardless of the number of + // Set autocheckpoint to 1 so that regardless of the number of // commits, explicit checkpoints only checkpoint the last update. db.wal_autocheckpoint(1); @@ -2759,7 +2808,7 @@ public void test_sum_plus_count() [Order(0)] public class class_test_sqlite3_config { - // this test class is special. + // this test class is special. // it needs to run first, before anything else. // it is marked with attributes so that fake_xunit // will find it and run it, but real xunit will ignore it. @@ -2839,6 +2888,45 @@ public void test_call_sqlite3_config_after_shutdown() } + [Collection("Init")] + public class class_test_sqlite3_db_config + { + [Fact] + public void test_call_sqlite3_db_config_3() + { + using (sqlite3 db = ugly.open(":memory:")) + { + var rc = raw.sqlite3_db_config(db, raw.SQLITE_DBCONFIG_MAINDBNAME, utf8z.FromString("new_main")); + + Assert.Equal(raw.SQLITE_OK, rc); + } + } + + [Fact] + public void test_call_sqlite3_db_config_4() + { + using (sqlite3 db = ugly.open(":memory:")) + { + int disabled = 0; + var rc = raw.sqlite3_db_config(db, raw.SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, 1, out disabled); + + Assert.Equal(1, disabled); + Assert.Equal(raw.SQLITE_OK, rc); + } + } + + [Fact] + public void test_call_sqlite3_db_config_5() + { + using (sqlite3 db = ugly.open(":memory:")) + { + var rc = raw.sqlite3_db_config(db, raw.SQLITE_DBCONFIG_LOOKASIDE, IntPtr.Zero, 256, 16); + + Assert.Equal(raw.SQLITE_OK, rc); + } + } + } + [Collection("Init")] public class class_test_hooks { diff --git a/src/providers/provider.tt b/src/providers/provider.tt index e779735f..d21fd0a5 100644 --- a/src/providers/provider.tt +++ b/src/providers/provider.tt @@ -760,6 +760,34 @@ namespace SQLitePCL return NativeMethods.sqlite3_config_int(op, val); } + unsafe int ISQLite3Provider.sqlite3_db_config(sqlite3 db, int op, utf8z val) + { + fixed (byte* p_val = val) + { + return NativeMethods.sqlite3_db_config_charptr(db, op, p_val); + } + } + + unsafe int ISQLite3Provider.sqlite3_db_config(sqlite3 db, int op, int val, out int result) + { + int out_result = 0; + int native_result = NativeMethods.sqlite3_db_config_int_outint(db, op, val, &out_result); + + result = out_result; + + return native_result; + } + + <#= KIND=="cil"?"unsafe ":"" #> int ISQLite3Provider.sqlite3_db_config(sqlite3 db, int op, IntPtr ptr, int int0, int int1) + { + return NativeMethods.sqlite3_db_config_intptr_int_int(db, op, ptr, int0, int1); + } + + int ISQLite3Provider.sqlite3_limit(sqlite3 db, int id, int newVal) + { + return NativeMethods.sqlite3_limit(db, id, newVal); + } + <#= KIND=="cil"?"unsafe ":"" #>int ISQLite3Provider.sqlite3_initialize() { return NativeMethods.sqlite3_initialize(); @@ -1290,6 +1318,16 @@ namespace SQLitePCL return NativeMethods.sqlite3_memory_highwater(resetFlag); } + long ISQLite3Provider.sqlite3_soft_heap_limit64(long n) + { + return NativeMethods.sqlite3_soft_heap_limit64(n); + } + + long ISQLite3Provider.sqlite3_hard_heap_limit64(long n) + { + return NativeMethods.sqlite3_hard_heap_limit64(n); + } + int ISQLite3Provider.sqlite3_status(int op, out int current, out int highwater, int resetFlag) { return NativeMethods.sqlite3_status(op, out current, out highwater, resetFlag); @@ -2006,6 +2044,15 @@ namespace SQLitePCL new Parm("int", "enable"), } ), + new Function( + "int", + "sqlite3_limit", + new Parm[] { + new Parm("sqlite3", "db"), + new Parm("int", "id"), + new Parm("int", "newVal"), + } + ), new Function( "int", "sqlite3_initialize", @@ -2140,6 +2187,20 @@ namespace SQLitePCL new Parm("int", "resetFlag"), } ), + new Function( + "long", + "sqlite3_soft_heap_limit64", + new Parm[] { + new Parm("long", "n"), + } + ), + new Function( + "long", + "sqlite3_hard_heap_limit64", + new Parm[] { + new Parm("long", "n"), + } + ), new Function( "int", "sqlite3_status", @@ -2569,6 +2630,59 @@ namespace SQLitePCL .SetEntryPoint("sqlite3_config") .SetVarArgs(true) , + // Since sqlite3_db_config() takes a variable argument list, we have to overload declarations + // for all possible calls that we want to use. + new Function( + "int", + "sqlite3_db_config_charptr", + new Parm[] { + new Parm("sqlite3", "db"), + new Parm("int", "op"), + } + ) + .SetExtraParms( + new Parm[] { + new Parm("byte*", "val"), + } + ) + .SetEntryPoint("sqlite3_db_config") + .SetVarArgs(true) + , + new Function( + "int", + "sqlite3_db_config_int_outint", + new Parm[] { + new Parm("sqlite3", "db"), + new Parm("int", "op"), + } + ) + .SetExtraParms( + new Parm[] { + new Parm("int", "val"), + new Parm("int*", "result"), + } + ) + .SetEntryPoint("sqlite3_db_config") + .SetVarArgs(true) + , + new Function( + "int", + "sqlite3_db_config_intptr_int_int", + new Parm[] { + new Parm("sqlite3", "db"), + new Parm("int", "op"), + } + ) + .SetExtraParms( + new Parm[] { + new Parm("IntPtr", "ptr"), + new Parm("int", "int0"), + new Parm("int", "int1"), + } + ) + .SetEntryPoint("sqlite3_db_config") + .SetVarArgs(true) + , new Function( "int", "sqlite3_create_collation", diff --git a/todo.txt b/todo.txt index 889cfd8a..ca6087de 100644 --- a/todo.txt +++ b/todo.txt @@ -346,19 +346,13 @@ unprotected sqlite3_value: sqlite3_column_value, sqlite3_bind_value, sqlite3_re sqlite3_create_module -sqlite3_db_config - sqlite3_db_mutex sqlite3_get_auxdata sqlite3_set_auxdata -sqlite3_limit - sqlite3_randomness -sqlite3_soft_heap_limit64 - sqlite3_wal_autocheckpoint sqlite3_wal_checkpoint sqlite3_wal_checkpoint_v2