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/manifest b/manifest
index 2d6c790..ce9b7c0 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\ssome\sextra\stests\sfor\sthe\srecent\strigger\scompilation\soptimization.\s(CVS\s4653)
-D 2008-01-02T04:41:25
+C Take\sadvantage\sof\sthe\sfact\sthat\sb-tree\scursors\sneed\snot\sbe\sclosed\swhile\sother\scursors\smodify\stheir\stables\sto\ssimplify\strigger\sprogram\sgeneration\scode.\s(CVS\s4654)
+D 2008-01-02T11:50:51
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -83,20 +83,20 @@
F src/attach.c 95658e74e3e0d1cbdb8658817516d4d1467fc13d
F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627
F src/btmutex.c 5d39da37c9d1282f3c6f9967afae6a34ee36b7ff
-F src/btree.c 6c3ded4f31046de72993a440921ad50a7eb4a65d
+F src/btree.c 5164b32950cfd41f2c5c31e8ff82c4a499918aef
F src/btree.h 19dcf5ad23c17b98855da548e9a8e3eb4429d5eb
F src/btreeInt.h 1c5a9da165718ef7de81e35ce9ab5d9ba9283f76
F src/build.c cbfd98ceb95c61c226cd60a845fa7967b66c8931
F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0
F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
F src/date.c 49c5a6d2de6c12000905b4d36868b07d3011bbf6
-F src/delete.c a4843531af1354882ea7dbe53fa5f46b581ae73c
+F src/delete.c e750b537a77da4971c39e3fbb569de55fe4cf095
F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
F src/expr.c c3fb939d6801071ce19243521ca444eca40b057a
F src/func.c 996071cf0af9d967e58b69fce1909555059ebc7d
F src/hash.c 45a7005aac044b6c86bd7e49c44bc15d30006d6c
F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53
-F src/insert.c 355c482603c8c5151b23c3c7661cf1044ec34d29
+F src/insert.c 1946d8c7431fc2b614a4b15155f960f999b14ba5
F src/journal.c 807bed7a158979ac8d63953e1774e8d85bff65e2
F src/legacy.c 4ac53191fad2e3c4d59bde1228879b2dc5a96d66
F src/limits.h 71ab25f17e35e0a9f3f6f234b8ed49cc56731d35
@@ -164,7 +164,7 @@
F src/test_thread.c e297dd41db0b249646e69f97d36ec13e56e8b730
F src/tokenize.c a4e04438c11fed2c67ec47fe3edbef9cca2d1b48
F src/trigger.c f8e2d42cf1782ffc14a9d7cee1d1a406f9b0c8c4
-F src/update.c fee857007be57b68a7539c26cc5563d8fbaf3f82
+F src/update.c 24ab2157d360bc20ac4447f50d3a70cd993a7d98
F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736
F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624
F src/vacuum.c 25ffbd766f25bca099ead1c1e11f5528c86102b8
@@ -172,7 +172,7 @@
F src/vdbe.h a042e6d3b567ac81f182ca5b4639807621355822
F src/vdbeInt.h 2985f1369273e635898cf5952237efcb3fdb21f3
F src/vdbeapi.c 4acfaab3e10c99eb66c5332979d7b14a1c3505ae
-F src/vdbeaux.c bca64691ad6bb11e45b5ccf494d9f088d23b3575
+F src/vdbeaux.c 9c2ce05e86502ac3dd148ed13535886e82678e04
F src/vdbeblob.c 82f51cdf9b0c0af729732fde48c824e498c0a1ca
F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6
F src/vdbemem.c 123994fcd344993d2fb050a83b91b341bbbd08b4
@@ -603,7 +603,7 @@
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
-P 051ec01f2799e095516015f2ef0180e50fac387c
-R b1162a1e7d20a24c20501e40bc7dde0f
+P de54dad800f0b62740ad4ebb3780464b44eb6dff
+R a86b5c6a0f11cd9be312d89f90e2feb5
U danielk1977
-Z 75dbf0acf2e3e5d3feebf07dfd171fca
+Z 5595cb26a9237dd9d189ded057a3e630
diff --git a/manifest.uuid b/manifest.uuid
index 9d5e3c6..f54999a 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-de54dad800f0b62740ad4ebb3780464b44eb6dff
\ No newline at end of file
+f1966a8a47fca85f7862c0797a527ab01ac8b0c1
\ No newline at end of file
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