Take advantage of the fact that b-tree cursors need not be closed while other cursors modify their tables to simplify trigger program generation code. (CVS 4654)
FossilOrigin-Name: f1966a8a47fca85f7862c0797a527ab01ac8b0c1
diff --git a/src/btree.c b/src/btree.c
index 4590bdd..7734de4 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
-** $Id: btree.c,v 1.435 2008/01/01 06:19:02 danielk1977 Exp $
+** $Id: btree.c,v 1.436 2008/01/02 11:50:51 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** See the header comment on "btreeInt.h" for additional information.
@@ -6229,7 +6229,9 @@
/* TODO: What about CURSOR_REQUIRESEEK state? Probably need to call
** restoreOrClearCursorPosition() here.
*/
- MemPage *pPage = pCur->pPage;
+ MemPage *pPage;
+ restoreOrClearCursorPosition(pCur);
+ pPage = pCur->pPage;
assert( cursorHoldsMutex(pCur) );
assert( pPage->pBt==pCur->pBt );
return pPage ? pPage->aData[pPage->hdrOffset] : 0;
diff --git a/src/delete.c b/src/delete.c
index f2a63d5..6dd0902 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** in order to generate code for DELETE FROM statements.
**
-** $Id: delete.c,v 1.136 2008/01/02 00:34:37 drh Exp $
+** $Id: delete.c,v 1.137 2008/01/02 11:50:51 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -175,6 +175,9 @@
*/
assert( pTabList->nSrc==1 );
iCur = pTabList->a[0].iCursor = pParse->nTab++;
+ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ pParse->nTab++;
+ }
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
sNC.pSrcList = pTabList;
@@ -293,19 +296,26 @@
*/
end = sqlite3VdbeMakeLabel(v);
- /* This is the beginning of the delete loop when there are
- ** row triggers.
+ if( !isView ){
+ /* Open cursors for the table we are deleting from and
+ ** all its indices.
+ */
+ sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite);
+ }
+
+ /* This is the beginning of the delete loop. If a trigger encounters
+ ** an IGNORE constraint, it jumps back to here.
*/
if( triggers_exist ){
- int mem1 = pParse->nMem++;
- int addr_rowdata;
- u32 mask;
sqlite3VdbeResolveLabel(v, addr);
- addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end);
- sqlite3VdbeAddOp(v, OP_StackDepth, -1, 0);
- sqlite3VdbeAddOp(v, OP_MemStore, mem1, 0);
+ }
+ addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end);
+ sqlite3VdbeAddOp(v, OP_StackDepth, -1, 0);
+
+ if( triggers_exist ){
+ int mem1 = pParse->nMem++;
if( !isView ){
- sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
+ sqlite3VdbeAddOp(v, OP_MemStore, mem1, 0);
}
sqlite3VdbeAddOp(v, OP_NotExists, iCur, addr);
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
@@ -329,21 +339,6 @@
}
if( !isView ){
- /* Open cursors for the table we are deleting from and all its
- ** indices. If there are row triggers, this happens inside the
- ** OP_FifoRead loop because the cursor have to all be closed
- ** before the trigger fires. If there are no row triggers, the
- ** cursors are opened only once on the outside the loop.
- */
- sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite);
-
- /* This is the beginning of the delete loop when there are no
- ** row triggers */
- if( !triggers_exist ){
- addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end);
- sqlite3VdbeAddOp(v, OP_StackDepth, -1, 0);
- }
-
/* Delete the row */
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pTab) ){
@@ -360,13 +355,6 @@
** the AFTER triggers
*/
if( triggers_exist ){
- if( !isView ){
- for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
- sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
- }
- sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
- }
-
/* Jump back and run the AFTER triggers */
sqlite3VdbeAddOp(v, OP_Goto, 0, iBeginAfterTrigger);
sqlite3VdbeJumpHere(v, iEndAfterTrigger);
@@ -377,7 +365,7 @@
sqlite3VdbeResolveLabel(v, end);
/* Close the cursors after the loop if there are no row triggers */
- if( !triggers_exist && !IsVirtual(pTab) ){
+ if( !isView && !IsVirtual(pTab) ){
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
}
diff --git a/src/insert.c b/src/insert.c
index 6e3440d..26eb7a2 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
**
-** $Id: insert.c,v 1.199 2008/01/02 00:34:37 drh Exp $
+** $Id: insert.c,v 1.200 2008/01/02 11:50:51 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -625,8 +625,8 @@
sqlite3VdbeAddOp(v, OP_MemInt, 0, iCntMem);
}
- /* Open tables and indices if there are no row triggers */
- if( !triggers_exist ){
+ /* If this is not a view, open the table and and all indices */
+ if( !isView ){
base = pParse->nTab;
sqlite3OpenTableAndIndices(pParse, pTab, base, OP_OpenWrite);
}
@@ -713,14 +713,6 @@
}
}
- /* If any triggers exists, the opening of tables and indices is deferred
- ** until now.
- */
- if( triggers_exist && !isView ){
- base = pParse->nTab;
- sqlite3OpenTableAndIndices(pParse, pTab, base, OP_OpenWrite);
- }
-
/* Push the record number for the new entry onto the stack. The
** record number is a randomly generate integer created by NewRowid
** except when the table has an INTEGER PRIMARY KEY column, in which
@@ -827,14 +819,6 @@
}
if( triggers_exist ){
- /* Close all tables opened */
- if( !isView ){
- sqlite3VdbeAddOp(v, OP_Close, base, 0);
- for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
- sqlite3VdbeAddOp(v, OP_Close, idx+base, 0);
- }
- }
-
/* Code AFTER triggers */
if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_AFTER, pTab,
newIdx, -1, onError, endOfLoop, 0, 0) ){
@@ -855,7 +839,7 @@
sqlite3VdbeResolveLabel(v, iCleanup);
}
- if( !triggers_exist && !IsVirtual(pTab) ){
+ if( !IsVirtual(pTab) && !isView ){
/* Close all tables opened */
sqlite3VdbeAddOp(v, OP_Close, base, 0);
for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
diff --git a/src/update.c b/src/update.c
index 0edc861..7c6017a 100644
--- a/src/update.c
+++ b/src/update.c
@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
-** $Id: update.c,v 1.146 2008/01/02 00:34:37 drh Exp $
+** $Id: update.c,v 1.147 2008/01/02 11:50:51 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -298,7 +298,16 @@
/* Generate the code for triggers.
*/
if( triggers_exist ){
- int iGoto = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
+ int iGoto;
+
+ /* Create pseudo-tables for NEW and OLD
+ */
+ sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
+ sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
+ sqlite3VdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
+ sqlite3VdbeAddOp(v, OP_SetNumColumns, newIdx, pTab->nCol);
+
+ iGoto = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
addr = sqlite3VdbeMakeLabel(v);
iBeginBeforeTrigger = sqlite3VdbeCurrentAddr(v);
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab,
@@ -347,27 +356,50 @@
sqlite3VdbeAddOp(v, OP_MemInt, 0, memCnt);
}
- if( triggers_exist ){
- /* Create pseudo-tables for NEW and OLD
+ if( !isView && !IsVirtual(pTab) ){
+ /*
+ ** Open every index that needs updating. Note that if any
+ ** index could potentially invoke a REPLACE conflict resolution
+ ** action, then we need to open all indices because we might need
+ ** to be deleting some records.
*/
- sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
- sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
- sqlite3VdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
- sqlite3VdbeAddOp(v, OP_SetNumColumns, newIdx, pTab->nCol);
-
- /* The top of the update loop for when there are triggers.
- */
- sqlite3VdbeResolveLabel(v, addr);
- addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);
- sqlite3VdbeAddOp(v, OP_StackDepth, -1, 0);
- sqlite3VdbeAddOp(v, OP_MemStore, mem1, 0);
-
- if( !isView ){
- /* Open a cursor and make it point to the record that is
- ** being updated.
- */
- sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
+ sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite);
+ if( onError==OE_Replace ){
+ openAll = 1;
+ }else{
+ openAll = 0;
+ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ if( pIdx->onError==OE_Replace ){
+ openAll = 1;
+ break;
+ }
+ }
}
+ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
+ if( openAll || aIdxUsed[i] ){
+ KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
+ sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
+ sqlite3VdbeOp3(v, OP_OpenWrite, iCur+i+1, pIdx->tnum,
+ (char*)pKey, P3_KEYINFO_HANDOFF);
+ assert( pParse->nTab>iCur+i+1 );
+ }
+ }
+
+ }
+
+ /* Jump back to this point if a trigger encounters an IGNORE constraint. */
+ if( triggers_exist ){
+ sqlite3VdbeResolveLabel(v, addr);
+ }
+
+ /* Top of the update loop */
+ addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);
+ sqlite3VdbeAddOp(v, OP_StackDepth, -1, 0);
+ sqlite3VdbeAddOp(v, OP_MemStore, mem1, 0);
+
+ if( triggers_exist ){
+ /* Make cursor iCur point to the record that is being updated.
+ */
sqlite3VdbeAddOp(v, OP_NotExists, iCur, addr);
/* Generate the OLD table
@@ -410,9 +442,6 @@
}
if( pParse->nErr ) goto update_cleanup;
sqlite3VdbeAddOp(v, OP_Insert, newIdx, 0);
- if( !isView ){
- sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
- }
sqlite3VdbeAddOp(v, OP_Goto, 0, iBeginBeforeTrigger);
sqlite3VdbeJumpHere(v, iEndBeforeTrigger);
@@ -423,33 +452,6 @@
}
if( !isView && !IsVirtual(pTab) ){
- /*
- ** Open every index that needs updating. Note that if any
- ** index could potentially invoke a REPLACE conflict resolution
- ** action, then we need to open all indices because we might need
- ** to be deleting some records.
- */
- sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite);
- if( onError==OE_Replace ){
- openAll = 1;
- }else{
- openAll = 0;
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- if( pIdx->onError==OE_Replace ){
- openAll = 1;
- break;
- }
- }
- }
- for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
- if( openAll || aIdxUsed[i] ){
- KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
- sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
- sqlite3VdbeOp3(v, OP_OpenWrite, iCur+i+1, pIdx->tnum,
- (char*)pKey, P3_KEYINFO_HANDOFF);
- assert( pParse->nTab>iCur+i+1 );
- }
- }
/* Loop over every record that needs updating. We have to load
** the old data for each record to be updated because some columns
@@ -457,11 +459,6 @@
** Also, the old data is needed to delete the old index entries.
** So make the cursor point at the old record.
*/
- if( !triggers_exist ){
- addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);
- sqlite3VdbeAddOp(v, OP_StackDepth, -1, 0);
- sqlite3VdbeAddOp(v, OP_MemStore, mem1, 0);
- }
sqlite3VdbeAddOp(v, OP_NotExists, iCur, addr);
sqlite3VdbeAddOp(v, OP_MemLoad, mem1, 0);
@@ -520,13 +517,6 @@
** through the loop. The fire the after triggers.
*/
if( triggers_exist ){
- if( !isView ){
- for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
- if( openAll || aIdxUsed[i] )
- sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
- }
- sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
- }
sqlite3VdbeAddOp(v, OP_Goto, 0, iBeginAfterTrigger);
sqlite3VdbeJumpHere(v, iEndAfterTrigger);
}
@@ -537,15 +527,14 @@
sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
sqlite3VdbeJumpHere(v, addr);
- /* Close all tables if there were no FOR EACH ROW triggers */
- if( !triggers_exist ){
- for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
- if( openAll || aIdxUsed[i] ){
- sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
- }
+ /* Close all tables */
+ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
+ if( openAll || aIdxUsed[i] ){
+ sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
}
- sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
- }else{
+ }
+ sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
+ if( triggers_exist ){
sqlite3VdbeAddOp(v, OP_Close, newIdx, 0);
sqlite3VdbeAddOp(v, OP_Close, oldIdx, 0);
}
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 69d1612..fbcb881 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -701,10 +701,12 @@
}
}
assert( zP3!=0 );
+#ifdef SQLITE_DEBUG
if( pOp->zComment && zP3==zTemp && (nP3 = strlen(zP3))<nTemp ){
sqlite3_snprintf(nTemp-nP3, &zP3[nP3], "%s# %s",
nP3>0 ? " " : "", pOp->zComment);
}
+#endif
return zP3;
}
#endif