Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Make sure statement journals are initiated when doing DROP operations (since the DROP might fail after sqlite_master changes). Also make sure statement journals are initiated if there are pending SELECT statements. Ticket #2820. (CVS 4591) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
bf34284ff0c60ae6e735e09bb29cd48b |
User & Date: | drh 2007-12-04 16:54:53.000 |
Context
2007-12-05
| ||
01:38 | Add the ability to change the autovacuum status of an existing database by setting the auto_vacuum pragma then running the VACUUM command. (CVS 4592) (check-in: bdfc19e838 user: drh tags: trunk) | |
2007-12-04
| ||
16:54 | Make sure statement journals are initiated when doing DROP operations (since the DROP might fail after sqlite_master changes). Also make sure statement journals are initiated if there are pending SELECT statements. Ticket #2820. (CVS 4591) (check-in: bf34284ff0 user: drh tags: trunk) | |
13:41 | Fix a bug in the TCL code for sqlite3_analyzer. (CVS 4590) (check-in: 7c2cf45428 user: drh tags: trunk) | |
Changes
Changes to src/build.c.
︙ | ︙ | |||
18 19 20 21 22 23 24 | ** CREATE INDEX ** DROP INDEX ** creating ID lists ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | ** CREATE INDEX ** DROP INDEX ** creating ID lists ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** ** $Id: build.c,v 1.450 2007/12/04 16:54:53 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** This routine is called when a new SQL statement is beginning to ** be parsed. Initialize the pParse structure as needed. |
︙ | ︙ | |||
1990 1991 1992 1993 1994 1995 1996 | /* Generate code to remove the table from the master table ** on disk. */ v = sqlite3GetVdbe(pParse); if( v ){ Trigger *pTrigger; Db *pDb = &db->aDb[iDb]; | | | 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 | /* Generate code to remove the table from the master table ** on disk. */ v = sqlite3GetVdbe(pParse); if( v ){ Trigger *pTrigger; Db *pDb = &db->aDb[iDb]; sqlite3BeginWriteOperation(pParse, 1, iDb); #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ Vdbe *v = sqlite3GetVdbe(pParse); if( v ){ sqlite3VdbeAddOp(v, OP_VBegin, 0, 0); } |
︙ | ︙ | |||
2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 | } } #endif /* Generate code to remove the index and from the master table */ v = sqlite3GetVdbe(pParse); if( v ){ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE name=%Q", db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pIndex->zName ); sqlite3ChangeCookie(db, v, iDb); destroyRootPage(pParse, pIndex->tnum, iDb); | > | 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 | } } #endif /* Generate code to remove the index and from the master table */ v = sqlite3GetVdbe(pParse); if( v ){ sqlite3BeginWriteOperation(pParse, 1, iDb); sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE name=%Q", db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pIndex->zName ); sqlite3ChangeCookie(db, v, iDb); destroyRootPage(pParse, pIndex->tnum, iDb); |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
39 40 41 42 43 44 45 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** 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.656 2007/12/04 16:54:53 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> #include "vdbeInt.h" /* ** The following global variable is incremented every time a cursor |
︙ | ︙ | |||
2406 2407 2408 2409 2410 2411 2412 | ** The statement is begun on the database file with index P1. The main ** database file has an index of 0 and the file used for temporary tables ** has an index of 1. */ case OP_Statement: { /* no-push */ int i = pOp->p1; Btree *pBt; | | > | 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 | ** The statement is begun on the database file with index P1. The main ** database file has an index of 0 and the file used for temporary tables ** has an index of 1. */ case OP_Statement: { /* no-push */ int i = pOp->p1; Btree *pBt; if( i>=0 && i<db->nDb && (pBt = db->aDb[i].pBt)!=0 && (db->autoCommit==0 || db->activeVdbeCnt>1) ){ assert( sqlite3BtreeIsInTrans(pBt) ); assert( (p->btreeMask & (1<<i))!=0 ); if( !sqlite3BtreeIsInStmt(pBt) ){ rc = sqlite3BtreeBeginStmt(pBt); p->openedStatement = 1; } } |
︙ | ︙ | |||
4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 | } } #else iCnt = db->activeVdbeCnt; #endif if( iCnt>1 ){ rc = SQLITE_LOCKED; }else{ assert( iCnt==1 ); assert( (p->btreeMask & (1<<pOp->p2))!=0 ); rc = sqlite3BtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1, &iMoved); pTos++; pTos->flags = MEM_Int; pTos->u.i = iMoved; | > | 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 | } } #else iCnt = db->activeVdbeCnt; #endif if( iCnt>1 ){ rc = SQLITE_LOCKED; p->errorAction = OE_Abort; }else{ assert( iCnt==1 ); assert( (p->btreeMask & (1<<pOp->p2))!=0 ); rc = sqlite3BtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1, &iMoved); pTos++; pTos->flags = MEM_Int; pTos->u.i = iMoved; |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
266 267 268 269 270 271 272 | ** to an OP_Function, OP_AggStep or OP_VFilter opcode. This is used by ** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array. ** ** The integer *pMaxStack is set to the maximum number of vdbe stack ** entries that static analysis reveals this program might need. ** ** This routine also does the following optimization: It scans for | > > > | > > > > | | | | 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 | ** to an OP_Function, OP_AggStep or OP_VFilter opcode. This is used by ** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array. ** ** The integer *pMaxStack is set to the maximum number of vdbe stack ** entries that static analysis reveals this program might need. ** ** This routine also does the following optimization: It scans for ** instructions that might cause a statement rollback. Such instructions ** are: ** ** * OP_Halt with P1=SQLITE_CONSTRAINT and P2=OE_Abort. ** * OP_Destroy ** * OP_VUpdate ** * OP_VRename ** ** If no such instruction is found, then every Statement instruction ** is changed to a Noop. In this way, we avoid creating the statement ** journal file unnecessarily. */ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs, int *pMaxStack){ int i; int nMaxArgs = 0; int nMaxStack = p->nOp; Op *pOp; int *aLabel = p->aLabel; |
︙ | ︙ | |||
295 296 297 298 299 300 301 302 303 304 305 306 307 308 | } if( opcode==OP_Halt ){ if( pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort ){ doesStatementRollback = 1; } }else if( opcode==OP_Statement ){ hasStatementBegin = 1; #ifndef SQLITE_OMIT_VIRTUALTABLE }else if( opcode==OP_VUpdate || opcode==OP_VRename ){ doesStatementRollback = 1; }else if( opcode==OP_VFilter ){ int n; assert( p->nOp - i >= 3 ); assert( pOp[-2].opcode==OP_Integer ); | > > | 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | } if( opcode==OP_Halt ){ if( pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort ){ doesStatementRollback = 1; } }else if( opcode==OP_Statement ){ hasStatementBegin = 1; }else if( opcode==OP_Destroy ){ doesStatementRollback = 1; #ifndef SQLITE_OMIT_VIRTUALTABLE }else if( opcode==OP_VUpdate || opcode==OP_VRename ){ doesStatementRollback = 1; }else if( opcode==OP_VFilter ){ int n; assert( p->nOp - i >= 3 ); assert( pOp[-2].opcode==OP_Integer ); |
︙ | ︙ | |||
1383 1384 1385 1386 1387 1388 1389 | /* Lock all btrees used by the statement */ sqlite3BtreeMutexArrayEnter(&p->aMutex); /* Check for one of the special errors */ mrc = p->rc & 0xff; isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR | | | 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 | /* Lock all btrees used by the statement */ sqlite3BtreeMutexArrayEnter(&p->aMutex); /* Check for one of the special errors */ mrc = p->rc & 0xff; isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR || mrc==SQLITE_INTERRUPT || mrc==SQLITE_FULL; if( isSpecialError ){ /* This loop does static analysis of the query to see which of the ** following three categories it falls into: ** ** Read-only ** Query with statement journal ** Query without statement journal |
︙ | ︙ |
Added test/tkt2820.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | # 2007 Dec 4 # # 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 is to test that ticket #2820 has been fixed. # Ticket #2820 observes that a DROP TABLE statement that # occurs while a query is in process will fail with a # "database is locked" error, but the entry in the sqlite_master # table will still be removed. This is incorrect. The # entry in the sqlite_master table should persist when # the DROP fails due to an error. # # $Id: tkt2820.test,v 1.1 2007/12/04 16:54:53 drh Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl proc test_schema_change {testid init ddl res} { db close file delete -force test.db test.db-journal sqlite3 db test.db execsql $init do_test tkt2820-$testid.1 { set STMT [sqlite3_prepare db {SELECT * FROM sqlite_master} -1 DUMMY] sqlite3_step $STMT } {SQLITE_ROW} #if {$testid==3} {execsql {PRAGMA vdbe_trace=ON}} do_test tkt2820-$testid.2 "catchsql [list $ddl]" \ {1 {database table is locked}} do_test tkt2820-$testid.3 { sqlite3_finalize $STMT execsql {SELECT name FROM sqlite_master ORDER BY 1} } $res integrity_check tkt2820-$testid.4 db close sqlite3 db test.db integrity_check tkt2820-$testid.5 } test_schema_change 1 { CREATE TABLE t1(a); } { DROP TABLE t1 } {t1} test_schema_change 2 { CREATE TABLE t1(a); CREATE TABLE t2(b); } { DROP TABLE t2 } {t1 t2} test_schema_change 3 { CREATE TABLE t1(a); CREATE INDEX i1 ON t1(a); } { DROP INDEX i1 } {i1 t1} # We further observe that prior to the fix associated with ticket #2820, # no statement journal would be created on an SQL statement that was run # while a second statement was active, as long as we are in autocommit # mode. This is incorrect. # do_test tkt2820-4.1 { db close file delete -force test.db test.db-journal sqlite3 db test.db db eval { CREATE TABLE t1(a INTEGER PRIMARY KEY); INSERT INTO t1 VALUES(1); INSERT INTO t1 VALUES(2); } # The INSERT statement within the loop should fail on a # constraint violation on the second inserted row. This # should cause the entire INSERT to rollback using a statement # journal. # db eval {SELECT name FROM sqlite_master} { catch {db eval { INSERT INTO t1 SELECT a+1 FROM t1 ORDER BY a DESC }} } db eval {SELECT a FROM t1 ORDER BY a} } {1 2} finish_test |
Changes to test/vtab7.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The focus # of this test is reading and writing to the database from within a # virtual table xSync() callback. # | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The focus # of this test is reading and writing to the database from within a # virtual table xSync() callback. # # $Id: vtab7.test,v 1.4 2007/12/04 16:54:53 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !vtab { finish_test return |
︙ | ︙ | |||
110 111 112 113 114 115 116 117 118 | execsql { INSERT INTO abc2 VALUES(1, 2, 3); SELECT name FROM sqlite_master ORDER BY name; } } {abc abc2 log newtab} # Drop a database table from within xSync callback. do_test vtab7-2.6 { set ::callbacks(xSync,abc) { | > > > | | > > > > | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | execsql { INSERT INTO abc2 VALUES(1, 2, 3); SELECT name FROM sqlite_master ORDER BY name; } } {abc abc2 log newtab} # Drop a database table from within xSync callback. # This is not allowed. Tables cannot be dropped while # any other statement is active. # do_test vtab7-2.6 { set ::callbacks(xSync,abc) { set ::rc [catchsql { DROP TABLE newtab }] } execsql { INSERT INTO abc2 VALUES(1, 2, 3); SELECT name FROM sqlite_master ORDER BY name; } } {abc abc2 log newtab} do_test vtab7-2.6.1 { set ::rc } {1 {database table is locked}} execsql {DROP TABLE newtab} # Write to an attached database from xSync(). ifcapable attach { do_test vtab7-3.1 { file delete -force test2.db file delete -force test2.db-journal execsql { |
︙ | ︙ | |||
194 195 196 197 198 199 200 | set ::error } {1 {database table is locked}} trace remove variable ::echo_module write echo_module_trace unset -nocomplain ::callbacks finish_test | < | 201 202 203 204 205 206 207 | set ::error } {1 {database table is locked}} trace remove variable ::echo_module write echo_module_trace unset -nocomplain ::callbacks finish_test |