Change the sqlite_stat2 schema to be more flexible.
FossilOrigin-Name: ded9dec6459baf21e01f63250db5ace57f390e7a
This commit is contained in:
parent
02fa469619
commit
e275dc3fb8
21
manifest
21
manifest
@ -1,5 +1,5 @@
|
||||
C First\sversion\sof\ssqlite_stat2\s(schema\sforces\sexactly\s10\ssamples).
|
||||
D 2009-08-17T17:06:59
|
||||
C Change\sthe\ssqlite_stat2\sschema\sto\sbe\smore\sflexible.
|
||||
D 2009-08-18T16:24:59
|
||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||
F Makefile.in 0f7761c5d1c62ae7a841e3393ffaff1fa0f5c00a
|
||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||
@ -100,7 +100,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
||||
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
|
||||
F src/alter.c 8b42cace4f8e312de596807ba2685179da64fec4
|
||||
F src/analyze.c c3f1ea347d5a2c90aec66a510e4c7b29d79fbca2
|
||||
F src/analyze.c 7f086e4da3db68c9fad2a4d61d90a62683084a57
|
||||
F src/attach.c 13995348fc5a26cdd136a50806faf292aabc173f
|
||||
F src/auth.c 802a9439dfa0b8c208b10055cba400e82ef18025
|
||||
F src/backup.c 6f1c2d9862c8a3feb7739dfcca02c1f5352e37f3
|
||||
@ -109,7 +109,7 @@ F src/btmutex.c 0f43a75bb5b8147b386e8e1c3e71ba734e3863b7
|
||||
F src/btree.c 49212ddaee8d7d12b4f1e17b9de62f7ea91ca59d
|
||||
F src/btree.h 577448a890c2ab9b21e6ab74f073526184bceebe
|
||||
F src/btreeInt.h 1c86297e69380f6577e7ae67452597dd8d5c2705
|
||||
F src/build.c 09389ab5d5a5997dbefa8f15fc4755f6c3243f4c
|
||||
F src/build.c 979b2aa9238531407ef7e64a56eed05d4c02b88d
|
||||
F src/callback.c cb68b21b0d4ae7d11ae0e487933bce3323784dcf
|
||||
F src/complete.c 5ad5c6cd4548211867c204c41a126d73a9fbcea0
|
||||
F src/date.c ab5f7137656652a48434d64f96bdcdc823bb23b3
|
||||
@ -163,7 +163,7 @@ F src/select.c 67b0778c9585905c8aa75aaa469e76ef3c1d315a
|
||||
F src/shell.c db2643650b9268df89a4bedca3f1c6d9e786f1bb
|
||||
F src/sqlite.h.in a6850e9034df1336e8139c4d6964d7d2f0f52337
|
||||
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
|
||||
F src/sqliteInt.h 21722d546c8a93bf079564d49e628d5e66d3244a
|
||||
F src/sqliteInt.h a11d40fc24390e5e0665cf8b1addbe162b9f76c3
|
||||
F src/sqliteLimit.h ffe93f5a0c4e7bd13e70cd7bf84cfb5c3465f45d
|
||||
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
|
||||
F src/table.c cc86ad3d6ad54df7c63a3e807b5783c90411a08d
|
||||
@ -204,7 +204,7 @@ F src/update.c 4da327f706c0d0dfedf4d92154b1b5688bdea0ac
|
||||
F src/utf.c 9b022ac1c1f306733d57daa0df0b8beb7c17e95e
|
||||
F src/util.c c2416f60ae704a8c4990e4909aa810f90cbffa07
|
||||
F src/vacuum.c 3fe0eebea6d2311c1c2ab2962887d11f7a4dcfb0
|
||||
F src/vdbe.c f2c07c6440826f69fc6d39083ac7fe5ba98fe3be
|
||||
F src/vdbe.c 464e2e30b1287554a23cdaa0b6b010a9dcb5eb29
|
||||
F src/vdbe.h 457b6c70f02885cec1f5225b5e6441d067b55d3f
|
||||
F src/vdbeInt.h 831c254a6eef237ef4664c8381a0137586567007
|
||||
F src/vdbeapi.c 0ab8ada7260b32031ca97f338caecf0812460624
|
||||
@ -213,7 +213,7 @@ F src/vdbeblob.c a3f3e0e877fc64ea50165eec2855f5ada4477611
|
||||
F src/vdbemem.c afd6ce02945e659f65642f290a37ccf4a88c4dcb
|
||||
F src/vtab.c aedd76e8670d5a5379f93804398d3ba960125547
|
||||
F src/walker.c 1edca756275f158b80f20eb6f104c8d3fcc96a04
|
||||
F src/where.c 33a3aa8bef9594002300b4bc9aa2a7b37c71345c
|
||||
F src/where.c 9d4c2f178f842c1ed18c068880f324479ea2cb38
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
F test/all.test 14165b3e32715b700b5f0cbf8f6e3833dda0be45
|
||||
@ -223,6 +223,7 @@ F test/alter3.test 25b95a136708f22b87184fa6a4309eea03d65153
|
||||
F test/alter4.test 9386ffd1e9c7245f43eca412b2058d747509cc1f
|
||||
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
|
||||
F test/analyze.test ad5329098fe4de4a96852231d53e3e9e6283ad4b
|
||||
F test/analyze2.test 30987f595f9e34b95bae81794e99b5ca2be7e46c
|
||||
F test/async.test 8c75d31b8330f8b70cf2571b014d4476a063efdb
|
||||
F test/async2.test bf5e2ca2c96763b4cba3d016249ad7259a5603b6
|
||||
F test/async3.test 93edaa9122f498e56ea98c36c72abc407f4fb11e
|
||||
@ -743,7 +744,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl 672f81d693a03f80f5ae60bfefacd8a349e76746
|
||||
P 0d5b058717858c9cda8ca120a3d814453a94a0e6
|
||||
R 942eb5447bdff248ec9f0cbf9f54bb64
|
||||
P dd96bda2a85c1d94fb4a0bf5f27e2977f7f7e42e
|
||||
R 3ad6c851396bbe27ea036387da51f58c
|
||||
U dan
|
||||
Z d16a7c84025a55a7e2426c9a05cd868d
|
||||
Z ea071f69e4d6383649120789bd868cdf
|
||||
|
@ -1 +1 @@
|
||||
dd96bda2a85c1d94fb4a0bf5f27e2977f7f7e42e
|
||||
ded9dec6459baf21e01f63250db5ace57f390e7a
|
266
src/analyze.c
266
src/analyze.c
@ -32,7 +32,7 @@ static void openStatTable(
|
||||
const char *zWhere /* Delete entries associated with this table */
|
||||
){
|
||||
const char *aName[] = { "sqlite_stat1", "sqlite_stat2" };
|
||||
const char *aCols[] = { "tbl,idx,stat", "tbl,idx," SQLITE_INDEX_SAMPLE_COLS };
|
||||
const char *aCols[] = { "tbl,idx,stat", "tbl,idx,sampleno,sample" };
|
||||
int aRoot[] = {0, 0};
|
||||
int aCreateTbl[] = {0, 0};
|
||||
|
||||
@ -94,7 +94,6 @@ static void analyzeOneTable(
|
||||
){
|
||||
Index *pIdx; /* An index to being analyzed */
|
||||
int iIdxCur; /* Index of VdbeCursor for index being analyzed */
|
||||
int nCol; /* Number of columns in the index */
|
||||
Vdbe *v; /* The virtual machine being built up */
|
||||
int i; /* Loop counter */
|
||||
int topOfLoop; /* The top of the loop */
|
||||
@ -102,6 +101,21 @@ static void analyzeOneTable(
|
||||
int addr; /* The address of an instruction */
|
||||
int iDb; /* Index of database containing pTab */
|
||||
|
||||
|
||||
/* Assign the required registers. */
|
||||
int regTabname = iMem++; /* Register containing table name */
|
||||
int regIdxname = iMem++; /* Register containing index name */
|
||||
int regSampleno = iMem++; /* Register containing next sample number */
|
||||
int regCol = iMem++; /* Content of a column analyzed table */
|
||||
|
||||
int regSamplerecno = iMem++; /* Next sample index record number */
|
||||
int regRecno = iMem++; /* Register next index record number */
|
||||
int regRec = iMem++; /* Register holding completed record */
|
||||
int regTemp = iMem++; /* Temporary use register */
|
||||
int regTemp2 = iMem++; /* Temporary use register */
|
||||
int regRowid = iMem++; /* Rowid for the inserted record */
|
||||
int regCount = iMem++; /* Total number of records in table */
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 || NEVER(pTab==0) || pTab->pIndex==0 ){
|
||||
/* Do no analysis for tables that have no indices */
|
||||
@ -120,39 +134,43 @@ static void analyzeOneTable(
|
||||
/* Establish a read-lock on the table at the shared-cache level. */
|
||||
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
||||
|
||||
iMem += 3;
|
||||
iIdxCur = pParse->nTab++;
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
int nCol = pIdx->nColumn;
|
||||
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
|
||||
int regFields; /* Register block for building records */
|
||||
int regRec; /* Register holding completed record */
|
||||
int regTemp; /* Temporary use register */
|
||||
int regCol; /* Content of a column from the table being analyzed */
|
||||
int regRowid; /* Rowid for the inserted record */
|
||||
int regF2;
|
||||
int regStat2;
|
||||
|
||||
/* Open a cursor to the index to be analyzed
|
||||
*/
|
||||
if( iMem+1+(nCol*2)>pParse->nMem ){
|
||||
pParse->nMem = iMem+1+(nCol*2);
|
||||
}
|
||||
|
||||
/* Open a cursor to the index to be analyzed. */
|
||||
assert( iDb==sqlite3SchemaToIndex(pParse->db, pIdx->pSchema) );
|
||||
nCol = pIdx->nColumn;
|
||||
sqlite3VdbeAddOp4(v, OP_OpenRead, iIdxCur, pIdx->tnum, iDb,
|
||||
(char *)pKey, P4_KEYINFO_HANDOFF);
|
||||
VdbeComment((v, "%s", pIdx->zName));
|
||||
regStat2 = iMem+nCol*2+1;
|
||||
regFields = regStat2+2+SQLITE_INDEX_SAMPLES;
|
||||
regTemp = regRowid = regCol = regFields+3;
|
||||
regRec = regCol+1;
|
||||
if( regRec>pParse->nMem ){
|
||||
pParse->nMem = regRec;
|
||||
}
|
||||
|
||||
/* Fill in the register with the total number of rows. */
|
||||
/* If this iteration of the loop is generating code to analyze the
|
||||
** first index in the pTab->pIndex list, then register regCount has
|
||||
** not been populated. In this case populate it now. */
|
||||
if( pTab->pIndex==pIdx ){
|
||||
sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, iMem-3);
|
||||
sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regCount);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, iMem-2);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, iMem-1);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, regIdxname, 0, pIdx->zName, 0);
|
||||
|
||||
/* Zero the regSampleno and regRecno registers. */
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regSampleno);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regRecno);
|
||||
|
||||
/* If there are less than INDEX_SAMPLES records in the index, then
|
||||
** set the contents of regSampleRecno to integer value INDEX_SAMPLES.
|
||||
** Otherwise, set it to zero. This is to ensure that if there are
|
||||
** less than the said number of entries in the index, no samples at
|
||||
** all are collected. */
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_INDEX_SAMPLES, regSamplerecno);
|
||||
sqlite3VdbeAddOp3(v, OP_Lt, regSamplerecno, sqlite3VdbeCurrentAddr(v)+2,
|
||||
regCount);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regSamplerecno);
|
||||
|
||||
/* Memory cells are used as follows. All memory cell addresses are
|
||||
** offset by iMem. That is, cell 0 below is actually cell iMem, cell
|
||||
@ -167,8 +185,6 @@ static void analyzeOneTable(
|
||||
** nCol+1..2*nCol: Previous value of indexed columns, from left to
|
||||
** right.
|
||||
**
|
||||
** 2*nCol+1..2*nCol+10: 10 evenly spaced samples.
|
||||
**
|
||||
** Cells iMem through iMem+nCol are initialized to 0. The others
|
||||
** are initialized to NULL.
|
||||
*/
|
||||
@ -179,7 +195,7 @@ static void analyzeOneTable(
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, iMem+nCol+i+1);
|
||||
}
|
||||
|
||||
/* Start the analysis loop. This loop runs through all the entries inof
|
||||
/* Start the analysis loop. This loop runs through all the entries in
|
||||
** the index b-tree. */
|
||||
endOfLoop = sqlite3VdbeMakeLabel(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, iIdxCur, endOfLoop);
|
||||
@ -189,15 +205,45 @@ static void analyzeOneTable(
|
||||
for(i=0; i<nCol; i++){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regCol);
|
||||
if( i==0 ){
|
||||
sqlite3VdbeAddOp3(v, OP_Sample, iMem-3, regCol, regStat2+2);
|
||||
|
||||
/* Check if the record that cursor iIdxCur points to contains a
|
||||
** value that should be stored in the sqlite_stat2 table. If so,
|
||||
** store it. */
|
||||
int ne = sqlite3VdbeAddOp3(v, OP_Ne, regRecno, 0, regSamplerecno);
|
||||
assert( regTabname+1==regIdxname
|
||||
&& regTabname+2==regSampleno
|
||||
&& regTabname+3==regCol
|
||||
);
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 4, regRec, "aaab", 0);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur+1, regRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur+1, regRec, regRowid);
|
||||
|
||||
/* Calculate new values for regSamplerecno and regSampleno.
|
||||
**
|
||||
** sampleno = sampleno + 1
|
||||
** samplerecno = samplerecno+(remaining records)/(remaining samples)
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, regSampleno, 1);
|
||||
sqlite3VdbeAddOp3(v, OP_Subtract, regRecno, regCount, regTemp);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, regTemp, -1);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_INDEX_SAMPLES, regTemp2);
|
||||
sqlite3VdbeAddOp3(v, OP_Subtract, regSampleno, regTemp2, regTemp2);
|
||||
sqlite3VdbeAddOp3(v, OP_Divide, regTemp2, regTemp, regTemp);
|
||||
sqlite3VdbeAddOp3(v, OP_Add, regSamplerecno, regTemp, regSamplerecno);
|
||||
|
||||
sqlite3VdbeJumpHere(v, ne);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, regRecno, 1);
|
||||
}
|
||||
|
||||
assert( sqlite3VdbeCurrentAddr(v)==(topOfLoop+14+2*i) );
|
||||
sqlite3VdbeAddOp3(v, OP_Ne, regCol, 0, iMem+nCol+i+1);
|
||||
|
||||
/**** TODO: add collating sequence *****/
|
||||
sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, endOfLoop);
|
||||
for(i=0; i<nCol; i++){
|
||||
sqlite3VdbeJumpHere(v, topOfLoop + 1 + 2*(i + 1));
|
||||
sqlite3VdbeJumpHere(v, topOfLoop+14+2*i);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, iMem+i+1, 1);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, iMem+nCol+i+1);
|
||||
}
|
||||
@ -226,33 +272,20 @@ static void analyzeOneTable(
|
||||
** is never possible.
|
||||
*/
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IfNot, iMem);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, regFields, 0, pTab->zName, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, regFields+1, 0, pIdx->zName, 0);
|
||||
regF2 = regFields+2;
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, iMem, regF2);
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, iMem, regSampleno);
|
||||
for(i=0; i<nCol; i++){
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, regTemp, 0, " ", 0);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regF2, regF2);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regSampleno, regSampleno);
|
||||
sqlite3VdbeAddOp3(v, OP_Add, iMem, iMem+i+1, regTemp);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, regTemp, -1);
|
||||
sqlite3VdbeAddOp3(v, OP_Divide, iMem+i+1, regTemp, regTemp);
|
||||
sqlite3VdbeAddOp1(v, OP_ToInt, regTemp);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regF2, regF2);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regSampleno, regSampleno);
|
||||
}
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regFields, 3, regRec, "aaa", 0);
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regRowid);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
||||
|
||||
/* Store the results in sqlite_stat2. */
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, regStat2, 0, pTab->zName, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, regStat2+1, 0, pIdx->zName, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regStat2, SQLITE_INDEX_SAMPLES+2,
|
||||
regRec, "aabbbbbbbbbb", 0
|
||||
);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur+1, regRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur+1, regRec, regRowid);
|
||||
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
}
|
||||
@ -461,85 +494,80 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
|
||||
sqlite3DbFree(db, zSql);
|
||||
}
|
||||
|
||||
/* Load the statistics from the sqlite_stat2 table */
|
||||
/* Load the statistics from the sqlite_stat2 table. */
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
|
||||
zSql = sqlite3MPrintf(db,
|
||||
"SELECT idx," SQLITE_INDEX_SAMPLE_COLS " FROM %Q.sqlite_stat2",
|
||||
sInfo.zDatabase
|
||||
"SELECT idx,sampleno,sample FROM %Q.sqlite_stat2", sInfo.zDatabase
|
||||
);
|
||||
if( zSql ){
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
(void)sqlite3SafetyOff(db);
|
||||
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
char *zIndex = (char *)sqlite3_column_text(pStmt, 0);
|
||||
Index *pIdx;
|
||||
pIdx = sqlite3FindIndex(db, zIndex, sInfo.zDatabase);
|
||||
if( pIdx ){
|
||||
char *pSpace;
|
||||
IndexSample *pSample;
|
||||
int iCol;
|
||||
int nAlloc = SQLITE_INDEX_SAMPLES * sizeof(IndexSample);
|
||||
for(iCol=1; iCol<=SQLITE_INDEX_SAMPLES; iCol++){
|
||||
int eType = sqlite3_column_type(pStmt, iCol);
|
||||
if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
|
||||
nAlloc += sqlite3_column_bytes(pStmt, iCol);
|
||||
}
|
||||
}
|
||||
pSample = sqlite3DbMallocRaw(db, nAlloc);
|
||||
if( !pSample ){
|
||||
rc = SQLITE_NOMEM;
|
||||
break;
|
||||
}
|
||||
sqlite3DbFree(db, pIdx->aSample);
|
||||
pIdx->aSample = pSample;
|
||||
pSpace = (char *)&pSample[SQLITE_INDEX_SAMPLES];
|
||||
for(iCol=1; iCol<=SQLITE_INDEX_SAMPLES; iCol++){
|
||||
int eType = sqlite3_column_type(pStmt, iCol);
|
||||
pSample[iCol-1].eType = eType;
|
||||
switch( eType ){
|
||||
case SQLITE_BLOB:
|
||||
case SQLITE_TEXT: {
|
||||
const char *z = (const char *)(
|
||||
(eType==SQLITE_BLOB) ?
|
||||
sqlite3_column_blob(pStmt, iCol):
|
||||
sqlite3_column_text(pStmt, iCol)
|
||||
);
|
||||
int n = sqlite3_column_bytes(pStmt, iCol);
|
||||
if( n>24 ){
|
||||
n = 24;
|
||||
}
|
||||
pSample[iCol-1].nByte = n;
|
||||
pSample[iCol-1].u.z = pSpace;
|
||||
memcpy(pSpace, z, n);
|
||||
pSpace += n;
|
||||
break;
|
||||
}
|
||||
case SQLITE_INTEGER:
|
||||
case SQLITE_FLOAT:
|
||||
pSample[iCol-1].u.r = sqlite3_column_double(pStmt, iCol);
|
||||
break;
|
||||
case SQLITE_NULL:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
sqlite3_finalize(pStmt);
|
||||
}else{
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
}
|
||||
}
|
||||
(void)sqlite3SafetyOn(db);
|
||||
sqlite3DbFree(db, zSql);
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
if( !zSql ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
(void)sqlite3SafetyOff(db);
|
||||
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
|
||||
assert( rc!=SQLITE_MISUSE );
|
||||
(void)sqlite3SafetyOn(db);
|
||||
sqlite3DbFree(db, zSql);
|
||||
(void)sqlite3SafetyOff(db);
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
char *zIndex = (char *)sqlite3_column_text(pStmt, 0);
|
||||
Index *pIdx = sqlite3FindIndex(db, zIndex, sInfo.zDatabase);
|
||||
if( pIdx ){
|
||||
int iSample = sqlite3_column_int(pStmt, 1);
|
||||
if( iSample<SQLITE_INDEX_SAMPLES && iSample>=0 ){
|
||||
int eType = sqlite3_column_type(pStmt, 2);
|
||||
|
||||
if( pIdx->aSample==0 ){
|
||||
pIdx->aSample = (IndexSample *)sqlite3DbMallocZero(db,
|
||||
sizeof(IndexSample)*SQLITE_INDEX_SAMPLES
|
||||
);
|
||||
if( pIdx->aSample==0 ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( pIdx->aSample ){
|
||||
IndexSample *pSample = &pIdx->aSample[iSample];
|
||||
if( pSample->eType==SQLITE_TEXT || pSample->eType==SQLITE_BLOB ){
|
||||
sqlite3DbFree(db, pSample->u.z);
|
||||
}
|
||||
pSample->eType = eType;
|
||||
if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
|
||||
pSample->u.r = sqlite3_column_double(pStmt, 2);
|
||||
}else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
|
||||
const char *z = (const char *)(
|
||||
(eType==SQLITE_BLOB) ?
|
||||
sqlite3_column_blob(pStmt, 2):
|
||||
sqlite3_column_text(pStmt, 2)
|
||||
);
|
||||
int n = sqlite3_column_bytes(pStmt, 2);
|
||||
if( n>24 ){
|
||||
n = 24;
|
||||
}
|
||||
pSample->nByte = n;
|
||||
pSample->u.z = sqlite3DbMallocRaw(db, n);
|
||||
if( pSample->u.z ){
|
||||
memcpy(pSample->u.z, z, n);
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
}
|
||||
(void)sqlite3SafetyOn(db);
|
||||
}
|
||||
|
||||
if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -343,6 +343,15 @@ Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
|
||||
static void freeIndex(Index *p){
|
||||
sqlite3 *db = p->pTable->dbMem;
|
||||
/* testcase( db==0 ); */
|
||||
if( p->aSample ){
|
||||
int i;
|
||||
for(i=0; i<SQLITE_INDEX_SAMPLES; i++){
|
||||
int e = p->aSample[i].eType;
|
||||
if( e==SQLITE_BLOB || e==SQLITE_TEXT ){
|
||||
sqlite3DbFree(db, p->aSample[i].u.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3DbFree(db, p->aSample);
|
||||
sqlite3DbFree(db, p->zColAff);
|
||||
sqlite3DbFree(db, p);
|
||||
|
@ -78,7 +78,6 @@
|
||||
#endif
|
||||
|
||||
#define SQLITE_INDEX_SAMPLES 10
|
||||
#define SQLITE_INDEX_SAMPLE_COLS "s1,s2,s3,s4,s5,s6,s7,s8,s9,s10"
|
||||
|
||||
/*
|
||||
** This macro is used to "hide" some ugliness in casting an int
|
||||
|
49
src/vdbe.c
49
src/vdbe.c
@ -1205,9 +1205,9 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */
|
||||
/* Opcode: Divide P1 P2 P3 * *
|
||||
**
|
||||
** Divide the value in register P1 by the value in register P2
|
||||
** and store the result in register P3. If the value in register P2
|
||||
** is zero, then the result is NULL.
|
||||
** If either input is NULL, the result is NULL.
|
||||
** and store the result in register P3 (P3=P2/P1). If the value in
|
||||
** register P1 is zero, then the result is NULL. If either input is
|
||||
** NULL, the result is NULL.
|
||||
*/
|
||||
/* Opcode: Remainder P1 P2 P3 * *
|
||||
**
|
||||
@ -4974,49 +4974,6 @@ case OP_Expire: {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* Opcode: Sample P1 P2 P3 * *
|
||||
**
|
||||
** Register P1 contains the total number of rows in the index being
|
||||
** analyzed. Register P1+1 contains an integer between 0 and 9, the
|
||||
** index of the next sample required. Register P1+2 contains an index
|
||||
** between 1 and *P1, the number of the next sample required. Register
|
||||
** P1+3 contains the current row index.
|
||||
**
|
||||
** If the integer in register P1+3 is the same as the integer in register
|
||||
** P1+1, then the following takes place:
|
||||
**
|
||||
** (a) the contents of register P1+1 is incremented.
|
||||
**
|
||||
** (b) the contents of the register identified by parameter P2 is
|
||||
** copied to register number (P3 + X), where X is the newly
|
||||
** incremented value of register P1+1.
|
||||
**
|
||||
** (c) register P1+2 is set to the index of the next sample required.
|
||||
*/
|
||||
case OP_Sample: {
|
||||
int p1 = pOp->p1;
|
||||
i64 iReq = p->aMem[p1+2].u.i;
|
||||
i64 iRow = p->aMem[p1+3].u.i;
|
||||
|
||||
while( iReq==iRow ){
|
||||
i64 nRow = p->aMem[p1].u.i;
|
||||
int iSample = ++p->aMem[p1+1].u.i;
|
||||
Mem *pReg = &p->aMem[pOp->p3 + iSample - 1];
|
||||
|
||||
assert( pReg<&p->aMem[p->nMem] );
|
||||
sqlite3VdbeMemShallowCopy(pReg, &p->aMem[pOp->p2], MEM_Ephem);
|
||||
Deephemeralize(pReg);
|
||||
if( iSample==SQLITE_INDEX_SAMPLES ){
|
||||
iReq = 0;
|
||||
}else{
|
||||
iReq = iRow + (nRow-iRow)/(SQLITE_INDEX_SAMPLES - iSample);
|
||||
p->aMem[p1+2].u.i = iReq;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
/* Opcode: TableLock P1 P2 P3 P4 *
|
||||
**
|
||||
|
40
src/where.c
40
src/where.c
@ -1929,40 +1929,40 @@ static int whereRangeRegion(
|
||||
if( eType==SQLITE_BLOB ){
|
||||
z = (const u8 *)sqlite3_value_blob(pVal);
|
||||
pColl = db->pDfltColl;
|
||||
assert( pColl->enc==SQLITE_UTF8 );
|
||||
assert( pColl->enc==SQLITE_UTF8 );
|
||||
}else{
|
||||
pColl = sqlite3FindCollSeq(db, SQLITE_UTF8, *pIdx->azColl, 0);
|
||||
if( sqlite3CheckCollSeq(pParse, pColl) ){
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
pColl = sqlite3FindCollSeq(db, SQLITE_UTF8, *pIdx->azColl, 0);
|
||||
if( sqlite3CheckCollSeq(pParse, pColl) ){
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
z = (const u8 *)sqlite3ValueText(pVal, pColl->enc);
|
||||
if( !z ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
if( !z ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
assert( z && pColl && pColl->xCmp );
|
||||
}
|
||||
n = sqlite3ValueBytes(pVal, pColl->enc);
|
||||
|
||||
for(i=0; i<SQLITE_INDEX_SAMPLES; i++){
|
||||
int r;
|
||||
int r;
|
||||
int eSampletype = aSample[i].eType;
|
||||
if( eSampletype==SQLITE_NULL || eSampletype<eType ) continue;
|
||||
if( (eSampletype!=eType) ) break;
|
||||
if( pColl->enc==SQLITE_UTF8 ){
|
||||
r = pColl->xCmp(pColl->pUser, aSample[i].nByte, aSample[i].u.z, n, z);
|
||||
r = pColl->xCmp(pColl->pUser, aSample[i].nByte, aSample[i].u.z, n, z);
|
||||
}else{
|
||||
int nSample;
|
||||
char *zSample = sqlite3Utf8to16(
|
||||
int nSample;
|
||||
char *zSample = sqlite3Utf8to16(
|
||||
db, pColl->enc, aSample[i].u.z, aSample[i].nByte, &nSample
|
||||
);
|
||||
if( !zSample ){
|
||||
assert( db->mallocFailed );
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
r = pColl->xCmp(pColl->pUser, nSample, zSample, n, z);
|
||||
sqlite3DbFree(db, zSample);
|
||||
if( !zSample ){
|
||||
assert( db->mallocFailed );
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
r = pColl->xCmp(pColl->pUser, nSample, zSample, n, z);
|
||||
sqlite3DbFree(db, zSample);
|
||||
}
|
||||
if( r>0 ) break;
|
||||
if( r>0 ) break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2246,7 +2246,7 @@ static void bestBtreeIndex(
|
||||
if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){
|
||||
WhereTerm *pTop = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pIdx);
|
||||
WhereTerm *pBtm = findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pIdx);
|
||||
whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &nBound);
|
||||
whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &nBound);
|
||||
if( pTop ){
|
||||
wsFlags |= WHERE_TOP_LIMIT;
|
||||
used |= pTop->prereqRight;
|
||||
|
247
test/analyze2.test
Normal file
247
test/analyze2.test
Normal file
@ -0,0 +1,247 @@
|
||||
# 2009 August 06
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# $Id: analyze.test,v 1.9 2008/08/11 18:44:58 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
sqlite3_db_config_lookaside db 0 0 0
|
||||
|
||||
do_test analyze2-0.1 {
|
||||
execsql { CREATE TABLE t1(x PRIMARY KEY) }
|
||||
for {set i 0} {$i < 1000} {incr i} {
|
||||
execsql { INSERT INTO t1 VALUES($i) }
|
||||
}
|
||||
execsql {
|
||||
ANALYZE;
|
||||
SELECT * FROM sqlite_stat2;
|
||||
}
|
||||
} [list t1 sqlite_autoindex_t1_1 0 0 \
|
||||
t1 sqlite_autoindex_t1_1 1 111 \
|
||||
t1 sqlite_autoindex_t1_1 2 222 \
|
||||
t1 sqlite_autoindex_t1_1 3 333 \
|
||||
t1 sqlite_autoindex_t1_1 4 444 \
|
||||
t1 sqlite_autoindex_t1_1 5 555 \
|
||||
t1 sqlite_autoindex_t1_1 6 666 \
|
||||
t1 sqlite_autoindex_t1_1 7 777 \
|
||||
t1 sqlite_autoindex_t1_1 8 888 \
|
||||
t1 sqlite_autoindex_t1_1 9 999 \
|
||||
]
|
||||
|
||||
do_test analyze2-0.2 {
|
||||
execsql {
|
||||
DELETE FROM t1 WHERe x>9;
|
||||
ANALYZE;
|
||||
SELECT tbl, idx, group_concat(sample, ' ') FROM sqlite_stat2;
|
||||
}
|
||||
} {t1 sqlite_autoindex_t1_1 {0 1 2 3 4 5 6 7 8 9}}
|
||||
|
||||
do_test analyze2-0.3 {
|
||||
execsql {
|
||||
DELETE FROM t1 WHERE x>5;
|
||||
ANALYZE;
|
||||
SELECT * FROM sqlite_stat2;
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test analyze2-0.4 {
|
||||
execsql {
|
||||
DELETE FROM t1;
|
||||
ANALYZE;
|
||||
SELECT * FROM sqlite_stat2;
|
||||
}
|
||||
} {}
|
||||
|
||||
proc eqp sql {
|
||||
uplevel execsql [list "EXPLAIN QUERY PLAN $sql"]
|
||||
}
|
||||
|
||||
do_test analyze2-1.1 {
|
||||
execsql {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(x, y);
|
||||
CREATE INDEX t1_x ON t1(x);
|
||||
CREATE INDEX t1_y ON t1(y);
|
||||
}
|
||||
|
||||
for {set i 0} {$i < 1000} {incr i} {
|
||||
execsql { INSERT INTO t1 VALUES($i, $i) }
|
||||
}
|
||||
execsql ANALYZE
|
||||
} {}
|
||||
do_test analyze2-1.2 {
|
||||
execsql { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE x>500 AND y>700 }
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_y}}
|
||||
|
||||
do_test analyze2-1.3 {
|
||||
execsql { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE x>700 AND y>500 }
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_x}}
|
||||
|
||||
do_test analyze2-1.3 {
|
||||
execsql { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE y>700 AND x>500 }
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_y}}
|
||||
do_test analyze2-1.4 {
|
||||
execsql { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE y>500 AND x>700 }
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_x}}
|
||||
|
||||
do_test analyze2-2.1 {
|
||||
eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 200 AND y BETWEEN 400 AND 700"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_x}}
|
||||
do_test analyze2-2.2 {
|
||||
eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 500 AND y BETWEEN 400 AND 700"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_y}}
|
||||
do_test analyze2-2.3 {
|
||||
eqp "SELECT * FROM t1 WHERE x BETWEEN -400 AND -300 AND y BETWEEN 100 AND 300"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_x}}
|
||||
do_test analyze2-2.4 {
|
||||
eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 300 AND y BETWEEN -400 AND -300"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_y}}
|
||||
|
||||
do_test analyze2-3.1 {
|
||||
eqp "SELECT * FROM t1 WHERE x BETWEEN 500 AND 100 AND y BETWEEN 100 AND 300"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_x}}
|
||||
do_test analyze2-3.2 {
|
||||
eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 300 AND y BETWEEN 500 AND 100"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_y}}
|
||||
|
||||
do_test analyze2-4.1 {
|
||||
set alphabet [list a b c d e f g h i j]
|
||||
for {set i 0} {$i < 1000} {incr i} {
|
||||
set str [lindex $alphabet [expr ($i/100)%10]]
|
||||
append str [lindex $alphabet [expr ($i/ 10)%10]]
|
||||
append str [lindex $alphabet [expr ($i/ 1)%10]]
|
||||
execsql { INSERT INTO t1 VALUES($str, $str) }
|
||||
}
|
||||
execsql ANALYZE
|
||||
execsql {
|
||||
SELECT tbl,idx,group_concat(sample,' ')
|
||||
FROM sqlite_stat2
|
||||
WHERE idx = 't1_x'
|
||||
GROUP BY tbl,idx
|
||||
}
|
||||
} {t1 t1_x {0 222 444 666 888 bba ddc ffe hhg jjj}}
|
||||
do_test analyze2-4.2 {
|
||||
execsql {
|
||||
SELECT tbl,idx,group_concat(sample,' ')
|
||||
FROM sqlite_stat2
|
||||
WHERE idx = 't1_y'
|
||||
GROUP BY tbl,idx
|
||||
}
|
||||
} {t1 t1_y {0 222 444 666 888 bba ddc ffe hhg jjj}}
|
||||
|
||||
do_test analyze2-4.3 {
|
||||
eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 500 AND y BETWEEN 'a' AND 'b'"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_y}}
|
||||
do_test analyze2-4.4 {
|
||||
eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 400 AND y BETWEEN 'a' AND 'h'"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_x}}
|
||||
do_test analyze2-4.5 {
|
||||
eqp "SELECT * FROM t1 WHERE x<'a' AND y>'h'"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_y}}
|
||||
do_test analyze2-4.6 {
|
||||
eqp "SELECT * FROM t1 WHERE x<444 AND y>'h'"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_y}}
|
||||
do_test analyze2-4.7 {
|
||||
eqp "SELECT * FROM t1 WHERE x<221 AND y>'h'"
|
||||
} {0 0 {TABLE t1 WITH INDEX t1_x}}
|
||||
|
||||
do_test analyze2-5.1 {
|
||||
execsql { CREATE TABLE t3(a COLLATE nocase, b) }
|
||||
execsql { CREATE INDEX t3a ON t3(a) }
|
||||
execsql { CREATE INDEX t3b ON t3(b) }
|
||||
set alphabet [list A b C d E f G h I j]
|
||||
for {set i 0} {$i < 1000} {incr i} {
|
||||
set str [lindex $alphabet [expr ($i/100)%10]]
|
||||
append str [lindex $alphabet [expr ($i/ 10)%10]]
|
||||
append str [lindex $alphabet [expr ($i/ 1)%10]]
|
||||
execsql { INSERT INTO t3 VALUES($str, $str) }
|
||||
}
|
||||
execsql ANALYZE
|
||||
} {}
|
||||
do_test analyze2-5.2 {
|
||||
execsql {
|
||||
SELECT tbl,idx,group_concat(sample,' ')
|
||||
FROM sqlite_stat2
|
||||
WHERE idx = 't3a'
|
||||
GROUP BY tbl,idx
|
||||
}
|
||||
} {t3 t3a {AAA bbb CCC ddd EEE fff GGG hhh III jjj}}
|
||||
do_test analyze2-5.3 {
|
||||
execsql {
|
||||
SELECT tbl,idx,group_concat(sample,' ')
|
||||
FROM sqlite_stat2
|
||||
WHERE idx = 't3b'
|
||||
GROUP BY tbl,idx
|
||||
}
|
||||
} {t3 t3b {AAA CCC EEE GGG III bbb ddd fff hhh jjj}}
|
||||
|
||||
do_test analyze2-5.4 {
|
||||
eqp "SELECT * FROM t3 WHERE a > 'A' AND a < 'C' AND b > 'A' AND b < 'C'"
|
||||
} {0 0 {TABLE t3 WITH INDEX t3b}}
|
||||
do_test analyze2-5.5 {
|
||||
eqp "SELECT * FROM t3 WHERE a > 'A' AND a < 'c' AND b > 'A' AND b < 'c'"
|
||||
} {0 0 {TABLE t3 WITH INDEX t3a}}
|
||||
|
||||
proc test_collate {enc lhs rhs} {
|
||||
# puts $enc
|
||||
return [string compare $lhs $rhs]
|
||||
}
|
||||
|
||||
do_test analyze2-6.1 {
|
||||
add_test_collate db 0 0 1
|
||||
execsql { CREATE TABLE t4(x COLLATE test_collate) }
|
||||
execsql { CREATE INDEX t4x ON t4(x) }
|
||||
set alphabet [list a b c d e f g h i j]
|
||||
for {set i 0} {$i < 1000} {incr i} {
|
||||
set str [lindex $alphabet [expr ($i/100)%10]]
|
||||
append str [lindex $alphabet [expr ($i/ 10)%10]]
|
||||
append str [lindex $alphabet [expr ($i/ 1)%10]]
|
||||
execsql { INSERT INTO t4 VALUES($str) }
|
||||
}
|
||||
execsql ANALYZE
|
||||
} {}
|
||||
do_test analyze2-6.2 {
|
||||
execsql {
|
||||
SELECT tbl,idx,group_concat(sample,' ')
|
||||
FROM sqlite_stat2
|
||||
WHERE tbl = 't4'
|
||||
GROUP BY tbl,idx
|
||||
}
|
||||
} {t4 t4x {aaa bbb ccc ddd eee fff ggg hhh iii jjj}}
|
||||
do_test analyze2-6.3 {
|
||||
eqp "SELECT * FROM t4 WHERE x>'ccc'"
|
||||
} {0 0 {TABLE t4 WITH INDEX t4x}}
|
||||
do_test analyze2-6.4 {
|
||||
eqp "SELECT * FROM t4 AS t41, t4 AS t42 WHERE t41.x>'ccc' AND t42.x>'ggg'"
|
||||
} {0 1 {TABLE t4 AS t42 WITH INDEX t4x} 1 0 {TABLE t4 AS t41 WITH INDEX t4x}}
|
||||
do_test analyze2-6.5 {
|
||||
eqp "SELECT * FROM t4 AS t41, t4 AS t42 WHERE t41.x>'ddd' AND t42.x>'ccc'"
|
||||
} {0 0 {TABLE t4 AS t41 WITH INDEX t4x} 1 1 {TABLE t4 AS t42 WITH INDEX t4x}}
|
||||
|
||||
ifcapable memdebug {
|
||||
execsql { DELETE FROM t4 }
|
||||
db close
|
||||
source $testdir/malloc_common.tcl
|
||||
file copy -force test.db bak.db
|
||||
|
||||
do_malloc_test analyze2-oom -tclprep {
|
||||
db close
|
||||
file copy -force bak.db test.db
|
||||
sqlite3 db test.db
|
||||
sqlite3_db_config_lookaside db 0 0 0
|
||||
add_test_collate db 0 0 1
|
||||
} -sqlbody {
|
||||
SELECT * FROM t4 AS t41, t4 AS t42 WHERE t41.x>'ddd' AND t42.x>'ccc'
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
Loading…
x
Reference in New Issue
Block a user