From 307f95c1e4a2bd4de776c94880e4ae4152288146 Mon Sep 17 00:00:00 2001 From: stephan Date: Sat, 11 Nov 2023 14:43:50 +0000 Subject: [PATCH 1/2] Do not cache a statement's column count in the JNI wrapper1 API because an ALTER TABLE via another statement may invalidate it, as reported in [forum:6d80efd58d4591c7|forum post 6d80efd58d4591c7]. FossilOrigin-Name: a6ab88e9a67f23ab7885402776282b94033cb48dbe34d4d18356e4dc22aae7cd --- ext/jni/src/org/sqlite/jni/capi/CApi.java | 2 +- .../src/org/sqlite/jni/wrapper1/Sqlite.java | 29 +++++++++---------- manifest | 16 +++++----- manifest.uuid | 2 +- 4 files changed, 24 insertions(+), 25 deletions(-) diff --git a/ext/jni/src/org/sqlite/jni/capi/CApi.java b/ext/jni/src/org/sqlite/jni/capi/CApi.java index 07ca851ce5..2dc238ce3e 100644 --- a/ext/jni/src/org/sqlite/jni/capi/CApi.java +++ b/ext/jni/src/org/sqlite/jni/capi/CApi.java @@ -69,7 +69,7 @@ import java.util.Arrays; NUL-terminated, and conversion to a Java byte array must sometimes be careful to add one. Functions which take a length do not require this so long as the length is provided. Search the CApi class - for "\0" for many examples. + for "\0" for examples. diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java index e61b7e59dd..0d7e2e3922 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java @@ -937,21 +937,11 @@ public final class Sqlite implements AutoCloseable { public static final class Stmt implements AutoCloseable { private Sqlite _db = null; private sqlite3_stmt stmt = null; - /** - We save the result column count in order to prevent having to - call into C to fetch that value every time we need to check - that value for the columnXyz() methods. - - Design note: if this is final then we cannot zero it in - finalizeStmt(). - */ - private int resultColCount; /** Only called by the prepare() factory functions. */ Stmt(Sqlite db, sqlite3_stmt stmt){ this._db = db; this.stmt = stmt; - this.resultColCount = CApi.sqlite3_column_count(stmt); synchronized(nativeToWrapper){ nativeToWrapper.put(this.stmt, this); } @@ -986,10 +976,10 @@ public final class Sqlite implements AutoCloseable { return stmt; } - /** Throws if n is out of range of this.resultColCount. Intended - to be used by the columnXyz() methods. */ + /** Throws if n is out of range of this statement's result column + count. Intended to be used by the columnXyz() methods. */ private sqlite3_stmt checkColIndex(int n){ - if(n<0 || n>=this.resultColCount){ + if(null==stmt || n<0 || n>=columnCount()){ throw new IllegalArgumentException("Column index "+n+" is out of range."); } return thisStmt(); @@ -1013,7 +1003,6 @@ public final class Sqlite implements AutoCloseable { CApi.sqlite3_finalize(stmt); stmt = null; _db = null; - resultColCount = 0; } return rc; } @@ -1184,8 +1173,18 @@ public final class Sqlite implements AutoCloseable { public String columnDeclType(int ndx){ return CApi.sqlite3_column_decltype( checkColIndex(ndx), ndx ); } + /** + Analog to sqlite3_column_count() but throws if this statement + has been finalized. + */ public int columnCount(){ - return resultColCount; + /* We cannot reliably cache the column count in a class + member because an ALTER TABLE from a separate statement + can invalidate that count and we have no way, short of + installing a COMMIT handler or the like, of knowing when + to re-read it. We cannot install such a handler without + interfering with a client's ability to do so. */ + return CApi.sqlite3_column_count(thisStmt()); } public int columnDataCount(){ return CApi.sqlite3_data_count( thisStmt() ); diff --git a/manifest b/manifest index f1683dfa58..8a365b54e0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sanother\sproblem\swith\smixed\sjoin\stypes\sand\sthe\sRIGHT\sJOIN\sstrength-reduction\soptimization.\s[forum:/forumpost/befdab472d\s|\sForum\spost\sbefdab472d]. -D 2023-11-10T20:55:20.957 +C Do\snot\scache\sa\sstatement's\scolumn\scount\sin\sthe\sJNI\swrapper1\sAPI\sbecause\san\sALTER\sTABLE\svia\sanother\sstatement\smay\sinvalidate\sit,\sas\sreported\sin\s[forum:6d80efd58d4591c7|forum\spost\s6d80efd58d4591c7]. +D 2023-11-11T14:43:50.704 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -251,7 +251,7 @@ F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java 0b72cdff61533b564d65b63 F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java c045a5b47e02bb5f1af91973814a905f12048c428a3504fbc5266d1c1be3de5a F ext/jni/src/org/sqlite/jni/capi/AutoExtensionCallback.java 74cc4998a73d6563542ecb90804a3c4f4e828cb4bd69e61226d1a51f4646e759 F ext/jni/src/org/sqlite/jni/capi/BusyHandlerCallback.java 7b8e19810c42b0ad21a04b5d8c804b32ee5905d137148703f16a75b612c380ca -F ext/jni/src/org/sqlite/jni/capi/CApi.java 92d443b08175c798e132a312f71b1a42140c60d473d35c149e3d95a45b6550f3 +F ext/jni/src/org/sqlite/jni/capi/CApi.java bd4a6490548f913bf9719443dee3d8a233f920ed1614b622738527d746e00f5d F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 57e2d275dcebe690b1fc1f3d34eb96879b2d7039bce30b563aee547bf45d8a8b F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java 5bfa226a8e7a92e804fd52d6e42b4c7b875fa7a94f8e2c330af8cc244a8920ab @@ -296,7 +296,7 @@ F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483 F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03 F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 27b141f5914c7cb0e40e90a301d5e05b77f3bd42236834a68031b7086381fafd -F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 0ef62b43b1d6a9f044e106b56c9ea42bc7150b82ebeb79cff58f5be08cb9a435 +F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 08a5037aaa5bc83d87f5389adce39c747835c210c445ff02669280e5cc7ffed1 F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 982538ddb4c0719ef87dfa664cd137b09890b546029a7477810bd64d4c47ee35 F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 40806dbbf8e120f115e33255d1813db13b40f0a598869e299a947a580429939b F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af @@ -2139,8 +2139,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 aca31e49d1d25043769544ccf2a07980c5f162a8eb2486e393bf9d9d1a394a60 -R 97cf5703d60c0dd519713f02ba70db03 -U dan -Z e3c451988b970e006792a61910aa1f15 +P f1eae192315335d7e385b0a801a17700a9718d245bda6628518c5df9a1e9d3d6 +R 6d2e0ef8621cb43b22b4fb0195114a8a +U stephan +Z 23f634cb68b0506eca8a1295175f53ed # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 873b025efc..d45a1f15b1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f1eae192315335d7e385b0a801a17700a9718d245bda6628518c5df9a1e9d3d6 \ No newline at end of file +a6ab88e9a67f23ab7885402776282b94033cb48dbe34d4d18356e4dc22aae7cd \ No newline at end of file From 56e1610f7a6be7ca5c6039c03a863f1ec58b8ba4 Mon Sep 17 00:00:00 2001 From: stephan Date: Sat, 11 Nov 2023 14:50:01 +0000 Subject: [PATCH 2/2] JNI wrapper1: when checking for an out-of-bounds statement column index, perform the is-statement-finalized check before the range check so that the former exception trumps the latter. FossilOrigin-Name: 0832f9a8e9f574b157c791c5cddc73aff7b2ff403509f5d78f310494d4a7f93d --- ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java | 2 +- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java index 0d7e2e3922..79ed32700c 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java @@ -979,7 +979,7 @@ public final class Sqlite implements AutoCloseable { /** Throws if n is out of range of this statement's result column count. Intended to be used by the columnXyz() methods. */ private sqlite3_stmt checkColIndex(int n){ - if(null==stmt || n<0 || n>=columnCount()){ + if(n<0 || n>=columnCount()){ throw new IllegalArgumentException("Column index "+n+" is out of range."); } return thisStmt(); diff --git a/manifest b/manifest index 8a365b54e0..a6ae666a58 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Do\snot\scache\sa\sstatement's\scolumn\scount\sin\sthe\sJNI\swrapper1\sAPI\sbecause\san\sALTER\sTABLE\svia\sanother\sstatement\smay\sinvalidate\sit,\sas\sreported\sin\s[forum:6d80efd58d4591c7|forum\spost\s6d80efd58d4591c7]. -D 2023-11-11T14:43:50.704 +C JNI\swrapper1:\swhen\schecking\sfor\san\sout-of-bounds\sstatement\scolumn\sindex,\sperform\sthe\sis-statement-finalized\scheck\sbefore\sthe\srange\scheck\sso\sthat\sthe\sformer\sexception\strumps\sthe\slatter. +D 2023-11-11T14:50:01.933 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -296,7 +296,7 @@ F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483 F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03 F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 27b141f5914c7cb0e40e90a301d5e05b77f3bd42236834a68031b7086381fafd -F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 08a5037aaa5bc83d87f5389adce39c747835c210c445ff02669280e5cc7ffed1 +F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java aeaec95323a8186d0b8e741affff067fe893849a2d862acd443373035c7b73a0 F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 982538ddb4c0719ef87dfa664cd137b09890b546029a7477810bd64d4c47ee35 F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 40806dbbf8e120f115e33255d1813db13b40f0a598869e299a947a580429939b F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af @@ -2139,8 +2139,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 f1eae192315335d7e385b0a801a17700a9718d245bda6628518c5df9a1e9d3d6 -R 6d2e0ef8621cb43b22b4fb0195114a8a +P a6ab88e9a67f23ab7885402776282b94033cb48dbe34d4d18356e4dc22aae7cd +R 78a63cfa87011ebb24c6cac260db14c9 U stephan -Z 23f634cb68b0506eca8a1295175f53ed +Z ad92dad6ace48bd20f7cf67cbd6f4f40 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index d45a1f15b1..4865106033 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a6ab88e9a67f23ab7885402776282b94033cb48dbe34d4d18356e4dc22aae7cd \ No newline at end of file +0832f9a8e9f574b157c791c5cddc73aff7b2ff403509f5d78f310494d4a7f93d \ No newline at end of file