Replace the VDBE Fifo object with the new RowSet object. (CVS 5977)
FossilOrigin-Name: 39a0750b49cf55e9c0927169ca47db909f5c16ea
This commit is contained in:
parent
947bd8091b
commit
3d4501e573
12
Makefile.in
12
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
|
||||
|
||||
|
6
main.mk
6
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 \
|
||||
|
34
manifest
34
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
|
||||
|
@ -1 +1 @@
|
||||
4697249fcc6041ba7d2fb89589c855a8bec71eb2
|
||||
39a0750b49cf55e9c0927169ca47db909f5c16ea
|
@ -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 */
|
||||
|
@ -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
|
||||
|
||||
|
238
src/rowset.c
Normal file
238
src/rowset.c
Normal file
@ -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;
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
10
src/update.c
10
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 ){
|
||||
|
76
src/vdbe.c
76
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,35 +4285,55 @@ 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: RowSetRead P1 P2 P3 * *
|
||||
**
|
||||
** 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_RowSetRead: { /* jump, out3 */
|
||||
Mem *pIdx;
|
||||
i64 val;
|
||||
assert( pOp->p1>0 && pOp->p1<=p->nMem );
|
||||
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;
|
||||
}
|
||||
|
||||
/* Opcode: FifoRead P1 P2 * * *
|
||||
**
|
||||
** Attempt to read a single integer from the Fifo. Store that
|
||||
** integer in register P1.
|
||||
**
|
||||
** If the Fifo is empty jump to P2.
|
||||
*/
|
||||
case OP_FifoRead: { /* jump */
|
||||
CHECK_FOR_INTERRUPT;
|
||||
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 ){
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
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 */
|
||||
|
@ -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 *);
|
||||
|
@ -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;
|
||||
|
130
src/vdbefifo.c
130
src/vdbefifo.c
@ -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);
|
||||
}
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user