Snapshot of upstream SQLite 3.25.0

This commit is contained in:
Stephen Lombardo
2018-09-18 12:31:37 -04:00
parent 1f3bc22483
commit bf3fa86130
558 changed files with 76379 additions and 20890 deletions
+1 -1
View File
@@ -65,7 +65,7 @@ do_test aggnested-2.0 {
t1.*
FROM t1;
}
} {A,B,B 3 33 333 3333}
} {A,B,B 1 11 111 1111}
db2 close
##################### Test cases for ticket [bfbf38e5e9956ac69f] ############
+1
View File
@@ -16,6 +16,7 @@ source $testdir/permutations.test
run_test_suite full
ifcapable rbu { run_test_suite rbu }
run_test_suite no_optimization
run_test_suite memsubsys1
run_test_suite memsubsys2
+13 -59
View File
@@ -681,21 +681,21 @@ do_test alter-8.2 {
} {1 18 2 9}
#--------------------------------------------------------------------------
# alter-9.X - Special test: Make sure the sqlite_rename_trigger() and
# alter-9.X - Special test: Make sure the sqlite_rename_column() and
# rename_table() functions do not crash when handed bad input.
#
ifcapable trigger {
do_test alter-9.1 {
execsql {SELECT SQLITE_RENAME_TRIGGER(0,0)}
} {{}}
do_test alter-9.1 {
execsql {SELECT SQLITE_RENAME_COLUMN(0,0,0,0,0,0,0,0,0)}
} {{}}
foreach {tn sql} {
1 { SELECT SQLITE_RENAME_TABLE(0,0,0,0,0,0,0) }
2 { SELECT SQLITE_RENAME_TABLE(10,20,30,40,50,60,70) }
3 { SELECT SQLITE_RENAME_TABLE('foo','foo','foo','foo','foo','foo','foo') }
} {
do_test alter-9.2.$tn {
catch { execsql $sql }
} 1
}
do_test alter-9.2 {
execsql {
SELECT SQLITE_RENAME_TABLE(0,0);
SELECT SQLITE_RENAME_TABLE(10,20);
SELECT SQLITE_RENAME_TABLE('foo', 'foo');
}
} {{} {} {}}
#------------------------------------------------------------------------
# alter-10.X - Make sure ALTER TABLE works with multi-byte UTF-8 characters
@@ -875,51 +875,5 @@ do_execsql_test alter-16.2 {
SELECT * FROM t16a_rn ORDER BY a;
} {abc 1.25 99 xyzzy cba 5.5 98 fizzle}
#-------------------------------------------------------------------------
# Verify that NULL values into the internal-use-only sqlite_rename_*()
# functions do not cause problems.
#
do_execsql_test alter-17.1 {
SELECT sqlite_rename_table('CREATE TABLE xyz(a,b,c)','abc');
} {{CREATE TABLE "abc"(a,b,c)}}
do_execsql_test alter-17.2 {
SELECT sqlite_rename_table('CREATE TABLE xyz(a,b,c)',NULL);
} {{CREATE TABLE "(NULL)"(a,b,c)}}
do_execsql_test alter-17.3 {
SELECT sqlite_rename_table(NULL,'abc');
} {{}}
do_execsql_test alter-17.4 {
SELECT sqlite_rename_trigger('CREATE TRIGGER r1 ON xyz WHEN','abc');
} {{CREATE TRIGGER r1 ON "abc" WHEN}}
do_execsql_test alter-17.5 {
SELECT sqlite_rename_trigger('CREATE TRIGGER r1 ON xyz WHEN',NULL);
} {{CREATE TRIGGER r1 ON "(NULL)" WHEN}}
do_execsql_test alter-17.6 {
SELECT sqlite_rename_trigger(NULL,'abc');
} {{}}
do_execsql_test alter-17.7 {
SELECT sqlite_rename_parent('CREATE TABLE t1(a REFERENCES "xyzzy")',
'xyzzy','lmnop');
} {{CREATE TABLE t1(a REFERENCES "lmnop")}}
do_execsql_test alter-17.8 {
SELECT sqlite_rename_parent('CREATE TABLE t1(a REFERENCES "xyzzy")',
'xyzzy',NULL);
} {{CREATE TABLE t1(a REFERENCES "(NULL)")}}
do_execsql_test alter-17.9 {
SELECT sqlite_rename_parent('CREATE TABLE t1(a REFERENCES "xyzzy")',
NULL, 'lmnop');
} {{}}
do_execsql_test alter-17.10 {
SELECT sqlite_rename_parent(NULL,'abc','xyz');
} {{}}
do_execsql_test alter-17.11 {
SELECT sqlite_rename_parent('create references ''','abc','xyz');
} {{create references '}}
do_execsql_test alter-17.12 {
SELECT sqlite_rename_parent('create references "abc"123" ','abc','xyz');
} {{create references "xyz"123" }}
do_execsql_test alter-17.13 {
SELECT sqlite_rename_parent("references '''",'abc','xyz');
} {{references '''}}
finish_test
+28
View File
@@ -394,4 +394,32 @@ do_test alter4-10.1 {
}
} {ok}
reset_db
do_execsql_test alter4-11.0 {
CREATE TABLE t1(c INTEGER PRIMARY KEY, d);
PRAGMA foreign_keys = on;
ALTER TABLE t1 ADD COLUMN e;
}
do_execsql_test alter4-11.1 {
ALTER TABLE t1 ADD COLUMN f REFERENCES t1;
}
do_catchsql_test alter4-11.2 {
ALTER TABLE t1 ADD COLUMN g REFERENCES t1 DEFAULT 4;
} {1 {Cannot add a REFERENCES column with non-NULL default value}}
do_catchsql_test alter4-11.3 {
ALTER TABLE t2 ADD COLUMN g;
} {1 {no such table: t2}}
ifcapable fts5 {
do_execsql_test alter4-11.4 {
CREATE VIRTUAL TABLE fff USING fts5(f);
}
do_catchsql_test alter4-11.2 {
ALTER TABLE fff ADD COLUMN g;
} {1 {virtual tables may not be altered}}
}
finish_test
+72
View File
@@ -0,0 +1,72 @@
# 2018 September 2
#
# 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.
#
#*************************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
ifcapable !altertable {
finish_test
return
}
set testprefix alterauth
set ::auth [list]
proc xAuth {type args} {
if {$type == "SQLITE_ALTER_TABLE"} {
lappend ::auth [concat $type $args]
}
return SQLITE_OK
}
db auth xAuth
do_execsql_test 1.0 { CREATE TABLE t1(a, b, c); }
do_test 1.1 {
set ::auth [list]
execsql { ALTER TABLE t1 RENAME TO t2 }
set ::auth
} {{SQLITE_ALTER_TABLE main t1 {} {}}}
do_test 1.2 {
set ::auth [list]
execsql { ALTER TABLE t2 RENAME c TO ccc }
set ::auth
} {{SQLITE_ALTER_TABLE main t2 {} {}}}
do_test 1.3 {
set ::auth [list]
execsql { ALTER TABLE t2 ADD COLUMN d }
set ::auth
} {{SQLITE_ALTER_TABLE main t2 {} {}}}
proc xAuth {type args} {
if {$type == "SQLITE_ALTER_TABLE"} {
return SQLITE_DENY
}
return SQLITE_OK
}
do_test 2.1 {
catchsql { ALTER TABLE t2 RENAME TO t3 }
} {1 {not authorized}}
do_test 2.2 {
catchsql { ALTER TABLE t2 RENAME d TO ddd }
} {1 {not authorized}}
do_test 2.3 {
catchsql { ALTER TABLE t2 ADD COLUMN e }
} {1 {not authorized}}
finish_test
+772
View File
@@ -0,0 +1,772 @@
# 2009 February 2
#
# 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 that SQLite can handle a subtle
# file format change that may be used in the future to implement
# "ALTER TABLE ... RENAME COLUMN ... TO".
#
# $Id: alter4.test,v 1.1 2009/02/02 18:03:22 drh Exp $
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix altercol
# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
ifcapable !altertable {
finish_test
return
}
# Drop all the tables and views in the 'main' database of database connect
# [db]. Sort the objects by name before dropping them.
#
proc drop_all_tables_and_views {db} {
set SQL {
SELECT name, type FROM sqlite_master
WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%'
ORDER BY 1
}
foreach {z t} [db eval $SQL] {
db eval "DROP $t $z"
}
}
foreach {tn before after} {
1 {CREATE TABLE t1(a INTEGER, b TEXT, c BLOB)}
{CREATE TABLE t1(a INTEGER, d TEXT, c BLOB)}
2 {CREATE TABLE t1(a INTEGER, x TEXT, "b" BLOB)}
{CREATE TABLE t1(a INTEGER, x TEXT, "d" BLOB)}
3 {CREATE TABLE t1(a INTEGER, b TEXT, c BLOB, CHECK(b!=''))}
{CREATE TABLE t1(a INTEGER, d TEXT, c BLOB, CHECK(d!=''))}
4 {CREATE TABLE t1(a INTEGER, b TEXT, c BLOB, CHECK(t1.b!=''))}
{CREATE TABLE t1(a INTEGER, d TEXT, c BLOB, CHECK(t1.d!=''))}
5 {CREATE TABLE t1(a INTEGER, b TEXT, c BLOB, CHECK( coalesce(b,c) ))}
{CREATE TABLE t1(a INTEGER, d TEXT, c BLOB, CHECK( coalesce(d,c) ))}
6 {CREATE TABLE t1(a INTEGER, "b"TEXT, c BLOB, CHECK( coalesce(b,c) ))}
{CREATE TABLE t1(a INTEGER, "d"TEXT, c BLOB, CHECK( coalesce(d,c) ))}
7 {CREATE TABLE t1(a INTEGER, b TEXT, c BLOB, PRIMARY KEY(b, c))}
{CREATE TABLE t1(a INTEGER, d TEXT, c BLOB, PRIMARY KEY(d, c))}
8 {CREATE TABLE t1(a INTEGER, b TEXT PRIMARY KEY, c BLOB)}
{CREATE TABLE t1(a INTEGER, d TEXT PRIMARY KEY, c BLOB)}
9 {CREATE TABLE t1(a, b TEXT, c, PRIMARY KEY(a, b), UNIQUE("B"))}
{CREATE TABLE t1(a, d TEXT, c, PRIMARY KEY(a, d), UNIQUE("d"))}
10 {CREATE TABLE t1(a, b, c); CREATE INDEX t1i ON t1(a, c)}
{{CREATE TABLE t1(a, d, c)} {CREATE INDEX t1i ON t1(a, c)}}
11 {CREATE TABLE t1(a, b, c); CREATE INDEX t1i ON t1(b, c)}
{{CREATE TABLE t1(a, d, c)} {CREATE INDEX t1i ON t1(d, c)}}
12 {CREATE TABLE t1(a, b, c); CREATE INDEX t1i ON t1(b+b+b+b, c) WHERE b>0}
{{CREATE TABLE t1(a, d, c)} {CREATE INDEX t1i ON t1(d+d+d+d, c) WHERE d>0}}
13 {CREATE TABLE t1(a, b, c, FOREIGN KEY (b) REFERENCES t2)}
{CREATE TABLE t1(a, d, c, FOREIGN KEY (d) REFERENCES t2)}
14 {CREATE TABLE t1(a INTEGER, b TEXT, c BLOB, PRIMARY KEY(b))}
{CREATE TABLE t1(a INTEGER, d TEXT, c BLOB, PRIMARY KEY(d))}
15 {CREATE TABLE t1(a INTEGER, b INTEGER, c BLOB, PRIMARY KEY(b))}
{CREATE TABLE t1(a INTEGER, d INTEGER, c BLOB, PRIMARY KEY(d))}
16 {CREATE TABLE t1(a INTEGER, b INTEGER PRIMARY KEY, c BLOB)}
{CREATE TABLE t1(a INTEGER, d INTEGER PRIMARY KEY, c BLOB)}
17 {CREATE TABLE t1(a INTEGER, b INTEGER PRIMARY KEY, c BLOB, FOREIGN KEY (b) REFERENCES t2)}
{CREATE TABLE t1(a INTEGER, d INTEGER PRIMARY KEY, c BLOB, FOREIGN KEY (d) REFERENCES t2)}
} {
reset_db
do_execsql_test 1.$tn.0 $before
do_execsql_test 1.$tn.1 {
INSERT INTO t1 VALUES(1, 2, 3);
}
do_execsql_test 1.$tn.2 {
ALTER TABLE t1 RENAME COLUMN b TO d;
}
do_execsql_test 1.$tn.3 {
SELECT * FROM t1;
} {1 2 3}
if {[string first INDEX $before]>0} {
set res $after
} else {
set res [list $after]
}
do_execsql_test 1.$tn.4 {
SELECT sql FROM sqlite_master WHERE tbl_name='t1' AND sql!=''
} $res
}
#-------------------------------------------------------------------------
#
do_execsql_test 2.0 {
CREATE TABLE t3(a, b, c, d, e, f, g, h, i, j, k, l, m, FOREIGN KEY (b, c, d, e, f, g, h, i, j, k, l, m) REFERENCES t4);
}
sqlite3 db2 test.db
do_execsql_test -db db2 2.1 { SELECT b FROM t3 }
do_execsql_test 2.2 {
ALTER TABLE t3 RENAME b TO biglongname;
SELECT sql FROM sqlite_master WHERE name='t3';
} {{CREATE TABLE t3(a, biglongname, c, d, e, f, g, h, i, j, k, l, m, FOREIGN KEY (biglongname, c, d, e, f, g, h, i, j, k, l, m) REFERENCES t4)}}
do_execsql_test -db db2 2.3 { SELECT biglongname FROM t3 }
#-------------------------------------------------------------------------
#
do_execsql_test 3.0 {
CREATE TABLE t4(x, y, z);
CREATE TRIGGER ttt AFTER INSERT ON t4 WHEN new.y<0 BEGIN
SELECT x, y, z FROM t4;
DELETE FROM t4 WHERE y=32;
UPDATE t4 SET x=y+1, y=0 WHERE y=32;
INSERT INTO t4(x, y, z) SELECT 4, 5, 6 WHERE 0;
END;
INSERT INTO t4 VALUES(3, 2, 1);
}
do_execsql_test 3.1 {
ALTER TABLE t4 RENAME y TO abc;
SELECT sql FROM sqlite_master WHERE name='t4';
} {{CREATE TABLE t4(x, abc, z)}}
do_execsql_test 3.2 {
SELECT * FROM t4;
} {3 2 1}
do_execsql_test 3.3 { INSERT INTO t4 VALUES(6, 5, 4); } {}
do_execsql_test 3.4 { SELECT sql FROM sqlite_master WHERE type='trigger' } {
{CREATE TRIGGER ttt AFTER INSERT ON t4 WHEN new.abc<0 BEGIN
SELECT x, abc, z FROM t4;
DELETE FROM t4 WHERE abc=32;
UPDATE t4 SET x=abc+1, abc=0 WHERE abc=32;
INSERT INTO t4(x, abc, z) SELECT 4, 5, 6 WHERE 0;
END}
}
#-------------------------------------------------------------------------
#
do_execsql_test 4.0 {
CREATE TABLE c1(a, b, FOREIGN KEY (a, b) REFERENCES p1(c, d));
CREATE TABLE p1(c, d, PRIMARY KEY(c, d));
PRAGMA foreign_keys = 1;
INSERT INTO p1 VALUES(1, 2);
INSERT INTO p1 VALUES(3, 4);
}
do_execsql_test 4.1 {
ALTER TABLE p1 RENAME d TO "silly name";
SELECT sql FROM sqlite_master WHERE name IN ('c1', 'p1');
} {
{CREATE TABLE c1(a, b, FOREIGN KEY (a, b) REFERENCES p1(c, "silly name"))}
{CREATE TABLE p1(c, "silly name", PRIMARY KEY(c, "silly name"))}
}
do_execsql_test 4.2 { INSERT INTO c1 VALUES(1, 2); }
do_execsql_test 4.3 {
CREATE TABLE c2(a, b, FOREIGN KEY (a, b) REFERENCES p1);
}
do_execsql_test 4.4 {
ALTER TABLE p1 RENAME "silly name" TO reasonable;
SELECT sql FROM sqlite_master WHERE name IN ('c1', 'c2', 'p1');
} {
{CREATE TABLE c1(a, b, FOREIGN KEY (a, b) REFERENCES p1(c, "reasonable"))}
{CREATE TABLE p1(c, "reasonable", PRIMARY KEY(c, "reasonable"))}
{CREATE TABLE c2(a, b, FOREIGN KEY (a, b) REFERENCES p1)}
}
#-------------------------------------------------------------------------
do_execsql_test 5.0 {
CREATE TABLE t5(a, b, c);
CREATE INDEX t5a ON t5(a);
INSERT INTO t5 VALUES(1, 2, 3), (4, 5, 6);
ANALYZE;
}
do_execsql_test 5.1 {
ALTER TABLE t5 RENAME b TO big;
SELECT big FROM t5;
} {2 5}
do_catchsql_test 6.1 {
ALTER TABLE sqlite_stat1 RENAME tbl TO thetable;
} {1 {table sqlite_stat1 may not be altered}}
#-------------------------------------------------------------------------
#
do_execsql_test 6.0 {
CREATE TABLE blob(
rid INTEGER PRIMARY KEY,
rcvid INTEGER,
size INTEGER,
uuid TEXT UNIQUE NOT NULL,
content BLOB,
CHECK( length(uuid)>=40 AND rid>0 )
);
}
do_execsql_test 6.1 {
ALTER TABLE "blob" RENAME COLUMN "rid" TO "a1";
}
do_catchsql_test 6.2 {
ALTER TABLE "blob" RENAME COLUMN "a1" TO [where];
} {0 {}}
do_execsql_test 6.3 {
SELECT "where" FROM blob;
} {}
#-------------------------------------------------------------------------
# Triggers.
#
db close
db2 close
reset_db
do_execsql_test 7.0 {
CREATE TABLE c(x);
INSERT INTO c VALUES(0);
CREATE TABLE t6("col a", "col b", "col c");
CREATE TRIGGER zzz AFTER UPDATE OF "col a", "col c" ON t6 BEGIN
UPDATE c SET x=x+1;
END;
}
do_execsql_test 7.1.1 {
INSERT INTO t6 VALUES(0, 0, 0);
UPDATE t6 SET "col c" = 1;
SELECT * FROM c;
} {1}
do_execsql_test 7.1.2 {
ALTER TABLE t6 RENAME "col c" TO "col 3";
}
do_execsql_test 7.1.3 {
UPDATE t6 SET "col 3" = 0;
SELECT * FROM c;
} {2}
#-------------------------------------------------------------------------
# Views.
#
reset_db
do_execsql_test 8.0 {
CREATE TABLE a1(x INTEGER, y TEXT, z BLOB, PRIMARY KEY(x));
CREATE TABLE a2(a, b, c);
CREATE VIEW v1 AS SELECT x, y, z FROM a1;
}
do_execsql_test 8.1 {
ALTER TABLE a1 RENAME y TO yyy;
SELECT sql FROM sqlite_master WHERE type='view';
} {{CREATE VIEW v1 AS SELECT x, yyy, z FROM a1}}
do_execsql_test 8.2.1 {
DROP VIEW v1;
CREATE VIEW v2 AS SELECT x, x+x, a, a+a FROM a1, a2;
} {}
do_execsql_test 8.2.2 {
ALTER TABLE a1 RENAME x TO xxx;
}
do_execsql_test 8.2.3 {
SELECT sql FROM sqlite_master WHERE type='view';
} {{CREATE VIEW v2 AS SELECT xxx, xxx+xxx, a, a+a FROM a1, a2}}
do_execsql_test 8.3.1 {
DROP TABLE a2;
DROP VIEW v2;
CREATE TABLE a2(a INTEGER PRIMARY KEY, b, c);
CREATE VIEW v2 AS SELECT xxx, xxx+xxx, a, a+a FROM a1, a2;
} {}
do_execsql_test 8.3.2 {
ALTER TABLE a1 RENAME xxx TO x;
}
do_execsql_test 8.3.3 {
SELECT sql FROM sqlite_master WHERE type='view';
} {{CREATE VIEW v2 AS SELECT x, x+x, a, a+a FROM a1, a2}}
do_execsql_test 8.4.0 {
CREATE TABLE b1(a, b, c);
CREATE TABLE b2(x, y, z);
}
do_execsql_test 8.4.1 {
CREATE VIEW vvv AS SELECT c+c || coalesce(c, c) FROM b1, b2 WHERE x=c GROUP BY c HAVING c>0;
ALTER TABLE b1 RENAME c TO "a;b";
SELECT sql FROM sqlite_master WHERE name='vvv';
} {{CREATE VIEW vvv AS SELECT "a;b"+"a;b" || coalesce("a;b", "a;b") FROM b1, b2 WHERE x="a;b" GROUP BY "a;b" HAVING "a;b">0}}
do_execsql_test 8.4.2 {
CREATE VIEW www AS SELECT b FROM b1 UNION ALL SELECT y FROM b2;
ALTER TABLE b1 RENAME b TO bbb;
SELECT sql FROM sqlite_master WHERE name='www';
} {{CREATE VIEW www AS SELECT bbb FROM b1 UNION ALL SELECT y FROM b2}}
db collate nocase {string compare}
do_execsql_test 8.4.3 {
CREATE VIEW xxx AS SELECT a FROM b1 UNION SELECT x FROM b2 ORDER BY 1 COLLATE nocase;
}
do_execsql_test 8.4.4 {
ALTER TABLE b2 RENAME x TO hello;
SELECT sql FROM sqlite_master WHERE name='xxx';
} {{CREATE VIEW xxx AS SELECT a FROM b1 UNION SELECT hello FROM b2 ORDER BY 1 COLLATE nocase}}
do_catchsql_test 8.4.5 {
CREATE VIEW zzz AS SELECT george, ringo FROM b1;
ALTER TABLE b1 RENAME a TO aaa;
} {1 {error in view zzz: no such column: george}}
#-------------------------------------------------------------------------
# More triggers.
#
proc do_rename_column_test {tn old new lSchema} {
for {set i 0} {$i < 2} {incr i} {
drop_all_tables_and_views db
set lSorted [list]
foreach sql $lSchema {
execsql $sql
lappend lSorted [string trim $sql]
}
set lSorted [lsort $lSorted]
do_execsql_test $tn.$i.1 {
SELECT sql FROM sqlite_master WHERE sql!='' ORDER BY 1
} $lSorted
if {$i==1} {
db close
sqlite3 db test.db
}
do_execsql_test $tn.$i.2 "ALTER TABLE t1 RENAME $old TO $new"
do_execsql_test $tn.$i.3 {
SELECT sql FROM sqlite_master ORDER BY 1
} [string map [list $old $new] $lSorted]
}
}
foreach {tn old new lSchema} {
1 _x_ _xxx_ {
{ CREATE TABLE t1(a, b, _x_) }
{ CREATE TRIGGER AFTER INSERT ON t1 BEGIN
SELECT _x_ FROM t1;
END }
}
2 _x_ _xxx_ {
{ CREATE TABLE t1(a, b, _x_) }
{ CREATE TABLE t2(c, d, e) }
{ CREATE TRIGGER ttt AFTER INSERT ON t2 BEGIN
SELECT _x_ FROM t1;
END }
}
3 _x_ _xxx_ {
{ CREATE TABLE t1(a, b, _x_ INTEGER, PRIMARY KEY(_x_), CHECK(_x_>0)) }
{ CREATE TABLE t2(c, d, e) }
{ CREATE TRIGGER ttt AFTER UPDATE ON t1 BEGIN
INSERT INTO t2 VALUES(new.a, new.b, new._x_);
END }
}
4 _x_ _xxx_ {
{ CREATE TABLE t1(a, b, _x_ INTEGER, PRIMARY KEY(_x_), CHECK(_x_>0)) }
{ CREATE TRIGGER ttt AFTER UPDATE ON t1 BEGIN
INSERT INTO t1 VALUES(new.a, new.b, new._x_)
ON CONFLICT (_x_) WHERE _x_>10 DO UPDATE SET _x_ = _x_+1;
END }
}
4 _x_ _xxx_ {
{ CREATE TABLE t1(a, b, _x_ INTEGER, PRIMARY KEY(_x_), CHECK(_x_>0)) }
{ CREATE TRIGGER ttt AFTER UPDATE ON t1 BEGIN
INSERT INTO t1 VALUES(new.a, new.b, new._x_)
ON CONFLICT (_x_) WHERE _x_>10 DO NOTHING;
END }
}
} {
do_rename_column_test 9.$tn $old $new $lSchema
}
#-------------------------------------------------------------------------
# Test that views can be edited even if there are missing collation
# sequences or user defined functions.
#
reset_db
ifcapable vtab {
foreach {tn old new lSchema} {
1 _x_ _xxx_ {
{ CREATE TABLE t1(a, b, _x_) }
{ CREATE VIEW s1 AS SELECT a, b, _x_ FROM t1 WHERE _x_='abc' COLLATE xyz }
}
2 _x_ _xxx_ {
{ CREATE TABLE t1(a, b, _x_) }
{ CREATE VIEW v1 AS SELECT a, b, _x_ FROM t1 WHERE scalar(_x_) }
}
3 _x_ _xxx_ {
{ CREATE TABLE t1(a, b, _x_) }
{ CREATE VIEW v1 AS SELECT a, b, _x_ FROM t1 WHERE _x_ = unicode(1, 2, 3) }
}
4 _x_ _xxx_ {
{ CREATE TABLE t1(a, b, _x_) }
{ CREATE VIRTUAL TABLE e1 USING echo(t1) }
}
} {
register_echo_module db
do_rename_column_test 10.$tn $old $new $lSchema
}
#--------------------------------------------------------------------------
# Test that if a view or trigger refers to a virtual table for which the
# module is not available, RENAME COLUMN cannot proceed.
#
reset_db
register_echo_module db
do_execsql_test 11.0 {
CREATE TABLE x1(a, b, c);
CREATE VIRTUAL TABLE e1 USING echo(x1);
}
db close
sqlite3 db test.db
do_execsql_test 11.1 {
ALTER TABLE x1 RENAME b TO bbb;
SELECT sql FROM sqlite_master;
} { {CREATE TABLE x1(a, bbb, c)} {CREATE VIRTUAL TABLE e1 USING echo(x1)} }
do_execsql_test 11.2 {
CREATE VIEW v1 AS SELECT e1.*, x1.c FROM e1, x1;
}
do_catchsql_test 11.3 {
ALTER TABLE x1 RENAME c TO ccc;
} {1 {error in view v1: no such module: echo}}
}
#-------------------------------------------------------------------------
# Test some error conditions:
#
# 1. Renaming a column of a system table,
# 2. Renaming a column of a VIEW,
# 3. Renaming a column of a virtual table.
# 4. Renaming a column that does not exist.
# 5. Renaming a column of a table that does not exist.
#
reset_db
do_execsql_test 12.1.1 {
CREATE TABLE t1(a, b);
CREATE INDEX t1a ON t1(a);
INSERT INTO t1 VALUES(1, 1), (2, 2), (3, 4);
ANALYZE;
}
do_catchsql_test 12.1.2 {
ALTER TABLE sqlite_stat1 RENAME idx TO theindex;
} {1 {table sqlite_stat1 may not be altered}}
do_execsql_test 12.1.3 {
SELECT sql FROM sqlite_master WHERE tbl_name = 'sqlite_stat1'
} {{CREATE TABLE sqlite_stat1(tbl,idx,stat)}}
do_execsql_test 12.2.1 {
CREATE VIEW v1 AS SELECT * FROM t1;
CREATE VIEW v2(c, d) AS SELECT * FROM t1;
}
do_catchsql_test 12.2.2 {
ALTER TABLE v1 RENAME a TO z;
} {1 {cannot rename columns of view "v1"}}
do_catchsql_test 12.2.3 {
ALTER TABLE v2 RENAME c TO y;
} {1 {cannot rename columns of view "v2"}}
ifcapable fts5 {
do_execsql_test 12.3.1 {
CREATE VIRTUAL TABLE ft USING fts5(a, b, c);
}
do_catchsql_test 12.3.2 {
ALTER TABLE ft RENAME a TO z;
} {1 {cannot rename columns of virtual table "ft"}}
}
do_execsql_test 12.4.1 {
CREATE TABLE t2(x, y, z);
}
do_catchsql_test 12.4.2 {
ALTER TABLE t2 RENAME COLUMN a TO b;
} {1 {no such column: "a"}}
do_catchsql_test 12.5.1 {
ALTER TABLE t3 RENAME COLUMN a TO b;
} {1 {no such table: t3}}
#-------------------------------------------------------------------------
# Test the effect of some parse/resolve errors.
#
reset_db
do_execsql_test 13.1.1 {
CREATE TABLE x1(i INTEGER, t TEXT UNIQUE);
CREATE TRIGGER tr1 AFTER INSERT ON x1 BEGIN
SELECT * FROM nosuchtable;
END;
}
do_catchsql_test 13.1.2 {
ALTER TABLE x1 RENAME COLUMN t TO ttt;
} {1 {error in trigger tr1: no such table: main.nosuchtable}}
do_execsql_test 13.1.3 {
DROP TRIGGER tr1;
CREATE INDEX x1i ON x1(i);
SELECT sql FROM sqlite_master WHERE name='x1i';
} {{CREATE INDEX x1i ON x1(i)}}
do_execsql_test 13.1.4 {
PRAGMA writable_schema = 1;
UPDATE sqlite_master SET sql = 'CREATE INDEX x1i ON x1(j)' WHERE name='x1i';
} {}
do_catchsql_test 13.1.5 {
ALTER TABLE x1 RENAME COLUMN t TO ttt;
} {1 {error in index x1i: no such column: j}}
do_execsql_test 13.1.6 {
UPDATE sqlite_master SET sql = '' WHERE name='x1i';
} {}
do_catchsql_test 13.1.7 {
ALTER TABLE x1 RENAME COLUMN t TO ttt;
} {1 {database disk image is malformed}}
do_execsql_test 13.1.8 {
DELETE FROM sqlite_master WHERE name = 'x1i';
}
do_execsql_test 13.2.0 {
CREATE TABLE data(x UNIQUE, y, z);
}
foreach {tn trigger error} {
1 {
CREATE TRIGGER tr1 AFTER INSERT ON x1 BEGIN
UPDATE data SET x=x+1 WHERE zzz=new.i;
END;
} {no such column: zzz}
2 {
CREATE TRIGGER tr1 AFTER INSERT ON x1 BEGIN
INSERT INTO data(x, y) VALUES(new.i, new.t, 1)
ON CONFLICT (x) DO UPDATE SET z=zz+1;
END;
} {no such column: zz}
3 {
CREATE TRIGGER tr1 AFTER INSERT ON x1 BEGIN
INSERT INTO x1(i, t) VALUES(new.i+1, new.t||'1')
ON CONFLICT (tttttt) DO UPDATE SET t=i+1;
END;
} {no such column: tttttt}
4 {
CREATE TRIGGER tr1 AFTER INSERT ON x1 BEGIN
INSERT INTO nosuchtable VALUES(new.i, new.t);
END;
} {no such table: main.nosuchtable}
} {
do_execsql_test 13.2.$tn.1 "
DROP TRIGGER IF EXISTS tr1;
$trigger
"
do_catchsql_test 13.2.$tn.2 {
ALTER TABLE x1 RENAME COLUMN t TO ttt;
} "1 {error in trigger tr1: $error}"
}
#-------------------------------------------------------------------------
# Passing invalid parameters directly to sqlite_rename_column().
#
do_execsql_test 14.1 {
CREATE TABLE ddd(sql, type, object, db, tbl, icol, znew, bquote);
INSERT INTO ddd VALUES(
'CREATE TABLE x1(i INTEGER, t TEXT)',
'table', 'x1', 'main', 'x1', -1, 'zzz', 0
), (
'CREATE TABLE x1(i INTEGER, t TEXT)',
'table', 'x1', 'main', 'x1', 2, 'zzz', 0
), (
'CREATE TABLE x1(i INTEGER, t TEXT)',
'table', 'x1', 'main', 'notable', 0, 'zzz', 0
), (
'CREATE TABLE x1(i INTEGER, t TEXT)',
'table', 'x1', 'main', 'ddd', -1, 'zzz', 0
);
} {}
do_execsql_test 14.2 {
SELECT
sqlite_rename_column(sql, type, object, db, tbl, icol, znew, bquote, 0)
FROM ddd;
} {{} {} {} {}}
#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 15.0 {
CREATE TABLE xxx(a, b, c);
SELECT a AS d FROM xxx WHERE d=0;
}
do_execsql_test 15.1 {
CREATE VIEW vvv AS SELECT a AS d FROM xxx WHERE d=0;
ALTER TABLE xxx RENAME a TO xyz;
}
do_execsql_test 15.2 {
SELECT sql FROM sqlite_master WHERE type='view';
} {{CREATE VIEW vvv AS SELECT xyz AS d FROM xxx WHERE d=0}}
#-------------------------------------------------------------------------
#
do_execsql_test 16.1.0 {
CREATE TABLE t1(a,b,c);
CREATE TABLE t2(d,e,f);
INSERT INTO t1 VALUES(1,2,3);
INSERT INTO t2 VALUES(4,5,6);
CREATE VIEW v4 AS SELECT a, d FROM t1, t2;
SELECT * FROM v4;
} {1 4}
do_catchsql_test 16.1.1 {
ALTER TABLE t2 RENAME d TO a;
} {1 {error in view v4 after rename: ambiguous column name: a}}
do_execsql_test 16.1.2 {
SELECT * FROM v4;
} {1 4}
do_execsql_test 16.1.3 {
CREATE UNIQUE INDEX t2d ON t2(d);
CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
INSERT INTO t2 VALUES(new.a, new.b, new.c)
ON CONFLICT(d) DO UPDATE SET f = excluded.f;
END;
}
do_execsql_test 16.1.4 {
INSERT INTO t1 VALUES(4, 8, 456);
SELECT * FROM t2;
} {4 5 456}
do_execsql_test 16.1.5 {
ALTER TABLE t2 RENAME COLUMN f TO "big f";
INSERT INTO t1 VALUES(4, 0, 20456);
SELECT * FROM t2;
} {4 5 20456}
do_execsql_test 16.1.6 {
ALTER TABLE t1 RENAME COLUMN c TO "big c";
INSERT INTO t1 VALUES(4, 0, 0);
SELECT * FROM t2;
} {4 5 0}
do_execsql_test 16.2.1 {
CREATE VIEW temp.v5 AS SELECT "big c" FROM t1;
SELECT * FROM v5;
} {3 456 20456 0}
do_execsql_test 16.2.2 {
ALTER TABLE t1 RENAME COLUMN "big c" TO reallybigc;
} {}
do_execsql_test 16.2.3 {
SELECT * FROM v5;
} {3 456 20456 0}
#-------------------------------------------------------------------------
#
do_execsql_test 17.0 {
CREATE TABLE u7(x, y, z);
CREATE TRIGGER u7t AFTER INSERT ON u7 BEGIN
INSERT INTO u8 VALUES(new.x, new.y, new.z);
END;
} {}
do_catchsql_test 17.1 {
ALTER TABLE u7 RENAME x TO xxx;
} {1 {error in trigger u7t: no such table: main.u8}}
do_execsql_test 17.2 {
CREATE TEMP TABLE uu7(x, y, z);
CREATE TRIGGER uu7t AFTER INSERT ON uu7 BEGIN
INSERT INTO u8 VALUES(new.x, new.y, new.z);
END;
} {}
do_catchsql_test 17.3 {
ALTER TABLE uu7 RENAME x TO xxx;
} {1 {error in trigger uu7t: no such table: u8}}
reset_db
forcedelete test.db2
do_execsql_test 18.0 {
ATTACH 'test.db2' AS aux;
CREATE TABLE t1(a);
CREATE TABLE aux.log(v);
CREATE TEMP TRIGGER tr1 AFTER INSERT ON t1 BEGIN
INSERT INTO log VALUES(new.a);
END;
INSERT INTO t1 VALUES(111);
SELECT v FROM log;
} {111}
do_execsql_test 18.1 {
ALTER TABLE t1 RENAME a TO b;
}
reset_db
do_execsql_test 19.0 {
CREATE TABLE t1(a, b);
CREATE TABLE t2(c, d);
CREATE VIEW v2(e) AS SELECT coalesce(t2.c,t1.a) FROM t1, t2 WHERE t1.b=t2.d;
}
do_execsql_test 19.1 {
ALTER TABLE t1 RENAME a TO f;
SELECT sql FROM sqlite_master WHERE name = 'v2';
} {
{CREATE VIEW v2(e) AS SELECT coalesce(t2.c,t1.f) FROM t1, t2 WHERE t1.b=t2.d}
}
finish_test
+75
View File
@@ -0,0 +1,75 @@
# 2018 August 20
#
# 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.
#
#*************************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set testprefix altermalloc2
# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
ifcapable !altertable {
finish_test
return
}
do_execsql_test 1.0 {
CREATE TABLE t1(abcd, efgh);
}
faultsim_save_and_close
do_faultsim_test 1 -prep {
faultsim_restore_and_reopen
} -body {
execsql {
ALTER TABLE t1 RENAME abcd TO dcba
}
} -test {
faultsim_test_result {0 {}}
}
catch {db close}
forcedelete test.db
sqlite3 db test.db
do_execsql_test 2.0 {
PRAGMA encoding = 'utf-16';
CREATE TABLE t1(abcd, efgh);
}
faultsim_save_and_close
do_faultsim_test 2 -prep {
faultsim_restore_and_reopen
} -body {
execsql {
ALTER TABLE t1 RENAME abcd TO dcba
}
} -test {
faultsim_test_result {0 {}}
}
reset_db
do_execsql_test 3.0 {
CREATE TABLE t1(abcd, efgh);
CREATE VIEW v1 AS SELECT * FROM t1 WHERE abcd>efgh;
}
faultsim_save_and_close
do_faultsim_test 3 -prep {
faultsim_restore_and_reopen
} -body {
execsql {
ALTER TABLE t1 RENAME abcd TO dcba
}
} -test {
faultsim_test_result {0 {}}
}
finish_test
+415
View File
@@ -0,0 +1,415 @@
# 2018 August 24
#
# 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.
#
#*************************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix altertab
# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
ifcapable !altertable {
finish_test
return
}
do_execsql_test 1.0 {
CREATE TABLE t1(a, b, CHECK(t1.a != t1.b));
CREATE TABLE t2(a, b);
CREATE INDEX t2expr ON t2(a) WHERE t2.b>0;
}
do_execsql_test 1.1 {
SELECT sql FROM sqlite_master
} {
{CREATE TABLE t1(a, b, CHECK(t1.a != t1.b))}
{CREATE TABLE t2(a, b)}
{CREATE INDEX t2expr ON t2(a) WHERE t2.b>0}
}
do_execsql_test 1.2 {
ALTER TABLE t1 RENAME TO t1new;
}
do_execsql_test 1.3 {
CREATE TABLE t3(c, d);
ALTER TABLE t3 RENAME TO t3new;
DROP TABLE t3new;
}
do_execsql_test 1.4 {
SELECT sql FROM sqlite_master
} {
{CREATE TABLE "t1new"(a, b, CHECK("t1new".a != "t1new".b))}
{CREATE TABLE t2(a, b)}
{CREATE INDEX t2expr ON t2(a) WHERE t2.b>0}
}
do_execsql_test 1.3 {
ALTER TABLE t2 RENAME TO t2new;
}
do_execsql_test 1.4 {
SELECT sql FROM sqlite_master
} {
{CREATE TABLE "t1new"(a, b, CHECK("t1new".a != "t1new".b))}
{CREATE TABLE "t2new"(a, b)}
{CREATE INDEX t2expr ON "t2new"(a) WHERE "t2new".b>0}
}
#-------------------------------------------------------------------------
reset_db
ifcapable vtab {
register_echo_module db
do_execsql_test 2.0 {
CREATE TABLE abc(a, b, c);
INSERT INTO abc VALUES(1, 2, 3);
CREATE VIRTUAL TABLE eee USING echo('abc');
SELECT * FROM eee;
} {1 2 3}
do_execsql_test 2.1 {
ALTER TABLE eee RENAME TO fff;
SELECT * FROM fff;
} {1 2 3}
db close
sqlite3 db test.db
do_catchsql_test 2.2 {
ALTER TABLE fff RENAME TO ggg;
} {1 {no such module: echo}}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 3.0 {
CREATE TABLE txx(a, b, c);
INSERT INTO txx VALUES(1, 2, 3);
CREATE VIEW vvv AS SELECT main.txx.a, txx.b, c FROM txx;
CREATE VIEW uuu AS SELECT main.one.a, one.b, c FROM txx AS one;
CREATE VIEW temp.ttt AS SELECT main.txx.a, txx.b, one.b, main.one.a FROM txx AS one, txx;
}
do_execsql_test 3.1.1 {
SELECT * FROM vvv;
} {1 2 3}
do_execsql_test 3.1.2 {
ALTER TABLE txx RENAME TO "t xx";
SELECT * FROM vvv;
} {1 2 3}
do_execsql_test 3.1.3 {
SELECT sql FROM sqlite_master WHERE name='vvv';
} {{CREATE VIEW vvv AS SELECT main."t xx".a, "t xx".b, c FROM "t xx"}}
do_execsql_test 3.2.1 {
SELECT * FROM uuu;
} {1 2 3}
do_execsql_test 3.2.2 {
SELECT sql FROM sqlite_master WHERE name='uuu';;
} {{CREATE VIEW uuu AS SELECT main.one.a, one.b, c FROM "t xx" AS one}}
do_execsql_test 3.3.1 {
SELECT * FROM ttt;
} {1 2 2 1}
do_execsql_test 3.3.2 {
SELECT sql FROM sqlite_temp_master WHERE name='ttt';
} {{CREATE VIEW ttt AS SELECT main."t xx".a, "t xx".b, one.b, main.one.a FROM "t xx" AS one, "t xx"}}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 4.0 {
CREATE table t1(x, y);
CREATE table t2(a, b);
CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
SELECT t1.x, * FROM t1, t2;
INSERT INTO t2 VALUES(new.x, new.y);
END;
}
do_execsql_test 4.1 {
INSERT INTO t1 VALUES(1, 1);
ALTER TABLE t1 RENAME TO t11;
INSERT INTO t11 VALUES(2, 2);
ALTER TABLE t2 RENAME TO t22;
INSERT INTO t11 VALUES(3, 3);
}
proc squish {a} {
string trim [regsub -all {[[:space:]][[:space:]]*} $a { }]
}
db func squish squish
do_test 4.2 {
execsql { SELECT squish(sql) FROM sqlite_master WHERE name = 'tr1' }
} [list [squish {
CREATE TRIGGER tr1 AFTER INSERT ON "t11" BEGIN
SELECT "t11".x, * FROM "t11", "t22";
INSERT INTO "t22" VALUES(new.x, new.y);
END
}]]
#-------------------------------------------------------------------------
reset_db
do_execsql_test 5.0 {
CREATE TABLE t9(a, b, c);
CREATE TABLE t10(a, b, c);
CREATE TEMP TABLE t9(a, b, c);
CREATE TRIGGER temp.t9t AFTER INSERT ON temp.t9 BEGIN
INSERT INTO t10 VALUES(new.a, new.b, new.c);
END;
INSERT INTO temp.t9 VALUES(1, 2, 3);
SELECT * FROM t10;
} {1 2 3}
do_execsql_test 5.1 {
ALTER TABLE temp.t9 RENAME TO 't1234567890'
}
do_execsql_test 5.2 {
CREATE TABLE t1(a, b);
CREATE TABLE t2(a, b);
INSERT INTO t1 VALUES(1, 2);
INSERT INTO t2 VALUES(3, 4);
CREATE VIEW v AS SELECT one.a, one.b, t2.a, t2.b FROM t1 AS one, t2;
SELECT * FROM v;
} {1 2 3 4}
do_catchsql_test 5.3 {
ALTER TABLE t2 RENAME TO one;
} {1 {error in view v after rename: ambiguous column name: one.a}}
do_execsql_test 5.4 {
SELECT * FROM v
} {1 2 3 4}
do_execsql_test 5.5 {
DROP VIEW v;
CREATE VIEW temp.vv AS SELECT one.a, one.b, t2.a, t2.b FROM t1 AS one, t2;
SELECT * FROM vv;
} {1 2 3 4}
do_catchsql_test 5.6 {
ALTER TABLE t2 RENAME TO one;
} {1 {error in view vv after rename: ambiguous column name: one.a}}
#-------------------------------------------------------------------------
ifcapable vtab {
register_tcl_module db
proc tcl_command {method args} {
switch -- $method {
xConnect {
return "CREATE TABLE t1(a, b, c)"
}
}
return {}
}
do_execsql_test 6.0 {
CREATE VIRTUAL TABLE x1 USING tcl(tcl_command);
}
do_execsql_test 6.1 {
ALTER TABLE x1 RENAME TO x2;
SELECT sql FROM sqlite_master WHERE name = 'x2'
} {{CREATE VIRTUAL TABLE "x2" USING tcl(tcl_command)}}
do_execsql_test 7.1 {
CREATE TABLE ddd(db, sql, zOld, zNew, bTemp);
INSERT INTO ddd VALUES(
'main', 'CREATE TABLE x1(i INTEGER, t TEXT)', 'ddd', NULL, 0
), (
'main', 'CREATE TABLE x1(i INTEGER, t TEXT)', NULL, 'eee', 0
), (
'main', NULL, 'ddd', 'eee', 0
);
} {}
do_execsql_test 7.2 {
SELECT
sqlite_rename_table(db, 0, 0, sql, zOld, zNew, bTemp)
FROM ddd;
} {{} {} {}}
}
#-------------------------------------------------------------------------
#
reset_db
forcedelete test.db2
do_execsql_test 8.1 {
ATTACH 'test.db2' AS aux;
PRAGMA foreign_keys = on;
CREATE TABLE aux.p1(a INTEGER PRIMARY KEY, b);
CREATE TABLE aux.c1(x INTEGER PRIMARY KEY, y REFERENCES p1(a));
INSERT INTO aux.p1 VALUES(1, 1);
INSERT INTO aux.p1 VALUES(2, 2);
INSERT INTO aux.c1 VALUES(NULL, 2);
CREATE TABLE aux.c2(x INTEGER PRIMARY KEY, y REFERENCES c1(a));
}
do_execsql_test 8.2 {
ALTER TABLE aux.p1 RENAME TO ppp;
}
do_execsql_test 8.2 {
INSERT INTO aux.c1 VALUES(NULL, 1);
SELECT sql FROM aux.sqlite_master WHERE name = 'c1';
} {{CREATE TABLE c1(x INTEGER PRIMARY KEY, y REFERENCES "ppp"(a))}}
reset_db
do_execsql_test 9.0 {
CREATE TABLE t1(a, b, c);
CREATE VIEW v1 AS SELECT * FROM t2;
}
do_catchsql_test 9.1 {
ALTER TABLE t1 RENAME TO t3;
} {1 {error in view v1: no such table: main.t2}}
do_execsql_test 9.2 {
DROP VIEW v1;
CREATE TRIGGER tr AFTER INSERT ON t1 BEGIN
INSERT INTO t2 VALUES(new.a);
END;
}
do_catchsql_test 9.3 {
ALTER TABLE t1 RENAME TO t3;
} {1 {error in trigger tr: no such table: main.t2}}
forcedelete test.db2
do_execsql_test 9.4 {
DROP TRIGGER tr;
ATTACH 'test.db2' AS aux;
CREATE TRIGGER tr AFTER INSERT ON t1 WHEN new.a IS NULL BEGIN SELECT 1, 2, 3; END;
CREATE TABLE aux.t1(x);
CREATE TEMP TRIGGER tr AFTER INSERT ON aux.t1 BEGIN SELECT 1, 2, 3; END;
}
do_execsql_test 9.5 {
ALTER TABLE main.t1 RENAME TO t3;
}
do_execsql_test 9.6 {
SELECT sql FROM sqlite_temp_master;
SELECT sql FROM sqlite_master WHERE type='trigger';
} {
{CREATE TRIGGER tr AFTER INSERT ON aux.t1 BEGIN SELECT 1, 2, 3; END}
{CREATE TRIGGER tr AFTER INSERT ON "t3" WHEN new.a IS NULL BEGIN SELECT 1, 2, 3; END}
}
#-------------------------------------------------------------------------
reset_db
ifcapable fts5 {
do_execsql_test 10.0 {
CREATE VIRTUAL TABLE fff USING fts5(x, y, z);
}
do_execsql_test 10.1 {
BEGIN;
INSERT INTO fff VALUES('a', 'b', 'c');
ALTER TABLE fff RENAME TO ggg;
COMMIT;
}
do_execsql_test 10.2 {
SELECT * FROM ggg;
} {a b c}
}
#-------------------------------------------------------------------------
reset_db
forcedelete test.db2
db func trigger trigger
set ::trigger [list]
proc trigger {args} {
lappend ::trigger $args
}
do_execsql_test 11.0 {
ATTACH 'test.db2' AS aux;
CREATE TABLE aux.t1(a, b, c);
CREATE TABLE main.t1(a, b, c);
CREATE TEMP TRIGGER tr AFTER INSERT ON aux.t1 BEGIN
SELECT trigger(new.a, new.b, new.c);
END;
}
do_execsql_test 11.1 {
INSERT INTO main.t1 VALUES(1, 2, 3);
INSERT INTO aux.t1 VALUES(4, 5, 6);
}
do_test 11.2 { set ::trigger } {{4 5 6}}
do_execsql_test 11.3 {
SELECT name, tbl_name FROM sqlite_temp_master;
} {tr t1}
do_execsql_test 11.4 {
ALTER TABLE main.t1 RENAME TO t2;
SELECT name, tbl_name FROM sqlite_temp_master;
} {tr t1}
do_execsql_test 11.5 {
ALTER TABLE aux.t1 RENAME TO t2;
SELECT name, tbl_name FROM sqlite_temp_master;
} {tr t2}
do_execsql_test 11.6 {
INSERT INTO aux.t2 VALUES(7, 8, 9);
}
do_test 11.7 { set ::trigger } {{4 5 6} {7 8 9}}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 12.0 {
CREATE TABLE t1(a);
CREATE TABLE t2(w);
CREATE TRIGGER temp.r1 AFTER INSERT ON main.t2 BEGIN
INSERT INTO t1(a) VALUES(new.w);
END;
CREATE TEMP TABLE t2(x);
}
do_execsql_test 12.1 {
ALTER TABLE main.t2 RENAME TO t3;
}
do_execsql_test 12.2 {
INSERT INTO t3 VALUES('WWW');
SELECT * FROM t1;
} {WWW}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 13.0 {
CREATE TABLE t1(x, y);
CREATE TABLE t2(a, b);
CREATE TABLE log(c);
CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
INSERT INTO log SELECT y FROM t1, t2;
END;
}
do_execsql_test 13.1 {
INSERT INTO t1 VALUES(1, 2);
}
do_catchsql_test 13.2 {
ALTER TABLE t2 RENAME b TO y;
} {1 {error in trigger tr1 after rename: ambiguous column name: y}}
finish_test
+17 -1
View File
@@ -349,7 +349,7 @@ ifcapable stat4||stat3 {
# This test corrupts the database file so it must be the last test
# in the series.
#
do_test analyze-99.1 {
do_test analyze-5.99 {
execsql {
PRAGMA writable_schema=on;
UPDATE sqlite_master SET sql='nonsense' WHERE name='sqlite_stat1';
@@ -361,4 +361,20 @@ do_test analyze-99.1 {
}
} {1 {malformed database schema (sqlite_stat1)}}
# Verify that tables whose names begin with "sqlite" but not
# "sqlite_" are analyzed.
#
db close
sqlite3 db :memory:
do_execsql_test analyze-6.1 {
CREATE TABLE sqliteDemo(a);
INSERT INTO sqliteDemo(a) VALUES(1),(2),(3),(4),(5);
CREATE TABLE SQLiteDemo2(a INTEGER PRIMARY KEY AUTOINCREMENT);
INSERT INTO SQLiteDemo2 SELECT * FROM sqliteDemo;
CREATE TABLE t1(b);
INSERT INTO t1(b) SELECT a FROM sqliteDemo;
ANALYZE;
SELECT tbl FROM sqlite_stat1 WHERE idx IS NULL ORDER BY tbl;
} {SQLiteDemo2 sqliteDemo t1}
finish_test
+15 -15
View File
@@ -118,10 +118,10 @@ do_execsql_test analyze3-1.1.x {
#
do_eqp_test analyze3-1.1.2 {
SELECT sum(y) FROM t1 WHERE x>200 AND x<300
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}}
} {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}
do_eqp_test analyze3-1.1.3 {
SELECT sum(y) FROM t1 WHERE x>0 AND x<1100
} {0 0 0 {SCAN TABLE t1}}
} {SCAN TABLE t1}
# 2017-06-26: Verify that the SQLITE_DBCONFIG_ENABLE_QPSG setting disables
# the use of bound parameters by STAT4
@@ -131,27 +131,27 @@ unset -nocomplain l
unset -nocomplain u
do_eqp_test analyze3-1.1.3.100 {
SELECT sum(y) FROM t1 WHERE x>$l AND x<$u
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}}
} {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}
set l 200
set u 300
do_eqp_test analyze3-1.1.3.101 {
SELECT sum(y) FROM t1 WHERE x>$l AND x<$u
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}}
} {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}
set l 0
set u 1100
do_eqp_test analyze3-1.1.3.102 {
SELECT sum(y) FROM t1 WHERE x>$l AND x<$u
} {0 0 0 {SCAN TABLE t1}}
} {SCAN TABLE t1}
db cache flush
sqlite3_db_config db ENABLE_QPSG 1
do_eqp_test analyze3-1.1.3.103 {
SELECT sum(y) FROM t1 WHERE x>$l AND x<$u
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}}
} {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}
db cache flush
sqlite3_db_config db ENABLE_QPSG 0
do_eqp_test analyze3-1.1.3.104 {
SELECT sum(y) FROM t1 WHERE x>$l AND x<$u
} {0 0 0 {SCAN TABLE t1}}
} {SCAN TABLE t1}
do_test analyze3-1.1.4 {
sf_execsql { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 }
@@ -201,10 +201,10 @@ do_execsql_test analyze3-2.1.x {
} {200 990}
do_eqp_test analyze3-1.2.2 {
SELECT sum(y) FROM t2 WHERE x>1 AND x<2
} {0 0 0 {SEARCH TABLE t2 USING INDEX i2 (x>? AND x<?)}}
} {SEARCH TABLE t2 USING INDEX i2 (x>? AND x<?)}
do_eqp_test analyze3-1.2.3 {
SELECT sum(y) FROM t2 WHERE x>0 AND x<99
} {0 0 0 {SCAN TABLE t2}}
} {SCAN TABLE t2}
do_test analyze3-1.2.4 {
sf_execsql { SELECT sum(y) FROM t2 WHERE x>12 AND x<20 }
@@ -253,10 +253,10 @@ do_execsql_test analyze3-1.3.x {
} {99 1000}
do_eqp_test analyze3-1.3.2 {
SELECT sum(y) FROM t3 WHERE x>200 AND x<300
} {0 0 0 {SEARCH TABLE t3 USING INDEX i3 (x>? AND x<?)}}
} {SEARCH TABLE t3 USING INDEX i3 (x>? AND x<?)}
do_eqp_test analyze3-1.3.3 {
SELECT sum(y) FROM t3 WHERE x>0 AND x<1100
} {0 0 0 {SCAN TABLE t3}}
} {SCAN TABLE t3}
do_test analyze3-1.3.4 {
sf_execsql { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 }
@@ -308,10 +308,10 @@ do_test analyze3-2.1 {
} {}
do_eqp_test analyze3-2.2 {
SELECT count(a) FROM t1 WHERE b LIKE 'a%'
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (b>? AND b<?)}}
} {SEARCH TABLE t1 USING INDEX i1 (b>? AND b<?)}
do_eqp_test analyze3-2.3 {
SELECT count(a) FROM t1 WHERE b LIKE '%a'
} {0 0 0 {SCAN TABLE t1}}
} {SCAN TABLE t1}
# Return the first argument if like_match_blobs is true (the default)
# or the second argument if not
@@ -698,11 +698,11 @@ do_test analyze3-6.1 {
do_eqp_test analyze3-6-3 {
SELECT * FROM t1 WHERE a = 5 AND c = 13;
} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (c=?)}}
} {SEARCH TABLE t1 USING INDEX i2 (c=?)}
do_eqp_test analyze3-6-2 {
SELECT * FROM t1 WHERE a = 5 AND b > 'w' AND c = 13;
} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (c=?)}}
} {SEARCH TABLE t1 USING INDEX i2 (c=?)}
#-----------------------------------------------------------------------------
# 2015-04-20.
+1 -1
View File
@@ -38,7 +38,7 @@ do_test analyze4-1.0 {
# Should choose the t1a index since it is more specific than t1b.
db eval {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=5 AND b IS NULL}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/}
# Verify that the t1b index shows that it does not narrow down the
# search any at all.
+17 -13
View File
@@ -61,14 +61,18 @@ do_test analyze6-1.0 {
#
do_test analyze6-1.1 {
eqp {SELECT count(*) FROM ev, cat WHERE x=y}
} {0 0 1 {SCAN TABLE cat USING COVERING INDEX catx} 0 1 0 {SEARCH TABLE ev USING COVERING INDEX evy (y=?)}}
} {/*SCAN TABLE cat USING COVERING INDEX catx*SEARCH TABLE ev USING COVERING INDEX evy (y=?)*/}
# The same plan is chosen regardless of the order of the tables in the
# FROM clause.
#
do_test analyze6-1.2 {
eqp {SELECT count(*) FROM cat, ev WHERE x=y}
} {0 0 0 {SCAN TABLE cat USING COVERING INDEX catx} 0 1 1 {SEARCH TABLE ev USING COVERING INDEX evy (y=?)}}
do_eqp_test analyze6-1.2 {
SELECT count(*) FROM cat, ev WHERE x=y
} {
QUERY PLAN
|--SCAN TABLE cat USING COVERING INDEX catx
`--SEARCH TABLE ev USING COVERING INDEX evy (y=?)
}
# Ticket [83ea97620bd3101645138b7b0e71c12c5498fe3d] 2011-03-30
@@ -82,26 +86,26 @@ do_test analyze6-2.1 {
ANALYZE;
}
eqp {SELECT * FROM t201 WHERE z=5}
} {0 0 0 {SEARCH TABLE t201 USING INDEX t201z (z=?)}}
} {/*SEARCH TABLE t201 USING INDEX t201z (z=?)*/}
do_test analyze6-2.2 {
eqp {SELECT * FROM t201 WHERE y=5}
} {0 0 0 {SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?)}}
} {/*SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?)*/}
do_test analyze6-2.3 {
eqp {SELECT * FROM t201 WHERE x=5}
} {0 0 0 {SEARCH TABLE t201 USING INTEGER PRIMARY KEY (rowid=?)}}
} {/*SEARCH TABLE t201 USING INTEGER PRIMARY KEY (rowid=?)*/}
do_test analyze6-2.4 {
execsql {
INSERT INTO t201 VALUES(1,2,3),(2,3,4),(3,4,5);
ANALYZE t201;
}
eqp {SELECT * FROM t201 WHERE z=5}
} {0 0 0 {SEARCH TABLE t201 USING INDEX t201z (z=?)}}
} {/*SEARCH TABLE t201 USING INDEX t201z (z=?)*/}
do_test analyze6-2.5 {
eqp {SELECT * FROM t201 WHERE y=5}
} {0 0 0 {SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?)}}
} {/*SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?)*/}
do_test analyze6-2.6 {
eqp {SELECT * FROM t201 WHERE x=5}
} {0 0 0 {SEARCH TABLE t201 USING INTEGER PRIMARY KEY (rowid=?)}}
} {/*SEARCH TABLE t201 USING INTEGER PRIMARY KEY (rowid=?)*/}
do_test analyze6-2.7 {
execsql {
INSERT INTO t201 VALUES(4,5,7);
@@ -111,12 +115,12 @@ do_test analyze6-2.7 {
ANALYZE t201;
}
eqp {SELECT * FROM t201 WHERE z=5}
} {0 0 0 {SEARCH TABLE t201 USING INDEX t201z (z=?)}}
} {/*SEARCH TABLE t201 USING INDEX t201z (z=?)*/}
do_test analyze6-2.8 {
eqp {SELECT * FROM t201 WHERE y=5}
} {0 0 0 {SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?)}}
} {/*SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?)*/}
do_test analyze6-2.9 {
eqp {SELECT * FROM t201 WHERE x=5}
} {0 0 0 {SEARCH TABLE t201 USING INTEGER PRIMARY KEY (rowid=?)}}
} {/*SEARCH TABLE t201 USING INTEGER PRIMARY KEY (rowid=?)*/}
finish_test
+16 -16
View File
@@ -37,13 +37,13 @@ do_test analyze7-1.0 {
WHERE value BETWEEN 1 AND 256;
EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123;
}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/}
do_test analyze7-1.1 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1b (b=?)*/}
do_test analyze7-1.2 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1cd (c=?)*/}
# Run an analyze on one of the three indices. Verify that this
# effects the row-count estimate on the one query that uses that
@@ -53,20 +53,20 @@ do_test analyze7-2.0 {
execsql {ANALYZE t1a;}
db cache flush
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123;}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/}
do_test analyze7-2.1 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1b (b=?)*/}
do_test analyze7-2.2 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1cd (c=?)*/}
# Verify that since the query planner now things that t1a is more
# selective than t1b, it prefers to use t1a.
#
do_test analyze7-2.3 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND b=123}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/}
# Run an analysis on another of the three indices. Verify that this
# new analysis works and does not disrupt the previous analysis.
@@ -75,40 +75,40 @@ do_test analyze7-3.0 {
execsql {ANALYZE t1cd;}
db cache flush;
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123;}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/}
do_test analyze7-3.1 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1b (b=?)*/}
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=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1cd (c=?)*/}
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=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1cd (c=?)*/}
} else {
# 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;}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1cd (c=?)*/}
}
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=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/}
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=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1b (b=?)*/}
do_test analyze7-3.5 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND c=123}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/}
}
do_test analyze7-3.6 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND d=123 AND b=123}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=? AND d=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1cd (c=? AND d=?)*/}
finish_test
+11 -11
View File
@@ -61,25 +61,25 @@ do_test 1.0 {
#
do_test 1.1 {
eqp {SELECT * FROM t1 WHERE a=100 AND b=55}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1b (b=?)*/}
do_test 1.2 {
eqp {SELECT * FROM t1 WHERE a=99 AND b=55}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/}
do_test 1.3 {
eqp {SELECT * FROM t1 WHERE a=101 AND b=55}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/}
do_test 1.4 {
eqp {SELECT * FROM t1 WHERE a=100 AND b=56}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1b (b=?)*/}
do_test 1.5 {
eqp {SELECT * FROM t1 WHERE a=99 AND b=56}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/}
do_test 1.6 {
eqp {SELECT * FROM t1 WHERE a=101 AND b=56}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/}
do_test 2.1 {
eqp {SELECT * FROM t1 WHERE a=100 AND b BETWEEN 50 AND 54}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}}
} {/*SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)*/}
# 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
@@ -99,17 +99,17 @@ do_execsql_test 3.0 {
} {50 376 32}
do_test 3.1 {
eqp {SELECT * FROM t1 WHERE b BETWEEN 30 AND 34 AND c BETWEEN 0 AND 100000}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}}
} {/*SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)*/}
do_test 3.2 {
eqp {SELECT * FROM t1
WHERE b BETWEEN 30 AND 34 AND c BETWEEN 800000 AND 900000}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}}
} {/*SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)*/}
do_test 3.3 {
eqp {SELECT * FROM t1 WHERE a=100 AND c BETWEEN 0 AND 100000}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}}
} {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/}
do_test 3.4 {
eqp {SELECT * FROM t1
WHERE a=100 AND c BETWEEN 800000 AND 900000}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}}
} {/*SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)*/}
finish_test
+17 -28
View File
@@ -987,7 +987,8 @@ do_eqp_test 21.3 {
reset_db
do_execsql_test 22.0 {
CREATE TABLE t3(a, b, c, d, PRIMARY KEY(a, b)) WITHOUT ROWID;
}
SELECT * FROM t3;
} {}
do_execsql_test 22.1 {
WITH r(x) AS (
SELECT 1
@@ -1052,15 +1053,14 @@ do_execsql_test 23.0 {
do_eqp_test 23.1 {
SELECT * FROM t4 WHERE
(e=1 AND b='xyz' AND c='zyx' AND a<'AEA') AND f<300
} {
0 0 0 {SEARCH TABLE t4 USING INDEX i41 (e=? AND c=? AND b=? AND a<?)}
}
-- Formerly used index i41. But i41 is not a covering index whereas
-- the PRIMARY KEY is a covering index, and so as of 2017-10-15, the
-- PRIMARY KEY is preferred.
} {SEARCH TABLE t4 USING PRIMARY KEY (c=? AND b=? AND a<?)}
do_eqp_test 23.2 {
SELECT * FROM t4 WHERE
(e=1 AND b='xyz' AND c='zyx' AND a<'JJJ') AND f<300
} {
0 0 0 {SEARCH TABLE t4 USING INDEX i42 (f<?)}
}
} {SEARCH TABLE t4 USING INDEX i42 (f<?)}
do_execsql_test 24.0 {
CREATE TABLE t5(c, d, b, e, a, PRIMARY KEY(a, b, c)) WITHOUT ROWID;
@@ -1105,33 +1105,26 @@ ifcapable stat4&&cte {
# Term (b<?) is estimated at 25%. Better than (a<30) but not as
# good as (a<20).
do_eqp_test 25.2.1 { SELECT * FROM t6 WHERE a<30 AND b<? } {
0 0 0 {SEARCH TABLE t6 USING INDEX bb (b<?)}
}
do_eqp_test 25.2.2 { SELECT * FROM t6 WHERE a<20 AND b<? } {
0 0 0 {SEARCH TABLE t6 USING INDEX aa (a<?)}
}
do_eqp_test 25.2.1 { SELECT * FROM t6 WHERE a<30 AND b<? } \
{SEARCH TABLE t6 USING INDEX bb (b<?)}
do_eqp_test 25.2.2 { SELECT * FROM t6 WHERE a<20 AND b<? } \
{SEARCH TABLE t6 USING INDEX aa (a<?)}
# Term (b BETWEEN ? AND ?) is estimated at 1/64.
do_eqp_test 25.3.1 {
SELECT * FROM t6 WHERE a BETWEEN 5 AND 10 AND b BETWEEN ? AND ?
} {
0 0 0 {SEARCH TABLE t6 USING INDEX bb (b>? AND b<?)}
}
} {SEARCH TABLE t6 USING INDEX bb (b>? AND b<?)}
# Term (b BETWEEN ? AND 60) is estimated to return roughly 15 rows -
# 60 from (b<=60) multiplied by 0.25 for the b>=? term. Better than
# (a<20) but not as good as (a<10).
do_eqp_test 25.4.1 {
SELECT * FROM t6 WHERE a < 10 AND (b BETWEEN ? AND 60)
} {
0 0 0 {SEARCH TABLE t6 USING INDEX aa (a<?)}
}
} {SEARCH TABLE t6 USING INDEX aa (a<?)}
do_eqp_test 25.4.2 {
SELECT * FROM t6 WHERE a < 20 AND (b BETWEEN ? AND 60)
} {
0 0 0 {SEARCH TABLE t6 USING INDEX bb (b>? AND b<?)}
}
} {SEARCH TABLE t6 USING INDEX bb (b>? AND b<?)}
}
#-------------------------------------------------------------------------
@@ -1187,9 +1180,7 @@ do_execsql_test 26.1.3 {
#
do_eqp_test 26.1.4 {
SELECT * FROM t1 WHERE x = 10000 AND y < 50 AND z = 444;
} {
0 0 0 {SEARCH TABLE t1 USING INDEX t1z (z=?)}
}
} {SEARCH TABLE t1 USING INDEX t1z (z=?)}
# This test - 26.2.* - tests that another manifestation of the same problem
@@ -1238,9 +1229,7 @@ do_execsql_test 26.2.1 {
do_eqp_test 26.2.2 {
SELECT * FROM t1 WHERE x='B' AND y>25 AND z=?;
} {
0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x=? AND y>?)}
}
} {SEARCH TABLE t1 USING INDEX i1 (x=? AND y>?)}
finish_test
+8 -8
View File
@@ -136,10 +136,10 @@ foreach {tn analyze_cmd} {
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=?)}}
} {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=?)}}
} {SEARCH TABLE t1 USING INDEX t1c (c=?)}
do_execsql_test 1.$tn.3.1 {
SELECT count(*) FROM t1 WHERE b BETWEEN 0 AND 50
@@ -156,31 +156,31 @@ foreach {tn analyze_cmd} {
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<?)}}
} {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<?)}}
} {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}
do_eqp_test 1.$tn.3.7 {
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<?)}}
} {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}
do_eqp_test 1.$tn.3.8 {
SELECT * FROM t1
WHERE b BETWEEN cast('0' AS int) AND cast('50.0' AS real)
AND c BETWEEN cast('0' AS numeric) AND cast('50.0' AS real)
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}}
} {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}
do_eqp_test 1.$tn.3.9 {
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<?)}}
} {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}
do_eqp_test 1.$tn.3.10 {
SELECT * FROM t1
WHERE b BETWEEN cast('75' AS int) AND cast('125.0' AS real)
AND c BETWEEN cast('75' AS numeric) AND cast('125.0' AS real)
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}}
} {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}
}
finish_test
+4 -12
View File
@@ -63,9 +63,7 @@ do_test 1.1 {
#
do_eqp_test 1.2 {
SELECT * FROM t1 WHERE a=3001 AND c=150;
} {
0 0 0 {SEARCH TABLE t1 USING INDEX t1_c (c=?)}
}
} {SEARCH TABLE t1 USING INDEX t1_c (c=?)}
do_test 1.3 {
execsql { DELETE FROM sqlite_stat1 }
@@ -80,9 +78,7 @@ do_test 1.3 {
#
do_eqp_test 1.4 {
SELECT * FROM t1 WHERE a=3001 AND c=150;
} {
0 0 0 {SEARCH TABLE t1 USING INDEX t1_ab (a=?)}
}
} {SEARCH TABLE t1 USING INDEX t1_ab (a=?)}
do_test 1.5 {
execsql {
@@ -93,9 +89,7 @@ do_test 1.5 {
do_eqp_test 1.6 {
SELECT * FROM t1 WHERE a=13 AND c=150;
} {
0 0 0 {SEARCH TABLE t1 USING INDEX t1_c (c=?)}
}
} {SEARCH TABLE t1 USING INDEX t1_c (c=?)}
do_test 1.7 {
execsql { DELETE FROM sqlite_stat1 }
@@ -108,8 +102,6 @@ do_test 1.7 {
# gets this right, even without stat1 data.
do_eqp_test 1.8 {
SELECT * FROM t1 WHERE a=13 AND c=150;
} {
0 0 0 {SEARCH TABLE t1 USING INDEX t1_c (c=?)}
}
} {SEARCH TABLE t1 USING INDEX t1_c (c=?)}
finish_test
+2 -2
View File
@@ -62,7 +62,7 @@ foreach {tn where idx} {
11 "x = nullif('19', 0) AND y = nullif('4', 0)" {t1y (y=?)}
12 "x = nullif('4', 0) AND y = nullif('19', 0)" {t1y (y=?)}
} {
set res "0 0 0 {SEARCH TABLE t1 USING INDEX $idx}"
set res "SEARCH TABLE t1 USING INDEX $idx"
do_eqp_test 1.$tn "SELECT * FROM t1 WHERE $where" $res
}
@@ -92,7 +92,7 @@ foreach {tn where idx} {
3 "x = nondet4() AND y = nondet19()" {t1y (y=?)}
4 "x = nondet19() AND y = nondet4()" {t1y (y=?)}
} {
set res "0 0 0 {SEARCH TABLE t1 USING INDEX $idx}"
set res "SEARCH TABLE t1 USING INDEX $idx"
do_eqp_test 3.$tn "SELECT * FROM t1 WHERE $where" $res
}
+41
View File
@@ -0,0 +1,41 @@
# 2015-11-07
#
# 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 file is testing the WITH clause.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set ::testprefix atomic
db close
if {[atomic_batch_write test.db]==0} {
puts "No f2fs atomic-batch-write support. Skipping tests..."
finish_test
return
}
reset_db
do_execsql_test 1.0 {
CREATE TABLE t1(x, y);
BEGIN;
INSERT INTO t1 VALUES(1, 2);
}
do_test 1.1 { file exists test.db-journal } {0}
do_execsql_test 1.2 {
COMMIT;
}
finish_test
+95
View File
@@ -0,0 +1,95 @@
# 2018-07-15
#
# 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 file is testing that if an IO error is encountered
# as part of an atomic F2FS commit, an attempt is made to commit the
# transaction using a legacy journal commit.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set ::testprefix atomic2
db close
if {[atomic_batch_write test.db]==0} {
puts "No f2fs atomic-batch-write support. Skipping tests..."
finish_test
return
}
reset_db
do_execsql_test 1.0 {
CREATE TABLE t1(x, y);
CREATE INDEX i1x ON t1(x);
CREATE INDEX i2x ON t1(y);
WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100 )
INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM s;
}
set setup [list \
-injectstart at_injectstart \
-injectstop at_injectstop \
]
set ::at_fail 0
set ::at_nfail 0
proc at_injectstart {iFail} {
set ::at_fail $iFail
set ::at_nfail 0
}
proc at_injectstop {} {
set ::at_fail 0
return $::at_nfail
}
proc at_vfs_callback {method file z args} {
if {$::at_fail>0} {
incr ::at_fail -1
if {$::at_fail==0} {
incr ::at_nfail
return SQLITE_IOERR
} elseif {$method=="xFileControl" && $z=="COMMIT_ATOMIC_WRITE"} {
set ::at_fail 0
}
}
return SQLITE_OK
}
testvfs tvfs -default 1
tvfs script at_vfs_callback
tvfs filter {xFileControl xWrite}
faultsim_save_and_close
do_one_faultsim_test 2.0 {*}$setup -prep {
faultsim_restore_and_reopen
} -body {
execsql {
WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100 )
INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM s;
}
} -test {
faultsim_test_result {0 {}}
set res [execsql {SELECT count(*) FROM t1; PRAGMA integrity_check}]
if {$res!="200 ok"} {
error "expected {200 ok}, got $res"
}
}
db close
tvfs delete
finish_test
+150
View File
@@ -0,0 +1,150 @@
/*
** This program generates a script that stresses the ALTER TABLE statement.
** Compile like this:
**
** gcc -g -c sqlite3.c
** gcc -g -o atrc atrc.c sqlite3.o -ldl -lpthread
**
** Run the program this way:
**
** ./atrc DATABASE | ./sqlite3 DATABASE
**
** This program "atrc" generates a script that can be fed into an ordinary
** command-line shell. The script performs many ALTER TABLE statements,
** runs ".schema --indent" and "PRAGMA integrity_check;", does more
** ALTER TABLE statements to restore the original schema, and then
** runs "PRAGMA integrity_check" again. Every table and column has its
** name changed. The entire script is contained within BEGIN...ROLLBACK
** so that no changes are ever actually made to the database.
*/
#include "sqlite3.h"
#include <stdio.h>
/*
** Generate the text of ALTER TABLE statements that will rename
** every column in table zTable to a generic name composed from
** zColPrefix and a sequential number. The generated text is
** appended pConvert. If pUndo is not NULL, then SQL text that
** will undo the change is appended to pUndo.
**
** The table to be converted must be in the "main" schema.
*/
int rename_all_columns_of_table(
sqlite3 *db, /* Database connection */
const char *zTab, /* Table whose columns should all be renamed */
const char *zColPrefix, /* Prefix for new column names */
sqlite3_str *pConvert, /* Append ALTER TABLE statements here */
sqlite3_str *pUndo /* SQL to undo the change, if not NULL */
){
sqlite3_stmt *pStmt;
int rc;
int cnt = 0;
rc = sqlite3_prepare_v2(db,
"SELECT name FROM pragma_table_info(?1);",
-1, &pStmt, 0);
if( rc ) return rc;
sqlite3_bind_text(pStmt, 1, zTab, -1, SQLITE_STATIC);
while( sqlite3_step(pStmt)==SQLITE_ROW ){
const char *zCol = (const char*)sqlite3_column_text(pStmt, 0);
cnt++;
sqlite3_str_appendf(pConvert,
"ALTER TABLE \"%w\" RENAME COLUMN \"%w\" TO \"%w%d\";\n",
zTab, zCol, zColPrefix, cnt
);
if( pUndo ){
sqlite3_str_appendf(pUndo,
"ALTER TABLE \"%w\" RENAME COLUMN \"%w%d\" TO \"%w\";\n",
zTab, zColPrefix, cnt, zCol
);
}
}
sqlite3_finalize(pStmt);
return SQLITE_OK;
}
/* Rename all tables and their columns in the main database
*/
int rename_all_tables(
sqlite3 *db, /* Database connection */
sqlite3_str *pConvert, /* Append SQL to do the rename here */
sqlite3_str *pUndo /* Append SQL to undo the rename here */
){
sqlite3_stmt *pStmt;
int rc;
int cnt = 0;
rc = sqlite3_prepare_v2(db,
"SELECT name FROM sqlite_master WHERE type='table'"
" AND name NOT LIKE 'sqlite_%';",
-1, &pStmt, 0);
if( rc ) return rc;
while( sqlite3_step(pStmt)==SQLITE_ROW ){
const char *zTab = (const char*)sqlite3_column_text(pStmt, 0);
char *zNewTab;
char zPrefix[2];
zPrefix[0] = (cnt%26) + 'a';
zPrefix[1] = 0;
zNewTab = sqlite3_mprintf("tx%d", ++cnt);
if( pUndo ){
sqlite3_str_appendf(pUndo,
"ALTER TABLE \"%s\" RENAME TO \"%w\";\n",
zNewTab, zTab
);
}
rename_all_columns_of_table(db, zTab, zPrefix, pConvert, pUndo);
sqlite3_str_appendf(pConvert,
"ALTER TABLE \"%w\" RENAME TO \"%s\";\n",
zTab, zNewTab
);
sqlite3_free(zNewTab);
}
sqlite3_finalize(pStmt);
return SQLITE_OK;
}
/*
** Generate a script that does this:
**
** (1) Start a transaction
** (2) Rename all tables and columns to use generic names.
** (3) Print the schema after this rename
** (4) Run pragma integrity_check
** (5) Do more ALTER TABLE statements to change the names back
** (6) Run pragma integrity_check again
** (7) Rollback the transaction
*/
int main(int argc, char **argv){
sqlite3 *db;
int rc;
sqlite3_str *pConvert;
sqlite3_str *pUndo;
char *zDbName;
char *zSql1, *zSql2;
if( argc!=2 ){
fprintf(stderr, "Usage: %s DATABASE\n", argv[0]);
}
zDbName = argv[1];
rc = sqlite3_open(zDbName, &db);
if( rc ){
fprintf(stderr, "sqlite3_open() returns %d\n", rc);
return 1;
}
pConvert = sqlite3_str_new(db);
pUndo = sqlite3_str_new(db);
rename_all_tables(db, pConvert, pUndo);
zSql1 = sqlite3_str_finish(pConvert);
zSql2 = sqlite3_str_finish(pUndo);
sqlite3_close(db);
printf("BEGIN;\n");
printf("%s", zSql1);
sqlite3_free(zSql1);
printf(".schema --indent\n");
printf("PRAGMA integrity_check;\n");
printf("%s", zSql2);
sqlite3_free(zSql2);
printf("PRAGMA integrity_check;\n");
printf("ROLLBACK;\n");
return 0;
}
+4 -10
View File
@@ -374,23 +374,17 @@ do_test attach2-6.1 {
do_test attach2-6.2 {
catchsql {
ATTACH 'test3.db' as aux2;
DETACH aux2;
}
} {1 {cannot ATTACH database within transaction}}
} {0 {}}
# EVIDENCE-OF: R-59740-55581 This statement will fail if SQLite is in
# the middle of a transaction.
# As of version 3.21.0: it is ok to DETACH from within a transaction
#
do_test attach2-6.3 {
catchsql {
DETACH aux;
}
} {1 {cannot DETACH database within transaction}}
do_test attach2-6.4 {
execsql {
COMMIT;
DETACH aux;
}
} {}
} {0 {}}
db close
+69
View File
@@ -2133,6 +2133,75 @@ ifcapable {cte} {
} {1 {not authorized}}
} ;# ifcapable cte
#
# db eval {SELECT sql FROM temp.sqlite_master} {puts "TEMP: $sql;"}
# db eval {SELECT sql FROM main.sqlite_master} {puts "MAIN: $sql;"}
#
# MAIN: CREATE TABLE "t2"(a,b,c);
# MAIN: CREATE TABLE t4(a,b,c);
# MAIN: CREATE INDEX t4i1 ON t4(a);
# MAIN: CREATE INDEX t4i2 ON t4(b,a,c);
# MAIN: CREATE TABLE sqlite_stat1(tbl,idx,stat);
# MAIN: CREATE TABLE t1(a,b);
#
ifcapable altertable&&vtab {
do_test 1.350 {
proc auth {code arg1 arg2 arg3 arg4 args} {
if {$code=="SQLITE_ALTER_TABLE"} {
set ::authargs [list $arg1 $arg2 $arg3 $arg4]
return SQLITE_OK
}
return SQLITE_OK
}
catchsql {
ALTER TABLE t1 RENAME COLUMN b TO bcdefg;
}
} {0 {}}
do_execsql_test auth-1.351 {
SELECT name FROM pragma_table_info('t1') ORDER BY cid;
} {a bcdefg}
do_test auth-1.352 {
set authargs
} {main t1 {} {}}
do_test 1.353 {
proc auth {code arg1 arg2 arg3 arg4 args} {
if {$code=="SQLITE_ALTER_TABLE"} {
set ::authargs [list $arg1 $arg2 $arg3 $arg4]
return SQLITE_IGNORE
}
return SQLITE_OK
}
catchsql {
ALTER TABLE t1 RENAME COLUMN bcdefg TO b;
}
} {0 {}}
do_execsql_test auth-1.354 {
SELECT name FROM pragma_table_info('t1') ORDER BY cid;
} {a bcdefg}
do_test auth-1.355 {
set authargs
} {main t1 {} {}}
do_test 1.356 {
proc auth {code arg1 arg2 arg3 arg4 args} {
if {$code=="SQLITE_ALTER_TABLE"} {
set ::authargs [list $arg1 $arg2 $arg3 $arg4]
return SQLITE_DENY
}
return SQLITE_OK
}
catchsql {
ALTER TABLE t1 RENAME COLUMN bcdefg TO b;
}
} {1 {not authorized}}
do_execsql_test auth-1.356 {
SELECT name FROM pragma_table_info('t1') ORDER BY cid;
} {a bcdefg}
do_test auth-1.357 {
set authargs
} {main t1 {} {}}
}
do_test auth-2.1 {
proc auth {code arg1 arg2 arg3 arg4 args} {
if {$code=="SQLITE_READ" && $arg1=="t3" && $arg2=="x"} {
+172
View File
@@ -25,6 +25,11 @@ ifcapable {!autoinc} {
return
}
if {[permutation]=="inmemory_journal"} {
finish_test
return
}
sqlite3_db_config_lookaside db 0 0 0
# The database is initially empty.
@@ -675,6 +680,173 @@ do_execsql_test autoinc-10.1 {
SELECT * FROM sqlite_sequence;
} {t10a 888 t10b 888}
# 2018-04-21 autoincrement does not cause problems for upsert
#
do_execsql_test autoinc-11.1 {
CREATE TABLE t11(a INTEGER PRIMARY KEY AUTOINCREMENT,b UNIQUE);
INSERT INTO t11(a,b) VALUES(2,3),(5,6),(4,3),(1,2)
ON CONFLICT(b) DO UPDATE SET a=a+1000;
SELECT seq FROM sqlite_sequence WHERE name='t11';
} {5}
# 2018-05-23 ticket d8dc2b3a58cd5dc2918a1d4acbba4676a23ada4c
# Does not crash if the sqlite_sequence table schema is missing
# or corrupt.
#
do_test autoinc-12.1 {
db close
forcedelete test.db
sqlite3 db test.db
db eval {
CREATE TABLE fake_sequence(name TEXT PRIMARY KEY,seq) WITHOUT ROWID;
PRAGMA writable_schema=on;
UPDATE sqlite_master SET
sql=replace(sql,'fake_','sqlite_'),
name='sqlite_sequence',
tbl_name='sqlite_sequence'
WHERE name='fake_sequence';
}
db close
sqlite3 db test.db
set res [catch {db eval {
CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);
INSERT INTO t1(b) VALUES('one');
}} msg]
lappend res $msg
} {1 {database disk image is malformed}}
do_test autoinc-12.2 {
db close
forcedelete test.db
sqlite3 db test.db
db eval {
CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);
INSERT INTO t1(b) VALUES('one');
PRAGMA writable_schema=on;
UPDATE sqlite_master SET
sql=replace(sql,'sqlite_','x_'),
name='x_sequence',
tbl_name='x_sequence'
WHERE name='sqlite_sequence';
}
db close
sqlite3 db test.db
set res [catch {db eval {
INSERT INTO t1(b) VALUES('two');
}} msg]
lappend res $msg
} {1 {database disk image is malformed}}
ifcapable vtab {
set err "database disk image is malformed"
} else {
set err {malformed database schema (sqlite_sequence) - near "VIRTUAL": syntax error}
}
do_test autoinc-12.3 {
db close
forcedelete test.db
sqlite3 db test.db
db eval {
CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);
INSERT INTO t1(b) VALUES('one');
PRAGMA writable_schema=on;
UPDATE sqlite_master SET
sql='CREATE VIRTUAL TABLE sqlite_sequence USING sqlite_dbpage'
WHERE name='sqlite_sequence';
}
db close
sqlite3 db test.db
set res [catch {db eval {
INSERT INTO t1(b) VALUES('two');
}} msg]
lappend res $msg
} [list 1 $err]
do_test autoinc-12.4 {
db close
forcedelete test.db
sqlite3 db test.db
db eval {
CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);
INSERT INTO t1(b) VALUES('one');
CREATE TABLE fake(name TEXT PRIMARY KEY,seq) WITHOUT ROWID;
}
set root1 [db one {SELECT rootpage FROM sqlite_master
WHERE name='sqlite_sequence'}]
set root2 [db one {SELECT rootpage FROM sqlite_master
WHERE name='fake'}]
db eval {
PRAGMA writable_schema=on;
UPDATE sqlite_master SET rootpage=$root2
WHERE name='sqlite_sequence';
UPDATE sqlite_master SET rootpage=$root1
WHERE name='fake';
}
db close
sqlite3 db test.db
set res [catch {db eval {
INSERT INTO t1(b) VALUES('two');
}} msg]
lappend res $msg
} {1 {database disk image is malformed}}
breakpoint
do_test autoinc-12.5 {
db close
forcedelete test.db
sqlite3 db test.db
db eval {
CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);
INSERT INTO t1(b) VALUES('one');
PRAGMA writable_schema=on;
UPDATE sqlite_master SET
sql='CREATE TABLE sqlite_sequence(x)'
WHERE name='sqlite_sequence';
}
db close
sqlite3 db test.db
set res [catch {db eval {
INSERT INTO t1(b) VALUES('two');
}} msg]
lappend res $msg
} {1 {database disk image is malformed}}
do_test autoinc-12.6 {
db close
forcedelete test.db
sqlite3 db test.db
db eval {
CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);
INSERT INTO t1(b) VALUES('one');
PRAGMA writable_schema=on;
UPDATE sqlite_master SET
sql='CREATE TABLE sqlite_sequence(x,y INTEGER PRIMARY KEY)'
WHERE name='sqlite_sequence';
}
db close
sqlite3 db test.db
set res [catch {db eval {
INSERT INTO t1(b) VALUES('two'),('three'),('four');
INSERT INTO t1(b) VALUES('five');
PRAGMA integrity_check;
}} msg]
lappend res $msg
} {0 ok}
do_test autoinc-12.7 {
db close
forcedelete test.db
sqlite3 db test.db
db eval {
CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);
INSERT INTO t1(b) VALUES('one');
PRAGMA writable_schema=on;
UPDATE sqlite_master SET
sql='CREATE TABLE sqlite_sequence(y INTEGER PRIMARY KEY,x)'
WHERE name='sqlite_sequence';
}
db close
sqlite3 db test.db
set res [catch {db eval {
INSERT INTO t1(b) VALUES('two'),('three'),('four');
INSERT INTO t1(b) VALUES('five');
PRAGMA integrity_check;
}} msg]
lappend res $msg
} {0 ok}
finish_test
+32 -25
View File
@@ -177,35 +177,36 @@ do_execsql_test autoindex1-500 {
INSERT INTO sqlite_stat1(tbl,idx,stat) VALUES('t501',null,'1000000');
INSERT INTO sqlite_stat1(tbl,idx,stat) VALUES('t502',null,'1000');
ANALYZE sqlite_master;
EXPLAIN QUERY PLAN
}
do_eqp_test autoindex1-500.1 {
SELECT b FROM t501
WHERE t501.a IN (SELECT x FROM t502 WHERE y=?);
} {
0 0 0 {SEARCH TABLE t501 USING INTEGER PRIMARY KEY (rowid=?)}
0 0 0 {EXECUTE LIST SUBQUERY 1}
1 0 0 {SCAN TABLE t502}
QUERY PLAN
|--SEARCH TABLE t501 USING INTEGER PRIMARY KEY (rowid=?)
`--LIST SUBQUERY
`--SCAN TABLE t502
}
do_execsql_test autoindex1-501 {
EXPLAIN QUERY PLAN
do_eqp_test autoindex1-501 {
SELECT b FROM t501
WHERE t501.a IN (SELECT x FROM t502 WHERE y=t501.b);
} {
0 0 0 {SCAN TABLE t501}
0 0 0 {EXECUTE CORRELATED LIST SUBQUERY 1}
1 0 0 {SEARCH TABLE t502 USING AUTOMATIC COVERING INDEX (y=?)}
QUERY PLAN
|--SCAN TABLE t501
`--CORRELATED LIST SUBQUERY
`--SEARCH TABLE t502 USING AUTOMATIC COVERING INDEX (y=?)
}
do_execsql_test autoindex1-502 {
EXPLAIN QUERY PLAN
do_eqp_test autoindex1-502 {
SELECT b FROM t501
WHERE t501.a=123
AND t501.a IN (SELECT x FROM t502 WHERE y=t501.b);
} {
0 0 0 {SEARCH TABLE t501 USING INTEGER PRIMARY KEY (rowid=?)}
0 0 0 {EXECUTE CORRELATED LIST SUBQUERY 1}
1 0 0 {SCAN TABLE t502}
QUERY PLAN
|--SEARCH TABLE t501 USING INTEGER PRIMARY KEY (rowid=?)
`--CORRELATED LIST SUBQUERY
`--SCAN TABLE t502
}
# The following code checks a performance regression reported on the
# mailing list on 2010-10-19. The problem is that the nRowEst field
# of ephermeral tables was not being initialized correctly and so no
@@ -257,7 +258,8 @@ do_execsql_test autoindex1-600 {
ON sheep (originating_flock);
CREATE INDEX sheep_reg_flock_index
ON sheep (registering_flock);
EXPLAIN QUERY PLAN
}
do_eqp_test autoindex1-600a {
SELECT x.sheep_no, x.registering_flock, x.date_of_registration
FROM sheep x LEFT JOIN
(SELECT s.sheep_no, prev.flock_no, prev.owner_person_id,
@@ -274,21 +276,26 @@ do_execsql_test autoindex1-600 {
WHERE y.sheep_no IS NULL
ORDER BY x.registering_flock;
} {
1 0 0 {SCAN TABLE sheep AS s}
1 1 1 {SEARCH TABLE flock_owner AS prev USING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date<?)}
1 0 0 {EXECUTE CORRELATED SCALAR SUBQUERY 2}
2 0 0 {SEARCH TABLE flock_owner AS later USING COVERING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date>? AND owner_change_date<?)}
0 0 0 {SCAN TABLE sheep AS x USING INDEX sheep_reg_flock_index}
0 1 1 {SEARCH SUBQUERY 1 AS y USING AUTOMATIC COVERING INDEX (sheep_no=?)}
QUERY PLAN
|--MATERIALIZE xxxxxx
| |--SCAN TABLE sheep AS s
| |--SEARCH TABLE flock_owner AS prev USING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date<?)
| `--CORRELATED SCALAR SUBQUERY
| `--SEARCH TABLE flock_owner AS later USING COVERING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date>? AND owner_change_date<?)
|--SCAN TABLE sheep AS x USING INDEX sheep_reg_flock_index
`--SEARCH SUBQUERY xxxxxx AS y USING AUTOMATIC COVERING INDEX (sheep_no=?)
}
do_execsql_test autoindex1-700 {
CREATE TABLE t5(a, b, c);
EXPLAIN QUERY PLAN SELECT a FROM t5 WHERE b=10 ORDER BY c;
}
do_eqp_test autoindex1-700a {
SELECT a FROM t5 WHERE b=10 ORDER BY c;
} {
0 0 0 {SCAN TABLE t5}
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
QUERY PLAN
|--SCAN TABLE t5
`--USE TEMP B-TREE FOR ORDER BY
}
# The following checks a performance issue reported on the sqlite-dev
+3 -2
View File
@@ -84,8 +84,9 @@ do_execsql_test 210 {
do_eqp_test 220 {
select count(*) from u, v where u.b = v.b and v.e > 34;
} {
0 0 1 {SEARCH TABLE v USING INDEX ve (e>?)}
0 1 0 {SEARCH TABLE u USING AUTOMATIC COVERING INDEX (b=?)}
QUERY PLAN
|--SEARCH TABLE v USING INDEX ve (e>?)
`--SEARCH TABLE u USING AUTOMATIC COVERING INDEX (b=?)
}
+2 -3
View File
@@ -84,8 +84,7 @@ do_execsql_test autoindex5-1.0 {
# The following query should use an automatic index for the view
# in FROM clause of the subquery of the second result column.
#
do_execsql_test autoindex5-1.1 {
EXPLAIN QUERY PLAN
do_eqp_test autoindex5-1.1 {
SELECT
st.bug_name,
(SELECT ALL debian_cve.bug FROM debian_cve
@@ -103,7 +102,7 @@ do_execsql_test autoindex5-1.1 {
AND ( sp.release = 'sid' OR sp.release = 'stretch' OR sp.release = 'jessie'
OR sp.release = 'wheezy' OR sp.release = 'squeeze' )
ORDER BY sp.name, st.bug_name, sp.release, sp.subrelease;
} {/SEARCH SUBQUERY 2 USING AUTOMATIC COVERING INDEX .bug_name=/}
} {SEARCH SUBQUERY * USING AUTOMATIC COVERING INDEX (bug_name=?)}
#-------------------------------------------------------------------------
# Test that ticket [8a2adec1] has been fixed.
+2 -1
View File
@@ -22,7 +22,7 @@ source $testdir/tester.tcl
# Create several tables to work with.
#
do_test avtrans-1.0 {
execsql { PRAGMA auto_vacuum=ON }
execsql { PRAGMA auto_vacuum=full }
wal_set_journal_mode
execsql {
CREATE TABLE one(a int PRIMARY KEY, b text);
@@ -32,6 +32,7 @@ do_test avtrans-1.0 {
SELECT b FROM one ORDER BY a;
}
} {one two three}
do_test avtrans-1.0.1 { execsql { PRAGMA auto_vacuum } } 1
do_test avtrans-1.1 {
execsql {
CREATE TABLE two(a int PRIMARY KEY, b text);
+12 -17
View File
@@ -51,16 +51,11 @@ do_execsql_test 1.0 {
do_eqp_test 1.1 {
SELECT * FROM x1 WHERE a = 'abc'
} {
0 0 0 {SCAN TABLE x1 VIRTUAL TABLE INDEX 555:eq!}
}
} {SCAN TABLE x1 VIRTUAL TABLE INDEX 555:eq!}
do_eqp_test 1.2 {
SELECT * FROM x1 WHERE a IN ('abc', 'def');
} {
0 0 0 {SCAN TABLE x1 VIRTUAL TABLE INDEX 555:eq!}
0 0 0 {EXECUTE LIST SUBQUERY 1}
}
} {SCAN TABLE x1 VIRTUAL TABLE INDEX 555:eq!}
#-------------------------------------------------------------------------
#
@@ -145,24 +140,24 @@ foreach {tn mode} {
} {1 4}
set plan(use) {
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%'}
0 0 0 {EXECUTE LIST SUBQUERY 1}
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
QUERY PLAN
|--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%'
`--USE TEMP B-TREE FOR ORDER BY
}
set plan(omit) {
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%'}
0 0 0 {EXECUTE LIST SUBQUERY 1}
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
QUERY PLAN
|--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%'
`--USE TEMP B-TREE FOR ORDER BY
}
set plan(use2) {
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x}
0 0 0 {EXECUTE LIST SUBQUERY 1}
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
QUERY PLAN
|--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x
`--USE TEMP B-TREE FOR ORDER BY
}
do_eqp_test 2.2.$mode.6 {
SELECT rowid FROM t1 WHERE a IN ('one', 'four') ORDER BY +rowid
} $plan($mode)
} [string map {"\n " "\n"} $plan($mode)]
}
# 2016-04-09.
+22 -21
View File
@@ -89,40 +89,40 @@ do_execsql_test 1.0 {
do_eqp_test 1.1 {
SELECT * FROM t1 WHERE a='abc'
} {
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=?)}
}
} {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=?)}
do_eqp_test 1.2 {
SELECT * FROM t1 WHERE a='abc' AND b='def'
} {
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=? AND b=?)}
}
} {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=? AND b=?)}
do_eqp_test 1.3 {
SELECT * FROM t1 WHERE a='abc' AND a='def'
} {
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=?)}
}
} {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=?)}
do_eqp_test 1.4 {
SELECT * FROM t1,t2 WHERE c=a
} {
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:}
0 1 1 {SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?)}
QUERY PLAN
|--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:
`--SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?)
}
do_eqp_test 1.5 {
SELECT * FROM t1, t2 CROSS JOIN t3 WHERE t2.c = +t1.b AND t3.e=t2.d
} {
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:}
0 1 1 {SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?)}
0 2 2 {SCAN TABLE t3 VIRTUAL TABLE INDEX 0:indexed(e=?)}
QUERY PLAN
|--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:
|--SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?)
`--SCAN TABLE t3 VIRTUAL TABLE INDEX 0:indexed(e=?)
}
do_eqp_test 1.6 {
SELECT * FROM t1, t2, t3 WHERE t2.c = +t1.b AND t3.e = t2.d
} {
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:}
0 1 1 {SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?)}
0 2 2 {SCAN TABLE t3 VIRTUAL TABLE INDEX 0:indexed(e=?)}
QUERY PLAN
|--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:
|--SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?)
`--SCAN TABLE t3 VIRTUAL TABLE INDEX 0:indexed(e=?)
}
do_execsql_test 1.7.1 {
@@ -132,10 +132,11 @@ do_eqp_test 1.7.2 {
SELECT * FROM x1 CROSS JOIN t1, t2, t3
WHERE t1.a = t2.c AND t1.b = t3.e
} {
0 0 0 {SCAN TABLE x1}
0 1 1 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:}
0 2 2 {SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?)}
0 3 3 {SCAN TABLE t3 VIRTUAL TABLE INDEX 0:indexed(e=?)}
QUERY PLAN
|--SCAN TABLE x1
|--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:
|--SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?)
`--SCAN TABLE t3 VIRTUAL TABLE INDEX 0:indexed(e=?)
}
finish_test
+16 -14
View File
@@ -79,28 +79,28 @@ do_execsql_test 1.0 {
do_eqp_test 1.1 {
SELECT * FROM t1 WHERE a LIKE 'abc';
} {
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a LIKE ?}
}
} {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a LIKE ?}
do_eqp_test 1.2 {
SELECT * FROM t1 WHERE a = 'abc';
} {
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a EQ ?}
}
} {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a EQ ?}
do_eqp_test 1.3 {
SELECT * FROM t1 WHERE a = 'abc' OR b = 'def';
} {
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a EQ ?}
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:b EQ ?}
QUERY PLAN
`--MULTI-INDEX OR
|--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a EQ ?
`--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:b EQ ?
}
do_eqp_test 1.4 {
SELECT * FROM t1 WHERE a LIKE 'abc%' OR b = 'def';
} {
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a LIKE ?}
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:b EQ ?}
QUERY PLAN
`--MULTI-INDEX OR
|--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a LIKE ?
`--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:b EQ ?
}
do_execsql_test 1.5 {
@@ -147,10 +147,12 @@ ifcapable !icu {
do_eqp_test 2.2 {
SELECT * FROM t2 WHERE x LIKE 'abc%' OR y = 'def'
} {
0 0 0 {SEARCH TABLE t2 USING INDEX t2x (x>? AND x<?)}
0 0 0 {SEARCH TABLE t2 USING INDEX t2y (y=?)}
}
} [string map {"\n " \n} {
QUERY PLAN
`--MULTI-INDEX OR
|--SEARCH TABLE t2 USING INDEX t2x (x>? AND x<?)
`--SEARCH TABLE t2 USING INDEX t2y (y=?)
}]
}
#-------------------------------------------------------------------------
+250
View File
@@ -0,0 +1,250 @@
# 2017 September 10
#
# 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.
#
#***********************************************************************
# Test the virtual table interface. In particular the xBestIndex
# method.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix bestindex4
ifcapable !vtab {
finish_test
return
}
#-------------------------------------------------------------------------
# Virtual table callback for a virtual table named $tbl.
#
proc vtab_cmd {method args} {
set binops(ne) !=
set binops(eq) =
set binops(isnot) "IS NOT"
set binops(is) "IS"
set unops(isnotnull) "IS NOT NULL"
set unops(isnull) "IS NULL"
set cols(0) a
set cols(1) b
set cols(2) c
switch -- $method {
xConnect {
return "CREATE TABLE t1(a, b, c)"
}
xBestIndex {
foreach {clist orderby mask} $args {}
set cost 1000000.0
set ret [list]
set str [list]
set v 0
for {set i 0} {$i < [llength $clist]} {incr i} {
array unset C
array set C [lindex $clist $i]
if {$C(usable)} {
if {[info exists binops($C(op))]} {
lappend ret omit $i
lappend str "$cols($C(column)) $binops($C(op)) %$v%"
incr v
set cost [expr $cost / 2]
}
if {[info exists unops($C(op))]} {
lappend ret omit $i
lappend str "$cols($C(column)) $unops($C(op))"
incr v
set cost [expr $cost / 2]
}
}
}
lappend ret idxstr [join $str " AND "]
lappend ret cost $cost
return $ret
}
xFilter {
set q [lindex $args 1]
set a [lindex $args 2]
for {set v 0} {$v < [llength $a]} {incr v} {
set val [lindex $a $v]
set q [string map [list %$v% '$val'] $q]
}
if {$q==""} { set q 1 }
lappend ::xFilterQueries "WHERE $q"
return [list sql "SELECT rowid, * FROM t1x WHERE $q"]
}
}
return ""
}
proc vtab_simple {method args} {
switch -- $method {
xConnect {
return "CREATE TABLE t2(x)"
}
xBestIndex {
return [list cost 999999.0]
}
xFilter {
return [list sql "SELECT rowid, * FROM t2x"]
}
}
return ""
}
register_tcl_module db
proc do_vtab_query_test {tn query result} {
set ::xFilterQueries [list]
uplevel [list
do_test $tn [string map [list %QUERY% $query] {
set r [execsql {%QUERY%}]
set r [concat $::xFilterQueries $r]
set r
}] [list {*}$result]
]
}
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING tcl('vtab_cmd');
CREATE TABLE t1x(a INTEGER, b TEXT, c REAL);
INSERT INTO t1x VALUES(1, 2, 3);
INSERT INTO t1x VALUES(4, 5, 6);
INSERT INTO t1x VALUES(7, 8, 9);
CREATE VIRTUAL TABLE t2 USING tcl('vtab_simple');
CREATE TABLE t2x(x INTEGER);
INSERT INTO t2x VALUES(1);
}
do_vtab_query_test 1.1 { SELECT * FROM t1 WHERE a!='hello'; } {
"WHERE a != 'hello'"
1 2 3.0 4 5 6.0 7 8 9.0
}
do_vtab_query_test 1.2.1 { SELECT * FROM t1 WHERE b!=8 } {
"WHERE b != '8'"
1 2 3.0 4 5 6.0
}
do_vtab_query_test 1.2.2 { SELECT * FROM t1 WHERE 8!=b } {
"WHERE b != '8'"
1 2 3.0 4 5 6.0
}
do_vtab_query_test 1.3 { SELECT * FROM t1 WHERE c IS NOT 3 } {
"WHERE c IS NOT '3'"
4 5 6.0 7 8 9.0
}
do_vtab_query_test 1.3.2 { SELECT * FROM t1 WHERE 3 IS NOT c } {
"WHERE c IS NOT '3'"
4 5 6.0 7 8 9.0
}
do_vtab_query_test 1.4.1 { SELECT * FROM t1, t2 WHERE x != a } {
"WHERE a != '1'"
4 5 6.0 1 7 8 9.0 1
}
do_vtab_query_test 1.4.2 { SELECT * FROM t1, t2 WHERE a != x } {
"WHERE a != '1'"
4 5 6.0 1 7 8 9.0 1
}
do_vtab_query_test 1.5.1 { SELECT * FROM t1 WHERE a IS NOT NULL } {
"WHERE a IS NOT NULL"
1 2 3.0 4 5 6.0 7 8 9.0
}
do_vtab_query_test 1.5.2 { SELECT * FROM t1 WHERE NULL IS NOT a } {
"WHERE a IS NOT ''"
1 2 3.0 4 5 6.0 7 8 9.0
}
do_vtab_query_test 1.6.1 { SELECT * FROM t1 WHERE a IS NULL } {
"WHERE a IS NULL"
}
do_vtab_query_test 1.6.2 { SELECT * FROM t1 WHERE NULL IS a } {
"WHERE a IS ''"
}
do_vtab_query_test 1.7.1 { SELECT * FROM t1 WHERE (a, b) IS (1, 2) } {
"WHERE a IS '1' AND b IS '2'"
1 2 3.0
}
do_vtab_query_test 1.7.2 { SELECT * FROM t1 WHERE (5, 4) IS (b, a) } {
{WHERE b IS '5' AND a IS '4'}
4 5 6.0
}
#---------------------------------------------------------------------
do_execsql_test 2.0.0 {
DELETE FROM t1x;
INSERT INTO t1x VALUES('a', 'b', 'c');
}
do_execsql_test 2.0.1 { SELECT * FROM t1 } {a b c}
do_execsql_test 2.0.2 { SELECT * FROM t1 WHERE (a, b) != ('a', 'b'); } {}
do_execsql_test 2.1.0 {
DELETE FROM t1x;
INSERT INTO t1x VALUES(7, 8, 9);
}
do_execsql_test 2.1.1 { SELECT * FROM t1 } {7 8 9.0}
do_execsql_test 2.1.2 { SELECT * FROM t1 WHERE (a, b) != (7, '8') } {}
do_execsql_test 2.1.3 { SELECT * FROM t1 WHERE a!=7 OR b!='8' }
do_execsql_test 2.1.4 { SELECT * FROM t1 WHERE a!=7 OR b!='8' }
do_execsql_test 2.2.1 {
CREATE TABLE t3(a INTEGER, b TEXT);
INSERT INTO t3 VALUES(45, 46);
}
do_execsql_test 2.2.2 { SELECT * FROM t3 WHERE (a, b) != (45, 46); }
do_execsql_test 2.2.3 { SELECT * FROM t3 WHERE (a, b) != ('45', '46'); }
do_execsql_test 2.2.4 { SELECT * FROM t3 WHERE (a, b) == (45, 46); } {45 46}
do_execsql_test 2.2.5 { SELECT * FROM t3 WHERE (a, b) == ('45', '46'); } {45 46}
#---------------------------------------------------------------------
# Test the != operator on a virtual table with column affinities.
#
proc vtab_simple_integer {method args} {
switch -- $method {
xConnect {
return "CREATE TABLE t4(x INTEGER)"
}
xBestIndex {
return [list cost 999999.0]
}
xFilter {
return [list sql "SELECT rowid, * FROM t4x"]
}
}
return ""
}
do_execsql_test 3.0 {
CREATE TABLE t4x(a INTEGER);
INSERT INTO t4x VALUES(245);
CREATE VIRTUAL TABLE t4 USING tcl('vtab_simple_integer');
}
do_execsql_test 3.1 { SELECT rowid, * FROM t4 WHERE x=245; } {1 245}
do_execsql_test 3.2 { SELECT rowid, * FROM t4 WHERE x='245'; } {1 245}
do_execsql_test 3.3 { SELECT rowid, * FROM t4 WHERE x!=245; } {}
do_execsql_test 3.4 { SELECT rowid, * FROM t4 WHERE x!='245'; } {}
do_execsql_test 3.5 { SELECT rowid, * FROM t4 WHERE rowid!=1 OR x!='245'; } {}
finish_test
+109
View File
@@ -0,0 +1,109 @@
# 2018-09-09
#
# 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.
#
#***********************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix bestindex6
ifcapable !vtab {
finish_test
return
}
register_tcl_module db
proc vtab_command {src method args} {
switch -- $method {
xConnect {
return [db one {SELECT sql FROM sqlite_master where name = $src}]
}
xBestIndex {
set clist [lindex $args 0]
set wlist 1
set iCons 0
set ret [list]
foreach cons $clist {
catch { array unset C }
array set C $cons
if {$C(usable)} {
set col [db one {
SELECT name FROM pragma_table_info($src) WHERE cid=$C(column)
}]
switch $C(op) {
isnull {
lappend wlist "$col IS NULL"
lappend ret omit $iCons
}
eq {
lappend wlist "$col = %$iCons%"
lappend ret omit $iCons
}
}
}
incr iCons
}
#puts "xBestIndex: $ret"
lappend ret idxStr [join $wlist " AND "]
return $ret
}
xFilter {
foreach {idxnum idxstr aa} $args {}
set map [list]
for {set iCons 0} {$iCons < [llength $aa]} {incr iCons} {
lappend map %$iCons% [lindex $aa $iCons]
}
set ret [list sql \
"SELECT rowid, * FROM $src WHERE [string map $map $idxstr]"
]
# puts "xFilter: $ret"
return $ret
}
}
return {}
}
do_execsql_test 1.0 {
CREATE TABLE t1(id int, value text);
CREATE TABLE t2(ctx int, id int, value text);
INSERT INTO t1 VALUES(1,'try');
INSERT INTO t2 VALUES(1,1,'good');
INSERT INTO t2 VALUES(2,2,'evil');
CREATE VIRTUAL TABLE vt1 USING tcl(vtab_command t1);
CREATE VIRTUAL TABLE vt2 USING tcl(vtab_command t2);
}
do_execsql_test 1.1 {
select * from t2 left join t1 on t1.id=t2.ctx where t1.value is null;
} {2 2 evil {} {}}
do_execsql_test 1.2 {
select * from vt2 left join vt1 on vt1.id=vt2.ctx where vt1.value is null;
} {2 2 evil {} {}}
unset -nocomplain xxx
do_execsql_test 1.3 {
select * from vt2 left join vt1 on vt1.id=vt2.ctx where vt1.value is $xxx;
} {2 2 evil {} {}}
do_execsql_test 1.4 {
select * from t2 left join vt1 on vt1.id=t2.ctx where vt1.value = 3
} {}
finish_test
+104
View File
@@ -0,0 +1,104 @@
# 2017 August 07
#
# 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 testing the ability of SQLite to use mmap
# to access files larger than 4GiB.
#
if {[file exists skip-big-file]} return
if {$tcl_platform(os)=="Darwin"} return
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix bigmmap
ifcapable !mmap||!vtab {
finish_test
return
}
set mmap_limit 0
db eval {
SELECT compile_options AS x FROM pragma_compile_options
WHERE x LIKE 'max_mmap_size=%'
} {
regexp {MAX_MMAP_SIZE=([0-9]*)} $x -> mmap_limit
}
if {$mmap_limit < [expr 8 * 1<<30]} {
puts "Skipping bigmmap.test - requires SQLITE_MAX_MMAP_SIZE >= 8G"
finish_test
return
}
#-------------------------------------------------------------------------
# Create the database file roughly 8GiB in size. Most pages are unused,
# except that there is a table and index clustered around each 1GiB
# boundary.
#
do_execsql_test 1.0 {
PRAGMA page_size = 4096;
CREATE TABLE t0(a INTEGER PRIMARY KEY, b, c, UNIQUE(b, c));
WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 100 )
INSERT INTO t0 SELECT i, 't0', randomblob(800) FROM s;
}
for {set i 1} {$i < 8} {incr i} {
fake_big_file [expr $i*1024] [get_pwd]/test.db
hexio_write test.db 28 [format %.8x [expr ($i*1024*1024*1024/4096) - 5]]
do_execsql_test 1.$i "
CREATE TABLE t$i (a INTEGER PRIMARY KEY, b, c, UNIQUE(b, c));
WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 100 )
INSERT INTO t$i SELECT i, 't$i', randomblob(800) FROM s;
"
}
#-------------------------------------------------------------------------
# Check that data can be retrieved from the db with a variety of
# configured mmap size limits.
#
for {set i 0} {$i < 9} {incr i} {
# Configure a memory mapping $i GB in size.
#
set val [expr $i*1024*1024*1024]
execsql "PRAGMA main.mmap_size = $val"
do_execsql_test 2.$i.0 {
PRAGMA main.mmap_size
} $val
for {set t 0} {$t < 8} {incr t} {
do_execsql_test 2.$i.$t.1 "
SELECT count(*) FROM t$t;
SELECT count(b || c) FROM t$t GROUP BY b;
" {100 100}
do_execsql_test 2.$i.$t.2 "
SELECT * FROM t$t AS o WHERE
NOT EXISTS( SELECT * FROM t$t AS i WHERE a=o.a AND +b=o.b AND +c=o.c )
ORDER BY b, c;
" {}
do_eqp_test 2.$i.$t.3 "
SELECT * FROM t$t AS o WHERE
NOT EXISTS( SELECT * FROM t$t AS i WHERE a=o.a AND +b=o.b AND +c=o.c )
ORDER BY b, c;
" [string map {"\n " "\n"} "
QUERY PLAN
|--SCAN TABLE t$t AS o USING COVERING INDEX sqlite_autoindex_t${t}_1
`--CORRELATED SCALAR SUBQUERY
`--SEARCH TABLE t$t AS i USING INTEGER PRIMARY KEY (rowid=?)
"]
}
}
finish_test
+3 -1
View File
@@ -33,6 +33,8 @@ do_test btree02-110 {
db eval BEGIN
set i 0
db eval {SELECT a, ax, b, cnt FROM t1 CROSS JOIN t3 WHERE b IS NOT NULL} {
if {$a==""} {set a 0}
if {$b==""} {set b 0}
db eval {INSERT INTO t2(x,y) VALUES($b,$cnt)}
# puts "a,b,cnt = ($a,$b,$cnt)"
incr i
@@ -47,6 +49,6 @@ do_test btree02-110 {
db eval {COMMIT; BEGIN}
}
db one {COMMIT; SELECT count(*) FROM t1;}
} {20}
} {27}
finish_test
+80 -2
View File
@@ -10,11 +10,11 @@
#***********************************************************************
# This file test the busy handler
#
# $Id: busy.test,v 1.3 2008/03/15 02:09:22 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix busy
do_test busy-1.1 {
sqlite3 db2 test.db
@@ -55,7 +55,85 @@ do_test busy-2.2 {
set busyargs
} {0 1 2 3}
db2 close
#-------------------------------------------------------------------------
# Test that the busy-handler is invoked correctly for "PRAGMA optimize"
# and ANALYZE commnds.
ifcapable pragma&&analyze&&!stat4 {
reset_db
do_execsql_test 3.1 {
CREATE TABLE t1(x);
CREATE TABLE t2(y);
CREATE TABLE t3(z);
CREATE INDEX i1 ON t1(x);
CREATE INDEX i2 ON t2(y);
INSERT INTO t1 VALUES(1);
INSERT INTO t2 VALUES(1);
ANALYZE;
SELECT * FROM t1 WHERE x=1;
SELECT * FROM t2 WHERE y=1;
} {1 1}
do_test 3.2 {
sqlite3 db2 test.db
execsql { BEGIN EXCLUSIVE } db2
catchsql { PRAGMA optimize }
} {1 {database is locked}}
proc busy_handler {n} {
if {$n>1000} { execsql { COMMIT } db2 }
return 0
}
db busy busy_handler
do_test 3.3 {
catchsql { PRAGMA optimize }
} {0 {}}
do_test 3.4 {
execsql {
BEGIN;
SELECT count(*) FROM sqlite_master;
} db2
} {6}
proc busy_handler {n} { return 1 }
do_test 3.5 {
catchsql { PRAGMA optimize }
} {0 {}}
do_test 3.6 {
execsql { COMMIT } db2
execsql {
WITH s(i) AS (
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1000
)
INSERT INTO t1 SELECT i FROM s;
}
execsql {
BEGIN;
SELECT count(*) FROM sqlite_master;
} db2
} {6}
do_test 3.7 {
catchsql { PRAGMA optimize }
} {1 {database is locked}}
proc busy_handler {n} {
if {$n>1000} { execsql { COMMIT } db2 }
return 0
}
do_test 3.8 {
catchsql { PRAGMA optimize }
} {0 {}}
}
finish_test
+2 -2
View File
@@ -163,7 +163,7 @@ do_test capi2-3.2 {
sqlite3_prepare $DB {select bogus from } -1 TAIL
} msg]
lappend rc $msg $TAIL
} {1 {(1) near " ": syntax error} {}}
} {1 {(1) incomplete input} {}}
do_test capi2-3.3 {
set rc [catch {
sqlite3_prepare $DB {;;;;select bogus from sqlite_master} -1 TAIL
@@ -184,7 +184,7 @@ do_test capi2-3.5 {
} {1 {(1) no such column: bogus} {;;x;}}
do_test capi2-3.6 {
set rc [catch {
sqlite3_prepare $DB {select 5/0} -1 TAIL
sqlite3_prepare $DB {select 5/0;} -1 TAIL
} VM]
lappend rc $TAIL
} {0 {}}
+12
View File
@@ -649,6 +649,18 @@ do_test capi3-5.33 {
sqlite3_finalize $STMT
} SQLITE_OK
# 2018-01-09: If a column is the last token if a string, the column name
# was not being set correctly, due to changes in check-in
# https://sqlite.org/src/info/0fdf97efe5df7455
#
# This problem was detected by the community during beta-testing.
#
do_test capi3-5.34 {
set STMT [sqlite3_prepare $DB {SELECT :a, :b} -1 TAIL]
sqlite3_column_count $STMT
} 2
check_header $STMT capi-5.35 {:a :b} {{} {}}
sqlite3_finalize $STMT
set ::ENC [execsql {pragma encoding}]
db close
+45
View File
@@ -343,4 +343,49 @@ do_test cast-4.4 {
}
} {0 abc 0.0 abc}
# Added 2018-01-26
#
# EVIDENCE-OF: R-48741-32454 If the prefix integer is greater than
# +9223372036854775807 then the result of the cast is exactly
# +9223372036854775807.
do_execsql_test cast-5.1 {
SELECT CAST('9223372036854775808' AS integer);
SELECT CAST(' +000009223372036854775808' AS integer);
SELECT CAST('12345678901234567890123' AS INTEGER);
} {9223372036854775807 9223372036854775807 9223372036854775807}
# EVIDENCE-OF: R-06028-16857 Similarly, if the prefix integer is less
# than -9223372036854775808 then the result of the cast is exactly
# -9223372036854775808.
do_execsql_test cast-5.2 {
SELECT CAST('-9223372036854775808' AS integer);
SELECT CAST('-9223372036854775809' AS integer);
SELECT CAST('-12345678901234567890123' AS INTEGER);
} {-9223372036854775808 -9223372036854775808 -9223372036854775808}
# EVIDENCE-OF: R-33990-33527 When casting to INTEGER, if the text looks
# like a floating point value with an exponent, the exponent will be
# ignored because it is no part of the integer prefix.
# EVIDENCE-OF: R-24225-46995 For example, "(CAST '123e+5' AS INTEGER)"
# results in 123, not in 12300000.
do_execsql_test case-5.3 {
SELECT CAST('123e+5' AS INTEGER);
SELECT CAST('123e+5' AS NUMERIC);
} {123 12300000.0}
# The following does not have anything to do with the CAST operator,
# but it does deal with affinity transformations.
#
do_execsql_test case-6.1 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a NUMERIC);
INSERT INTO t1 VALUES
('9000000000000000001'),
('9000000000000000001 '),
(' 9000000000000000001'),
(' 9000000000000000001 ');
SELECT * FROM t1;
} {9000000000000000001 9000000000000000001 9000000000000000001 9000000000000000001}
finish_test
+19
View File
@@ -273,4 +273,23 @@ do_execsql_test 5.1 {
ORDER BY id;
} {8 9 10 11 12 13 14 15}
#-------------------------------------------------------------------------
# At one point the following join query was causing a malfunction in
# xBestIndex.
#
do_execsql_test 6.0 {
CREATE TABLE t4 (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
parent_id INTEGER
);
CREATE VIRTUAL TABLE vt4 USING transitive_closure (
idcolumn=id, parentcolumn=parent_id, tablename=t4
);
}
do_execsql_test 6.1 {
SELECT * FROM t4, vt4 WHERE t4.id = vt4.root AND vt4.id=4 AND vt4.depth=2;
}
finish_test
+59
View File
@@ -378,5 +378,64 @@ do_test colname-9.210 {
execsql2 {SELECT t1.a, v3.a AS n FROM t1 JOIN v3}
} {a 1 n 3}
# 2017-12-23: Ticket https://www.sqlite.org/src/info/3b4450072511e621
# Inconsistent column names in CREATE TABLE AS
#
# Verify that the names of columns in the created table of a CREATE TABLE AS
# are the same as the names of result columns in the SELECT statement.
#
do_execsql_test colname-9.300 {
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
CREATE TABLE t1(aaa INT);
INSERT INTO t1(aaa) VALUES(123);
}
do_test colname-9.310 {
execsql2 {SELECT BBb FROM (SELECT aaa AS Bbb FROM t1)}
} {Bbb 123}
ifcapable vtab {
do_execsql_test colname-9.320 {
CREATE TABLE t2 AS SELECT BBb FROM (SELECT aaa AS Bbb FROM t1);
SELECT name FROM pragma_table_info('t2');
} {Bbb}
}
# Issue detected by OSSFuzz on 2017-12-24 (Christmas Eve)
# caused by check-in https://sqlite.org/src/info/6b2ff26c25
#
# Prior to being fixed, the following CREATE TABLE was dereferencing
# a NULL pointer and segfaulting.
#
do_catchsql_test colname-9.400 {
CREATE TABLE t4 AS SELECT #0;
} {1 {near "#0": syntax error}}
# Issue detected by OSSFuzz on 2017-12-25 (Christmas Day)
# also caused by check-in https://sqlite.org/src/info/6b2ff26c25
#
# Prior to being fixed, the following CREATE TABLE caused an
# assertion fault.
#
do_catchsql_test colname-9.410 {
CREATE TABLE t5 AS SELECT RAISE(abort,a);
} {1 {RAISE() may only be used within a trigger-program}}
# Make sure the quotation marks get removed from the column names
# when constructing a new table from an aggregate SELECT.
# Email from Juergen Palm on 2017-07-11.
#
do_execsql_test colname-10.100 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1("with space" TEXT);
DROP TABLE IF EXISTS t2;
CREATE TABLE t2 AS SELECT "with space" FROM t1;
PRAGMA table_info(t2);
} {0 {with space} TEXT 0 {} 0}
do_execsql_test colname-10.110 {
DROP TABLE IF EXISTS t3;
CREATE TABLE t3 AS SELECT "with space" FROM t1 GROUP BY 1;
PRAGMA table_info(t3);
} {0 {with space} TEXT 0 {} 0}
finish_test
+2 -2
View File
@@ -591,7 +591,7 @@ do_test 14.2 {
do_execsql_test 14.3 {
PRAGMA integrity_check;
} {{*** in database main ***
Main freelist: free-page count in header is too small}}
Main freelist: size is 3 but should be 2}}
# Use 2 of the free pages on the free-list.
#
@@ -603,7 +603,7 @@ do_execsql_test 14.4 {
do_execsql_test 14.5 {
PRAGMA integrity_check;
} {{*** in database main ***
Page 3 is never used}}
Main freelist: size is 1 but should be 0}}
finish_test
+8 -4
View File
@@ -67,8 +67,7 @@ do_test corrupt3-1.5 {
integrity_check corrupt3-1.6
# Make the overflow chain loop back on itself. See if the
# corruption is detected. (Actually, the last pointer in
# an overflow chain is ignored, so this is not an error.)
# corruption is detected.
#
do_test corrupt3-1.7 {
db close
@@ -78,7 +77,12 @@ do_test corrupt3-1.7 {
SELECT x FROM t1
}
} [list 0 $bigstring]
integrity_check corrupt3-1.8
do_test corrupt3-1.8 {
catchsql {
PRAGMA integrity_check
}
} {0 {{*** in database main ***
On tree page 2 cell 0: 2nd reference to page 3}}}
# Change the pointer for the first page of the overflow
# change to be a non-existant page.
@@ -111,7 +115,7 @@ do_test corrupt3-1.12 {
PRAGMA integrity_check
}
} {0 {{*** in database main ***
On tree page 2 cell 0: 1 of 1 pages missing from overflow list starting at 0
On tree page 2 cell 0: overflow list length is 0 but should be 1
Page 3 is never used}}}
finish_test
+1 -1
View File
@@ -164,7 +164,7 @@ do_test corruptC-2.5 {
catchsql {BEGIN; UPDATE t2 SET y='abcdef-uvwxyz'; ROLLBACK;}
catchsql {PRAGMA integrity_check}
} {0 {{*** in database main ***
On tree page 4 cell 19: Extends off end of page}}}
On tree page 4 cell 19: Extends off end of page} {database disk image is malformed}}}
# {0 {{*** in database main ***
# Corruption detected in cell 710 on page 4
+115
View File
@@ -107,6 +107,121 @@ do_catchsql_test 2.3 {
INSERT INTO t1 VALUES(randomblob(900));
} {1 {database disk image is malformed}}
#-------------------------------------------------------------------------
ifcapable vtab {
if {[permutation]!="inmemory_journal"} {
proc hex2blob {hex} {
# Split on newlines:
set bytes [list]
foreach l [split $hex "\n"] {
if {[string is space $l]} continue
set L [list]
foreach b [split $l] {
if {[string is xdigit $b] && [string length $b]==2} {
lappend L [expr "0x$b"]
}
}
if {[llength $L]!=16} {
error "Badly formed hex (1)"
}
set bytes [concat $bytes $L]
}
binary format c* $bytes
}
reset_db
db func hex2blob hex2blob
do_execsql_test 3.1 {
PRAGMA page_size=1024;
CREATE TABLE t1(a, b, c);
CREATE TABLE t2(a, b, c);
CREATE TABLE t3(a, b, c);
CREATE TABLE t4(a, b, c);
CREATE TABLE t5(a, b, c);
}
do_execsql_test 3.2 {
UPDATE sqlite_dbpage SET data = hex2blob('
000: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
010: 04 00 01 01 20 40 20 20 00 00 3e d9 00 00 00 06 .... @ ..>.....
020: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 04 ................
030: 0f 00 00 00 00 00 00 00 00 00 00 01 00 00 83 00 ................
040: 00 00 00 00 00 00 00 00 00 00 00 00 00 38 00 00 .............8..
050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3e d9 ..............>.
060: 00 2d e6 07 0d 00 00 00 01 03 a0 00 03 e0 00 00 .-..............
070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0d0: 00 00 00 00 00 c1 00 00 00 00 00 00 00 00 00 00 ................
0e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
160: 00 83 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
180: 00 00 00 00 00 00 00 00 00 00 07 00 30 00 00 00 ............0...
190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
1a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
1b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
1c0: 02 00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 ................
1d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
1e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
1f0: 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
210: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
220: 00 00 0e 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
230: 0c 00 00 00 00 00 00 60 00 00 00 06 00 00 c3 00 .......`........
240: 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
250: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
260: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
270: 00 00 00 18 00 00 00 00 00 00 00 00 00 00 00 00 ................
280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
290: 04 00 0e 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2b0: 00 00 00 00 83 00 8c 00 00 00 00 00 00 00 00 00 ................
2c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
310: 00 78 00 00 00 00 00 00 00 00 00 00 00 00 70 00 .x............p.
320: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
330: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
340: 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 ................
350: 00 00 00 00 00 68 00 00 00 00 00 00 00 00 00 00 .....h..........
360: 00 00 00 00 00 03 00 00 00 00 00 00 00 00 00 00 ................
370: 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 ................
380: 00 00 00 00 70 00 00 00 00 00 00 00 00 00 00 00 ....p...........
390: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
3a0: 5e 01 07 17 1b 1b 01 81 13 74 61 62 6c 65 73 65 ^........tablese
3b0: 6e 73 6f 32 73 73 65 6e 73 6f 72 73 02 43 52 45 nso2ssensors.CRE
3c0: 41 54 45 20 54 41 42 4c 45 20 73 65 6e 73 6f 72 ATE TABLE sensor
3d0: 73 20 0a 20 20 24 20 20 20 20 20 20 20 20 20 20 s . $
3e0: b8 6e 61 6d 65 21 74 65 78 74 2c 20 79 61 6c 20 .name!text, yal
3f0: 72 65 61 6c 2c 20 74 69 6d 65 20 74 65 78 74 29 real, time text)
') WHERE pgno=1
}
db close
sqlite3 db test.db
do_catchsql_test 3.3 {
PRAGMA integrity_check;
} {1 {database disk image is malformed}}
} ;# [permutation]!="inmemory_journal"
} ;# ifcapable vtab
+40 -47
View File
@@ -24,8 +24,9 @@ do_execsql_test 1.1 {
do_eqp_test 1.2 {
SELECT e FROM t3, t4 WHERE b=c ORDER BY b, d;
} {
0 0 0 {SCAN TABLE t3 USING COVERING INDEX i3}
0 1 1 {SEARCH TABLE t4 USING INDEX i4 (c=?)}
QUERY PLAN
|--SCAN TABLE t3 USING COVERING INDEX i3
`--SEARCH TABLE t4 USING INDEX i4 (c=?)
}
@@ -38,9 +39,7 @@ do_execsql_test 2.1 {
# if the index is a non-covering index.
do_eqp_test 2.2 {
SELECT * FROM t1 ORDER BY a;
} {
0 0 0 {SCAN TABLE t1 USING INDEX i1}
}
} {SCAN TABLE t1 USING INDEX i1}
do_execsql_test 3.1 {
CREATE TABLE t5(a INTEGER PRIMARY KEY,b,c,d,e,f,g);
@@ -57,10 +56,12 @@ do_eqp_test 3.2 {
WHERE b IS NULL OR c IS NULL OR d IS NULL
ORDER BY a;
} {
0 0 0 {SEARCH TABLE t5 USING INDEX t5b (b=?)}
0 0 0 {SEARCH TABLE t5 USING INDEX t5c (c=?)}
0 0 0 {SEARCH TABLE t5 USING INDEX t5d (d=?)}
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
QUERY PLAN
|--MULTI-INDEX OR
| |--SEARCH TABLE t5 USING INDEX t5b (b=?)
| |--SEARCH TABLE t5 USING INDEX t5c (c=?)
| `--SEARCH TABLE t5 USING INDEX t5d (d=?)
`--USE TEMP B-TREE FOR ORDER BY
}
#-------------------------------------------------------------------------
@@ -79,14 +80,11 @@ do_execsql_test 4.1 {
}
do_eqp_test 4.2 {
SELECT * FROM t1 WHERE likelihood(a=?, 0.014) AND b BETWEEN ? AND ?;
} {
0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}
}
} {SEARCH TABLE t1 USING INDEX i1 (a=?)}
do_eqp_test 4.3 {
SELECT * FROM t1 WHERE likelihood(a=?, 0.016) AND b BETWEEN ? AND ?;
} {
0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b>? AND b<?)}
}
} {SEARCH TABLE t1 USING INDEX i2 (b>? AND b<?)}
#-------------------------------------------------------------------------
@@ -100,15 +98,17 @@ do_execsql_test 5.1 {
do_eqp_test 5.2 {
SELECT * FROM t2 ORDER BY x, y;
} {
0 0 0 {SCAN TABLE t2 USING INDEX t2i1}
0 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
QUERY PLAN
|--SCAN TABLE t2 USING INDEX t2i1
`--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY
}
do_eqp_test 5.3 {
SELECT * FROM t2 WHERE x BETWEEN ? AND ? ORDER BY rowid;
} {
0 0 0 {SEARCH TABLE t2 USING INDEX t2i1 (x>? AND x<?)}
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
QUERY PLAN
|--SEARCH TABLE t2 USING INDEX t2i1 (x>? AND x<?)
`--USE TEMP B-TREE FOR ORDER BY
}
# where7.test, where8.test:
@@ -122,9 +122,11 @@ do_execsql_test 6.1 {
do_eqp_test 6.2 {
SELECT a FROM t3 WHERE (b BETWEEN 2 AND 4) OR c=100 ORDER BY a
} {
0 0 0 {SEARCH TABLE t3 USING INDEX t3i1 (b>? AND b<?)}
0 0 0 {SEARCH TABLE t3 USING INDEX t3i2 (c=?)}
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
QUERY PLAN
|--MULTI-INDEX OR
| |--SEARCH TABLE t3 USING INDEX t3i1 (b>? AND b<?)
| `--SEARCH TABLE t3 USING INDEX t3i2 (c=?)
`--USE TEMP B-TREE FOR ORDER BY
}
#-------------------------------------------------------------------------
@@ -145,9 +147,11 @@ do_eqp_test 7.2 {
WHERE (b>=950 AND b<=1010) OR (b IS NULL AND c NOT NULL)
ORDER BY a
} {
0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}
0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
QUERY PLAN
|--MULTI-INDEX OR
| |--SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)
| `--SEARCH TABLE t1 USING INDEX t1b (b=?)
`--USE TEMP B-TREE FOR ORDER BY
}
do_eqp_test 7.3 {
@@ -155,15 +159,11 @@ do_eqp_test 7.3 {
WHERE (+b IS NULL AND c NOT NULL AND d NOT NULL)
OR (b NOT NULL AND c IS NULL AND d NOT NULL)
OR (b NOT NULL AND c NOT NULL AND d IS NULL)
} {
0 0 0 {SCAN TABLE t1}
}
} {SCAN TABLE t1}
do_eqp_test 7.4 {
SELECT rowid FROM t1 WHERE (+b IS NULL AND c NOT NULL) OR c IS NULL
} {
0 0 0 {SCAN TABLE t1}
}
} {SCAN TABLE t1}
#-------------------------------------------------------------------------
#
@@ -194,10 +194,11 @@ do_eqp_test 8.2 {
AND unlikely(composer.cid=track.cid)
AND unlikely(album.aid=track.aid);
} {
0 0 2 {SCAN TABLE track}
0 1 0 {SEARCH TABLE album USING INTEGER PRIMARY KEY (rowid=?)}
0 2 1 {SEARCH TABLE composer USING INTEGER PRIMARY KEY (rowid=?)}
0 0 0 {USE TEMP B-TREE FOR DISTINCT}
QUERY PLAN
|--SCAN TABLE track
|--SEARCH TABLE album USING INTEGER PRIMARY KEY (rowid=?)
|--SEARCH TABLE composer USING INTEGER PRIMARY KEY (rowid=?)
`--USE TEMP B-TREE FOR DISTINCT
}
#-------------------------------------------------------------------------
@@ -263,27 +264,19 @@ ifcapable stat4 {
do_eqp_test 10.3 {
SELECT rowid FROM t6 WHERE a=0 AND c=0
} {
0 0 0 {SEARCH TABLE t6 USING INDEX t6i2 (c=?)}
}
} {SEARCH TABLE t6 USING INDEX t6i2 (c=?)}
do_eqp_test 10.4 {
SELECT rowid FROM t6 WHERE a=0 AND b='xyz' AND c=0
} {
0 0 0 {SEARCH TABLE t6 USING INDEX t6i2 (c=?)}
}
} {SEARCH TABLE t6 USING INDEX t6i2 (c=?)}
do_eqp_test 10.5 {
SELECT rowid FROM t6 WHERE likelihood(a=0, 0.1) AND c=0
} {
0 0 0 {SEARCH TABLE t6 USING INDEX t6i1 (a=?)}
}
} {SEARCH TABLE t6 USING INDEX t6i1 (a=?)}
do_eqp_test 10.6 {
SELECT rowid FROM t6 WHERE likelihood(a=0, 0.1) AND b='xyz' AND c=0
} {
0 0 0 {SEARCH TABLE t6 USING INDEX t6i1 (a=? AND b=?)}
}
} {SEARCH TABLE t6 USING INDEX t6i1 (a=? AND b=?)}
}
finish_test
+44
View File
@@ -0,0 +1,44 @@
# 2018-08-04
#
# 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.
#
#***********************************************************************
#
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set testprefix countofview
do_execsql_test 1.0 {
CREATE TABLE t2(c);
CREATE TABLE t3(f);
INSERT INTO t2 VALUES(1), (2);
INSERT INTO t3 VALUES(3);
}
do_execsql_test 1.1 {
select c from t2 union all select f from t3 limit 1 offset 1
} {2}
do_execsql_test 1.2 {
select count(*) from (
select c from t2 union all select f from t3 limit 1 offset 1
)
} {1}
do_execsql_test 1.3 {
select count(*) from (
select c from t2 union all select f from t3
)
} {3}
finish_test
+2 -7
View File
@@ -109,16 +109,11 @@ do_execsql_test 5.1.0 "
do_eqp_test 5.1.1 {
SELECT * FROM t1 ORDER BY c1, c2;
} {
0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1}
}
} {SCAN TABLE t1 USING COVERING INDEX i1}
do_eqp_test 5.1.2 {
SELECT * FROM t2 ORDER BY c1, c2;
} {
0 0 0 {SCAN TABLE t2 USING COVERING INDEX i2}
}
} {SCAN TABLE t2 USING COVERING INDEX i2}
finish_test
+13 -3
View File
@@ -142,6 +142,7 @@ proc write_file {zFile zData} {
# b) Less than 512, or
# c) Greater than SQLITE_MAX_PAGE_SIZE
#
if {[atomic_batch_write test.db]==0} {
do_test crash8-3.1 {
list [file exists test.db-joural] [file exists test.db]
} {0 1}
@@ -228,6 +229,7 @@ do_test crash8-3.11 {
PRAGMA integrity_check
}
} {6 ok}
}
# If a connection running in persistent-journal mode is part of a
@@ -266,8 +268,12 @@ ifcapable pragma {
UPDATE aux.ab SET b = randstr(1000,1000) WHERE a>=1;
UPDATE ab SET b = randstr(1000,1000) WHERE a>=1;
}
list [file exists test.db-journal] [file exists test2.db-journal]
} {1 1}
} {persist persist}
if {[atomic_batch_write test.db]==0} {
do_test crash8.4.1.1 {
list [file exists test.db-journal] [file exists test2.db-journal]
} {1 1}
}
do_test crash8-4.2 {
execsql {
@@ -346,7 +352,11 @@ ifcapable pragma {
# Since the following tests (crash8-5.*) rely upon being able
# to copy a file while open, they will not work on Windows.
#
if {$::tcl_platform(platform)=="unix"} {
# They also depend on being able to copy the journal file, which
# is not created on F2FS file-systems that support atomic
# write. So do not run these tests in that case either.
#
if {$::tcl_platform(platform)=="unix" && [atomic_batch_write test.db]==0 } {
for {set i 1} {$i < 10} {incr i} {
catch { db close }
forcedelete test.db test.db-journal
+51 -3
View File
@@ -93,6 +93,7 @@ do_catchsql_test 3.2 {
SELECT rowid, a FROM t3;
} {1 {no such column: rowid}}
# Multi-column WITHOUT ROWID virtual tables may not be writable.
do_catchsql_test 4.0 {
DROP TABLE t3;
CREATE VIRTUAL TABLE temp.t4 USING csv_wr(
@@ -100,13 +101,60 @@ do_catchsql_test 4.0 {
'1,2,3,4
5,6,7,8
9,10,11,12
13,14,15,16
',
13,14,15,16',
columns=4,
schema=
'CREATE TABLE t3(a PRIMARY KEY,b TEXT,c TEXT,d TEXT) WITHOUT ROWID',
'CREATE TABLE t3(a,b,c,d,PRIMARY KEY(a,b)) WITHOUT ROWID',
testflags=1
);
} {1 {vtable constructor failed: t4}}
# WITHOUT ROWID tables with a single-column PRIMARY KEY may be writable.
do_catchsql_test 4.1 {
DROP TABLE IF EXISTS t4;
CREATE VIRTUAL TABLE temp.t4 USING csv_wr(
data=
'1,2,3,4
5,6,7,8
9,10,11,12
13,14,15,16',
columns=4,
schema=
'CREATE TABLE t3(a,b,c,d,PRIMARY KEY(b)) WITHOUT ROWID',
testflags=1
);
} {0 {}}
do_catchsql_test 4.2 {
DROP TABLE IF EXISTS t5;
CREATE VIRTUAL TABLE temp.t5 USING csv_wr(
data=
'1,2,3,4
5,6,7,8
9,10,11,12
13,14,15,16',
columns=4,
schema=
'CREATE TABLE t3(a,b,c,d) WITHOUT ROWID',
testflags=1
);
} {1 {vtable constructor failed: t5}}
# 2018-04-24
# Memory leak reported on the sqlite-users mailing list by Ralf Junker.
#
do_catchsql_test 4.3 {
CREATE VIRTUAL TABLE IF NOT EXISTS temp.t1
USING csv(filename='FileDoesNotExist.csv');
} {1 {cannot open 'FileDoesNotExist.csv' for reading}}
# 2018-06-02
# Problem with single-column CSV support reported on the mailing list
# by Trent W. Buck.
#
do_execsql_test 4.4 {
CREATE VIRTUAL TABLE temp.trent USING csv(data='1');
SELECT * FROM trent;
} {1}
finish_test
+56 -36
View File
@@ -136,49 +136,69 @@ do_extract_hints_test 2.5 {
x2 {EQ(c0,r[2])}
}
do_extract_hints_test 2.6 {
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE 0 = (b IS NOT NULL)
} {
x2 {EQ(c0,r[2])}
}
do_extract_hints_test 2.7 {
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE 0 = (b IS NOT +NULL)
} {
x2 {EQ(c0,r[2])}
}
do_extract_hints_test 2.8 {
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE b IS NOT +NULL
} {
x2 {EQ(c0,r[2])}
}
do_extract_hints_test 2.9 {
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE CASE b WHEN 0 THEN 0 ELSE 1 END;
} {
x2 {EQ(c0,r[2])}
}
do_extract_hints_test 2.10 {
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE x2.b = 32+32
} {
x2 {AND(EQ(c1,ADD(32,32)),EQ(c0,r[2]))}
}
ifcapable !icu {
# This test only works using the built-in LIKE, not the ICU LIKE extension.
do_extract_hints_test 2.11 {
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE x2.b LIKE 'abc%'
if {0} {
# These tests no longer work due to the LEFT-JOIN strength reduction
# optimization
do_extract_hints_test 2.6 {
SELECT * FROM x1 CROSS JOIN x2 ON (a=x) WHERE 0 = (b IS NOT NULL)
} {
x2 {AND(expr,EQ(c0,r[2]))}
x2 {EQ(c0,r[2])}
}
do_extract_hints_test 2.7 {
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE 0 = (b IS NOT +NULL)
} {
x2 {EQ(c0,r[2])}
}
do_extract_hints_test 2.8 {
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE b IS NOT +NULL
} {
x2 {EQ(c0,r[2])}
}
do_extract_hints_test 2.9 {
SELECT * FROM x1 LEFT JOIN x2 ON (a=x)
WHERE CASE b WHEN 0 THEN 0 ELSE 1 END;
} {
x2 {EQ(c0,r[2])}
}
do_extract_hints_test 2.10 {
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE x2.b = 32+32
} {
x2 {AND(EQ(c1,ADD(32,32)),EQ(c0,r[2]))}
}
ifcapable !icu {
# This test only works using the built-in LIKE, not the ICU LIKE extension.
do_extract_hints_test 2.11 {
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE x2.b LIKE 'abc%'
} {
x2 {AND(expr,EQ(c0,r[2]))}
}
}
}
do_extract_hints_test 2.12 {
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE coalesce(x2.b, 1)
} {
x2 {EQ(c0,r[2])}
}
reset_db
do_execsql_test 3.0 {
CREATE TABLE t1 (i1 TEXT);
CREATE TABLE t2 (i2 TEXT UNIQUE);
INSERT INTO t1 VALUES('0');
INSERT INTO t2 VALUES('0');
}
do_extract_hints_test 3.1 {
SELECT * FROM t1 CROSS JOIN t2 WHERE (t1.i1 = t2.i2) AND t2.i2 = 1;
} {
t1 {EQ(c0,r[1])} t2 EQ(c0,1)
}
finish_test
+87
View File
@@ -0,0 +1,87 @@
# 2018-07-18
#
# 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.
#
#***********************************************************************
#
# Test case for SQLITE_FCNTL_DATA_VERSION
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Construct a database and get its initial data version
sqlite3 db test.db
do_test dataversion1-100 {
db eval {
CREATE TABLE t1(x);
INSERT INTO t1(x) VALUES(99);
SELECT * FROM t1;
}
} {99}
set dv1 [file_control_data_version db main]
# The data version does not change by ATTACH or by changes to
# other schemas within the same connection.
#
do_test dataversion1-101 {
db eval {
ATTACH ':memory:' AS aux1;
CREATE TABLE aux1.t2(y);
CREATE TEMP TABLE t3(z);
}
file_control_data_version db main
} $dv1
# The data version does change when SQL modifies the table
do_test dataversion1-110 {
db eval {
UPDATE t1 SET x=x+1;
}
set dv2 [file_control_data_version db]
expr {$::dv1==$dv2}
} {0}
# But the data version is constant if there are changes to other
# schemas
set dv1 [file_control_data_version db main]
do_test dataversion1-120 {
db eval {
UPDATE t2 SET y=y+1;
}
file_control_data_version db
} $dv1
# Changes to the database via another connection are not detected
# until there is a read transaction.
#
sqlite3 db2 test.db
do_test dataversion1-130 {
db2 eval {
SELECT * FROM t1
}
} {100}
do_test dataversion1-131 {
file_control_data_version db
} $dv1
do_test dataversion1-132 {
db2 eval {
UPDATE t1 SET x=x+1;
}
set dv2 [file_control_data_version db]
expr {$::dv1==$dv2}
} {1}
do_test dataversion1-133 {
db eval {SELECT * FROM t1}
set dv2 [file_control_data_version db]
expr {$::dv1==$dv2}
} {0}
finish_test
+104
View File
@@ -0,0 +1,104 @@
# 2017-10-11
#
# 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 file is testing the sqlite_dbpage virtual table.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix dbpage
ifcapable !vtab||!compound {
finish_test
return
}
do_test 100 {
execsql {
PRAGMA auto_vacuum=0;
PRAGMA page_size=4096;
PRAGMA journal_mode=WAL;
}
execsql {
CREATE TABLE t1(a,b);
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
INSERT INTO t1(a,b) SELECT x, printf('%d-x%.*c',x,x,'x') FROM c;
PRAGMA integrity_check;
}
} {ok}
do_execsql_test 110 {
SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage('main') ORDER BY pgno;
} {1 X'53514C6974' 2 X'0500000001' 3 X'0D0000004E' 4 X'0D00000016'}
do_execsql_test 120 {
SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage WHERE pgno=2;
} {2 X'0500000001'}
do_execsql_test 130 {
SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage WHERE pgno=4;
} {4 X'0D00000016'}
do_execsql_test 140 {
SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage WHERE pgno=5;
} {}
do_execsql_test 150 {
SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage WHERE pgno=0;
} {}
do_execsql_test 160 {
ATTACH ':memory:' AS aux1;
PRAGMA aux1.page_size=4096;
CREATE TABLE aux1.t2(a,b,c);
INSERT INTO t2 VALUES(11,12,13);
SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage('aux1');
} {1 X'53514C6974' 2 X'0D00000001'}
do_execsql_test 170 {
CREATE TABLE aux1.x3(x,y,z);
INSERT INTO x3(x,y,z) VALUES(1,'main',1),(2,'aux1',1);
SELECT pgno, schema, substr(data,1,6)
FROM sqlite_dbpage, x3
WHERE sqlite_dbpage.schema=x3.y AND sqlite_dbpage.pgno=x3.z
ORDER BY x3.x;
} {1 main SQLite 1 aux1 SQLite}
do_execsql_test 200 {
CREATE TEMP TABLE saved_content(x);
INSERT INTO saved_content(x) SELECT data FROM sqlite_dbpage WHERE pgno=4;
UPDATE sqlite_dbpage SET data=zeroblob(4096) WHERE pgno=4;
} {}
do_catchsql_test 210 {
PRAGMA integrity_check;
} {1 {database disk image is malformed}}
do_execsql_test 220 {
SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage('main') ORDER BY pgno;
} {1 X'53514C6974' 2 X'0500000001' 3 X'0D0000004E' 4 X'0000000000'}
do_execsql_test 230 {
UPDATE sqlite_dbpage SET data=(SELECT x FROM saved_content) WHERE pgno=4;
} {}
do_catchsql_test 230 {
PRAGMA integrity_check;
} {0 ok}
do_execsql_test 240 {
DELETE FROM saved_content;
INSERT INTO saved_content(x)
SELECT data FROM sqlite_dbpage WHERE schema='aux1' AND pgno=2;
} {}
do_execsql_test 241 {
UPDATE sqlite_dbpage SET data=zeroblob(4096) WHERE pgno=2 AND schema='aux1';
} {}
do_catchsql_test 250 {
PRAGMA aux1.integrity_check;
} {1 {database disk image is malformed}}
do_execsql_test 260 {
UPDATE sqlite_dbpage SET data=(SELECT x FROM saved_content)
WHERE pgno=2 AND schema='aux1';
} {}
do_catchsql_test 270 {
PRAGMA aux1.integrity_check;
} {0 ok}
finish_test
+39
View File
@@ -415,4 +415,43 @@ ifcapable shared_cache {
}
}
#-------------------------------------------------------------------------
# Test that passing an out-of-range value to sqlite3_stmt_status does
# not cause a crash.
reset_db
do_execsql_test 5.0 {
CREATE TABLE t1(x, y);
INSERT INTO t1 VALUES(1, 2);
INSERT INTO t1 VALUES(3, 4);
}
do_test 5.1 {
set ::stmt [sqlite3_prepare db "SELECT * FROM t1" -1 dummy]
sqlite3_step $::stmt
sqlite3_step $::stmt
sqlite3_step $::stmt
sqlite3_reset $::stmt
} {SQLITE_OK}
ifcapable api_armor {
do_test 5.2 { sqlite3_stmt_status $::stmt -1 0 } 0
}
do_test 5.3 { sqlite3_stmt_status $::stmt 0 0 } 0
do_test 5.4 {
expr [sqlite3_stmt_status $::stmt 99 0]>0
} 1
foreach {tn id res} {
1 SQLITE_STMTSTATUS_MEMUSED 1
2 SQLITE_STMTSTATUS_FULLSCAN_STEP 1
3 SQLITE_STMTSTATUS_SORT 0
4 SQLITE_STMTSTATUS_AUTOINDEX 0
5 SQLITE_STMTSTATUS_VM_STEP 1
6 SQLITE_STMTSTATUS_REPREPARE 0
7 SQLITE_STMTSTATUS_RUN 1
} {
if {$tn==2} breakpoint
do_test 5.5.$tn { expr [sqlite3_stmt_status $::stmt $id 0]>0 } $res
}
sqlite3_finalize $::stmt
finish_test
+13
View File
@@ -37,6 +37,10 @@ proc db_write {db {reset 0}} {
sqlite3_db_status $db CACHE_WRITE $reset
}
proc db_spill {db {reset 0}} {
sqlite3_db_status $db CACHE_SPILL $reset
}
do_test 1.1 {
db close
sqlite3 db test.db
@@ -98,5 +102,14 @@ do_test 2.7 {
} {0 4 0}
do_test 2.8 { db_write db 1 } {0 4 0}
do_test 2.9 { db_write db 0 } {0 0 0}
do_test 3.0 { db_spill db 1 } {0 0 0}
do_test 3.1 { db_spill db 0 } {0 0 0}
do_execsql_test 3.2 {
PRAGMA journal_mode=DELETE;
PRAGMA cache_size=3;
UPDATE t1 SET b=randomblob(1000);
} {delete}
do_test 3.3 { db_spill db 0 } {0 8 0}
finish_test
+12
View File
@@ -403,5 +403,17 @@ do_execsql_test delete-10.2 {
SELECT * FROM t1 WHERE a='1' AND b='2';
}
do_execsql_test delete-11.0 {
CREATE TABLE t11(a INTEGER PRIMARY KEY, b INT);
WITH RECURSIVE cnt(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM cnt WHERE x<20)
INSERT INTO t11(a,b) SELECT x, (x*17)%100 FROM cnt;
SELECT * FROM t11;
} {1 17 2 34 3 51 4 68 5 85 6 2 7 19 8 36 9 53 10 70 11 87 12 4 13 21 14 38 15 55 16 72 17 89 18 6 19 23 20 40}
do_execsql_test delete-11.1 {
DELETE FROM t11 AS xyz
WHERE EXISTS(SELECT 1 FROM t11 WHERE t11.a>xyz.a AND t11.b<=xyz.b);
SELECT * FROM t11;
} {6 2 12 4 18 6 19 23 20 40}
finish_test
+5
View File
@@ -17,6 +17,11 @@ set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix delete_db
if {[atomic_batch_write test.db]} {
finish_test
return
}
proc delete_all {} {
foreach f [glob -nocomplain test2*] { file delete $f }
foreach f [glob -nocomplain test3*] { file delete $f }
+50
View File
@@ -179,5 +179,55 @@ do_execsql_test 920 {
wxYZ wxYz wxYz wxyZ wxyZ wxyz wxyz
}
# Ticket https://sqlite.org/src/info/ef9318757b152e3a on 2017-11-21
# Incorrect result due to a skip-ahead-distinct optimization on a
# join where no rows of the inner loop appear in the result set.
#
db close
sqlite3 db :memory:
do_execsql_test 1000 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b INTEGER);
CREATE INDEX t1b ON t1(b);
CREATE TABLE t2(x INTEGER PRIMARY KEY, y INTEGER);
CREATE INDEX t2y ON t2(y);
WITH RECURSIVE c(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM c WHERE x<49)
INSERT INTO t1(b) SELECT x/10 - 1 FROM c;
WITH RECURSIVE c(x) AS (VALUES(-1) UNION ALL SELECT x+1 FROM c WHERE x<19)
INSERT INTO t2(x,y) SELECT x, 1 FROM c;
SELECT DISTINCT y FROM t1, t2 WHERE b=x AND b<>-1;
ANALYZE;
SELECT DISTINCT y FROM t1, t2 WHERE b=x AND b<>-1;
} {1 1}
db close
sqlite3 db :memory:
do_execsql_test 1010 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b INTEGER);
CREATE INDEX t1b ON t1(b);
CREATE TABLE t2(x INTEGER PRIMARY KEY, y INTEGER);
CREATE INDEX t2y ON t2(y);
WITH RECURSIVE c(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM c WHERE x<49)
INSERT INTO t1(b) SELECT -(x/10 - 1) FROM c;
WITH RECURSIVE c(x) AS (VALUES(-1) UNION ALL SELECT x+1 FROM c WHERE x<19)
INSERT INTO t2(x,y) SELECT -x, 1 FROM c;
SELECT DISTINCT y FROM t1, t2 WHERE b=x AND b<>1 ORDER BY y DESC;
ANALYZE;
SELECT DISTINCT y FROM t1, t2 WHERE b=x AND b<>1 ORDER BY y DESC;
} {1 1}
db close
sqlite3 db :memory:
do_execsql_test 1020 {
CREATE TABLE t1(a, b);
CREATE INDEX t1a ON t1(a, b);
-- Lots of rows of (1, 'no'), followed by a single (1, 'yes').
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
INSERT INTO t1(a, b) SELECT 1, 'no' FROM c;
INSERT INTO t1(a, b) VALUES(1, 'yes');
CREATE TABLE t2(x PRIMARY KEY);
INSERT INTO t2 VALUES('yes');
SELECT DISTINCT a FROM t1, t2 WHERE x=b;
ANALYZE;
SELECT DISTINCT a FROM t1, t2 WHERE x=b;
} {1 1}
finish_test
+7 -7
View File
@@ -656,11 +656,11 @@ do_createtable_tests 2.1 -tclquery {
5 "CREATE TABLE x1 AS SELECT count(a) AS a, max(b) FROM t1" {a max(b)}
}
# EVIDENCE-OF: R-37111-22855 The declared type of each column is
# EVIDENCE-OF: R-55407-45319 The declared type of each column is
# determined by the expression affinity of the corresponding expression
# in the result set of the SELECT statement, as follows: Expression
# Affinity Column Declared Type TEXT "TEXT" NUMERIC "NUM" INTEGER "INT"
# REAL "REAL" NONE "" (empty string)
# REAL "REAL" BLOB (a.k.a "NONE") "" (empty string)
#
do_createtable_tests 2.2 -tclquery {
table_column_decltypes x1
@@ -883,8 +883,8 @@ do_execsql_test e_createtable-3.3.1 {
);
} {}
# EVIDENCE-OF: R-18415-27776 For the purposes of the DEFAULT clause, an
# expression is considered constant if it does contains no sub-queries,
# EVIDENCE-OF: R-33440-07331 For the purposes of the DEFAULT clause, an
# expression is considered constant if it contains no sub-queries,
# column or table references, bound parameters, or string literals
# enclosed in double-quotes instead of single-quotes.
#
@@ -1385,13 +1385,13 @@ do_execsql_test 4.10.0 {
}
do_createtable_tests 4.10 {
1 "EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b = 5"
{0 0 0 {SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (b=?)}}
{/*SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (b=?)*/}
2 "EXPLAIN QUERY PLAN SELECT * FROM t2 ORDER BY b, c"
{0 0 0 {SCAN TABLE t2 USING INDEX sqlite_autoindex_t2_1}}
{/*SCAN TABLE t2 USING INDEX sqlite_autoindex_t2_1*/}
3 "EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE b=10 AND c>10"
{0 0 0 {SEARCH TABLE t2 USING INDEX sqlite_autoindex_t2_1 (b=? AND c>?)}}
{/*SEARCH TABLE t2 USING INDEX sqlite_autoindex_t2_1 (b=? AND c>?)*/}
}
# EVIDENCE-OF: R-45493-35653 A CHECK constraint may be attached to a
+44
View File
@@ -1663,6 +1663,50 @@ do_expr_test e_expr-32.2.3 {
do_expr_test e_expr-32.2.4 {
CAST(9223372036854775807 AS NUMERIC)
} integer 9223372036854775807
do_expr_test e_expr-32.2.5 {
CAST('9223372036854775807 ' AS NUMERIC)
} integer 9223372036854775807
do_expr_test e_expr-32.2.6 {
CAST(' 9223372036854775807 ' AS NUMERIC)
} integer 9223372036854775807
do_expr_test e_expr-32.2.7 {
CAST(' ' AS NUMERIC)
} integer 0
do_execsql_test e_expr-32.2.8 {
WITH t1(x) AS (VALUES
('9000000000000000001'),
('9000000000000000001x'),
('9000000000000000001 '),
(' 9000000000000000001 '),
(' 9000000000000000001'),
(' 9000000000000000001.'),
('9223372036854775807'),
('9223372036854775807 '),
(' 9223372036854775807 '),
('9223372036854775808'),
(' 9223372036854775808 '),
('9223372036854775807.0'),
('9223372036854775807e+0'),
('-5.0'),
('-5e+0'))
SELECT typeof(CAST(x AS NUMERIC)), CAST(x AS NUMERIC)||'' FROM t1;
} [list \
integer 9000000000000000001 \
integer 9000000000000000001 \
integer 9000000000000000001 \
integer 9000000000000000001 \
integer 9000000000000000001 \
integer 9000000000000000001 \
integer 9223372036854775807 \
integer 9223372036854775807 \
integer 9223372036854775807 \
real 9.22337203685478e+18 \
real 9.22337203685478e+18 \
integer 9223372036854775807 \
integer 9223372036854775807 \
integer -5 \
integer -5 \
]
# EVIDENCE-OF: R-64550-29191 Note that the result from casting any
# non-BLOB value into a BLOB and the result from casting any BLOB value
+31 -15
View File
@@ -24,7 +24,24 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
proc eqp {sql {db db}} { uplevel execsql [list "EXPLAIN QUERY PLAN $sql"] $db }
proc eqp {sql {db db}} {
uplevel [subst -nocommands {
set eqpres [list]
$db eval "$sql" {
lappend eqpres [set detail]
}
set eqpres
}]
}
proc do_detail_test {tn sql res} {
set normalres [list {*}$res]
uplevel [subst -nocommands {
do_test $tn {
eqp { $sql }
} {$normalres}
}]
}
###########################################################################
### SECTION 2: Enabling Foreign Key Support
@@ -970,20 +987,20 @@ do_test e_fkey-25.1 {
);
}
} {}
do_execsql_test e_fkey-25.2 {
do_detail_test e_fkey-25.2 {
PRAGMA foreign_keys = OFF;
EXPLAIN QUERY PLAN DELETE FROM artist WHERE 1;
EXPLAIN QUERY PLAN SELECT rowid FROM track WHERE trackartist = ?;
} {
0 0 0 {SCAN TABLE artist}
0 0 0 {SCAN TABLE track}
{SCAN TABLE artist}
{SCAN TABLE track}
}
do_execsql_test e_fkey-25.3 {
do_detail_test e_fkey-25.3 {
PRAGMA foreign_keys = ON;
EXPLAIN QUERY PLAN DELETE FROM artist WHERE 1;
} {
0 0 0 {SCAN TABLE artist}
0 0 0 {SCAN TABLE track}
{SCAN TABLE artist}
{SCAN TABLE track}
}
do_test e_fkey-25.4 {
execsql {
@@ -1097,21 +1114,20 @@ do_test e_fkey-27.1 {
do_test e_fkey-27.2 {
eqp { INSERT INTO artist VALUES(?, ?) }
} {}
do_execsql_test e_fkey-27.3 {
do_detail_test e_fkey-27.3 {
EXPLAIN QUERY PLAN UPDATE artist SET artistid = ?, artistname = ?
} {
0 0 0 {SCAN TABLE artist}
0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?)}
0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?)}
{SCAN TABLE artist}
{SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?)}
{SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?)}
}
do_execsql_test e_fkey-27.4 {
do_detail_test e_fkey-27.4 {
EXPLAIN QUERY PLAN DELETE FROM artist
} {
0 0 0 {SCAN TABLE artist}
0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?)}
{SCAN TABLE artist}
{SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?)}
}
###########################################################################
### SECTION 4.1: Composite Foreign Key Constraints
###########################################################################
+14 -14
View File
@@ -748,7 +748,7 @@ do_execsql_test e_select-3.2.1a {
SELECT k FROM x1 LEFT JOIN x2 USING(k)
} {1 2 3 4 5 6}
do_execsql_test e_select-3.2.1b {
SELECT k FROM x1 LEFT JOIN x2 USING(k) WHERE x2.k
SELECT k FROM x1 LEFT JOIN x2 USING(k) WHERE x2.k ORDER BY +k
} {1 3 5}
do_execsql_test e_select-3.2.2 {
SELECT k FROM x1 LEFT JOIN x2 USING(k) WHERE x2.k IS NULL
@@ -801,7 +801,7 @@ do_select_tests e_select-4.1 {
4 "SELECT z2.* FROM z1,z2 LIMIT 1" {{} 21}
5 "SELECT z2.*, z1.* FROM z1,z2 LIMIT 1" {{} 21 51.65 -59.58 belfries}
6 "SELECT count(*), * FROM z1" {6 63 born -26}
6 "SELECT count(*), * FROM z1" {6 51.65 -59.58 belfries}
7 "SELECT max(a), * FROM z1" {63 63 born -26}
8 "SELECT *, min(a) FROM z1" {-5 {} 75 -5}
@@ -939,13 +939,13 @@ do_execsql_test e_select-4.6.0 {
INSERT INTO a2 VALUES(10, 4);
} {}
do_select_tests e_select-4.6 {
1 "SELECT one, two, count(*) FROM a1" {4 10 4}
2 "SELECT one, two, count(*) FROM a1 WHERE one<3" {2 3 2}
1 "SELECT one, two, count(*) FROM a1" {1 1 4}
2 "SELECT one, two, count(*) FROM a1 WHERE one<3" {1 1 2}
3 "SELECT one, two, count(*) FROM a1 WHERE one>3" {4 10 1}
4 "SELECT *, count(*) FROM a1 JOIN a2" {4 10 10 4 16}
5 "SELECT *, sum(three) FROM a1 NATURAL JOIN a2" {3 6 2 3}
6 "SELECT *, sum(three) FROM a1 NATURAL JOIN a2" {3 6 2 3}
7 "SELECT group_concat(three, ''), a1.* FROM a1 NATURAL JOIN a2" {12 3 6}
4 "SELECT *, count(*) FROM a1 JOIN a2" {1 1 1 1 16}
5 "SELECT *, sum(three) FROM a1 NATURAL JOIN a2" {1 1 1 3}
6 "SELECT *, sum(three) FROM a1 NATURAL JOIN a2" {1 1 1 3}
7 "SELECT group_concat(three, ''), a1.* FROM a1 NATURAL JOIN a2" {12 1 1}
}
# EVIDENCE-OF: R-04486-07266 Or, if the dataset contains zero rows, then
@@ -1128,7 +1128,7 @@ do_select_tests e_select-4.13 {
2.1 "SELECT up FROM c1 GROUP BY up HAVING down>10" {y}
2.2 "SELECT up FROM c1 GROUP BY up HAVING up='y'" {y}
2.3 "SELECT i, j FROM c2 GROUP BY i>4 HAVING i>6" {9 36}
2.3 "SELECT i, j FROM c2 GROUP BY i>4 HAVING j>6" {5 10}
}
# EVIDENCE-OF: R-23927-54081 Each expression in the result-set is then
@@ -1154,12 +1154,12 @@ do_select_tests e_select-4.15 {
# for the same row.
#
do_select_tests e_select-4.15 {
1 "SELECT i, j FROM c2 GROUP BY i%2" {8 28 9 36}
2 "SELECT i, j FROM c2 GROUP BY i%2 HAVING j<30" {8 28}
3 "SELECT i, j FROM c2 GROUP BY i%2 HAVING j>30" {9 36}
4 "SELECT i, j FROM c2 GROUP BY i%2 HAVING j>30" {9 36}
1 "SELECT i, j FROM c2 GROUP BY i%2" {2 1 1 0}
2 "SELECT i, j FROM c2 GROUP BY i%2 HAVING j<30" {2 1 1 0}
3 "SELECT i, j FROM c2 GROUP BY i%2 HAVING j>30" {}
4 "SELECT i, j FROM c2 GROUP BY i%2 HAVING j>30" {}
5 "SELECT count(*), i, k FROM c2 NATURAL JOIN c3 GROUP BY substr(k, 1, 1)"
{2 5 boron 2 2 helium 1 3 lithium}
{2 4 beryllium 2 1 hydrogen 1 3 lithium}
}
# EVIDENCE-OF: R-19334-12811 Each group of input dataset rows
+2 -2
View File
@@ -50,8 +50,8 @@ proc open_uri_error {uri} {
# and the filename argument begins with "file:", then the filename is
# interpreted as a URI.
#
# EVIDENCE-OF: R-24124-56960 URI filename interpretation is enabled if
# the SQLITE_OPEN_URI flag is set in the fourth argument to
# EVIDENCE-OF: R-27632-24205 URI filename interpretation is enabled if
# the SQLITE_OPEN_URI flag is set in the third argument to
# sqlite3_open_v2(), or if it has been enabled globally using the
# SQLITE_CONFIG_URI option with the sqlite3_config() method or by the
# SQLITE_USE_URI compile-time option.
+349 -171
View File
@@ -43,78 +43,110 @@ do_execsql_test 1.1 {
do_eqp_test 1.2 {
SELECT * FROM t2, t1 WHERE t1.a=1 OR t1.b=2;
} {
0 0 1 {SEARCH TABLE t1 USING INDEX i1 (a=?)}
0 0 1 {SEARCH TABLE t1 USING INDEX i2 (b=?)}
0 1 0 {SCAN TABLE t2}
QUERY PLAN
|--MULTI-INDEX OR
| |--SEARCH TABLE t1 USING INDEX i1 (a=?)
| `--SEARCH TABLE t1 USING INDEX i2 (b=?)
`--SCAN TABLE t2
}
do_eqp_test 1.3 {
SELECT * FROM t2 CROSS JOIN t1 WHERE t1.a=1 OR t1.b=2;
} {
0 0 0 {SCAN TABLE t2}
0 1 1 {SEARCH TABLE t1 USING INDEX i1 (a=?)}
0 1 1 {SEARCH TABLE t1 USING INDEX i2 (b=?)}
QUERY PLAN
|--SCAN TABLE t2
`--MULTI-INDEX OR
|--SEARCH TABLE t1 USING INDEX i1 (a=?)
`--SEARCH TABLE t1 USING INDEX i2 (b=?)
}
do_eqp_test 1.3 {
SELECT a FROM t1 ORDER BY a
} {
0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1}
QUERY PLAN
`--SCAN TABLE t1 USING COVERING INDEX i1
}
do_eqp_test 1.4 {
SELECT a FROM t1 ORDER BY +a
} {
0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1}
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
QUERY PLAN
|--SCAN TABLE t1 USING COVERING INDEX i1
`--USE TEMP B-TREE FOR ORDER BY
}
do_eqp_test 1.5 {
SELECT a FROM t1 WHERE a=4
} {
0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}
QUERY PLAN
`--SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)
}
do_eqp_test 1.6 {
SELECT DISTINCT count(*) FROM t3 GROUP BY a;
} {
0 0 0 {SCAN TABLE t3}
0 0 0 {USE TEMP B-TREE FOR GROUP BY}
0 0 0 {USE TEMP B-TREE FOR DISTINCT}
QUERY PLAN
|--SCAN TABLE t3
|--USE TEMP B-TREE FOR GROUP BY
`--USE TEMP B-TREE FOR DISTINCT
}
do_eqp_test 1.7 {
SELECT * FROM t3 JOIN (SELECT 1)
} {
0 0 1 {SCAN SUBQUERY 1}
0 1 0 {SCAN TABLE t3}
QUERY PLAN
|--MATERIALIZE xxxxxx
| `--SCAN CONSTANT ROW
|--SCAN SUBQUERY xxxxxx
`--SCAN TABLE t3
}
do_eqp_test 1.8 {
SELECT * FROM t3 JOIN (SELECT 1 UNION SELECT 2)
} {
1 0 0 {COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (UNION)}
0 0 1 {SCAN SUBQUERY 1}
0 1 0 {SCAN TABLE t3}
QUERY PLAN
|--MATERIALIZE xxxxxx
| `--COMPOUND QUERY
| |--LEFT-MOST SUBQUERY
| | `--SCAN CONSTANT ROW
| `--UNION USING TEMP B-TREE
| `--SCAN CONSTANT ROW
|--SCAN SUBQUERY xxxxxx
`--SCAN TABLE t3
}
do_eqp_test 1.9 {
SELECT * FROM t3 JOIN (SELECT 1 EXCEPT SELECT a FROM t3 LIMIT 17)
} {
3 0 0 {SCAN TABLE t3}
1 0 0 {COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (EXCEPT)}
0 0 1 {SCAN SUBQUERY 1}
0 1 0 {SCAN TABLE t3}
QUERY PLAN
|--MATERIALIZE xxxxxx
| `--COMPOUND QUERY
| |--LEFT-MOST SUBQUERY
| | `--SCAN CONSTANT ROW
| `--EXCEPT USING TEMP B-TREE
| `--SCAN TABLE t3
|--SCAN SUBQUERY xxxxxx
`--SCAN TABLE t3
}
do_eqp_test 1.10 {
SELECT * FROM t3 JOIN (SELECT 1 INTERSECT SELECT a FROM t3 LIMIT 17)
} {
3 0 0 {SCAN TABLE t3}
1 0 0 {COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (INTERSECT)}
0 0 1 {SCAN SUBQUERY 1}
0 1 0 {SCAN TABLE t3}
QUERY PLAN
|--MATERIALIZE xxxxxx
| `--COMPOUND QUERY
| |--LEFT-MOST SUBQUERY
| | `--SCAN CONSTANT ROW
| `--INTERSECT USING TEMP B-TREE
| `--SCAN TABLE t3
|--SCAN SUBQUERY xxxxxx
`--SCAN TABLE t3
}
do_eqp_test 1.11 {
SELECT * FROM t3 JOIN (SELECT 1 UNION ALL SELECT a FROM t3 LIMIT 17)
} {
3 0 0 {SCAN TABLE t3}
1 0 0 {COMPOUND SUBQUERIES 2 AND 3 (UNION ALL)}
0 0 1 {SCAN SUBQUERY 1}
0 1 0 {SCAN TABLE t3}
QUERY PLAN
|--MATERIALIZE xxxxxx
| `--COMPOUND QUERY
| |--LEFT-MOST SUBQUERY
| | `--SCAN CONSTANT ROW
| `--UNION ALL
| `--SCAN TABLE t3
|--SCAN SUBQUERY xxxxxx
`--SCAN TABLE t3
}
#-------------------------------------------------------------------------
@@ -129,48 +161,58 @@ do_execsql_test 2.1 {
}
det 2.2.1 "SELECT DISTINCT min(x), max(x) FROM t1 GROUP BY x ORDER BY 1" {
0 0 0 {SCAN TABLE t1}
0 0 0 {USE TEMP B-TREE FOR GROUP BY}
0 0 0 {USE TEMP B-TREE FOR DISTINCT}
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
QUERY PLAN
|--SCAN TABLE t1
|--USE TEMP B-TREE FOR GROUP BY
|--USE TEMP B-TREE FOR DISTINCT
`--USE TEMP B-TREE FOR ORDER BY
}
det 2.2.2 "SELECT DISTINCT min(x), max(x) FROM t2 GROUP BY x ORDER BY 1" {
0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1}
0 0 0 {USE TEMP B-TREE FOR DISTINCT}
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
QUERY PLAN
|--SCAN TABLE t2 USING COVERING INDEX t2i1
|--USE TEMP B-TREE FOR DISTINCT
`--USE TEMP B-TREE FOR ORDER BY
}
det 2.2.3 "SELECT DISTINCT * FROM t1" {
0 0 0 {SCAN TABLE t1}
0 0 0 {USE TEMP B-TREE FOR DISTINCT}
QUERY PLAN
|--SCAN TABLE t1
`--USE TEMP B-TREE FOR DISTINCT
}
det 2.2.4 "SELECT DISTINCT * FROM t1, t2" {
0 0 0 {SCAN TABLE t1}
0 1 1 {SCAN TABLE t2}
0 0 0 {USE TEMP B-TREE FOR DISTINCT}
QUERY PLAN
|--SCAN TABLE t1
|--SCAN TABLE t2
`--USE TEMP B-TREE FOR DISTINCT
}
det 2.2.5 "SELECT DISTINCT * FROM t1, t2 ORDER BY t1.x" {
0 0 0 {SCAN TABLE t1}
0 1 1 {SCAN TABLE t2}
0 0 0 {USE TEMP B-TREE FOR DISTINCT}
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
QUERY PLAN
|--SCAN TABLE t1
|--SCAN TABLE t2
|--USE TEMP B-TREE FOR DISTINCT
`--USE TEMP B-TREE FOR ORDER BY
}
det 2.2.6 "SELECT DISTINCT t2.x FROM t1, t2 ORDER BY t2.x" {
0 0 1 {SCAN TABLE t2 USING COVERING INDEX t2i1}
0 1 0 {SCAN TABLE t1}
QUERY PLAN
|--SCAN TABLE t2 USING COVERING INDEX t2i1
`--SCAN TABLE t1
}
det 2.3.1 "SELECT max(x) FROM t2" {
0 0 0 {SEARCH TABLE t2 USING COVERING INDEX t2i1}
QUERY PLAN
`--SEARCH TABLE t2 USING COVERING INDEX t2i1
}
det 2.3.2 "SELECT min(x) FROM t2" {
0 0 0 {SEARCH TABLE t2 USING COVERING INDEX t2i1}
QUERY PLAN
`--SEARCH TABLE t2 USING COVERING INDEX t2i1
}
det 2.3.3 "SELECT min(x), max(x) FROM t2" {
0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1}
QUERY PLAN
`--SCAN TABLE t2 USING COVERING INDEX t2i1
}
det 2.4.1 "SELECT * FROM t1 WHERE rowid=?" {
0 0 0 {SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?)}
QUERY PLAN
`--SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?)
}
@@ -181,40 +223,46 @@ det 2.4.1 "SELECT * FROM t1 WHERE rowid=?" {
do_eqp_test 3.1.1 {
SELECT (SELECT x FROM t1 AS sub) FROM t1;
} {
0 0 0 {SCAN TABLE t1}
0 0 0 {EXECUTE SCALAR SUBQUERY 1}
1 0 0 {SCAN TABLE t1 AS sub}
QUERY PLAN
|--SCAN TABLE t1
`--SCALAR SUBQUERY
`--SCAN TABLE t1 AS sub
}
do_eqp_test 3.1.2 {
SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub);
} {
0 0 0 {EXECUTE SCALAR SUBQUERY 1}
1 0 0 {SCAN TABLE t1 AS sub}
0 0 0 {SCAN TABLE t1}
QUERY PLAN
|--SCAN TABLE t1
`--SCALAR SUBQUERY
`--SCAN TABLE t1 AS sub
}
do_eqp_test 3.1.3 {
SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub ORDER BY y);
} {
0 0 0 {EXECUTE SCALAR SUBQUERY 1}
1 0 0 {SCAN TABLE t1 AS sub}
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
0 0 0 {SCAN TABLE t1}
QUERY PLAN
|--SCAN TABLE t1
`--SCALAR SUBQUERY
|--SCAN TABLE t1 AS sub
`--USE TEMP B-TREE FOR ORDER BY
}
do_eqp_test 3.1.4 {
SELECT * FROM t1 WHERE (SELECT x FROM t2 ORDER BY x);
} {
0 0 0 {EXECUTE SCALAR SUBQUERY 1}
1 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1}
0 0 0 {SCAN TABLE t1}
QUERY PLAN
|--SCAN TABLE t1
`--SCALAR SUBQUERY
`--SCAN TABLE t2 USING COVERING INDEX t2i1
}
det 3.2.1 {
SELECT * FROM (SELECT * FROM t1 ORDER BY x LIMIT 10) ORDER BY y LIMIT 5
} {
1 0 0 {SCAN TABLE t1}
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
0 0 0 {SCAN SUBQUERY 1}
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
QUERY PLAN
|--CO-ROUTINE xxxxxx
| |--SCAN TABLE t1
| `--USE TEMP B-TREE FOR ORDER BY
|--SCAN SUBQUERY xxxxxx
`--USE TEMP B-TREE FOR ORDER BY
}
det 3.2.2 {
SELECT * FROM
@@ -222,34 +270,40 @@ det 3.2.2 {
(SELECT * FROM t2 ORDER BY x LIMIT 10) AS x2
ORDER BY x2.y LIMIT 5
} {
1 0 0 {SCAN TABLE t1}
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {SCAN TABLE t2 USING INDEX t2i1}
0 0 0 {SCAN SUBQUERY 1 AS x1}
0 1 1 {SCAN SUBQUERY 2 AS x2}
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
QUERY PLAN
|--MATERIALIZE xxxxxx
| |--SCAN TABLE t1
| `--USE TEMP B-TREE FOR ORDER BY
|--MATERIALIZE xxxxxx
| `--SCAN TABLE t2 USING INDEX t2i1
|--SCAN SUBQUERY xxxxxx AS x1
|--SCAN SUBQUERY xxxxxx AS x2
`--USE TEMP B-TREE FOR ORDER BY
}
det 3.3.1 {
SELECT * FROM t1 WHERE y IN (SELECT y FROM t2)
} {
0 0 0 {SCAN TABLE t1}
0 0 0 {EXECUTE LIST SUBQUERY 1}
1 0 0 {SCAN TABLE t2}
QUERY PLAN
|--SCAN TABLE t1
`--LIST SUBQUERY
`--SCAN TABLE t2
}
det 3.3.2 {
SELECT * FROM t1 WHERE y IN (SELECT y FROM t2 WHERE t1.x!=t2.x)
} {
0 0 0 {SCAN TABLE t1}
0 0 0 {EXECUTE CORRELATED LIST SUBQUERY 1}
1 0 0 {SCAN TABLE t2}
QUERY PLAN
|--SCAN TABLE t1
`--CORRELATED LIST SUBQUERY
`--SCAN TABLE t2
}
det 3.3.3 {
SELECT * FROM t1 WHERE EXISTS (SELECT y FROM t2 WHERE t1.x!=t2.x)
} {
0 0 0 {SCAN TABLE t1}
0 0 0 {EXECUTE CORRELATED SCALAR SUBQUERY 1}
1 0 0 {SCAN TABLE t2}
QUERY PLAN
|--SCAN TABLE t1
`--CORRELATED SCALAR SUBQUERY
`--SCAN TABLE t2
}
#-------------------------------------------------------------------------
@@ -258,119 +312,158 @@ det 3.3.3 {
do_eqp_test 4.1.1 {
SELECT * FROM t1 UNION ALL SELECT * FROM t2
} {
1 0 0 {SCAN TABLE t1}
2 0 0 {SCAN TABLE t2}
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)}
QUERY PLAN
`--COMPOUND QUERY
|--LEFT-MOST SUBQUERY
| `--SCAN TABLE t1
`--UNION ALL
`--SCAN TABLE t2
}
do_eqp_test 4.1.2 {
SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY 2
} {
1 0 0 {SCAN TABLE t1}
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {SCAN TABLE t2}
2 0 0 {USE TEMP B-TREE FOR ORDER BY}
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)}
QUERY PLAN
`--MERGE (UNION ALL)
|--LEFT
| |--SCAN TABLE t1
| `--USE TEMP B-TREE FOR ORDER BY
`--RIGHT
|--SCAN TABLE t2
`--USE TEMP B-TREE FOR ORDER BY
}
do_eqp_test 4.1.3 {
SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY 2
} {
1 0 0 {SCAN TABLE t1}
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {SCAN TABLE t2}
2 0 0 {USE TEMP B-TREE FOR ORDER BY}
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION)}
QUERY PLAN
`--MERGE (UNION)
|--LEFT
| |--SCAN TABLE t1
| `--USE TEMP B-TREE FOR ORDER BY
`--RIGHT
|--SCAN TABLE t2
`--USE TEMP B-TREE FOR ORDER BY
}
do_eqp_test 4.1.4 {
SELECT * FROM t1 INTERSECT SELECT * FROM t2 ORDER BY 2
} {
1 0 0 {SCAN TABLE t1}
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {SCAN TABLE t2}
2 0 0 {USE TEMP B-TREE FOR ORDER BY}
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (INTERSECT)}
QUERY PLAN
`--MERGE (INTERSECT)
|--LEFT
| |--SCAN TABLE t1
| `--USE TEMP B-TREE FOR ORDER BY
`--RIGHT
|--SCAN TABLE t2
`--USE TEMP B-TREE FOR ORDER BY
}
do_eqp_test 4.1.5 {
SELECT * FROM t1 EXCEPT SELECT * FROM t2 ORDER BY 2
} {
1 0 0 {SCAN TABLE t1}
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {SCAN TABLE t2}
2 0 0 {USE TEMP B-TREE FOR ORDER BY}
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)}
QUERY PLAN
`--MERGE (EXCEPT)
|--LEFT
| |--SCAN TABLE t1
| `--USE TEMP B-TREE FOR ORDER BY
`--RIGHT
|--SCAN TABLE t2
`--USE TEMP B-TREE FOR ORDER BY
}
do_eqp_test 4.2.2 {
SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY 1
} {
1 0 0 {SCAN TABLE t1}
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {SCAN TABLE t2 USING INDEX t2i1}
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)}
QUERY PLAN
`--MERGE (UNION ALL)
|--LEFT
| |--SCAN TABLE t1
| `--USE TEMP B-TREE FOR ORDER BY
`--RIGHT
`--SCAN TABLE t2 USING INDEX t2i1
}
do_eqp_test 4.2.3 {
SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY 1
} {
1 0 0 {SCAN TABLE t1}
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {SCAN TABLE t2 USING INDEX t2i1}
2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION)}
QUERY PLAN
`--MERGE (UNION)
|--LEFT
| |--SCAN TABLE t1
| `--USE TEMP B-TREE FOR ORDER BY
`--RIGHT
|--SCAN TABLE t2 USING INDEX t2i1
`--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY
}
do_eqp_test 4.2.4 {
SELECT * FROM t1 INTERSECT SELECT * FROM t2 ORDER BY 1
} {
1 0 0 {SCAN TABLE t1}
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {SCAN TABLE t2 USING INDEX t2i1}
2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (INTERSECT)}
QUERY PLAN
`--MERGE (INTERSECT)
|--LEFT
| |--SCAN TABLE t1
| `--USE TEMP B-TREE FOR ORDER BY
`--RIGHT
|--SCAN TABLE t2 USING INDEX t2i1
`--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY
}
do_eqp_test 4.2.5 {
SELECT * FROM t1 EXCEPT SELECT * FROM t2 ORDER BY 1
} {
1 0 0 {SCAN TABLE t1}
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {SCAN TABLE t2 USING INDEX t2i1}
2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)}
QUERY PLAN
`--MERGE (EXCEPT)
|--LEFT
| |--SCAN TABLE t1
| `--USE TEMP B-TREE FOR ORDER BY
`--RIGHT
|--SCAN TABLE t2 USING INDEX t2i1
`--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY
}
do_eqp_test 4.3.1 {
SELECT x FROM t1 UNION SELECT x FROM t2
} {
1 0 0 {SCAN TABLE t1}
2 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1}
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION)}
QUERY PLAN
`--COMPOUND QUERY
|--LEFT-MOST SUBQUERY
| `--SCAN TABLE t1
`--UNION USING TEMP B-TREE
`--SCAN TABLE t2 USING COVERING INDEX t2i1
}
do_eqp_test 4.3.2 {
SELECT x FROM t1 UNION SELECT x FROM t2 UNION SELECT x FROM t1
} {
2 0 0 {SCAN TABLE t1}
3 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1}
1 0 0 {COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (UNION)}
4 0 0 {SCAN TABLE t1}
0 0 0 {COMPOUND SUBQUERIES 1 AND 4 USING TEMP B-TREE (UNION)}
QUERY PLAN
`--COMPOUND QUERY
|--LEFT-MOST SUBQUERY
| `--SCAN TABLE t1
|--UNION USING TEMP B-TREE
| `--SCAN TABLE t2 USING COVERING INDEX t2i1
`--UNION USING TEMP B-TREE
`--SCAN TABLE t1
}
do_eqp_test 4.3.3 {
SELECT x FROM t1 UNION SELECT x FROM t2 UNION SELECT x FROM t1 ORDER BY 1
} {
2 0 0 {SCAN TABLE t1}
2 0 0 {USE TEMP B-TREE FOR ORDER BY}
3 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1}
1 0 0 {COMPOUND SUBQUERIES 2 AND 3 (UNION)}
4 0 0 {SCAN TABLE t1}
4 0 0 {USE TEMP B-TREE FOR ORDER BY}
0 0 0 {COMPOUND SUBQUERIES 1 AND 4 (UNION)}
QUERY PLAN
`--MERGE (UNION)
|--LEFT
| `--MERGE (UNION)
| |--LEFT
| | |--SCAN TABLE t1
| | `--USE TEMP B-TREE FOR ORDER BY
| `--RIGHT
| `--SCAN TABLE t2 USING COVERING INDEX t2i1
`--RIGHT
|--SCAN TABLE t1
`--USE TEMP B-TREE FOR ORDER BY
}
if 0 {
#-------------------------------------------------------------------------
# This next block of tests verifies that the examples on the
# lang_explain.html page are correct.
#
drop_all_tables
# EVIDENCE-OF: R-47779-47605 sqlite> EXPLAIN QUERY PLAN SELECT a, b
# XVIDENCE-OF: R-47779-47605 sqlite> EXPLAIN QUERY PLAN SELECT a, b
# FROM t1 WHERE a=1;
# 0|0|0|SCAN TABLE t1
#
@@ -379,7 +472,7 @@ det 5.1.1 "SELECT a, b FROM t1 WHERE a=1" {
0 0 0 {SCAN TABLE t1}
}
# EVIDENCE-OF: R-55852-17599 sqlite> CREATE INDEX i1 ON t1(a);
# XVIDENCE-OF: R-55852-17599 sqlite> CREATE INDEX i1 ON t1(a);
# sqlite> EXPLAIN QUERY PLAN SELECT a, b FROM t1 WHERE a=1;
# 0|0|0|SEARCH TABLE t1 USING INDEX i1
#
@@ -388,7 +481,7 @@ det 5.2.1 "SELECT a, b FROM t1 WHERE a=1" {
0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}
}
# EVIDENCE-OF: R-21179-11011 sqlite> CREATE INDEX i2 ON t1(a, b);
# XVIDENCE-OF: R-21179-11011 sqlite> CREATE INDEX i2 ON t1(a, b);
# sqlite> EXPLAIN QUERY PLAN SELECT a, b FROM t1 WHERE a=1;
# 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)
#
@@ -397,7 +490,7 @@ det 5.3.1 "SELECT a, b FROM t1 WHERE a=1" {
0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)}
}
# EVIDENCE-OF: R-09991-48941 sqlite> EXPLAIN QUERY PLAN
# XVIDENCE-OF: R-09991-48941 sqlite> EXPLAIN QUERY PLAN
# SELECT t1.*, t2.* FROM t1, t2 WHERE t1.a=1 AND t1.b>2;
# 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?)
# 0|1|1|SCAN TABLE t2
@@ -408,7 +501,7 @@ det 5.4.1 "SELECT t1.a, t2.c FROM t1, t2 WHERE t1.a=1 AND t1.b>2" {
0 1 1 {SCAN TABLE t2}
}
# EVIDENCE-OF: R-33626-61085 sqlite> EXPLAIN QUERY PLAN
# XVIDENCE-OF: R-33626-61085 sqlite> EXPLAIN QUERY PLAN
# SELECT t1.*, t2.* FROM t2, t1 WHERE t1.a=1 AND t1.b>2;
# 0|0|1|SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?)
# 0|1|0|SCAN TABLE t2
@@ -418,7 +511,7 @@ det 5.5 "SELECT t1.a, t2.c FROM t2, t1 WHERE t1.a=1 AND t1.b>2" {
0 1 0 {SCAN TABLE t2}
}
# EVIDENCE-OF: R-04002-25654 sqlite> CREATE INDEX i3 ON t1(b);
# XVIDENCE-OF: R-04002-25654 sqlite> CREATE INDEX i3 ON t1(b);
# sqlite> EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=1 OR b=2;
# 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)
# 0|0|0|SEARCH TABLE t1 USING INDEX i3 (b=?)
@@ -429,7 +522,7 @@ det 5.6.1 "SELECT a, b FROM t1 WHERE a=1 OR b=2" {
0 0 0 {SEARCH TABLE t1 USING INDEX i3 (b=?)}
}
# EVIDENCE-OF: R-24577-38891 sqlite> EXPLAIN QUERY PLAN
# XVIDENCE-OF: R-24577-38891 sqlite> EXPLAIN QUERY PLAN
# SELECT c, d FROM t2 ORDER BY c;
# 0|0|0|SCAN TABLE t2
# 0|0|0|USE TEMP B-TREE FOR ORDER BY
@@ -439,7 +532,7 @@ det 5.7 "SELECT c, d FROM t2 ORDER BY c" {
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
}
# EVIDENCE-OF: R-58157-12355 sqlite> CREATE INDEX i4 ON t2(c);
# XVIDENCE-OF: R-58157-12355 sqlite> CREATE INDEX i4 ON t2(c);
# sqlite> EXPLAIN QUERY PLAN SELECT c, d FROM t2 ORDER BY c;
# 0|0|0|SCAN TABLE t2 USING INDEX i4
#
@@ -448,7 +541,7 @@ det 5.8.1 "SELECT c, d FROM t2 ORDER BY c" {
0 0 0 {SCAN TABLE t2 USING INDEX i4}
}
# EVIDENCE-OF: R-13931-10421 sqlite> EXPLAIN QUERY PLAN SELECT
# XVIDENCE-OF: R-13931-10421 sqlite> EXPLAIN QUERY PLAN SELECT
# (SELECT b FROM t1 WHERE a=0), (SELECT a FROM t1 WHERE b=t2.c) FROM t2;
# 0|0|0|SCAN TABLE t2
# 0|0|0|EXECUTE SCALAR SUBQUERY 1
@@ -466,7 +559,7 @@ det 5.9 {
2 0 0 {SEARCH TABLE t1 USING INDEX i3 (b=?)}
}
# EVIDENCE-OF: R-50892-45943 sqlite> EXPLAIN QUERY PLAN
# XVIDENCE-OF: R-50892-45943 sqlite> EXPLAIN QUERY PLAN
# SELECT count(*) FROM (SELECT max(b) AS x FROM t1 GROUP BY a) GROUP BY x;
# 1|0|0|SCAN TABLE t1 USING COVERING INDEX i2
# 0|0|0|SCAN SUBQUERY 1
@@ -480,7 +573,7 @@ det 5.10 {
0 0 0 {USE TEMP B-TREE FOR GROUP BY}
}
# EVIDENCE-OF: R-46219-33846 sqlite> EXPLAIN QUERY PLAN
# XVIDENCE-OF: R-46219-33846 sqlite> EXPLAIN QUERY PLAN
# SELECT * FROM (SELECT * FROM t2 WHERE c=1), t1;
# 0|0|0|SEARCH TABLE t2 USING INDEX i4 (c=?)
# 0|1|1|SCAN TABLE t1
@@ -490,7 +583,7 @@ det 5.11 "SELECT a, b FROM (SELECT * FROM t2 WHERE c=1), t1" {
0 1 1 {SCAN TABLE t1 USING COVERING INDEX i2}
}
# EVIDENCE-OF: R-37879-39987 sqlite> EXPLAIN QUERY PLAN
# XVIDENCE-OF: R-37879-39987 sqlite> EXPLAIN QUERY PLAN
# SELECT a FROM t1 UNION SELECT c FROM t2;
# 1|0|0|SCAN TABLE t1
# 2|0|0|SCAN TABLE t2
@@ -502,7 +595,7 @@ det 5.12 "SELECT a,b FROM t1 UNION SELECT c, 99 FROM t2" {
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION)}
}
# EVIDENCE-OF: R-44864-63011 sqlite> EXPLAIN QUERY PLAN
# XVIDENCE-OF: R-44864-63011 sqlite> EXPLAIN QUERY PLAN
# SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1;
# 1|0|0|SCAN TABLE t1 USING COVERING INDEX i2
# 2|0|0|SCAN TABLE t2 2|0|0|USE TEMP B-TREE FOR ORDER BY
@@ -515,7 +608,6 @@ det 5.13 "SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1" {
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)}
}
if {![nonzero_reserved_bytes]} {
#-------------------------------------------------------------------------
# The following tests - eqp-6.* - test that the example C code on
@@ -557,6 +649,7 @@ if {![nonzero_reserved_bytes]} {
0 0 0 COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)
}]
}
}
#-------------------------------------------------------------------------
# The following tests - eqp-7.* - test that queries that use the OP_Count
@@ -571,11 +664,13 @@ do_execsql_test 7.0 {
}
det 7.1 "SELECT count(*) FROM t1" {
0 0 0 {SCAN TABLE t1}
QUERY PLAN
`--SCAN TABLE t1
}
det 7.2 "SELECT count(*) FROM t2" {
0 0 0 {SCAN TABLE t2 USING COVERING INDEX i1}
QUERY PLAN
`--SCAN TABLE t2 USING COVERING INDEX i1
}
do_execsql_test 7.3 {
@@ -593,11 +688,13 @@ db close
sqlite3 db test.db
det 7.4 "SELECT count(*) FROM t1" {
0 0 0 {SCAN TABLE t1}
QUERY PLAN
`--SCAN TABLE t1
}
det 7.5 "SELECT count(*) FROM t2" {
0 0 0 {SCAN TABLE t2 USING COVERING INDEX i1}
QUERY PLAN
`--SCAN TABLE t2 USING COVERING INDEX i1
}
#-------------------------------------------------------------------------
@@ -612,37 +709,118 @@ do_execsql_test 8.0 {
}
det 8.1.1 "SELECT * FROM t2" {
0 0 0 {SCAN TABLE t2}
QUERY PLAN
`--SCAN TABLE t2
}
det 8.1.2 "SELECT * FROM t2 WHERE rowid=?" {
0 0 0 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)}
QUERY PLAN
`--SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)
}
det 8.1.3 "SELECT count(*) FROM t2" {
0 0 0 {SCAN TABLE t2}
QUERY PLAN
`--SCAN TABLE t2
}
det 8.2.1 "SELECT * FROM t1" {
0 0 0 {SCAN TABLE t1}
QUERY PLAN
`--SCAN TABLE t1
}
det 8.2.2 "SELECT * FROM t1 WHERE b=?" {
0 0 0 {SEARCH TABLE t1 USING PRIMARY KEY (b=?)}
QUERY PLAN
`--SEARCH TABLE t1 USING PRIMARY KEY (b=?)
}
det 8.2.3 "SELECT * FROM t1 WHERE b=? AND c=?" {
0 0 0 {SEARCH TABLE t1 USING PRIMARY KEY (b=? AND c=?)}
QUERY PLAN
`--SEARCH TABLE t1 USING PRIMARY KEY (b=? AND c=?)
}
det 8.2.4 "SELECT count(*) FROM t1" {
0 0 0 {SCAN TABLE t1}
QUERY PLAN
`--SCAN TABLE t1
}
# 2018-08-16: While working on Fossil I discovered that EXPLAIN QUERY PLAN
# did not describe IN operators implemented using a ROWID lookup. These
# test cases ensure that problem as been fixed.
#
do_execsql_test 9.0 {
-- Schema from Fossil 2018-08-16
CREATE TABLE forumpost(
fpid INTEGER PRIMARY KEY,
froot INT,
fprev INT,
firt INT,
fmtime REAL
);
CREATE INDEX forumthread ON forumpost(froot,fmtime);
CREATE TABLE blob(
rid INTEGER PRIMARY KEY,
rcvid INTEGER,
size INTEGER,
uuid TEXT UNIQUE NOT NULL,
content BLOB,
CHECK( length(uuid)>=40 AND rid>0 )
);
CREATE TABLE event(
type TEXT,
mtime DATETIME,
objid INTEGER PRIMARY KEY,
tagid INTEGER,
uid INTEGER REFERENCES user,
bgcolor TEXT,
euser TEXT,
user TEXT,
ecomment TEXT,
comment TEXT,
brief TEXT,
omtime DATETIME
);
CREATE INDEX event_i1 ON event(mtime);
CREATE TABLE private(rid INTEGER PRIMARY KEY);
}
do_eqp_test 9.1 {
WITH thread(age,duration,cnt,root,last) AS (
SELECT
julianday('now') - max(fmtime) AS age,
max(fmtime) - min(fmtime) AS duration,
sum(fprev IS NULL) AS msg_count,
froot,
(SELECT fpid FROM forumpost
WHERE froot=x.froot
AND fpid NOT IN private
ORDER BY fmtime DESC LIMIT 1)
FROM forumpost AS x
WHERE fpid NOT IN private --- Ensure this table mentioned in EQP output!
GROUP BY froot
ORDER BY 1 LIMIT 26 OFFSET 5
)
SELECT
thread.age,
thread.duration,
thread.cnt,
blob.uuid,
substr(event.comment,instr(event.comment,':')+1)
FROM thread, blob, event
WHERE blob.rid=thread.last
AND event.objid=thread.last
ORDER BY 1;
} {
QUERY PLAN
|--MATERIALIZE xxxxxx
| |--SCAN TABLE forumpost AS x USING INDEX forumthread
| |--USING ROWID SEARCH ON TABLE private FOR IN-OPERATOR
| |--CORRELATED SCALAR SUBQUERY
| | |--SEARCH TABLE forumpost USING COVERING INDEX forumthread (froot=?)
| | `--USING ROWID SEARCH ON TABLE private FOR IN-OPERATOR
| `--USE TEMP B-TREE FOR ORDER BY
|--SCAN SUBQUERY xxxxxx
|--SEARCH TABLE blob USING INTEGER PRIMARY KEY (rowid=?)
|--SEARCH TABLE event USING INTEGER PRIMARY KEY (rowid=?)
`--USE TEMP B-TREE FOR ORDER BY
}
finish_test
+6 -1
View File
@@ -252,7 +252,9 @@ db2 close
# opens the journal file for exclusive access, preventing its contents
# from being inspected externally.
#
if {$tcl_platform(platform) != "windows"} {
if {$tcl_platform(platform) != "windows"
&& [atomic_batch_write test.db]==0
} {
# Return a list of two booleans (either 0 or 1). The first is true
# if the named file exists. The second is true only if the file
@@ -391,6 +393,7 @@ do_test exclusive-4.5 {
# Tests exclusive-5.X - test that statement journals are truncated
# instead of deleted when in exclusive access mode.
#
if {[atomic_batch_write test.db]==0} {
# Close and reopen the database so that the temp database is no
# longer active.
@@ -508,4 +511,6 @@ do_execsql_test exclusive-6.5 {
SELECT * FROM sqlite_master;
} {exclusive}
} ;# atomic_batch_write==0
finish_test
+57
View File
@@ -977,6 +977,63 @@ do_execsql_test expr-13.9 {
SELECT '' <= "";
} {1}
# 2018-02-26. Ticket https://www.sqlite.org/src/tktview/36fae083b450e3af85
#
do_execsql_test expr-14.1 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(0),(1),(NULL),(0.5),('1x'),('0x');
SELECT count(*) FROM t1
WHERE (x OR (8==9)) != (CASE WHEN x THEN 1 ELSE 0 END);
} {0}
do_execsql_test expr-14.2 {
SELECT count(*) FROM t1
WHERE (x OR (8==9)) != (NOT NOT x);
} {0}
do_execsql_test expr-14.3 {
SELECT sum(NOT x) FROM t1
WHERE x
} {0}
do_execsql_test expr-14.4 {
SELECT sum(CASE WHEN x THEN 0 ELSE 1 END) FROM t1
WHERE x
} {0}
foreach {tn val} [list 1 NaN 2 -NaN 3 NaN0 4 -NaN0 5 Inf 6 -Inf] {
do_execsql_test expr-15.$tn.1 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(0),(1),(NULL),(0.5),('1x'),('0x');
}
do_test expr-15.$tn.2 {
set ::STMT [sqlite3_prepare db "INSERT INTO t1 VALUES(?)" -1 TAIL]
sqlite3_bind_double $::STMT 1 $val
sqlite3_step $::STMT
sqlite3_reset $::STMT
sqlite3_finalize $::STMT
} {SQLITE_OK}
do_execsql_test expr-15.$tn.3 {
SELECT count(*) FROM t1
WHERE (x OR (8==9)) != (CASE WHEN x THEN 1 ELSE 0 END);
} {0}
do_execsql_test expr-15.$tn.4 {
SELECT count(*) FROM t1
WHERE (x OR (8==9)) != (NOT NOT x);
} {0}
do_execsql_test expr-15.$tn.5 {
SELECT sum(NOT x) FROM t1
WHERE x
} {0}
do_execsql_test expr-15.$tn.6 {
SELECT sum(CASE WHEN x THEN 0 ELSE 1 END) FROM t1
WHERE x
} {0}
}
finish_test
+4 -1
View File
@@ -59,7 +59,10 @@ do_test fallocate-1.6 {
#
do_test fallocate-1.7 {
execsql { BEGIN; INSERT INTO t1 VALUES(1, 2); }
if {[permutation] != "inmemory_journal"} {
if {[permutation] != "inmemory_journal"
&& [permutation] != "atomic-batch-write"
&& [atomic_batch_write test.db]==0
} {
hexio_get_int [hexio_read test.db-journal 16 4]
} else {
set {} 1024
+16
View File
@@ -171,6 +171,22 @@ do_catchsql_test fkey1-5.2 {
INSERT OR REPLACE INTO t11 VALUES (2, 3);
} {1 {FOREIGN KEY constraint failed}}
# Make sure sqlite3_trace() output works with triggers used to implement
# FK constraints
#
ifcapable trace {
proc sqltrace {txt} {
global traceoutput
lappend traceoutput $txt
}
do_test fkey1-5.2.1 {
unset -nocomplain traceoutput
db trace sqltrace
catch {db eval {INSERT OR REPLACE INTO t11 VALUES(2,3);}}
set traceoutput
} {{INSERT OR REPLACE INTO t11 VALUES(2,3);} {INSERT OR REPLACE INTO t11 VALUES(2,3);} {INSERT OR REPLACE INTO t11 VALUES(2,3);}}
}
# A similar test to the above.
do_execsql_test fkey1-5.3 {
CREATE TABLE Foo (
+3 -1
View File
@@ -983,7 +983,9 @@ ifcapable altertable {
# Test the sqlite_rename_parent() function directly.
#
proc test_rename_parent {zCreate zOld zNew} {
db eval {SELECT sqlite_rename_parent($zCreate, $zOld, $zNew)}
db eval {SELECT sqlite_rename_table(
'main', 'table', 't1', $zCreate, $zOld, $zNew, 0
)}
}
do_test fkey2-14.2.1.1 {
test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3
+14
View File
@@ -68,4 +68,18 @@ ifcapable incrblob {
} {SQLITE_CONSTRAINT}
}
ifcapable stat4 {
do_execsql_test 3.0 {
CREATE TABLE p4 (id INTEGER NOT NULL PRIMARY KEY);
INSERT INTO p4 VALUES(1), (2), (3);
CREATE TABLE c4(x INTEGER REFERENCES p4(id) DEFERRABLE INITIALLY DEFERRED);
CREATE INDEX c4_x ON c4(x);
INSERT INTO c4 VALUES(1), (2), (3);
ANALYZE;
INSERT INTO p4(id) VALUES(4);
}
}
finish_test
+1
View File
@@ -250,4 +250,5 @@ do_execsql_test 9.2 {
CREATE VIRTUAL TABLE t10 USING fts3(<, b, c);
}
expand_all_sql db
finish_test
+1 -1
View File
@@ -93,7 +93,7 @@ do_test fts3ao-2.9 {
}
} {1 {SQL logic error}}
do_test fts3ao-2.10 {
execsql { SELECT rowid, snippet(fts_t1) FROM fts_t1 WHERE a MATCH 'four'; }
execsql { SELECT rowid, snippet( fts_t1 ) FROM fts_t1 WHERE a MATCH 'four'; }
} {1 {one three <b>four</b>}}
do_test fts3ao-2.11 {
execsql { SELECT tbl_name FROM sqlite_master WHERE type = 'table'}
+30 -20
View File
@@ -105,10 +105,10 @@ db func rec rec
#
do_execsql_test 2.1.1.1 {
EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term='braid'
} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 1:} }
} {/*SCAN TABLE terms VIRTUAL TABLE INDEX 1:*/}
do_execsql_test 2.1.1.2 {
EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term='braid'
} {0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:}}
} {/*SCAN TABLE terms VIRTUAL TABLE INDEX 0:*/}
# Now show that using "term='braid'" means the virtual table returns
# only 1 row to SQLite, but "+term='braid'" means all 19 are returned.
@@ -154,24 +154,24 @@ do_execsql_test 2.1.5 { SELECT * FROM terms WHERE term=NULL } {}
do_execsql_test 2.2.1.1 {
EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term>'brain'
} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 2:} }
} {/*SCAN TABLE terms VIRTUAL TABLE INDEX 2:*/}
do_execsql_test 2.2.1.2 {
EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term>'brain'
} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:} }
} {/*SCAN TABLE terms VIRTUAL TABLE INDEX 0:*/}
do_execsql_test 2.2.1.3 {
EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term<'brain'
} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 4:} }
} {/*SCAN TABLE terms VIRTUAL TABLE INDEX 4:*/}
do_execsql_test 2.2.1.4 {
EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term<'brain'
} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:} }
} {/*SCAN TABLE terms VIRTUAL TABLE INDEX 0:*/}
do_execsql_test 2.2.1.5 {
EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term BETWEEN 'brags' AND 'brain'
} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 6:} }
} {/*SCAN TABLE terms VIRTUAL TABLE INDEX 6:*/}
do_execsql_test 2.2.1.6 {
EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term BETWEEN 'brags' AND 'brain'
} { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:} }
} {/*SCAN TABLE terms VIRTUAL TABLE INDEX 0:*/}
do_test 2.2.2.1 {
set cnt 0
@@ -335,8 +335,9 @@ foreach {tn sort orderby} {
9 1 "ORDER BY occurrences DESC"
} {
set res [list 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:}]
if {$sort} { lappend res 0 0 0 {USE TEMP B-TREE FOR ORDER BY} }
set res {SCAN TABLE terms VIRTUAL TABLE INDEX 0:}
if {$sort} { append res {*USE TEMP B-TREE FOR ORDER BY} }
set res "/*$res*/"
set sql "SELECT * FROM terms $orderby"
do_execsql_test 2.3.1.$tn "EXPLAIN QUERY PLAN $sql" $res
@@ -403,39 +404,48 @@ do_execsql_test 4.1 {
INSERT INTO x3 SELECT term FROM terms WHERE col = '*';
}
proc do_plansql_test {tn sql r} {
uplevel do_execsql_test $tn [list "EXPLAIN QUERY PLAN $sql ; $sql"] [list $r]
proc do_plansql_test {tn sql r1 r2} {
do_eqp_test $tn.eqp $sql $r1
do_execsql_test $tn $sql $r2
}
do_plansql_test 4.2 {
SELECT y FROM x2, terms WHERE y = term AND col = '*'
} {
0 0 0 {SCAN TABLE x2}
0 1 1 {SCAN TABLE terms VIRTUAL TABLE INDEX 1:}
QUERY PLAN
|--SCAN TABLE x2
`--SCAN TABLE terms VIRTUAL TABLE INDEX 1:
} {
a b c d e f g h i j k l
}
do_plansql_test 4.3 {
SELECT y FROM terms, x2 WHERE y = term AND col = '*'
} {
0 0 1 {SCAN TABLE x2}
0 1 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 1:}
QUERY PLAN
|--SCAN TABLE x2
`--SCAN TABLE terms VIRTUAL TABLE INDEX 1:
} {
a b c d e f g h i j k l
}
do_plansql_test 4.4 {
SELECT y FROM x3, terms WHERE y = term AND col = '*'
} {
0 0 1 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:}
0 1 0 {SEARCH TABLE x3 USING COVERING INDEX i1 (y=?)}
QUERY PLAN
|--SCAN TABLE terms VIRTUAL TABLE INDEX 0:
`--SEARCH TABLE x3 USING COVERING INDEX i1 (y=?)
} {
a b c d e f g h i j k l
}
do_plansql_test 4.5 {
SELECT y FROM terms, x3 WHERE y = term AND occurrences>1 AND col = '*'
} {
0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:}
0 1 1 {SEARCH TABLE x3 USING COVERING INDEX i1 (y=?)}
QUERY PLAN
|--SCAN TABLE terms VIRTUAL TABLE INDEX 0:
`--SEARCH TABLE x3 USING COVERING INDEX i1 (y=?)
} {
a k l
}
+43 -41
View File
@@ -136,47 +136,49 @@ do_execsql_test 2.2.2 { COMMIT }
do_execsql_test 2.2.3 { SELECT * FROM t1 } {{a b c} {a b c}}
fts3_integrity 2.2.4 db t1
do_execsql_test 3.1 {
CREATE VIRTUAL TABLE t3 USING fts4;
REPLACE INTO t3(docid, content) VALUES (1, 'one two');
SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'one'
} {X'0100000002000000'}
do_execsql_test 3.2 {
REPLACE INTO t3(docid, content) VALUES (2, 'one two three four');
SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'four'
} {X'0200000003000000'}
do_execsql_test 3.3 {
REPLACE INTO t3(docid, content) VALUES (1, 'one two three four five six');
SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'six'
} {X'0200000005000000'}
do_execsql_test 3.4 {
UPDATE OR REPLACE t3 SET docid = 2 WHERE docid=1;
SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'six'
} {X'0100000006000000'}
do_execsql_test 3.5 {
UPDATE OR REPLACE t3 SET docid = 3 WHERE docid=2;
SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'six'
} {X'0100000006000000'}
do_execsql_test 3.6 {
REPLACE INTO t3(docid, content) VALUES (3, 'one two');
SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'one'
} {X'0100000002000000'}
do_execsql_test 3.7 {
REPLACE INTO t3(docid, content) VALUES (NULL, 'one two three four');
REPLACE INTO t3(docid, content) VALUES (NULL, 'one two three four five six');
SELECT docid FROM t3;
} {3 4 5}
do_execsql_test 3.8 {
UPDATE OR REPLACE t3 SET docid = 5, content='three four' WHERE docid = 4;
SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'one'
} {X'0200000002000000'}
if {$tcl_platform(byteOrder)=="littleEndian"} {
do_execsql_test 3.1 {
CREATE VIRTUAL TABLE t3 USING fts4;
REPLACE INTO t3(docid, content) VALUES (1, 'one two');
SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'one'
} {X'0100000002000000'}
do_execsql_test 3.2 {
REPLACE INTO t3(docid, content) VALUES (2, 'one two three four');
SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'four'
} {X'0200000003000000'}
do_execsql_test 3.3 {
REPLACE INTO t3(docid, content) VALUES (1, 'one two three four five six');
SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'six'
} {X'0200000005000000'}
do_execsql_test 3.4 {
UPDATE OR REPLACE t3 SET docid = 2 WHERE docid=1;
SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'six'
} {X'0100000006000000'}
do_execsql_test 3.5 {
UPDATE OR REPLACE t3 SET docid = 3 WHERE docid=2;
SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'six'
} {X'0100000006000000'}
do_execsql_test 3.6 {
REPLACE INTO t3(docid, content) VALUES (3, 'one two');
SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'one'
} {X'0100000002000000'}
do_execsql_test 3.7 {
REPLACE INTO t3(docid, content) VALUES(NULL,'one two three four');
REPLACE INTO t3(docid, content) VALUES(NULL,'one two three four five six');
SELECT docid FROM t3;
} {3 4 5}
do_execsql_test 3.8 {
UPDATE OR REPLACE t3 SET docid = 5, content='three four' WHERE docid = 4;
SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'one'
} {X'0200000002000000'}
}
#-------------------------------------------------------------------------
# Test that the xSavepoint is invoked correctly if the first write
+1 -1
View File
@@ -409,7 +409,7 @@ do_test fts3expr-5.1 {
} {1 {Usage: fts3_exprtest(tokenizer, expr, col1, ...}}
do_test fts3expr-5.2 {
catchsql { SELECT fts3_exprtest('doesnotexist', 'a b', 'c') }
} {1 {No such tokenizer module}}
} {1 {unknown tokenizer: doesnotexist}}
do_test fts3expr-5.3 {
catchsql { SELECT fts3_exprtest('simple', 'a b OR', 'c') }
} {1 {Error parsing expression}}
+2 -1
View File
@@ -29,7 +29,8 @@ proc test_fts3expr {tokenizer expr} {
}
proc do_icu_expr_test {tn expr res} {
uplevel [list do_test $tn [list test_fts3expr icu $expr] [list {*}$res]]
set res2 [list {*}$res]
uplevel [list do_test $tn [list test_fts3expr "icu en_US" $expr] $res2]
}
proc do_simple_expr_test {tn expr res} {
+5 -3
View File
@@ -96,9 +96,11 @@ do_eqp_test 4.2 {
) AS rr ON t4.rowid=rr.docid
WHERE t4.y = ?;
} {
1 0 0 {SCAN TABLE ft4 VIRTUAL TABLE INDEX 3:}
0 0 0 {SCAN TABLE t4}
0 1 1 {SEARCH SUBQUERY 1 AS rr USING AUTOMATIC COVERING INDEX (docid=?)}
QUERY PLAN
|--MATERIALIZE xxxxxx
| `--SCAN TABLE ft4 VIRTUAL TABLE INDEX 3:
|--SCAN TABLE t4
`--SEARCH SUBQUERY xxxxxx AS rr USING AUTOMATIC COVERING INDEX (docid=?)
}
finish_test
+12 -8
View File
@@ -118,26 +118,30 @@ do_test fts3query-4.1 {
do_eqp_test fts3query-4.2 {
SELECT t1.number FROM t1, ft WHERE t1.number=ft.rowid ORDER BY t1.date
} {
0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1}
0 1 1 {SCAN TABLE ft VIRTUAL TABLE INDEX 1:}
QUERY PLAN
|--SCAN TABLE t1 USING COVERING INDEX i1
`--SCAN TABLE ft VIRTUAL TABLE INDEX 1:
}
do_eqp_test fts3query-4.3 {
SELECT t1.number FROM ft, t1 WHERE t1.number=ft.rowid ORDER BY t1.date
} {
0 0 1 {SCAN TABLE t1 USING COVERING INDEX i1}
0 1 0 {SCAN TABLE ft VIRTUAL TABLE INDEX 1:}
QUERY PLAN
|--SCAN TABLE t1 USING COVERING INDEX i1
`--SCAN TABLE ft VIRTUAL TABLE INDEX 1:
}
do_eqp_test fts3query-4.4 {
SELECT t1.number FROM t1, bt WHERE t1.number=bt.rowid ORDER BY t1.date
} {
0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1}
0 1 1 {SEARCH TABLE bt USING INTEGER PRIMARY KEY (rowid=?)}
QUERY PLAN
|--SCAN TABLE t1 USING COVERING INDEX i1
`--SEARCH TABLE bt USING INTEGER PRIMARY KEY (rowid=?)
}
do_eqp_test fts3query-4.5 {
SELECT t1.number FROM bt, t1 WHERE t1.number=bt.rowid ORDER BY t1.date
} {
0 0 1 {SCAN TABLE t1 USING COVERING INDEX i1}
0 1 0 {SEARCH TABLE bt USING INTEGER PRIMARY KEY (rowid=?)}
QUERY PLAN
|--SCAN TABLE t1 USING COVERING INDEX i1
`--SEARCH TABLE bt USING INTEGER PRIMARY KEY (rowid=?)
}
+69
View File
@@ -0,0 +1,69 @@
# 2017 October 7
#
# 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 FTS3 module.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix fts3rank
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts3 {
finish_test
return
}
install_fts3_rank_function db
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING fts3(a, b);
INSERT INTO t1 VALUES('one two', 'one');
INSERT INTO t1 VALUES('one two', 'three');
INSERT INTO t1 VALUES('one two', 'two');
}
do_execsql_test 1.1 {
SELECT * FROM t1 WHERE t1 MATCH 'one'
ORDER BY rank(matchinfo(t1), 1.0, 1.0) DESC, rowid
} {
{one two} one
{one two} three
{one two} two
}
do_execsql_test 1.2 {
SELECT * FROM t1 WHERE t1 MATCH 'two'
ORDER BY rank(matchinfo(t1), 1.0, 1.0) DESC, rowid
} {
{one two} two
{one two} one
{one two} three
}
do_catchsql_test 1.3 {
SELECT * FROM t1 ORDER BY rank(matchinfo(t1), 1.0, 1.0) DESC, rowid
} {1 {invalid matchinfo blob passed to function rank()}}
do_catchsql_test 1.4 {
SELECT * FROM t1 ORDER BY rank(x'0000000000000000') DESC, rowid
} {0 {{one two} one {one two} three {one two} two}}
if {$tcl_platform(byteOrder)=="littleEndian"} {
do_catchsql_test 1.5le {
SELECT * FROM t1 ORDER BY rank(x'0100000001000000') DESC, rowid
} {1 {invalid matchinfo blob passed to function rank()}}
} else {
do_catchsql_test 1.5be {
SELECT * FROM t1 ORDER BY rank(x'0000000100000001') DESC, rowid
} {1 {invalid matchinfo blob passed to function rank()}}
}
finish_test
+14
View File
@@ -143,4 +143,18 @@ foreach {tn tcl1 tcl2} {
eval $tcl2
}
do_execsql_test 4.0 {
CREATE VIRTUAL TABLE zt USING fts4(a, b);
INSERT INTO zt(rowid, a, b) VALUES(1, 'unus duo', NULL);
INSERT INTO zt(rowid, a, b) VALUES(2, NULL, NULL);
BEGIN;
UPDATE zt SET b='septum' WHERE rowid = 1;
UPDATE zt SET b='octo' WHERE rowid = 1;
COMMIT;
SELECT count(*) FROM zt_segdir;
} {3}
finish_test
+11
View File
@@ -507,6 +507,17 @@ if {$encoding=="UTF-16le"} {
execsql {SELECT hex(replace('aabcdefg','a','aaa'))}
} {616161616161626364656667}
}
do_execsql_test func-9.14 {
WITH RECURSIVE c(x) AS (
VALUES(1)
UNION ALL
SELECT x+1 FROM c WHERE x<1040
)
SELECT
count(*),
sum(length(replace(printf('abc%.*cxyz',x,'m'),'m','nnnn'))-(6+x*4))
FROM c;
} {1040 0}
# Use the "sqlite_register_test_function" TCL command which is part of
# the text fixture in order to verify correct operation of some of
+174
View File
@@ -0,0 +1,174 @@
# 2017-12-16
#
# 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.
#
#*************************************************************************
#
# Test cases for the sqlite_offset() function.
#
# Some of the tests in this file depend on the exact placement of content
# within b-tree pages. Such placement is at the implementations discretion,
# and so it is possible for results to change from one release to the next.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !offset_sql_func {
finish_test
return
}
set bNullTrim 0
ifcapable null_trim {
set bNullTrim 1
}
do_execsql_test func6-100 {
PRAGMA page_size=4096;
PRAGMA auto_vacuum=NONE;
CREATE TABLE t1(a,b,c,d);
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
INSERT INTO t1(a,b,c,d) SELECT printf('abc%03x',x), x, 1000-x, NULL FROM c;
CREATE INDEX t1a ON t1(a);
CREATE INDEX t1bc ON t1(b,c);
CREATE TABLE t2(x TEXT PRIMARY KEY, y) WITHOUT ROWID;
INSERT INTO t2(x,y) SELECT a, b FROM t1;
}
# Load the contents of $file from disk and return it encoded as a hex
# string.
proc loadhex {file} {
set fd [open $file]
fconfigure $fd -translation binary -encoding binary
set data [read $fd]
close $fd
binary encode hex $data
}
# Each argument is either an integer between 0 and 65535, a text value, or
# an empty string representing an SQL NULL. This command builds an SQLite
# record containing the values passed as arguments and returns it encoded
# as a hex string.
proc hexrecord {args} {
set hdr ""
set body ""
if {$::bNullTrim} {
while {[llength $args] && [lindex $args end]=={}} {
set args [lrange $args 0 end-1]
}
}
foreach x $args {
if {$x==""} {
append hdr 00
} elseif {[string is integer $x]==0} {
set n [string length $x]
append hdr [format %02x [expr $n*2 + 13]]
append body [binary encode hex $x]
} elseif {$x == 0} {
append hdr 08
} elseif {$x == 1} {
append hdr 09
} elseif {$x <= 127} {
append hdr 01
append body [format %02x $x]
} else {
append hdr 02
append body [format %04x $x]
}
}
set res [format %02x [expr 1 + [string length $hdr]/2]]
append res $hdr
append res $body
}
# Argument $off is an offset into the database image encoded as a hex string
# in argument $hexdb. This command returns 0 if the offset contains the hex
# $hexrec, or throws an exception otherwise.
#
proc offset_contains_record {off hexdb hexrec} {
set n [string length $hexrec]
set off [expr $off*2]
if { [string compare $hexrec [string range $hexdb $off [expr $off+$n-1]]] } {
error "record not found!"
}
return 0
}
# This command is the implementation of SQL function "offrec()". The first
# argument to this is an offset value. The remaining values are used to
# formulate an SQLite record. If database file test.db does not contain
# an equivalent record at the specified offset, an exception is thrown.
# Otherwise, 0 is returned.
#
proc offrec {args} {
set offset [lindex $args 0]
set rec [hexrecord {*}[lrange $args 1 end]]
offset_contains_record $offset $::F $rec
}
set F [loadhex test.db]
db func offrec offrec
# Test the sanity of the tests.
if {$bNullTrim} {
set offset 8180
} else {
set offset 8179
}
do_execsql_test func6-105 {
SELECT sqlite_offset(d) FROM t1 ORDER BY rowid LIMIT 1;
} $offset
do_test func6-106 {
set r [hexrecord abc001 1 999 {}]
offset_contains_record $offset $F $r
} 0
set z100 [string trim [string repeat "0 " 100]]
# Test offsets within table b-tree t1.
do_execsql_test func6-110 {
SELECT offrec(sqlite_offset(d), a, b, c, d) FROM t1 ORDER BY rowid
} $z100
do_execsql_test func6-120 {
SELECT a, typeof(sqlite_offset(+a)) FROM t1
ORDER BY rowid LIMIT 2;
} {abc001 null abc002 null}
# Test offsets within index b-tree t1a.
do_execsql_test func6-130 {
SELECT offrec(sqlite_offset(a), a, rowid) FROM t1 ORDER BY a
} $z100
# Test offsets within table b-tree t1 with a temp b-tree ORDER BY.
do_execsql_test func6-140 {
SELECT offrec(sqlite_offset(d), a, b, c, d) FROM t1 ORDER BY a
} $z100
# Test offsets from both index t1a and table t1 in the same query.
do_execsql_test func6-150 {
SELECT offrec(sqlite_offset(a), a, rowid),
offrec(sqlite_offset(d), a, b, c, d)
FROM t1 ORDER BY a
} [concat $z100 $z100]
# Test offsets from both index t1bc and table t1 in the same query.
do_execsql_test func6-160 {
SELECT offrec(sqlite_offset(b), b, c, rowid),
offrec(sqlite_offset(c), b, c, rowid),
offrec(sqlite_offset(d), a, b, c, d)
FROM t1
ORDER BY b
} [concat $z100 $z100 $z100]
# Test offsets in WITHOUT ROWID table t2.
do_execsql_test func6-200 {
SELECT offrec( sqlite_offset(y), x, y ) FROM t2 ORDER BY x
} $z100
finish_test
+13 -2
View File
@@ -57,9 +57,20 @@ proc do_fuzzy_malloc_test {testname args} {
incr jj
set ::sql [subst $::fuzzyopts(-template)]
# puts fuzyy-sql=\[$::sql\]; flush stdout
foreach {rc res} [catchsql "$::sql"] {}
foreach {rc ::fmtres} [catchsql "$::sql"] {}
if {$rc==0} {
do_malloc_test $testname-$ii -sqlbody $::sql -sqlprep $::prep
set nErr1 [set_test_counter errors]
do_faultsim_test $testname-$ii -faults oom* -body {
execsql $::sql
} -test {
if {$testrc && $testresult!="datatype mismatch"} {
faultsim_test_result {0 {}}
}
}
if {[set_test_counter errors]>$nErr1} {
puts "Previous fuzzy-sql=\[$::sql\]"
flush stdout
}
} else {
incr ii -1
}
+73 -14
View File
@@ -81,7 +81,13 @@
#ifdef SQLITE_OSS_FUZZ
# include <stddef.h>
# include <stdint.h>
# if !defined(_MSC_VER)
# include <stdint.h>
# endif
#endif
#if defined(_MSC_VER)
typedef unsigned char uint8_t;
#endif
/*
@@ -714,11 +720,13 @@ static void rebuild_database(sqlite3 *db){
"BEGIN;\n"
"CREATE TEMP TABLE dbx AS SELECT DISTINCT dbcontent FROM db;\n"
"DELETE FROM db;\n"
"INSERT INTO db(dbid, dbcontent) SELECT NULL, dbcontent FROM dbx ORDER BY 2;\n"
"INSERT INTO db(dbid, dbcontent) "
" SELECT NULL, dbcontent FROM dbx ORDER BY 2;\n"
"DROP TABLE dbx;\n"
"CREATE TEMP TABLE sx AS SELECT DISTINCT sqltext FROM xsql;\n"
"DELETE FROM xsql;\n"
"INSERT INTO xsql(sqlid,sqltext) SELECT NULL, sqltext FROM sx ORDER BY 2;\n"
"INSERT INTO xsql(sqlid,sqltext) "
" SELECT NULL, sqltext FROM sx ORDER BY 2;\n"
"DROP TABLE sx;\n"
"COMMIT;\n"
"PRAGMA page_size=1024;\n"
@@ -798,16 +806,17 @@ static void showHelp(void){
" --export-db DIR Write databases to files(s) in DIR. Works with --dbid\n"
" --export-sql DIR Write SQL to file(s) in DIR. Also works with --sqlid\n"
" --help Show this help text\n"
" -q|--quiet Reduced output\n"
" --info Show information about SOURCE-DB w/o running tests\n"
" --limit-mem N Limit memory used by test SQLite instance to N bytes\n"
" --limit-vdbe Panic if any test runs for more than 100,000 cycles\n"
" --load-sql ARGS... Load SQL scripts fro files into SOURCE-DB\n"
" --load-sql ARGS... Load SQL scripts fron files into SOURCE-DB\n"
" --load-db ARGS... Load template databases from files into SOURCE_DB\n"
" -m TEXT Add a description to the database\n"
" --native-vfs Use the native VFS for initially empty database files\n"
" --native-malloc Turn off MEMSYS3/5 and Lookaside\n"
" --oss-fuzz Enable OSS-FUZZ testing\n"
" --prng-seed N Seed value for the PRGN inside of SQLite\n"
" -q|--quiet Reduced output\n"
" --rebuild Rebuild and vacuum the database file\n"
" --result-trace Show the results of each SQL command\n"
" --sqlid N Use only SQL where sqlid=N\n"
@@ -821,7 +830,7 @@ int main(int argc, char **argv){
int quietFlag = 0; /* True if --quiet or -q */
int verboseFlag = 0; /* True if --verbose or -v */
char *zInsSql = 0; /* SQL statement for --load-db or --load-sql */
int iFirstInsArg = 0; /* First argv[] to use for --load-db or --load-sql */
int iFirstInsArg = 0; /* First argv[] for --load-db or --load-sql */
sqlite3 *db = 0; /* The open database connection */
sqlite3_stmt *pStmt; /* A prepared statement */
int rc; /* Result code from SQLite interface calls */
@@ -833,6 +842,7 @@ int main(int argc, char **argv){
int nativeFlag = 0; /* --native-vfs */
int rebuildFlag = 0; /* --rebuild */
int vdbeLimitFlag = 0; /* --limit-vdbe */
int infoFlag = 0; /* --info */
int timeoutTest = 0; /* undocumented --timeout-test flag */
int runFlags = 0; /* Flags sent to runSql() */
char *zMsg = 0; /* Add this message */
@@ -841,9 +851,9 @@ int main(int argc, char **argv){
int iSrcDb; /* Loop over all source databases */
int nTest = 0; /* Total number of tests performed */
char *zDbName = ""; /* Appreviated name of a source database */
const char *zFailCode = 0; /* Value of the TEST_FAILURE environment variable */
const char *zFailCode = 0; /* Value of the TEST_FAILURE env variable */
int cellSzCkFlag = 0; /* --cell-size-check */
int sqlFuzz = 0; /* True for SQL fuzz testing. False for DB fuzz */
int sqlFuzz = 0; /* True for SQL fuzz. False for DB fuzz */
int iTimeout = 120; /* Default 120-second timeout */
int nMem = 0; /* Memory limit */
int nMemThisDb = 0; /* Memory limit set by the CONFIG table */
@@ -854,12 +864,14 @@ int main(int argc, char **argv){
int ossFuzzThisDb = 0; /* ossFuzz value for this particular database */
int nativeMalloc = 0; /* Turn off MEMSYS3/5 and lookaside if true */
sqlite3_vfs *pDfltVfs; /* The default VFS */
int openFlags4Data; /* Flags for sqlite3_open_v2() */
iBegin = timeOfDay();
#ifdef __unix__
signal(SIGALRM, timeoutHandler);
#endif
g.zArgv0 = argv[0];
openFlags4Data = SQLITE_OPEN_READONLY;
zFailCode = getenv("TEST_FAILURE");
pDfltVfs = sqlite3_vfs_find(0);
inmemVfsRegister(1);
@@ -887,6 +899,9 @@ int main(int argc, char **argv){
showHelp();
return 0;
}else
if( strcmp(z,"info")==0 ){
infoFlag = 1;
}else
if( strcmp(z,"limit-mem")==0 ){
#if !defined(SQLITE_ENABLE_MEMSYS3) && !defined(SQLITE_ENABLE_MEMSYS5)
fatalError("the %s option requires -DSQLITE_ENABLE_MEMSYS5 or _MEMSYS3",
@@ -900,18 +915,21 @@ int main(int argc, char **argv){
vdbeLimitFlag = 1;
}else
if( strcmp(z,"load-sql")==0 ){
zInsSql = "INSERT INTO xsql(sqltext) VALUES(CAST(readfile(?1) AS text))";
zInsSql = "INSERT INTO xsql(sqltext)VALUES(CAST(readfile(?1) AS text))";
iFirstInsArg = i+1;
openFlags4Data = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
break;
}else
if( strcmp(z,"load-db")==0 ){
zInsSql = "INSERT INTO db(dbcontent) VALUES(readfile(?1))";
iFirstInsArg = i+1;
openFlags4Data = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
break;
}else
if( strcmp(z,"m")==0 ){
if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]);
zMsg = argv[++i];
openFlags4Data = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
}else
if( strcmp(z,"native-malloc")==0 ){
nativeMalloc = 1;
@@ -932,6 +950,7 @@ int main(int argc, char **argv){
}else
if( strcmp(z,"rebuild")==0 ){
rebuildFlag = 1;
openFlags4Data = SQLITE_OPEN_READWRITE;
}else
if( strcmp(z,"result-trace")==0 ){
runFlags |= SQL_OUTPUT;
@@ -977,11 +996,47 @@ int main(int argc, char **argv){
/* Process each source database separately */
for(iSrcDb=0; iSrcDb<nSrcDb; iSrcDb++){
rc = sqlite3_open_v2(azSrcDb[iSrcDb], &db,
SQLITE_OPEN_READWRITE, pDfltVfs->zName);
openFlags4Data, pDfltVfs->zName);
if( rc ){
fatalError("cannot open source database %s - %s",
azSrcDb[iSrcDb], sqlite3_errmsg(db));
}
/* Print the description, if there is one */
if( infoFlag ){
int n;
zDbName = azSrcDb[iSrcDb];
i = (int)strlen(zDbName) - 1;
while( i>0 && zDbName[i-1]!='/' && zDbName[i-1]!='\\' ){ i--; }
zDbName += i;
sqlite3_prepare_v2(db, "SELECT msg FROM readme", -1, &pStmt, 0);
if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
printf("%s: %s", zDbName, sqlite3_column_text(pStmt,0));
}else{
printf("%s: (empty \"readme\")", zDbName);
}
sqlite3_finalize(pStmt);
sqlite3_prepare_v2(db, "SELECT count(*) FROM db", -1, &pStmt, 0);
if( pStmt
&& sqlite3_step(pStmt)==SQLITE_ROW
&& (n = sqlite3_column_int(pStmt,0))>0
){
printf(" - %d DBs", n);
}
sqlite3_finalize(pStmt);
sqlite3_prepare_v2(db, "SELECT count(*) FROM xsql", -1, &pStmt, 0);
if( pStmt
&& sqlite3_step(pStmt)==SQLITE_ROW
&& (n = sqlite3_column_int(pStmt,0))>0
){
printf(" - %d scripts", n);
}
sqlite3_finalize(pStmt);
printf("\n");
sqlite3_close(db);
continue;
}
rc = sqlite3_exec(db,
"CREATE TABLE IF NOT EXISTS db(\n"
" dbid INTEGER PRIMARY KEY, -- database id\n"
@@ -1008,7 +1063,8 @@ int main(int argc, char **argv){
/* If the CONFIG(name,value) table exists, read db-specific settings
** from that table */
if( sqlite3_table_column_metadata(db,0,"config",0,0,0,0,0,0)==SQLITE_OK ){
rc = sqlite3_prepare_v2(db, "SELECT name, value FROM config", -1, &pStmt, 0);
rc = sqlite3_prepare_v2(db, "SELECT name, value FROM config",
-1, &pStmt, 0);
if( rc ) fatalError("cannot prepare query of CONFIG table: %s",
sqlite3_errmsg(db));
while( SQLITE_ROW==sqlite3_step(pStmt) ){
@@ -1047,7 +1103,8 @@ int main(int argc, char **argv){
}
sqlite3_finalize(pStmt);
rc = sqlite3_exec(db, "COMMIT", 0, 0, 0);
if( rc ) fatalError("cannot commit the transaction: %s", sqlite3_errmsg(db));
if( rc ) fatalError("cannot commit the transaction: %s",
sqlite3_errmsg(db));
rebuild_database(db);
sqlite3_close(db);
return 0;
@@ -1191,7 +1248,8 @@ int main(int argc, char **argv){
sqlite3_randomness(0,0);
if( ossFuzzThisDb ){
#ifndef SQLITE_OSS_FUZZ
fatalError("--oss-fuzz not supported: recompile with -DSQLITE_OSS_FUZZ");
fatalError("--oss-fuzz not supported: recompile"
" with -DSQLITE_OSS_FUZZ");
#else
extern int LLVMFuzzerTestOneInput(const uint8_t*, size_t);
LLVMFuzzerTestOneInput((const uint8_t*)pSql->a, (size_t)pSql->sz);
@@ -1210,7 +1268,8 @@ int main(int argc, char **argv){
setAlarm(iTimeout);
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
if( sqlFuzz || vdbeLimitFlag ){
sqlite3_progress_handler(db, 100000, progressHandler, &vdbeLimitFlag);
sqlite3_progress_handler(db, 100000, progressHandler,
&vdbeLimitFlag);
}
#endif
do{
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+18 -13
View File
@@ -65,19 +65,6 @@ foreach {tn sql1 sql2} {
3 "SELECT a, sum(b) FROM t1 GROUP BY a COLLATE binary HAVING a=2"
"SELECT a, sum(b) FROM t1 WHERE a=2 GROUP BY a COLLATE binary"
4 {
SELECT x,y FROM (
SELECT a AS x, sum(b) AS y FROM t1
GROUP BY a
) WHERE x BETWEEN 8888 AND 9999
} {
SELECT x,y FROM (
SELECT a AS x, sum(b) AS y FROM t1
WHERE x BETWEEN 8888 AND 9999
GROUP BY a
)
}
5 "SELECT a, sum(b) FROM t1 GROUP BY a COLLATE binary HAVING 0"
"SELECT a, sum(b) FROM t1 WHERE 0 GROUP BY a COLLATE binary"
@@ -98,6 +85,24 @@ foreach {tn sql1 sql2} {
do_compare_vdbe_test 2.$tn $sql1 $sql2 1
}
# The (4) test in the above set used to generate identical bytecode, but
# that is no longer the case. The byte code is equivalent, though.
#
do_execsql_test 2.4a {
SELECT x,y FROM (
SELECT a AS x, sum(b) AS y FROM t1
GROUP BY a
) WHERE x BETWEEN 2 AND 9999
} {2 12}
do_execsql_test 2.4b {
SELECT x,y FROM (
SELECT a AS x, sum(b) AS y FROM t1
WHERE x BETWEEN 2 AND 9999
GROUP BY a
)
} {2 12}
#-------------------------------------------------------------------------
# 1: Test that the optimization is only applied if the GROUP BY term
# uses BINARY collation.
+51
View File
@@ -906,5 +906,56 @@ do_preupdate_test 10.3 {
DELETE FROM t3 WHERE b=1
} {DELETE main t3 1 1 0 {} 1}
#-------------------------------------------------------------------------
# Test that the "update" hook is not fired for operations on the
# sqlite_stat1 table performed by ANALYZE, even if a pre-update hook is
# registered.
ifcapable analyze {
reset_db
do_execsql_test 11.1 {
CREATE TABLE t1(a, b);
CREATE INDEX idx1 ON t1(a);
CREATE INDEX idx2 ON t1(b);
INSERT INTO t1 VALUES(1, 2);
INSERT INTO t1 VALUES(3, 4);
INSERT INTO t1 VALUES(5, 6);
INSERT INTO t1 VALUES(7, 8);
}
db preupdate hook preupdate_cb
db update_hook update_cb
proc preupdate_cb {args} { lappend ::res "preupdate" $args }
proc update_cb {args} { lappend ::res "update" $args }
set ::res [list]
do_test 11.2 {
execsql ANALYZE
set ::res
} [list {*}{
preupdate {INSERT main sqlite_stat1 1 1}
preupdate {INSERT main sqlite_stat1 2 2}
}]
do_execsql_test 11.3 {
INSERT INTO t1 VALUES(9, 10);
INSERT INTO t1 VALUES(11, 12);
INSERT INTO t1 VALUES(13, 14);
INSERT INTO t1 VALUES(15, 16);
}
set ::res [list]
do_test 11.4 {
execsql ANALYZE
set ::res
} [list {*}{
preupdate {DELETE main sqlite_stat1 1 1}
preupdate {DELETE main sqlite_stat1 2 2}
preupdate {INSERT main sqlite_stat1 1 1}
preupdate {INSERT main sqlite_stat1 2 2}
}]
}
finish_test
+62 -58
View File
@@ -15,7 +15,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !icu {
ifcapable !icu&&!icu_collations {
finish_test
return
}
@@ -35,54 +35,57 @@ proc test_expr {name settings expr result} {
} $settings $expr] $result
}
# Tests of the REGEXP operator.
#
test_expr icu-1.1 {i1='hello'} {i1 REGEXP 'hello'} 1
test_expr icu-1.2 {i1='hello'} {i1 REGEXP '.ello'} 1
test_expr icu-1.3 {i1='hello'} {i1 REGEXP '.ell'} 0
test_expr icu-1.4 {i1='hello'} {i1 REGEXP '.ell.*'} 1
test_expr icu-1.5 {i1=NULL} {i1 REGEXP '.ell.*'} {}
ifcapable icu {
# Some non-ascii characters with defined case mappings
#
set ::EGRAVE "\xC8"
set ::egrave "\xE8"
# Tests of the REGEXP operator.
#
test_expr icu-1.1 {i1='hello'} {i1 REGEXP 'hello'} 1
test_expr icu-1.2 {i1='hello'} {i1 REGEXP '.ello'} 1
test_expr icu-1.3 {i1='hello'} {i1 REGEXP '.ell'} 0
test_expr icu-1.4 {i1='hello'} {i1 REGEXP '.ell.*'} 1
test_expr icu-1.5 {i1=NULL} {i1 REGEXP '.ell.*'} {}
set ::OGRAVE "\xD2"
set ::ograve "\xF2"
# Some non-ascii characters with defined case mappings
#
set ::EGRAVE "\xC8"
set ::egrave "\xE8"
# That German letter that looks a bit like a B. The
# upper-case version of which is "SS" (two characters).
#
set ::szlig "\xDF"
set ::OGRAVE "\xD2"
set ::ograve "\xF2"
# Tests of the upper()/lower() functions.
#
test_expr icu-2.1 {i1='HellO WorlD'} {upper(i1)} {HELLO WORLD}
test_expr icu-2.2 {i1='HellO WorlD'} {lower(i1)} {hello world}
test_expr icu-2.3 {i1=$::egrave} {lower(i1)} $::egrave
test_expr icu-2.4 {i1=$::egrave} {upper(i1)} $::EGRAVE
test_expr icu-2.5 {i1=$::ograve} {lower(i1)} $::ograve
test_expr icu-2.6 {i1=$::ograve} {upper(i1)} $::OGRAVE
test_expr icu-2.3 {i1=$::EGRAVE} {lower(i1)} $::egrave
test_expr icu-2.4 {i1=$::EGRAVE} {upper(i1)} $::EGRAVE
test_expr icu-2.5 {i1=$::OGRAVE} {lower(i1)} $::ograve
test_expr icu-2.6 {i1=$::OGRAVE} {upper(i1)} $::OGRAVE
# That German letter that looks a bit like a B. The
# upper-case version of which is "SS" (two characters).
#
set ::szlig "\xDF"
test_expr icu-2.7 {i1=$::szlig} {upper(i1)} "SS"
test_expr icu-2.8 {i1='SS'} {lower(i1)} "ss"
# Tests of the upper()/lower() functions.
#
test_expr icu-2.1 {i1='HellO WorlD'} {upper(i1)} {HELLO WORLD}
test_expr icu-2.2 {i1='HellO WorlD'} {lower(i1)} {hello world}
test_expr icu-2.3 {i1=$::egrave} {lower(i1)} $::egrave
test_expr icu-2.4 {i1=$::egrave} {upper(i1)} $::EGRAVE
test_expr icu-2.5 {i1=$::ograve} {lower(i1)} $::ograve
test_expr icu-2.6 {i1=$::ograve} {upper(i1)} $::OGRAVE
test_expr icu-2.3 {i1=$::EGRAVE} {lower(i1)} $::egrave
test_expr icu-2.4 {i1=$::EGRAVE} {upper(i1)} $::EGRAVE
test_expr icu-2.5 {i1=$::OGRAVE} {lower(i1)} $::ograve
test_expr icu-2.6 {i1=$::OGRAVE} {upper(i1)} $::OGRAVE
do_execsql_test icu-2.9 {
SELECT upper(char(0xfb04,0xfb04,0xfb04,0xfb04));
} {FFLFFLFFLFFL}
test_expr icu-2.7 {i1=$::szlig} {upper(i1)} "SS"
test_expr icu-2.8 {i1='SS'} {lower(i1)} "ss"
# In turkish (locale="tr_TR"), the lower case version of I
# is "small dotless i" (code point 0x131 (decimal 305)).
#
set ::small_dotless_i "\u0131"
test_expr icu-3.1 {i1='I'} {lower(i1)} "i"
test_expr icu-3.2 {i1='I'} {lower(i1, 'tr_tr')} $::small_dotless_i
test_expr icu-3.3 {i1='I'} {lower(i1, 'en_AU')} "i"
do_execsql_test icu-2.9 {
SELECT upper(char(0xfb04,0xfb04,0xfb04,0xfb04));
} {FFLFFLFFLFFL}
# In turkish (locale="tr_TR"), the lower case version of I
# is "small dotless i" (code point 0x131 (decimal 305)).
#
set ::small_dotless_i "\u0131"
test_expr icu-3.1 {i1='I'} {lower(i1)} "i"
test_expr icu-3.2 {i1='I'} {lower(i1, 'tr_tr')} $::small_dotless_i
test_expr icu-3.3 {i1='I'} {lower(i1, 'en_AU')} "i"
}
#--------------------------------------------------------------------
# Test the collation sequence function.
@@ -124,22 +127,23 @@ do_test icu-4.3 {
#
# http://src.chromium.org/viewvc/chrome/trunk/src/third_party/sqlite/icu-regexp.patch?revision=34807&view=markup
#
do_catchsql_test icu-5.1 { SELECT regexp('a[abc]c.*', 'abc') } {0 1}
do_catchsql_test icu-5.2 {
SELECT regexp('a[abc]c.*')
} {1 {wrong number of arguments to function regexp()}}
do_catchsql_test icu-5.3 {
SELECT regexp('a[abc]c.*', 'abc', 'c')
} {1 {wrong number of arguments to function regexp()}}
do_catchsql_test icu-5.4 {
SELECT 'abc' REGEXP 'a[abc]c.*'
} {0 1}
do_catchsql_test icu-5.4 { SELECT 'abc' REGEXP } {1 {near " ": syntax error}}
do_catchsql_test icu-5.5 { SELECT 'abc' REGEXP, 1 } {1 {near ",": syntax error}}
do_malloc_test icu-6.10 -sqlbody {
SELECT upper(char(0xfb04,0xdf,0xfb04,0xe8,0xfb04));
ifcapable icu {
do_catchsql_test icu-5.1 { SELECT regexp('a[abc]c.*', 'abc') } {0 1}
do_catchsql_test icu-5.2 {
SELECT regexp('a[abc]c.*')
} {1 {wrong number of arguments to function regexp()}}
do_catchsql_test icu-5.3 {
SELECT regexp('a[abc]c.*', 'abc', 'c')
} {1 {wrong number of arguments to function regexp()}}
do_catchsql_test icu-5.4 {
SELECT 'abc' REGEXP 'a[abc]c.*'
} {0 1}
do_catchsql_test icu-5.5 {SELECT 'abc' REGEXP } {1 {incomplete input}}
do_catchsql_test icu-5.6 {SELECT 'abc' REGEXP, 1} {1 {near ",": syntax error}}
do_malloc_test icu-6.10 -sqlbody {
SELECT upper(char(0xfb04,0xdf,0xfb04,0xe8,0xfb04));
}
}
finish_test
+80
View File
@@ -0,0 +1,80 @@
# 2018-06-07
#
# 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.
#
#***********************************************************************
#
# A multi-key index that uses an IN operator on one of the keys other
# than the left-most key is able to abort the IN-operator loop early
# if key terms further to the left do not match.
#
# Call this the "multikey-IN-operator early-out optimization" or
# just "IN-early-out" optimization for short.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix in6
do_test in6-1.1 {
db eval {
CREATE TABLE t1(a,b,c,d);
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
INSERT INTO t1(a,b,c,d)
SELECT 100, 200+x/2, 300+x/5, x FROM c;
CREATE INDEX t1abc ON t1(a,b,c);
ANALYZE;
UPDATE sqlite_stat1 SET stat='1000000 500000 500 50';
ANALYZE sqlite_master;
}
set ::sqlite_search_count 0
db eval {
SELECT d FROM t1
WHERE a=99
AND b IN (200,205,201,204)
AND c IN (304,302,309,308);
}
} {}
do_test in6-1.2 {
set ::sqlite_search_count
} {0} ;# Without the IN-early-out optimization, this value would be 15
# The multikey-IN-operator early-out optimization does not apply
# when the IN operator is on the left-most column of the index.
#
do_test in6-1.3 {
db eval {
EXPLAIN
SELECT d FROM t1
WHERE a IN (98,99,100,101)
AND b=200 AND c=300;
}
} {~/(IfNoHope|SeekHit)/}
set sqlite_search_count 0
do_execsql_test in6-1.4 {
SELECT d FROM t1
WHERE a=100
AND b IN (200,201,202,204)
AND c IN (300,302,301,305)
ORDER BY +d;
} {1 2 3 4 5 8 9}
do_test in6-1.5 {
set ::sqlite_search_count
} {39}
do_execsql_test in6-2.1 {
CREATE TABLE t2(e INT UNIQUE, f TEXT);
SELECT d, f FROM t1 LEFT JOIN t2 ON (e=d)
WHERE a=100
AND b IN (200,201,202,204)
AND c IN (300,302,301,305)
ORDER BY +d;
} {1 {} 2 {} 3 {} 4 {} 5 {} 8 {} 9 {}}
finish_test
+3 -2
View File
@@ -318,8 +318,9 @@ do_execsql_test index6-8.0 {
do_eqp_test index6-8.1 {
SELECT * FROM t8a LEFT JOIN t8b ON (x = 'value' AND y = a)
} {
0 0 0 {SCAN TABLE t8a}
0 1 1 {SEARCH TABLE t8b USING INDEX i8c (y=?)}
QUERY PLAN
|--SCAN TABLE t8a
`--SEARCH TABLE t8b USING INDEX i8c (y=?)
}
do_execsql_test index6-8.2 {
+2 -3
View File
@@ -321,9 +321,8 @@ do_execsql_test index7-6.3 {
}
do_eqp_test index7-6.4 {
SELECT * FROM v4 WHERE d='xyz' AND c='def'
} {
0 0 0 {SEARCH TABLE t4 USING INDEX i4 (c=?)}
}
} {SEARCH TABLE t4 USING INDEX i4 (c=?)}
do_catchsql_test index7-6.5 {
CREATE INDEX t5a ON t5(a) WHERE a=#1;
} {1 {near "#1": syntax error}}
+96 -78
View File
@@ -40,17 +40,18 @@ proc EQP {sql} {
# These tests are to check that "EXPLAIN QUERY PLAN" is working as expected.
#
do_execsql_test indexedby-1.2 {
EXPLAIN QUERY PLAN select * from t1 WHERE a = 10;
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}}
do_execsql_test indexedby-1.3 {
EXPLAIN QUERY PLAN select * from t1 ;
} {0 0 0 {SCAN TABLE t1}}
do_execsql_test indexedby-1.4 {
EXPLAIN QUERY PLAN select * from t1, t2 WHERE c = 10;
do_eqp_test indexedby-1.2 {
select * from t1 WHERE a = 10;
} {SEARCH TABLE t1 USING INDEX i1 (a=?)}
do_eqp_test indexedby-1.3 {
select * from t1 ;
} {SCAN TABLE t1}
do_eqp_test indexedby-1.4 {
select * from t1, t2 WHERE c = 10;
} {
0 0 1 {SEARCH TABLE t2 USING INDEX i3 (c=?)}
0 1 0 {SCAN TABLE t1}
QUERY PLAN
|--SEARCH TABLE t2 USING INDEX i3 (c=?)
`--SCAN TABLE t1
}
# Parser tests. Test that an INDEXED BY or NOT INDEX clause can be
@@ -58,7 +59,7 @@ do_execsql_test indexedby-1.4 {
# SQL view. Also test that specifying an index that does not exist or
# is attached to a different table is detected as an error.
#
# EVIDENCE-OF: R-07004-11522 -- syntax diagram qualified-table-name
# X-EVIDENCE-OF: R-07004-11522 -- syntax diagram qualified-table-name
#
# EVIDENCE-OF: R-58230-57098 The "INDEXED BY index-name" phrase
# specifies that the named index must be used in order to look up values
@@ -115,25 +116,23 @@ do_test indexedby-2.7 {
# the rowid can still be used to look up entries even when "NOT INDEXED"
# is specified.
#
do_execsql_test indexedby-3.1 {
EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a = 'one' AND b = 'two'
do_eqp_test indexedby-3.1 {
SELECT * FROM t1 WHERE a = 'one' AND b = 'two'
} {/SEARCH TABLE t1 USING INDEX/}
do_execsql_test indexedby-3.1.1 {
EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE a = 'one' AND b = 'two'
} {0 0 0 {SCAN TABLE t1}}
do_execsql_test indexedby-3.1.2 {
EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE rowid=1
do_eqp_test indexedby-3.1.1 {
SELECT * FROM t1 NOT INDEXED WHERE a = 'one' AND b = 'two'
} {SCAN TABLE t1}
do_eqp_test indexedby-3.1.2 {
SELECT * FROM t1 NOT INDEXED WHERE rowid=1
} {/SEARCH TABLE t1 USING INTEGER PRIMARY KEY .rowid=/}
do_execsql_test indexedby-3.2 {
EXPLAIN QUERY PLAN
do_eqp_test indexedby-3.2 {
SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' AND b = 'two'
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}}
do_execsql_test indexedby-3.3 {
EXPLAIN QUERY PLAN
} {SEARCH TABLE t1 USING INDEX i1 (a=?)}
do_eqp_test indexedby-3.3 {
SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' AND b = 'two'
} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}}
} {SEARCH TABLE t1 USING INDEX i2 (b=?)}
do_test indexedby-3.4 {
catchsql { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' }
} {1 {no query solution}}
@@ -147,14 +146,12 @@ do_test indexedby-3.7 {
catchsql { SELECT * FROM t1 INDEXED BY i1 ORDER BY a }
} {0 {}}
do_execsql_test indexedby-3.8 {
EXPLAIN QUERY PLAN
do_eqp_test indexedby-3.8 {
SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 ORDER BY e
} {0 0 0 {SCAN TABLE t3 USING INDEX sqlite_autoindex_t3_1}}
do_execsql_test indexedby-3.9 {
EXPLAIN QUERY PLAN
} {SCAN TABLE t3 USING INDEX sqlite_autoindex_t3_1}
do_eqp_test indexedby-3.9 {
SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE e = 10
} {0 0 0 {SEARCH TABLE t3 USING INDEX sqlite_autoindex_t3_1 (e=?)}}
} {SEARCH TABLE t3 USING INDEX sqlite_autoindex_t3_1 (e=?)}
do_test indexedby-3.10 {
catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE f = 10 }
} {1 {no query solution}}
@@ -164,17 +161,19 @@ do_test indexedby-3.11 {
# Tests for multiple table cases.
#
do_execsql_test indexedby-4.1 {
EXPLAIN QUERY PLAN SELECT * FROM t1, t2 WHERE a = c
do_eqp_test indexedby-4.1 {
SELECT * FROM t1, t2 WHERE a = c
} {
0 0 0 {SCAN TABLE t1}
0 1 1 {SEARCH TABLE t2 USING INDEX i3 (c=?)}
QUERY PLAN
|--SCAN TABLE t1
`--SEARCH TABLE t2 USING INDEX i3 (c=?)
}
do_execsql_test indexedby-4.2 {
EXPLAIN QUERY PLAN SELECT * FROM t1 INDEXED BY i1, t2 WHERE a = c
do_eqp_test indexedby-4.2 {
SELECT * FROM t1 INDEXED BY i1, t2 WHERE a = c
} {
0 0 1 {SCAN TABLE t2}
0 1 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}
QUERY PLAN
|--SCAN TABLE t2
`--SEARCH TABLE t1 USING INDEX i1 (a=?)
}
do_test indexedby-4.3 {
catchsql {
@@ -194,10 +193,10 @@ do_test indexedby-4.4 {
do_execsql_test indexedby-5.1 {
CREATE VIEW v2 AS SELECT * FROM t1 INDEXED BY i1 WHERE a > 5;
EXPLAIN QUERY PLAN SELECT * FROM v2
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}}
} {/*SEARCH TABLE t1 USING INDEX i1 (a>?)*/}
do_execsql_test indexedby-5.2 {
EXPLAIN QUERY PLAN SELECT * FROM v2 WHERE b = 10
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}}
} {/*SEARCH TABLE t1 USING INDEX i1 (a>?)*/}
do_test indexedby-5.3 {
execsql { DROP INDEX i1 }
catchsql { SELECT * FROM v2 }
@@ -216,12 +215,12 @@ do_test indexedby-5.5 {
# Test that "NOT INDEXED" may use the rowid index, but not others.
#
do_execsql_test indexedby-6.1 {
EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b = 10 ORDER BY rowid
} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}}
do_execsql_test indexedby-6.2 {
EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE b = 10 ORDER BY rowid
} {0 0 0 {SCAN TABLE t1}}
do_eqp_test indexedby-6.1 {
SELECT * FROM t1 WHERE b = 10 ORDER BY rowid
} {SEARCH TABLE t1 USING INDEX i2 (b=?)}
do_eqp_test indexedby-6.2 {
SELECT * FROM t1 NOT INDEXED WHERE b = 10 ORDER BY rowid
} {SCAN TABLE t1}
# EVIDENCE-OF: R-40297-14464 The INDEXED BY phrase forces the SQLite
# query planner to use a particular named index on a DELETE, SELECT, or
@@ -229,44 +228,42 @@ do_execsql_test indexedby-6.2 {
#
# Test that "INDEXED BY" can be used in a DELETE statement.
#
do_execsql_test indexedby-7.1 {
EXPLAIN QUERY PLAN DELETE FROM t1 WHERE a = 5
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}}
do_execsql_test indexedby-7.2 {
EXPLAIN QUERY PLAN DELETE FROM t1 NOT INDEXED WHERE a = 5
} {0 0 0 {SCAN TABLE t1}}
do_execsql_test indexedby-7.3 {
EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i1 WHERE a = 5
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}}
do_execsql_test indexedby-7.4 {
EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i1 WHERE a = 5 AND b = 10
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}}
do_execsql_test indexedby-7.5 {
EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i2 WHERE a = 5 AND b = 10
} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}}
do_eqp_test indexedby-7.1 {
DELETE FROM t1 WHERE a = 5
} {SEARCH TABLE t1 USING INDEX i1 (a=?)}
do_eqp_test indexedby-7.2 {
DELETE FROM t1 NOT INDEXED WHERE a = 5
} {SCAN TABLE t1}
do_eqp_test indexedby-7.3 {
DELETE FROM t1 INDEXED BY i1 WHERE a = 5
} {SEARCH TABLE t1 USING INDEX i1 (a=?)}
do_eqp_test indexedby-7.4 {
DELETE FROM t1 INDEXED BY i1 WHERE a = 5 AND b = 10
} {SEARCH TABLE t1 USING INDEX i1 (a=?)}
do_eqp_test indexedby-7.5 {
DELETE FROM t1 INDEXED BY i2 WHERE a = 5 AND b = 10
} {SEARCH TABLE t1 USING INDEX i2 (b=?)}
do_test indexedby-7.6 {
catchsql { DELETE FROM t1 INDEXED BY i2 WHERE a = 5}
} {1 {no query solution}}
# Test that "INDEXED BY" can be used in an UPDATE statement.
#
do_execsql_test indexedby-8.1 {
EXPLAIN QUERY PLAN UPDATE t1 SET rowid=rowid+1 WHERE a = 5
} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}}
do_execsql_test indexedby-8.2 {
EXPLAIN QUERY PLAN UPDATE t1 NOT INDEXED SET rowid=rowid+1 WHERE a = 5
} {0 0 0 {SCAN TABLE t1}}
do_execsql_test indexedby-8.3 {
EXPLAIN QUERY PLAN UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5
} {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}}
do_execsql_test indexedby-8.4 {
EXPLAIN QUERY PLAN
do_eqp_test indexedby-8.1 {
UPDATE t1 SET rowid=rowid+1 WHERE a = 5
} {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}
do_eqp_test indexedby-8.2 {
UPDATE t1 NOT INDEXED SET rowid=rowid+1 WHERE a = 5
} {SCAN TABLE t1}
do_eqp_test indexedby-8.3 {
UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5
} {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}
do_eqp_test indexedby-8.4 {
UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 AND b = 10
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}}
do_execsql_test indexedby-8.5 {
EXPLAIN QUERY PLAN
} {SEARCH TABLE t1 USING INDEX i1 (a=?)}
do_eqp_test indexedby-8.5 {
UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5 AND b = 10
} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}}
} {SEARCH TABLE t1 USING INDEX i2 (b=?)}
do_test indexedby-8.6 {
catchsql { UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5}
} {1 {no query solution}}
@@ -341,7 +338,7 @@ do_execsql_test 11.4 {
} {1 1 3}
do_eqp_test 11.5 {
SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0';
} {0 0 0 {SEARCH TABLE x1 USING COVERING INDEX x1i (a=? AND b=? AND rowid=?)}}
} {SEARCH TABLE x1 USING COVERING INDEX x1i (a=? AND b=? AND rowid=?)}
do_execsql_test 11.6 {
CREATE TABLE x2(c INTEGER PRIMARY KEY, a, b TEXT);
@@ -362,6 +359,27 @@ do_execsql_test 11.9 {
} {1 1 3}
do_eqp_test 11.10 {
SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3.0';
} {0 0 0 {SEARCH TABLE x2 USING COVERING INDEX x2i (a=? AND b=? AND rowid=?)}}
} {SEARCH TABLE x2 USING COVERING INDEX x2i (a=? AND b=? AND rowid=?)}
#-------------------------------------------------------------------------
# Check INDEXED BY works (throws an exception) with partial indexes that
# cannot be used.
do_execsql_test 12.1 {
CREATE TABLE o1(x INTEGER PRIMARY KEY, y, z);
CREATE INDEX p1 ON o1(z);
CREATE INDEX p2 ON o1(y) WHERE z=1;
}
do_catchsql_test 12.2 {
SELECT * FROM o1 INDEXED BY p2 ORDER BY 1;
} {1 {no query solution}}
do_execsql_test 12.3 {
DROP INDEX p1;
DROP INDEX p2;
CREATE INDEX p2 ON o1(y) WHERE z=1;
CREATE INDEX p1 ON o1(z);
}
do_catchsql_test 12.4 {
SELECT * FROM o1 INDEXED BY p2 ORDER BY 1;
} {1 {no query solution}}
finish_test
+66
View File
@@ -380,4 +380,70 @@ do_execsql_test indexexpr1-1300.1 {
SELECT a FROM t1300 WHERE substr(b,4)='ess' COLLATE nocase ORDER BY +a;
} {3 4}
# Ticket https://sqlite.org/src/tktview/aa98619a
# Assertion fault using an index on a constant
#
do_execsql_test indexexpr1-1400 {
CREATE TABLE t1400(x TEXT);
CREATE INDEX t1400x ON t1400(1); -- Index on a constant
SELECT 1 IN (SELECT 2) FROM t1400;
} {}
do_execsql_test indexexpr1-1410 {
INSERT INTO t1400 VALUES('a'),('b');
SELECT 1 IN (SELECT 2) FROM t1400;
} {0 0}
do_execsql_test indexexpr1-1420 {
SELECT 1 IN (SELECT 2 UNION ALL SELECT 1) FROM t1400;
} {1 1}
do_execsql_test indexexpr1-1430 {
DROP INDEX t1400x;
CREATE INDEX t1400x ON t1400(abs(15+3));
SELECT abs(15+3) IN (SELECT 17 UNION ALL SELECT 18) FROM t1;
} {1 1}
# 2018-01-02 ticket https://sqlite.org/src/info/dc3f932f5a147771
# A REPLACE into a table that uses an index on an expression causes
# an assertion fault. Problem discovered by OSSFuzz.
#
do_execsql_test indexexpr1-1500 {
CREATE TABLE t1500(a INT PRIMARY KEY, b INT UNIQUE);
CREATE INDEX t1500ab ON t1500(a*b);
INSERT INTO t1500(a,b) VALUES(1,2);
REPLACE INTO t1500(a,b) VALUES(1,3); -- formerly caused assertion fault
SELECT * FROM t1500;
} {1 3}
# 2018-01-03 OSSFuzz discovers another test case for the same problem
# above.
#
do_execsql_test indexexpr-1510 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a PRIMARY KEY,b UNIQUE);
REPLACE INTO t1 VALUES(2, 1);
REPLACE INTO t1 SELECT 6,1;
CREATE INDEX t1aa ON t1(a-a);
REPLACE INTO t1 SELECT a, randomblob(a) FROM t1
} {}
# 2018-01-31 https://www.sqlite.org/src/tktview/343634942dd54ab57b702411
# When an index on an expression depends on the string representation of
# a numeric table column, trouble can arise since there are multiple
# string that can map to the same numeric value. (Ex: 123, 0123, 000123).
#
do_execsql_test indexexpr-1600 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (a INTEGER, b);
CREATE INDEX idx1 ON t1 (lower(a));
INSERT INTO t1 VALUES('0001234',3);
PRAGMA integrity_check;
} {ok}
do_execsql_test indexexpr-1610 {
INSERT INTO t1 VALUES('1234',0),('001234',2),('01234',1);
SELECT b FROM t1 WHERE lower(a)='1234' ORDER BY +b;
} {0 1 2 3}
do_execsql_test indexexpr-1620 {
SELECT b FROM t1 WHERE lower(a)='01234' ORDER BY +b;
} {}
finish_test
+120
View File
@@ -40,4 +40,124 @@ do_execsql_test 2.1 {
SELECT a+1, quote(a+1) FROM t1 ORDER BY 1;
} {2 2 3 3 4 4}
#-------------------------------------------------------------------------
# At one point SQLite was incorrectly using indexes on expressions to
# optimize ORDER BY and GROUP BY clauses even when the collation
# sequences of the query and index did not match (ticket [e20dd54ab0e4]).
# The following tests - 3.* - attempt to verify that this has been fixed.
#
reset_db
do_execsql_test 3.1.0 {
CREATE TABLE t1(a, b);
CREATE INDEX i1 ON t1(a, b);
} {}
do_eqp_test 3.1.1 {
SELECT b FROM t1 WHERE b IS NOT NULL AND a IS NULL
GROUP BY b COLLATE nocase
ORDER BY b COLLATE nocase;
} {/USE TEMP B-TREE FOR GROUP BY/}
do_execsql_test 3.2.0 {
CREATE TABLE t2(x);
INSERT INTO t2 VALUES('.ABC');
INSERT INTO t2 VALUES('.abcd');
INSERT INTO t2 VALUES('.defg');
INSERT INTO t2 VALUES('.DEF');
} {}
do_execsql_test 3.2.1 {
SELECT x FROM t2 ORDER BY substr(x, 2) COLLATE nocase;
} {
.ABC .abcd .DEF .defg
}
do_execsql_test 3.2.2 {
CREATE INDEX i2 ON t2( substr(x, 2) );
SELECT x FROM t2 ORDER BY substr(x, 2) COLLATE nocase;
} {
.ABC .abcd .DEF .defg
}
do_execsql_test 3.3.0 {
CREATE TABLE t3(x);
}
ifcapable json1 {
do_eqp_test 3.3.1 {
SELECT json_extract(x, '$.b') FROM t2
WHERE json_extract(x, '$.b') IS NOT NULL AND json_extract(x, '$.a') IS NULL
GROUP BY json_extract(x, '$.b') COLLATE nocase
ORDER BY json_extract(x, '$.b') COLLATE nocase;
} [string map {"\n " \n} {
QUERY PLAN
|--SCAN TABLE t2
`--USE TEMP B-TREE FOR GROUP BY
}]
do_execsql_test 3.3.2 {
CREATE INDEX i3 ON t3(json_extract(x, '$.a'), json_extract(x, '$.b'));
} {}
do_eqp_test 3.3.3 {
SELECT json_extract(x, '$.b') FROM t3
WHERE json_extract(x, '$.b') IS NOT NULL AND json_extract(x, '$.a') IS NULL
GROUP BY json_extract(x, '$.b') COLLATE nocase
ORDER BY json_extract(x, '$.b') COLLATE nocase;
} [string map {"\n " \n} {
QUERY PLAN
|--SEARCH TABLE t3 USING INDEX i3 (<expr>=?)
`--USE TEMP B-TREE FOR GROUP BY
}]
}
do_execsql_test 3.4.0 {
CREATE TABLE t4(a, b);
INSERT INTO t4 VALUES('.ABC', 1);
INSERT INTO t4 VALUES('.abc', 2);
INSERT INTO t4 VALUES('.ABC', 3);
INSERT INTO t4 VALUES('.abc', 4);
}
do_execsql_test 3.4.1 {
SELECT * FROM t4
WHERE substr(a, 2) = 'abc' COLLATE NOCASE
ORDER BY substr(a, 2), b;
} {
.ABC 1 .ABC 3 .abc 2 .abc 4
}
do_execsql_test 3.4.2 {
CREATE INDEX i4 ON t4( substr(a, 2) COLLATE NOCASE, b );
SELECT * FROM t4
WHERE substr(a, 2) = 'abc' COLLATE NOCASE
ORDER BY substr(a, 2), b;
} {
.ABC 1 .ABC 3 .abc 2 .abc 4
}
do_execsql_test 3.4.3 {
DROP INDEX i4;
UPDATE t4 SET a = printf('%s%d',a,b);
SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE nocase;
} {.ABC1 1 .abc2 2 .ABC3 3 .abc4 4}
do_execsql_test 3.4.4 {
SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE binary;
} {.ABC1 1 .ABC3 3 .abc2 2 .abc4 4}
do_execsql_test 3.4.5 {
CREATE INDEX i4 ON t4( Substr(a,-2) COLLATE nocase );
SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE nocase;
} {.ABC1 1 .abc2 2 .ABC3 3 .abc4 4}
do_execsql_test 3.4.5eqp {
EXPLAIN QUERY PLAN
SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE nocase;
} {/SCAN TABLE t4 USING INDEX i4/}
do_execsql_test 3.4.6 {
SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE binary;
} {.ABC1 1 .ABC3 3 .abc2 2 .abc4 4}
finish_test
+13
View File
@@ -435,6 +435,19 @@ do_execsql_test insert-12.3 {
SELECT * FROM t12c;
} {one xyzzy two}
# 2018-06-11. From OSSFuzz. A column cache malfunction in
# the constraint checking on an index of expressions causes
# an assertion fault in a REPLACE. Ticket
# https://www.sqlite.org/src/info/c2432ef9089ee73b
#
do_execsql_test insert-13.1 {
DROP TABLE IF EXISTS t13;
CREATE TABLE t13(a INTEGER PRIMARY KEY,b UNIQUE);
CREATE INDEX t13x1 ON t13(-b=b);
INSERT INTO t13 VALUES(1,5),(6,2);
REPLACE INTO t13 SELECT b,0 FROM t13;
SELECT * FROM t13 ORDER BY +b;
} {2 0 6 2 1 5}
integrity_check insert-99.0
+2 -2
View File
@@ -172,7 +172,7 @@ ifcapable crashtest&&attach {
# These tests can't be run on windows because the windows version of
# SQLite holds a mandatory exclusive lock on journal files it has open.
#
if {$tcl_platform(platform)!="windows"} {
if {$tcl_platform(platform)!="windows" && ![atomic_batch_write test.db]} {
do_ioerr_test ioerr-7 -tclprep {
db close
sqlite3 db2 test2.db
@@ -211,7 +211,7 @@ do_ioerr_test ioerr-8 -ckrefcount true -tclprep {
# For test coverage: Cause an IO error whilst reading the master-journal
# name from a journal file.
if {$tcl_platform(platform)=="unix"} {
if {$tcl_platform(platform)=="unix" && [atomic_batch_write test.db]==0} {
do_ioerr_test ioerr-9 -ckrefcount true -tclprep {
execsql {
CREATE TABLE t1(a,b,c);
+161
View File
@@ -0,0 +1,161 @@
# 2018-02-26
#
# 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 file is testing expressions of the form
#
# x IS TRUE
# x IS FALSE
# x IS NOT TRUE
# x IS NOT FALSE
#
# Tests are also included for the use of TRUE and FALSE as
# literal values.
set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_execsql_test istrue-100 {
CREATE TABLE t1(x INTEGER PRIMARY KEY, y BOOLEAN);
INSERT INTO t1 VALUES(1, true),(2, false),(3, null);
SELECT x FROM t1 WHERE y IS TRUE;
} {1}
do_execsql_test istrue-110 {
SELECT x FROM t1 WHERE y IS FALSE;
} {2}
do_execsql_test istrue-120 {
SELECT x FROM t1 WHERE y IS NULL;
} {3}
do_execsql_test istrue-130 {
SELECT x FROM t1 WHERE y IS NOT TRUE;
} {2 3}
do_execsql_test istrue-140 {
SELECT x FROM t1 WHERE y IS NOT FALSE;
} {1 3}
do_execsql_test istrue-150 {
SELECT x FROM t1 WHERE y IS NOT NULL;
} {1 2}
unset -nocomplain X
set X 9
do_execsql_test istrue-160 {
SELECT x FROM t1 WHERE y IS TRUE OR (8==$X)
} {1}
do_execsql_test istrue-170 {
SELECT x FROM t1 WHERE y IS FALSE OR (8==$X)
} {2}
do_execsql_test istrue-180 {
SELECT x FROM t1 WHERE y IS NULL OR (8==$X);
} {3}
do_execsql_test istrue-190 {
SELECT x FROM t1 WHERE y IS NOT TRUE OR (8==$X);
} {2 3}
do_execsql_test istrue-200 {
SELECT x FROM t1 WHERE y IS NOT FALSE OR (8==$X);
} {1 3}
do_execsql_test istrue-210 {
SELECT x FROM t1 WHERE y IS NOT NULL OR (8==$X);
} {1 2}
do_execsql_test istrue-300 {
SELECT x,
y IS TRUE, y IS FALSE, y is NULL,
y IS NOT TRUE, y IS NOT FALSE, y IS NOT NULL, '|'
FROM t1 ORDER BY x;
} {1 1 0 0 0 1 1 | 2 0 1 0 1 0 1 | 3 0 0 1 1 1 0 |}
do_execsql_test istrue-400 {
SELECT x FROM t1 WHERE true;
} {1 2 3}
do_execsql_test istrue-410 {
SELECT x FROM t1 WHERE false;
} {}
do_execsql_test istrue-500 {
CREATE TABLE t2(
a INTEGER PRIMARY KEY,
b BOOLEAN DEFAULT true,
c BOOLEAN DEFAULT(true),
d BOOLEAN DEFAULT false,
e BOOLEAN DEFAULT(false)
);
INSERT INTO t2 DEFAULT VALUES;
SELECT * FROM t2;
} {1 1 1 0 0}
do_execsql_test istrue-510 {
DROP TABLE t2;
CREATE TABLE t2(
a INTEGER PRIMARY KEY,
b BOOLEAN DEFAULT(not true),
c BOOLEAN DEFAULT(not false)
);
INSERT INTO t2(a) VALUES(99);
SELECT * FROM t2;
} {99 0 1}
do_execsql_test istrue-520 {
DROP TABLE t2;
CREATE TABLE t2(
a INTEGER PRIMARY KEY,
b BOOLEAN CHECK(b IS TRUE),
c BOOLEAN CHECK(c IS FALSE),
d BOOLEAN CHECK(d IS NOT TRUE),
e BOOLEAN CHECK(e IS NOT FALSE)
);
INSERT INTO t2 VALUES(1,true,false,null,null);
SELECT * FROM t2;
} {1 1 0 {} {}}
do_catchsql_test istrue-521 {
INSERT INTO t2 VALUES(2,false,false,null,null);
} {1 {CHECK constraint failed: t2}}
do_catchsql_test istrue-522 {
INSERT INTO t2 VALUES(2,true,true,null,null);
} {1 {CHECK constraint failed: t2}}
do_catchsql_test istrue-523 {
INSERT INTO t2 VALUES(2,true,false,true,null);
} {1 {CHECK constraint failed: t2}}
do_catchsql_test istrue-524 {
INSERT INTO t2 VALUES(2,true,false,null,false);
} {1 {CHECK constraint failed: t2}}
foreach {tn val} [list 1 NaN 2 -NaN 3 NaN0 4 -NaN0 5 Inf 6 -Inf] {
do_execsql_test istrue-600.$tn.1 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(x);
}
do_test istrue-600.$tn.2 {
set ::STMT [sqlite3_prepare db "INSERT INTO t1 VALUES(?)" -1 TAIL]
sqlite3_bind_double $::STMT 1 $val
sqlite3_step $::STMT
sqlite3_reset $::STMT
sqlite3_finalize $::STMT
} {SQLITE_OK}
do_execsql_test istrue-600.$tn.3 {
SELECT x IS TRUE FROM t1;
} [expr {$tn in [list 5 6] ? {1} : {0}}]
do_execsql_test istrue-600.$tn.4 {
SELECT x IS FALSE FROM t1;
} {0}
}
do_execsql_test istrue-700 {
CREATE TABLE t7(
a INTEGER PRIMARY KEY,
b BOOLEAN DEFAULT false,
c BOOLEAN DEFAULT true
);
INSERT INTO t7(a) VALUES(1);
INSERT INTO t7(a,b,c) VALUES(2,true,false);
ALTER TABLE t7 ADD COLUMN d BOOLEAN DEFAULT false;
ALTER TABLE t7 ADD COLUMN e BOOLEAN DEFAULT true;
INSERT INTO t7(a,b,c) VALUES(3,true,false);
INSERT INTO t7 VALUES(4,false,true,true,false);
SELECT *,'x' FROM t7 ORDER BY a;
} {1 0 1 0 1 x 2 1 0 0 1 x 3 1 0 0 1 x 4 0 1 1 0 x}
finish_test

Some files were not shown because too many files have changed in this diff Show More