From 46c43edd397ee5b0ed7b783b4c41edf8b4c5cdc0 Mon Sep 17 00:00:00 2001 From: danielk1977 Date: Wed, 30 Jun 2004 06:30:25 +0000 Subject: [PATCH] Add some tests for overlapping SELECT, COMMIT and ROLLBACK commands. (CVS 1774) FossilOrigin-Name: d256c14943968e7adf4b73988cac6af941c9b12d --- manifest | 20 +++--- manifest.uuid | 2 +- src/vacuum.c | 24 +++++-- src/vdbe.c | 17 ++++- test/capi2.test | 16 ++--- test/capi3.test | 165 ++++++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 212 insertions(+), 32 deletions(-) diff --git a/manifest b/manifest index 4bbd27432c..1b467c4d3d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improve\stest\scoverage\sof\sutil.c\s(CVS\s1773) -D 2004-06-30T04:02:12 +C Add\ssome\stests\sfor\soverlapping\sSELECT,\sCOMMIT\sand\sROLLBACK\scommands.\s(CVS\s1774) +D 2004-06-30T06:30:26 F Makefile.in cb7a9889c38723f72b2506c4236ff30a05ff172b F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -72,8 +72,8 @@ F src/trigger.c 6aaf6d79cc2157c70a06031dd1531707d644cfb4 F src/update.c b66b1896c9da54678ba3eff2bf0b4d291a95986a F src/utf.c f03535db72bfa09e24202ccdd245f21d2fc65f0a F src/util.c b267d0fe10cffa3301fe9fab6592a6808a38bce6 -F src/vacuum.c 353c7f69dbeb6738434d81798465cc0698844640 -F src/vdbe.c 32039b08701f1c19fcd9b684366cefaa8fabaa72 +F src/vacuum.c 4aede0a7048d8b71a43f45cc15359e16eddc8a2e +F src/vdbe.c 6950e25d93346b03404d2fc383883ff9fa2e5966 F src/vdbe.h 75b241c02431b9c0f16eaa9cdbb34146c6287f52 F src/vdbeInt.h d83fd7389838453d8392915c21f432014afc99cf F src/vdbeapi.c ba3722f45db3d3c3509bf5d24f4f868f4c64449d @@ -95,8 +95,8 @@ F test/btree4.test 3797b4305694c7af6828675b0f4b1424b8ca30e4 F test/btree5.test 8e5ff32c02e685d36516c6499add9375fe1377f2 F test/btree6.test a5ede6bfbbb2ec8b27e62813612c0f28e8f3e027 F test/btree7.test 429b96cfef5b51a7d512cfb4b5b3e453384af293 -F test/capi2.test fe61f341e953f73c29bacfcbdaf688cd7b0e0d38 -F test/capi3.test 3a7f759ce26a300ecdd288be901fcb0727f8773a +F test/capi2.test 78f2c486689fcc80394a24c2cc32725330ab6299 +F test/capi3.test 85c4445cd9bd1fa0cd9d8af56a4fae361b57c553 F test/collate1.test 2ee4fa3a47a652ccf56c5ddf65dcc44d9bad82ef F test/collate2.test c1a3b41f761b28853c5696037f92de928f93233b F test/collate3.test e60b428e07ec945492ba90ff1c895902ee3a8a50 @@ -232,7 +232,7 @@ F www/tclsqlite.tcl 19191cf2a1010eaeff74c51d83fd5f5a4d899075 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9 F www/version3.tcl 563ba3ac02f64da27ab17f3edbe8e56bfd0293fb F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P 0c999f28137bd82ba24dd263bab30d22329eed73 -R aac9bef2959b49a3b21126dff36eb51a -U drh -Z d9d34e7eed57c4c6a384e0a609787172 +P 68ac32213766c5e83de54373b90030a458538017 +R 744bf93dd2f36513077a290ed8b8aa9f +U danielk1977 +Z aa9871afb1977e06c76a2d6bc3030445 diff --git a/manifest.uuid b/manifest.uuid index c10c079327..c44e0ae335 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -68ac32213766c5e83de54373b90030a458538017 \ No newline at end of file +d256c14943968e7adf4b73988cac6af941c9b12d \ No newline at end of file diff --git a/src/vacuum.c b/src/vacuum.c index 8fdf06b5dd..e2a26eaf90 100644 --- a/src/vacuum.c +++ b/src/vacuum.c @@ -14,7 +14,7 @@ ** Most of the code in this file may be omitted by defining the ** SQLITE_OMIT_VACUUM macro. ** -** $Id: vacuum.c,v 1.24 2004/06/26 08:38:25 danielk1977 Exp $ +** $Id: vacuum.c,v 1.25 2004/06/30 06:30:26 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -97,9 +97,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite *db){ char *zTemp = 0; /* a temporary file in same directory as zFilename */ int i; /* Loop counter */ Btree *pTemp; - char *zSql = 0; - sqlite3_stmt *pStmt = 0; if( !db->autoCommit ){ sqlite3SetString(pzErrMsg, "cannot VACUUM from within a transaction", @@ -129,8 +127,16 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite *db){ if( !sqlite3OsFileExists(zTemp) ) break; } - /* Attach the temporary database as 'vacuum' */ + /* Attach the temporary database as 'vacuum_db'. The synchronous pragma + ** can be set to 'off' for this file, as it is not recovered if a crash + ** occurs anyway. The integrity of the database is maintained by a + ** (possibly synchronous) transaction opened on the main database before + ** sqlite3BtreeCopyFile() is called. + ** + ** An optimisation would be to use a non-journaled pager. + */ zSql = sqlite3MPrintf("ATTACH '%s' AS vacuum_db;", zTemp); + execSql(db, "PRAGMA vacuum_db.synchronous = off;"); if( !zSql ){ rc = SQLITE_NOMEM; goto end_of_vacuum; @@ -217,14 +223,20 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite *db){ } end_of_vacuum: - execSql(db, "ROLLBACK;"); + /* Currently there is an SQL level transaction open on the vacuum + ** database. No locks are held on any other files (since the main file + ** was committed at the btree level). So it safe to end the transaction + ** by manually setting the autoCommit flag to true and detaching the + ** vacuum database. The vacuum_db journal file is deleted when the pager + ** is closed by the DETACH. + */ + db->autoCommit = 1; execSql(db, "DETACH vacuum_db;"); if( zTemp ){ sqlite3OsDelete(zTemp); sqliteFree(zTemp); } if( zSql ) sqliteFree( zSql ); - if( pStmt ) sqlite3_finalize( pStmt ); #endif return rc; } diff --git a/src/vdbe.c b/src/vdbe.c index 442e396ae5..4fe0fe9842 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.396 2004/06/30 02:43:38 danielk1977 Exp $ +** $Id: vdbe.c,v 1.397 2004/06/30 06:30:26 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -2212,7 +2212,8 @@ case OP_Statement: { /* Opcode: AutoCommit P1 P2 * ** ** Set the database auto-commit flag to P1 (1 or 0). If P2 is true, roll -** back any currently active btree transactions. +** back any currently active btree transactions. If there are any active +** VMs (apart from this one), then the COMMIT or ROLLBACK statement fails. */ case OP_AutoCommit: { u8 i = pOp->p1; @@ -2221,7 +2222,17 @@ case OP_AutoCommit: { assert( i==1 || i==0 ); assert( i==1 || rollback==0 ); - if( i!=db->autoCommit ){ + assert( db->activeVdbeCnt>0 ); + + if( db->activeVdbeCnt>1 && i && !db->autoCommit ){ + /* If this instruction implements a COMMIT or ROLLBACK, other VMs are + ** still running, and a transaction is active, return an error indicating + ** that the other VMs must complete first. + */ + sqlite3SetString(&p->zErrMsg, "cannot ", rollback?"rollback":"commit", + " transaction - SQL statements in progress", 0); + rc = SQLITE_ERROR; + }else if( i!=db->autoCommit ){ db->autoCommit = i; p->autoCommitOn |= i; if( pOp->p2 ){ diff --git a/test/capi2.test b/test/capi2.test index a4265c9a16..6af1989dcc 100644 --- a/test/capi2.test +++ b/test/capi2.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this script testing the callback-free C/C++ API. # -# $Id: capi2.test,v 1.17 2004/06/26 09:50:12 danielk1977 Exp $ +# $Id: capi2.test,v 1.18 2004/06/30 06:30:26 danielk1977 Exp $ # set testdir [file dirname $argv0] @@ -484,18 +484,18 @@ do_test capi2-6.20 { [get_row_values $VM1] \ [get_column_names $VM1] } {SQLITE_ROW 1 9 {x counter}} -do_test capi2-6.21 { - execsql {ROLLBACK; SELECT * FROM t1} -} {1 2 3} +#do_test capi2-6.21 { +# execsql {ROLLBACK; SELECT * FROM t1} +#} {1 2 3} do_test capi2-6.22 { list [sqlite3_step $VM1] \ [sqlite3_column_count $VM1] \ [get_row_values $VM1] \ [get_column_names $VM1] } {SQLITE_ROW 1 10 {x counter}} -do_test capi2-6.23 { - execsql {BEGIN TRANSACTION;} -} {} +#do_test capi2-6.23 { +# execsql {BEGIN TRANSACTION;} +#} {} do_test capi2-6.24 { list [sqlite3_step $VM1] \ [sqlite3_column_count $VM1] \ @@ -507,7 +507,7 @@ do_test capi2-6.25 { INSERT INTO t1 VALUES(2,3,4); SELECT * FROM t1; } -} {1 2 3 2 3 4} +} {1 3 3 2 3 4} do_test capi2-6.26 { list [sqlite3_step $VM1] \ [sqlite3_column_count $VM1] \ diff --git a/test/capi3.test b/test/capi3.test index 7dce3722df..a595bff52a 100644 --- a/test/capi3.test +++ b/test/capi3.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this script testing the callback-free C/C++ API. # -# $Id: capi3.test,v 1.18 2004/06/30 02:35:51 danielk1977 Exp $ +# $Id: capi3.test,v 1.19 2004/06/30 06:30:26 danielk1977 Exp $ # set testdir [file dirname $argv0] @@ -498,7 +498,7 @@ do_test capi3-8.2 { # Build a 5-field row record consisting of 5 null records. This is # officially black magic. - unset data + catch {unset data} set data [binary format c6 {6 0 0 0 0 0}] btree_insert $::bc 5 $data @@ -601,7 +601,164 @@ db close sqlite_malloc_fail 0 } +# The following tests - capi3-11.* - test that a COMMIT or ROLLBACK +# statement issued while there are still outstanding VMs that are part of +# the transaction fails. +set DB [sqlite3 db test.db] +sqlite_register_test_function $DB func +do_test capi3-11.1 { + execsql { + BEGIN; + CREATE TABLE t1(a, b); + INSERT INTO t1 VALUES(1, 'int'); + INSERT INTO t1 VALUES(2, 'notatype'); + } +} {} +do_test capi3-11.2 { + set STMT [sqlite3_prepare $DB "SELECT func(b, a) FROM t1" -1 TAIL] + sqlite3_step $STMT +} {SQLITE_ROW} +do_test capi3-11.3 { + catchsql { + COMMIT; + } +} {1 {cannot commit transaction - SQL statements in progress}} +do_test capi3-11.4 { + sqlite3_step $STMT +} {SQLITE_ERROR} +do_test capi3-11.5 { + sqlite3_finalize $STMT +} {SQLITE_ERROR} +do_test capi3-11.6 { + catchsql { + SELECT * FROM t1; + } +} {0 {1 int 2 notatype}} +do_test capi3-11.7 { + catchsql { + COMMIT; + } +} {0 {}} +do_test capi3-11.8 { + execsql { + CREATE TABLE t2(a); + INSERT INTO t2 VALUES(1); + INSERT INTO t2 VALUES(2); + BEGIN; + INSERT INTO t2 VALUES(3); + } +} {} +do_test capi3-11.9 { + set STMT [sqlite3_prepare $DB "SELECT a FROM t2" -1 TAIL] + sqlite3_step $STMT +} {SQLITE_ROW} +do_test capi3-11.3 { + catchsql { + ROLLBACK; + } +} {1 {cannot rollback transaction - SQL statements in progress}} +do_test capi3-11.10 { + sqlite3_step $STMT +} {SQLITE_ROW} +do_test capi3-11.11 { + sqlite3_step $STMT +} {SQLITE_ROW} +do_test capi3-11.12 { + sqlite3_step $STMT +} {SQLITE_DONE} +do_test capi3-11.13 { + sqlite3_finalize $STMT +} {SQLITE_OK} +do_test capi3-11.14 { + execsql { + SELECT a FROM t2; + } +} {1 2 3} +do_test capi3-11.15 { + catchsql { + ROLLBACK; + } +} {0 {}} +do_test capi3-11.16 { + execsql { + SELECT a FROM t2; + } +} {1 2} + +# Sanity check on the definition of 'outstanding VM'. This means any VM +# that has had sqlite3_step() called more recently than sqlite3_finalize() or +# sqlite3_reset(). So a VM that has just been prepared or reset does not +# count as an active VM. +do_test capi3-11.17 { + execsql { + BEGIN; + } +} {} +do_test capi3-11.18 { + set STMT [sqlite3_prepare $DB "SELECT a FROM t1" -1 TAIL] + catchsql { + COMMIT; + } +} {0 {}} +do_test capi3-11.19 { + sqlite3_step $STMT +} {SQLITE_ROW} +do_test capi3-11.20 { + catchsql { + BEGIN; + COMMIT; + } +} {1 {cannot commit transaction - SQL statements in progress}} +do_test capi3-11.20 { + sqlite3_reset $STMT + catchsql { + COMMIT; + } +} {0 {}} +do_test capi3-11.21 { + sqlite3_finalize $STMT +} {SQLITE_OK} + +# The following tests - capi3-12.* - check that it's Ok to start a +# transaction while other VMs are active, and that it's Ok to execute +# atomic updates in the same situation (so long as they are on a different +# table). +do_test capi3-12.1 { + set STMT [sqlite3_prepare $DB "SELECT a FROM t2" -1 TAIL] + sqlite3_step $STMT +} {SQLITE_ROW} +do_test capi3-12.2 { + catchsql { + INSERT INTO t1 VALUES(3, NULL); + } +} {0 {}} +do_test capi3-12.3 { + catchsql { + INSERT INTO t2 VALUES(4); + } +} {1 {database table is locked}} +do_test capi3-12.4 { + catchsql { + BEGIN; + INSERT INTO t1 VALUES(4, NULL); + } +} {0 {}} +do_test capi3-12.5 { + sqlite3_step $STMT +} {SQLITE_ROW} +do_test capi3-12.6 { + sqlite3_step $STMT +} {SQLITE_DONE} +do_test capi3-12.7 { + sqlite3_finalize $STMT +} {SQLITE_OK} +do_test capi3-12.8 { + execsql { + COMMIT; + SELECT a FROM t1; + } +} {1 2 3 4} + + finish_test - -