From e437ca5ec0af264b3f299409d18c381800414082 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 11 Jul 2011 19:45:38 +0000 Subject: [PATCH] Modifications so that the sessions extension works with blob handles. FossilOrigin-Name: 82ac16c4f873d3bd7c22f36ba7b974b4903a2d50 --- ext/session/session6.test | 90 +++++++++++++++++++++++++++++++++++++++ manifest | 19 +++++---- manifest.uuid | 2 +- src/vdbeapi.c | 2 +- src/vdbeaux.c | 6 ++- src/vdbeblob.c | 28 ++++++++++++ 6 files changed, 135 insertions(+), 12 deletions(-) create mode 100644 ext/session/session6.test diff --git a/ext/session/session6.test b/ext/session/session6.test new file mode 100644 index 0000000000..8a1f172cde --- /dev/null +++ b/ext/session/session6.test @@ -0,0 +1,90 @@ +# 2011 July 11 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite sessions extension. +# Specifically, it tests that sessions work when the database is modified +# using incremental blob handles. +# + +if {![info exists testdir]} { + set testdir [file join [file dirname [info script]] .. .. test] +} +source [file join [file dirname [info script]] session_common.tcl] +source $testdir/tester.tcl +ifcapable !session {finish_test; return} + +set testprefix session6 + +proc do_then_apply_tcl {tcl {dbname main}} { + proc xConflict args { return "OMIT" } + set rc [catch { + sqlite3session S db $dbname + db eval "SELECT name FROM $dbname.sqlite_master WHERE type = 'table'" { + S attach $name + } + eval $tcl + sqlite3changeset_apply db2 [S changeset] xConflict + } msg] + + catch { S delete } + if {$rc} {error $msg} +} + +test_sqlite3_log x +proc x {args} {puts $args} + +forcedelete test.db2 +sqlite3 db2 test.db2 + +do_common_sql { + CREATE TABLE t1(a PRIMARY KEY, b); + CREATE TABLE t2(c PRIMARY KEY, d); +} + +# Test a blob update. +# +do_test 1.1 { + do_then_apply_tcl { + db eval { INSERT INTO t1 VALUES(1, 'helloworld') } + db eval { INSERT INTO t2 VALUES(2, 'onetwothree') } + } + compare_db db db2 +} {} +do_test 1.2 { + do_then_apply_tcl { + set fd [db incrblob t1 b 1] + puts -nonewline $fd 1234567890 + close $fd + } + compare_db db db2 +} {} + +# Test an attached database. +# +do_test 2.1 { + forcedelete test.db3 + file copy test.db2 test.db3 + execsql { ATTACH 'test.db3' AS aux; } + + do_then_apply_tcl { + set fd [db incrblob aux t2 d 1] + puts -nonewline $fd fourfivesix + close $fd + } aux + + sqlite3 db3 test.db3 + compare_db db2 db3 +} {} + + +db3 close +db2 close + +finish_test diff --git a/manifest b/manifest index 8bdd0ba57a..31ce25fa38 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Pull\sthe\slatest\sversion\s3.7.7\srelease-candidate\schanges\sinto\sthe\nsessions\sbranch. -D 2011-06-23T17:40:15.467 +C Modifications\sso\sthat\sthe\ssessions\sextension\sworks\swith\sblob\shandles. +D 2011-07-11T19:45:38.954 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in c1d7a7f4fd8da6b1815032efca950e3d5125407e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -107,6 +107,7 @@ F ext/session/session2.test 99ca0da7ddb617d42bafd83adccf99f18ae0384b F ext/session/session3.test a7a9ce59b8d1e49e2cc23d81421ac485be0eea01 F ext/session/session4.test a6ed685da7a5293c5d6f99855bcf41dbc352ca84 F ext/session/session5.test 8fdfaf9dba28a2f1c6b89b06168bdab1fef2d478 +F ext/session/session6.test 443789bc2fca12e4f7075cf692c60b8a2bea1a26 F ext/session/session_common.tcl 1539d8973b2aea0025c133eb0cc4c89fcef541a5 F ext/session/sessionfault.test 401045278298a242cbc2e4bc986c102f01ff2180 F ext/session/sqlite3session.c 26de50c3e34d89ae62e97024ad07e772e1c52db2 @@ -251,9 +252,9 @@ F src/vacuum.c 05513dca036a1e7848fe18d5ed1265ac0b32365e F src/vdbe.c df52db6162fd94767b76bb4e9a7cb9207e83086f F src/vdbe.h 322af148cceef120bb1ec9cff7f122e76abf94da F src/vdbeInt.h 3de6588b36c833969aebab202e1766d586c37ec2 -F src/vdbeapi.c 1d947da083c24e8bf61823f02f619a1f4a682100 -F src/vdbeaux.c db3d4eedccea5add714dfb8b10f70d0f8d692db5 -F src/vdbeblob.c f024f0bf420f36b070143c32b15cc7287341ffd3 +F src/vdbeapi.c 432a8a194accb9fe9fae45338f210174c6c961b4 +F src/vdbeaux.c bb86d48ce99c288d17e8d79711713399c21f0a8d +F src/vdbeblob.c a547f286b651641bdb43a567af66d0e776a39ea2 F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114 F src/vtab.c 901791a47318c0562cd0c676a2c6ff1bc530e582 @@ -960,7 +961,7 @@ F tool/symbols.sh bc2a3709940d47c8ac8e0a1fdf17ec801f015a00 F tool/tostr.awk 11760e1b94a5d3dcd42378f3cc18544c06cfa576 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings.sh 347d974d143cf132f953b565fbc03026f19fcb4d -P 5d95b42946b5cf0346164aebe0a8c4f37527bc31 b61a76a53af04f731fe7617f7b6b4fb2aef6587b -R 5b9118bd8782ff0e4b99f3cb89f8be24 -U drh -Z 3edc7355d0a27e1ff60419d5d75c34a3 +P 840bf9c2d92192ee3cc2aa7c0e9bdb805a066fd4 +R c823c2479e73fc426d6fab6fb150638b +U dan +Z 6339a08530525dea9c6675e0fc9a27f5 diff --git a/manifest.uuid b/manifest.uuid index 6c62bceba4..fecbc08bba 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -840bf9c2d92192ee3cc2aa7c0e9bdb805a066fd4 \ No newline at end of file +82ac16c4f873d3bd7c22f36ba7b974b4903a2d50 \ No newline at end of file diff --git a/src/vdbeapi.c b/src/vdbeapi.c index f7b3b41623..136a8cd168 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -1389,7 +1389,7 @@ int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ */ int sqlite3_preupdate_count(sqlite3 *db){ PreUpdate *p = db->pPreUpdate; - return (p ? p->pCsr->nField : 0); + return (p ? p->keyinfo.nField : 0); } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index a45f7a2892..8c442fce51 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -3274,13 +3274,17 @@ void sqlite3VdbePreUpdateHook( iKey2 = iKey1; } + assert( pCsr->nField==pTab->nCol + || (pCsr->nField==pTab->nCol+1 && op==SQLITE_DELETE && iReg==-1) + ); + preupdate.v = v; preupdate.pCsr = pCsr; preupdate.op = op; preupdate.iNewReg = iReg; preupdate.keyinfo.db = db; preupdate.keyinfo.enc = ENC(db); - preupdate.keyinfo.nField = pCsr->nField; + preupdate.keyinfo.nField = pTab->nCol; preupdate.iKey1 = iKey1; preupdate.iKey2 = iKey2; preupdate.iPKey = pTab->iPKey; diff --git a/src/vdbeblob.c b/src/vdbeblob.c index a8728e6d25..4dc9ef4fff 100644 --- a/src/vdbeblob.c +++ b/src/vdbeblob.c @@ -30,6 +30,8 @@ struct Incrblob { BtCursor *pCsr; /* Cursor pointing at blob row */ sqlite3_stmt *pStmt; /* Statement holding cursor open */ sqlite3 *db; /* The associated database */ + char *zDb; /* Database name */ + Table *pTab; /* Table object */ }; @@ -194,6 +196,8 @@ int sqlite3_blob_open( sqlite3BtreeLeaveAll(db); goto blob_open_out; } + pBlob->pTab = pTab; + pBlob->zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zName; /* Now search pTab for the exact column. */ for(iCol=0; iColnCol; iCol++) { @@ -386,6 +390,30 @@ static int blobReadWrite( */ assert( db == v->db ); sqlite3BtreeEnterCursor(p->pCsr); + +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + if( xCall==sqlite3BtreePutData ){ + /* If a pre-update hook is registered and this is a write cursor, + ** invoke it here. + ** + ** TODO: The preupdate-hook is passed SQLITE_DELETE, even though this + ** operation should really be an SQLITE_UPDATE. This is probably + ** incorrect, but is convenient because at this point the new.* values + ** are not easily obtainable. And for the sessions module, an + ** SQLITE_UPDATE where the PK columns do not change is handled in the + ** same way as an SQLITE_DELETE (the SQLITE_DELETE code is actually + ** slightly more efficient). Since you cannot write to a PK column + ** using the incremental-blob API, this works. For the sessions module + ** anyhow. + */ + sqlite3_int64 iKey; + sqlite3BtreeKeySize(p->pCsr, &iKey); + sqlite3VdbePreUpdateHook( + v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1 + ); + } +#endif + rc = xCall(p->pCsr, iOffset+p->iOffset, n, z); sqlite3BtreeLeaveCursor(p->pCsr); if( rc==SQLITE_ABORT ){