sqlite/test/join8.test
drh ea488b1258 New test cases to further demonstrate the difference in name matching rules
for LEFT JOIN versus RIGHT JOIN that protect legacy behavior.
[forum:/forumpost/e90a8e6e6fa652ac|Forum thread e90a8e6e6fa652ac].

FossilOrigin-Name: 2c586060a016f5481bad29bfb8f4ac4e1204075afdd0fa1851fbbcf2abda4893
2022-05-23 12:37:54 +00:00

410 lines
13 KiB
Plaintext

# 2022-04-12
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file implements tests for RIGHT and FULL OUTER JOINs.
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !vtab {
finish_test
return
}
db null NULL
# EVIDENCE-OF: R-33754-02880 you can say "LEFT RIGHT JOIN" which is the
# same as "FULL JOIN".
do_execsql_test join8-10 {
CREATE TABLE t1(a,b,c);
CREATE TABLE t2(x,y);
CREATE INDEX t2x ON t2(x);
SELECT avg(DISTINCT b) FROM (SELECT * FROM t2 LEFT RIGHT JOIN t1 ON c);
} {NULL}
# Pending optimization opportunity:
# Row-value initialization subroutines must be called from with the
# RIGHT JOIN body subroutine before the first use of any register containing
# the results of that subroutine. This seems dodgy. Test case:
#
reset_db
do_execsql_test join8-1000 {
CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT,b,c,d,e,f,g,h,j,k,l,m,n,o,p,q,r,s);
CREATE INDEX t1x1 ON t1(g+h,j,k);
CREATE INDEX t1x2 ON t1(b);
INSERT INTO t1 DEFAULT VALUES;
} {}
do_catchsql_test join8-1010 {
SELECT a
FROM (
SELECT a
FROM (
SELECT a
FROM (
SELECT a FROM t1 NATURAL LEFT JOIN t1
WHERE (b, 2 ) IS ( SELECT 2 IN(2,2),2)
)
NATURAL LEFT FULL JOIN t1
WHERE ( rowid , 1 )<=(CASE 5 WHEN 619 THEN 841 ELSE 3374391096 END,0)
ORDER BY a ASC
)
NATURAL LEFT JOIN t1
WHERE (b, 2 ) IS ( SELECT 3 IN(3,3),3)
)
NATURAL LEFT FULL JOIN t1
WHERE ( rowid , 1 )<=(CASE 5 WHEN 619 THEN 841 ELSE 3374391096 END,0)
ORDER BY a ASC;
} {0 1}
# Pending issue #2: (now resolved)
# Jump to addrHalt inside the RIGHT JOIN body subroutine bypasses the
# OP_Return, resulting in a subroutine loop. Test case:
#
reset_db
do_execsql_test join8-2000 {
CREATE TABLE t1(a int, b int, c int);
INSERT INTO t1 VALUES(1,2,3),(4,5,6);
CREATE TABLE t2(d int, e int);
INSERT INTO t2 VALUES(3,333),(4,444);
CREATE TABLE t3(f int, g int);
PRAGMA automatic_index=off;
} {}
do_catchsql_test join8-2010 {
SELECT * FROM t1 RIGHT JOIN t2 ON c=d JOIN t3 ON f=e;
} {0 {}}
# Demonstrate that nested FULL JOINs and USING clauses work
#
reset_db
load_static_extension db series
do_execsql_test join8-3000 {
CREATE TABLE t1(id INTEGER PRIMARY KEY, a INT);
CREATE TABLE t2(id INTEGER PRIMARY KEY, b INT);
CREATE TABLE t3(id INTEGER PRIMARY KEY, c INT);
CREATE TABLE t4(id INTEGER PRIMARY KEY, d INT);
CREATE TABLE t5(id INTEGER PRIMARY KEY, e INT);
CREATE TABLE t6(id INTEGER PRIMARY KEY, f INT);
CREATE TABLE t7(id INTEGER PRIMARY KEY, g INT);
CREATE TABLE t8(id INTEGER PRIMARY KEY, h INT);
INSERT INTO t1 SELECT value, 1 FROM generate_series(1,256) WHERE value & 1;
INSERT INTO t2 SELECT value, 1 FROM generate_series(1,256) WHERE value & 2;
INSERT INTO t3 SELECT value, 1 FROM generate_series(1,256) WHERE value & 4;
INSERT INTO t4 SELECT value, 1 FROM generate_series(1,256) WHERE value & 8;
INSERT INTO t5 SELECT value, 1 FROM generate_series(1,256) WHERE value & 16;
INSERT INTO t6 SELECT value, 1 FROM generate_series(1,256) WHERE value & 32;
INSERT INTO t7 SELECT value, 1 FROM generate_series(1,256) WHERE value & 64;
INSERT INTO t8 SELECT value, 1 FROM generate_series(1,256) WHERE value & 128;
CREATE TABLE t9 AS
SELECT id, h, g, f, e, d, c, b, a
FROM t1
NATURAL FULL JOIN t2
NATURAL FULL JOIN t3
NATURAL FULL JOIN t4
NATURAL FULL JOIN t5
NATURAL FULL JOIN t6
NATURAL FULL JOIN t7
NATURAL FULL JOIN t8;
} {}
do_execsql_test join8-3010 {
SELECT count(*) FROM t9;
} {255}
do_execsql_test join8-3020 {
SELECT id, count(*) FROM t9 GROUP BY id HAVING count(*)!=1;
} {}
do_execsql_test join8-3030 {
UPDATE t9 SET a=0 WHERE a IS NULL;
UPDATE t9 SET b=0 WHERE b IS NULL;
UPDATE t9 SET c=0 WHERE c IS NULL;
UPDATE t9 SET d=0 WHERE d IS NULL;
UPDATE t9 SET e=0 WHERE e IS NULL;
UPDATE t9 SET f=0 WHERE f IS NULL;
UPDATE t9 SET g=0 WHERE g IS NULL;
UPDATE t9 SET h=0 WHERE h IS NULL;
SELECT count(*) FROM t9 WHERE id=128*h+64*g+32*f+16*e+8*d+4*c+2*b+a;
} {255}
do_execsql_test join8-3040 {
SELECT * FROM t9 WHERE id<>128*h+64*g+32*f+16*e+8*d+4*c+2*b+a;
} {}
# 2022-04-21 dbsqlfuzz find
#
reset_db
do_execsql_test join8-4000 {
CREATE TABLE t1(x INTEGER PRIMARY KEY, a, b);
INSERT INTO t1 VALUES(1,5555,4);
CREATE INDEX i1a ON t1(a);
CREATE INDEX i1b ON t1(b);
SELECT a FROM t1 NATURAL RIGHT JOIN t1 WHERE a=5555 OR (1,b)==(SELECT 2 IN (2,2),4);
} {5555}
# 2022-04-23 dbsqlfuzz c7ee5500e3abddec3557016de777713b80c790d3
# Escape from the right-join body subroutine via the ORDER BY LIMIT optimization.
#
reset_db
db null -
do_catchsql_test join8-5000 {
CREATE TABLE t1(x);
INSERT INTO t1(x) VALUES(NULL),(NULL);
CREATE TABLE t2(c, d);
INSERT INTO t2(c,d) SELECT x, x FROM t1;
CREATE INDEX t2dc ON t2(d, c);
SELECT (SELECT c FROM sqlite_temp_schema FULL JOIN t2 ON d IN (1,2,3) ORDER BY d) AS x FROM t1;
} {0 {- -}}
# 2022-04-29 dbsqlfuzz 19f1102a70cf966ab249de56d944fc20dbebcfcf
#
reset_db
do_execsql_test join8-6000 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT, c TEXT, d REAL);
INSERT INTO t1 VALUES(1,'A','aa',2.5);
SELECT * FROM t1 AS t2 NATURAL RIGHT JOIN t1 AS t3
WHERE (a,b) IN (SELECT rowid, b FROM t1);
} {1 A aa 2.5}
do_execsql_test join8-6010 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INT PRIMARY KEY, b TEXT, c TEXT, d INT) WITHOUT ROWID;
INSERT INTO t1 VALUES(15,'xray','baker',42);
SELECT value, t1.* FROM json_each('7') NATURAL RIGHT JOIN t1
WHERE (a,b) IN (SELECT a, b FROM t1);
} {7 15 xray baker 42}
do_execsql_test join8-6020 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INTEGER PRIMARY KEY,b);
INSERT INTO t1 VALUES(0,NULL),(1,2);
SELECT value, t1.* FROM json_each('17') NATURAL RIGHT JOIN t1
WHERE (a,b) IN (SELECT rowid, b FROM t1);
} {17 1 2}
# Bloom filter usage by RIGHT and FULL JOIN
#
reset_db
do_execsql_test join8-7000 {
CREATE TABLE t1(a INT, b INT, c INT, d INT);
WITH RECURSIVE c(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM c WHERE x<10)
INSERT INTO t1(a,b,c,d) SELECT x, x+100, x+200, x+300 FROM c;
CREATE TABLE t2(b INT, x INT);
INSERT INTO t2(b,x) SELECT b, a FROM t1 WHERE a%2=0;
CREATE INDEX t2b ON t2(b);
CREATE TABLE t3(c INT, y INT);
INSERT INTO t3(c,y) SELECT c, a FROM t1 WHERE a%3=0;
CREATE INDEX t3c ON t3(c);
CREATE TABLE t4(d INT, z INT);
INSERT INTO t4(d,z) SELECT d, a FROM t1 WHERE a%5=0;
CREATE INDEX t4d ON t4(d);
INSERT INTO t1(a,b,c,d) VALUES
(96,NULL,296,396),
(97,197,NULL,397),
(98,198,298,NULL),
(99,NULL,NULL,NULL);
ANALYZE sqlite_schema;
INSERT INTO sqlite_stat1 VALUES('t4','t4d','20 1');
INSERT INTO sqlite_stat1 VALUES('t3','t3c','32 1');
INSERT INTO sqlite_stat1 VALUES('t2','t2b','48 1');
INSERT INTO sqlite_stat1 VALUES('t1',NULL,'100');
ANALYZE sqlite_schema;
} {}
db null -
do_execsql_test join8-7010 {
WITH t0 AS MATERIALIZED (
SELECT t1.*, t2.*, t3.*
FROM t1 INNER JOIN t2 ON t1.b=t2.b AND t2.x>0
RIGHT JOIN t3 ON t1.c=t3.c AND t3.y>0
)
SELECT * FROM t0 FULL JOIN t4 ON t0.a=t4.d AND t4.z>0
ORDER BY coalesce(t0.a, t0.y+200, t4.d);
} {
6 106 206 306 106 6 206 6 - -
- - - - - - 200 0 - -
- - - - - - 203 3 - -
- - - - - - 209 9 - -
- - - - - - - - 300 0
- - - - - - - - 305 5
- - - - - - - - 310 10
}
# EVIDENCE-OF: R-33754-02880 you can say "LEFT RIGHT JOIN" which is the
# same as "FULL JOIN".
do_execsql_test join8-7011 {
WITH t0 AS MATERIALIZED (
SELECT t1.*, t2.*, t3.*
FROM t1 INNER JOIN t2 ON t1.b=t2.b AND t2.x>0
RIGHT JOIN t3 ON t1.c=t3.c AND t3.y>0
)
SELECT * FROM t0 LEFT RIGHT JOIN t4 ON t0.a=t4.d AND t4.z>0
ORDER BY coalesce(t0.a, t0.y+200, t4.d);
} {
6 106 206 306 106 6 206 6 - -
- - - - - - 200 0 - -
- - - - - - 203 3 - -
- - - - - - 209 9 - -
- - - - - - - - 300 0
- - - - - - - - 305 5
- - - - - - - - 310 10
}
do_execsql_test join8-7020 {
EXPLAIN QUERY PLAN
WITH t0 AS MATERIALIZED (
SELECT t1.*, t2.*, t3.*
FROM t1 INNER JOIN t2 ON t1.b=t2.b AND t2.x>0
RIGHT JOIN t3 ON t1.c=t3.c AND t3.y>0
)
SELECT * FROM t0 FULL JOIN t4 ON t0.a=t4.d AND t4.z>0
ORDER BY coalesce(t0.a, t0.y+200, t4.d);
} {/.*BLOOM FILTER ON t2.*BLOOM FILTER ON t3.*BLOOM FILTER ON t4.*/}
# 2022-05-12 Difference with PG found (by Dan) while exploring
# https://sqlite.org/forum/forumpost/677a0ab93fcd9ccd
#
reset_db
do_execsql_test join8-8000 {
CREATE TABLE t1(a INT, b INT);
CREATE TABLE t2(c INT, d INT);
CREATE TABLE t3(e INT, f INT);
INSERT INTO t1 VALUES(1, 2);
INSERT INTO t2 VALUES(3, 4);
INSERT INTO t3 VALUES(5, 6);
} {}
do_execsql_test join8-8010 {
SELECT *
FROM t3 LEFT JOIN t2 ON true
JOIN t1 ON (t3.e IS t2.c);
} {}
do_execsql_test join8-8020 {
SELECT *
FROM t3 LEFT JOIN t2 ON true
JOIN t1 ON (t3.e IS NOT DISTINCT FROM t2.c);
} {}
# 2022-05-13 The idea of reusing subquery cursors does not
# work, if the cursors are used both for scanning and lookups.
#
reset_db
db null -
do_execsql_test join8-9000 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT, c TEXT, d REAL);
INSERT INTO t1 VALUES(1,'E','bb',NULL),(2,NULL,NULL,NULL);
SELECT * FROM t1 NATURAL RIGHT JOIN t1 AS t2 WHERE (a,b) IN (SELECT a+0, b FROM t1);
} {1 E bb -}
# 2022-05-14 https://sqlite.org/forum/forumpost/c06b10ad7e
#
reset_db
db null -
do_execsql_test join8-10000 {
CREATE TABLE t1(c0 INT UNIQUE);
CREATE TABLE t2(c0);
CREATE TABLE t2i(c0 INT);
CREATE TABLE t3(c0 INT);
INSERT INTO t1 VALUES(1);
INSERT INTO t2 VALUES(2);
INSERT INTO t2i VALUES(2);
INSERT INTO t3 VALUES(3);
} {}
do_execsql_test join8-10010 {
SELECT DISTINCT t1.c0, t3.c0
FROM t2 NATURAL JOIN t1 RIGHT JOIN t3 ON t1.c0;
} {- 3}
do_execsql_test join8-10020 {
SELECT t1.c0, t3.c0
FROM t2 NATURAL JOIN t1 RIGHT JOIN t3 ON t1.c0;
} {- 3}
do_execsql_test join8-10030 {
SELECT DISTINCT t1.c0, t3.c0
FROM t2 NATURAL CROSS JOIN t1 RIGHT JOIN t3 ON t1.c0;
} {- 3}
do_execsql_test join8-10040 {
SELECT t1.c0, t3.c0
FROM t1 NATURAL CROSS JOIN t2 RIGHT JOIN t3 ON t1.c0;
} {- 3}
do_execsql_test join8-10050 {
SELECT DISTINCT t1.c0, t3.c0
FROM t2i NATURAL JOIN t1 RIGHT JOIN t3 ON t1.c0;
} {- 3}
do_execsql_test join8-10060 {
SELECT DISTINCT +t1.c0, t3.c0
FROM t2 NATURAL JOIN t1 RIGHT JOIN t3 ON t1.c0;
} {- 3}
do_execsql_test join8-10070 {
SELECT DISTINCT +t1.c0, t3.c0
FROM t1 NATURAL CROSS JOIN t2 RIGHT JOIN t3 ON t1.c0;
} {- 3}
do_execsql_test join8-10080 {
SELECT DISTINCT t1.c0, t3.c0
FROM t2 NATURAL JOIN t1 RIGHT JOIN t3 ON t1.c0<>0;
} {- 3}
# 2022-05-14
# index-on-expr scan on a RIGHT JOIN
# dbsqlfuzz 39ee60004ff027a9e2846cf76e02cd5ac0953739
#
reset_db
db null -
do_execsql_test join8-11000 {
CREATE TABLE t1(a);
CREATE TABLE t2(b);
INSERT INTO t2 VALUES(0),(1),(2);
SELECT * FROM t1 RIGHT JOIN t2 ON (a=b) WHERE 99+(b+1)!=99;
} {- 0 - 1 - 2}
do_execsql_test join8-11010 {
CREATE INDEX t2b ON t2(b+1) WHERE b IS NOT NULL;
SELECT * FROM t1 RIGHT JOIN t2 ON (a=b) WHERE 99+(b+1)!=99;
} {- 0 - 1 - 2}
do_execsql_test join8-11020 {
DROP TABLE t1;
DROP TABLE t2;
CREATE TABLE t1(a);
CREATE TABLE t2(b, c, d);
INSERT INTO t2 VALUES(1, 3, 'not-4');
SELECT b, d FROM t1 RIGHT JOIN t2 WHERE (b+0)=1 AND d!=4;
} {1 not-4}
do_execsql_test join8-11030 {
CREATE INDEX i2 ON t2((b+0), d);
SELECT b, d FROM t1 RIGHT JOIN t2 WHERE (b+0)=1 AND d!=4;
} {1 not-4}
do_execsql_test join8-11040 {
DROP INDEX i2;
CREATE INDEX i2 ON t2((b+0), d) WHERE d IS NOT NULL;
SELECT b, d FROM t1 RIGHT JOIN t2 WHERE (b+0)=1 AND d!=4;
} {1 not-4}
# 2022-05-23
# NATURAL JOIN name resolution is more forgiving with LEFT JOIN
# https://sqlite.org/forum/forumpost/e90a8e6e6f
#
reset_db
db null -
do_execsql_test join8-12000 {
CREATE TABLE t1(a INT); INSERT INTO t1 VALUES(0),(1);
CREATE TABLE t2(a INT); INSERT INTO t2 VALUES(0),(2);
CREATE TABLE t3(a INT); INSERT INTO t3 VALUES(0),(3);
} {}
do_catchsql_test join8-12010 {
SELECT * FROM t1 RIGHT JOIN t2 ON t2.a<>0 NATURAL RIGHT JOIN t3;
} {1 {ambiguous reference to a in USING()}}
do_catchsql_test join8-12020 {
SELECT * FROM t1 RIGHT JOIN t2 ON t2.a<>0 NATURAL LEFT JOIN t3;
} {1 {ambiguous reference to a in USING()}}
do_catchsql_test join8-12030 {
SELECT * FROM t1 LEFT JOIN t2 ON t2.a<>0 NATURAL RIGHT JOIN t3;
} {1 {ambiguous reference to a in USING()}}
# The following query should probably also return the same error as the
# previous three cases. However, historical versions of SQLite have always
# let it pass. We will not "fix" this, since to do so might break legacy
# applications.
#
do_catchsql_test join8-12040 {
SELECT * FROM t1 LEFT JOIN t2 ON t2.a<>0 NATURAL LEFT JOIN t3;
} {0 {0 2 1 2}}
finish_test