Clean up sqlite_stat2 related code. Add test cases.

FossilOrigin-Name: aa728e06ce456fa42e68687bff6c7424460c31ef
This commit is contained in:
dan 2009-08-19 14:34:54 +00:00
parent a898aac951
commit 85c165caca
7 changed files with 330 additions and 129 deletions

View File

@ -1,5 +1,5 @@
C Fix\sa\sproblem\swhere\sa\sbuffer\sallocated\sfrom\sa\slookaside\spool\swas\sbeing\sreleased\susing\sthe\ssystem\sfree().
D 2009-08-19T09:09:38
C Clean\sup\ssqlite_stat2\srelated\scode.\sAdd\stest\scases.
D 2009-08-19T14:34:55
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 3213d61ee5fbcf8a54ccfc6c07667c595316c559
F src/analyze.c 985949131d55e3d9551cf00bff48409660a36a46
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 979b2aa9238531407ef7e64a56eed05d4c02b88d
F src/build.c ace6b5d99f724f102077ab6b0883ce1059c75271
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 4422daf1c74034094eee966cbce357232767b308
F src/sqliteInt.h 6bf0a232dc66ef02c4f1bedacc63322282081757
F src/sqliteLimit.h ffe93f5a0c4e7bd13e70cd7bf84cfb5c3465f45d
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
F src/table.c cc86ad3d6ad54df7c63a3e807b5783c90411a08d
@ -223,7 +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 f58acc55f582996dc68ec9d28ede4ebb68afd11f
F test/analyze2.test eb66cbd9486460a9a74876d2c6e0a49a08a44a87
F test/async.test 8c75d31b8330f8b70cf2571b014d4476a063efdb
F test/async2.test bf5e2ca2c96763b4cba3d016249ad7259a5603b6
F test/async3.test 93edaa9122f498e56ea98c36c72abc407f4fb11e
@ -448,7 +448,7 @@ F test/lock6.test 862aa71e97b288d6b3f92ba3313f51bd0b003776
F test/lookaside.test 1dd350dc6dff015c47c07fcc5a727a72fc5bae02
F test/main.test 347ab987f16167858781383427476b33dc69fdb7
F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
F test/malloc.test 7d7e1f04e6c2f338965e4220f2653f8b34ad3ee5
F test/malloc.test d23580e15c33ee0353717129421b077541e910dc
F test/malloc3.test 4bc57f850b212f706f3e1b37c4eced1d5a727cd1
F test/malloc4.test 957337613002b7058a85116493a262f679f3a261
F test/malloc5.test 4d16d1bb26d2deddd7c4f480deec341f9b2d0e22
@ -744,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 362665e89c21fd603d9f8ad6c0ead590e885af7c
R 0f4157c0cca678abe78a1dd4148f5f03
P 67207a15bd7302ffeb2f342532b57b4852838d83
R fc67b3175e5d16a0dc57c70ae312c646
U dan
Z 51de1621e1a30aec3aaa94297a00c42c
Z b80db5caa38d8f59e436115740e81d97

View File

@ -1 +1 @@
67207a15bd7302ffeb2f342532b57b4852838d83
aa728e06ce456fa42e68687bff6c7424460c31ef

View File

@ -116,16 +116,13 @@ static void analyzeOneTable(
int endOfLoop; /* The end of the loop */
int addr; /* The address of an instruction */
int iDb; /* Index of database containing pTab */
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 regRec = iMem++; /* Register holding completed record */
int regTemp = iMem++; /* Temporary use register */
int regRowid = iMem++; /* Rowid for the inserted record */
#ifdef SQLITE_ENABLE_STAT2
int regTemp2 = iMem++; /* Temporary use register */
int regSamplerecno = iMem++; /* Next sample index record number */
@ -195,21 +192,21 @@ static void analyzeOneTable(
sqlite3VdbeAddOp2(v, OP_Integer, 0, regSamplerecno);
#endif
/* Memory cells are used as follows. All memory cell addresses are
** offset by iMem. That is, cell 0 below is actually cell iMem, cell
** 1 is cell 1+iMem, etc.
/* The block of memory cells initialized here is used as follows.
**
** 0: The total number of rows in the table.
** iMem:
** The total number of rows in the table.
**
** 1..nCol: Number of distinct entries in index considering the
** left-most N columns, where N is the same as the
** memory cell number.
** iMem+1 .. iMem+nCol:
** Number of distinct entries in index considering the
** left-most N columns only, where N is between 1 and nCol,
** inclusive.
**
** nCol+1..2*nCol: Previous value of indexed columns, from left to
** right.
** iMem+nCol+1 .. Mem+2*nCol:
** Previous value of indexed columns, from left to right.
**
** Cells iMem through iMem+nCol are initialized to 0. The others
** are initialized to NULL.
** Cells iMem through iMem+nCol are initialized to 0. The others are
** initialized to contain an SQL NULL.
*/
for(i=0; i<=nCol; i++){
sqlite3VdbeAddOp2(v, OP_Integer, 0, iMem+i);
@ -257,23 +254,15 @@ static void analyzeOneTable(
sqlite3VdbeJumpHere(v, ne);
sqlite3VdbeAddOp2(v, OP_AddImm, regRecno, 1);
}
assert( sqlite3VdbeCurrentAddr(v)==(topOfLoop+14+2*i) );
#else
assert( sqlite3VdbeCurrentAddr(v)==(topOfLoop+2+2*i) );
#endif
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++){
#ifdef SQLITE_ENABLE_STAT2
sqlite3VdbeJumpHere(v, topOfLoop+14+2*i);
#else
sqlite3VdbeJumpHere(v, topOfLoop+2+2*i);
#endif
sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-(nCol*2));
sqlite3VdbeAddOp2(v, OP_AddImm, iMem+i+1, 1);
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, iMem+nCol+i+1);
}
@ -486,8 +475,45 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
}
/*
** Load the content of the sqlite_stat1 and sqlite_stat2 tables into the
** index hash tables.
** If the Index.aSample variable is not NULL, delete the aSample[] array
** and its contents.
*/
void sqlite3DeleteIndexSamples(Index *pIdx){
#ifdef SQLITE_ENABLE_STAT2
if( pIdx->aSample ){
int j;
sqlite3 *dbMem = pIdx->pTable->dbMem;
for(j=0; j<SQLITE_INDEX_SAMPLES; j++){
IndexSample *p = &pIdx->aSample[j];
if( p->eType==SQLITE_TEXT || p->eType==SQLITE_BLOB ){
sqlite3DbFree(pIdx->pTable->dbMem, p->u.z);
}
}
sqlite3DbFree(dbMem, pIdx->aSample);
pIdx->aSample = 0;
}
#endif
}
/*
** Load the content of the sqlite_stat1 and sqlite_stat2 tables. The
** contents of sqlite_stat1 are used to populate the Index.aiRowEst[]
** arrays. The contents of sqlite_stat2 are used to populate the
** Index.aSample[] arrays.
**
** If the sqlite_stat1 table is not present in the database, SQLITE_ERROR
** is returned. In this case, even if SQLITE_ENABLE_STAT2 was defined
** during compilation and the sqlite_stat2 table is present, no data is
** read from it.
**
** If SQLITE_ENABLE_STAT2 was defined during compilation and the
** sqlite_stat2 table is not present in the database, SQLITE_ERROR is
** returned. However, in this case, data is read from the sqlite_stat1
** table (if it is present) before returning.
**
** If an OOM error occurs, this function always sets db->mallocFailed.
** This means if the caller does not care about other errors, the return
** code may be ignored.
*/
int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
analysisInfo sInfo;
@ -503,18 +529,19 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
Index *pIdx = sqliteHashData(i);
sqlite3DefaultRowEst(pIdx);
sqlite3DeleteIndexSamples(pIdx);
}
/* Check to make sure the sqlite_stat1 table existss */
/* Check to make sure the sqlite_stat1 table exists */
sInfo.db = db;
sInfo.zDatabase = db->aDb[iDb].zName;
if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)==0 ){
return SQLITE_ERROR;
return SQLITE_ERROR;
}
/* Load new statistics out of the sqlite_stat1 table */
zSql = sqlite3MPrintf(db, "SELECT idx, stat FROM %Q.sqlite_stat1",
sInfo.zDatabase);
zSql = sqlite3MPrintf(db,
"SELECT idx, stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
if( zSql==0 ){
rc = SQLITE_NOMEM;
}else{
@ -524,33 +551,35 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
sqlite3DbFree(db, zSql);
}
/* Load the statistics from the sqlite_stat2 table. */
#ifdef SQLITE_ENABLE_STAT2
if( rc==SQLITE_OK && !sqlite3FindTable(db, "sqlite_stat2", sInfo.zDatabase) ){
rc = SQLITE_ERROR;
}
if( rc==SQLITE_OK ){
sqlite3_stmt *pStmt = 0;
zSql = sqlite3MPrintf(db,
"SELECT idx,sampleno,sample FROM %Q.sqlite_stat2", sInfo.zDatabase
);
"SELECT idx,sampleno,sample FROM %Q.sqlite_stat2", sInfo.zDatabase);
if( !zSql ){
return SQLITE_NOMEM;
rc = SQLITE_NOMEM;
}else{
(void)sqlite3SafetyOff(db);
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
(void)sqlite3SafetyOn(db);
sqlite3DbFree(db, zSql);
}
(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 ){
(void)sqlite3SafetyOff(db);
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);
sqlite3 *dbMem = pIdx->pTable->dbMem;
assert( dbMem==db || dbMem==0 );
assert( dbMem==db || dbMem==0 );
if( iSample<SQLITE_INDEX_SAMPLES && iSample>=0 ){
int eType = sqlite3_column_type(pStmt, 2);
@ -558,16 +587,13 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
static const int sz = sizeof(IndexSample)*SQLITE_INDEX_SAMPLES;
pIdx->aSample = (IndexSample *)sqlite3DbMallocZero(dbMem, sz);
if( pIdx->aSample==0 ){
db->mallocFailed = 1;
db->mallocFailed = 1;
break;
}
}
if( pIdx->aSample ){
IndexSample *pSample = &pIdx->aSample[iSample];
if( pSample->eType==SQLITE_TEXT || pSample->eType==SQLITE_BLOB ){
sqlite3DbFree(dbMem, pSample->u.z);
}
pSample->eType = eType;
if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
pSample->u.r = sqlite3_column_double(pStmt, 2);
@ -586,7 +612,7 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
if( pSample->u.z ){
memcpy(pSample->u.z, z, n);
}else{
db->mallocFailed = 1;
db->mallocFailed = 1;
break;
}
}
@ -595,8 +621,8 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
}
}
rc = sqlite3_finalize(pStmt);
(void)sqlite3SafetyOn(db);
}
(void)sqlite3SafetyOn(db);
}
#endif

View File

@ -343,16 +343,7 @@ 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);
sqlite3DeleteIndexSamples(p);
sqlite3DbFree(db, p->zColAff);
sqlite3DbFree(db, p);
}

View File

@ -2833,6 +2833,7 @@ int sqlite3InvokeBusyHandler(BusyHandler*);
int sqlite3FindDb(sqlite3*, Token*);
int sqlite3FindDbName(sqlite3 *, const char *);
int sqlite3AnalysisLoad(sqlite3*,int iDB);
void sqlite3DeleteIndexSamples(Index*);
void sqlite3DefaultRowEst(Index*);
void sqlite3RegisterLikeFunctions(sqlite3*, int);
int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*);

View File

@ -19,7 +19,34 @@ ifcapable !stat2 {
return
}
proc eqp sql {
#--------------------------------------------------------------------
# Test organization:
#
# analyze2-1.*: Tests to verify that ANALYZE creates and populates the
# sqlite_stat2 table as expected.
#
# analyze2-2.*: Test that when a table has two indexes on it and either
# index may be used for the scan, the index suggested by
# the contents of sqlite_stat2 table is prefered.
#
# analyze2-3.*: Similar to the previous block of tests, but using tables
# that contain a mixture of NULL, numeric, text and blob
# values.
#
# analyze2-4.*: Check that when an indexed column uses a collation other
# than BINARY, the collation is taken into account when
# using the contents of sqlite_stat2 to estimate the cost
# of a range scan.
#
# analyze2-5.*: Check that collation sequences are used as described above
# even when the only available version of the collation
# function require UTF-16 encoded arguments.
#
# analyze2-6.*: Check that the library behaves correctly when one of the
# sqlite_stat2 or sqlite_stat1 tables are missing.
#
proc eqp {sql} {
uplevel execsql [list "EXPLAIN QUERY PLAN $sql"]
}
@ -43,7 +70,6 @@ do_test analyze2-1.1 {
t1 sqlite_autoindex_t1_1 8 888 \
t1 sqlite_autoindex_t1_1 9 999 \
]
do_test analyze2-1.2 {
execsql {
DELETE FROM t1 WHERe x>9;
@ -51,7 +77,6 @@ do_test analyze2-1.2 {
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-1.3 {
execsql {
DELETE FROM t1 WHERE x>5;
@ -59,7 +84,6 @@ do_test analyze2-1.3 {
SELECT * FROM sqlite_stat2;
}
} {}
do_test analyze2-1.4 {
execsql {
DELETE FROM t1;
@ -68,62 +92,62 @@ do_test analyze2-1.4 {
}
} {}
do_test analyze2-1.1 {
do_test analyze2-2.1 {
execsql {
BEGIN;
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 COMMIT
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"
eqp "SELECT * FROM t1 WHERE x>500 AND y>700"
} {0 0 {TABLE t1 WITH INDEX t1_y}}
do_test analyze2-2.3 {
eqp "SELECT * FROM t1 WHERE x>700 AND y>500"
} {0 0 {TABLE t1 WITH INDEX t1_x}}
do_test analyze2-2.3 {
eqp "SELECT * FROM t1 WHERE y>700 AND x>500"
} {0 0 {TABLE t1 WITH INDEX t1_y}}
do_test analyze2-2.4 {
eqp "SELECT * FROM t1 WHERE y>500 AND x>700"
} {0 0 {TABLE t1 WITH INDEX t1_x}}
do_test analyze2-2.5 {
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.6 {
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.7 {
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 {
do_test analyze2-2.8 {
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 {
do_test analyze2-2.9 {
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 {
do_test analyze2-2.10 {
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 {
do_test analyze2-3.1 {
set alphabet [list a b c d e f g h i j]
execsql BEGIN
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 COMMIT
execsql ANALYZE
execsql {
SELECT tbl,idx,group_concat(sample,' ')
@ -132,7 +156,7 @@ do_test analyze2-4.1 {
GROUP BY tbl,idx
}
} {t1 t1_x {0 222 444 666 888 bba ddc ffe hhg jjj}}
do_test analyze2-4.2 {
do_test analyze2-3.2 {
execsql {
SELECT tbl,idx,group_concat(sample,' ')
FROM sqlite_stat2
@ -141,36 +165,38 @@ do_test analyze2-4.2 {
}
} {t1 t1_y {0 222 444 666 888 bba ddc ffe hhg jjj}}
do_test analyze2-4.3 {
do_test analyze2-3.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 {
do_test analyze2-3.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 {
do_test analyze2-3.5 {
eqp "SELECT * FROM t1 WHERE x<'a' AND y>'h'"
} {0 0 {TABLE t1 WITH INDEX t1_y}}
do_test analyze2-4.6 {
do_test analyze2-3.6 {
eqp "SELECT * FROM t1 WHERE x<444 AND y>'h'"
} {0 0 {TABLE t1 WITH INDEX t1_y}}
do_test analyze2-4.7 {
do_test analyze2-3.7 {
eqp "SELECT * FROM t1 WHERE x<221 AND y>'h'"
} {0 0 {TABLE t1 WITH INDEX t1_x}}
do_test analyze2-5.1 {
do_test analyze2-4.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]
execsql BEGIN
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 COMMIT
execsql ANALYZE
} {}
do_test analyze2-5.2 {
do_test analyze2-4.2 {
execsql {
SELECT tbl,idx,group_concat(sample,' ')
FROM sqlite_stat2
@ -178,7 +204,7 @@ do_test analyze2-5.2 {
GROUP BY tbl,idx
}
} {t3 t3a {AAA bbb CCC ddd EEE fff GGG hhh III jjj}}
do_test analyze2-5.3 {
do_test analyze2-4.3 {
execsql {
SELECT tbl,idx,group_concat(sample,' ')
FROM sqlite_stat2
@ -187,10 +213,10 @@ do_test analyze2-5.3 {
}
} {t3 t3b {AAA CCC EEE GGG III bbb ddd fff hhh jjj}}
do_test analyze2-5.4 {
do_test analyze2-4.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 {
do_test analyze2-4.5 {
eqp "SELECT * FROM t3 WHERE a > 'A' AND a < 'c' AND b > 'A' AND b < 'c'"
} {0 0 {TABLE t3 WITH INDEX t3a}}
@ -198,21 +224,22 @@ proc test_collate {enc lhs rhs} {
# puts $enc
return [string compare $lhs $rhs]
}
do_test analyze2-6.1 {
do_test analyze2-5.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]
execsql BEGIN
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 COMMIT
execsql ANALYZE
} {}
do_test analyze2-6.2 {
do_test analyze2-5.2 {
execsql {
SELECT tbl,idx,group_concat(sample,' ')
FROM sqlite_stat2
@ -220,31 +247,160 @@ do_test analyze2-6.2 {
GROUP BY tbl,idx
}
} {t4 t4x {aaa bbb ccc ddd eee fff ggg hhh iii jjj}}
do_test analyze2-6.3 {
do_test analyze2-5.3 {
eqp "SELECT * FROM t4 WHERE x>'ccc'"
} {0 0 {TABLE t4 WITH INDEX t4x}}
do_test analyze2-6.4 {
do_test analyze2-5.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 {
do_test analyze2-5.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'
#--------------------------------------------------------------------
# These tests, analyze2-6.*, verify that the library behaves correctly
# when one of the sqlite_stat1 and sqlite_stat2 tables is missing.
#
# If the sqlite_stat1 table is not present, then the sqlite_stat2
# table is not read. However, if it is the sqlite_stat2 table that
# is missing, the data in the sqlite_stat1 table is still used.
#
# Tests analyze2-6.1.* test the libary when the sqlite_stat2 table
# is missing. Tests analyze2-6.2.* test the library when sqlite_stat1
# is not present.
#
do_test analyze2-6.0 {
execsql {
DROP TABLE t4;
CREATE TABLE t5(a, b); CREATE INDEX t5i ON t5(a, b);
CREATE TABLE t6(a, b); CREATE INDEX t6i ON t6(a, b);
}
}
for {set ii 0} {$ii < 20} {incr ii} {
execsql {
INSERT INTO t5 VALUES($ii, $ii);
INSERT INTO t6 VALUES($ii/10, $ii/10);
}
}
execsql {
CREATE TABLE master AS
SELECT * FROM sqlite_master WHERE name LIKE 'sqlite_stat%'
}
} {}
do_test analyze2-6.1.1 {
eqp {SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a = 1 AND
t6.a = 1 AND t6.b = 1
}
} {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
do_test analyze2-6.1.2 {
db cache flush
execsql ANALYZE
eqp {SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a = 1 AND
t6.a = 1 AND t6.b = 1
}
} {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}}
do_test analyze2-6.1.3 {
sqlite3 db test.db
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a = 1 AND
t6.a = 1 AND t6.b = 1
}
} {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}}
do_test analyze2-6.1.4 {
execsql {
PRAGMA writable_schema = 1;
DELETE FROM sqlite_master WHERE tbl_name = 'sqlite_stat2';
}
sqlite3 db test.db
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a = 1 AND
t6.a = 1 AND t6.b = 1
}
} {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}}
do_test analyze2-6.1.5 {
execsql {
PRAGMA writable_schema = 1;
DELETE FROM sqlite_master WHERE tbl_name = 'sqlite_stat1';
}
sqlite3 db test.db
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a = 1 AND
t6.a = 1 AND t6.b = 1
}
} {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
do_test analyze2-6.1.6 {
execsql {
PRAGMA writable_schema = 1;
INSERT INTO sqlite_master SELECT * FROM master;
}
sqlite3 db test.db
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a = 1 AND
t6.a = 1 AND t6.b = 1
}
} {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}}
do_test analyze2-6.2.1 {
execsql {
DELETE FROM sqlite_stat1;
DELETE FROM sqlite_stat2;
}
sqlite3 db test.db
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a>1 AND t5.a<15 AND
t6.a>1
}
} {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}}
do_test analyze2-6.2.2 {
db cache flush
execsql ANALYZE
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a>1 AND t5.a<15 AND
t6.a>1
}
} {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
do_test analyze2-6.2.3 {
sqlite3 db test.db
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a>1 AND t5.a<15 AND
t6.a>1
}
} {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
do_test analyze2-6.2.4 {
execsql {
PRAGMA writable_schema = 1;
DELETE FROM sqlite_master WHERE tbl_name = 'sqlite_stat1';
}
sqlite3 db test.db
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a>1 AND t5.a<15 AND
t6.a>1
}
} {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}}
do_test analyze2-6.2.5 {
execsql {
PRAGMA writable_schema = 1;
DELETE FROM sqlite_master WHERE tbl_name = 'sqlite_stat2';
}
sqlite3 db test.db
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a>1 AND t5.a<15 AND
t6.a>1
}
} {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}}
do_test analyze2-6.2.6 {
execsql {
PRAGMA writable_schema = 1;
INSERT INTO sqlite_master SELECT * FROM master;
}
sqlite3 db test.db
execsql ANALYZE
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a>1 AND t5.a<15 AND
t6.a>1
}
} {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}}
finish_test

View File

@ -866,6 +866,33 @@ if {[db eval {PRAGMA locking_mode}]!="exclusive"} {
catch { db2 close }
}
ifcapable stat2 {
do_malloc_test 38 -tclprep {
add_test_collate db 0 0 1
execsql {
ANALYZE;
CREATE TABLE t4(x COLLATE test_collate);
CREATE INDEX t4x ON t4(x);
INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 0, 'aaa');
INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 1, 'aaa');
INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 2, 'aaa');
INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 3, 'aaa');
INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 4, 'aaa');
INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 5, 'aaa');
INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 6, 'aaa');
INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 7, 'aaa');
INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 8, 'aaa');
INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 9, 'aaa');
}
db close
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'
}
}
# Ensure that no file descriptors were leaked.
do_test malloc-99.X {
catch {db close}