Clean up sqlite_stat2 related code. Add test cases.
FossilOrigin-Name: aa728e06ce456fa42e68687bff6c7424460c31ef
This commit is contained in:
parent
a898aac951
commit
85c165caca
20
manifest
20
manifest
@ -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
|
||||
|
@ -1 +1 @@
|
||||
67207a15bd7302ffeb2f342532b57b4852838d83
|
||||
aa728e06ce456fa42e68687bff6c7424460c31ef
|
118
src/analyze.c
118
src/analyze.c
@ -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
|
||||
|
||||
|
11
src/build.c
11
src/build.c
@ -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);
|
||||
}
|
||||
|
@ -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*);
|
||||
|
@ -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
|
||||
|
@ -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}
|
||||
|
Loading…
Reference in New Issue
Block a user