]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Replace OP_List with OP_Fifo. This is the first step toward allowing
authordrh <drh@noemail.net>
Fri, 8 Jul 2005 13:07:59 +0000 (13:07 +0000)
committerdrh <drh@noemail.net>
Fri, 8 Jul 2005 13:07:59 +0000 (13:07 +0000)
recursive delete triggers and later foreign keys with cascading deletes. (CVS 2538)

FossilOrigin-Name: 94c120bb782fed53142317d1755e70c858930486

Makefile.in
main.mk
manifest
manifest.uuid
src/delete.c
src/update.c
src/vdbe.c
src/vdbeInt.h
src/vdbeaux.c
src/vdbefifo.c [new file with mode: 0644]

index ed86ef3c2e5f44f5e82d76f4e3b4cfaf99fc4a54..ae8da76dd63d265b08d48a9b161956f419ae0d4a 100644 (file)
@@ -118,7 +118,8 @@ LIBOBJ = alter.lo analyze.lo attach.lo auth.lo btree.lo build.lo \
          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.
@@ -166,6 +167,7 @@ SRC = \
   $(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
@@ -392,6 +394,9 @@ vdbeapi.lo: $(TOP)/src/vdbeapi.c $(VDBEHDR)
 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
 
diff --git a/main.mk b/main.mk
index e29acbea2f3c03f5dcce7914e69cb6425c45de47..3c73fb0bec31cfea4669e8db861c40f62a50fe29 100644 (file)
--- a/main.mk
+++ b/main.mk
@@ -61,7 +61,7 @@ LIBOBJ+= alter.o analyze.o attach.o auth.o btree.o build.o \
          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.
@@ -109,6 +109,7 @@ SRC = \
   $(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
@@ -328,6 +329,9 @@ vdbeapi.o:  $(TOP)/src/vdbeapi.c $(VDBEHDR)
 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
 
index ad33bde4c4eeb7748c331e2df3c5b6b0290da4bb..c98e4b66b6661bc5d4095efec3f2d7969bf2bb77 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,6 +1,6 @@
-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
@@ -16,7 +16,7 @@ F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538
 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
@@ -36,7 +36,7 @@ F src/btree.h 41a71ce027db9ddee72cb43df2316bbe3a1d92af
 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
@@ -74,15 +74,16 @@ F src/test4.c 7c6b9fc33dd1f3f93c7f1ee6e5e6d016afa6c1df
 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
@@ -284,7 +285,7 @@ F www/tclsqlite.tcl 425be741b8ae664f55cb1ef2371aab0a75109cf9
 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
index 93ef94bc46ed4170d884be2e5bc0c92607cfc7a9..d7402771fa788668106fd36e738e3e69737031fe 100644 (file)
@@ -1 +1 @@
-05b6ac9a76fd5765c50e81588f8e71c59fe35ce4
\ No newline at end of file
+94c120bb782fed53142317d1755e70c858930486
\ No newline at end of file
index cd8498807f7083638fd82fe025d419c50e8a6a5d..faf0f2fc812fa311ff2101879a495c0d48379453 100644 (file)
@@ -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.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"
 
@@ -240,7 +240,7 @@ void sqlite3DeleteFrom(
     /* 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);
     }
@@ -260,14 +260,13 @@ void sqlite3DeleteFrom(
     ** 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);
@@ -288,7 +287,7 @@ void sqlite3DeleteFrom(
     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.
       */
@@ -297,7 +296,7 @@ void sqlite3DeleteFrom(
       /* 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 */
@@ -322,7 +321,6 @@ void sqlite3DeleteFrom(
     /* 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 ){
index 0002d2ff46b33df696b1500e17ad2e023e87c3fa..0ff9eb732d430962e2f189a76b39b4c8c36c8360 100644 (file)
@@ -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.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"
 
@@ -273,7 +273,7 @@ void sqlite3Update(
   /* 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.
   */
@@ -295,8 +295,7 @@ void sqlite3Update(
 
     /* 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);
@@ -389,8 +388,7 @@ void sqlite3Update(
     ** 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);
@@ -468,7 +466,6 @@ void sqlite3Update(
   */
   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 ){
index 15305116c3d784fd2db64f9f44b3e5246447bb0a..3a176cad8847d29623e4e580de16fdb97519d90f 100644 (file)
@@ -43,7 +43,7 @@
 ** 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"
@@ -3975,86 +3975,35 @@ case OP_IntegrityCk: {
 }
 #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;
 }
@@ -4105,8 +4054,8 @@ case OP_ContextPush: {        /* no-push */
   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;
 }
 
@@ -4121,8 +4070,8 @@ case OP_ContextPop: {        /* no-push */
   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 */
index 1feb9bab45e76fffa21e3c58e5aadcd136b78114..0b3e35fa02467e81748aff56d319158522ab22bf 100644 (file)
@@ -260,17 +260,29 @@ struct Set {
 };
 
 /*
-** 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 */
 };
 
 /*
@@ -286,7 +298,7 @@ typedef struct Context Context;
 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 */
 };
 
 /*
@@ -325,7 +337,7 @@ struct Vdbe {
   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*/
@@ -362,7 +374,6 @@ struct Vdbe {
 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)
@@ -411,3 +422,7 @@ int sqlite3VdbeOpcodeNoPush(u8);
 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*);
index fea26fe89adfa15434f79ad5c502b76f7dba432f..c251fc938dacb6588a0c1367937f334107da64f6 100644 (file)
@@ -952,18 +952,6 @@ int sqlite3VdbeAggReset(sqlite3 *db, Agg *pAgg, KeyInfo *pKeyInfo){
   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.
@@ -1010,13 +998,10 @@ static void Cleanup(Vdbe *p){
   }
   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);
   }
diff --git a/src/vdbefifo.c b/src/vdbefifo.c
new file mode 100644 (file)
index 0000000..e752e16
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+** 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);
+}