diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/delete.c | 7 | ||||
-rw-r--r-- | src/pcache.c | 3 | ||||
-rw-r--r-- | src/rowset.c | 238 | ||||
-rw-r--r-- | src/sqliteInt.h | 8 | ||||
-rw-r--r-- | src/update.c | 10 | ||||
-rw-r--r-- | src/vdbe.c | 64 | ||||
-rw-r--r-- | src/vdbeInt.h | 62 | ||||
-rw-r--r-- | src/vdbeaux.c | 17 | ||||
-rw-r--r-- | src/vdbefifo.c | 130 | ||||
-rw-r--r-- | src/vdbemem.c | 58 |
10 files changed, 373 insertions, 224 deletions
diff --git a/src/delete.c b/src/delete.c index 7c3f0add1..6fad57aef 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.187 2008/11/19 09:05:27 danielk1977 Exp $ +** $Id: delete.c,v 1.188 2008/12/04 20:40:10 drh Exp $ */ #include "sqliteInt.h" @@ -390,6 +390,7 @@ void sqlite3DeleteFrom( */ { int iRowid = ++pParse->nMem; /* Used for storing rowid values. */ + int iRowSet = ++pParse->nMem; /* Register for rowset of rows to delete */ /* Begin the database scan */ @@ -399,7 +400,7 @@ void sqlite3DeleteFrom( /* Remember the rowid of every item to be deleted. */ sqlite3VdbeAddOp2(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, iRowid); - sqlite3VdbeAddOp1(v, OP_FifoWrite, iRowid); + sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iRowid); if( db->flags & SQLITE_CountRows ){ sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1); } @@ -434,7 +435,7 @@ void sqlite3DeleteFrom( if( triggers_exist ){ sqlite3VdbeResolveLabel(v, addr); } - addr = sqlite3VdbeAddOp2(v, OP_FifoRead, iRowid, end); + addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, end, iRowid); if( triggers_exist ){ int iData = ++pParse->nMem; /* For storing row data of OLD table */ diff --git a/src/pcache.c b/src/pcache.c index c008f4b60..b513e275c 100644 --- a/src/pcache.c +++ b/src/pcache.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file implements that page cache. ** -** @(#) $Id: pcache.c,v 1.38 2008/11/19 16:52:44 danielk1977 Exp $ +** @(#) $Id: pcache.c,v 1.39 2008/12/04 20:40:10 drh Exp $ */ #include "sqliteInt.h" @@ -578,4 +578,3 @@ void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)){ } } #endif - diff --git a/src/rowset.c b/src/rowset.c new file mode 100644 index 000000000..2be962759 --- /dev/null +++ b/src/rowset.c @@ -0,0 +1,238 @@ +/* +** 2008 December 3 +** +** 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 module implements an object we call a "Row Set". +** +** The RowSet object is a bag of rowids. Rowids +** are inserted into the bag in an arbitrary order. Then they are +** pulled from the bag in sorted order. Rowids only appear in the +** bag once. If the same rowid is inserted multiple times, the +** second and subsequent inserts make no difference on the output. +** +** This implementation accumulates rowids in a linked list. For +** output, it first sorts the linked list (removing duplicates during +** the sort) then returns elements one by one by walking the list. +** +** Big chunks of rowid/next-ptr pairs are allocated at a time, to +** reduce the malloc overhead. +*/ +#include "sqliteInt.h" + +/* +** The number of rowset entries per allocation chunk. +*/ +#define ROWSET_ENTRY_PER_CHUNK 63 + +/* +** Each entry in a RowSet is an instance of the following +** structure: +*/ +struct RowSetEntry { + i64 v; /* ROWID value for this entry */ + struct RowSetEntry *pNext; /* Next entry on a list of all entries */ +}; + +/* +** Index entries are allocated in large chunks (instances of the +** following structure) to reduce memory allocation overhead. The +** chunks are kept on a linked list so that they can be deallocated +** when the RowSet is destroyed. +*/ +struct RowSetChunk { + struct RowSetChunk *pNext; /* Next chunk on list of them all */ + struct RowSetEntry aEntry[ROWSET_ENTRY_PER_CHUNK]; /* Allocated entries */ +}; + +/* +** A RowSet in an instance of the following structure. +** +** A typedef of this structure if found in sqliteInt.h. +*/ +struct RowSet { + struct RowSetChunk *pChunk; /* List of all chunk allocations */ + sqlite3 *db; /* The database connection */ + struct RowSetEntry *pEntry; /* List of entries in the rowset */ + struct RowSetEntry *pLast; /* Last entry on the pEntry list */ + struct RowSetEntry *pFresh; /* Source of new entry objects */ + u16 nFresh; /* Number of objects on pFresh */ + u8 isSorted; /* True if content is sorted */ +}; + +/* +** Turn bulk memory into a RowSet object. N bytes of memory +** are available at pSpace. The db pointer is used as a memory context +** for any subsequent allocations that need to occur. +** Return a pointer to the new RowSet object. +** +** If N is not sufficient memory to make even a minimum RowSet, +** then return NULL. If N is larger than the minimum, use +** the surplus as an initial allocation of entries available to +** be filled. +*/ +RowSet *sqlite3RowSetInit(sqlite3 *db, void *pSpace, unsigned int N){ + RowSet *p; + if( N<sizeof(*p) ){ + p = 0; + }else{ + p = pSpace; + p->pChunk = 0; + p->db = db; + p->pEntry = 0; + p->pLast = 0; + p->pFresh = (struct RowSetEntry*)&p[1]; + p->nFresh = (u16)((N - sizeof(*p))/sizeof(struct RowSetEntry)); + p->isSorted = 1; + } + return p; +} + +/* +** Deallocate all chunks from a RowSet. +*/ +void sqlite3RowSetClear(RowSet *p){ + struct RowSetChunk *pChunk, *pNextChunk; + for(pChunk=p->pChunk; pChunk; pChunk = pNextChunk){ + pNextChunk = pChunk->pNext; + sqlite3DbFree(p->db, pChunk); + } + p->pChunk = 0; + p->nFresh = 0; + p->pEntry = 0; + p->pLast = 0; + p->isSorted = 1; +} + +/* +** Insert a new value into a RowSet. +** +** The mallocFailed flag of the database connection is set if a +** memory allocation fails. +*/ +void sqlite3RowSetInsert(RowSet *p, i64 rowid){ + struct RowSetEntry *pEntry; + struct RowSetEntry *pLast; + if( p==0 ) return; /* Must have been a malloc failure */ + if( p->nFresh==0 ){ + struct RowSetChunk *pNew; + pNew = sqlite3DbMallocRaw(p->db, sizeof(*pNew)); + if( pNew==0 ){ + return; + } + pNew->pNext = p->pChunk; + p->pChunk = pNew; + p->pFresh = pNew->aEntry; + p->nFresh = ROWSET_ENTRY_PER_CHUNK; + } + pEntry = p->pFresh++; + p->nFresh--; + pEntry->v = rowid; + pEntry->pNext = 0; + pLast = p->pLast; + if( pLast ){ + if( p->isSorted && rowid<=pLast->v ){ + p->isSorted = 0; + } + pLast->pNext = pEntry; + }else{ + assert( p->pEntry==0 ); + p->pEntry = pEntry; + } + p->pLast = pEntry; +} + +/* +** Merge two lists of RowSet entries. Remove duplicates. +** +** The input lists are assumed to be in sorted order. +*/ +static struct RowSetEntry *boolidxMerge( + struct RowSetEntry *pA, /* First sorted list to be merged */ + struct RowSetEntry *pB /* Second sorted list to be merged */ +){ + struct RowSetEntry head; + struct RowSetEntry *pTail; + + pTail = &head; + while( pA && pB ){ + assert( pA->pNext==0 || pA->v<=pA->pNext->v ); + assert( pB->pNext==0 || pB->v<=pB->pNext->v ); + if( pA->v<pB->v ){ + pTail->pNext = pA; + pA = pA->pNext; + pTail = pTail->pNext; + }else if( pB->v<pA->v ){ + pTail->pNext = pB; + pB = pB->pNext; + pTail = pTail->pNext; + }else{ + pA = pA->pNext; + } + } + if( pA ){ + assert( pA->pNext==0 || pA->v<=pA->pNext->v ); + pTail->pNext = pA; + }else{ + assert( pB==0 || pB->pNext==0 || pB->v<=pB->pNext->v ); + pTail->pNext = pB; + } + return head.pNext; +} + +/* +** Sort all elements of the RowSet into ascending order. +*/ +static void sqlite3RowSetSort(RowSet *p){ + unsigned int i; + struct RowSetEntry *pEntry; + struct RowSetEntry *aBucket[40]; + + assert( p->isSorted==0 ); + memset(aBucket, 0, sizeof(aBucket)); + while( p->pEntry ){ + pEntry = p->pEntry; + p->pEntry = pEntry->pNext; + pEntry->pNext = 0; + for(i=0; aBucket[i]; i++){ + pEntry = boolidxMerge(aBucket[i],pEntry); + aBucket[i] = 0; + } + aBucket[i] = pEntry; + } + pEntry = 0; + for(i=0; i<sizeof(aBucket)/sizeof(aBucket[0]); i++){ + pEntry = boolidxMerge(pEntry,aBucket[i]); + } + p->pEntry = pEntry; + p->pLast = 0; + p->isSorted = 1; +} + +/* +** Extract the next (smallest) element from the RowSet. +** Write the element into *pRowid. Return 1 on success. Return +** 0 if the RowSet is already empty. +*/ +int sqlite3RowSetNext(RowSet *p, i64 *pRowid){ + if( !p->isSorted ){ + sqlite3RowSetSort(p); + } + if( p->pEntry ){ + *pRowid = p->pEntry->v; + p->pEntry = p->pEntry->pNext; + if( p->pEntry==0 ){ + sqlite3RowSetClear(p); + } + return 1; + }else{ + return 0; + } +} diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 86d26a66b..0cd41f8d8 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.799 2008/11/24 20:01:33 shane Exp $ +** @(#) $Id: sqliteInt.h,v 1.800 2008/12/04 20:40:10 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -503,6 +503,7 @@ struct BusyHandler { typedef struct AggInfo AggInfo; typedef struct AuthContext AuthContext; typedef struct Bitvec Bitvec; +typedef struct RowSet RowSet; typedef struct CollSeq CollSeq; typedef struct Column Column; typedef struct Db Db; @@ -2161,6 +2162,11 @@ void sqlite3BitvecClear(Bitvec*, u32); void sqlite3BitvecDestroy(Bitvec*); int sqlite3BitvecBuiltinTest(int,int*); +RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int); +void sqlite3RowSetClear(RowSet*); +void sqlite3RowSetInsert(RowSet*, i64); +int sqlite3RowSetNext(RowSet*, i64*); + void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int); #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) diff --git a/src/update.c b/src/update.c index 34a496e48..06b500de5 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.187 2008/11/19 09:05:27 danielk1977 Exp $ +** $Id: update.c,v 1.188 2008/12/04 20:40:10 drh Exp $ */ #include "sqliteInt.h" @@ -124,6 +124,7 @@ void sqlite3Update( int regOldRowid; /* The old rowid */ int regNewRowid; /* The new rowid */ int regData; /* New data for the row */ + int regRowSet; /* Rowset of rows to be updated */ sContext.pParse = 0; db = pParse->db; @@ -352,7 +353,10 @@ void sqlite3Update( /* Remember the rowid of every item to be updated. */ sqlite3VdbeAddOp2(v, IsVirtual(pTab)?OP_VRowid:OP_Rowid, iCur, regOldRowid); - if( !okOnePass ) sqlite3VdbeAddOp2(v, OP_FifoWrite, regOldRowid, 0); + if( !okOnePass ){ + regRowSet = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid); + } /* End the database scan loop. */ @@ -405,7 +409,7 @@ void sqlite3Update( addr = sqlite3VdbeAddOp0(v, OP_Goto); sqlite3VdbeJumpHere(v, a1); }else{ - addr = sqlite3VdbeAddOp2(v, OP_FifoRead, regOldRowid, 0); + addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet, 0, regOldRowid); } if( triggers_exist ){ diff --git a/src/vdbe.c b/src/vdbe.c index 9e471a086..191b3c58f 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.789 2008/12/04 12:17:30 drh Exp $ +** $Id: vdbe.c,v 1.790 2008/12/04 20:40:10 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -189,7 +189,7 @@ static VdbeCursor *allocateCursor( Vdbe *p, /* The virtual machine */ int iCur, /* Index of the new VdbeCursor */ Op *pOp, /* */ - int iDb, /* */ + int iDb, /* When database the cursor belongs to, or -1 */ int isBtreeCursor /* */ ){ /* Find the memory cell that will be used to store the blob of memory @@ -804,7 +804,7 @@ case OP_Yield: { /* Opcode: Halt P1 P2 * P4 * ** -** Exit immediately. All open cursors, Fifos, etc are closed +** Exit immediately. All open cursors, etc are closed ** automatically. ** ** P1 is the result code returned by sqlite3_exec(), sqlite3_reset(), @@ -4285,36 +4285,56 @@ case OP_IntegrityCk: { } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ -/* Opcode: FifoWrite P1 * * * * +/* Opcode: RowSetAdd P1 P2 * * * ** -** Write the integer from register P1 into the Fifo. +** Insert the integer value held by register P2 into a boolean index +** held in register P1. +** +** An assertion fails if P2 is not an integer. */ -case OP_FifoWrite: { /* in1 */ - p->sFifo.db = db; - if( sqlite3VdbeFifoPush(&p->sFifo, sqlite3VdbeIntValue(pIn1))==SQLITE_NOMEM ){ - goto no_mem; - } +case OP_RowSetAdd: { /* in2 */ + Mem *pIdx; + Mem *pVal; + assert( pOp->p1>0 && pOp->p1<=p->nMem ); + pIdx = &p->aMem[pOp->p1]; + assert( pOp->p2>0 && pOp->p2<=p->nMem ); + pVal = &p->aMem[pOp->p2]; + assert( (pVal->flags & MEM_Int)!=0 ); + if( (pIdx->flags & MEM_RowSet)==0 ){ + sqlite3VdbeMemSetRowSet(pIdx); + } + sqlite3RowSetInsert(pIdx->u.pRowSet, pVal->u.i); break; } -/* Opcode: FifoRead P1 P2 * * * +/* Opcode: RowSetRead P1 P2 P3 * * ** -** Attempt to read a single integer from the Fifo. Store that -** integer in register P1. -** -** If the Fifo is empty jump to P2. +** Extract the smallest value from boolean index P1 and put that value into +** register P3. Or, if boolean index P1 is initially empty, leave P3 +** unchanged and jump to instruction P2. */ -case OP_FifoRead: { /* jump */ - CHECK_FOR_INTERRUPT; +case OP_RowSetRead: { /* jump, out3 */ + Mem *pIdx; + i64 val; assert( pOp->p1>0 && pOp->p1<=p->nMem ); - pOut = &p->aMem[pOp->p1]; - MemSetTypeFlag(pOut, MEM_Int); - if( sqlite3VdbeFifoPop(&p->sFifo, &pOut->u.i)==SQLITE_DONE ){ + CHECK_FOR_INTERRUPT; + pIdx = &p->aMem[pOp->p1]; + if( (pIdx->flags & MEM_RowSet)==0 + || sqlite3RowSetNext(pIdx->u.pRowSet, &val)==0 + ){ + /* The boolean index is empty */ + sqlite3VdbeMemSetNull(pIdx); pc = pOp->p2 - 1; + }else{ + /* A value was pulled from the index */ + assert( pOp->p3>0 && pOp->p3<=p->nMem ); + pOut = &p->aMem[pOp->p3]; + sqlite3VdbeMemSetInt64(pOut, val); } break; } + #ifndef SQLITE_OMIT_TRIGGER /* Opcode: ContextPush * * * ** @@ -4337,8 +4357,6 @@ case OP_ContextPush: { pContext = &p->contextStack[i]; pContext->lastRowid = db->lastRowid; pContext->nChange = p->nChange; - pContext->sFifo = p->sFifo; - sqlite3VdbeFifoInit(&p->sFifo, db); break; } @@ -4353,8 +4371,6 @@ case OP_ContextPop: { assert( p->contextStackTop>=0 ); db->lastRowid = pContext->lastRowid; p->nChange = pContext->nChange; - sqlite3VdbeFifoClear(&p->sFifo); - p->sFifo = pContext->sFifo; break; } #endif /* #ifndef SQLITE_OMIT_TRIGGER */ diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 312ea8041..e637974d6 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -15,7 +15,7 @@ ** 6000 lines long) it was split up into several smaller files and ** this header information was factored out. ** -** $Id: vdbeInt.h,v 1.158 2008/11/17 15:31:48 danielk1977 Exp $ +** $Id: vdbeInt.h,v 1.159 2008/12/04 20:40:10 drh Exp $ */ #ifndef _VDBEINT_H_ #define _VDBEINT_H_ @@ -113,8 +113,9 @@ typedef struct VdbeCursor VdbeCursor; */ struct Mem { union { - i64 i; /* Integer value. Or FuncDef* when flags==MEM_Agg */ + i64 i; /* Integer value. */ FuncDef *pDef; /* Used only when flags==MEM_Agg */ + RowSet *pRowSet; /* Used only when flags==MEM_RowSet */ } u; double r; /* Real value */ sqlite3 *db; /* The associated database connection */ @@ -147,21 +148,20 @@ struct Mem { #define MEM_Int 0x0004 /* Value is an integer */ #define MEM_Real 0x0008 /* Value is a real number */ #define MEM_Blob 0x0010 /* Value is a BLOB */ - -#define MemSetTypeFlag(p, f) \ - ((p)->flags = ((p)->flags&~(MEM_Int|MEM_Real|MEM_Null|MEM_Blob|MEM_Str))|f) +#define MEM_RowSet 0x0020 /* Value is a RowSet object */ +#define MEM_TypeMask 0x00ff /* Mask of type bits */ /* Whenever Mem contains a valid string or blob representation, one of ** the following flags must be set to determine the memory management ** policy for Mem.z. The MEM_Term flag tells us whether or not the ** string is \000 or \u0000 terminated */ -#define MEM_Term 0x0020 /* String rep is nul terminated */ -#define MEM_Dyn 0x0040 /* Need to call sqliteFree() on Mem.z */ -#define MEM_Static 0x0080 /* Mem.z points to a static string */ -#define MEM_Ephem 0x0100 /* Mem.z points to an ephemeral string */ -#define MEM_Agg 0x0400 /* Mem.z points to an agg function context */ -#define MEM_Zero 0x0800 /* Mem.i contains count of 0s appended to blob */ +#define MEM_Term 0x0200 /* String rep is nul terminated */ +#define MEM_Dyn 0x0400 /* Need to call sqliteFree() on Mem.z */ +#define MEM_Static 0x0800 /* Mem.z points to a static string */ +#define MEM_Ephem 0x1000 /* Mem.z points to an ephemeral string */ +#define MEM_Agg 0x2000 /* Mem.z points to an agg function context */ +#define MEM_Zero 0x4000 /* Mem.i contains count of 0s appended to blob */ #ifdef SQLITE_OMIT_INCRBLOB #undef MEM_Zero @@ -169,6 +169,12 @@ struct Mem { #endif +/* +** Clear any existing type flags from a Mem and replace them with f +*/ +#define MemSetTypeFlag(p, f) ((p)->flags = ((p)->flags&~(MEM_TypeMask))|f) + + /* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains ** additional information about auxiliary information bound to arguments ** of the function. This is used to implement the sqlite3_get_auxdata() @@ -222,33 +228,6 @@ struct Set { }; /* -** A FifoPage structure holds a single page of valves. Pages are arranged -** in a list. -*/ -typedef struct FifoPage FifoPage; -struct FifoPage { - int nSlot; /* Number of entries aSlot[] */ - int iWrite; /* Push the next value into this entry in aSlot[] */ - int 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 */ - sqlite3 *db; /* The associated database connection */ - FifoPage *pFirst; /* First page on the list */ - FifoPage *pLast; /* Last page on the list */ -}; - -/* ** A Context stores the last insert rowid, the last statement change count, ** and the current statement change count (i.e. changes since last statement). ** The current keylist is also stored in the context. @@ -261,7 +240,6 @@ typedef struct Context Context; struct Context { i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */ int nChange; /* Statement changes (Vdbe.nChanges) */ - Fifo sFifo; /* Records that will participate in a DELETE or UPDATE */ }; /* @@ -301,7 +279,6 @@ struct Vdbe { Mem *aMem; /* The memory locations */ int nCallback; /* Number of callbacks invoked so far */ int cacheCtr; /* VdbeCursor row cache generation counter */ - 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*/ @@ -383,6 +360,7 @@ void sqlite3VdbeMemSetInt64(Mem*, i64); void sqlite3VdbeMemSetDouble(Mem*, double); void sqlite3VdbeMemSetNull(Mem*); void sqlite3VdbeMemSetZeroBlob(Mem*,int); +void sqlite3VdbeMemSetRowSet(Mem*); int sqlite3VdbeMemMakeWriteable(Mem*); int sqlite3VdbeMemStringify(Mem*, int); i64 sqlite3VdbeIntValue(Mem*); @@ -411,10 +389,6 @@ int sqlite3VdbeMemTranslate(Mem*, u8); void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf); #endif int sqlite3VdbeMemHandleBom(Mem *pMem); -void sqlite3VdbeFifoInit(Fifo*, sqlite3*); -int sqlite3VdbeFifoPush(Fifo*, i64); -int sqlite3VdbeFifoPop(Fifo*, i64*); -void sqlite3VdbeFifoClear(Fifo*); #ifndef SQLITE_OMIT_INCRBLOB int sqlite3VdbeMemExpandBlob(Mem *); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index b3710e994..b95140070 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -14,7 +14,7 @@ ** to version 2.8.7, all this code was combined into the vdbe.c source file. ** But that file was getting too big so this subroutines were split out. ** -** $Id: vdbeaux.c,v 1.421 2008/11/21 16:58:03 danielk1977 Exp $ +** $Id: vdbeaux.c,v 1.422 2008/12/04 20:40:10 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -802,6 +802,9 @@ int sqlite3VdbeReleaseBuffers(Vdbe *p){ assert( sqlite3_mutex_held(p->db->mutex) ); for(ii=1; ii<=p->nMem; ii++){ Mem *pMem = &p->aMem[ii]; + if( pMem->flags & MEM_RowSet ){ + sqlite3RowSetClear(pMem->u.pRowSet); + } if( pMem->z && pMem->flags&MEM_Dyn ){ assert( !pMem->xDel ); nFree += sqlite3DbMallocSize(pMem->db, pMem->z); @@ -1156,16 +1159,16 @@ static void closeAllCursorsExceptActiveVtabs(Vdbe *p){ static void Cleanup(Vdbe *p){ int i; sqlite3 *db = p->db; + Mem *pMem; closeAllCursorsExceptActiveVtabs(p); - for(i=1; i<=p->nMem; i++){ - MemSetTypeFlag(&p->aMem[i], MEM_Null); + for(pMem=&p->aMem[1], i=1; i<=p->nMem; i++, pMem++){ + if( pMem->flags & MEM_RowSet ){ + sqlite3RowSetClear(pMem->u.pRowSet); + } + MemSetTypeFlag(pMem, MEM_Null); } releaseMemArray(&p->aMem[1], p->nMem); - sqlite3VdbeFifoClear(&p->sFifo); if( p->contextStack ){ - for(i=0; i<p->contextStackTop; i++){ - sqlite3VdbeFifoClear(&p->contextStack[i].sFifo); - } sqlite3DbFree(db, p->contextStack); } p->contextStack = 0; diff --git a/src/vdbefifo.c b/src/vdbefifo.c deleted file mode 100644 index 5a266bb2c..000000000 --- a/src/vdbefifo.c +++ /dev/null @@ -1,130 +0,0 @@ -/* -** 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. -** -** $Id: vdbefifo.c,v 1.9 2008/11/17 19:18:55 danielk1977 Exp $ -*/ -#include "sqliteInt.h" -#include "vdbeInt.h" - -/* -** Constants FIFOSIZE_FIRST and FIFOSIZE_MAX are the initial -** number of entries in a fifo page and the maximum number of -** entries in a fifo page. -*/ -#define FIFOSIZE_FIRST (((128-sizeof(FifoPage))/8)+1) -#ifdef SQLITE_MALLOC_SOFT_LIMIT -# define FIFOSIZE_MAX (int)(((SQLITE_MALLOC_SOFT_LIMIT-sizeof(FifoPage))/8)+1) -#else -# define FIFOSIZE_MAX (int)(((262144-sizeof(FifoPage))/8)+1) -#endif - -/* -** 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 *allocateFifoPage(sqlite3 *db, int nEntry){ - FifoPage *pPage; - if( nEntry>FIFOSIZE_MAX ){ - nEntry = FIFOSIZE_MAX; - } - pPage = sqlite3DbMallocRaw(db, 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, sqlite3 *db){ - memset(pFifo, 0, sizeof(*pFifo)); - pFifo->db = db; -} - -/* -** 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 = - allocateFifoPage(pFifo->db, FIFOSIZE_FIRST); - if( pPage==0 ){ - return SQLITE_NOMEM; - } - }else if( pPage->iWrite>=pPage->nSlot ){ - pPage->pNext = allocateFifoPage(pFifo->db, 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->iWrite<=pPage->nSlot ); - assert( pPage->iRead<pPage->nSlot ); - assert( pPage->iRead>=0 ); - *pVal = pPage->aSlot[pPage->iRead++]; - pFifo->nEntry--; - if( pPage->iRead>=pPage->iWrite ){ - pFifo->pFirst = pPage->pNext; - sqlite3DbFree(pFifo->db, 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; - sqlite3DbFree(pFifo->db, pPage); - } - sqlite3VdbeFifoInit(pFifo, pFifo->db); -} diff --git a/src/vdbemem.c b/src/vdbemem.c index 8d96e62df..d9ec059e8 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -15,7 +15,7 @@ ** only within the VDBE. Interface routines refer to a Mem using the ** name sqlite_value ** -** $Id: vdbemem.c,v 1.126 2008/11/11 00:21:30 drh Exp $ +** $Id: vdbemem.c,v 1.127 2008/12/04 20:40:10 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -42,6 +42,7 @@ */ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ int rc; + assert( (pMem->flags&MEM_RowSet)==0 ); if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){ return SQLITE_OK; } @@ -81,6 +82,7 @@ int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve){ ((pMem->flags&MEM_Ephem) ? 1 : 0) + ((pMem->flags&MEM_Static) ? 1 : 0) ); + assert( (pMem->flags&MEM_RowSet)==0 ); if( n<32 ) n = 32; if( sqlite3DbMallocSize(pMem->db, pMem->zMalloc)<n ){ @@ -121,6 +123,7 @@ int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve){ int sqlite3VdbeMemMakeWriteable(Mem *pMem){ int f; assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); + assert( (pMem->flags&MEM_RowSet)==0 ); expandBlob(pMem); f = pMem->flags; if( (f&(MEM_Str|MEM_Blob)) && pMem->z!=pMem->zMalloc ){ @@ -144,6 +147,7 @@ int sqlite3VdbeMemExpandBlob(Mem *pMem){ if( pMem->flags & MEM_Zero ){ int nByte; assert( pMem->flags&MEM_Blob ); + assert( (pMem->flags&MEM_RowSet)==0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); /* Set nByte to the number of bytes required to store the expanded blob. */ @@ -203,6 +207,8 @@ int sqlite3VdbeMemStringify(Mem *pMem, int enc){ assert( !(fg&MEM_Zero) ); assert( !(fg&(MEM_Str|MEM_Blob)) ); assert( fg&(MEM_Int|MEM_Real) ); + assert( (pMem->flags&MEM_RowSet)==0 ); + if( sqlite3VdbeMemGrow(pMem, nByte, 0) ){ return SQLITE_NOMEM; @@ -267,8 +273,11 @@ void sqlite3VdbeMemReleaseExternal(Mem *p){ assert( (p->flags & MEM_Agg)==0 ); sqlite3VdbeMemRelease(p); }else if( p->flags&MEM_Dyn && p->xDel ){ + assert( (p->flags&MEM_RowSet)==0 ); p->xDel((void *)p->z); p->xDel = 0; + }else if( p->flags&MEM_RowSet ){ + sqlite3RowSetClear(p->u.pRowSet); } } @@ -383,6 +392,7 @@ double sqlite3VdbeRealValue(Mem *pMem){ */ void sqlite3VdbeIntegerAffinity(Mem *pMem){ assert( pMem->flags & MEM_Real ); + assert( (pMem->flags & MEM_RowSet)==0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); pMem->u.i = doubleToInt64(pMem->r); @@ -391,17 +401,14 @@ void sqlite3VdbeIntegerAffinity(Mem *pMem){ } } -static void setTypeFlag(Mem *pMem, int f){ - MemSetTypeFlag(pMem, f); -} - /* ** Convert pMem to type integer. Invalidate any prior representations. */ int sqlite3VdbeMemIntegerify(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); + assert( (pMem->flags & MEM_RowSet)==0 ); pMem->u.i = sqlite3VdbeIntValue(pMem); - setTypeFlag(pMem, MEM_Int); + MemSetTypeFlag(pMem, MEM_Int); return SQLITE_OK; } @@ -412,7 +419,7 @@ int sqlite3VdbeMemIntegerify(Mem *pMem){ int sqlite3VdbeMemRealify(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); pMem->r = sqlite3VdbeRealValue(pMem); - setTypeFlag(pMem, MEM_Real); + MemSetTypeFlag(pMem, MEM_Real); return SQLITE_OK; } @@ -433,7 +440,7 @@ int sqlite3VdbeMemNumerify(Mem *pMem){ sqlite3VdbeMemIntegerify(pMem); }else{ pMem->r = r1; - setTypeFlag(pMem, MEM_Real); + MemSetTypeFlag(pMem, MEM_Real); } return SQLITE_OK; } @@ -442,7 +449,10 @@ int sqlite3VdbeMemNumerify(Mem *pMem){ ** Delete any previous value and set the value stored in *pMem to NULL. */ void sqlite3VdbeMemSetNull(Mem *pMem){ - setTypeFlag(pMem, MEM_Null); + if( pMem->flags & MEM_RowSet ){ + sqlite3RowSetClear(pMem->u.pRowSet); + } + MemSetTypeFlag(pMem, MEM_Null); pMem->type = SQLITE_NULL; } @@ -452,7 +462,7 @@ void sqlite3VdbeMemSetNull(Mem *pMem){ */ void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ sqlite3VdbeMemRelease(pMem); - setTypeFlag(pMem, MEM_Blob); + MemSetTypeFlag(pMem, MEM_Blob); pMem->flags = MEM_Blob|MEM_Zero; pMem->type = SQLITE_BLOB; pMem->n = 0; @@ -488,6 +498,28 @@ void sqlite3VdbeMemSetDouble(Mem *pMem, double val){ } /* +** Delete any previous value and set the value of pMem to be an +** empty boolean index. +*/ +void sqlite3VdbeMemSetRowSet(Mem *pMem){ + sqlite3 *db = pMem->db; + assert( db!=0 ); + if( pMem->flags & MEM_RowSet ){ + sqlite3RowSetClear(pMem->u.pRowSet); + }else{ + sqlite3VdbeMemRelease(pMem); + pMem->zMalloc = sqlite3DbMallocRaw(db, 32); + } + if( !db->mallocFailed ){ + assert( pMem->zMalloc ); + pMem->u.pRowSet = sqlite3RowSetInit(db, pMem->zMalloc, + sqlite3DbMallocSize(db, pMem->zMalloc)); + assert( pMem->u.pRowSet!=0 ); + pMem->flags = MEM_RowSet|MEM_Dyn; + } +} + +/* ** Return true if the Mem object contains a TEXT or BLOB that is ** too large - whose size exceeds SQLITE_MAX_LENGTH. */ @@ -515,6 +547,7 @@ int sqlite3VdbeMemTooBig(Mem *p){ ** and flags gets srcType (either MEM_Ephem or MEM_Static). */ void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ + assert( (pFrom->flags & MEM_RowSet)==0 ); sqlite3VdbeMemReleaseExternal(pTo); memcpy(pTo, pFrom, MEMCELLSIZE); pTo->xDel = 0; @@ -532,6 +565,7 @@ void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ int rc = SQLITE_OK; + assert( (pFrom->flags & MEM_RowSet)==0 ); sqlite3VdbeMemReleaseExternal(pTo); memcpy(pTo, pFrom, MEMCELLSIZE); pTo->flags &= ~MEM_Dyn; @@ -585,6 +619,7 @@ int sqlite3VdbeMemSetStr( int flags = 0; /* New value for pMem->flags */ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); + assert( (pMem->flags & MEM_RowSet)==0 ); /* If z is a NULL pointer, set pMem to contain an SQL NULL. */ if( !z ){ @@ -672,6 +707,7 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){ f1 = pMem1->flags; f2 = pMem2->flags; combined_flags = f1|f2; + assert( (combined_flags & MEM_RowSet)==0 ); /* If one value is NULL, it is less than the other. If both values ** are NULL, return 0. @@ -799,6 +835,7 @@ int sqlite3VdbeMemFromBtree( db = sqlite3BtreeCursorDb(pCur); assert( sqlite3_mutex_held(db->mutex) ); + assert( (pMem->flags & MEM_RowSet)==0 ); if( key ){ zData = (char *)sqlite3BtreeKeyFetch(pCur, &available); }else{ @@ -894,6 +931,7 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){ assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); + assert( (pVal->flags & MEM_RowSet)==0 ); if( pVal->flags&MEM_Null ){ return 0; |