2014-07-15 13:59:44 +02:00
|
|
|
# 2014 July 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.
|
|
|
|
#
|
|
|
|
|
|
|
|
set testdir [file dirname $argv0]
|
|
|
|
source $testdir/tester.tcl
|
|
|
|
set testprefix cursorhint
|
|
|
|
|
2015-10-27 14:24:37 +01:00
|
|
|
ifcapable !cursorhints {
|
|
|
|
finish_test
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2014-07-15 13:59:44 +02:00
|
|
|
do_execsql_test 1.0 {
|
2015-08-14 22:08:13 +02:00
|
|
|
CREATE TABLE t1(a,b,c,d);
|
|
|
|
CREATE TABLE t2(x,y,z);
|
|
|
|
INSERT INTO t1(a,b) VALUES(10, 15);
|
|
|
|
INSERT INTO t1(a,b) VALUES(20, 25);
|
|
|
|
INSERT INTO t2(x,y) VALUES('ten', 'fifteen');
|
|
|
|
INSERT INTO t2(x,y) VALUES('twenty', 'twentyfive');
|
|
|
|
CREATE TABLE t3(id TEXT PRIMARY KEY, a, b, c, d) WITHOUT ROWID;
|
|
|
|
INSERT INTO t3(id,a,b,c,d) SELECT rowid, a, b, c, d FROM t1;
|
2014-07-15 13:59:44 +02:00
|
|
|
PRAGMA automatic_index = 0;
|
|
|
|
}
|
|
|
|
|
2015-08-14 22:08:13 +02:00
|
|
|
# Run EXPLAIN on $sql. Return a list of P4 values for all $opcode
|
|
|
|
# opcodes.
|
|
|
|
#
|
|
|
|
proc p4_of_opcode {db opcode sql} {
|
|
|
|
set res {}
|
|
|
|
$db eval "EXPLAIN $sql" x {
|
|
|
|
if {$x(opcode)==$opcode} {lappend res $x(p4)}
|
|
|
|
}
|
|
|
|
return $res
|
2014-07-15 13:59:44 +02:00
|
|
|
}
|
|
|
|
|
2015-08-14 22:08:13 +02:00
|
|
|
# Run EXPLAIN on $sql. Return a list of P5 values for all $opcode
|
|
|
|
# opcodes that contain regexp $comment in their comment
|
|
|
|
#
|
2016-01-04 02:08:50 +01:00
|
|
|
proc p5_of_opcode {db opcode sql} {
|
2015-08-14 22:08:13 +02:00
|
|
|
set res {}
|
|
|
|
$db eval "EXPLAIN $sql" x {
|
2016-01-04 02:08:50 +01:00
|
|
|
if {$x(opcode)==$opcode} {
|
2015-08-14 22:08:13 +02:00
|
|
|
lappend res $x(p5)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $res
|
2014-07-15 13:59:44 +02:00
|
|
|
}
|
|
|
|
|
2015-08-14 22:08:13 +02:00
|
|
|
# Verify that when t1 is in the outer loop and t2 is in the inner loop,
|
|
|
|
# no cursor hints occur for t1 (since it is a full table scan) but that
|
|
|
|
# each t2 access has a cursor hint based on the current t1.a value.
|
|
|
|
#
|
|
|
|
do_test 1.1 {
|
|
|
|
p4_of_opcode db CursorHint {
|
|
|
|
SELECT * FROM t1 CROSS JOIN t2 WHERE a=x
|
|
|
|
}
|
2015-08-15 02:51:23 +02:00
|
|
|
} {{EQ(r[1],c0)}}
|
2015-08-14 22:08:13 +02:00
|
|
|
do_test 1.2 {
|
2016-01-04 02:08:50 +01:00
|
|
|
p5_of_opcode db OpenRead {
|
2015-08-14 22:08:13 +02:00
|
|
|
SELECT * FROM t1 CROSS JOIN t2 WHERE a=x
|
|
|
|
}
|
2020-05-15 13:26:31 +02:00
|
|
|
} {0 0}
|
2014-07-15 13:59:44 +02:00
|
|
|
|
2015-08-14 22:08:13 +02:00
|
|
|
# Do the same test the other way around.
|
|
|
|
#
|
|
|
|
do_test 2.1 {
|
|
|
|
p4_of_opcode db CursorHint {
|
|
|
|
SELECT * FROM t2 CROSS JOIN t1 WHERE a=x
|
|
|
|
}
|
2015-08-15 02:51:23 +02:00
|
|
|
} {{EQ(c0,r[1])}}
|
2015-08-14 22:08:13 +02:00
|
|
|
do_test 2.2 {
|
2016-01-04 02:08:50 +01:00
|
|
|
p5_of_opcode db OpenRead {
|
2015-08-14 22:08:13 +02:00
|
|
|
SELECT * FROM t2 CROSS JOIN t1 WHERE a=x
|
|
|
|
}
|
2020-05-15 13:26:31 +02:00
|
|
|
} {0 0}
|
2014-07-15 13:59:44 +02:00
|
|
|
|
2015-08-14 22:08:13 +02:00
|
|
|
# Various expressions captured by CursorHint
|
|
|
|
#
|
|
|
|
do_test 3.1 {
|
|
|
|
p4_of_opcode db CursorHint {
|
|
|
|
SELECT * FROM t1 WHERE a=15 AND c=22 AND rowid!=98
|
|
|
|
}
|
2015-08-15 02:51:23 +02:00
|
|
|
} {AND(AND(EQ(c0,15),EQ(c2,22)),NE(rowid,98))}
|
2015-08-14 22:08:13 +02:00
|
|
|
do_test 3.2 {
|
|
|
|
p4_of_opcode db CursorHint {
|
|
|
|
SELECT * FROM t3 WHERE a<15 AND b>22 AND id!=98
|
|
|
|
}
|
2015-08-15 02:51:23 +02:00
|
|
|
} {AND(AND(LT(c1,15),GT(c2,22)),NE(c0,98))}
|
2014-07-15 13:59:44 +02:00
|
|
|
|
2015-08-14 22:08:13 +02:00
|
|
|
# Indexed queries
|
|
|
|
#
|
2015-08-17 19:19:28 +02:00
|
|
|
do_test 4.1asc {
|
2015-08-14 22:08:13 +02:00
|
|
|
db eval {
|
|
|
|
CREATE INDEX t1bc ON t1(b,c);
|
|
|
|
CREATE INDEX t2yz ON t2(y,z);
|
|
|
|
}
|
|
|
|
p4_of_opcode db CursorHint {
|
2015-08-17 19:19:28 +02:00
|
|
|
SELECT * FROM t1 WHERE b>11 ORDER BY b ASC;
|
|
|
|
}
|
|
|
|
} {}
|
|
|
|
do_test 4.1desc {
|
|
|
|
p4_of_opcode db CursorHint {
|
|
|
|
SELECT * FROM t1 WHERE b>11 ORDER BY b DESC;
|
2015-08-14 22:08:13 +02:00
|
|
|
}
|
2015-08-15 02:51:23 +02:00
|
|
|
} {GT(c0,11)}
|
2015-08-14 22:08:13 +02:00
|
|
|
do_test 4.2 {
|
2016-01-04 02:08:50 +01:00
|
|
|
p5_of_opcode db OpenRead {
|
2015-08-14 22:08:13 +02:00
|
|
|
SELECT * FROM t1 WHERE b>11;
|
|
|
|
}
|
2020-05-15 13:26:31 +02:00
|
|
|
} {2 0}
|
2015-08-17 19:19:28 +02:00
|
|
|
do_test 4.3asc {
|
2015-08-14 22:08:13 +02:00
|
|
|
p4_of_opcode db CursorHint {
|
2015-08-17 19:19:28 +02:00
|
|
|
SELECT c FROM t1 WHERE b<11 ORDER BY b ASC;
|
2015-08-14 22:08:13 +02:00
|
|
|
}
|
2015-08-17 19:19:28 +02:00
|
|
|
} {LT(c0,11)}
|
|
|
|
do_test 4.3desc {
|
|
|
|
p4_of_opcode db CursorHint {
|
|
|
|
SELECT c FROM t1 WHERE b<11 ORDER BY b DESC;
|
|
|
|
}
|
|
|
|
} {}
|
2015-08-14 22:08:13 +02:00
|
|
|
do_test 4.4 {
|
2016-01-04 02:08:50 +01:00
|
|
|
p5_of_opcode db OpenRead {
|
2015-08-17 19:19:28 +02:00
|
|
|
SELECT c FROM t1 WHERE b<11;
|
2015-08-14 22:08:13 +02:00
|
|
|
}
|
2020-05-15 13:26:31 +02:00
|
|
|
} {0}
|
2014-07-15 13:59:44 +02:00
|
|
|
|
2015-08-17 19:19:28 +02:00
|
|
|
do_test 4.5asc {
|
|
|
|
p4_of_opcode db CursorHint {
|
|
|
|
SELECT c FROM t1 WHERE b>=10 AND b<=20 ORDER BY b ASC;
|
|
|
|
}
|
|
|
|
} {LE(c0,20)}
|
|
|
|
do_test 4.5desc {
|
|
|
|
p4_of_opcode db CursorHint {
|
|
|
|
SELECT c FROM t1 WHERE b>=10 AND b<=20 ORDER BY b DESC;
|
|
|
|
}
|
|
|
|
} {GE(c0,10)}
|
2015-08-18 17:58:05 +02:00
|
|
|
|
|
|
|
# If there are any equality terms used in the constraint, then all terms
|
|
|
|
# should be hinted.
|
|
|
|
#
|
2015-08-17 19:19:28 +02:00
|
|
|
do_test 4.6asc {
|
|
|
|
p4_of_opcode db CursorHint {
|
|
|
|
SELECT rowid FROM t1 WHERE b=22 AND c>=10 AND c<=20 ORDER BY b,c ASC;
|
|
|
|
}
|
2015-08-18 17:58:05 +02:00
|
|
|
} {AND(AND(EQ(c0,22),GE(c1,10)),LE(c1,20))}
|
2015-08-17 19:19:28 +02:00
|
|
|
do_test 4.6desc {
|
|
|
|
p4_of_opcode db CursorHint {
|
|
|
|
SELECT rowid FROM t1 WHERE b=22 AND c>=10 AND c<=20 ORDER BY b,c DESC;
|
|
|
|
}
|
2015-08-18 17:58:05 +02:00
|
|
|
} {AND(AND(EQ(c0,22),GE(c1,10)),LE(c1,20))}
|
2014-07-15 13:59:44 +02:00
|
|
|
|
2023-03-24 20:17:25 +01:00
|
|
|
# 2023-03-24 https://sqlite.org/forum/forumpost/591006b1cc
|
|
|
|
#
|
|
|
|
reset_db
|
|
|
|
do_execsql_test 5.0 {
|
|
|
|
CREATE TABLE t1(x TEXT PRIMARY KEY) WITHOUT ROWID;
|
|
|
|
CREATE VIEW t2 AS SELECT 0 FROM t1 WHERE x>='a' OR x='1';
|
|
|
|
SELECT * FROM t2 RIGHT JOIN t1 ON true;
|
|
|
|
}
|
2023-03-25 03:07:20 +01:00
|
|
|
# Additional test case from https://sqlite.org/forum/forumpost/d34ad68c36?t=c
|
|
|
|
# which is a different way to acces the same problem.
|
|
|
|
#
|
|
|
|
do_execsql_test 5.1 {
|
|
|
|
CREATE TABLE v1 (c1, PRIMARY KEY( c1 )) WITHOUT ROWID;
|
|
|
|
CREATE VIEW v2 AS SELECT 0 FROM v1 WHERE c1 IS '' OR c1 > '';
|
|
|
|
CREATE VIEW v3 AS SELECT 0 FROM v2 JOIN (v2 RIGHT JOIN v1);
|
|
|
|
CREATE VIEW v4 AS SELECT 0 FROM v3, v3;
|
|
|
|
SELECT * FROM v3 JOIN v3 AS a0, v4 AS a1, v4 AS a2, v3 AS a3,
|
|
|
|
v3 AS a4, v4 AS a5
|
|
|
|
ORDER BY 1;
|
|
|
|
}
|
2023-03-24 20:17:25 +01:00
|
|
|
|
2023-04-10 20:44:00 +02:00
|
|
|
# 2023-04-10 https://sqlite.org/forum/forumpost/0b53708c95
|
|
|
|
#
|
|
|
|
do_execsql_test 6.0 {
|
|
|
|
CREATE TABLE t6(a TEXT UNIQUE, b TEXT);
|
|
|
|
INSERT INTO t6(a,b) VALUES('uvw','xyz'),('abc','def');
|
|
|
|
WITH v1(a) AS (SELECT a COLLATE NOCASE FROM t6)
|
|
|
|
SELECT v1.a, count(*) FROM t6 LEFT JOIN v1 ON true
|
|
|
|
GROUP BY 1
|
|
|
|
HAVING (SELECT true FROM t6 AS aa LEFT JOIN t6 AS bb ON length(v1.a)>5);
|
|
|
|
} {abc 2 uvw 2}
|
|
|
|
|
2023-05-04 13:29:15 +02:00
|
|
|
|
|
|
|
# 2023-05-04 https://sqlite.org/forum/forumpost/29a47cf6d1
|
|
|
|
#
|
|
|
|
# codeCursorHint() should not walk expressions that have been optimized
|
|
|
|
# out and converted to TRUE or FALSE. This only comes up when compiling
|
|
|
|
# with SQLITE_ENABLE_CURSOR_HINTS
|
|
|
|
#
|
|
|
|
reset_db
|
|
|
|
do_execsql_test 7.1 {
|
|
|
|
CREATE TABLE t1(a INT PRIMARY KEY) WITHOUT ROWID;
|
|
|
|
CREATE TABLE t2(b INT PRIMARY KEY) WITHOUT ROWID;
|
|
|
|
CREATE TABLE t3(c INT PRIMARY KEY) WITHOUT ROWID;
|
|
|
|
INSERT INTO t1(a) VALUES(1),(2);
|
|
|
|
INSERT INTO t2(b) VALUES(4),(8);
|
|
|
|
INSERT INTO t3(c) VALUES(16),(32);
|
|
|
|
CREATE VIEW v4(d) AS SELECT c FROM t3;
|
|
|
|
SELECT * FROM t1 RIGHT JOIN t2 ON true JOIN v4 ON (d IS NULL);
|
|
|
|
} {}
|
|
|
|
|
|
|
|
|
2014-07-15 13:59:44 +02:00
|
|
|
finish_test
|