diff options
author | drh <drh@noemail.net> | 2008-04-28 20:27:53 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2008-04-28 20:27:53 +0000 |
commit | cd3dd9d343592d495bb8297745c0a0e94a4e0a67 (patch) | |
tree | b37609a1d013cc34858be0702efae271d9260537 | |
parent | 4f3dd1502e052b7dd3f1581aec32f294710a84d9 (diff) | |
download | sqlite-cd3dd9d343592d495bb8297745c0a0e94a4e0a67.tar.gz sqlite-cd3dd9d343592d495bb8297745c0a0e94a4e0a67.zip |
Add test cases to verify that multiple virtual tables can be updated
within a trigger and that xSync, xCommit, and xRollback are never called
except following xBegin or xCreate. Ticket #3083. (CVS 5064)
FossilOrigin-Name: 76175199ac2fda57e616eb386ba0bad6aa9f74b4
-rw-r--r-- | manifest | 13 | ||||
-rw-r--r-- | manifest.uuid | 2 | ||||
-rw-r--r-- | src/test8.c | 42 | ||||
-rw-r--r-- | test/vtabC.test | 114 |
4 files changed, 162 insertions, 9 deletions
@@ -1,5 +1,5 @@ -C Make\ssure\sthat\stransactions\sare\sstarted\son\sall\svirtual\stables\sthat\nchanges\sin\sa\ssingle\sstatement,\snot\sjust\sthe\sfirst.\s\sTicket\s#3083.\nNeed\sto\sadd\stest\scases.\s(CVS\s5063) -D 2008-04-28T18:46:43 +C Add\stest\scases\sto\sverify\sthat\smultiple\svirtual\stables\scan\sbe\supdated\nwithin\sa\strigger\sand\sthat\sxSync,\sxCommit,\sand\sxRollback\sare\snever\scalled\nexcept\sfollowing\sxBegin\sor\sxCreate.\s\sTicket\s#3083.\s(CVS\s5064) +D 2008-04-28T20:27:54 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.in 25b3282a4ac39388632c2fb0e044ff494d490952 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -145,7 +145,7 @@ F src/test4.c c2c0f5dc907f1346f5d4b65eb5799f11eb9e4071 F src/test5.c 3a6a5717a149d7ca2e6d14f5be72cf7555d54dc4 F src/test6.c 62281c0a9ac0265e579065942f7de4e080f8eb05 F src/test7.c acec2256c7c2d279db5a8b5fa1a2a68fcc942c67 -F src/test8.c 7933b27f8d300512546ef6bdd25f2fe64c3c13f3 +F src/test8.c a7fdf75d7e6c06ca9aa77b026f6d76dbd41aef25 F src/test9.c 4615ef08750245a2d96aaa7cbe2fb4aff2b57acc F src/test_async.c 3147c64c34721f088d5ab20f85dabd5d7732c007 F src/test_autoext.c 5e892ab84aece3f0428920bf46923f16ac83962a @@ -539,6 +539,7 @@ F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583 F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b F test/vtabA.test 9cb6b1afead6fdd91bbdf1ca65c44ccfd9b10936 F test/vtabB.test 04df5dc531b9f44d9ca65b9c1b79f12b5922a796 +F test/vtabC.test 9f2d9eb84bf65e606d6616f20977c5a32a11f548 F test/vtab_alter.test 3a299749fee97ca3d53bd55717f536e4a2284856 F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8 F test/vtab_shared.test c19b2555b807ef2ee014c882cdda5bc8d84fcf48 @@ -631,7 +632,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P be10f5dda6e9c245c05b51840c173e83ece6b245 -R d532e0634e4454f09b4dec2c285b448f +P 133b7ee50ea6012739ebe0e334374c5d9b1fcc7f +R d24a295d23f75ea44f2833f350b9f9f0 U drh -Z 4c6262b2a9c2a39caa1b707bf007c996 +Z 635c743fe71c1f4dbacd2725b4d43e66 diff --git a/manifest.uuid b/manifest.uuid index ead359b5d..11e093178 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -133b7ee50ea6012739ebe0e334374c5d9b1fcc7f
\ No newline at end of file +76175199ac2fda57e616eb386ba0bad6aa9f74b4
\ No newline at end of file diff --git a/src/test8.c b/src/test8.c index a0749cb22..064279d25 100644 --- a/src/test8.c +++ b/src/test8.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test8.c,v 1.61 2008/03/17 09:36:45 danielk1977 Exp $ +** $Id: test8.c,v 1.62 2008/04/28 20:27:54 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -61,6 +61,7 @@ struct echo_vtab { sqlite3 *db; /* Database connection */ int isPattern; + int inTransaction; /* True if within a transaction */ char *zThis; /* Name of the echo table */ char *zTableName; /* Name of the real table */ char *zLogName; /* Name of the log table */ @@ -467,6 +468,10 @@ static int echoCreate( *ppVtab = 0; } + if( rc==SQLITE_OK ){ + (*(echo_vtab**)ppVtab)->inTransaction = 1; + } + return rc; } @@ -883,6 +888,10 @@ int echoUpdate( assert( nData==pVtab->nCol+2 || nData==1 ); + /* Ticket #3083 - make sure we always start a transaction prior to + ** making any changes to a virtual table */ + assert( pVtab->inTransaction ); + /* If apData[0] is an integer and nData>1 then do an UPDATE */ if( nData>1 && sqlite3_value_type(apData[0])==SQLITE_INTEGER ){ char *zSep = " SET"; @@ -1002,6 +1011,10 @@ static int echoBegin(sqlite3_vtab *tab){ Tcl_Interp *interp = pVtab->interp; const char *zVal; + /* Ticket #3083 - do not start a transaction if we are already in + ** a transaction */ + assert( !pVtab->inTransaction ); + rc = echoTransactionCall(tab, "xBegin"); if( rc==SQLITE_OK ){ @@ -1014,6 +1027,9 @@ static int echoBegin(sqlite3_vtab *tab){ rc = SQLITE_ERROR; } } + if( rc==SQLITE_OK ){ + pVtab->inTransaction = 1; + } return rc; } static int echoSync(sqlite3_vtab *tab){ @@ -1022,6 +1038,10 @@ static int echoSync(sqlite3_vtab *tab){ Tcl_Interp *interp = pVtab->interp; const char *zVal; + /* Ticket #3083 - Only call xSync if we have previously started a + ** transaction */ + assert( pVtab->inTransaction ); + rc = echoTransactionCall(tab, "xSync"); if( rc==SQLITE_OK ){ @@ -1037,14 +1057,32 @@ static int echoSync(sqlite3_vtab *tab){ return rc; } static int echoCommit(sqlite3_vtab *tab){ + echo_vtab *pVtab = (echo_vtab*)tab; int rc; + + /* Ticket #3083 - Only call xCommit if we have previously started + ** a transaction */ + assert( pVtab->inTransaction ); + sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, 1); rc = echoTransactionCall(tab, "xCommit"); sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, 0); + if( rc==SQLITE_OK ){ + pVtab->inTransaction = 0; + } return rc; } static int echoRollback(sqlite3_vtab *tab){ - return echoTransactionCall(tab, "xRollback"); + int rc; + echo_vtab *pVtab = (echo_vtab*)tab; + + /* Ticket #3083 - Only call xRollback if we have previously started + ** a transaction */ + assert( pVtab->inTransaction ); + + rc = echoTransactionCall(tab, "xRollback"); + pVtab->inTransaction = 0; + return rc; } /* diff --git a/test/vtabC.test b/test/vtabC.test new file mode 100644 index 000000000..483974887 --- /dev/null +++ b/test/vtabC.test @@ -0,0 +1,114 @@ +# 2008 April 10 +# +# 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 library. The +# focus of this file is is verifying that the xUpdate, xSync, xCommit +# and xRollback methods are only invoked after an xBegin or xCreate. +# Ticket #3083. +# +# $Id: vtabC.test,v 1.1 2008/04/28 20:27:54 drh Exp $ + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +ifcapable !vtab { + finish_test + return +} + + +# N will be the number of virtual tables we have defined. +# +unset -nocomplain N +for {set N 1} {$N<=20} {incr N} { + db close + file delete -force test.db test.db-journal + sqlite3 db test.db + register_echo_module [sqlite3_connection_pointer db] + + # Create $N tables and $N virtual tables to echo them. + # + unset -nocomplain tablist + set tablist {} + do_test vtabC-1.$N.1 { + for {set i 1} {$i<=$::N} {incr i} { + execsql "CREATE TABLE t${i}(x)" + execsql "CREATE VIRTUAL TABLE vt$i USING echo(t$i)" + lappend ::tablist t$i vt$i + } + execsql {SELECT count(*) FROM sqlite_master} + } [expr {$N*2}] + do_test vtabC-1.$N.2 { + execsql {SELECT name FROM sqlite_master} + } $tablist + + # Create a table m and add triggers to make changes on all + # of the virtual tables when m is changed. + # + do_test vtabC-1.$N.3 { + execsql {CREATE TABLE m(a)} + set sql "CREATE TRIGGER rins AFTER INSERT ON m BEGIN\n" + for {set i 1} {$i<=$::N} {incr i} { + append sql " INSERT INTO vt$i VALUES(NEW.a+$i);\n" + } + append sql "END;" + execsql $sql + execsql {SELECT count(*) FROM sqlite_master} + } [expr {$N*2+2}] + do_test vtabC-1.$N.4 { + execsql { + INSERT INTO m VALUES(1000); + SELECT * FROM m; + } + } {1000} + for {set j 1} {$j<=$::N} {incr j} { + do_test vtabC-1.$N.5.$j { + execsql "SELECT * FROM t$::j" + } [expr {$j+1000}] + do_test vtabC-1.$N.6.$j { + execsql "SELECT * FROM vt$::j" + } [expr {$j+1000}] + } + do_test vtabC-1.$N.7 { + set sql "CREATE TRIGGER rins2 BEFORE INSERT ON m BEGIN\n" + for {set i 1} {$i<=$::N} {incr i} { + append sql " INSERT INTO vt$i VALUES(NEW.a+$i*100);\n" + } + for {set i 1} {$i<=$::N} {incr i} { + append sql " INSERT INTO vt$i VALUES(NEW.a+$i*10000);\n" + } + append sql "END;" + execsql $sql + execsql {SELECT count(*) FROM sqlite_master} + } [expr {$N*2+3}] + do_test vtabC-1.$N.8 { + execsql { + INSERT INTO m VALUES(9000000); + SELECT * FROM m; + } + } {1000 9000000} + unset -nocomplain res + for {set j 1} {$j<=$::N} {incr j} { + set res [expr {$j+1000}] + lappend res [expr {$j*100+9000000}] + lappend res [expr {$j*10000+9000000}] + lappend res [expr {$j+9000000}] + do_test vtabC-1.$N.9.$j { + execsql "SELECT * FROM t$::j" + } $res + do_test vtabC-1.$N.10.$j { + execsql "SELECT * FROM vt$::j" + } $res + } +} +unset -nocomplain res N i j + + +finish_test |