From: drh Date: Thu, 4 Dec 2008 20:40:10 +0000 (+0000) Subject: Replace the VDBE Fifo object with the new RowSet object. (CVS 5977) X-Git-Tag: version-3.6.10~207 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3d4501e573517b6d2a7b51058b2d162446df059d;p=thirdparty%2Fsqlite.git Replace the VDBE Fifo object with the new RowSet object. (CVS 5977) FossilOrigin-Name: 39a0750b49cf55e9c0927169ca47db909f5c16ea --- diff --git a/Makefile.in b/Makefile.in index 427680ee65..3b0f9a12b8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -168,10 +168,10 @@ OBJS0 = alter.lo analyze.lo attach.lo auth.lo bitvec.lo btmutex.lo \ mutex.lo mutex_noop.lo mutex_os2.lo mutex_unix.lo mutex_w32.lo \ opcodes.lo os.lo os_unix.lo os_win.lo os_os2.lo \ pager.lo parse.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \ - random.lo resolve.lo select.lo status.lo \ + random.lo resolve.lo rowset.lo select.lo status.lo \ table.lo tokenize.lo trigger.lo update.lo \ util.lo vacuum.lo \ - vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbefifo.lo vdbemem.lo \ + vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo \ walker.lo where.lo utf.lo vtab.lo # Object files for the amalgamation. @@ -243,6 +243,7 @@ SRC = \ $(TOP)/src/printf.c \ $(TOP)/src/random.c \ $(TOP)/src/resolve.c \ + $(TOP)/src/rowset.c \ $(TOP)/src/select.c \ $(TOP)/src/status.c \ $(TOP)/src/shell.c \ @@ -263,7 +264,6 @@ SRC = \ $(TOP)/src/vdbeapi.c \ $(TOP)/src/vdbeaux.c \ $(TOP)/src/vdbeblob.c \ - $(TOP)/src/vdbefifo.c \ $(TOP)/src/vdbemem.c \ $(TOP)/src/vdbeInt.h \ $(TOP)/src/vtab.c \ @@ -649,6 +649,9 @@ random.lo: $(TOP)/src/random.c $(HDR) resolve.lo: $(TOP)/src/resolve.c $(HDR) $(LTCOMPILE) -c $(TOP)/src/resolve.c +rowset.lo: $(TOP)/src/rowset.c $(HDR) + $(LTCOMPILE) -c $(TOP)/src/rowset.c + select.lo: $(TOP)/src/select.c $(HDR) $(LTCOMPILE) -c $(TOP)/src/select.c @@ -699,9 +702,6 @@ vdbeaux.lo: $(TOP)/src/vdbeaux.c $(HDR) vdbeblob.lo: $(TOP)/src/vdbeblob.c $(HDR) $(LTCOMPILE) -c $(TOP)/src/vdbeblob.c -vdbefifo.lo: $(TOP)/src/vdbefifo.c $(HDR) - $(LTCOMPILE) -c $(TOP)/src/vdbefifo.c - vdbemem.lo: $(TOP)/src/vdbemem.c $(HDR) $(LTCOMPILE) -c $(TOP)/src/vdbemem.c diff --git a/main.mk b/main.mk index 9145832b3e..d3c33517ac 100644 --- a/main.mk +++ b/main.mk @@ -61,10 +61,10 @@ LIBOBJ+= alter.o analyze.o attach.o auth.o \ mutex.o mutex_noop.o mutex_os2.o mutex_unix.o mutex_w32.o \ opcodes.o os.o os_os2.o os_unix.o os_win.o \ pager.o parse.o pcache.o pcache1.o pragma.o prepare.o printf.o \ - random.o resolve.o rtree.o select.o status.o \ + random.o resolve.o rowset.o rtree.o select.o status.o \ table.o tokenize.o trigger.o \ update.o util.o vacuum.o \ - vdbe.o vdbeapi.o vdbeaux.o vdbeblob.o vdbefifo.o vdbemem.o \ + vdbe.o vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o \ walker.o where.o utf.o vtab.o @@ -128,6 +128,7 @@ SRC = \ $(TOP)/src/printf.c \ $(TOP)/src/random.c \ $(TOP)/src/resolve.c \ + $(TOP)/src/rowset.c \ $(TOP)/src/select.c \ $(TOP)/src/status.c \ $(TOP)/src/shell.c \ @@ -148,7 +149,6 @@ SRC = \ $(TOP)/src/vdbeapi.c \ $(TOP)/src/vdbeaux.c \ $(TOP)/src/vdbeblob.c \ - $(TOP)/src/vdbefifo.c \ $(TOP)/src/vdbemem.c \ $(TOP)/src/vdbeInt.h \ $(TOP)/src/vtab.c \ diff --git a/manifest b/manifest index 6572cbace8..10cdf8435d 100644 --- a/manifest +++ b/manifest @@ -1,7 +1,7 @@ -C Make\ssure\sdot-lock\sis\sfully\senabled\swhen\sSQLITE_ENABLE_LOCKING_STYLE\sis\ndisabled.\s\sFix\scompiler\swarnings\swhen\sSQLITE_ENABLE_LOCKING_STYLE\sis\ndisabled.\s(CVS\s5976) -D 2008-12-04T12:34:16 +C Replace\sthe\sVDBE\sFifo\sobject\swith\sthe\snew\sRowSet\sobject.\s(CVS\s5977) +D 2008-12-04T20:40:10 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 -F Makefile.in 0aa7bbe3be6acc4045706e3bb3fd0b8f38f4a3b5 +F Makefile.in f7e4c81c347b04f7b0f1c1b081a168645d7b8af7 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 F Makefile.vxwSH4 d53b4be86491060d498b22148951b6d765884cab F README b974cdc3f9f12b87e851b04e75996d720ebf81ac @@ -80,7 +80,7 @@ F ext/rtree/tkt3363.test 6662237ea75bb431cd5d262dfc9535e1023315fc F ext/rtree/viewrtree.tcl 09526398dae87a5a87c5aac2b3854dbaf8376869 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 F ltmain.sh 09fe5815427dc7d0abb188bbcdf0e34896577210 -F main.mk 87a73e91a3d0827dc796a249260866335e38a36e +F main.mk 5923e75b5ac4b265f322597c3953dda7175f4405 F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac @@ -107,7 +107,7 @@ F src/build.c a89e901ea24d8ec845286f9a1fbfd14572a7777e F src/callback.c e970e5beddbdb23f89a6d05cb1a6419d9f755624 F src/complete.c cb14e06dbe79dee031031f0d9e686ff306afe07c F src/date.c 88898ae96a0d7f66711caffa40b2cf30e623a387 -F src/delete.c 2f85d6d00333343a76824a899e15f241ca383c7c +F src/delete.c d60885716666e5ea0f177b8db73c22c67ccba2cb F src/expr.c 01b1cf0783a6d0093d72b799fcb22c86146362ef F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff F src/func.c b4570eb73d873041b8e68f5cdbb4556ff13a94c3 @@ -142,7 +142,7 @@ F src/os_win.c 3dff41670fb9798a869c636626bb7d6d8b6a45bb F src/pager.c a193da9e271898077de815819e4c29fc2b6ece2a F src/pager.h a02ef8e6cc7e78b54874166e5ce786c9d4c489bf F src/parse.y 72397fe334b25b4f3411edbf49b5b706f2d7bdae -F src/pcache.c f3121a531745b20f5b824201eb63949a7e2959ac +F src/pcache.c 16dc8da6e6ba6250f8dfd9ee46036db1cbceedc6 F src/pcache.h f20c3e82dd6da622c3fe296170cb1801f9a2d75a F src/pcache1.c d8d412326cc5123ba3bfaa66e36205ca8c5dbc5e F src/pragma.c 539e28c90e782fa909a3b3a6849d18a9eb11a548 @@ -150,11 +150,12 @@ F src/prepare.c fcadb25d2ad722d87103517333c825b56b79a770 F src/printf.c e29d9475c63e1dbfae005b98da3a60e07b5c1ca5 F src/random.c a87afbd598aa877e23ac676ee92fd8ee5c786a51 F src/resolve.c 4af5391d2b4c1d6c583a6805ac6660181de4545b +F src/rowset.c 2256fa4a928f750e2f3d6fc733523034beceb1d6 F src/select.c b296a7b53dd0b2c42ab8b67d969e2c924529008c F src/shell.c 838c745e7ac5c9fe17bc996224ed2f928d178bb2 F src/sqlite.h.in b5d50f12fb9c7460a4ddfef8c1e799afaabefebf F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17 -F src/sqliteInt.h 54d956e75ec8b8d174eb3d98de6f54db8507da5d +F src/sqliteInt.h 1ed98f6df8475b82fed5bc174ebe1637dd9fc7d1 F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8 F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76 F src/table.c 22744786199c9195720c15a7a42cb97b2e2728d8 @@ -189,18 +190,17 @@ F src/test_thread.c d74fc445e0dba0e00806117eb449b307c0b146bf F src/test_wsd.c c297d7d6b8a990239e1bd25935e81d612d8ae31d F src/tokenize.c aaa5fa6a4536a9dd7c855a3f66f32508f1612138 F src/trigger.c b86eb6d216c0014138f858a04185113cb54518e4 -F src/update.c 37d03659f4d2186ffb8d0ab1df9c3038273fb488 +F src/update.c 7143ac31d26dee156277126e9a7c5be953b18347 F src/utf.c 86dc0f8076f606432a01f1498ae054c32de1f9d2 F src/util.c b9a5d1c4c1a433e17d5828f9717fac763016a2cb F src/vacuum.c 383d6297bddc011ab04a9eed110db6eaf523e8e9 -F src/vdbe.c 3291fb0fe366634da2b92db4ca962b8d21427324 +F src/vdbe.c 5c46d3742f36599e615ce57164e44c64df5d0470 F src/vdbe.h 03516f28bf5aca00a53c4dccd6c313f96adb94f6 -F src/vdbeInt.h 6b1082480832d406c57a7f469a1c61f1a8759aca +F src/vdbeInt.h 1df957ab0f6a129735513d528c930dddfb4b23ef F src/vdbeapi.c 20722164e7701a0747eaea03cddbbe0de5cb37bf -F src/vdbeaux.c 250296ad13b368b9e1076c7b002b3435154ed31f +F src/vdbeaux.c 33ba6b66bc595f5522e6a6995a86799bacd8961b F src/vdbeblob.c b0dcebfafedcf9c0addc7901ad98f6f986c08935 -F src/vdbefifo.c e6326ad6d16ccd8c2ef659046e3a509c0ae4990a -F src/vdbemem.c 223e03281855515e9474dbf66f157452093a77c2 +F src/vdbemem.c 2f386accfa1f4f11f0f12c2b6dcd4948e6df9c1f F src/vtab.c 02c51eac45dbff1a1d6e73f58febf92ecb563f7f F src/walker.c 488c2660e13224ff70c0c82761118efb547f8f0d F src/where.c 96f7c2bd9e83c252d90ee2794f7a902fc5ba505b @@ -647,7 +647,7 @@ F tool/memleak3.tcl 7707006ee908cffff210c98158788d85bb3fcdbf F tool/mkkeywordhash.c c219ee2b8b5b8e7011cccfa1caec62d9812e82e7 F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e x F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 -F tool/mksqlite3c.tcl 619c0629ac51f670f1f522cd0ab1fbb62ca97d45 +F tool/mksqlite3c.tcl 75cb8cdbea59c0db53a2393df15229376c211ca1 F tool/mksqlite3internalh.tcl 7b43894e21bcb1bb39e11547ce7e38a063357e87 F tool/omittest.tcl 27d6f6e3b1e95aeb26a1c140e6eb57771c6d794a F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c @@ -662,7 +662,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e -P cb9c15431c53b13b70d006d8c47741ebc1caaca3 -R 39955cff0967682033948df06f70c97f +P 4697249fcc6041ba7d2fb89589c855a8bec71eb2 +R 854bd2622f9c32e838b36a1ab2f599ef U drh -Z 033061a221ce993448c8fae205600a11 +Z 79aa37bffdc9ab8f785db1e32012837b diff --git a/manifest.uuid b/manifest.uuid index 00d56e781b..3ff0380ac7 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4697249fcc6041ba7d2fb89589c855a8bec71eb2 \ No newline at end of file +39a0750b49cf55e9c0927169ca47db909f5c16ea \ No newline at end of file diff --git a/src/delete.c b/src/delete.c index 7c3f0add10..6fad57aef7 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 c008f4b608..b513e275c1 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 0000000000..2be962759c --- /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( NpChunk = 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->vv ){ + pTail->pNext = pA; + pA = pA->pNext; + pTail = pTail->pNext; + }else if( pB->vv ){ + 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; ipEntry = 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 86d26a66b5..0cd41f8d83 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 34a496e485..06b500de51 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 9e471a0863..191b3c58f5 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 @@ -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 312ea80416..e637974d68 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() @@ -221,33 +227,6 @@ struct Set { HashElem *prev; /* Previously accessed hash elemen */ }; -/* -** 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). @@ -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 b3710e9947..b95140070c 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 @@ -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; icontextStackTop; 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 5a266bb2c3..0000000000 --- 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->iReadnSlot ); - 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 8d96e62df2..d9ec059e8e 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 @@ -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)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; @@ -487,6 +497,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; diff --git a/tool/mksqlite3c.tcl b/tool/mksqlite3c.tcl index 1f00b9fcb4..7b64c539ef 100644 --- a/tool/mksqlite3c.tcl +++ b/tool/mksqlite3c.tcl @@ -236,12 +236,12 @@ foreach file { bitvec.c pcache.c pcache1.c + rowset.c pager.c btmutex.c btree.c - vdbefifo.c vdbemem.c vdbeaux.c vdbeapi.c