Merge from trunk: (1) Recent bug fixes (2) STAT4 support (3) win32-longpath

support.

FossilOrigin-Name: e7ebc8f74fe91dee26f952fdf49e427b45448667
This commit is contained in:
drh
2013-08-29 15:08:38 +00:00
52 changed files with 3413 additions and 1245 deletions
+1 -1
View File
@@ -847,7 +847,7 @@ do_test alter-14.2 {
set system_table_list {1 sqlite_master}
catchsql ANALYZE
ifcapable analyze { lappend system_table_list 2 sqlite_stat1 }
ifcapable stat3 { lappend system_table_list 4 sqlite_stat3 }
ifcapable stat4 { lappend system_table_list 4 sqlite_stat4 }
foreach {tn tbl} $system_table_list {
do_test alter-15.$tn.1 {
+5
View File
@@ -143,6 +143,11 @@ do_test alter4-2.6 {
alter table t1 add column d DEFAULT CURRENT_TIME;
}
} {1 {Cannot add a column with non-constant default}}
do_test alter4-2.7 {
catchsql {
alter table t1 add column d default (-+1);
}
} {1 {Cannot add a column with non-constant default}}
do_test alter4-2.99 {
execsql {
DROP TABLE t1;
+17 -17
View File
@@ -288,7 +288,7 @@ do_test analyze-4.3 {
} {}
# Verify that DROP TABLE and DROP INDEX remove entries from the
# sqlite_stat1 and sqlite_stat3 tables.
# sqlite_stat1, sqlite_stat3 and sqlite_stat4 tables.
#
do_test analyze-5.0 {
execsql {
@@ -306,12 +306,13 @@ do_test analyze-5.0 {
SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1;
}
} {t3i1 t3i2 t3i3 t4i1 t4i2 t3 t4}
ifcapable stat3 {
ifcapable stat4||stat3 {
ifcapable stat4 {set stat sqlite_stat4} else {set stat sqlite_stat3}
do_test analyze-5.1 {
execsql {
SELECT DISTINCT idx FROM sqlite_stat3 ORDER BY 1;
SELECT DISTINCT tbl FROM sqlite_stat3 ORDER BY 1;
}
execsql "
SELECT DISTINCT idx FROM $stat ORDER BY 1;
SELECT DISTINCT tbl FROM $stat ORDER BY 1;
"
} {t3i1 t3i2 t3i3 t4i1 t4i2 t3 t4}
}
do_test analyze-5.2 {
@@ -321,12 +322,12 @@ do_test analyze-5.2 {
SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1;
}
} {t3i1 t3i3 t4i1 t4i2 t3 t4}
ifcapable stat3 {
ifcapable stat4||stat3 {
do_test analyze-5.3 {
execsql {
SELECT DISTINCT idx FROM sqlite_stat3 ORDER BY 1;
SELECT DISTINCT tbl FROM sqlite_stat3 ORDER BY 1;
}
execsql "
SELECT DISTINCT idx FROM $stat ORDER BY 1;
SELECT DISTINCT tbl FROM $stat ORDER BY 1;
"
} {t3i1 t3i3 t4i1 t4i2 t3 t4}
}
do_test analyze-5.4 {
@@ -336,12 +337,12 @@ do_test analyze-5.4 {
SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1;
}
} {t4i1 t4i2 t4}
ifcapable stat3 {
ifcapable stat4||stat3 {
do_test analyze-5.5 {
execsql {
SELECT DISTINCT idx FROM sqlite_stat3 ORDER BY 1;
SELECT DISTINCT tbl FROM sqlite_stat3 ORDER BY 1;
}
execsql "
SELECT DISTINCT idx FROM $stat ORDER BY 1;
SELECT DISTINCT tbl FROM $stat ORDER BY 1;
"
} {t4i1 t4i2 t4}
}
@@ -360,5 +361,4 @@ do_test analyze-99.1 {
}
} {1 {malformed database schema (sqlite_stat1) - near "nonsense": syntax error}}
finish_test
+8 -3
View File
@@ -17,7 +17,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !stat3 {
ifcapable !stat4&&!stat3 {
finish_test
return
}
@@ -95,7 +95,13 @@ do_test analyze3-1.1.1 {
COMMIT;
ANALYZE;
}
} {}
ifcapable stat4 {
execsql { SELECT count(*)>0 FROM sqlite_stat4; }
} else {
execsql { SELECT count(*)>0 FROM sqlite_stat3; }
}
} {1}
do_eqp_test analyze3-1.1.2 {
SELECT sum(y) FROM t1 WHERE x>200 AND x<300
@@ -312,7 +318,6 @@ do_test analyze3-3.1 {
execsql COMMIT
execsql ANALYZE
} {}
do_test analyze3-3.2.1 {
set S [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE b>?" -1 dummy]
sqlite3_expired $S
+42 -8
View File
@@ -10,14 +10,14 @@
#***********************************************************************
#
# This file implements tests for SQLite library. The focus of the tests
# in this file is the use of the sqlite_stat3 histogram data on tables
# in this file is the use of the sqlite_stat4 histogram data on tables
# with many repeated values and only a few distinct values.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !stat3 {
ifcapable !stat4&&!stat3 {
finish_test
return
}
@@ -28,6 +28,17 @@ proc eqp {sql {db db}} {
uplevel execsql [list "EXPLAIN QUERY PLAN $sql"] $db
}
proc alpha {blob} {
set ret ""
foreach c [split $blob {}] {
if {[string is alpha $c]} {append ret $c}
}
return $ret
}
db func alpha alpha
db func lindex lindex
unset -nocomplain i t u v w x y z
do_test analyze5-1.0 {
db eval {CREATE TABLE t1(t,u,v TEXT COLLATE nocase,w,x,y,z)}
@@ -55,17 +66,40 @@ do_test analyze5-1.0 {
CREATE INDEX t1y ON t1(y); -- integers 0 and very few 1s
CREATE INDEX t1z ON t1(z); -- integers 0, 1, 2, and 3
ANALYZE;
SELECT sample FROM sqlite_stat3 WHERE idx='t1u' ORDER BY nlt;
}
ifcapable stat4 {
db eval {
SELECT DISTINCT lindex(test_decode(sample),0)
FROM sqlite_stat4 WHERE idx='t1u' ORDER BY nlt;
}
} else {
db eval {
SELECT sample FROM sqlite_stat3 WHERE idx='t1u' ORDER BY nlt;
}
}
} {alpha bravo charlie delta}
do_test analyze5-1.1 {
db eval {SELECT DISTINCT lower(sample) FROM sqlite_stat3 WHERE idx='t1v'
ORDER BY 1}
ifcapable stat4 {
db eval {
SELECT DISTINCT lower(lindex(test_decode(sample), 0))
FROM sqlite_stat4 WHERE idx='t1v' ORDER BY 1
}
} else {
db eval {
SELECT lower(sample) FROM sqlite_stat3 WHERE idx='t1v' ORDER BY 1
}
}
} {alpha bravo charlie delta}
do_test analyze5-1.2 {
db eval {SELECT idx, count(*) FROM sqlite_stat3 GROUP BY 1 ORDER BY 1}
} {t1t 4 t1u 4 t1v 4 t1w 4 t1x 4 t1y 2 t1z 4}
ifcapable stat4 {
do_test analyze5-1.2 {
db eval {SELECT idx, count(*) FROM sqlite_stat4 GROUP BY 1 ORDER BY 1}
} {t1t 8 t1u 8 t1v 8 t1w 8 t1x 8 t1y 9 t1z 8}
} else {
do_test analyze5-1.2 {
db eval {SELECT idx, count(*) FROM sqlite_stat3 GROUP BY 1 ORDER BY 1}
} {t1t 4 t1u 4 t1v 4 t1w 4 t1x 4 t1y 2 t1z 4}
}
# Verify that range queries generate the correct row count estimates
#
+1 -1
View File
@@ -17,7 +17,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !stat3 {
ifcapable !stat4&&!stat3 {
finish_test
return
}
+5 -4
View File
@@ -82,14 +82,14 @@ do_test analyze7-3.1 {
do_test analyze7-3.2.1 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=?;}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?)}}
ifcapable stat3 {
# If ENABLE_STAT3 is defined, SQLite comes up with a different estimated
ifcapable stat4||stat3 {
# If ENABLE_STAT4 is defined, SQLite comes up with a different estimated
# row count for (c=2) than it does for (c=?).
do_test analyze7-3.2.2 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?)}}
} else {
# If ENABLE_STAT3 is not defined, the expected row count for (c=2) is the
# If ENABLE_STAT4 is not defined, the expected row count for (c=2) is the
# same as that for (c=?).
do_test analyze7-3.2.3 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;}
@@ -98,7 +98,8 @@ ifcapable stat3 {
do_test analyze7-3.3 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND b=123}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}}
ifcapable {!stat3} {
ifcapable {!stat4 && !stat3} {
do_test analyze7-3.4 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND b=123}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}}
+13 -1
View File
@@ -16,7 +16,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !stat3 {
ifcapable !stat4&&!stat3 {
finish_test
return
}
@@ -84,7 +84,19 @@ do_test 2.1 {
# There are many more values of c between 0 and 100000 than there are
# between 800000 and 900000. So t1c is more selective for the latter
# range.
#
# Test 3.2 is a little unstable. It depends on the planner estimating
# that (b BETWEEN 50 AND 54) will match more rows than (c BETWEEN
# 800000 AND 900000). Which is a pretty close call (50 vs. 32), so
# the planner could get it wrong with an unlucky set of samples. This
# case happens to work, but others ("b BETWEEN 40 AND 44" for example)
# will fail.
#
do_execsql_test 3.0 {
SELECT count(*) FROM t1 WHERE b BETWEEN 50 AND 54;
SELECT count(*) FROM t1 WHERE c BETWEEN 0 AND 100000;
SELECT count(*) FROM t1 WHERE c BETWEEN 800000 AND 900000;
} {50 376 32}
do_test 3.1 {
eqp {SELECT * FROM t1 WHERE b BETWEEN 50 AND 54 AND c BETWEEN 0 AND 100000}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}}
+426
View File
@@ -0,0 +1,426 @@
# 2013 August 3
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file contains automated tests used to verify that the sqlite_stat4
# functionality is working.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix analyze9
ifcapable !stat4 {
finish_test
return
}
proc s {blob} {
set ret ""
binary scan $blob c* bytes
foreach b $bytes {
set t [binary format c $b]
if {[string is print $t]} {
append ret $t
} else {
append ret .
}
}
return $ret
}
db function s s
do_execsql_test 1.0 {
CREATE TABLE t1(a TEXT, b TEXT);
INSERT INTO t1 VALUES('(0)', '(0)');
INSERT INTO t1 VALUES('(1)', '(1)');
INSERT INTO t1 VALUES('(2)', '(2)');
INSERT INTO t1 VALUES('(3)', '(3)');
INSERT INTO t1 VALUES('(4)', '(4)');
CREATE INDEX i1 ON t1(a, b);
} {}
do_execsql_test 1.1 {
ANALYZE;
} {}
do_execsql_test 1.2 {
SELECT tbl,idx,nEq,nLt,nDLt,test_decode(sample) FROM sqlite_stat4;
} {
t1 i1 {1 1 1} {0 0 0} {0 0 0} {(0) (0) 1}
t1 i1 {1 1 1} {1 1 1} {1 1 1} {(1) (1) 2}
t1 i1 {1 1 1} {2 2 2} {2 2 2} {(2) (2) 3}
t1 i1 {1 1 1} {3 3 3} {3 3 3} {(3) (3) 4}
t1 i1 {1 1 1} {4 4 4} {4 4 4} {(4) (4) 5}
}
if {[permutation] != "utf16"} {
do_execsql_test 1.3 {
SELECT tbl,idx,nEq,nLt,nDLt,s(sample) FROM sqlite_stat4;
} {
t1 i1 {1 1 1} {0 0 0} {0 0 0} ....(0)(0)
t1 i1 {1 1 1} {1 1 1} {1 1 1} ....(1)(1).
t1 i1 {1 1 1} {2 2 2} {2 2 2} ....(2)(2).
t1 i1 {1 1 1} {3 3 3} {3 3 3} ....(3)(3).
t1 i1 {1 1 1} {4 4 4} {4 4 4} ....(4)(4).
}
}
#-------------------------------------------------------------------------
# This is really just to test SQL user function "test_decode".
#
reset_db
do_execsql_test 2.1 {
CREATE TABLE t1(a, b, c);
INSERT INTO t1 VALUES('some text', 14, NULL);
INSERT INTO t1 VALUES(22.0, NULL, x'656667');
CREATE INDEX i1 ON t1(a, b, c);
ANALYZE;
SELECT test_decode(sample) FROM sqlite_stat4;
} {
{22.0 NULL x'656667' 2}
{{some text} 14 NULL 1}
}
#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 3.1 {
CREATE TABLE t2(a, b);
CREATE INDEX i2 ON t2(a, b);
BEGIN;
}
do_test 3.2 {
for {set i 0} {$i < 1000} {incr i} {
set a [expr $i / 10]
set b [expr int(rand() * 15.0)]
execsql { INSERT INTO t2 VALUES($a, $b) }
}
execsql COMMIT
} {}
db func lindex lindex
# Each value of "a" occurs exactly 10 times in the table.
#
do_execsql_test 3.3.1 {
SELECT count(*) FROM t2 GROUP BY a;
} [lrange [string repeat "10 " 100] 0 99]
# The first element in the "nEq" list of all samples should therefore be 10.
#
do_execsql_test 3.3.2 {
ANALYZE;
SELECT lindex(nEq, 0) FROM sqlite_stat4;
} [lrange [string repeat "10 " 100] 0 23]
#-------------------------------------------------------------------------
#
do_execsql_test 3.4 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
INSERT INTO t1 VALUES(1, 1, 'one-a');
INSERT INTO t1 VALUES(11, 1, 'one-b');
INSERT INTO t1 VALUES(21, 1, 'one-c');
INSERT INTO t1 VALUES(31, 1, 'one-d');
INSERT INTO t1 VALUES(41, 1, 'one-e');
INSERT INTO t1 VALUES(51, 1, 'one-f');
INSERT INTO t1 VALUES(61, 1, 'one-g');
INSERT INTO t1 VALUES(71, 1, 'one-h');
INSERT INTO t1 VALUES(81, 1, 'one-i');
INSERT INTO t1 VALUES(91, 1, 'one-j');
INSERT INTO t1 SELECT a+1,2,'two' || substr(c,4) FROM t1;
INSERT INTO t1 SELECT a+2,3,'three'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';
INSERT INTO t1 SELECT a+3,4,'four'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';
INSERT INTO t1 SELECT a+4,5,'five'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';
INSERT INTO t1 SELECT a+5,6,'six'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';
CREATE INDEX t1b ON t1(b);
ANALYZE;
SELECT c FROM t1 WHERE b=3 AND a BETWEEN 30 AND 60;
} {three-d three-e three-f}
#-------------------------------------------------------------------------
# These tests verify that the sample selection for stat4 appears to be
# working as designed.
#
reset_db
db func lindex lindex
db func lrange lrange
do_execsql_test 4.0 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a, b, c);
CREATE INDEX i1 ON t1(c, b, a);
}
proc insert_filler_rows_n {iStart args} {
set A(-ncopy) 1
set A(-nval) 1
foreach {k v} $args {
if {[info exists A($k)]==0} { error "no such option: $k" }
set A($k) $v
}
if {[llength $args] % 2} {
error "option requires an argument: [lindex $args end]"
}
for {set i 0} {$i < $A(-nval)} {incr i} {
set iVal [expr $iStart+$i]
for {set j 0} {$j < $A(-ncopy)} {incr j} {
execsql { INSERT INTO t1 VALUES($iVal, $iVal, $iVal) }
}
}
}
do_test 4.1 {
execsql { BEGIN }
insert_filler_rows_n 0 -ncopy 10 -nval 19
insert_filler_rows_n 20 -ncopy 1 -nval 100
execsql {
INSERT INTO t1(c, b, a) VALUES(200, 1, 'a');
INSERT INTO t1(c, b, a) VALUES(200, 1, 'b');
INSERT INTO t1(c, b, a) VALUES(200, 1, 'c');
INSERT INTO t1(c, b, a) VALUES(200, 2, 'e');
INSERT INTO t1(c, b, a) VALUES(200, 2, 'f');
INSERT INTO t1(c, b, a) VALUES(201, 3, 'g');
INSERT INTO t1(c, b, a) VALUES(201, 4, 'h');
ANALYZE;
SELECT count(*) FROM sqlite_stat4;
SELECT count(*) FROM t1;
}
} {24 297}
do_execsql_test 4.2 {
SELECT
neq,
lrange(nlt, 0, 2),
lrange(ndlt, 0, 2),
lrange(test_decode(sample), 0, 2)
FROM sqlite_stat4
ORDER BY rowid LIMIT 16;
} {
{10 10 10 1} {0 0 0} {0 0 0} {0 0 0}
{10 10 10 1} {10 10 10} {1 1 1} {1 1 1}
{10 10 10 1} {20 20 20} {2 2 2} {2 2 2}
{10 10 10 1} {30 30 30} {3 3 3} {3 3 3}
{10 10 10 1} {40 40 40} {4 4 4} {4 4 4}
{10 10 10 1} {50 50 50} {5 5 5} {5 5 5}
{10 10 10 1} {60 60 60} {6 6 6} {6 6 6}
{10 10 10 1} {70 70 70} {7 7 7} {7 7 7}
{10 10 10 1} {80 80 80} {8 8 8} {8 8 8}
{10 10 10 1} {90 90 90} {9 9 9} {9 9 9}
{10 10 10 1} {100 100 100} {10 10 10} {10 10 10}
{10 10 10 1} {110 110 110} {11 11 11} {11 11 11}
{10 10 10 1} {120 120 120} {12 12 12} {12 12 12}
{10 10 10 1} {130 130 130} {13 13 13} {13 13 13}
{10 10 10 1} {140 140 140} {14 14 14} {14 14 14}
{10 10 10 1} {150 150 150} {15 15 15} {15 15 15}
}
do_execsql_test 4.3 {
SELECT
neq,
lrange(nlt, 0, 2),
lrange(ndlt, 0, 2),
lrange(test_decode(sample), 0, 1)
FROM sqlite_stat4
ORDER BY rowid DESC LIMIT 2;
} {
{2 1 1 1} {295 296 296} {120 122 125} {201 4}
{5 3 1 1} {290 290 292} {119 119 121} {200 1}
}
do_execsql_test 4.4 { SELECT count(DISTINCT c) FROM t1 WHERE c<201 } 120
do_execsql_test 4.5 { SELECT count(DISTINCT c) FROM t1 WHERE c<200 } 119
# Check that the perioidic samples are present.
do_execsql_test 4.6 {
SELECT count(*) FROM sqlite_stat4
WHERE lindex(test_decode(sample), 3) IN
('34', '68', '102', '136', '170', '204', '238', '272')
} {8}
reset_db
do_test 4.7 {
execsql {
BEGIN;
CREATE TABLE t1(o,t INTEGER PRIMARY KEY);
CREATE INDEX i1 ON t1(o);
}
for {set i 0} {$i<10000} {incr i [expr (($i<1000)?1:10)]} {
execsql { INSERT INTO t1 VALUES('x', $i) }
}
execsql {
COMMIT;
ANALYZE;
SELECT count(*) FROM sqlite_stat4;
}
} {8}
do_execsql_test 4.8 {
SELECT test_decode(sample) FROM sqlite_stat4;
} {
{x 211} {x 423} {x 635} {x 847}
{x 1590} {x 3710} {x 5830} {x 7950}
}
#-------------------------------------------------------------------------
# The following would cause a crash at one point.
#
reset_db
do_execsql_test 5.1 {
PRAGMA encoding = 'utf-16';
CREATE TABLE t0(v);
ANALYZE;
}
#-------------------------------------------------------------------------
# This was also crashing (corrupt sqlite_stat4 table).
#
reset_db
do_execsql_test 6.1 {
CREATE TABLE t1(a, b);
CREATE INDEX i1 ON t1(a);
CREATE INDEX i2 ON t1(b);
INSERT INTO t1 VALUES(1, 1);
INSERT INTO t1 VALUES(2, 2);
INSERT INTO t1 VALUES(3, 3);
INSERT INTO t1 VALUES(4, 4);
INSERT INTO t1 VALUES(5, 5);
ANALYZE;
PRAGMA writable_schema = 1;
CREATE TEMP TABLE x1 AS
SELECT tbl,idx,neq,nlt,ndlt,sample FROM sqlite_stat4
ORDER BY (rowid%5), rowid;
DELETE FROM sqlite_stat4;
INSERT INTO sqlite_stat4 SELECT * FROM x1;
PRAGMA writable_schema = 0;
ANALYZE sqlite_master;
}
do_execsql_test 6.2 {
SELECT * FROM t1 WHERE a = 'abc';
}
#-------------------------------------------------------------------------
# The following tests experiment with adding corrupted records to the
# 'sample' column of the sqlite_stat4 table.
#
reset_db
sqlite3_db_config_lookaside db 0 0 0
do_execsql_test 7.1 {
CREATE TABLE t1(a, b);
CREATE INDEX i1 ON t1(a, b);
INSERT INTO t1 VALUES(1, 1);
INSERT INTO t1 VALUES(2, 2);
INSERT INTO t1 VALUES(3, 3);
INSERT INTO t1 VALUES(4, 4);
INSERT INTO t1 VALUES(5, 5);
ANALYZE;
UPDATE sqlite_stat4 SET sample = X'' WHERE rowid = 1;
ANALYZE sqlite_master;
}
do_execsql_test 7.2 {
UPDATE sqlite_stat4 SET sample = X'FFFF';
ANALYZE sqlite_master;
SELECT * FROM t1 WHERE a = 1;
} {1 1}
do_execsql_test 7.3 {
ANALYZE;
UPDATE sqlite_stat4 SET neq = '0 0 0';
ANALYZE sqlite_master;
SELECT * FROM t1 WHERE a = 1;
} {1 1}
do_execsql_test 7.4 {
ANALYZE;
UPDATE sqlite_stat4 SET ndlt = '0 0 0';
ANALYZE sqlite_master;
SELECT * FROM t1 WHERE a = 3;
} {3 3}
do_execsql_test 7.5 {
ANALYZE;
UPDATE sqlite_stat4 SET nlt = '0 0 0';
ANALYZE sqlite_master;
SELECT * FROM t1 WHERE a = 5;
} {5 5}
#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 8.1 {
CREATE TABLE t1(x TEXT);
CREATE INDEX i1 ON t1(x);
INSERT INTO t1 VALUES('1');
INSERT INTO t1 VALUES('2');
INSERT INTO t1 VALUES('3');
INSERT INTO t1 VALUES('4');
ANALYZE;
}
do_execsql_test 8.2 {
SELECT * FROM t1 WHERE x = 3;
} {3}
#-------------------------------------------------------------------------
# Check that the bug fixed by [91733bc485] really is fixed.
#
reset_db
do_execsql_test 9.1 {
CREATE TABLE t1(a, b, c, d, e);
CREATE INDEX i1 ON t1(a, b, c, d);
CREATE INDEX i2 ON t1(e);
}
do_test 9.2 {
execsql BEGIN;
for {set i 0} {$i < 100} {incr i} {
execsql "INSERT INTO t1 VALUES('x', 'y', 'z', $i, [expr $i/2])"
}
for {set i 0} {$i < 20} {incr i} {
execsql "INSERT INTO t1 VALUES('x', 'y', 'z', 101, $i)"
}
for {set i 102} {$i < 200} {incr i} {
execsql "INSERT INTO t1 VALUES('x', 'y', 'z', $i, [expr $i/2])"
}
execsql COMMIT
execsql ANALYZE
} {}
do_eqp_test 9.3.1 {
SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=101 AND e=5;
} {/t1 USING INDEX i2/}
do_eqp_test 9.3.2 {
SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=99 AND e=5;
} {/t1 USING INDEX i1/}
set value_d [expr 101]
do_eqp_test 9.4.1 {
SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=$value_d AND e=5
} {/t1 USING INDEX i2/}
set value_d [expr 99]
do_eqp_test 9.4.2 {
SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=$value_d AND e=5
} {/t1 USING INDEX i1/}
finish_test
+167
View File
@@ -0,0 +1,167 @@
# 2013 August 3
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file contains automated tests used to verify that the current build
# (which must be either ENABLE_STAT3 or ENABLE_STAT4) works with both stat3
# and stat4 data.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix analyzeA
ifcapable !stat4&&!stat3 {
finish_test
return
}
# Populate the stat3 table according to the current contents of the db
#
proc populate_stat3 {{bDropTable 1}} {
# Open a second connection on database "test.db" and run ANALYZE. If this
# is an ENABLE_STAT3 build, this is all that is required to create and
# populate the sqlite_stat3 table.
#
sqlite3 db2 test.db
execsql { ANALYZE }
# Now, if this is an ENABLE_STAT4 build, create and populate the
# sqlite_stat3 table based on the stat4 data gathered by the ANALYZE
# above. Then drop the sqlite_stat4 table.
#
ifcapable stat4 {
db2 func lindex lindex
execsql {
PRAGMA writable_schema = on;
CREATE TABLE sqlite_stat3(tbl,idx,neq,nlt,ndlt,sample);
INSERT INTO sqlite_stat3
SELECT DISTINCT tbl, idx,
lindex(neq,0), lindex(nlt,0), lindex(ndlt,0), test_extract(sample, 0)
FROM sqlite_stat4;
} db2
if {$bDropTable} { execsql {DROP TABLE sqlite_stat4} db2 }
execsql { PRAGMA writable_schema = off }
}
# Modify the database schema cookie to ensure that the other connection
# reloads the schema.
#
execsql {
CREATE TABLE obscure_tbl_nm(x);
DROP TABLE obscure_tbl_nm;
} db2
db2 close
}
# Populate the stat4 table according to the current contents of the db
#
proc populate_stat4 {{bDropTable 1}} {
sqlite3 db2 test.db
execsql { ANALYZE }
ifcapable stat3 {
execsql {
PRAGMA writable_schema = on;
CREATE TABLE sqlite_stat4(tbl,idx,neq,nlt,ndlt,sample);
INSERT INTO sqlite_stat4
SELECT tbl, idx, neq, nlt, ndlt, sqlite_record(sample)
FROM sqlite_stat3;
} db2
if {$bDropTable} { execsql {DROP TABLE sqlite_stat3} db2 }
execsql { PRAGMA writable_schema = off }
}
# Modify the database schema cookie to ensure that the other connection
# reloads the schema.
#
execsql {
CREATE TABLE obscure_tbl_nm(x);
DROP TABLE obscure_tbl_nm;
} db2
db2 close
}
# Populate the stat4 table according to the current contents of the db.
# Leave deceptive data in the stat3 table. This data should be ignored
# in favour of that from the stat4 table.
#
proc populate_both {} {
ifcapable stat4 { populate_stat3 0 }
ifcapable stat3 { populate_stat4 0 }
sqlite3 db2 test.db
execsql {
PRAGMA writable_schema = on;
UPDATE sqlite_stat3 SET idx =
CASE idx WHEN 't1b' THEN 't1c' ELSE 't1b'
END;
PRAGMA writable_schema = off;
CREATE TABLE obscure_tbl_nm(x);
DROP TABLE obscure_tbl_nm;
} db2
db2 close
}
foreach {tn analyze_cmd} {
1 populate_stat4
2 populate_stat3
3 populate_both
} {
reset_db
do_test 1.$tn.1 {
execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c) }
for {set i 0} {$i < 100} {incr i} {
set c [expr int(pow(1.1,$i)/100)]
set b [expr 125 - int(pow(1.1,99-$i))/100]
execsql {INSERT INTO t1 VALUES($i, $b, $c)}
}
} {}
execsql { CREATE INDEX t1b ON t1(b) }
execsql { CREATE INDEX t1c ON t1(c) }
$analyze_cmd
do_execsql_test 1.$tn.2.1 { SELECT count(*) FROM t1 WHERE b=31 } 1
do_execsql_test 1.$tn.2.2 { SELECT count(*) FROM t1 WHERE c=0 } 49
do_execsql_test 1.$tn.2.3 { SELECT count(*) FROM t1 WHERE b=125 } 49
do_execsql_test 1.$tn.2.4 { SELECT count(*) FROM t1 WHERE c=16 } 1
do_eqp_test 1.$tn.2.5 {
SELECT * FROM t1 WHERE b = 31 AND c = 0;
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}}
do_eqp_test 1.$tn.2.6 {
SELECT * FROM t1 WHERE b = 125 AND c = 16;
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c=?)}}
do_execsql_test 1.$tn.3.1 {
SELECT count(*) FROM t1 WHERE b BETWEEN 0 AND 50
} {6}
do_execsql_test 1.$tn.3.2 {
SELECT count(*) FROM t1 WHERE c BETWEEN 0 AND 50
} {90}
do_execsql_test 1.$tn.3.3 {
SELECT count(*) FROM t1 WHERE b BETWEEN 75 AND 125
} {90}
do_execsql_test 1.$tn.3.4 {
SELECT count(*) FROM t1 WHERE c BETWEEN 75 AND 125
} {6}
do_eqp_test 1.$tn.3.5 {
SELECT * FROM t1 WHERE b BETWEEN 0 AND 50 AND c BETWEEN 0 AND 50
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}}
do_eqp_test 1.$tn.3.6 {
SELECT * FROM t1 WHERE b BETWEEN 75 AND 125 AND c BETWEEN 75 AND 125
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}}
}
finish_test
+8 -4
View File
@@ -2325,10 +2325,14 @@ ifcapable compound&&subquery {
}
}
}
ifcapable stat3 {
set stat3 "sqlite_stat3 "
ifcapable stat4 {
set stat4 "sqlite_stat4 "
} else {
set stat3 ""
ifcapable stat3 {
set stat4 "sqlite_stat3 "
} else {
set stat4 ""
}
}
do_test auth-5.2 {
execsql {
@@ -2337,7 +2341,7 @@ ifcapable compound&&subquery {
WHERE type='table'
ORDER BY name
}
} "sqlite_stat1 ${stat3}t1 t2 t3 t4"
} "sqlite_stat1 ${stat4}t1 t2 t3 t4"
}
# Ticket #3944
+2 -2
View File
@@ -61,7 +61,7 @@ proc lookaside {db} {
}
}
ifcapable stat3 {
ifcapable stat4||stat3 {
set STAT3 1
} else {
set STAT3 0
@@ -214,7 +214,7 @@ foreach ::lookaside_buffer_size {0 64 120} {
# much greater than just that reported by DBSTATUS_SCHEMA_USED in this
# case.
#
# Some of the memory used for sqlite_stat3 is unaccounted for by
# Some of the memory used for sqlite_stat4 is unaccounted for by
# dbstatus.
#
# Finally, on osx the estimate of memory used by the schema may be
+3 -3
View File
@@ -149,15 +149,15 @@ do_test index6-2.2 {
SELECT * FROM t2 WHERE a=5;
}
} {/.* TABLE t2 USING INDEX t2a1 .*/}
ifcapable stat3 {
do_test index6-2.3stat3 {
ifcapable stat4||stat3 {
do_test index6-2.3stat4 {
execsql {
EXPLAIN QUERY PLAN
SELECT * FROM t2 WHERE a IS NOT NULL;
}
} {/.* TABLE t2 USING INDEX t2a1 .*/}
} else {
do_test index6-2.3stat3 {
do_test index6-2.3stat4 {
execsql {
EXPLAIN QUERY PLAN
SELECT * FROM t2 WHERE a IS NOT NULL AND a>0;
+31 -1
View File
@@ -15,6 +15,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set testprefix mallocA
# Only run these tests if memory debugging is turned on.
#
@@ -40,7 +41,6 @@ db eval {
db close
copy_file test.db test.db.bu
do_malloc_test mallocA-1 -testdb test.db.bu -sqlbody {
ANALYZE
}
@@ -53,6 +53,7 @@ do_malloc_test mallocA-1.2 -testdb test.db.bu -sqlbody {
do_malloc_test mallocA-1.3 -testdb test.db.bu -sqlbody {
ANALYZE main.t1
}
ifcapable reindex {
do_malloc_test mallocA-2 -testdb test.db.bu -sqlbody {
REINDEX;
@@ -68,6 +69,35 @@ ifcapable reindex {
}
}
reset_db
sqlite3_db_config_lookaside db 0 0 0
do_execsql_test 6-prep {
CREATE TABLE t1(a, b);
CREATE INDEX i1 ON t1(a, b);
INSERT INTO t1 VALUES('abc', 'w'); -- rowid=1
INSERT INTO t1 VALUES('abc', 'x'); -- rowid=2
INSERT INTO t1 VALUES('abc', 'y'); -- rowid=3
INSERT INTO t1 VALUES('abc', 'z'); -- rowid=4
INSERT INTO t1 VALUES('def', 'w'); -- rowid=5
INSERT INTO t1 VALUES('def', 'x'); -- rowid=6
INSERT INTO t1 VALUES('def', 'y'); -- rowid=7
INSERT INTO t1 VALUES('def', 'z'); -- rowid=8
ANALYZE;
}
do_faultsim_test 6.1 -faults oom* -body {
execsql { SELECT rowid FROM t1 WHERE a='abc' AND b='x' }
} -test {
faultsim_test_result [list 0 2]
}
do_faultsim_test 6.2 -faults oom* -body {
execsql { SELECT rowid FROM t1 WHERE a='abc' AND b<'y' }
} -test {
faultsim_test_result [list 0 {1 2}]
}
# Ensure that no file descriptors were leaked.
do_test malloc-99.X {
catch {db close}
+2
View File
@@ -503,6 +503,8 @@ test_suite "utf16" -description {
pragma encoding = 'UTF-16'
} -files {
alter.test alter3.test
analyze.test analyze3.test analyze4.test analyze5.test analyze6.test
analyze7.test analyze8.test analyze9.test analyzeA.test
auth.test bind.test blob.test capi2.test capi3.test collate1.test
collate2.test collate3.test collate4.test collate5.test collate6.test
conflict.test date.test delete.test expr.test fkey1.test func.test
+26
View File
@@ -242,4 +242,30 @@ SELECT * FROM t1;}
5,"this is 5"}}
}
# Import columns containing quoted strings
do_test shell5-1.9 {
set out [open shell5.csv w]
puts $out {1,"",11}
puts $out {2,"x",22}
puts $out {3,"""",33}
puts $out {4,"hello",44}
puts $out "5,55,\"\"\r"
puts $out {6,66,"x"}
puts $out {7,77,""""}
puts $out {8,88,"hello"}
puts $out {"",9,99}
puts $out {"x",10,110}
puts $out {"""",11,121}
puts $out {"hello",12,132}
close $out
file delete -force test.db
catchcmd test.db {.mode csv
CREATE TABLE t1(a,b,c);
.import shell5.csv t1
}
sqlite3 db test.db
db eval {SELECT *, '|' FROM t1 ORDER BY rowid}
} {1 {} 11 | 2 x 22 | 3 {"} 33 | 4 hello 44 | 5 55 {} | 6 66 x | 7 77 {"} | 8 88 hello | {} 9 99 | x 10 110 | {"} 11 121 | hello 12 132 |}
db close
finish_test
+1
View File
@@ -268,6 +268,7 @@ do_test table-5.2.1 {
DROP TABLE IF EXISTS sqlite_stat1;
DROP TABLE IF EXISTS sqlite_stat2;
DROP TABLE IF EXISTS sqlite_stat3;
DROP TABLE IF EXISTS sqlite_stat4;
SELECT name FROM sqlite_master WHERE name GLOB 'sqlite_stat*';
}
} {}
+104 -34
View File
@@ -14,7 +14,7 @@
# $Id: tester.tcl,v 1.143 2009/04/09 01:23:49 drh Exp $
#-------------------------------------------------------------------------
# The commands provided by the code in this file to help with creating
# The commands provided by the code in this file to help with creating
# test cases are as follows:
#
# Commands to manipulate the db and the file-system at a high level:
@@ -42,6 +42,7 @@
#
# Commands to execute/explain SQL statements:
#
# memdbsql SQL
# stepsql DB SQL
# execsql2 SQL
# explain_no_trace SQL
@@ -80,7 +81,7 @@
# presql
#
# Set the precision of FP arithmatic used by the interpreter. And
# Set the precision of FP arithmatic used by the interpreter. And
# configure SQLite to take database file locks on the page that begins
# 64KB into the database file instead of the one 1GB in. This means
# the code that handles that special case can be tested without creating
@@ -90,7 +91,7 @@ set tcl_precision 15
sqlite3_test_control_pending_byte 0x0010000
# If the pager codec is available, create a wrapper for the [sqlite3]
# If the pager codec is available, create a wrapper for the [sqlite3]
# command that appends "-key {xyzzy}" to the command line. i.e. this:
#
# sqlite3 db test.db
@@ -122,7 +123,7 @@ if {[info command sqlite_orig]==""} {
}
set res
} else {
# This command is not opening a new database connection. Pass the
# This command is not opening a new database connection. Pass the
# arguments through to the C implementation as the are.
#
uplevel 1 sqlite_orig $args
@@ -291,6 +292,66 @@ proc do_delete_file {force args} {
}
}
if {$::tcl_platform(platform) eq "windows"} {
proc do_remove_win32_dir {args} {
set nRetry [getFileRetries] ;# Maximum number of retries.
set nDelay [getFileRetryDelay] ;# Delay in ms before retrying.
foreach dirName $args {
# On windows, sometimes even a [remove_win32_dir] can fail just after
# a directory is emptied. The cause is usually "tag-alongs" - programs
# like anti-virus software, automatic backup tools and various explorer
# extensions that keep a file open a little longer than we expect,
# causing the delete to fail.
#
# The solution is to wait a short amount of time before retrying the
# removal.
#
if {$nRetry > 0} {
for {set i 0} {$i < $nRetry} {incr i} {
set rc [catch {
remove_win32_dir $dirName
} msg]
if {$rc == 0} break
if {$nDelay > 0} { after $nDelay }
}
if {$rc} { error $msg }
} else {
remove_win32_dir $dirName
}
}
}
proc do_delete_win32_file {args} {
set nRetry [getFileRetries] ;# Maximum number of retries.
set nDelay [getFileRetryDelay] ;# Delay in ms before retrying.
foreach fileName $args {
# On windows, sometimes even a [delete_win32_file] can fail just after
# a file is closed. The cause is usually "tag-alongs" - programs like
# anti-virus software, automatic backup tools and various explorer
# extensions that keep a file open a little longer than we expect,
# causing the delete to fail.
#
# The solution is to wait a short amount of time before retrying the
# delete.
#
if {$nRetry > 0} {
for {set i 0} {$i < $nRetry} {incr i} {
set rc [catch {
delete_win32_file $fileName
} msg]
if {$rc == 0} break
if {$nDelay > 0} { after $nDelay }
}
if {$rc} { error $msg }
} else {
delete_win32_file $fileName
}
}
}
}
proc execpresql {handle args} {
trace remove execution $handle enter [list execpresql $handle]
if {[info exists ::G(perm:presql)]} {
@@ -312,8 +373,8 @@ proc do_not_use_codec {} {
#
if {[info exists cmdlinearg]==0} {
# Parse any options specified in the $argv array. This script accepts the
# following options:
# Parse any options specified in the $argv array. This script accepts the
# following options:
#
# --pause
# --soft-heap-limit=NN
@@ -342,7 +403,7 @@ if {[info exists cmdlinearg]==0} {
foreach a $argv {
switch -regexp -- $a {
{^-+pause$} {
# Wait for user input before continuing. This is to give the user an
# Wait for user input before continuing. This is to give the user an
# opportunity to connect profiling tools to the process.
puts -nonewline "Press RETURN to begin..."
flush stdout
@@ -405,8 +466,8 @@ if {[info exists cmdlinearg]==0} {
# Install the malloc layer used to inject OOM errors. And the 'automatic'
# extensions. This only needs to be done once for the process.
#
sqlite3_shutdown
install_malloc_faultsim 1
sqlite3_shutdown
install_malloc_faultsim 1
sqlite3_initialize
autoinstall_test_functions
@@ -516,7 +577,7 @@ proc incr_ntest {} {
}
# Invoke the do_test procedure to run a single test
# Invoke the do_test procedure to run a single test
#
proc do_test {name cmd expected} {
global argv cmdlinearg
@@ -525,7 +586,7 @@ proc do_test {name cmd expected} {
sqlite3_memdebug_settitle $name
# if {[llength $argv]==0} {
# if {[llength $argv]==0} {
# set go 1
# } else {
# set go 0
@@ -628,7 +689,7 @@ proc do_realnum_test {name cmd expected} {
proc fix_testname {varname} {
upvar $varname testname
if {[info exists ::testprefix]
if {[info exists ::testprefix]
&& [string is digit [string range $testname 0 0]]
} {
set testname "${::testprefix}-$testname"
@@ -640,7 +701,7 @@ proc normalize_list {L} {
foreach l $L {lappend L2 $l}
set L2
}
proc do_execsql_test {testname sql {result {}}} {
fix_testname testname
uplevel do_test [list $testname] [list "execsql {$sql}"] [list [list {*}$result]]
@@ -726,7 +787,7 @@ proc delete_all_data {} {
}
}
# Run an SQL script.
# Run an SQL script.
# Return the number of microseconds per statement.
#
proc speed_trial {name numstmt units sql} {
@@ -990,6 +1051,15 @@ proc execsql2 {sql} {
return $result
}
# Use a temporary in-memory database to execute SQL statements
#
proc memdbsql {sql} {
sqlite3 memdb :memory:
set result [memdb eval $sql]
memdb close
return $result
}
# Use the non-callback API to execute multiple SQL statements
#
proc stepsql {dbptr sql} {
@@ -1104,7 +1174,7 @@ proc crashsql {args} {
set crashfile ""
set dc ""
set sql [lindex $args end]
for {set ii 0} {$ii < [llength $args]-1} {incr ii 2} {
set z [lindex $args $ii]
set n [string length $z]
@@ -1123,7 +1193,7 @@ proc crashsql {args} {
error "Compulsory option -file missing"
}
# $crashfile gets compared to the native filename in
# $crashfile gets compared to the native filename in
# cfSync(), which can be different then what TCL uses by
# default, so here we force it to the "nativename" format.
set cfile [string map {\\ \\\\} [file nativename [file join [get_pwd] $crashfile]]]
@@ -1158,7 +1228,7 @@ proc crashsql {args} {
set r [catch {
exec [info nameofexec] crash.tcl >@stdout
} msg]
# Windows/ActiveState TCL returns a slightly different
# error message. We map that to the expected message
# so that we don't have to change all of the test
@@ -1168,7 +1238,7 @@ proc crashsql {args} {
set msg "child process exited abnormally"
}
}
lappend r $msg
}
@@ -1194,7 +1264,7 @@ proc run_ioerr_prep {} {
# Usage: do_ioerr_test <test number> <options...>
#
# This proc is used to implement test cases that check that IO errors
# are correctly handled. The first argument, <test number>, is an integer
# are correctly handled. The first argument, <test number>, is an integer
# used to name the tests executed by this proc. Options are as follows:
#
# -tclprep TCL script to run to prepare test.
@@ -1223,7 +1293,7 @@ proc do_ioerr_test {testname args} {
# TEMPORARY: For 3.5.9, disable testing of extended result codes. There are
# a couple of obscure IO errors that do not return them.
set ::ioerropts(-erc) 0
# Create a single TCL script from the TCL and SQL specified
# as the body of the test.
set ::ioerrorbody {}
@@ -1247,7 +1317,7 @@ proc do_ioerr_test {testname args} {
set ::TN $n
incr ::ioerropts(-count) -1
if {$::ioerropts(-count)<0} break
# Skip this IO error if it was specified with the "-exclude" option.
if {[info exists ::ioerropts(-exclude)]} {
if {[lsearch $::ioerropts(-exclude) $n]!=-1} continue
@@ -1256,7 +1326,7 @@ proc do_ioerr_test {testname args} {
restore_prng_state
}
# Delete the files test.db and test2.db, then execute the TCL and
# Delete the files test.db and test2.db, then execute the TCL and
# SQL (in that order) to prepare for the test case.
do_test $testname.$n.1 {
run_ioerr_prep
@@ -1274,7 +1344,7 @@ proc do_ioerr_test {testname args} {
}] $n
# Execute the TCL script created for the body of this test. If
# at least N IO operations performed by SQLite as a result of
# at least N IO operations performed by SQLite as a result of
# the script, the Nth will fail.
do_test $testname.$n.3 {
set ::sqlite_io_error_hit 0
@@ -1328,12 +1398,12 @@ proc do_ioerr_test {testname args} {
set ::sqlite_io_error_hit 0
set ::sqlite_io_error_pending 0
# Check that no page references were leaked. There should be
# a single reference if there is still an active transaction,
# Check that no page references were leaked. There should be
# a single reference if there is still an active transaction,
# or zero otherwise.
#
# UPDATE: If the IO error occurs after a 'BEGIN' but before any
# locks are established on database files (i.e. if the error
# locks are established on database files (i.e. if the error
# occurs while attempting to detect a hot-journal file), then
# there may 0 page references and an active transaction according
# to [sqlite3_get_autocommit].
@@ -1349,7 +1419,7 @@ proc do_ioerr_test {testname args} {
} {1}
}
# If there is an open database handle and no open transaction,
# If there is an open database handle and no open transaction,
# and the pager is not running in exclusive-locking mode,
# check that the pager is in "unlocked" state. Theoretically,
# if a call to xUnlock() failed due to an IO error the underlying
@@ -1453,7 +1523,7 @@ proc allcksum {{db db}} {
}
# Generate a checksum based on the contents of a single database with
# a database connection. The name of the database is $dbname.
# a database connection. The name of the database is $dbname.
# Examples of $dbname are "temp" or "main".
#
proc dbcksum {db dbname} {
@@ -1547,8 +1617,8 @@ proc drop_all_tables {{db db}} {
#-------------------------------------------------------------------------
# If a test script is executed with global variable $::G(perm:name) set to
# "wal", then the tests are run in WAL mode. Otherwise, they should be run
# in rollback mode. The following Tcl procs are used to make this less
# "wal", then the tests are run in WAL mode. Otherwise, they should be run
# in rollback mode. The following Tcl procs are used to make this less
# intrusive:
#
# wal_set_journal_mode ?DB?
@@ -1563,9 +1633,9 @@ proc drop_all_tables {{db db}} {
# Otherwise (if not running a WAL permutation) this is a no-op.
#
# wal_is_wal_mode
#
#
# Returns true if this test should be run in WAL mode. False otherwise.
#
#
proc wal_is_wal_mode {} {
expr {[permutation] eq "wal"}
}
@@ -1666,10 +1736,10 @@ proc slave_test_file {zFile} {
}
set ::sqlite_open_file_count 0
# Test that the global "shared-cache" setting was not altered by
# Test that the global "shared-cache" setting was not altered by
# the test script.
#
ifcapable shared_cache {
ifcapable shared_cache {
set res [expr {[sqlite3_enable_shared_cache] == $scs}]
do_test ${tail}-sharedcachesetting [list set {} $res] 1
}
+79
View File
@@ -0,0 +1,79 @@
# 2013 August 29
#
# 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 regression tests for SQLite library.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set ::testprefix tkt-9f2eb3abac
do_execsql_test 1.1 {
CREATE TABLE t1(a,b,c,d,e, PRIMARY KEY(a,b,c,d,e));
SELECT * FROM t1 WHERE a=? AND b=? AND c=? AND d=? AND e=?;
} {}
do_execsql_test 1.2 {
CREATE TABLE "a" (
"b" integer NOT NULL,
"c" integer NOT NULL,
PRIMARY KEY ("b", "c")
);
CREATE TABLE "d" (
"e" integer NOT NULL,
"g" integer NOT NULL,
"f" integer NOT NULL,
"h" integer NOT NULL,
"i" character(10) NOT NULL,
"j" int,
PRIMARY KEY ("e", "g", "f", "h")
);
CREATE TABLE "d_to_a" (
"f_e" integer NOT NULL,
"f_g" integer NOT NULL,
"f_f" integer NOT NULL,
"f_h" integer NOT NULL,
"t_b" integer NOT NULL,
"t_c" integer NOT NULL,
"r" character NOT NULL,
"s" integer,
PRIMARY KEY ("f_e", "f_g", "f_f", "f_h", "t_b", "t_c")
);
INSERT INTO d (g, e, h, f, j, i) VALUES ( 1, 1, 1, 1, 1, 1 );
INSERT INTO a (b, c) VALUES ( 1, 1 );
INSERT INTO d_to_a VALUES (1, 1, 1, 1, 1, 1, 1, 1);
DELETE FROM d_to_a
WHERE f_g = 1 AND f_e = 1 AND f_h = 1 AND f_f = 1 AND t_b = 1 AND t_c = 1;
SELECT * FROM d_to_a;
} {}
faultsim_delete_and_reopen
do_execsql_test 2.0 { CREATE TABLE t1(a,b,c,d,e, PRIMARY KEY(a,b,c,d,e)) }
do_execsql_test 2.1 { CREATE TABLE t2(x) }
faultsim_save_and_close
do_faultsim_test 3 -faults oom* -prep {
faultsim_restore_and_reopen
execsql { SELECT 1 FROM sqlite_master }
} -body {
execsql { SELECT * FROM t1,t2 WHERE a=? AND b=? AND c=? AND d=? AND e=? }
} -test {
faultsim_test_result {0 {}}
}
finish_test
+36 -9
View File
@@ -16,11 +16,26 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !stat3 {
ifcapable !stat4&&!stat3 {
finish_test
return
}
proc s {blob} {
set ret ""
binary scan $blob c* bytes
foreach b $bytes {
set t [binary format c $b]
if {[string is print $t]} {
append ret $t
} else {
append ret .
}
}
return $ret
}
db function s s
do_test tkt-cbd05-1.1 {
db eval {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT UNIQUE NOT NULL);
@@ -39,18 +54,30 @@ do_test tkt-cbd05-1.1 {
}
} {10}
do_test tkt-cbd05-1.2 {
db eval {
ANALYZE;
db eval { ANALYZE; }
ifcapable stat4 {
db eval {
PRAGMA writable_schema = 1;
CREATE VIEW vvv AS
SELECT tbl,idx,neq,nlt,ndlt,test_extract(sample,0) AS sample
FROM sqlite_stat4;
PRAGMA writable_schema = 0;
}
} else {
db eval {
CREATE VIEW vvv AS
SELECT tbl,idx,neq,nlt,ndlt,sample FROM sqlite_stat3;
}
}
} {}
do_test tkt-cbd05-1.3 {
execsql {
SELECT tbl,idx,group_concat(sample,' ')
FROM sqlite_stat3
SELECT tbl,idx,group_concat(s(sample),' ')
FROM vvv
WHERE idx = 't1_x'
GROUP BY tbl,idx
}
} {/t1 t1_x .[ ABCDEFGHI]{10}./}
} {t1 t1_x { A B C D E F G H I}}
do_test tkt-cbd05-2.1 {
db eval {
@@ -77,11 +104,11 @@ do_test tkt-cbd05-2.2 {
} {}
do_test tkt-cbd05-2.3 {
execsql {
SELECT tbl,idx,group_concat(sample,' ')
FROM sqlite_stat3
SELECT tbl,idx,group_concat(s(sample),' ')
FROM vvv
WHERE idx = 't1_x'
GROUP BY tbl,idx
}
} {/t1 t1_x .[ ABCDEFGHI]{10}./}
} {t1 t1_x { A B C D E F G H I}}
finish_test
+32 -3
View File
@@ -781,11 +781,11 @@ do_test where9-6.8.2 {
OR (b NOT NULL AND c NOT NULL AND d IS NULL)
}
} {1 {no query solution}}
ifcapable stat3 {
ifcapable stat4||stat3 {
# When STAT3 is enabled, the "b NOT NULL" terms get translated
# into b>NULL, which can be satified by the index t1b. It is a very
# expensive way to do the query, but it works, and so a solution is possible.
do_test where9-6.8.3-stat3 {
do_test where9-6.8.3-stat4 {
catchsql {
UPDATE t1 INDEXED BY t1b SET a=a+100
WHERE (b IS NULL AND c NOT NULL AND d NOT NULL)
@@ -793,7 +793,7 @@ ifcapable stat3 {
OR (b NOT NULL AND c NOT NULL AND d IS NULL)
}
} {0 {}}
do_test where9-6.8.4-stat3 {
do_test where9-6.8.4-stat4 {
catchsql {
DELETE FROM t1 INDEXED BY t1b
WHERE (b IS NULL AND c NOT NULL AND d NOT NULL)
@@ -851,6 +851,11 @@ do_test where9-7.0 {
INSERT INTO t6 SELECT * FROM t5;
ANALYZE t5;
}
ifcapable stat3 {
sqlite3 db2 test.db
db2 eval { DROP TABLE IF EXISTS sqlite_stat3 }
db2 close
}
} {}
do_test where9-7.1.1 {
count_steps {
@@ -951,4 +956,28 @@ do_test where9-9.1 {
}
} {1 2 3 4 8 9}
# Fix for ticket [bc878246eafe0f52c519e29049b2fe4a99491b27]
# Incorrect result when OR is used in a join to the right of a LEFT JOIN
#
do_test where9-10.1 {
db eval {
CREATE TABLE t101 (id INTEGER PRIMARY KEY);
INSERT INTO t101 VALUES (1);
SELECT * FROM t101 AS t0
LEFT JOIN t101 AS t1 ON t1.id BETWEEN 10 AND 20
JOIN t101 AS t2 ON (t2.id = t0.id OR (t2.id<>555 AND t2.id=t1.id));
}
} {1 {} 1}
do_test where9-10.2 {
db eval {
CREATE TABLE t102 (id TEXT UNIQUE NOT NULL);
INSERT INTO t102 VALUES ('1');
SELECT * FROM t102 AS t0
LEFT JOIN t102 AS t1 ON t1.id GLOB 'abc%'
JOIN t102 AS t2 ON (t2.id = t0.id OR (t2.id<>555 AND t2.id=t1.id));
}
} {1 {} 1}
finish_test
+102
View File
@@ -0,0 +1,102 @@
# 2013 August 27
#
# 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 regression tests for SQLite library. The
# focus of this script is testing the file name handling provided
# by the "win32-longpath" VFS.
#
if {$tcl_platform(platform)!="windows"} return
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix win32longpath
db close
set path [file nativename [get_pwd]]
sqlite3 db [file join $path test.db] -vfs win32-longpath
do_test 1.1 {
db eval {
BEGIN EXCLUSIVE;
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(1);
INSERT INTO t1 VALUES(2);
INSERT INTO t1 VALUES(3);
INSERT INTO t1 VALUES(4);
SELECT x FROM t1 ORDER BY x;
COMMIT;
}
} {1 2 3 4}
set longPath(1) \\\\?\\$path\\[pid]
make_win32_dir $longPath(1)
set longPath(2) $longPath(1)\\[string repeat X 255]
make_win32_dir $longPath(2)
set longPath(3) $longPath(2)\\[string repeat Y 255]
make_win32_dir $longPath(3)
set fileName $longPath(3)\\test.db
do_test 1.2 {
list [catch {sqlite3 db2 [string range $fileName 4 end]} msg] $msg
} {1 {unable to open database file}}
sqlite3 db3 $fileName -vfs win32-longpath
do_test 1.3 {
db3 eval {
BEGIN EXCLUSIVE;
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(5);
INSERT INTO t1 VALUES(6);
INSERT INTO t1 VALUES(7);
INSERT INTO t1 VALUES(8);
SELECT x FROM t1 ORDER BY x;
COMMIT;
}
} {5 6 7 8}
db3 close
# puts " Database exists \{[exists_win32_path $fileName]\}"
sqlite3 db3 $fileName -vfs win32-longpath
do_test 1.4 {
db3 eval {
PRAGMA journal_mode = WAL;
}
} {wal}
do_test 1.5 {
db3 eval {
BEGIN EXCLUSIVE;
INSERT INTO t1 VALUES(9);
INSERT INTO t1 VALUES(10);
INSERT INTO t1 VALUES(11);
INSERT INTO t1 VALUES(12);
SELECT x FROM t1 ORDER BY x;
COMMIT;
}
} {5 6 7 8 9 10 11 12}
db3 close
# puts " Database exists \{[exists_win32_path $fileName]\}"
do_delete_win32_file $fileName
# puts " Files remaining \{[find_win32_file $longPath(3)\\*]\}"
do_remove_win32_dir $longPath(3)
do_remove_win32_dir $longPath(2)
do_remove_win32_dir $longPath(1)
finish_test