sqlite/test/in6.test
drh 81f5ef05a9 Fix the IN-early-out optimization so that it works even for the corner case
where the NULL bypass fires before the affinity of the LHS operator has been
set.  Fix for the problem described in
[forum:/forumpost/6a3ec138e9|forum post 6a3ec138e9].

FossilOrigin-Name: eb40248ce606b792a02e4e0b7dd826a82891c5f4c9793f3ca5d332e593109525
2021-04-29 15:49:34 +00:00

120 lines
3.4 KiB
Plaintext

# 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 {}}
# 2020-03-16 ticket 82b588d342d515d1
# Ensure that the IN-early-out optimization works with LEFT JOINs
#
reset_db
do_execsql_test in6-3.100 {
CREATE TABLE t1(a);
INSERT INTO t1 VALUES(0);
CREATE TABLE t2(b, c, d);
INSERT INTO t2(b,c,d) VALUES(4,5,3),(4,5,4),(4,5,8);
CREATE INDEX t2bcd ON t2(b, c, d);
SELECT * FROM t1 LEFT JOIN t2 ON b=NULL AND c=5 AND d IN (2,3,4);
} {0 {} {} {}}
do_execsql_test in6-3.110 {
CREATE TABLE v0(v1);
CREATE TABLE v3(v5, v4);
INSERT INTO v0 VALUES(0);
CREATE INDEX v9 ON v3(v4, v4, v5);
SELECT quote(v5) FROM v0 LEFT JOIN v3 ON v4 = NULL AND v5 IN(0);
} {NULL}
# 2021-04-29 forum https://sqlite.org/forum/forumpost/6a3ec138e9
# An early OP_IsNull bypass might skip over the OP_Affinity and
# cause the OP_IfNoHope to jump on a false-positive, resulting in
# incomplete output.
#
reset_db
do_execsql_test in6-3.120 {
CREATE TABLE t1(a TEXT, b TEXT);
INSERT INTO t1 VALUES(null,10),(0,10),(10,10);
CREATE INDEX t1ab ON t1(a,b);
SELECT quote(a), quote(b), '|' FROM t1 WHERE b in (SELECT a FROM t1) AND a=0;
} {'0' '10' |}
do_execsql_test in6-3.130 {
CREATE TABLE t2(x TEXT);
INSERT INTO t2(x) VALUES(NULL),(0),(10);
SELECT quote(x), quote(a), quote(b), 'x'
FROM t2 LEFT JOIN t1 ON a=x AND b in (null,0,10);
} {NULL NULL NULL x '0' '0' '10' x '10' '10' '10' x}
finish_test