Also free up the MEM_RowSet bit in the Mem.flags field and have RowSet objects

be destroyed using Mem.xDel.  This change results in faster code.

FossilOrigin-Name: f48e9feb3fca514e4e586932e6d19a5e34a384204effeba553006dcddf5f13d2
This commit is contained in:
drh 2018-08-29 20:24:03 +00:00
parent 72f56ef95d
commit 9d67afc421
8 changed files with 101 additions and 88 deletions

View File

@ -1,5 +1,5 @@
C Free\sup\sthe\sMEM_Frame\sbit\sin\sMem.flags\sobject.\s\sStore\sVdbeFrame\sobjects\nas\sMEM_Blob\swith\sa\sspecial\sMem.xDel\spointer\sinstead. C Also\sfree\sup\sthe\sMEM_RowSet\sbit\sin\sthe\sMem.flags\sfield\sand\shave\sRowSet\sobjects\nbe\sdestroyed\susing\sMem.xDel.\s\sThis\schange\sresults\sin\sfaster\scode.
D 2018-08-29T18:47:22.883 D 2018-08-29T20:24:03.572
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F Makefile.in d06f463c5b623a61ac27f5cb8214fca9e53a6704d34d6b8f2124e2b1b293c88f F Makefile.in d06f463c5b623a61ac27f5cb8214fca9e53a6704d34d6b8f2124e2b1b293c88f
@ -499,13 +499,13 @@ F src/prepare.c e966ecc97c3671ff0e96227c8c877b83f2d33ea371ee190bbf1698b36b5605c0
F src/printf.c 7f6f3cba8e0c49c19e30a1ff4e9aeda6e06814dcbad4b664a69e1b6cb6e7e365 F src/printf.c 7f6f3cba8e0c49c19e30a1ff4e9aeda6e06814dcbad4b664a69e1b6cb6e7e365
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
F src/resolve.c 797088662ed61102485e3070ba3b3f7828bd5ef6a588223ba6865d77d52f6cea F src/resolve.c 797088662ed61102485e3070ba3b3f7828bd5ef6a588223ba6865d77d52f6cea
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93
F src/select.c ae7396a314cc1bb1d767947cd57094e3a9ffcbb155ebc1b1c391e028c44a9a04 F src/select.c ae7396a314cc1bb1d767947cd57094e3a9ffcbb155ebc1b1c391e028c44a9a04
F src/shell.c.in 6e0aad854be738a5d0368940459399be211e9ac43aebe92bb9ed46cfe38d0e1f F src/shell.c.in 6e0aad854be738a5d0368940459399be211e9ac43aebe92bb9ed46cfe38d0e1f
F src/sqlite.h.in 5a2d431493020c2c9f2f37c9119d6439444e3c44a714566a5192b6911ac917e6 F src/sqlite.h.in 5a2d431493020c2c9f2f37c9119d6439444e3c44a714566a5192b6911ac917e6
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7 F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7
F src/sqliteInt.h 2a670143a4f6b7d85958bac125e4d9d8ad14f016a3582e9d7c6907d9d50b75a0 F src/sqliteInt.h 26e48f0c823844fcce67bd2a11ad1ad3468aaed32fd8864bc69c4147cb608728
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
@ -571,13 +571,13 @@ F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5 F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157 F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157
F src/vacuum.c 36e7d21a20c0bf6ef4ef7c399d192b5239410b7c4d3c1070fba4e30810d0b855 F src/vacuum.c 36e7d21a20c0bf6ef4ef7c399d192b5239410b7c4d3c1070fba4e30810d0b855
F src/vdbe.c a44a1cd246f808d36ee0ce7dc031d9624a50242db96ac57f65ad93aea65ceaac F src/vdbe.c 74671dff9ba856c5464557a8dbf2ba940fc4fa67efbceb32e262eedac31d86ca
F src/vdbe.h 5081dcc497777efe5e9ebe7330d283a044a005e4bdda2e2e984f03bf89a0d907 F src/vdbe.h 5081dcc497777efe5e9ebe7330d283a044a005e4bdda2e2e984f03bf89a0d907
F src/vdbeInt.h a660268d9e60dcd60abe8768c1582dd35f3d174ad12f742aee8c805af72dac03 F src/vdbeInt.h f1f35f70460698d8f5a2bdef1001114babf318e2983a067804e2ae077d8e9827
F src/vdbeapi.c 2ba821c5929a2769e4b217dd85843479c718b8989d414723ec8af0616a83d611 F src/vdbeapi.c 2ba821c5929a2769e4b217dd85843479c718b8989d414723ec8af0616a83d611
F src/vdbeaux.c 20da0273e9bdb3f49dafa71123d7bdd63b2656134ecd73123562c028847d0e07 F src/vdbeaux.c 1ee77344fe9fd6ac11fae6f0150f81e0eadf349a9957340089cf82284e6b379a
F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191 F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191
F src/vdbemem.c 9a9aa4262f2c5620a552ad83902379d9b1dbb792eb4c1e8758ffffa7ab8a2e64 F src/vdbemem.c 81329ab760e4ec0162119d9cd10193e0303c45c5935bb20c7ae9139d44dd6641
F src/vdbesort.c 90aad5a92608f2dd771c96749beabdb562c9d881131a860a7a5bccf66dc3be7f F src/vdbesort.c 90aad5a92608f2dd771c96749beabdb562c9d881131a860a7a5bccf66dc3be7f
F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392 F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392
F src/vtab.c 678992ac8ec677a3f9b08126aaf891441083805e3b42574e3654d44538381c14 F src/vtab.c 678992ac8ec677a3f9b08126aaf891441083805e3b42574e3654d44538381c14
@ -1758,7 +1758,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 2d4debccbc027405a33aeb10f9d65f6fe4bfb5eb1be5a4d8b82158caba04643f P 62db5fd47660bbc4fcf2c6d4a6c5a3077f12c6442a128d22b66b789a0409ef32
R bd76e3ebc281873295239e9b6605a092 R b874f6bc6fe7e6d492c17f3293f43632
U drh U drh
Z 6a1519aefdfc6d3a0da507442f0a767b Z e2bd09cc55c8cf3a3298f3d931f8e0b9

View File

@ -1 +1 @@
62db5fd47660bbc4fcf2c6d4a6c5a3077f12c6442a128d22b66b789a0409ef32 f48e9feb3fca514e4e586932e6d19a5e34a384204effeba553006dcddf5f13d2

View File

@ -124,30 +124,23 @@ struct RowSet {
#define ROWSET_NEXT 0x02 /* True if sqlite3RowSetNext() has been called */ #define ROWSET_NEXT 0x02 /* True if sqlite3RowSetNext() has been called */
/* /*
** Turn bulk memory into a RowSet object. N bytes of memory ** Allocate a RowSet object. Return NULL if a memory allocation
** are available at pSpace. The db pointer is used as a memory context ** error occurs.
** for any subsequent allocations that need to occur.
** Return a pointer to the new RowSet object.
**
** It must be the case that N is sufficient to make a Rowset. If not
** an assertion fault occurs.
**
** 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 *sqlite3RowSetInit(sqlite3 *db){
RowSet *p; RowSet *p = sqlite3DbMallocRawNN(db, sizeof(*p));
assert( N >= ROUND8(sizeof(*p)) ); if( p ){
p = pSpace; int N = sqlite3DbMallocSize(db, p);
p->pChunk = 0; p->pChunk = 0;
p->db = db; p->db = db;
p->pEntry = 0; p->pEntry = 0;
p->pLast = 0; p->pLast = 0;
p->pForest = 0; p->pForest = 0;
p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p); p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p);
p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry)); p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry));
p->rsFlags = ROWSET_SORTED; p->rsFlags = ROWSET_SORTED;
p->iBatch = 0; p->iBatch = 0;
}
return p; return p;
} }
@ -156,7 +149,8 @@ RowSet *sqlite3RowSetInit(sqlite3 *db, void *pSpace, unsigned int N){
** the RowSet has allocated over its lifetime. This routine is ** the RowSet has allocated over its lifetime. This routine is
** the destructor for the RowSet. ** the destructor for the RowSet.
*/ */
void sqlite3RowSetClear(RowSet *p){ void sqlite3RowSetClear(void *pArg){
RowSet *p = (RowSet*)pArg;
struct RowSetChunk *pChunk, *pNextChunk; struct RowSetChunk *pChunk, *pNextChunk;
for(pChunk=p->pChunk; pChunk; pChunk = pNextChunk){ for(pChunk=p->pChunk; pChunk; pChunk = pNextChunk){
pNextChunk = pChunk->pNextChunk; pNextChunk = pChunk->pNextChunk;
@ -170,6 +164,16 @@ void sqlite3RowSetClear(RowSet *p){
p->rsFlags = ROWSET_SORTED; p->rsFlags = ROWSET_SORTED;
} }
/*
** Deallocate all chunks from a RowSet. This frees all memory that
** the RowSet has allocated over its lifetime. This routine is
** the destructor for the RowSet.
*/
void sqlite3RowSetDelete(void *pArg){
sqlite3RowSetClear(pArg);
sqlite3DbFree(((RowSet*)pArg)->db, pArg);
}
/* /*
** Allocate a new RowSetEntry object that is associated with the ** Allocate a new RowSetEntry object that is associated with the
** given RowSet. Return a pointer to the new and completely uninitialized ** given RowSet. Return a pointer to the new and completely uninitialized

View File

@ -3825,8 +3825,9 @@ u32 sqlite3BitvecSize(Bitvec*);
int sqlite3BitvecBuiltinTest(int,int*); int sqlite3BitvecBuiltinTest(int,int*);
#endif #endif
RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int); RowSet *sqlite3RowSetInit(sqlite3*);
void sqlite3RowSetClear(RowSet*); void sqlite3RowSetDelete(void*);
void sqlite3RowSetClear(void*);
void sqlite3RowSetInsert(RowSet*, i64); void sqlite3RowSetInsert(RowSet*, i64);
int sqlite3RowSetTest(RowSet*, int iBatch, i64); int sqlite3RowSetTest(RowSet*, int iBatch, i64);
int sqlite3RowSetNext(RowSet*, i64*); int sqlite3RowSetNext(RowSet*, i64*);

View File

@ -502,7 +502,7 @@ static void memTracePrint(Mem *p){
}else if( p->flags & MEM_Real ){ }else if( p->flags & MEM_Real ){
printf(" r:%g", p->u.r); printf(" r:%g", p->u.r);
#endif #endif
}else if( p->flags & MEM_RowSet ){ }else if( sqlite3VdbeMemIsRowSet(p) ){
printf(" (rowset)"); printf(" (rowset)");
}else{ }else{
char zBuf[200]; char zBuf[200];
@ -5903,11 +5903,11 @@ case OP_RowSetAdd: { /* in1, in2 */
pIn1 = &aMem[pOp->p1]; pIn1 = &aMem[pOp->p1];
pIn2 = &aMem[pOp->p2]; pIn2 = &aMem[pOp->p2];
assert( (pIn2->flags & MEM_Int)!=0 ); assert( (pIn2->flags & MEM_Int)!=0 );
if( (pIn1->flags & MEM_RowSet)==0 ){ if( (pIn1->flags & MEM_Blob)==0 ){
sqlite3VdbeMemSetRowSet(pIn1); if( sqlite3VdbeMemSetRowSet(pIn1) ) goto no_mem;
if( (pIn1->flags & MEM_RowSet)==0 ) goto no_mem;
} }
sqlite3RowSetInsert(pIn1->u.pRowSet, pIn2->u.i); assert( sqlite3VdbeMemIsRowSet(pIn1) );
sqlite3RowSetInsert((RowSet*)pIn1->z, pIn2->u.i);
break; break;
} }
@ -5923,8 +5923,9 @@ case OP_RowSetRead: { /* jump, in1, out3 */
i64 val; i64 val;
pIn1 = &aMem[pOp->p1]; pIn1 = &aMem[pOp->p1];
if( (pIn1->flags & MEM_RowSet)==0 assert( (pIn1->flags & MEM_Blob)==0 || sqlite3VdbeMemIsRowSet(pIn1) );
|| sqlite3RowSetNext(pIn1->u.pRowSet, &val)==0 if( (pIn1->flags & MEM_Blob)==0
|| sqlite3RowSetNext((RowSet*)pIn1->z, &val)==0
){ ){
/* The boolean index is empty */ /* The boolean index is empty */
sqlite3VdbeMemSetNull(pIn1); sqlite3VdbeMemSetNull(pIn1);
@ -5973,20 +5974,19 @@ case OP_RowSetTest: { /* jump, in1, in3 */
/* If there is anything other than a rowset object in memory cell P1, /* If there is anything other than a rowset object in memory cell P1,
** delete it now and initialize P1 with an empty rowset ** delete it now and initialize P1 with an empty rowset
*/ */
if( (pIn1->flags & MEM_RowSet)==0 ){ if( (pIn1->flags & MEM_Blob)==0 ){
sqlite3VdbeMemSetRowSet(pIn1); if( sqlite3VdbeMemSetRowSet(pIn1) ) goto no_mem;
if( (pIn1->flags & MEM_RowSet)==0 ) goto no_mem;
} }
assert( sqlite3VdbeMemIsRowSet(pIn1) );
assert( pOp->p4type==P4_INT32 ); assert( pOp->p4type==P4_INT32 );
assert( iSet==-1 || iSet>=0 ); assert( iSet==-1 || iSet>=0 );
if( iSet ){ if( iSet ){
exists = sqlite3RowSetTest(pIn1->u.pRowSet, iSet, pIn3->u.i); exists = sqlite3RowSetTest((RowSet*)pIn1->z, iSet, pIn3->u.i);
VdbeBranchTaken(exists!=0,2); VdbeBranchTaken(exists!=0,2);
if( exists ) goto jump_to_p2; if( exists ) goto jump_to_p2;
} }
if( iSet>=0 ){ if( iSet>=0 ){
sqlite3RowSetInsert(pIn1->u.pRowSet, pIn3->u.i); sqlite3RowSetInsert((RowSet*)pIn1->z, pIn3->u.i);
} }
break; break;
} }

View File

@ -203,7 +203,6 @@ struct sqlite3_value {
int nZero; /* Extra zero bytes when MEM_Zero and MEM_Blob set */ int nZero; /* Extra zero bytes when MEM_Zero and MEM_Blob set */
const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */ const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */
FuncDef *pDef; /* Used only when flags==MEM_Agg */ FuncDef *pDef; /* Used only when flags==MEM_Agg */
RowSet *pRowSet; /* Used only when flags==MEM_RowSet */
} u; } u;
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */ u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */ u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
@ -247,7 +246,7 @@ struct sqlite3_value {
#define MEM_Real 0x0008 /* Value is a real number */ #define MEM_Real 0x0008 /* Value is a real number */
#define MEM_Blob 0x0010 /* Value is a BLOB */ #define MEM_Blob 0x0010 /* Value is a BLOB */
#define MEM_AffMask 0x001f /* Mask of affinity bits */ #define MEM_AffMask 0x001f /* Mask of affinity bits */
#define MEM_RowSet 0x0020 /* Value is a RowSet object */ /* Available 0x0020 */
/* Available 0x0040 */ /* Available 0x0040 */
#define MEM_Undefined 0x0080 /* Value is undefined */ #define MEM_Undefined 0x0080 /* Value is undefined */
#define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */ #define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */
@ -275,7 +274,7 @@ struct sqlite3_value {
** that needs to be deallocated to avoid a leak. ** that needs to be deallocated to avoid a leak.
*/ */
#define VdbeMemDynamic(X) \ #define VdbeMemDynamic(X) \
(((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet))!=0) (((X)->flags&(MEM_Agg|MEM_Dyn))!=0)
/* /*
** Clear any existing type flags from a Mem and replace them with f ** Clear any existing type flags from a Mem and replace them with f
@ -488,7 +487,10 @@ void sqlite3VdbeMemSetPointer(Mem*, void*, const char*, void(*)(void*));
void sqlite3VdbeMemInit(Mem*,sqlite3*,u16); void sqlite3VdbeMemInit(Mem*,sqlite3*,u16);
void sqlite3VdbeMemSetNull(Mem*); void sqlite3VdbeMemSetNull(Mem*);
void sqlite3VdbeMemSetZeroBlob(Mem*,int); void sqlite3VdbeMemSetZeroBlob(Mem*,int);
void sqlite3VdbeMemSetRowSet(Mem*); #ifdef SQLITE_DEBUG
int sqlite3VdbeMemIsRowSet(const Mem*);
#endif
int sqlite3VdbeMemSetRowSet(Mem*);
int sqlite3VdbeMemMakeWriteable(Mem*); int sqlite3VdbeMemMakeWriteable(Mem*);
int sqlite3VdbeMemStringify(Mem*, u8, u8); int sqlite3VdbeMemStringify(Mem*, u8, u8);
i64 sqlite3VdbeIntValue(Mem*); i64 sqlite3VdbeIntValue(Mem*);

View File

@ -1663,7 +1663,7 @@ static void releaseMemArray(Mem *p, int N){
testcase( p->flags & MEM_Dyn ); testcase( p->flags & MEM_Dyn );
testcase( p->xDel==sqlite3VdbeFrameMemDel ); testcase( p->xDel==sqlite3VdbeFrameMemDel );
testcase( p->flags & MEM_RowSet ); testcase( p->flags & MEM_RowSet );
if( p->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet) ){ if( p->flags&(MEM_Agg|MEM_Dyn) ){
sqlite3VdbeMemRelease(p); sqlite3VdbeMemRelease(p);
}else if( p->szMalloc ){ }else if( p->szMalloc ){
sqlite3DbFreeNN(db, p->zMalloc); sqlite3DbFreeNN(db, p->zMalloc);
@ -3991,7 +3991,7 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
f1 = pMem1->flags; f1 = pMem1->flags;
f2 = pMem2->flags; f2 = pMem2->flags;
combined_flags = f1|f2; combined_flags = f1|f2;
assert( (combined_flags & MEM_RowSet)==0 ); assert( !sqlite3VdbeMemIsRowSet(pMem1) && !sqlite3VdbeMemIsRowSet(pMem2) );
/* If one value is NULL, it is less than the other. If both values /* If one value is NULL, it is less than the other. If both values
** are NULL, return 0. ** are NULL, return 0.

View File

@ -42,8 +42,7 @@ int sqlite3VdbeCheckMemInvariants(Mem *p){
if( p->flags & MEM_Null ){ if( p->flags & MEM_Null ){
/* Cannot be both MEM_Null and some other type */ /* Cannot be both MEM_Null and some other type */
assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob|MEM_Agg))==0 );
|MEM_RowSet|MEM_Agg))==0 );
/* If MEM_Null is set, then either the value is a pure NULL (the usual /* If MEM_Null is set, then either the value is a pure NULL (the usual
** case) or it is a pointer set using sqlite3_bind_pointer() or ** case) or it is a pointer set using sqlite3_bind_pointer() or
@ -156,7 +155,7 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
#ifndef SQLITE_OMIT_UTF16 #ifndef SQLITE_OMIT_UTF16
int rc; int rc;
#endif #endif
assert( (pMem->flags&MEM_RowSet)==0 ); assert( !sqlite3VdbeMemIsRowSet(pMem) );
assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE
|| desiredEnc==SQLITE_UTF16BE ); || desiredEnc==SQLITE_UTF16BE );
if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){ if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){
@ -189,7 +188,7 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
*/ */
SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){ SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
assert( sqlite3VdbeCheckMemInvariants(pMem) ); assert( sqlite3VdbeCheckMemInvariants(pMem) );
assert( (pMem->flags&MEM_RowSet)==0 ); assert( !sqlite3VdbeMemIsRowSet(pMem) );
testcase( pMem->db==0 ); testcase( pMem->db==0 );
/* If the bPreserve flag is set to true, then the memory cell must already /* If the bPreserve flag is set to true, then the memory cell must already
@ -277,7 +276,7 @@ static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){
*/ */
int sqlite3VdbeMemMakeWriteable(Mem *pMem){ int sqlite3VdbeMemMakeWriteable(Mem *pMem){
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( (pMem->flags&MEM_RowSet)==0 ); assert( !sqlite3VdbeMemIsRowSet(pMem) );
if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){ if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){
if( ExpandBlob(pMem) ) return SQLITE_NOMEM; if( ExpandBlob(pMem) ) return SQLITE_NOMEM;
if( pMem->szMalloc==0 || pMem->z!=pMem->zMalloc ){ if( pMem->szMalloc==0 || pMem->z!=pMem->zMalloc ){
@ -302,7 +301,7 @@ int sqlite3VdbeMemExpandBlob(Mem *pMem){
int nByte; int nByte;
assert( pMem->flags & MEM_Zero ); assert( pMem->flags & MEM_Zero );
assert( pMem->flags&MEM_Blob ); assert( pMem->flags&MEM_Blob );
assert( (pMem->flags&MEM_RowSet)==0 ); assert( !sqlite3VdbeMemIsRowSet(pMem) );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
/* Set nByte to the number of bytes required to store the expanded blob. */ /* Set nByte to the number of bytes required to store the expanded blob. */
@ -357,7 +356,7 @@ int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
assert( !(fg&MEM_Zero) ); assert( !(fg&MEM_Zero) );
assert( !(fg&(MEM_Str|MEM_Blob)) ); assert( !(fg&(MEM_Str|MEM_Blob)) );
assert( fg&(MEM_Int|MEM_Real) ); assert( fg&(MEM_Int|MEM_Real) );
assert( (pMem->flags&MEM_RowSet)==0 ); assert( !sqlite3VdbeMemIsRowSet(pMem) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) );
@ -462,11 +461,8 @@ static SQLITE_NOINLINE void vdbeMemClearExternAndSetNull(Mem *p){
testcase( p->flags & MEM_Dyn ); testcase( p->flags & MEM_Dyn );
} }
if( p->flags&MEM_Dyn ){ if( p->flags&MEM_Dyn ){
assert( (p->flags&MEM_RowSet)==0 );
assert( p->xDel!=SQLITE_DYNAMIC && p->xDel!=0 ); assert( p->xDel!=SQLITE_DYNAMIC && p->xDel!=0 );
p->xDel((void *)p->z); p->xDel((void *)p->z);
}else if( p->flags&MEM_RowSet ){
sqlite3RowSetClear(p->u.pRowSet);
} }
p->flags = MEM_Null; p->flags = MEM_Null;
} }
@ -614,7 +610,7 @@ int sqlite3VdbeBooleanValue(Mem *pMem, int ifNull){
void sqlite3VdbeIntegerAffinity(Mem *pMem){ void sqlite3VdbeIntegerAffinity(Mem *pMem){
i64 ix; i64 ix;
assert( pMem->flags & MEM_Real ); assert( pMem->flags & MEM_Real );
assert( (pMem->flags & MEM_RowSet)==0 ); assert( !sqlite3VdbeMemIsRowSet(pMem) );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) );
@ -641,7 +637,7 @@ void sqlite3VdbeIntegerAffinity(Mem *pMem){
*/ */
int sqlite3VdbeMemIntegerify(Mem *pMem){ int sqlite3VdbeMemIntegerify(Mem *pMem){
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( (pMem->flags & MEM_RowSet)==0 ); assert( !sqlite3VdbeMemIsRowSet(pMem) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) );
pMem->u.i = sqlite3VdbeIntValue(pMem); pMem->u.i = sqlite3VdbeIntValue(pMem);
@ -859,26 +855,36 @@ void sqlite3VdbeMemSetDouble(Mem *pMem, double val){
} }
#endif #endif
#ifdef SQLITE_DEBUG
/*
** Return true if the Mem holds a RowSet object. This routine is intended
** for use inside of assert() statements.
*/
int sqlite3VdbeMemIsRowSet(const Mem *pMem){
return (pMem->flags&(MEM_Blob|MEM_Dyn))==(MEM_Blob|MEM_Dyn)
&& pMem->xDel==sqlite3RowSetDelete;
}
#endif
/* /*
** Delete any previous value and set the value of pMem to be an ** Delete any previous value and set the value of pMem to be an
** empty boolean index. ** empty boolean index.
**
** Return SQLITE_OK on success and SQLITE_NOMEM if a memory allocation
** error occurs.
*/ */
void sqlite3VdbeMemSetRowSet(Mem *pMem){ int sqlite3VdbeMemSetRowSet(Mem *pMem){
sqlite3 *db = pMem->db; sqlite3 *db = pMem->db;
RowSet *p;
assert( db!=0 ); assert( db!=0 );
assert( (pMem->flags & MEM_RowSet)==0 ); assert( !sqlite3VdbeMemIsRowSet(pMem) );
sqlite3VdbeMemRelease(pMem); sqlite3VdbeMemRelease(pMem);
pMem->zMalloc = sqlite3DbMallocRawNN(db, 64); p = sqlite3RowSetInit(db);
if( db->mallocFailed ){ if( p==0 ) return SQLITE_NOMEM;
pMem->flags = MEM_Null; pMem->z = (char*)p;
pMem->szMalloc = 0; pMem->flags = MEM_Blob|MEM_Dyn;
}else{ pMem->xDel = sqlite3RowSetDelete;
assert( pMem->zMalloc ); return SQLITE_OK;
pMem->szMalloc = sqlite3DbMallocSize(db, pMem->zMalloc);
pMem->u.pRowSet = sqlite3RowSetInit(db, pMem->zMalloc, pMem->szMalloc);
assert( pMem->u.pRowSet!=0 );
pMem->flags = MEM_RowSet;
}
} }
/* /*
@ -946,7 +952,7 @@ static SQLITE_NOINLINE void vdbeClrCopy(Mem *pTo, const Mem *pFrom, int eType){
sqlite3VdbeMemShallowCopy(pTo, pFrom, eType); sqlite3VdbeMemShallowCopy(pTo, pFrom, eType);
} }
void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){
assert( (pFrom->flags & MEM_RowSet)==0 ); assert( !sqlite3VdbeMemIsRowSet(pFrom) );
assert( pTo->db==pFrom->db ); assert( pTo->db==pFrom->db );
if( VdbeMemDynamic(pTo) ){ vdbeClrCopy(pTo,pFrom,srcType); return; } if( VdbeMemDynamic(pTo) ){ vdbeClrCopy(pTo,pFrom,srcType); return; }
memcpy(pTo, pFrom, MEMCELLSIZE); memcpy(pTo, pFrom, MEMCELLSIZE);
@ -964,7 +970,7 @@ void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){
int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
int rc = SQLITE_OK; int rc = SQLITE_OK;
assert( (pFrom->flags & MEM_RowSet)==0 ); assert( !sqlite3VdbeMemIsRowSet(pFrom) );
if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo); if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo);
memcpy(pTo, pFrom, MEMCELLSIZE); memcpy(pTo, pFrom, MEMCELLSIZE);
pTo->flags &= ~MEM_Dyn; pTo->flags &= ~MEM_Dyn;
@ -1022,7 +1028,7 @@ int sqlite3VdbeMemSetStr(
u16 flags = 0; /* New value for pMem->flags */ u16 flags = 0; /* New value for pMem->flags */
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( (pMem->flags & MEM_RowSet)==0 ); assert( !sqlite3VdbeMemIsRowSet(pMem) );
/* If z is a NULL pointer, set pMem to contain an SQL NULL. */ /* If z is a NULL pointer, set pMem to contain an SQL NULL. */
if( !z ){ if( !z ){
@ -1144,7 +1150,7 @@ int sqlite3VdbeMemFromBtree(
/* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert()
** that both the BtShared and database handle mutexes are held. */ ** that both the BtShared and database handle mutexes are held. */
assert( (pMem->flags & MEM_RowSet)==0 ); assert( !sqlite3VdbeMemIsRowSet(pMem) );
zData = (char *)sqlite3BtreePayloadFetch(pCur, &available); zData = (char *)sqlite3BtreePayloadFetch(pCur, &available);
assert( zData!=0 ); assert( zData!=0 );
@ -1168,7 +1174,7 @@ static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){
assert( pVal!=0 ); assert( pVal!=0 );
assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) );
assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) );
assert( (pVal->flags & MEM_RowSet)==0 ); assert( !sqlite3VdbeMemIsRowSet(pVal) );
assert( (pVal->flags & (MEM_Null))==0 ); assert( (pVal->flags & (MEM_Null))==0 );
if( pVal->flags & (MEM_Blob|MEM_Str) ){ if( pVal->flags & (MEM_Blob|MEM_Str) ){
if( ExpandBlob(pVal) ) return 0; if( ExpandBlob(pVal) ) return 0;
@ -1211,7 +1217,7 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
if( !pVal ) return 0; if( !pVal ) return 0;
assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) );
assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) );
assert( (pVal->flags & MEM_RowSet)==0 ); assert( !sqlite3VdbeMemIsRowSet(pVal) );
if( (pVal->flags&(MEM_Str|MEM_Term))==(MEM_Str|MEM_Term) && pVal->enc==enc ){ if( (pVal->flags&(MEM_Str|MEM_Term))==(MEM_Str|MEM_Term) && pVal->enc==enc ){
assert( sqlite3VdbeMemConsistentDualRep(pVal) ); assert( sqlite3VdbeMemConsistentDualRep(pVal) );
return pVal->z; return pVal->z;