From: drh Date: Fri, 8 Jul 2005 13:07:59 +0000 (+0000) Subject: Replace OP_List with OP_Fifo. This is the first step toward allowing X-Git-Tag: version-3.6.10~3621 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a01f79df494b0dbf05e142318670ea0762db1156;p=thirdparty%2Fsqlite.git Replace OP_List with OP_Fifo. This is the first step toward allowing recursive delete triggers and later foreign keys with cascading deletes. (CVS 2538) FossilOrigin-Name: 94c120bb782fed53142317d1755e70c858930486 --- diff --git a/Makefile.in b/Makefile.in index ed86ef3c2e..ae8da76dd6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 e29acbea2f..3c73fb0bec 100644 --- 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 diff --git a/manifest b/manifest index ad33bde4c4..c98e4b66b6 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index 93ef94bc46..d7402771fa 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -05b6ac9a76fd5765c50e81588f8e71c59fe35ce4 \ No newline at end of file +94c120bb782fed53142317d1755e70c858930486 \ No newline at end of file diff --git a/src/delete.c b/src/delete.c index cd8498807f..faf0f2fc81 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.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 ){ diff --git a/src/update.c b/src/update.c index 0002d2ff46..0ff9eb732d 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.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 ){ diff --git a/src/vdbe.c b/src/vdbe.c index 15305116c3..3a176cad88 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -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->nReadnUsed ); - assert( pKeylist->nReadnKey ); + 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 */ diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 1feb9bab45..0b3e35fa02 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -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*); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index fea26fe89a..c251fc938d 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -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; icontextStackTop; 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 index 0000000000..e752e16698 --- /dev/null +++ b/src/vdbefifo.c @@ -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->iReadnSlot ); + *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); +}