]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Combine the OP_Statement and OP_Transaction opcodes.
authordan <dan@noemail.net>
Tue, 8 Sep 2009 19:15:01 +0000 (19:15 +0000)
committerdan <dan@noemail.net>
Tue, 8 Sep 2009 19:15:01 +0000 (19:15 +0000)
FossilOrigin-Name: aec9dbd8d21c55c3945287a3dfa55d3ed168f977

15 files changed:
manifest
manifest.uuid
src/alter.c
src/build.c
src/delete.c
src/expr.c
src/insert.c
src/sqliteInt.h
src/update.c
src/vdbe.c
src/vdbe.h
src/vdbeapi.c
src/vdbeaux.c
src/vdbeblob.c
test/triggerC.test

index 29b6ef18a215255c73f88f4f299cbadd739f1156..7c094215f9a50b63843798646c7dbe56c108864c 100644 (file)
--- 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
index 15344aef712c9d563837d540aa1921924e423ae5..75afbe71487476b0591c24040be6d32ce26a52e4 100644 (file)
@@ -1 +1 @@
-85cb0c94a63eda5f059ebe40887c7af9b4869893
\ No newline at end of file
+aec9dbd8d21c55c3945287a3dfa55d3ed168f977
\ No newline at end of file
index 14b58df336dd39cf3078825bdbf175868ff2abf1..819d5bbf8f4486636bb6dbe791ce2b1b1b7f5cbc 100644 (file)
@@ -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
 
index 431d5b5cdbd34a5e2c418b649ec38863507f8a8f..4e0f13475aff4d5e356f57dae643c9801a04d466 100644 (file)
@@ -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<<iDb;
-  if( setStatement && pParse->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);
 }
 
 /*
index f0ca8ab4714a4eb616375c3daf586df3837bb172..6f4b54e917246d318db7bde545b5f8f9d8998d07 100644 (file)
@@ -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
     {
index 75ff04bce8de2016460390d89c22872f62e70091..50b24de413423884968b6ea7b9273e7c317e9c5b 100644 (file)
@@ -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
index a1db400e1eb0e2a255cf06b7e426316ddb9c78d0..f27d50f23eb344cc1d8dce4a8e316d5bc234a22e 100644 (file)
@@ -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 ){
index 45742738090896321a890d2e5086682b836c3cb8..fa5aaa0b42a607a46279077fb3b8754c781e6e40 100644 (file)
@@ -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);
index ba1ad91f2c5d1992131e8b86a50c6ec06e4bf4e0..b0df33399d52c12540e971441ddd38fbafa97073 100644 (file)
@@ -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);
index 6d972d3837cd966f9497e1fea79fd8b5d7bdc2f7..823b5f6f8cd2ecfe2847227ea02636e40c1dbf87 100644 (file)
@@ -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->p1<db->nDb );
-    assert( db->aDb[pOp->p1].pBt!=0 );
-    pBt = db->aDb[pOp->p1].pBt;
-    assert( sqlite3BtreeIsInTrans(pBt) );
-    assert( (p->btreeMask & (1<<pOp->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;
 }
index 3fef873827a90344e09e6cad8a273a45496fac43..3df12c363ce5452cd2e7a4222ec76633a12eb682 100644 (file)
@@ -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*);
index fc3af40040467d8c03da8d7ca53e3c055bb34e15..634c29c45da0ebd97528401035cc3d63897abc90 100644 (file)
@@ -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);
index 35ae1e355c8ab7231cd73d3dd4a36ebbd39ddaec..b410c4322068bccfb0349f704bab56dd0dba746c 100644 (file)
@@ -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;
     }
index b17af8acf78c4b6aeaa6167b9715b930be53b7c9..009234f4ef7f7f5995d4ed454af221e94672e0a3 100644 (file)
@@ -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);
       }
     }
    
index 426d6108c8f3a32033127195f7e359694c2111af..2df9e135e8f57abdb668e7ee1243ad854ac558b5 100644 (file)
@@ -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