-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
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
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
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
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
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
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
-67207a15bd7302ffeb2f342532b57b4852838d83
\ No newline at end of file
+aa728e06ce456fa42e68687bff6c7424460c31ef
\ No newline at end of file
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 */
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);
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);
}
}
/*
-** 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;
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{
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);
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);
if( pSample->u.z ){
memcpy(pSample->u.z, z, n);
}else{
- db->mallocFailed = 1;
+ db->mallocFailed = 1;
break;
}
}
}
}
rc = sqlite3_finalize(pStmt);
+ (void)sqlite3SafetyOn(db);
}
- (void)sqlite3SafetyOn(db);
}
#endif
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);
}
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*);
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"]
}
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;
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;
SELECT * FROM sqlite_stat2;
}
} {}
-
do_test analyze2-1.4 {
execsql {
DELETE FROM t1;
}
} {}
-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 }
+do_test analyze2-2.2 {
+ eqp "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 }
+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-1.3 {
- execsql { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE y>700 AND x>500 }
+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-1.4 {
- execsql { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE y>500 AND x>700 }
+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.1 {
+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.2 {
+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.3 {
+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,' ')
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
}
} {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
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
}
} {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}}
# 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
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
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}