main.lo opcodes.lo os_unix.lo os_win.lo \
pager.lo parse.lo pragma.lo prepare.lo printf.lo random.lo \
select.lo table.lo tokenize.lo trigger.lo update.lo \
- util.lo vacuum.lo vdbe.lo vdbeapi.lo vdbeaux.lo vdbemem.lo \
+ util.lo vacuum.lo \
+ vdbe.lo vdbeapi.lo vdbeaux.lo vdbefifo.lo vdbemem.lo \
where.lo utf.lo legacy.lo
# All of the source code files.
$(TOP)/src/vdbe.h \
$(TOP)/src/vdbeapi.c \
$(TOP)/src/vdbeaux.c \
+ $(TOP)/src/vdbefifo.c \
$(TOP)/src/vdbemem.c \
$(TOP)/src/vdbeInt.h \
$(TOP)/src/where.c
vdbeaux.lo: $(TOP)/src/vdbeaux.c $(VDBEHDR)
$(LTCOMPILE) -c $(TOP)/src/vdbeaux.c
+vdbefifo.lo: $(TOP)/src/vdbefifo.c $(VDBEHDR)
+ $(LTCOMPILE) -c $(TOP)/src/vdbefifo.c
+
vdbemem.lo: $(TOP)/src/vdbemem.c $(VDBEHDR)
$(LTCOMPILE) -c $(TOP)/src/vdbemem.c
pager.o parse.o pragma.o prepare.o printf.o random.o \
select.o table.o tclsqlite.o tokenize.o trigger.o \
update.o util.o vacuum.o \
- vdbe.o vdbeapi.o vdbeaux.o vdbemem.o \
+ vdbe.o vdbeapi.o vdbeaux.o vdbefifo.o vdbemem.o \
where.o utf.o legacy.o
# All of the source code files.
$(TOP)/src/vdbe.h \
$(TOP)/src/vdbeapi.c \
$(TOP)/src/vdbeaux.c \
+ $(TOP)/src/vdbefifo.c \
$(TOP)/src/vdbemem.c \
$(TOP)/src/vdbeInt.h \
$(TOP)/src/where.c
vdbeaux.o: $(TOP)/src/vdbeaux.c $(VDBEHDR)
$(TCCX) -c $(TOP)/src/vdbeaux.c
+vdbefifo.o: $(TOP)/src/vdbefifo.c $(VDBEHDR)
+ $(TCCX) -c $(TOP)/src/vdbefifo.c
+
vdbemem.o: $(TOP)/src/vdbemem.c $(VDBEHDR)
$(TCCX) -c $(TOP)/src/vdbemem.c
-C Add\sinfrastructure\sfor\sthe\sANALYZE\scommand.\s\sDoes\snot\syet\sactually\ndo\sanything.\s(CVS\s2537)
-D 2005-07-08T12:13:04
-F Makefile.in bc7bffc4ca6f09f2ffa9c9f5c43fc624fb566970
+C Replace\sOP_List\swith\sOP_Fifo.\s\sThis\sis\sthe\sfirst\sstep\stoward\sallowing\nrecursive\sdelete\striggers\sand\slater\sforeign\skeys\swith\scascading\sdeletes.\s(CVS\s2538)
+D 2005-07-08T13:08:00
+F Makefile.in 3c10cd7bc3ecbd60fe4d5a5c0f59bfa7fb217a66
F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
F VERSION 44fad0bf0996660a11bf8187361de03941d9b7b0
F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
F ltmain.sh f6b283068efa69f06eb8aa1fe4bddfdbdeb35826
-F main.mk 675e435ca670e30513907265cc9cc0c011b40c17
+F main.mk b2d38013a10e1c6a821e3d117294bf785deecf97
F mkdll.sh 5ec23622515d5bf8969404e80cfb5e220ddf0512
F mkopcodec.awk bd46ad001c98dfbab07b1713cb8e692fa0e5415d
F mkopcodeh.awk 7563ad235670e864ead95cf672be3fe081450ae0
F src/build.c 1f40c07a11e0a4eed1cef1ad4e52cf3f9770f220
F src/callback.c 0910b611e0c158f107ee3ff86f8a371654971e2b
F src/date.c 7444b0900a28da77e57e3337a636873cff0ae940
-F src/delete.c 9bb19ede439cf325bc6d6f5995b6393fb85b5162
+F src/delete.c 250d436a68fe371b4ab403d1c0f6fdc9a6860c39
F src/experimental.c 50c1e3b34f752f4ac10c36f287db095c2b61766d
F src/expr.c fdc8b82babbb266eeded4a314fd2f1d315133797
F src/func.c cbdf7256400ac7d5f020d131261bb2bd41bb631f
F src/test5.c 64f08b2a50ef371a1bd68ff206829e7b1b9997f5
F src/tokenize.c 57ec9926612fb9e325b57a141303573bc20c79bf
F src/trigger.c f51dec15921629591cb98bf2e350018e268b109a
-F src/update.c e96c7b342cd8903c672162f4cf84d2c737943347
+F src/update.c 49a9c618c3ba1ca57038d9ce41f14e958442fe58
F src/utf.c bda5eb85039ef16f2d17004c1e18c96e1ab0a80c
F src/util.c 1acbe299cbe51f45176ac1e48ded9bea206c3c23
F src/vacuum.c 829d9e1a6d7c094b80e0899686670932eafd768c
-F src/vdbe.c 56e892e351eb3ed634c3c239e4ad5c03aecfc2bf
+F src/vdbe.c 87dda3fc214e4828641dd53527777f1b7d37b85f
F src/vdbe.h 75e466d84d362b0c4498978a9d6b1e6bd32ecf3b
-F src/vdbeInt.h 4312faf41630a6c215924b6c7c2f39ebb1af8ffb
+F src/vdbeInt.h 9be9a6c43d38124bd03cc5cf05715605b1789fd9
F src/vdbeapi.c 7f392f0792d1258c958083d7de9eae7c3530c9a6
-F src/vdbeaux.c 38332d91887817a2146f46b58fff2a8a88ed0278
+F src/vdbeaux.c 3732a86566a6be4da4c606e9334baf3fd98667af
+F src/vdbefifo.c b8805850afe13b43f1de78d58088cb5d66f88e1e
F src/vdbemem.c da8e8d6f29dd1323f782f000d7cd120027c9ff03
F src/where.c 97f356317024597e684b750658f2e8822cb15f10
F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
F www/whentouse.tcl 528299b8316726dbcc5548e9aa0648c8b1bd055b
-P b34647a2ebec6f915f9914034e9370459873215e
-R e47c1bc2e59627b5b8cf84918bbd5426
+P 05b6ac9a76fd5765c50e81588f8e71c59fe35ce4
+R ad75c3dbc9b87159735faff9e7381646
U drh
-Z 50fe8e6711c2298fa85b1472b5a9b5e5
+Z 29241e9900ff613d77be112c57ad8310
-05b6ac9a76fd5765c50e81588f8e71c59fe35ce4
\ No newline at end of file
+94c120bb782fed53142317d1755e70c858930486
\ No newline at end of file
** 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.107 2005/06/24 03:53:06 drh Exp $
+** $Id: delete.c,v 1.108 2005/07/08 13:08:00 drh Exp $
*/
#include "sqliteInt.h"
/* Remember the rowid of every item to be deleted.
*/
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
- sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0);
+ sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0);
if( db->flags & SQLITE_CountRows ){
sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
}
** database scan. We have to delete items after the scan is complete
** because deleting an item can change the scan order.
*/
- sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0);
end = sqlite3VdbeMakeLabel(v);
/* This is the beginning of the delete loop when there are
** row triggers.
*/
if( triggers_exist ){
- addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end);
+ addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end);
if( !isView ){
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
sqlite3OpenTableForReading(v, iCur, pTab);
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_ListRead loop because the cursor have to all be closed
+ ** 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.
*/
/* This is the beginning of the delete loop when there are no
** row triggers */
if( !triggers_exist ){
- addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end);
+ addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end);
}
/* Delete the row */
/* End of the delete loop */
sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
sqlite3VdbeResolveLabel(v, end);
- sqlite3VdbeAddOp(v, OP_ListReset, 0, 0);
/* Close the cursors after the loop if there are no row triggers */
if( !triggers_exist ){
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
-** $Id: update.c,v 1.108 2005/06/12 21:35:53 drh Exp $
+** $Id: update.c,v 1.109 2005/07/08 13:08:00 drh Exp $
*/
#include "sqliteInt.h"
/* Remember the index of every item to be updated.
*/
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
- sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0);
+ sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0);
/* End the database scan loop.
*/
/* The top of the update loop for when there are triggers.
*/
- sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0);
- addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, 0);
+ addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);
if( !isView ){
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
** So make the cursor point at the old record.
*/
if( !triggers_exist ){
- sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0);
- addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, 0);
+ addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
}
sqlite3VdbeAddOp(v, OP_NotExists, iCur, addr);
*/
sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
- sqlite3VdbeAddOp(v, OP_ListReset, 0, 0);
/* Close all tables if there were no FOR EACH ROW triggers */
if( !triggers_exist ){
** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
-** $Id: vdbe.c,v 1.472 2005/06/25 18:42:15 drh Exp $
+** $Id: vdbe.c,v 1.473 2005/07/08 13:08:00 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
-/* Opcode: ListWrite * * *
+/* Opcode: FifoWrite * * *
**
** Write the integer on the top of the stack
-** into the temporary storage list.
+** into the Fifo.
*/
-case OP_ListWrite: { /* no-push */
- Keylist *pKeylist;
+case OP_FifoWrite: { /* no-push */
assert( pTos>=p->aStack );
- pKeylist = p->pList;
- if( pKeylist==0 || pKeylist->nUsed>=pKeylist->nKey ){
- pKeylist = sqliteMallocRaw( sizeof(Keylist)+999*sizeof(pKeylist->aKey[0]) );
- if( pKeylist==0 ) goto no_mem;
- pKeylist->nKey = 1000;
- pKeylist->nRead = 0;
- pKeylist->nUsed = 0;
- pKeylist->pNext = p->pList;
- p->pList = pKeylist;
- }
Integerify(pTos);
- pKeylist->aKey[pKeylist->nUsed++] = pTos->i;
+ sqlite3VdbeFifoPush(&p->sFifo, pTos->i);
assert( (pTos->flags & MEM_Dyn)==0 );
pTos--;
break;
}
-/* Opcode: ListRewind * * *
-**
-** Rewind the temporary buffer back to the beginning.
-*/
-case OP_ListRewind: { /* no-push */
- /* What this opcode codes, really, is reverse the order of the
- ** linked list of Keylist structures so that they are read out
- ** in the same order that they were read in. */
- Keylist *pRev, *pTop;
- pRev = 0;
- while( p->pList ){
- pTop = p->pList;
- p->pList = pTop->pNext;
- pTop->pNext = pRev;
- pRev = pTop;
- }
- p->pList = pRev;
- break;
-}
-
-/* Opcode: ListRead * P2 *
+/* Opcode: FifoRead * P2 *
**
-** Attempt to read an integer from the temporary storage buffer
-** and push it onto the stack. If the storage buffer is empty,
+** Attempt to read a single integer from the Fifo
+** and push it onto the stack. If the Fifo is empty
** push nothing but instead jump to P2.
*/
-case OP_ListRead: {
- Keylist *pKeylist;
+case OP_FifoRead: {
+ i64 v;
CHECK_FOR_INTERRUPT;
- pKeylist = p->pList;
- if( pKeylist!=0 ){
- assert( pKeylist->nRead>=0 );
- assert( pKeylist->nRead<pKeylist->nUsed );
- assert( pKeylist->nRead<pKeylist->nKey );
+ if( sqlite3VdbeFifoPop(&p->sFifo, &v)==SQLITE_DONE ){
+ pc = pOp->p2 - 1;
+ }else{
pTos++;
- pTos->i = pKeylist->aKey[pKeylist->nRead++];
+ pTos->i = v;
pTos->flags = MEM_Int;
- if( pKeylist->nRead>=pKeylist->nUsed ){
- p->pList = pKeylist->pNext;
- sqliteFree(pKeylist);
- }
- }else{
- pc = pOp->p2 - 1;
- }
- break;
-}
-
-/* Opcode: ListReset * * *
-**
-** Reset the temporary storage buffer so that it holds nothing.
-*/
-case OP_ListReset: { /* no-push */
- if( p->pList ){
- sqlite3VdbeKeylistFree(p->pList);
- p->pList = 0;
}
break;
}
pContext = &p->contextStack[i];
pContext->lastRowid = db->lastRowid;
pContext->nChange = p->nChange;
- pContext->pList = p->pList;
- p->pList = 0;
+ pContext->sFifo = p->sFifo;
+ sqlite3VdbeFifoInit(&p->sFifo);
break;
}
assert( p->contextStackTop>=0 );
db->lastRowid = pContext->lastRowid;
p->nChange = pContext->nChange;
- sqlite3VdbeKeylistFree(p->pList);
- p->pList = pContext->pList;
+ sqlite3VdbeFifoClear(&p->sFifo);
+ p->sFifo = pContext->sFifo;
break;
}
#endif /* #ifndef SQLITE_OMIT_TRIGGER */
};
/*
-** A Keylist is a bunch of keys into a table. The keylist can
-** grow without bound. The keylist stores the ROWIDs of database
-** records that need to be deleted or updated.
+** A FifoPage structure holds a single page of valves. Pages are arranged
+** in a list.
*/
-typedef struct Keylist Keylist;
-struct Keylist {
- int nKey; /* Number of slots in aKey[] */
- int nUsed; /* Next unwritten slot in aKey[] */
- int nRead; /* Next unread slot in aKey[] */
- Keylist *pNext; /* Next block of keys */
- i64 aKey[1]; /* One or more keys. Extra space allocated as needed */
+typedef struct FifoPage FifoPage;
+struct FifoPage {
+ u16 nSlot; /* Number of entries aSlot[] */
+ u16 iWrite; /* Push the next value into this entry in aSlot[] */
+ i16 iRead; /* Read the next value from this entry in aSlot[] */
+ FifoPage *pNext; /* Next page in the fifo */
+ i64 aSlot[1]; /* One or more slots for rowid values */
+};
+
+/*
+** The Fifo structure is typedef-ed in vdbeInt.h. But the implementation
+** of that structure is private to this file.
+**
+** The Fifo structure describes the entire fifo.
+*/
+typedef struct Fifo Fifo;
+struct Fifo {
+ int nEntry; /* Total number of entries */
+ FifoPage *pFirst; /* First page on the list */
+ FifoPage *pLast; /* Last page on the list */
};
/*
struct Context {
int lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
int nChange; /* Statement changes (Vdbe.nChanges) */
- Keylist *pList; /* Records that will participate in a DELETE or UPDATE */
+ Fifo sFifo; /* Records that will participate in a DELETE or UPDATE */
};
/*
Agg *apAgg; /* Array of aggregate contexts */
Agg *pAgg; /* Current aggregate context */
int nCallback; /* Number of callbacks invoked so far */
- Keylist *pList; /* A list of ROWIDs */
+ Fifo sFifo; /* A list of ROWIDs */
int contextStackTop; /* Index of top element in the context stack */
int contextStackDepth; /* The size of the "context" stack */
Context *contextStack; /* Stack used by opcodes ContextPush & ContextPop*/
void sqlite3VdbeFreeCursor(Cursor*);
void sqlite3VdbeSorterReset(Vdbe*);
int sqlite3VdbeAggReset(sqlite3*, Agg *, KeyInfo *);
-void sqlite3VdbeKeylistFree(Keylist*);
void sqliteVdbePopStack(Vdbe*,int);
int sqlite3VdbeCursorMoveto(Cursor*);
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
int sqlite3VdbeMemTranslate(Mem*, u8);
void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf, int nBuf);
int sqlite3VdbeMemHandleBom(Mem *pMem);
+void sqlite3VdbeFifoInit(Fifo*);
+int sqlite3VdbeFifoPush(Fifo*, i64);
+int sqlite3VdbeFifoPop(Fifo*, i64*);
+void sqlite3VdbeFifoClear(Fifo*);
return SQLITE_OK;
}
-
-/*
-** Delete a keylist
-*/
-void sqlite3VdbeKeylistFree(Keylist *p){
- while( p ){
- Keylist *pNext = p->pNext;
- sqliteFree(p);
- p = pNext;
- }
-}
-
/*
** Close a cursor and release all the resources that cursor happens
** to hold.
}
closeAllCursors(p);
releaseMemArray(p->aMem, p->nMem);
- if( p->pList ){
- sqlite3VdbeKeylistFree(p->pList);
- p->pList = 0;
- }
+ sqlite3VdbeFifoClear(&p->sFifo);
if( p->contextStack ){
for(i=0; i<p->contextStackTop; i++){
- sqlite3VdbeKeylistFree(p->contextStack[i].pList);
+ sqlite3VdbeFifoClear(&p->contextStack[i].sFifo);
}
sqliteFree(p->contextStack);
}
--- /dev/null
+/*
+** 2005 June 16
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file implements a FIFO queue of rowids used for processing
+** UPDATE and DELETE statements.
+*/
+#include "sqliteInt.h"
+#include "vdbeInt.h"
+
+/*
+** Allocate a new FifoPage and return a pointer to it. Return NULL if
+** we run out of memory. Leave space on the page for nEntry entries.
+*/
+static FifoPage *allocatePage(int nEntry){
+ FifoPage *pPage;
+ pPage = sqliteMallocRaw( sizeof(FifoPage) + sizeof(i64)*(nEntry-1) );
+ if( pPage ){
+ pPage->nSlot = nEntry;
+ pPage->iWrite = 0;
+ pPage->iRead = 0;
+ pPage->pNext = 0;
+ }
+ return pPage;
+}
+
+/*
+** Initialize a Fifo structure.
+*/
+void sqlite3VdbeFifoInit(Fifo *pFifo){
+ memset(pFifo, 0, sizeof(*pFifo));
+}
+
+/*
+** Push a single 64-bit integer value into the Fifo. Return SQLITE_OK
+** normally. SQLITE_NOMEM is returned if we are unable to allocate
+** memory.
+*/
+int sqlite3VdbeFifoPush(Fifo *pFifo, i64 val){
+ FifoPage *pPage;
+ pPage = pFifo->pLast;
+ if( pPage==0 ){
+ pPage = pFifo->pLast = pFifo->pFirst = allocatePage(20);
+ if( pPage==0 ){
+ return SQLITE_NOMEM;
+ }
+ }else if( pPage->iWrite>=pPage->nSlot ){
+ pPage->pNext = allocatePage(pFifo->nEntry);
+ if( pPage->pNext==0 ){
+ return SQLITE_NOMEM;
+ }
+ pPage = pFifo->pLast = pPage->pNext;
+ }
+ pPage->aSlot[pPage->iWrite++] = val;
+ pFifo->nEntry++;
+ return SQLITE_OK;
+}
+
+/*
+** Extract a single 64-bit integer value from the Fifo. The integer
+** extracted is the one least recently inserted. If the Fifo is empty
+** return SQLITE_DONE.
+*/
+int sqlite3VdbeFifoPop(Fifo *pFifo, i64 *pVal){
+ FifoPage *pPage;
+ if( pFifo->nEntry==0 ){
+ return SQLITE_DONE;
+ }
+ assert( pFifo->nEntry>0 );
+ pPage = pFifo->pFirst;
+ assert( pPage!=0 );
+ assert( pPage->iWrite>pPage->iRead );
+ assert( pPage->iRead<pPage->nSlot );
+ *pVal = pPage->aSlot[pPage->iRead++];
+ pFifo->nEntry--;
+ if( pPage->iRead>=pPage->iWrite ){
+ pFifo->pFirst = pPage->pNext;
+ sqliteFree(pPage);
+ if( pFifo->nEntry==0 ){
+ assert( pFifo->pLast==pPage );
+ pFifo->pLast = 0;
+ }else{
+ assert( pFifo->pFirst!=0 );
+ }
+ }else{
+ assert( pFifo->nEntry>0 );
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Delete all information from a Fifo object. Free all memory held
+** by the Fifo.
+*/
+void sqlite3VdbeFifoClear(Fifo *pFifo){
+ FifoPage *pPage, *pNextPage;
+ for(pPage=pFifo->pFirst; pPage; pPage=pNextPage){
+ pNextPage = pPage->pNext;
+ sqliteFree(pPage);
+ }
+ sqlite3VdbeFifoInit(pFifo);
+}