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)

FossilOrigin-Name: bf34284ff0c60ae6e735e09bb29cd48b158e8dce
This commit is contained in:
drh 2007-12-04 16:54:52 +00:00
parent 0349688fbc
commit 77658e2f0d
7 changed files with 136 additions and 23 deletions

View File

@ -1,5 +1,5 @@
C Fix\sa\sbug\sin\sthe\sTCL\scode\sfor\ssqlite3_analyzer.\s(CVS\s4590)
D 2007-12-04T13:41:51
C Make\ssure\sstatement\sjournals\sare\sinitiated\swhen\sdoing\sDROP\soperations\n(since\sthe\sDROP\smight\sfail\safter\ssqlite_master\schanges).\s\sAlso\smake\nsure\sstatement\sjournals\sare\sinitiated\sif\sthere\sare\spending\sSELECT\nstatements.\s\sTicket\s#2820.\s(CVS\s4591)
D 2007-12-04T16:54:53
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@ -86,7 +86,7 @@ F src/btmutex.c 442be6f068d77ca9ffd69899cf0a3943c244548c
F src/btree.c c5844bb4bbe997a7c8400a714fcf304d91855383
F src/btree.h d0736ebca4b6eafbdd823c46a8de574cea078211
F src/btreeInt.h 4330c19b8314545fdb209cc77e2a57f6a5290e9c
F src/build.c 04e0783a105d4d65c1850815adfdfe7403dcb592
F src/build.c 580561a0d9e070ff2741f3b115cae51c1ef08260
F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0
F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
F src/date.c 49c5a6d2de6c12000905b4d36868b07d3011bbf6
@ -168,11 +168,11 @@ F src/update.c 2add92a6159fa73128653706574afbcd8fd1dd80
F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736
F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624
F src/vacuum.c a5e51c77370c1a6445e86d42abfc43867cdd482d
F src/vdbe.c 9859467b3762a1c05f956b5f556fb922e139ff9f
F src/vdbe.c a99beac1162fa490c4b75ac36ed97146ab181837
F src/vdbe.h 79e09ff13b85457abe437d9814454534ebbc1fe3
F src/vdbeInt.h 630145b9bfaa19190ab491f52658a7db550f2247
F src/vdbeapi.c dd2c43317294e0a013e9f634ee4209a3ea459b43
F src/vdbeaux.c 285f113364134f7c1571456723dcb84be89e6c3f
F src/vdbeaux.c 5bc14ff3da6c6b3b7f643cbc3d50a344e9b599f8
F src/vdbeblob.c 82f51cdf9b0c0af729732fde48c824e498c0a1ca
F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6
F src/vdbemem.c 123994fcd344993d2fb050a83b91b341bbbd08b4
@ -477,6 +477,7 @@ F test/tkt2643.test 3f3ebb743da00d4fed4fcf6daed92a0e18e57813
F test/tkt2686.test 8815c3eeae7c8363bd7c2889349ec39e8bc8000d
F test/tkt2767.test 6b02308d553d194f329a469bf5c157fe724738d4
F test/tkt2817.test 709a2201a5590bf56cb97f6fb168a62282203fd1
F test/tkt2820.test 017fdee33aaef7abc092beab6088816f1942304b
F test/trace.test 75ffc1b992c780d054748a656e3e7fd674f18567
F test/trans.test b73289992b46d38d9479ecc4fdc03d8edb2413dc
F test/trigger1.test 7c13f39ca36f529bf856e05c7d004fc0531d48b4
@ -504,7 +505,7 @@ F test/vtab3.test f38d6d7d19f08bffdadce4d5b8cba078f8118587
F test/vtab4.test a9d7104d41a787754a734740d7aa61c807a69f87
F test/vtab5.test 26bc7a0a52c5c2bcfa849ba327f8a0d4abccdb23
F test/vtab6.test ec0036f29f8a803da9935206f2d9d1b6a8026392
F test/vtab7.test 9249e8e31f4f1a44f07984b402d12ce3e63be4f3
F test/vtab7.test a8c3c3cb3eb60be364991bd714e4927e26c4cd85
F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583
F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b
F test/vtabA.test 9cb6b1afead6fdd91bbdf1ca65c44ccfd9b10936
@ -596,7 +597,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
P 78f359dffa6f4af4d5b7e4523f451e0e405350c0
R cfc28c51a4620cec082dc386c8465836
P 7c2cf4542852a81daf29a930ab103c52bb678326
R c111fb18ebb6378f510e950ea7f7ef09
U drh
Z c95254d1012df22f0a03f3a42376bc6c
Z 60a6d3adb97dfb253eaa60aa3a1f2c5c

View File

@ -1 +1 @@
7c2cf4542852a81daf29a930ab103c52bb678326
bf34284ff0c60ae6e735e09bb29cd48b158e8dce

View File

@ -22,7 +22,7 @@
** COMMIT
** ROLLBACK
**
** $Id: build.c,v 1.449 2007/12/02 11:46:35 danielk1977 Exp $
** $Id: build.c,v 1.450 2007/12/04 16:54:53 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -1994,7 +1994,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
if( v ){
Trigger *pTrigger;
Db *pDb = &db->aDb[iDb];
sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3BeginWriteOperation(pParse, 1, iDb);
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pTab) ){
@ -2808,6 +2808,7 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
/* 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),

View File

@ -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.655 2007/11/29 17:05:18 danielk1977 Exp $
** $Id: vdbe.c,v 1.656 2007/12/04 16:54:53 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -2410,7 +2410,8 @@ case OP_MakeRecord: {
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) ){
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) ){
@ -4088,6 +4089,7 @@ case OP_Destroy: {
#endif
if( iCnt>1 ){
rc = SQLITE_LOCKED;
p->errorAction = OE_Abort;
}else{
assert( iCnt==1 );
assert( (p->btreeMask & (1<<pOp->p2))!=0 );

View File

@ -270,10 +270,17 @@ int sqlite3VdbeOpcodeNoPush(u8 op){
** entries that static analysis reveals this program might need.
**
** This routine also does the following optimization: It scans for
** Halt instructions where P1==SQLITE_CONSTRAINT or P2==OE_Abort or for
** IdxInsert instructions where P2!=0. 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.
** 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;
@ -299,6 +306,8 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs, int *pMaxStack){
}
}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;
@ -1387,7 +1396,7 @@ int sqlite3VdbeHalt(Vdbe *p){
/* Check for one of the special errors */
mrc = p->rc & 0xff;
isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR
|| mrc==SQLITE_INTERRUPT || mrc==SQLITE_FULL ;
|| 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:

94
test/tkt2820.test Normal file
View File

@ -0,0 +1,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

View File

@ -12,7 +12,7 @@
# of this test is reading and writing to the database from within a
# virtual table xSync() callback.
#
# $Id: vtab7.test,v 1.3 2007/10/09 08:29:33 danielk1977 Exp $
# $Id: vtab7.test,v 1.4 2007/12/04 16:54:53 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@ -114,15 +114,22 @@ do_test vtab7-2.5 {
} {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) {
execsql { DROP TABLE newtab }
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}
} {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 {
@ -198,4 +205,3 @@ trace remove variable ::echo_module write echo_module_trace
unset -nocomplain ::callbacks
finish_test