aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordan <Dan Kennedy>2025-07-07 11:37:55 +0000
committerdan <Dan Kennedy>2025-07-07 11:37:55 +0000
commit8504d37b99002d8bc0466c401ed441274f5557f7 (patch)
tree45aaa77e99258a0b1d025060e8e38e2c34d4cff3
parent084046068949dfaeaae71ce4fe9cdbe5ccb24db4 (diff)
downloadsqlite-8504d37b99002d8bc0466c401ed441274f5557f7.tar.gz
sqlite-8504d37b99002d8bc0466c401ed441274f5557f7.zip
Avoid invoking the preupdate hook from within sqlite3_blob_write() if the cursor is already invalid.
FossilOrigin-Name: 9f335b9a4e9e761a0c6afd6dc69665a24506141bde88530bf59fcbdf957ae881
-rw-r--r--manifest16
-rw-r--r--manifest.uuid2
-rw-r--r--src/vdbeblob.c33
-rw-r--r--test/incrblob4.test91
4 files changed, 124 insertions, 18 deletions
diff --git a/manifest b/manifest
index c3bcb089c..696aaba12 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sparser\serror\sintroduced\sby\s[325e547a2195571e].\s\sSee\n[forum:/forumpost/095dbfc06e5b1f7e|forum\spost\s095dbfc06e5].
-D 2025-07-07T02:18:27.401
+C Avoid\sinvoking\sthe\spreupdate\shook\sfrom\swithin\ssqlite3_blob_write()\sif\sthe\scursor\sis\salready\sinvalid.
+D 2025-07-07T11:37:55.009
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -857,7 +857,7 @@ F src/vdbe.h 93761ed7c6b8bc19524912fd9b9b587d41bf4f1d0ade650a00dadc10518d8958
F src/vdbeInt.h 0bc581a9763be385e3af715e8c0a503ba8422c2b7074922faf4bb0d6ae31b15e
F src/vdbeapi.c f9a4881a9674fec3fa13da35044a1484d3c4b95f9ec891cc8ffb02ef2b7a41df
F src/vdbeaux.c fd2c6b19a8892c31a2adc719f156f313560f9cc490cdbd04ff08fdae5d7aedb7
-F src/vdbeblob.c b1b4032cac46b41e44b957c4d00aee9851f862dfd85ecb68116ba49884b03dfd
+F src/vdbeblob.c b3f0640db9642fbdc88bd6ebcc83d6009514cafc98f062f675f2c8d505d82692
F src/vdbemem.c e67d9c6484d868c879d20c70d00bf4a9058082f1d4058607ca15d50eb3aebc21
F src/vdbesort.c cb6f472e83ca12c46aa7de0ac0a9d11458b357986f2617a1c90dfb19a542ecbe
F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823
@@ -1315,7 +1315,7 @@ F test/in7.test d9efdee00b074a60c6343993b2eda78bc369ab080dad864513c73f8aca89d566
F test/incrblob.test c9b96afc292aeff43d6687bcb09b0280aa599822
F test/incrblob2.test a494c9e848560039a23974b9119cfc2cf3ad3bd15cc2694ee6367ae537ef8f1f
F test/incrblob3.test 67621a04b3084113bf38ce03797d70eca012d9d8f948193b8f655df577b0da6f
-F test/incrblob4.test 21a52a6843a56cdcce968c6a86b72a7066d0e6ba
+F test/incrblob4.test 10f4537febe1774c02f8d490d393322b4a50898d4027868b67055e9c3adc22db
F test/incrblob_err.test 89372a28f1d98254f03fed705f9efcd34ef61a674df16d2dbb4726944a2de5e9
F test/incrblobfault.test de274b1e329169c2c3438f9528994807ea8201ebf38ae9f157d34bf3ec0cc549
F test/incrcorrupt.test 6c567fbf870aa9e91866fe52ce6f200cd548939a
@@ -2208,8 +2208,8 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P c60907e77b32824aaaf024d299cdaf161b5f64fc927ffe5d5455eeb5754e6b01
-R 9751f5fd5db45dc9854f3e80aaabd1b6
-U drh
-Z 4f27d9f9c6c0d2b5f41153ee565cb8ec
+P 4eefab44941fc6e17742fa49c8734e7f00a2177d82bc572e596228add53aad39
+R 8dd2c3d3469e31d78df8ad758ebdebcb
+U dan
+Z 1af57e86c85e1876b1c7c9bf1cb0169c
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index 387609d24..843f25873 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-4eefab44941fc6e17742fa49c8734e7f00a2177d82bc572e596228add53aad39
+9f335b9a4e9e761a0c6afd6dc69665a24506141bde88530bf59fcbdf957ae881
diff --git a/src/vdbeblob.c b/src/vdbeblob.c
index 42edcf7de..a15fec6c4 100644
--- a/src/vdbeblob.c
+++ b/src/vdbeblob.c
@@ -385,7 +385,7 @@ static int blobReadWrite(
int iOffset,
int (*xCall)(BtCursor*, u32, u32, void*)
){
- int rc;
+ int rc = SQLITE_OK;
Incrblob *p = (Incrblob *)pBlob;
Vdbe *v;
sqlite3 *db;
@@ -425,17 +425,32 @@ static int blobReadWrite(
** using the incremental-blob API, this works. For the sessions module
** anyhow.
*/
- sqlite3_int64 iKey;
- iKey = sqlite3BtreeIntegerKey(p->pCsr);
- assert( v->apCsr[0]!=0 );
- assert( v->apCsr[0]->eCurType==CURTYPE_BTREE );
- sqlite3VdbePreUpdateHook(
- v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1, p->iCol
- );
+ if( sqlite3BtreeCursorIsValidNN(p->pCsr)==0 ){
+ /* If the cursor is not currently valid, try to reseek it. This
+ ** always either fails or finds the correct row - the cursor will
+ ** have been marked permanently CURSOR_INVALID if the open row has
+ ** been deleted. */
+ int bDiff = 0;
+ rc = sqlite3BtreeCursorRestore(p->pCsr, &bDiff);
+ assert( bDiff==0 || sqlite3BtreeCursorIsValidNN(p->pCsr)==0 );
+ }
+ if( sqlite3BtreeCursorIsValidNN(p->pCsr) ){
+ sqlite3_int64 iKey;
+ iKey = sqlite3BtreeIntegerKey(p->pCsr);
+ assert( v->apCsr[0]!=0 );
+ assert( v->apCsr[0]->eCurType==CURTYPE_BTREE );
+ sqlite3VdbePreUpdateHook(
+ v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1, p->iCol
+ );
+ }
}
+ if( rc==SQLITE_OK ){
+ rc = xCall(p->pCsr, iOffset+p->iOffset, n, z);
+ }
+#else
+ rc = xCall(p->pCsr, iOffset+p->iOffset, n, z);
#endif
- rc = xCall(p->pCsr, iOffset+p->iOffset, n, z);
sqlite3BtreeLeaveCursor(p->pCsr);
if( rc==SQLITE_ABORT ){
sqlite3VdbeFinalize(v);
diff --git a/test/incrblob4.test b/test/incrblob4.test
index dbff8eb7d..31040e91b 100644
--- a/test/incrblob4.test
+++ b/test/incrblob4.test
@@ -106,4 +106,95 @@ do_test 4.4 {
} {SQLITE_LOCKED}
close $blob
+#-------------------------------------------------------------------------
+
+reset_db
+do_execsql_test 5.1 {
+ CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
+ INSERT INTO t2 VALUES(1000, 'abcdefghijklmnopqrstuvwxyz');
+ INSERT INTO t2 VALUES(2000, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
+ INSERT INTO t2 VALUES(3000, 'abcdefghijklmnopqrstuvwxyz');
+}
+
+do_test 5.2.1 {
+ execsql BEGIN
+ set blob [db incrblob t2 b 2000]
+ seek $blob 0
+ puts -nonewline $blob "hello "
+ flush $blob
+ execsql ROLLBACK
+} {}
+
+do_test 5.2.2 {
+ puts -nonewline $blob "world"
+ list [catch { flush $blob } msg] $msg
+} "1 {error flushing \"$blob\": I/O error}"
+catch { close $blob }
+
+set preupdate_count 0
+proc preupdate {args} { incr ::preupdate_count ; return {} }
+db preupdate hook preupdate
+
+set preupdate_count 0
+do_test 5.3.1 {
+ execsql BEGIN
+ set blob [db incrblob t2 b 1000]
+ seek $blob 0
+ puts -nonewline $blob "hello "
+ flush $blob
+ execsql ROLLBACK
+} {}
+
+do_test 5.3.2 {
+ puts -nonewline $blob "world"
+ list [catch { flush $blob } msg] $msg
+} "1 {error flushing \"$blob\": I/O error}"
+catch { close $blob }
+
+do_test 5.3.3 {
+ set ::preupdate_count
+} {1}
+
+set preupdate_count 0
+do_test 5.4.1 {
+ execsql BEGIN
+ set blob [db incrblob t2 b 1000]
+ seek $blob 0
+ puts -nonewline $blob "hello "
+ flush $blob
+ execsql { DELETE FROM t2 WHERE a=3000; }
+} {}
+
+do_test 5.4.2 {
+ puts -nonewline $blob "world"
+ list [catch { flush $blob } msg] $msg
+} "0 {}"
+catch { close $blob }
+catchsql { ROLLBACK }
+
+do_test 5.3.3 {
+ set ::preupdate_count
+} {3}
+
+set preupdate_count 0
+do_test 5.4.3 {
+ execsql BEGIN
+ set blob [db incrblob t2 b 2000]
+ seek $blob 0
+ puts -nonewline $blob "hello "
+ flush $blob
+ execsql { UPDATE t2 SET b='abcdefghijklmnopqrstuvwxyz' WHERE a=2000 }
+} {}
+
+do_test 5.4.4 {
+ puts -nonewline $blob "world"
+ list [catch { flush $blob } msg] $msg
+} "1 {error flushing \"$blob\": I/O error}"
+catch { close $blob }
+catchsql { ROLLBACK }
+
+do_test 5.3.3 {
+ set ::preupdate_count
+} {2}
+
finish_test