aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/jni/src/c/sqlite3-jni.c8
-rw-r--r--ext/jni/src/org/sqlite/jni/Sqlite.java126
-rw-r--r--ext/jni/src/org/sqlite/jni/SqliteException.java14
-rw-r--r--ext/jni/src/org/sqlite/jni/Tester2.java47
-rw-r--r--ext/wasm/api/sqlite3-wasm.c8
-rw-r--r--manifest26
-rw-r--r--manifest.uuid2
-rw-r--r--src/malloc.c2
-rw-r--r--src/pager.c2
-rw-r--r--src/shell.c.in6
10 files changed, 211 insertions, 30 deletions
diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c
index ab8dac644..7afc9a0f0 100644
--- a/ext/jni/src/c/sqlite3-jni.c
+++ b/ext/jni/src/c/sqlite3-jni.c
@@ -43,6 +43,14 @@
/**********************************************************************/
/* SQLITE_ENABLE_... */
+/*
+** Unconditionally enable API_ARMOR in the JNI build. It ensures that
+** public APIs behave predictable in the face of passing illegal NULLs
+** or ranges which might otherwise invoke undefined behavior.
+*/
+#undef SQLITE_ENABLE_API_ARMOR
+#define SQLITE_ENABLE_API_ARMOR 1
+
#ifndef SQLITE_ENABLE_BYTECODE_VTAB
# define SQLITE_ENABLE_BYTECODE_VTAB 1
#endif
diff --git a/ext/jni/src/org/sqlite/jni/Sqlite.java b/ext/jni/src/org/sqlite/jni/Sqlite.java
index b964c57b3..5c2c45629 100644
--- a/ext/jni/src/org/sqlite/jni/Sqlite.java
+++ b/ext/jni/src/org/sqlite/jni/Sqlite.java
@@ -12,6 +12,7 @@
** This file is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni;
+import java.nio.charset.StandardCharsets;
import static org.sqlite.jni.CApi.*;
/**
@@ -22,7 +23,7 @@ import static org.sqlite.jni.CApi.*;
individual instances are tied to a specific database connection.
*/
public final class Sqlite implements AutoCloseable {
- private sqlite3 db = null;
+ private sqlite3 db;
//! Used only by the open() factory functions.
private Sqlite(sqlite3 db){
@@ -33,6 +34,9 @@ public final class Sqlite implements AutoCloseable {
Returns a newly-opened db connection or throws SqliteException if
opening fails. All arguments are as documented for
sqlite3_open_v2().
+
+ Design question: do we want static factory functions or should
+ this be reformulated as a constructor?
*/
public static Sqlite open(String filename, int flags, String vfsName){
final OutputPointer.sqlite3 out = new OutputPointer.sqlite3();
@@ -40,7 +44,9 @@ public final class Sqlite implements AutoCloseable {
final sqlite3 n = out.take();
if( 0!=rc ){
if( null==n ) throw new SqliteException(rc);
- else throw new SqliteException(n);
+ final SqliteException ex = new SqliteException(n);
+ n.close();
+ throw ex;
}
return new Sqlite(n);
}
@@ -64,6 +70,120 @@ public final class Sqlite implements AutoCloseable {
Returns this object's underlying native db handle, or null if
this instance has been closed.
*/
- sqlite3 dbHandle(){ return this.db; }
+ sqlite3 nativeHandle(){ return this.db; }
+
+ private void affirmOpen(){
+ if( null==db || 0==db.getNativePointer() ){
+ throw new IllegalArgumentException("This database instance is closed.");
+ }
+ }
+
+ // private byte[] stringToUtf8(String s){
+ // return s==null ? null : s.getBytes(StandardCharsets.UTF_8);
+ // }
+
+ private void affirmRcOk(int rc){
+ if( 0!=rc ){
+ throw new SqliteException(db);
+ }
+ }
+
+ public final class Stmt implements AutoCloseable {
+ private Sqlite _db = null;
+ private sqlite3_stmt stmt = null;
+ /** Only called by the prepare() factory functions. */
+ Stmt(Sqlite db, sqlite3_stmt stmt){
+ this._db = db;
+ this.stmt = stmt;
+ }
+
+ sqlite3_stmt nativeHandle(){
+ return stmt;
+ }
+
+ private sqlite3_stmt affirmOpen(){
+ if( null==stmt || 0==stmt.getNativePointer() ){
+ throw new IllegalArgumentException("This Stmt has been finalized.");
+ }
+ return stmt;
+ }
+
+ /**
+ Corresponds to sqlite3_finalize(), but we cannot override the
+ name finalize() here because this one requires a different
+ signature. We do not throw on error here because "destructors
+ do not throw." If it returns non-0, the object is still
+ finalized.
+ */
+ public int finalizeStmt(){
+ int rc = 0;
+ if( null!=stmt ){
+ sqlite3_finalize(stmt);
+ stmt = null;
+ }
+ return rc;
+ }
+
+ @Override public void close(){
+ finalizeStmt();
+ }
+
+ /**
+ Throws if rc is any value other than 0, SQLITE_ROW, or
+ SQLITE_DONE, else returns rc.
+ */
+ private int checkRc(int rc){
+ switch(rc){
+ case 0:
+ case SQLITE_ROW:
+ case SQLITE_DONE: return rc;
+ default:
+ throw new SqliteException(this);
+ }
+ }
+
+ /**
+ Works like sqlite3_step() but throws SqliteException for any
+ result other than 0, SQLITE_ROW, or SQLITE_DONE.
+ */
+ public int step(){
+ return checkRc(sqlite3_step(affirmOpen()));
+ }
+
+ public Sqlite db(){ return this._db; }
+
+ /**
+ Works like sqlite3_reset() but throws on error.
+ */
+ public void reset(){
+ checkRc(sqlite3_reset(affirmOpen()));
+ }
+
+ public void clearBindings(){
+ sqlite3_clear_bindings( affirmOpen() );
+ }
+ }
+
+
+ /**
+ prepare() TODOs include:
+
+ - overloads taking byte[] and ByteBuffer.
+
+ - multi-statement processing, like CApi.sqlite3_prepare_multi()
+ but using a callback specific to the higher-level Stmt class
+ rather than the sqlite3_stmt class.
+ */
+ public Stmt prepare(String sql, int prepFlags){
+ affirmOpen();
+ final OutputPointer.sqlite3_stmt out = new OutputPointer.sqlite3_stmt();
+ final int rc = sqlite3_prepare_v3(this.db, sql, prepFlags, out);
+ affirmRcOk(rc);
+ return new Stmt(this, out.take());
+ }
+
+ public Stmt prepare(String sql){
+ return prepare(sql, 0);
+ }
}
diff --git a/ext/jni/src/org/sqlite/jni/SqliteException.java b/ext/jni/src/org/sqlite/jni/SqliteException.java
index 3da5d8c58..c15cb3491 100644
--- a/ext/jni/src/org/sqlite/jni/SqliteException.java
+++ b/ext/jni/src/org/sqlite/jni/SqliteException.java
@@ -46,7 +46,12 @@ public final class SqliteException extends java.lang.RuntimeException {
/**
Records the current error state of db (which must not be null and
- must refer to an opened db object) then closes it.
+ must refer to an opened db object). Note that this does NOT close
+ the db.
+
+ Design note: closing the db on error is likely only useful during
+ a failed db-open operation, and the place(s) where that can
+ happen are inside this library, not client-level code.
*/
public SqliteException(sqlite3 db){
super(sqlite3_errmsg(db));
@@ -54,7 +59,6 @@ public final class SqliteException extends java.lang.RuntimeException {
xerrCode = sqlite3_extended_errcode(db);
errOffset = sqlite3_error_offset(db);
sysErrno = sqlite3_system_errno(db);
- db.close();
}
/**
@@ -62,7 +66,11 @@ public final class SqliteException extends java.lang.RuntimeException {
refer to an open database) then closes it.
*/
public SqliteException(Sqlite db){
- this(db.dbHandle());
+ this(db.nativeHandle());
+ }
+
+ public SqliteException(Sqlite.Stmt stmt){
+ this( stmt.db() );
}
public int errcode(){ return errCode; }
diff --git a/ext/jni/src/org/sqlite/jni/Tester2.java b/ext/jni/src/org/sqlite/jni/Tester2.java
index b7701f1a9..e75f56e06 100644
--- a/ext/jni/src/org/sqlite/jni/Tester2.java
+++ b/ext/jni/src/org/sqlite/jni/Tester2.java
@@ -126,16 +126,51 @@ public class Tester2 implements Runnable {
}
}
+ Sqlite openDb(String name){
+ return Sqlite.open(name, SQLITE_OPEN_READWRITE|
+ SQLITE_OPEN_CREATE|
+ SQLITE_OPEN_EXRESCODE);
+ }
+
+ Sqlite openDb(){ return openDb(":memory:"); }
+
void testOpenDb1(){
- Sqlite db = Sqlite.open(":memory:");
- affirm( 0!=db.dbHandle().getNativePointer() );
+ Sqlite db = openDb();
+ affirm( 0!=db.nativeHandle().getNativePointer() );
db.close();
- affirm( null==db.dbHandle() );
+ affirm( null==db.nativeHandle() );
+
+ SqliteException ex = null;
+ try {
+ db = openDb("/no/such/dir/.../probably");
+ }catch(SqliteException e){
+ ex = e;
+ }
+ affirm( ex!=null );
+ affirm( ex.errcode() != 0 );
+ affirm( ex.extendedErrcode() != 0 );
+ affirm( ex.errorOffset() < 0 );
+ // there's no reliable way to predict what ex.systemErrno() might be
}
- @ManualTest /* because we only want to run this test on demand */
- private void testFail(){
- affirm( false, "Intentional failure." );
+ void testPrepare1(){
+ try (Sqlite db = openDb()) {
+ Sqlite.Stmt stmt = db.prepare("SELECT 1");
+ affirm( null!=stmt.nativeHandle() );
+ affirm( SQLITE_ROW == stmt.step() );
+ affirm( SQLITE_DONE == stmt.step() );
+ stmt.reset();
+ affirm( SQLITE_ROW == stmt.step() );
+ affirm( SQLITE_DONE == stmt.step() );
+ affirm( 0 == stmt.finalizeStmt() );
+ affirm( null==stmt.nativeHandle() );
+
+ stmt = db.prepare("SELECT 1");
+ affirm( SQLITE_ROW == stmt.step() );
+ affirm( 0 == stmt.finalizeStmt() )
+ /* getting a non-0 out of sqlite3_finalize() is tricky */;
+ affirm( null==stmt.nativeHandle() );
+ }
}
private void runTests(boolean fromThread) throws Exception {
diff --git a/ext/wasm/api/sqlite3-wasm.c b/ext/wasm/api/sqlite3-wasm.c
index db77010d9..88a679c51 100644
--- a/ext/wasm/api/sqlite3-wasm.c
+++ b/ext/wasm/api/sqlite3-wasm.c
@@ -84,6 +84,14 @@
/**********************************************************************/
/* SQLITE_ENABLE_... */
+/*
+** Unconditionally enable API_ARMOR in the WASM build. It ensures that
+** public APIs behave predictable in the face of passing illegal NULLs
+** or ranges which might otherwise invoke undefined behavior.
+*/
+#undef SQLITE_ENABLE_API_ARMOR
+#define SQLITE_ENABLE_API_ARMOR 1
+
#ifndef SQLITE_ENABLE_BYTECODE_VTAB
# define SQLITE_ENABLE_BYTECODE_VTAB 1
#endif
diff --git a/manifest b/manifest
index 29b386a1a..addf7011f 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sthe\suse\sof\san\suninitialized\svalue\sthat\soccurs\swhen\sdoing\sa\sjson_insert()\nof\sa\sstring\svalue\sthat\scontains\sembedded\sU+0000\scharacters.
-D 2023-10-11T17:21:16.637
+C Merge\sfixes\sfrom\strunk\sinto\sthe\sjsonb\sbranch.
+D 2023-10-12T17:47:50.731
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -238,7 +238,7 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3
F ext/jni/GNUmakefile 6da240c9a11701f3ed569384cd15ef611e8b3c5e3897d265923b14bf0e1eb272
F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4
F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
-F ext/jni/src/c/sqlite3-jni.c fb8f178d27df828e3c797b4427a0a20545b44f5147ce38d09ce9b465be5a840b
+F ext/jni/src/c/sqlite3-jni.c bf432771fbc84da2b5f4037e0bcf20757548aac2fa782b272c4894a9c279964a
F ext/jni/src/c/sqlite3-jni.h be1fdff7ab3a2bb357197271c8ac5d2bf6ff59380c106dde3a13be88724bad22
F ext/jni/src/org/sqlite/jni/AbstractCollationCallback.java 95e88ba04f4aac51ffec65693e878e234088b2f21b387f4e4285c8b72b33e436
F ext/jni/src/org/sqlite/jni/AggregateFunction.java 7312486bc65fecdb91753c0a4515799194e031f45edbe16a6373cea18f404dc4
@@ -262,11 +262,11 @@ F ext/jni/src/org/sqlite/jni/RollbackHookCallback.java ec6cd96bff5d3bc5af079cbf1
F ext/jni/src/org/sqlite/jni/SQLFunction.java 544a875d33fd160467d82e2397ac33157b29971d715a821a4fad3c899113ee8c
F ext/jni/src/org/sqlite/jni/SQLTester.java d246c67f93e2fa2603bd106dbb3246ea725c987dffd6e5d42214ae262f750c68
F ext/jni/src/org/sqlite/jni/ScalarFunction.java 6d387bb499fbe3bc13c53315335233dbf6a0c711e8fa7c521683219b041c614c
-F ext/jni/src/org/sqlite/jni/Sqlite.java 713f973764de9f918500b8723f347e67d29da226ad34b18e1f37865397c0efcb
-F ext/jni/src/org/sqlite/jni/SqliteException.java f5d17a10202c0983fb074f66a0b48cf1e573b1da2eaeda679825e3edc1829706
+F ext/jni/src/org/sqlite/jni/Sqlite.java 1617ea2bf3dfa493b7f031a3187cbfd6837c39bc1d406c4b3edcf9aab941639d
+F ext/jni/src/org/sqlite/jni/SqliteException.java e17500e8bca2c68c260d8d0163fe4b7dc8bd0b1b90211201325c4a5566ce75ca
F ext/jni/src/org/sqlite/jni/TableColumnMetadata.java 54511b4297fa28dcb3f49b24035e34ced10e3fd44fd0e458e784f4d6b0096dab
F ext/jni/src/org/sqlite/jni/Tester1.java f7b85fe24cf6c3e43bdf7e390617657e8137359f804d76921829c2a8c41b6df1
-F ext/jni/src/org/sqlite/jni/Tester2.java 3e7b3c05c08bdbf899684074f095724e1853dc16912dfb53306a03e5c4cbd614
+F ext/jni/src/org/sqlite/jni/Tester2.java 70e005d41060e398ec0f69bd39a8e1c376fd51f81629cf25e877889ec9cb6ec6
F ext/jni/src/org/sqlite/jni/TesterFts5.java d60fe9944a81156b3b5325dd1b0e8e92a1547468f39fd1266d06f7bb6a95fa70
F ext/jni/src/org/sqlite/jni/TraceV2Callback.java f157edd9c72e7d2243c169061487cd7bb51a0d50f3ac976dbcbbacf748ab1fc2
F ext/jni/src/org/sqlite/jni/UpdateHookCallback.java 959d4677a857c9079c6e96ddd10918b946d68359af6252b6f284379069ea3d27
@@ -581,7 +581,7 @@ F ext/wasm/api/sqlite3-opfs-async-proxy.js 8cf8a897726f14071fae6be6648125162b256
F ext/wasm/api/sqlite3-v-helper.js 7daa0eab0a513a25b05e9abae7b5beaaa39209b3ed12f86aeae9ef8d2719ed25
F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js f7c965cf9ac0b66a538cd8f6c156f3f2a235e089821ca78cabd7bce41ce16bf7
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 46c4afa6c50d7369252c104f274ad977a97e91ccfafc38b400fe36e90bdda88e
-F ext/wasm/api/sqlite3-wasm.c 65d60439671e24d50d9119ca805ac1c68fb36129e164377eb46f8d037bd88b07
+F ext/wasm/api/sqlite3-wasm.c c8c5b81b838cef2053b1eb6e7a79c44a2caedcf0c9e6b0d12a45d73ce0617be0
F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js bc06df0d599e625bde6a10a394e326dc68da9ff07fa5404354580f81566e591f
F ext/wasm/api/sqlite3-worker1.c-pp.js da509469755035e919c015deea41b4514b5e84c12a1332e6cc8d42cb2cc1fb75
F ext/wasm/batch-runner.html 4deeed44fe41496dc6898d9fb17938ea3291f40f4bfb977e29d0cef96fbbe4c8
@@ -678,7 +678,7 @@ F src/json.c fc8783af356d27cfdf14a583e5a7809394269763384cde979c0825a29f13e1d6
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 98cfba10989b3da6f1807ad42444017742db7f100a54f1032af7a8b1295912c0
F src/main.c 618aeb399e993cf561864f4b0cf6a331ee4f355cf663635f8d9da3193a46aa40
-F src/malloc.c 47b82c5daad557d9b963e3873e99c22570fb470719082c6658bf64e3012f7d23
+F src/malloc.c f016922435dc7d1f1f5083a03338a3e91f8c67ce2c5bdcfa4cdef62e612f5fcc
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
F src/mem2.c c8bfc9446fd0798bddd495eb5d9dbafa7d4b7287d8c22d50a83ac9daa26d8a75
@@ -701,7 +701,7 @@ F src/os_setup.h 6011ad7af5db4e05155f385eb3a9b4470688de6f65d6166b8956e58a3d87210
F src/os_unix.c 2e8b12107f75d1bd16412f312b4c5d5103191807a37836d3b81beb26436ad81b
F src/os_win.c 4a50a154aeebc66a1f8fb79c1ff6dd5fe3d005556533361e0d460d41cb6a45a8
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
-F src/pager.c bbd9b93c014679d8148235cc42b73bebda3f598d4f63a63cf7723ddf3087fd58
+F src/pager.c 4aa388e47138551c83ae265e2efd4e01f0aa5afb6a958f45579658847b3430ff
F src/pager.h f4d33fec8052603758792045493423b8871a996da2d0973927b7d36cd6070473
F src/parse.y aeb7760d41cfa86465e3adba506500c021597049fd55f82a30e5b7045862c28c
F src/pcache.c 040b165f30622a21b7a9a77c6f2e4877a32fb7f22d4c7f0d2a6fa6833a156a75
@@ -715,7 +715,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
F src/resolve.c 0c3046b88901336709cd09f474303a16fc54bce13a2befcab66d0fa6b44ca869
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c 7f9155185be78902818b21c2cd3e33f01b4306279a15d6719eb1bbb9779034aa
-F src/shell.c.in 6d26db96a7d53e7b499c8ae2f794dfc020a96e64d5757aebd0e4cf743b6de031
+F src/shell.c.in cf0a3387c5bb05ca2fe6073fa7df21aaa11e749ca5b3846b80b586a447e728aa
F src/sqlite.h.in 4f39f61c35348f0c56dd2c7a2294d1f0564389a0086dab80ce0960bfd772dc1b
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 2f30b2671f4c03cd27a43f039e11251391066c97d11385f5f963bb40b03038ac
@@ -2129,8 +2129,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P fb81d570a3d9b8f55e9f278d5240605c5d0f3c5abde51550797999d03cf193a7
-R d78e19c15a2441ced442368555cb1a45
+P fc5ee9e51ad4556af526a6cefca5ae5a3b1b7affc4edf09832491d6b4f4ba366 29937081a986d88f495ad48748c35ff5829f0ac31dd4ad3e48d180ae2fcb9a0c
+R 34f098f7c4eafcb6644778066535a3a0
U drh
-Z 3bf927da2cbd54464f0b6fb8e90f7a35
+Z dd04631a3fb3a59b7149d92d361ffe54
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index 0fb4b428b..643a123ac 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-fc5ee9e51ad4556af526a6cefca5ae5a3b1b7affc4edf09832491d6b4f4ba366 \ No newline at end of file
+a760bd7bcc63aac41c989bb5f4fbc927f9a93fe9c0aa18da2f0131483ec3f189 \ No newline at end of file
diff --git a/src/malloc.c b/src/malloc.c
index 48c460060..356750682 100644
--- a/src/malloc.c
+++ b/src/malloc.c
@@ -896,5 +896,5 @@ int sqlite3ApiExit(sqlite3* db, int rc){
if( db->mallocFailed || rc ){
return apiHandleError(db, rc);
}
- return rc & db->errMask;
+ return 0;
}
diff --git a/src/pager.c b/src/pager.c
index af21ad611..1423b6654 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -7369,7 +7369,7 @@ int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
}
assert( state==pPager->eState );
}
- }else if( eMode==PAGER_JOURNALMODE_OFF ){
+ }else if( eMode==PAGER_JOURNALMODE_OFF || eMode==PAGER_JOURNALMODE_MEMORY ){
sqlite3OsClose(pPager->jfd);
}
}
diff --git a/src/shell.c.in b/src/shell.c.in
index 1699820a6..beea0f9b0 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -8772,8 +8772,10 @@ static int do_meta_command(char *zLine, ShellState *p){
"SELECT rowid FROM sqlite_schema"
" WHERE name GLOB 'sqlite_stat[134]'",
-1, &pStmt, 0);
- doStats = sqlite3_step(pStmt)==SQLITE_ROW;
- sqlite3_finalize(pStmt);
+ if( rc==SQLITE_OK ){
+ doStats = sqlite3_step(pStmt)==SQLITE_ROW;
+ sqlite3_finalize(pStmt);
+ }
}
if( doStats==0 ){
raw_printf(p->out, "/* No STAT tables available */\n");