Re-enable reading from the sqlite_stat3 table (as well as sqlite_stat4).
FossilOrigin-Name: 6d45078e621526fc2bac0eaefbb0f9602b9a8ec5
This commit is contained in:
parent
5133c78cae
commit
0106e378f1
21
manifest
21
manifest
@ -1,5 +1,5 @@
|
||||
C Fix\sa\sbug\sin\scalculating\sthe\saverage\snumber\sof\sentries\sfor\skeys\snot\spresent\sin\sthe\ssqlite_stat4\stable.
|
||||
D 2013-08-12T11:21:10.969
|
||||
C Re-enable\sreading\sfrom\sthe\ssqlite_stat3\stable\s(as\swell\sas\ssqlite_stat4).
|
||||
D 2013-08-12T16:34:32.514
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -157,7 +157,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
||||
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
|
||||
F src/alter.c 2af0330bb1b601af7a7789bf7229675fd772a083
|
||||
F src/analyze.c fd1bcb9bc4ca29cd36f60c620cc501c933048c28
|
||||
F src/analyze.c e5ce42f04f58003fa45908791a5ad06bdd2c2ff1
|
||||
F src/attach.c 1816f5a9eea8d2010fc2b22b44f0f63eb3a62704
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c 43b348822db3e4cef48b2ae5a445fbeb6c73a165
|
||||
@ -175,7 +175,7 @@ F src/delete.c 2317c814866d9aa71fea16b3faf4fdd4d6a49b94
|
||||
F src/expr.c 0bbb44462a19169189b2709fbbd800950521b5ae
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 914a6bbd987d857c41ac9d244efa6641f36faadb
|
||||
F src/func.c 5c50c1ea31fd864b0fe921fe1a8d4c55acd609ef
|
||||
F src/func.c 78c371ddfb0bb2d4c4356e8d7336b582d4ca96a9
|
||||
F src/global.c 5caf4deab621abb45b4c607aad1bd21c20aac759
|
||||
F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
|
||||
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
|
||||
@ -221,7 +221,7 @@ F src/shell.c 128eb16ccec68509a4a2f1948f2483819bf63425
|
||||
F src/sqlite.h.in bd1451ba1ab681022a53bccc3c39580ba094a3ff
|
||||
F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0
|
||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||
F src/sqliteInt.h 0ff47977058e1babf0c4265f1791c379d172b02f
|
||||
F src/sqliteInt.h 646063fc1564842fd8e54eee00f8b8b429e2eb1f
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
@ -243,7 +243,7 @@ F src/test_config.c 636ecd15a6ba18bf97a590b5a21f47573c8c2b65
|
||||
F src/test_demovfs.c 69b2085076654ebc18014cbc6386f04409c959a9
|
||||
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
|
||||
F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f
|
||||
F src/test_func.c fcd238feb694332d5962ee08578ef30ff4ac6559
|
||||
F src/test_func.c 338a6e5ade3560ad36280881bbcf45f28d06cb68
|
||||
F src/test_hexio.c abfdecb6fa58c354623978efceb088ca18e379cd
|
||||
F src/test_init.c 3cbad7ce525aec925f8fda2192d576d47f0d478a
|
||||
F src/test_intarray.c 87847c71c3c36889c0bcc9c4baf9d31881665d61
|
||||
@ -308,7 +308,8 @@ F test/analyze5.test 96ac783a56142bbbedb58a7c1eebd1808b49cfae
|
||||
F test/analyze6.test 3c01e084309706a1033f850330ea24f6f7846297
|
||||
F test/analyze7.test c0af22c5e0140e2e4ac556a21c2b6fff58229c98
|
||||
F test/analyze8.test 8d1f76ff1e47c4093bb7be3971ba08fa56dc470d
|
||||
F test/analyze9.test 3e1bd0209354bb987832fba580c754cf77dc6ba3
|
||||
F test/analyze9.test 1b419d03407f2a6f4f1485620d54cb3e1bab3a71
|
||||
F test/analyzeA.test 949c3344280e0ca6de0b49805e4f291cdc1daa43
|
||||
F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b
|
||||
F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b
|
||||
F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7
|
||||
@ -1106,7 +1107,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
||||
F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae
|
||||
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
|
||||
P 088d1ff94890ada50d43e6a366a58167ec5a8e96
|
||||
R 4b6821682980828caa2dcfc6f067a6e7
|
||||
P ec3ffb174844406a6186c3dcc41b76d0331b502c
|
||||
R e94619aadc884e84bf22674359c1bbe0
|
||||
U dan
|
||||
Z 150d3ee65bd4be58d3670346ad74798d
|
||||
Z c424468455b7fdc35c2aa42e6130568e
|
||||
|
@ -1 +1 @@
|
||||
ec3ffb174844406a6186c3dcc41b76d0331b502c
|
||||
6d45078e621526fc2bac0eaefbb0f9602b9a8ec5
|
150
src/analyze.c
150
src/analyze.c
@ -168,8 +168,10 @@ static void openStatTable(
|
||||
const char *zCols;
|
||||
} aTable[] = {
|
||||
{ "sqlite_stat1", "tbl,idx,stat" },
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
#if defined(SQLITE_ENABLE_STAT4)
|
||||
{ "sqlite_stat4", "tbl,idx,neq,nlt,ndlt,sample" },
|
||||
#elif defined(SQLITE_ENABLE_STAT3)
|
||||
{ "sqlite_stat3", "tbl,idx,neq,nlt,ndlt,sample" },
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -1206,11 +1208,81 @@ void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
|
||||
/*
|
||||
** Load content from the sqlite_stat4 table into the Index.aSample[]
|
||||
** arrays of all indices.
|
||||
** The implementation of the sqlite_record() function. This function accepts
|
||||
** a single argument of any type. The return value is a formatted database
|
||||
** record (a blob) containing the argument value.
|
||||
**
|
||||
** This is used to convert the value stored in the 'sample' column of the
|
||||
** sqlite_stat3 table to the record format SQLite uses internally.
|
||||
*/
|
||||
static int loadStat4(sqlite3 *db, const char *zDb){
|
||||
static void recordFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const int file_format = 1;
|
||||
int iSerial; /* Serial type */
|
||||
int nSerial; /* Bytes of space for iSerial as varint */
|
||||
int nVal; /* Bytes of space required for argv[0] */
|
||||
int nRet;
|
||||
sqlite3 *db;
|
||||
u8 *aRet;
|
||||
|
||||
iSerial = sqlite3VdbeSerialType(argv[0], file_format);
|
||||
nSerial = sqlite3VarintLen(iSerial);
|
||||
nVal = sqlite3VdbeSerialTypeLen(iSerial);
|
||||
db = sqlite3_context_db_handle(context);
|
||||
|
||||
nRet = 1 + nSerial + nVal;
|
||||
aRet = sqlite3DbMallocRaw(db, nRet);
|
||||
if( aRet==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
}else{
|
||||
aRet[0] = nSerial+1;
|
||||
sqlite3PutVarint(&aRet[1], iSerial);
|
||||
sqlite3VdbeSerialPut(&aRet[1+nSerial], nVal, argv[0], file_format);
|
||||
sqlite3_result_blob(context, aRet, nRet, SQLITE_TRANSIENT);
|
||||
sqlite3DbFree(db, aRet);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Register built-in functions used to help read ANALYZE data.
|
||||
*/
|
||||
void sqlite3AnalyzeFunctions(void){
|
||||
static SQLITE_WSD FuncDef aAnalyzeTableFuncs[] = {
|
||||
FUNCTION(sqlite_record, 1, 0, 0, recordFunc),
|
||||
};
|
||||
int i;
|
||||
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
|
||||
FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAnalyzeTableFuncs);
|
||||
for(i=0; i<ArraySize(aAnalyzeTableFuncs); i++){
|
||||
sqlite3FuncDefInsert(pHash, &aFunc[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Load the content from either the sqlite_stat4 or sqlite_stat3 table
|
||||
** into the relevant Index.aSample[] arrays.
|
||||
**
|
||||
** Arguments zSql1 and zSql2 must point to SQL statements that return
|
||||
** data equivalent to the following (statements are different for stat3,
|
||||
** see the caller of this function for details):
|
||||
**
|
||||
** zSql1: SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx
|
||||
** zSql2: SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4
|
||||
**
|
||||
** where %Q is replaced with the database name before the SQL is executed.
|
||||
*/
|
||||
static int loadStatTbl(
|
||||
sqlite3 *db, /* Database handle */
|
||||
int bStat3, /* Assume single column records only */
|
||||
const char *zSql1, /* SQL statement 1 (see above) */
|
||||
const char *zSql2, /* SQL statement 2 (see above) */
|
||||
const char *zDb /* Database name (e.g. "main") */
|
||||
){
|
||||
int rc; /* Result codes from subroutines */
|
||||
sqlite3_stmt *pStmt = 0; /* An SQL statement being run */
|
||||
char *zSql; /* Text of the SQL statement */
|
||||
@ -1219,13 +1291,7 @@ static int loadStat4(sqlite3 *db, const char *zDb){
|
||||
IndexSample *pSample; /* A slot in pIdx->aSample[] */
|
||||
|
||||
assert( db->lookaside.bEnabled==0 );
|
||||
if( !sqlite3FindTable(db, "sqlite_stat4", zDb) ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
zSql = sqlite3MPrintf(db,
|
||||
"SELECT idx,count(*) FROM %Q.sqlite_stat4"
|
||||
" GROUP BY idx", zDb);
|
||||
zSql = sqlite3MPrintf(db, zSql1, zDb);
|
||||
if( !zSql ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@ -1234,6 +1300,9 @@ static int loadStat4(sqlite3 *db, const char *zDb){
|
||||
if( rc ) return rc;
|
||||
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
int nIdxCol = 1; /* Number of columns in stat4 records */
|
||||
int nAvgCol = 1; /* Number of entries in Index.aAvgEq */
|
||||
|
||||
char *zIndex; /* Index name */
|
||||
Index *pIdx; /* Pointer to the index object */
|
||||
int nSample; /* Number of samples */
|
||||
@ -1247,10 +1316,14 @@ static int loadStat4(sqlite3 *db, const char *zDb){
|
||||
pIdx = sqlite3FindIndex(db, zIndex, zDb);
|
||||
if( pIdx==0 ) continue;
|
||||
assert( pIdx->nSample==0 );
|
||||
if( bStat3==0 ){
|
||||
nIdxCol = pIdx->nColumn+1;
|
||||
nAvgCol = pIdx->nColumn;
|
||||
}
|
||||
pIdx->nSample = nSample;
|
||||
nByte = sizeof(IndexSample) * nSample;
|
||||
nByte += sizeof(tRowcnt) * (pIdx->nColumn+1) * 3 * nSample;
|
||||
nByte += pIdx->nColumn * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */
|
||||
nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample;
|
||||
nByte += nAvgCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */
|
||||
|
||||
pIdx->aSample = sqlite3DbMallocZero(db, nByte);
|
||||
if( pIdx->aSample==0 ){
|
||||
@ -1258,19 +1331,18 @@ static int loadStat4(sqlite3 *db, const char *zDb){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pSpace = (tRowcnt*)&pIdx->aSample[nSample];
|
||||
pIdx->aAvgEq = pSpace; pSpace += pIdx->nColumn;
|
||||
pIdx->aAvgEq = pSpace; pSpace += nAvgCol;
|
||||
for(i=0; i<pIdx->nSample; i++){
|
||||
pIdx->aSample[i].anEq = pSpace; pSpace += pIdx->nColumn+1;
|
||||
pIdx->aSample[i].anLt = pSpace; pSpace += pIdx->nColumn+1;
|
||||
pIdx->aSample[i].anDLt = pSpace; pSpace += pIdx->nColumn+1;
|
||||
pIdx->aSample[i].anEq = pSpace; pSpace += nIdxCol;
|
||||
pIdx->aSample[i].anLt = pSpace; pSpace += nIdxCol;
|
||||
pIdx->aSample[i].anDLt = pSpace; pSpace += nIdxCol;
|
||||
}
|
||||
assert( ((u8*)pSpace)-nByte==(u8*)(pIdx->aSample) );
|
||||
}
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
if( rc ) return rc;
|
||||
|
||||
zSql = sqlite3MPrintf(db,
|
||||
"SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4", zDb);
|
||||
zSql = sqlite3MPrintf(db, zSql2, zDb);
|
||||
if( !zSql ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@ -1279,10 +1351,10 @@ static int loadStat4(sqlite3 *db, const char *zDb){
|
||||
if( rc ) return rc;
|
||||
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
char *zIndex; /* Index name */
|
||||
Index *pIdx; /* Pointer to the index object */
|
||||
int i; /* Loop counter */
|
||||
int nCol; /* Number of columns in index */
|
||||
char *zIndex; /* Index name */
|
||||
Index *pIdx; /* Pointer to the index object */
|
||||
int i; /* Loop counter */
|
||||
int nCol = 1; /* Number of columns in index */
|
||||
|
||||
zIndex = (char *)sqlite3_column_text(pStmt, 0);
|
||||
if( zIndex==0 ) continue;
|
||||
@ -1297,7 +1369,9 @@ static int loadStat4(sqlite3 *db, const char *zDb){
|
||||
assert( idx<pIdx->nSample );
|
||||
pSample = &pIdx->aSample[idx];
|
||||
|
||||
nCol = pIdx->nColumn+1;
|
||||
if( bStat3==0 ){
|
||||
nCol = pIdx->nColumn+1;
|
||||
}
|
||||
decodeIntArray((char*)sqlite3_column_text(pStmt,1), nCol, pSample->anEq, 0);
|
||||
decodeIntArray((char*)sqlite3_column_text(pStmt,2), nCol, pSample->anLt, 0);
|
||||
decodeIntArray((char*)sqlite3_column_text(pStmt,3), nCol, pSample->anDLt,0);
|
||||
@ -1327,6 +1401,7 @@ static int loadStat4(sqlite3 *db, const char *zDb){
|
||||
}
|
||||
if( avgEq==0 ) avgEq = 1;
|
||||
pIdx->aAvgEq[iCol] = avgEq;
|
||||
if( bStat3 ) break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1340,6 +1415,33 @@ static int loadStat4(sqlite3 *db, const char *zDb){
|
||||
}
|
||||
return sqlite3_finalize(pStmt);
|
||||
}
|
||||
|
||||
/*
|
||||
** Load content from the sqlite_stat4 and sqlite_stat3 tables into
|
||||
** the Index.aSample[] arrays of all indices.
|
||||
*/
|
||||
static int loadStat4(sqlite3 *db, const char *zDb){
|
||||
int rc = SQLITE_OK; /* Result codes from subroutines */
|
||||
|
||||
assert( db->lookaside.bEnabled==0 );
|
||||
if( sqlite3FindTable(db, "sqlite_stat4", zDb) ){
|
||||
rc = loadStatTbl(db, 0,
|
||||
"SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx",
|
||||
"SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4",
|
||||
zDb
|
||||
);
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK && sqlite3FindTable(db, "sqlite_stat3", zDb) ){
|
||||
rc = loadStatTbl(db, 1,
|
||||
"SELECT idx,count(*) FROM %Q.sqlite_stat3 GROUP BY idx",
|
||||
"SELECT idx,neq,nlt,ndlt,sqlite_record(sample) FROM %Q.sqlite_stat3",
|
||||
zDb
|
||||
);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_STAT4 */
|
||||
|
||||
/*
|
||||
|
@ -1715,4 +1715,7 @@ void sqlite3RegisterGlobalFunctions(void){
|
||||
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||
sqlite3AlterFunctions();
|
||||
#endif
|
||||
#if defined(SQLITE_ENABLE_STAT3) || defined(SQLITE_ENABLE_STAT4)
|
||||
sqlite3AnalyzeFunctions();
|
||||
#endif
|
||||
}
|
||||
|
@ -3055,6 +3055,7 @@ extern int sqlite3PendingByte;
|
||||
void sqlite3RootPageMoved(sqlite3*, int, int, int);
|
||||
void sqlite3Reindex(Parse*, Token*, Token*);
|
||||
void sqlite3AlterFunctions(void);
|
||||
void sqlite3AnalyzeFunctions(void);
|
||||
void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
|
||||
int sqlite3GetToken(const unsigned char *, int *);
|
||||
void sqlite3NestedParse(Parse*, const char*, ...);
|
||||
|
@ -461,6 +461,54 @@ static void real2hex(
|
||||
sqlite3_result_text(context, zOut, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: test_extract(record, field)
|
||||
**
|
||||
** This function implements an SQL user-function that accepts a blob
|
||||
** containing a formatted database record as the first argument. The
|
||||
** second argument is the index of the field within that record to
|
||||
** extract and return.
|
||||
*/
|
||||
static void test_extract(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
u8 *pRec;
|
||||
u8 *pEndHdr; /* Points to one byte past record header */
|
||||
u8 *pHdr; /* Current point in record header */
|
||||
u8 *pBody; /* Current point in record data */
|
||||
u64 nHdr; /* Bytes in record header */
|
||||
int iIdx; /* Required field */
|
||||
int iCurrent = 0; /* Current field */
|
||||
|
||||
assert( argc==2 );
|
||||
pRec = (u8*)sqlite3_value_blob(argv[0]);
|
||||
iIdx = sqlite3_value_int(argv[1]);
|
||||
|
||||
pHdr = pRec + sqlite3GetVarint(pRec, &nHdr);
|
||||
pBody = pEndHdr = &pRec[nHdr];
|
||||
|
||||
for(iCurrent=0; pHdr<pEndHdr && iCurrent<=iIdx; iCurrent++){
|
||||
u64 iSerialType;
|
||||
Mem mem;
|
||||
|
||||
memset(&mem, 0, sizeof(mem));
|
||||
mem.db = db;
|
||||
mem.enc = SQLITE_UTF8;
|
||||
pHdr += sqlite3GetVarint(pHdr, &iSerialType);
|
||||
pBody += sqlite3VdbeSerialGet(pBody, (u32)iSerialType, &mem);
|
||||
sqlite3VdbeMemStoreType(&mem);
|
||||
|
||||
if( iCurrent==iIdx ){
|
||||
sqlite3_result_value(context, &mem);
|
||||
}
|
||||
|
||||
sqlite3DbFree(db, mem.zMalloc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: test_decode(record)
|
||||
**
|
||||
@ -579,6 +627,7 @@ static int registerTestFunctions(sqlite3 *db){
|
||||
{ "test_counter", 1, SQLITE_UTF8, counterFunc},
|
||||
{ "real2hex", 1, SQLITE_UTF8, real2hex},
|
||||
{ "test_decode", 1, SQLITE_UTF8, test_decode},
|
||||
{ "test_extract", 2, SQLITE_UTF8, test_extract},
|
||||
};
|
||||
int i;
|
||||
|
||||
|
@ -9,6 +9,9 @@
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file contains automated tests used to verify that the sqlite_stat4
|
||||
# functionality is working.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
132
test/analyzeA.test
Normal file
132
test/analyzeA.test
Normal file
@ -0,0 +1,132 @@
|
||||
# 2013 August 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 file contains automated tests used to verify that the current build
|
||||
# (which must be either ENABLE_STAT3 or ENABLE_STAT4) works with both stat3
|
||||
# and stat4 data.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix analyzeA
|
||||
|
||||
ifcapable !stat4&&!stat3 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
proc populate_stat3 {} {
|
||||
# Open a second connection on database "test.db" and run ANALYZE. If this
|
||||
# is an ENABLE_STAT3 build, this is all that is required to create and
|
||||
# populate the sqlite_stat3 table.
|
||||
#
|
||||
sqlite3 db2 test.db
|
||||
execsql { ANALYZE }
|
||||
|
||||
# Now, if this is an ENABLE_STAT4 build, create and populate the
|
||||
# sqlite_stat3 table based on the stat4 data gathered by the ANALYZE
|
||||
# above. Then drop the sqlite_stat4 table.
|
||||
#
|
||||
ifcapable stat4 {
|
||||
db2 func lindex lindex
|
||||
execsql {
|
||||
PRAGMA writable_schema = on;
|
||||
CREATE TABLE sqlite_stat3(tbl,idx,neq,nlt,ndlt,sample);
|
||||
INSERT INTO sqlite_stat3
|
||||
SELECT DISTINCT tbl, idx,
|
||||
lindex(neq,0), lindex(nlt,0), lindex(ndlt,0), test_extract(sample, 0)
|
||||
FROM sqlite_stat4;
|
||||
DROP TABLE sqlite_stat4;
|
||||
PRAGMA writable_schema = off;
|
||||
} db2
|
||||
}
|
||||
|
||||
# Modify the database schema cookie to ensure that the other connection
|
||||
# reloads the schema.
|
||||
#
|
||||
execsql {
|
||||
CREATE TABLE obscure_tbl_nm(x);
|
||||
DROP TABLE obscure_tbl_nm;
|
||||
} db2
|
||||
db2 close
|
||||
}
|
||||
|
||||
|
||||
proc populate_stat4 {} {
|
||||
execsql { ANALYZE }
|
||||
# ifcapable stat3 {
|
||||
# execsql {
|
||||
# PRAGMA writable_schema = on;
|
||||
# CREATE TABLE sqlite_stat4(tbl,idx,neq,nlt,ndlt,sample);
|
||||
# INSERT INTO sqlite_stat4 SELECT
|
||||
# tbl, idx, nlt, neq, ndlt,
|
||||
# test_extract(sample, 1)
|
||||
# FROM sqlite_stat4;
|
||||
# DROP TABLE sqlite_stat4;
|
||||
# PRAGMA writable_schema = off;
|
||||
# ANALYZE sqlite_master;
|
||||
# }
|
||||
# }
|
||||
}
|
||||
|
||||
foreach {tn analyze_cmd} {1 populate_stat4 2 populate_stat3} {
|
||||
reset_db
|
||||
do_test 1.$tn.1 {
|
||||
execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c) }
|
||||
for {set i 0} {$i < 100} {incr i} {
|
||||
set c [expr int(pow(1.1,$i)/100)]
|
||||
set b [expr 125 - int(pow(1.1,99-$i))/100]
|
||||
execsql {INSERT INTO t1 VALUES($i, $b, $c)}
|
||||
}
|
||||
} {}
|
||||
|
||||
execsql { CREATE INDEX t1b ON t1(b) }
|
||||
execsql { CREATE INDEX t1c ON t1(c) }
|
||||
$analyze_cmd
|
||||
|
||||
do_execsql_test 1.$tn.2.1 { SELECT count(*) FROM t1 WHERE b=31 } 1
|
||||
do_execsql_test 1.$tn.2.2 { SELECT count(*) FROM t1 WHERE c=0 } 49
|
||||
do_execsql_test 1.$tn.2.3 { SELECT count(*) FROM t1 WHERE b=125 } 49
|
||||
do_execsql_test 1.$tn.2.4 { SELECT count(*) FROM t1 WHERE c=16 } 1
|
||||
|
||||
do_eqp_test 1.$tn.2.5 {
|
||||
SELECT * FROM t1 WHERE b = 31 AND c = 0;
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}}
|
||||
do_eqp_test 1.$tn.2.6 {
|
||||
SELECT * FROM t1 WHERE b = 125 AND c = 16;
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c=?)}}
|
||||
|
||||
do_execsql_test 1.$tn.3.1 {
|
||||
SELECT count(*) FROM t1 WHERE b BETWEEN 0 AND 50
|
||||
} {6}
|
||||
do_execsql_test 1.$tn.3.2 {
|
||||
SELECT count(*) FROM t1 WHERE c BETWEEN 0 AND 50
|
||||
} {90}
|
||||
|
||||
do_execsql_test 1.$tn.3.3 {
|
||||
SELECT count(*) FROM t1 WHERE b BETWEEN 75 AND 125
|
||||
} {90}
|
||||
do_execsql_test 1.$tn.3.4 {
|
||||
SELECT count(*) FROM t1 WHERE c BETWEEN 75 AND 125
|
||||
} {6}
|
||||
|
||||
do_eqp_test 1.$tn.3.5 {
|
||||
SELECT * FROM t1 WHERE b BETWEEN 0 AND 50 AND c BETWEEN 0 AND 50
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}}
|
||||
|
||||
do_eqp_test 1.$tn.3.6 {
|
||||
SELECT * FROM t1 WHERE b BETWEEN 75 AND 125 AND c BETWEEN 75 AND 125
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
Loading…
x
Reference in New Issue
Block a user