Add test cases for skip-scan. Enhance "do_test" so that if the expected result

is of the form "/*..*/" or "~/*..*/" it treats the expected result as a glob
pattern rather than as a regular expression.  Fix a bug in ANALYZE result
loading associated with WITHOUT ROWID tables.

FossilOrigin-Name: d3e6e9b2a74074c05429d3c341c23525504351ab
This commit is contained in:
drh 2013-11-13 15:32:15 +00:00
parent cd8629e4bb
commit c2b23e7a98
5 changed files with 179 additions and 18 deletions

View File

@ -1,5 +1,5 @@
C Add\sthe\sability\sto\suse\san\sindex\seven\sif\sthe\sleft-most\scolumns\sof\sthe\sindex\nare\sunconstrainted,\sprovided\sthat\sthe\sleft-most\scolumns\shave\sfew\sdistinct\nvalues. C Add\stest\scases\sfor\sskip-scan.\s\sEnhance\s"do_test"\sso\sthat\sif\sthe\sexpected\sresult\nis\sof\sthe\sform\s"/*..*/"\sor\s"~/*..*/"\sit\streats\sthe\sexpected\sresult\sas\sa\sglob\npattern\srather\sthan\sas\sa\sregular\sexpression.\s\sFix\sa\sbug\sin\sANALYZE\sresult\nloading\sassociated\swith\sWITHOUT\sROWID\stables.
D 2013-11-13T12:27:25.442 D 2013-11-13T15:32:15.331
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 8a07bebafbfda0eb67728f4bd15a36201662d1a1 F Makefile.in 8a07bebafbfda0eb67728f4bd15a36201662d1a1
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -160,7 +160,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F src/alter.c 2af0330bb1b601af7a7789bf7229675fd772a083 F src/alter.c 2af0330bb1b601af7a7789bf7229675fd772a083
F src/analyze.c 27f0c132aa0679189837e0addf8762e7fd6831b6 F src/analyze.c 581d5c18ce89c6f45d4dca65914d0de5b4dad41f
F src/attach.c 0a17c9364895316ca4f52d06a97a72c0af1ae8b3 F src/attach.c 0a17c9364895316ca4f52d06a97a72c0af1ae8b3
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c 2f1987981139bd2f6d8c728d64bf09fb387443c3 F src/backup.c 2f1987981139bd2f6d8c728d64bf09fb387443c3
@ -805,6 +805,7 @@ F test/shell5.test 46c8c18d62732415c4fe084816c13d559831705e
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3 F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
F test/shrink.test 8c70f62b6e8eb4d54533de6d65bd06b1b9a17868 F test/shrink.test 8c70f62b6e8eb4d54533de6d65bd06b1b9a17868
F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329 F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329
F test/skipscan1.test 63af32c300be545417410ea2ce44e78c5b2e34b1
F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f
F test/softheap1.test 40562fe6cac6d9827b7b42b86d45aedf12c15e24 F test/softheap1.test 40562fe6cac6d9827b7b42b86d45aedf12c15e24
F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5 F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
@ -835,7 +836,7 @@ F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30 F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
F test/temptrigger.test 0a48d94222d50e6e50d72ac103606c4f8e7cbb81 F test/temptrigger.test 0a48d94222d50e6e50d72ac103606c4f8e7cbb81
F test/tester.tcl 3f675f00d22de3595be25dc2d2cba7ff623ef058 F test/tester.tcl bce6b929932498383ce92431da6a96432c690bf7
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5 F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
@ -1138,10 +1139,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
P 5196000930600d0cd931b87e864507791b9dab08 P 27dd5993d1ae5625eb94bf406421eb390d001be9
R d1d503c972952b4e29bfacf424d1532a R 56958c69a5559324c31384471b37b6dc
T *branch * skip-scan
T *sym-skip-scan *
T -sym-trunk *
U drh U drh
Z c64da1e6d225931e6198f9f21b69efb9 Z 2ff45f7229fb8bf180b3b10c0362f0e0

View File

@ -1 +1 @@
27dd5993d1ae5625eb94bf406421eb390d001be9 d3e6e9b2a74074c05429d3c341c23525504351ab

View File

@ -1428,10 +1428,12 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
if( pTable==0 ){ if( pTable==0 ){
return 0; return 0;
} }
if( argv[1] ){ if( argv[1]==0 ){
pIndex = sqlite3FindIndex(pInfo->db, argv[1], pInfo->zDatabase);
}else{
pIndex = 0; pIndex = 0;
}else if( sqlite3_stricmp(argv[0],argv[1])==0 ){
pIndex = sqlite3PrimaryKeyIndex(pTable);
}else{
pIndex = sqlite3FindIndex(pInfo->db, argv[1], pInfo->zDatabase);
} }
z = argv[2]; z = argv[2];

148
test/skipscan1.test Normal file
View File

@ -0,0 +1,148 @@
# 2013-11-13
#
# 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 implements tests of the "skip-scan" query strategy.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_execsql_test skipscan1-1.1 {
CREATE TABLE t1(a TEXT, b INT, c INT, d INT);
CREATE INDEX t1abc ON t1(a,b,c);
INSERT INTO t1 VALUES('abc',123,4,5);
INSERT INTO t1 VALUES('abc',234,5,6);
INSERT INTO t1 VALUES('abc',234,6,7);
INSERT INTO t1 VALUES('abc',345,7,8);
INSERT INTO t1 VALUES('def',567,8,9);
INSERT INTO t1 VALUES('def',345,9,10);
INSERT INTO t1 VALUES('bcd',100,6,11);
/* Fake the sqlite_stat1 table so that the query planner believes
** the table contains thousands of rows and that the first few
** columns are not selective. */
ANALYZE;
DELETE FROM sqlite_stat1;
INSERT INTO sqlite_stat1 VALUES('t1','t1abc','10000 5000 2000 10');
ANALYZE sqlite_master;
} {}
# Simple queries that leave the first one or two columns of the
# index unconstrainted.
#
do_execsql_test skipscan1-1.2 {
SELECT a,b,c,d,'|' FROM t1 WHERE b=345 ORDER BY a;
} {abc 345 7 8 | def 345 9 10 |}
do_execsql_test skipscan1-1.2eqp {
EXPLAIN QUERY PLAN
SELECT a,b,c,d,'|' FROM t1 WHERE b=345 ORDER BY a;
} {/* USING INDEX t1abc (ANY(a) AND b=?)*/}
do_execsql_test skipscan1-1.2sort {
EXPLAIN QUERY PLAN
SELECT a,b,c,d,'|' FROM t1 WHERE b=345 ORDER BY a;
} {~/*ORDER BY*/}
do_execsql_test skipscan1-1.3 {
SELECT a,b,c,d,'|' FROM t1 WHERE b=345 ORDER BY a DESC;
} {def 345 9 10 | abc 345 7 8 |}
do_execsql_test skipscan1-1.3eqp {
EXPLAIN QUERY PLAN
SELECT a,b,c,d,'|' FROM t1 WHERE b=345 ORDER BY a;
} {/* USING INDEX t1abc (ANY(a) AND b=?)*/}
do_execsql_test skipscan1-1.3sort {
EXPLAIN QUERY PLAN
SELECT a,b,c,d,'|' FROM t1 WHERE b=345 ORDER BY a;
} {~/*ORDER BY*/}
do_execsql_test skipscan1-1.4 {
SELECT a,b,c,d,'|' FROM t1 WHERE c=6 ORDER BY a, b, c;
} {abc 234 6 7 | bcd 100 6 11 |}
do_execsql_test skipscan1-1.4eqp {
EXPLAIN QUERY PLAN
SELECT a,b,c,d,'|' FROM t1 WHERE c=6 ORDER BY a, b, c;
} {/* USING INDEX t1abc (ANY(a) AND ANY(b) AND c=?)*/}
do_execsql_test skipscan1-1.4sort {
EXPLAIN QUERY PLAN
SELECT a,b,c,d,'|' FROM t1 WHERE c=6 ORDER BY a, b, c;
} {~/*ORDER BY*/}
# Joins
#
do_execsql_test skipscan1-1.5 {
CREATE TABLE t1j(x TEXT, y INTEGER);
INSERT INTO t1j VALUES('one',1),('six',6),('ninty-nine',99);
SELECT x, a, b, c, d, '|' FROM t1j, t1 WHERE c=y ORDER BY +a;
} {six abc 234 6 7 | six bcd 100 6 11 |}
do_execsql_test skipscan1-1.5eqp {
EXPLAIN QUERY PLAN
SELECT x, a, b, c, d, '|' FROM t1j, t1 WHERE c=y ORDER BY +a;
} {/* INDEX t1abc (ANY(a) AND ANY(b) AND c=?)*/}
do_execsql_test skipscan1-1.6 {
SELECT x, a, b, c, d, '|' FROM t1j LEFT JOIN t1 ON c=y ORDER BY +y, +a;
} {one {} {} {} {} | six abc 234 6 7 | six bcd 100 6 11 | ninty-nine {} {} {} {} |}
do_execsql_test skipscan1-1.6eqp {
EXPLAIN QUERY PLAN
SELECT x, a, b, c, d, '|' FROM t1j LEFT JOIN t1 ON c=y ORDER BY +y, +a;
} {/* INDEX t1abc (ANY(a) AND ANY(b) AND c=?)*/}
do_execsql_test skipscan1-2.1 {
CREATE TABLE t2(a TEXT, b INT, c INT, d INT,
PRIMARY KEY(a,b,c));
INSERT INTO t2 SELECT * FROM t1;
/* Fake the sqlite_stat1 table so that the query planner believes
** the table contains thousands of rows and that the first few
** columns are not selective. */
ANALYZE;
UPDATE sqlite_stat1 SET stat='10000 5000 2000 10' WHERE idx NOT NULL;
ANALYZE sqlite_master;
} {}
do_execsql_test skipscan1-2.2 {
SELECT a,b,c,d,'|' FROM t2 WHERE b=345 ORDER BY a;
} {abc 345 7 8 | def 345 9 10 |}
do_execsql_test skipscan1-2.2eqp {
EXPLAIN QUERY PLAN
SELECT a,b,c,d,'|' FROM t2 WHERE b=345 ORDER BY a;
} {/* USING INDEX sqlite_autoindex_t2_1 (ANY(a) AND b=?)*/}
do_execsql_test skipscan1-2.2sort {
EXPLAIN QUERY PLAN
SELECT a,b,c,d,'|' FROM t2 WHERE b=345 ORDER BY a;
} {~/*ORDER BY*/}
do_execsql_test skipscan1-3.1 {
CREATE TABLE t3(a TEXT, b INT, c INT, d INT,
PRIMARY KEY(a,b,c)) WITHOUT ROWID;
INSERT INTO t3 SELECT * FROM t1;
/* Fake the sqlite_stat1 table so that the query planner believes
** the table contains thousands of rows and that the first few
** columns are not selective. */
ANALYZE;
UPDATE sqlite_stat1 SET stat='10000 5000 2000 10' WHERE idx NOT NULL;
ANALYZE sqlite_master;
} {}
do_execsql_test skipscan1-3.2 {
SELECT a,b,c,d,'|' FROM t3 WHERE b=345 ORDER BY a;
} {abc 345 7 8 | def 345 9 10 |}
do_execsql_test skipscan1-3.2eqp {
EXPLAIN QUERY PLAN
SELECT a,b,c,d,'|' FROM t3 WHERE b=345 ORDER BY a;
} {/* INDEX sqlite_autoindex_t3_1 (ANY(a) AND b=?)*/}
do_execsql_test skipscan1-3.2sort {
EXPLAIN QUERY PLAN
SELECT a,b,c,d,'|' FROM t3 WHERE b=345 ORDER BY a;
} {~/*ORDER BY*/}
finish_test

View File

@ -616,11 +616,24 @@ proc do_test {name cmd expected} {
# regular expression PATTERN matches the result. "~/PATTERN/" means # regular expression PATTERN matches the result. "~/PATTERN/" means
# the regular expression must not match. # the regular expression must not match.
if {[string index $expected 0]=="~"} { if {[string index $expected 0]=="~"} {
set re [string map {# {[-0-9.]+}} [string range $expected 2 end-1]] set re [string range $expected 2 end-1]
set ok [expr {![regexp $re $result]}] if {[string index $re 0]=="*"} {
# If the regular expression begins with * then treat it as a glob instead
set ok [string match $re $result]
} else {
set re [string map {# {[-0-9.]+}} $re]
set ok [regexp $re $result]
}
set ok [expr {!$ok}]
} else { } else {
set re [string map {# {[-0-9.]+}} [string range $expected 1 end-1]] set re [string range $expected 1 end-1]
set ok [regexp $re $result] if {[string index $re 0]=="*"} {
# If the regular expression begins with * then treat it as a glob instead
set ok [string match $re $result]
} else {
set re [string map {# {[-0-9.]+}} $re]
set ok [regexp $re $result]
}
} }
} elseif {[regexp {^~?\*.*\*$} $expected]} { } elseif {[regexp {^~?\*.*\*$} $expected]} {
# "expected" is of the form "*GLOB*" then the result if correct if # "expected" is of the form "*GLOB*" then the result if correct if