]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Replace the VDBE Fifo object with the new RowSet object. (CVS 5977)
authordrh <drh@noemail.net>
Thu, 4 Dec 2008 20:40:10 +0000 (20:40 +0000)
committerdrh <drh@noemail.net>
Thu, 4 Dec 2008 20:40:10 +0000 (20:40 +0000)
FossilOrigin-Name: 39a0750b49cf55e9c0927169ca47db909f5c16ea

15 files changed:
Makefile.in
main.mk
manifest
manifest.uuid
src/delete.c
src/pcache.c
src/rowset.c [new file with mode: 0644]
src/sqliteInt.h
src/update.c
src/vdbe.c
src/vdbeInt.h
src/vdbeaux.c
src/vdbefifo.c [deleted file]
src/vdbemem.c
tool/mksqlite3c.tcl

index 427680ee65cdef6990771780f1186f62cf45247a..3b0f9a12b8aa39ca3fc349c4058206c51a4d5618 100644 (file)
@@ -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 9145832b3e89ee237e40b06c45cfe369948f1900..d3c33517ace3efc6e3f3d7622a6061886337b5fb 100644 (file)
--- 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 \
index 6572cbace85238e0ffb780ddd08c165714b8032f..10cdf8435d641694a35f84cadd1adf556d97948e 100644 (file)
--- 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
index 00d56e781b11c5d50e14444adeedd7fcf89e3bc1..3ff0380ac7f53ce924b10e4c0871173c3725b683 100644 (file)
@@ -1 +1 @@
-4697249fcc6041ba7d2fb89589c855a8bec71eb2
\ No newline at end of file
+39a0750b49cf55e9c0927169ca47db909f5c16ea
\ No newline at end of file
index 7c3f0add101864f1075e8cf52c0bd01d94dba5a2..6fad57aef79888b815a8b3cd787a120c29dd70e2 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.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 */
index c008f4b60834355993558511b3c6319bef6bece6..b513e275c14679dba336a32e4a42128f7f72af09 100644 (file)
@@ -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 (file)
index 0000000..2be9627
--- /dev/null
@@ -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;
+  }
+}
index 86d26a66b50362da7a5e5e6445a3c8c0ae5a4b7f..0cd41f8d83aabca5f624b3f3602513eed2492be5 100644 (file)
@@ -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)
index 34a496e4857158bb5138bb7ba9e37ebb00d9857c..06b500de5106ca90be899fde052252c6bedce12a 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.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 ){
index 9e471a08632d7d91c69a9a397ee1c4c3c6e28868..191b3c58f55b5c967c90c7439bb7eccee8d0f951 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.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 */
index 312ea80416dac563748cfafab0393ad923956046..e637974d6854d0482b6172e1060292c72c1ed3e0 100644 (file)
@@ -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 *);
index b3710e99473e6b2a169ebdc4e6f1b4d24e941255..b95140070cdfcd65e71b7884eb0cec69eccc97d8 100644 (file)
@@ -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 (file)
index 5a266bb..0000000
+++ /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);
-}
index 8d96e62df22b490724b36c08db5cca9abede8422..d9ec059e8e1857b0a7583ec16ef97ead36ff33ab 100644 (file)
@@ -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;
@@ -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;
index 1f00b9fcb489be0ba16d70b631fcc70c233a53de..7b64c539ef33d7a94dd8aced39ce64547a61a9ae 100644 (file)
@@ -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