mirror of https://github.com/sqlite/sqlite
Combine the OP_Statement and OP_Transaction opcodes.
FossilOrigin-Name: aec9dbd8d21c55c3945287a3dfa55d3ed168f977
This commit is contained in:
parent
2283d46cd6
commit
e0af83aca6
36
manifest
36
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
|
||||
|
|
|
@ -1 +1 @@
|
|||
85cb0c94a63eda5f059ebe40887c7af9b4869893
|
||||
aec9dbd8d21c55c3945287a3dfa55d3ed168f977
|
|
@ -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
|
||||
|
||||
|
|
35
src/build.c
35
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<<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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
23
src/expr.c
23
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
|
||||
|
|
16
src/insert.c
16
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 ){
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
62
src/vdbe.c
62
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->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;
|
||||
}
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue