From: dan Date: Tue, 8 Sep 2009 19:15:01 +0000 (+0000) Subject: Combine the OP_Statement and OP_Transaction opcodes. X-Git-Tag: fts3-refactor~206 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e0af83aca632cb406a40e5de08347e3af8b1b460;p=thirdparty%2Fsqlite.git Combine the OP_Statement and OP_Transaction opcodes. FossilOrigin-Name: aec9dbd8d21c55c3945287a3dfa55d3ed168f977 --- diff --git a/manifest b/manifest index 29b6ef18a2..7c094215f9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C If\srecursive-triggers\sare\senabled,\sfire\sDELETE\striggers\sif\sdatabase\srows\sare\sremoved\sas\sa\sresult\sof\sOR\sREPLACE\sconflict\sresolution. -D 2009-09-08T15:55:16 +C Combine\sthe\sOP_Statement\sand\sOP_Transaction\sopcodes. +D 2009-09-08T19:15:01 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in 73ddeec9dd10b85876c5c2ce1fdce627e1dcc7f8 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -99,7 +99,7 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad -F src/alter.c 55b601857d924e07c91cfa69e9b2cb5093498c93 +F src/alter.c 0bbc34296384ae85e0e5e857aa605614ca2d404c F src/analyze.c 5a8b8aa3d170eac5e71af45458cec61f83c623ee F src/attach.c 13995348fc5a26cdd136a50806faf292aabc173f F src/auth.c d6a88bf8e81e6a079ccb8881002b327e42ec46b9 @@ -109,19 +109,19 @@ F src/btmutex.c 0f43a75bb5b8147b386e8e1c3e71ba734e3863b7 F src/btree.c 873a82706e07604a638e02e12617983df8e8070a F src/btree.h 577448a890c2ab9b21e6ab74f073526184bceebe F src/btreeInt.h 1c86297e69380f6577e7ae67452597dd8d5c2705 -F src/build.c df8dfff696329c192240e3d532f9dad0ef5abace +F src/build.c 1a21d6dcb6a60b065f5407c6a5f2d021f946fa34 F src/callback.c f49c305dc94b78da948953c392963929c0e70f9b F src/complete.c 5ad5c6cd4548211867c204c41a126d73a9fbcea0 F src/date.c ab5f7137656652a48434d64f96bdcdc823bb23b3 -F src/delete.c 4c9b899246a12795ae7f145ad7c5c3ac563fa05f -F src/expr.c 2605f0f161442e3153e0c41e987525260e9ad306 +F src/delete.c 70abd255f094f37411d7c76c65874cf86d435529 +F src/expr.c 638b599adad562d41c3bf90f542f9419664aa7b8 F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff F src/func.c e536218d193b8d326aab91120bc4c6f28aa2b606 F src/global.c 271952d199a8cc59d4ce840b3bbbfd2f30c8ba32 F src/hash.c ebcaa921ffd9d86f7ea5ae16a0a29d1c871130a7 F src/hash.h 35b216c13343d0b4f87d9f21969ac55ad72174e1 F src/hwtime.h 4a1d45f4cae1f402ea19686acf24acf4f0cb53cb -F src/insert.c 5cf80f9b4222c2145cab299e9b829385846b6937 +F src/insert.c 755028b84a6442b684ee24b445daee612d9aa539 F src/journal.c e00df0c0da8413ab6e1bb7d7cab5665d4a9000d0 F src/legacy.c 303b4ffcf1ae652fcf5ef635846c563c254564f6 F src/lempar.c 0c4d1ab0a5ef2b0381eb81a732c54f68f27a574d @@ -163,7 +163,7 @@ F src/select.c a7a075456d4e640ffd7d0a33202d306c69c88f72 F src/shell.c db2643650b9268df89a4bedca3f1c6d9e786f1bb F src/sqlite.h.in e5949b46f9a05aadde22848f92fae5c9ba87ee0e F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17 -F src/sqliteInt.h b39de08df1442d48a6ea85c227c609e696a85b89 +F src/sqliteInt.h 66914c7a4a8ad427dc3705e13df95763003ea8fb F src/sqliteLimit.h be44f7f46c14bb4c21870074b1e6f1ac0abd6701 F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76 F src/table.c cc86ad3d6ad54df7c63a3e807b5783c90411a08d @@ -201,16 +201,16 @@ F src/test_thread.c b8a1ab7ca1a632f18e8a361880d5d65eeea08eac F src/test_wsd.c 3ae5101de6cbfda2720152ab659ea84079719241 F src/tokenize.c af8a56e6a50c5042fc305bfa796275e9bf26ff2b F src/trigger.c 054c08339b3471c785f1cf041ed878a425850e33 -F src/update.c 3e97974baa914f32d4ae690fa0cb7281aff8cd39 +F src/update.c 7a2c0dad3badd60320ff12bb42ca1446c1f7da28 F src/utf.c 99cf927eabb104621ba889ac0dd075fc1657ad30 F src/util.c 59d4e9456bf1fe581f415a783fa0cee6115c8f35 F src/vacuum.c 3fe0eebea6d2311c1c2ab2962887d11f7a4dcfb0 -F src/vdbe.c 5dc91d9b7da2277b72721948134fd800918cca35 -F src/vdbe.h 080fe6bc1264438becb8bf9b9f3c84074c336b78 +F src/vdbe.c aba680ec9cf68890f3600a4c0c1936b1d789d111 +F src/vdbe.h afd9c99544fd916c93c6de5b1d11490899e483ea F src/vdbeInt.h 004dbb28a9195b6c85fe3255c7cc300ffd8b9453 -F src/vdbeapi.c 8d5013ab6104be757c208a70ffb191cc27d2b688 -F src/vdbeaux.c ec1545ece73dd739c9043f14963fb3f20d3880d6 -F src/vdbeblob.c f93cb60ac388633ed3bde8a94ef161ad2dbfb689 +F src/vdbeapi.c b7e5f34436e298e2b0168e71323b5d97f7e9b080 +F src/vdbeaux.c 75dff9148f3bcdb5772ca00be774f7194a4fce61 +F src/vdbeblob.c 4d6b702ca714a2d52552eee72d3e3191f8444eab F src/vdbemem.c 0ff2b209fccade3ff6709286057b82ed7f6c1e70 F src/vtab.c 3e54fe39374e5feb8b174de32a90e7a21966025d F src/walker.c 1edca756275f158b80f20eb6f104c8d3fcc96a04 @@ -682,7 +682,7 @@ F test/trigger8.test 30cb0530bd7c4728055420e3f739aa00412eafa4 F test/trigger9.test 5b0789f1c5c4600961f8e68511b825b87be53e31 F test/triggerA.test 0718ad2d9bfef27c7af00e636df79bee6b988da7 F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe -F test/triggerC.test 3e13e9a87939797115343b261a3f893c71304106 +F test/triggerC.test 427f3036f0d1a8e65db99d3e98b9c34edf559104 F test/types.test 9a825ec8eea4e965d7113b74c76a78bb5240f2ac F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84 F test/types3.test a0f66bf12f80fad89493535474f7a6d16fa58150 @@ -750,7 +750,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 4ab8c841f818326b0b04b95e3edd828c77f109d9 -R 3fb4417640a30cdf072206af6c01b085 +P 85cb0c94a63eda5f059ebe40887c7af9b4869893 +R 6a11a24dc821178a3e61515331c83e2c U dan -Z 8bcac683a9d824da75eea0a85386a639 +Z 33e8150d74d6f5afb30b73dad757212c diff --git a/manifest.uuid b/manifest.uuid index 15344aef71..75afbe7148 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -85cb0c94a63eda5f059ebe40887c7af9b4869893 \ No newline at end of file +aec9dbd8d21c55c3945287a3dfa55d3ed168f977 \ No newline at end of file diff --git a/src/alter.c b/src/alter.c index 14b58df336..819d5bbf8f 100644 --- a/src/alter.c +++ b/src/alter.c @@ -362,6 +362,7 @@ void sqlite3AlterRenameTable( int i = ++pParse->nMem; sqlite3VdbeAddOp4(v, OP_String8, 0, i, 0, zName, 0); sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pVTab, P4_VTAB); + sqlite3MayAbort(pParse); } #endif diff --git a/src/build.c b/src/build.c index 431d5b5cdb..4e0f13475a 100644 --- a/src/build.c +++ b/src/build.c @@ -195,7 +195,8 @@ void sqlite3FinishCoding(Parse *pParse){ #endif assert( pParse->iCacheLevel==0 ); /* Disables and re-enables match */ sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem, - pParse->nTab, pParse->nMaxArg, pParse->explain); + pParse->nTab, pParse->nMaxArg, pParse->explain, + pParse->isMultiWrite && pParse->mayAbort); pParse->rc = SQLITE_DONE; pParse->colNamesSet = 0; }else if( pParse->rc==SQLITE_OK ){ @@ -1878,6 +1879,7 @@ static void destroyRootPage(Parse *pParse, int iTable, int iDb){ Vdbe *v = sqlite3GetVdbe(pParse); int r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb); + sqlite3MayAbort(pParse); #ifndef SQLITE_OMIT_AUTOVACUUM /* OP_Destroy stores an in integer r1. If this integer ** is non-zero, then it is the root page number of a table moved to @@ -2319,8 +2321,8 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ ** since sqlite3ReleaseTempRange() was called, it is safe to do so. */ sqlite3VdbeAddOp4(v, OP_IsUnique, iIdx, j2, regRowid, pRegKey, P4_INT32); - sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, OE_Abort, 0, - "indexed columns are not unique", P4_STATIC); + sqlite3HaltConstraint( + pParse, OE_Abort, "indexed columns are not unique", P4_STATIC); } sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); @@ -3465,12 +3467,29 @@ void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){ Parse *pToplevel = sqlite3ParseToplevel(pParse); sqlite3CodeVerifySchema(pParse, iDb); pToplevel->writeMask |= 1<nested==0 && pParse==pToplevel ){ - /* Every place where this routine is called with setStatement!=0 has - ** already successfully created a VDBE. */ - assert( pParse->pVdbe ); - sqlite3VdbeAddOp1(pParse->pVdbe, OP_Statement, iDb); + pToplevel->isMultiWrite |= setStatement; +} + +/* +** Set the "may throw abort exception" flag for the statement currently +** being coded. +*/ +void sqlite3MayAbort(Parse *pParse){ + Parse *pToplevel = sqlite3ParseToplevel(pParse); + pToplevel->mayAbort = 1; +} + +/* +** Code an OP_Halt that causes the vdbe to return an SQLITE_CONSTRAINT +** error. The onError parameter determines which (if any) of the statement +** and/or current transaction is rolled back. +*/ +void sqlite3HaltConstraint(Parse *pParse, int onError, char *p4, int p4type){ + Vdbe *v = sqlite3GetVdbe(pParse); + if( onError==OE_Abort ){ + sqlite3MayAbort(pParse); } + sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, p4, p4type); } /* diff --git a/src/delete.c b/src/delete.c index f0ca8ab471..6f4b54e917 100644 --- a/src/delete.c +++ b/src/delete.c @@ -392,6 +392,7 @@ void sqlite3DeleteFrom( const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); sqlite3VtabMakeWritable(pParse, pTab); sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iRowid, pVTab, P4_VTAB); + sqlite3MayAbort(pParse); }else #endif { diff --git a/src/expr.c b/src/expr.c index 75ff04bce8..50b24de413 100644 --- a/src/expr.c +++ b/src/expr.c @@ -2692,20 +2692,27 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ } #ifndef SQLITE_OMIT_TRIGGER case TK_RAISE: { - int vrc; - if( !pParse->pTriggerTab ){ - sqlite3ErrorMsg(pParse, - "RAISE() may only be used within a trigger-program"); - return 0; - } assert( pExpr->affinity==OE_Rollback || pExpr->affinity==OE_Abort || pExpr->affinity==OE_Fail || pExpr->affinity==OE_Ignore ); + if( !pParse->pTriggerTab ){ + sqlite3ErrorMsg(pParse, + "RAISE() may only be used within a trigger-program"); + return 0; + } + if( pExpr->affinity==OE_Abort ){ + sqlite3MayAbort(pParse); + } assert( !ExprHasProperty(pExpr, EP_IntValue) ); - vrc = (pExpr->affinity==OE_Ignore ? SQLITE_OK : SQLITE_CONSTRAINT); - sqlite3VdbeAddOp4(v, OP_Halt, vrc, pExpr->affinity, 0, pExpr->u.zToken,0); + if( pExpr->affinity==OE_Ignore ){ + sqlite3VdbeAddOp4( + v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0); + }else{ + sqlite3HaltConstraint(pParse, pExpr->affinity, pExpr->u.zToken, 0); + } + break; } #endif diff --git a/src/insert.c b/src/insert.c index a1db400e1e..f27d50f23e 100644 --- a/src/insert.c +++ b/src/insert.c @@ -971,6 +971,7 @@ void sqlite3Insert( const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); sqlite3VtabMakeWritable(pParse, pTab); sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns, pVTab, P4_VTAB); + sqlite3MayAbort(pParse); }else #endif { @@ -1169,8 +1170,9 @@ void sqlite3GenerateConstraintChecks( assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail || onError==OE_Ignore || onError==OE_Replace ); switch( onError ){ - case OE_Rollback: case OE_Abort: + sqlite3MayAbort(pParse); + case OE_Rollback: case OE_Fail: { char *zMsg; j1 = sqlite3VdbeAddOp3(v, OP_HaltIfNull, @@ -1205,7 +1207,7 @@ void sqlite3GenerateConstraintChecks( if( onError==OE_Ignore ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); }else{ - sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_CONSTRAINT, onError); + sqlite3HaltConstraint(pParse, onError, 0, 0); } sqlite3VdbeResolveLabel(v, allOk); } @@ -1236,8 +1238,8 @@ void sqlite3GenerateConstraintChecks( case OE_Rollback: case OE_Abort: case OE_Fail: { - sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, - "PRIMARY KEY must be unique", P4_STATIC); + sqlite3HaltConstraint( + pParse, onError, "PRIMARY KEY must be unique", P4_STATIC); break; } case OE_Replace: { @@ -1350,7 +1352,7 @@ void sqlite3GenerateConstraintChecks( sqlite3StrAccumAppend(&errMsg, pIdx->nColumn>1 ? " are not unique" : " is not unique", -1); zErr = sqlite3StrAccumFinish(&errMsg); - sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, zErr, 0); + sqlite3HaltConstraint(pParse, onError, zErr, 0); sqlite3DbFree(errMsg.db, zErr); break; } @@ -1747,8 +1749,8 @@ static int xferOptimization( if( pDest->iPKey>=0 ){ addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid); - sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, - "PRIMARY KEY must be unique", P4_STATIC); + sqlite3HaltConstraint( + pParse, onError, "PRIMARY KEY must be unique", P4_STATIC); sqlite3VdbeJumpHere(v, addr2); autoIncStep(pParse, regAutoinc, regRowid); }else if( pDest->pIndex==0 ){ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 4574273809..fa5aaa0b42 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2097,6 +2097,8 @@ struct Parse { } aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */ u32 writeMask; /* Start a write transaction on these databases */ u32 cookieMask; /* Bitmask of schema verified databases */ + u8 isMultiWrite; /* True if statement may affect/insert multiple rows */ + u8 mayAbort; /* True if statement may throw an ABORT exception */ int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */ int cookieValue[SQLITE_MAX_ATTACHED+2]; /* Values of cookies to verify */ #ifndef SQLITE_OMIT_SHARED_CACHE @@ -2655,6 +2657,8 @@ void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int, void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*, int, int, int); int sqlite3OpenTableAndIndices(Parse*, Table*, int, int); void sqlite3BeginWriteOperation(Parse*, int, int); +void sqlite3MayAbort(Parse *); +void sqlite3HaltConstraint(Parse*, int, char*, int); Expr *sqlite3ExprDup(sqlite3*,Expr*,int); ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int); SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int); diff --git a/src/update.c b/src/update.c index ba1ad91f2c..b0df33399d 100644 --- a/src/update.c +++ b/src/update.c @@ -586,6 +586,7 @@ static void updateVirtualTable( } sqlite3VtabMakeWritable(pParse, pTab); sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2, iReg, pVTab, P4_VTAB); + sqlite3MayAbort(pParse); sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1); sqlite3VdbeJumpHere(v, addr); sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0); diff --git a/src/vdbe.c b/src/vdbe.c index 6d972d3837..823b5f6f8c 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2452,46 +2452,6 @@ case OP_Count: { /* out2-prerelease */ } #endif -/* Opcode: Statement P1 * * * * -** -** Begin an individual statement transaction which is part of a larger -** transaction. This is needed so that the statement -** can be rolled back after an error without having to roll back the -** entire transaction. The statement transaction will automatically -** commit when the VDBE halts. -** -** If the database connection is currently in autocommit mode (that -** is to say, if it is in between BEGIN and COMMIT) -** and if there are no other active statements on the same database -** connection, then this operation is a no-op. No statement transaction -** is needed since any error can use the normal ROLLBACK process to -** undo changes. -** -** If a statement transaction is started, then a statement journal file -** will be allocated and initialized. -** -** 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: { - Btree *pBt; - if( db->autoCommit==0 || db->activeVdbeCnt>1 ){ - assert( pOp->p1>=0 && pOp->p1nDb ); - assert( db->aDb[pOp->p1].pBt!=0 ); - pBt = db->aDb[pOp->p1].pBt; - assert( sqlite3BtreeIsInTrans(pBt) ); - assert( (p->btreeMask & (1<p1))!=0 ); - if( p->iStatement==0 ){ - assert( db->nStatement>=0 && db->nSavepoint>=0 ); - db->nStatement++; - p->iStatement = db->nSavepoint + db->nStatement; - } - rc = sqlite3BtreeBeginStmt(pBt, p->iStatement); - } - break; -} - /* Opcode: Savepoint P1 * * P4 * ** ** Open, release or rollback the savepoint named by parameter P4, depending @@ -2720,6 +2680,16 @@ case OP_AutoCommit: { ** database. If P2 is 2 or greater then an EXCLUSIVE lock is also obtained ** on the file. ** +** If a write-transaction is started and the Vdbe.usesStmtJournal flag is +** true (this flag is set if the Vdbe may modify more than one row and may +** throw an ABORT exception), a statement transaction may also be opened. +** More specifically, a statement transaction is opened iff the database +** connection is currently not in autocommit mode, or if there are other +** active statements. A statement transaction allows the affects of this +** VDBE to be rolled back after an error without having to roll back the +** entire transaction. If no error is encountered, the statement transaction +** will automatically commit when the VDBE halts. +** ** If P2 is zero, then a read-lock is obtained on the database file. */ case OP_Transaction: { @@ -2739,6 +2709,18 @@ case OP_Transaction: { if( rc!=SQLITE_OK && rc!=SQLITE_READONLY /* && rc!=SQLITE_BUSY */ ){ goto abort_due_to_error; } + + if( pOp->p2 && p->usesStmtJournal + && (db->autoCommit==0 || db->activeVdbeCnt>1) + ){ + assert( sqlite3BtreeIsInTrans(pBt) ); + if( p->iStatement==0 ){ + assert( db->nStatement>=0 && db->nSavepoint>=0 ); + db->nStatement++; + p->iStatement = db->nSavepoint + db->nStatement; + } + rc = sqlite3BtreeBeginStmt(pBt, p->iStatement); + } } break; } diff --git a/src/vdbe.h b/src/vdbe.h index 3fef873827..3df12c363c 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -184,7 +184,7 @@ void sqlite3VdbeUsesBtree(Vdbe*, int); VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); int sqlite3VdbeMakeLabel(Vdbe*); void sqlite3VdbeDelete(Vdbe*); -void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int,int); +void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int,int,int); int sqlite3VdbeFinalize(Vdbe*); void sqlite3VdbeResolveLabel(Vdbe*, int); int sqlite3VdbeCurrentAddr(Vdbe*); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index fc3af40040..634c29c45d 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -76,7 +76,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt){ Vdbe *v = (Vdbe*)pStmt; sqlite3_mutex_enter(v->db->mutex); rc = sqlite3VdbeReset(v); - sqlite3VdbeMakeReady(v, -1, 0, 0, 0, 0); + sqlite3VdbeMakeReady(v, -1, 0, 0, 0, 0, 0); assert( (rc & (v->db->errMask))==rc ); rc = sqlite3ApiExit(v->db, rc); sqlite3_mutex_leave(v->db->mutex); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 35ae1e355c..b410c43220 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -250,29 +250,13 @@ void sqlite3VdbeResolveLabel(Vdbe *p, int x){ ** Variable *pMaxFuncArgs is set to the maximum value of any P2 argument ** to an OP_Function, OP_AggStep or OP_VFilter opcode. This is used by ** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array. -** -** 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 i; int nMaxArgs = *pMaxFuncArgs; Op *pOp; int *aLabel = p->aLabel; - int doesStatementRollback = 0; - int hasStatementBegin = 0; p->readOnly = 1; - p->usesStmtJournal = 0; for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){ u8 opcode = pOp->opcode; @@ -282,21 +266,9 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ }else if( opcode==OP_VUpdate ){ if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2; #endif - } - if( opcode==OP_Halt ){ - if( pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort ){ - doesStatementRollback = 1; - } - }else if( opcode==OP_Statement ){ - hasStatementBegin = 1; - p->usesStmtJournal = 1; - }else if( opcode==OP_Destroy || opcode==OP_Program ){ - doesStatementRollback = 1; }else if( opcode==OP_Transaction && pOp->p2!=0 ){ p->readOnly = 0; #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 ); @@ -315,20 +287,6 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ p->aLabel = 0; *pMaxFuncArgs = nMaxArgs; - - /* If we never rollback a statement transaction, then statement - ** transactions are not needed. So change every OP_Statement - ** opcode into an OP_Noop. This avoid a call to sqlite3OsOpenExclusive() - ** which can be expensive on some platforms. - */ - if( hasStatementBegin && !doesStatementRollback ){ - p->usesStmtJournal = 0; - for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){ - if( pOp->opcode==OP_Statement ){ - pOp->opcode = OP_Noop; - } - } - } } /* @@ -1237,7 +1195,8 @@ void sqlite3VdbeMakeReady( int nMem, /* Number of memory cells to allocate */ int nCursor, /* Number of cursors to allocate */ int nArg, /* Maximum number of args in SubPrograms */ - int isExplain /* True if the EXPLAIN keywords is present */ + int isExplain, /* True if the EXPLAIN keywords is present */ + int usesStmtJournal /* True to set Vdbe.usesStmtJournal */ ){ int n; sqlite3 *db = p->db; @@ -1273,6 +1232,7 @@ void sqlite3VdbeMakeReady( u8 *zEnd = (u8 *)&p->aOp[p->nOpAlloc]; int nByte; resolveP2Values(p, &nArg); + p->usesStmtJournal = usesStmtJournal; if( isExplain && nMem<10 ){ nMem = 10; } diff --git a/src/vdbeblob.c b/src/vdbeblob.c index b17af8acf7..009234f4ef 100644 --- a/src/vdbeblob.c +++ b/src/vdbeblob.c @@ -204,7 +204,7 @@ int sqlite3_blob_open( sqlite3VdbeChangeP4(v, 3+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32); sqlite3VdbeChangeP2(v, 7, pTab->nCol); if( !db->mallocFailed ){ - sqlite3VdbeMakeReady(v, 1, 1, 1, 0, 0); + sqlite3VdbeMakeReady(v, 1, 1, 1, 0, 0, 0); } } diff --git a/test/triggerC.test b/test/triggerC.test index 426d6108c8..2df9e135e8 100644 --- a/test/triggerC.test +++ b/test/triggerC.test @@ -34,6 +34,9 @@ ifcapable {!trigger} { # REPLACE conflict resolution. And that they are not fired # if recursive triggers are not enabled. # +# triggerC-6.*: Test that the recursive_triggers pragma returns correct +# results when invoked without an argument. +# # Enable recursive triggers for this file. # @@ -660,5 +663,11 @@ do_test triggerC-6.3 { } } {1} +#------------------------------------------------------------------------- +# Test some of the "undefined behaviour" associated with triggers. The +# undefined behaviour occurs when a row being updated or deleted is +# manipulated by a BEFORE trigger. +# + finish_test