should be it
This commit is contained in:
110
external/duckdb/test/sql/optimizer/plan/plan_struct_projection_pushdown.test
vendored
Normal file
110
external/duckdb/test/sql/optimizer/plan/plan_struct_projection_pushdown.test
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
# name: test/sql/optimizer/plan/plan_struct_projection_pushdown.test
|
||||
# description: Test struct projection pushdown
|
||||
# group: [plan]
|
||||
|
||||
require parquet
|
||||
|
||||
statement ok
|
||||
CREATE TABLE struct_pushdown_test(id INT, struct_col STRUCT(sub_col1 integer, sub_col2 bool));
|
||||
|
||||
statement ok
|
||||
INSERT INTO struct_pushdown_test VALUES (1, {'sub_col1': 42, 'sub_col2': true}), (2, NULL), (3, {'sub_col1': 84, 'sub_col2': NULL}), (4, {'sub_col1': NULL, 'sub_col2': false});
|
||||
|
||||
statement ok
|
||||
COPY struct_pushdown_test TO '__TEST_DIR__/struct_pushdown_test.parquet'
|
||||
|
||||
statement ok
|
||||
PRAGMA explain_output = 'PHYSICAL_ONLY';
|
||||
|
||||
foreach source struct_pushdown_test read_parquet('__TEST_DIR__/struct_pushdown_test.parquet')
|
||||
|
||||
# verify we are only selecting sub_col2
|
||||
query II
|
||||
EXPLAIN SELECT struct_col.sub_col2 FROM ${source};
|
||||
----
|
||||
physical_plan <REGEX>:.*struct_col.sub_col2.*
|
||||
|
||||
# verify we are only selecting sub_col1
|
||||
query II
|
||||
EXPLAIN SELECT struct_col.sub_col1 FROM ${source};
|
||||
----
|
||||
physical_plan <REGEX>:.*struct_col.sub_col1.*
|
||||
|
||||
query II
|
||||
EXPLAIN SELECT struct_col.sub_col1, struct_col.sub_col2 FROM ${source};
|
||||
----
|
||||
physical_plan <REGEX>:.*struct_col.sub_col1.*struct_col.sub_col2.*
|
||||
|
||||
# here we need to select the entire column
|
||||
query II
|
||||
EXPLAIN SELECT struct_col.sub_col1, struct_col FROM ${source};
|
||||
----
|
||||
physical_plan <REGEX>:.*struct_col .*
|
||||
|
||||
endloop
|
||||
|
||||
# do the same with 2-nested structs
|
||||
statement ok
|
||||
CREATE TABLE nested_struct_pushdown_test(id INT, struct_col STRUCT(name STRUCT(v VARCHAR, id INT), nested_struct STRUCT(a integer, b bool)));
|
||||
|
||||
statement ok
|
||||
INSERT INTO nested_struct_pushdown_test
|
||||
VALUES (1, {'name': {'v': 'Row 1', 'id': 1}, 'nested_struct': {'a': 42, 'b': true}}),
|
||||
(2, NULL),
|
||||
(3, {'name': {'v': 'Row 3', 'id': 3}, 'nested_struct': {'a': 84, 'b': NULL}}),
|
||||
(4, {'name': NULL, 'nested_struct': {'a': NULL, 'b': false}});
|
||||
|
||||
statement ok
|
||||
COPY nested_struct_pushdown_test TO '__TEST_DIR__/nested_struct_pushdown_test.parquet'
|
||||
|
||||
foreach source nested_struct_pushdown_test read_parquet('__TEST_DIR__/nested_struct_pushdown_test.parquet')
|
||||
|
||||
query II
|
||||
EXPLAIN SELECT struct_col.name.id FROM ${source};
|
||||
----
|
||||
physical_plan <REGEX>:.*struct_col.name.id.*
|
||||
|
||||
query II
|
||||
EXPLAIN SELECT struct_col.name.id, struct_col.name FROM ${source};
|
||||
----
|
||||
physical_plan <REGEX>:.*struct_col.name .*
|
||||
|
||||
query II
|
||||
EXPLAIN SELECT struct_col.name.id, struct_col FROM ${source};
|
||||
----
|
||||
physical_plan <REGEX>:.*struct_col .*
|
||||
|
||||
endloop
|
||||
|
||||
# 3 layers of nesting
|
||||
statement ok
|
||||
CREATE OR REPLACE TABLE nested_struct_pushdown_test(id INT, struct_col STRUCT(s STRUCT(name STRUCT(v VARCHAR, id INT), nested_struct STRUCT(a integer, b bool))));
|
||||
|
||||
statement ok
|
||||
INSERT INTO nested_struct_pushdown_test
|
||||
VALUES (1, {'s': {'name': {'v': 'Row 1', 'id': 1}, 'nested_struct': {'a': 42, 'b': true}}}),
|
||||
(2, NULL),
|
||||
(3, {'s': {'name': {'v': 'Row 3', 'id': 3}, 'nested_struct': {'a': 84, 'b': NULL}}}),
|
||||
(4, {'s': {'name': NULL, 'nested_struct': {'a': NULL, 'b': false}}});
|
||||
|
||||
statement ok
|
||||
COPY nested_struct_pushdown_test TO '__TEST_DIR__/nested_struct_pushdown_test.parquet'
|
||||
|
||||
foreach source nested_struct_pushdown_test read_parquet('__TEST_DIR__/nested_struct_pushdown_test.parquet')
|
||||
|
||||
query II
|
||||
EXPLAIN SELECT struct_col.s.name.id FROM ${source};
|
||||
----
|
||||
physical_plan <REGEX>:.*struct_col.s.name.id.*
|
||||
|
||||
query II
|
||||
EXPLAIN SELECT struct_col.s.name.id, struct_col.s.name FROM ${source};
|
||||
----
|
||||
physical_plan <REGEX>:.*struct_col.s.name .*
|
||||
|
||||
query II
|
||||
EXPLAIN SELECT struct_col.s.name.id, struct_col FROM ${source};
|
||||
----
|
||||
physical_plan <REGEX>:.*struct_col .*
|
||||
|
||||
endloop
|
||||
52
external/duckdb/test/sql/optimizer/plan/table_filter_pushdown_large_strings.test_slow
vendored
Normal file
52
external/duckdb/test/sql/optimizer/plan/table_filter_pushdown_large_strings.test_slow
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
# name: test/sql/optimizer/plan/table_filter_pushdown_large_strings.test_slow
|
||||
# description: Test Table Filter Push Down Scan String
|
||||
# group: [plan]
|
||||
|
||||
statement ok
|
||||
PRAGMA enable_verification
|
||||
|
||||
statement ok
|
||||
CREATE TABLE strings AS select i FROM (VALUES('pedro'), ('peter'), ('mark')) t1(i), range(0, 100000) t2(j) order by j
|
||||
|
||||
query I
|
||||
SELECT count(i) FROM strings where i = 'pedro'
|
||||
----
|
||||
100000
|
||||
|
||||
query I
|
||||
SELECT count(i) FROM strings where i = 'peter'
|
||||
----
|
||||
100000
|
||||
|
||||
query I
|
||||
SELECT count(i) FROM strings where i = 'mark'
|
||||
----
|
||||
100000
|
||||
|
||||
query I
|
||||
SELECT count(i) FROM strings where i = 'diego'
|
||||
----
|
||||
0
|
||||
|
||||
|
||||
statement ok
|
||||
INSERT INTO strings VALUES('po')
|
||||
|
||||
statement ok
|
||||
INSERT INTO strings VALUES('stefan manegold')
|
||||
|
||||
statement ok
|
||||
INSERT INTO strings VALUES('tim k')
|
||||
|
||||
statement ok
|
||||
INSERT INTO strings VALUES('tim k')
|
||||
|
||||
statement ok
|
||||
update strings set i = 'zorro' where i = 'pedro'
|
||||
|
||||
query I
|
||||
SELECT count(i) FROM strings where i >= 'tim k'
|
||||
----
|
||||
100002
|
||||
|
||||
|
||||
14
external/duckdb/test/sql/optimizer/plan/test_disable_build_side_probe_side.test
vendored
Normal file
14
external/duckdb/test/sql/optimizer/plan/test_disable_build_side_probe_side.test
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# name: test/sql/optimizer/plan/test_disable_build_side_probe_side.test
|
||||
# description: Test that disabling BuildProbeSideOptimizer does not swap RIGHT joins to LEFT
|
||||
# group: [plan]
|
||||
|
||||
statement ok
|
||||
pragma explain_output='optimized_only'
|
||||
|
||||
statement ok
|
||||
set disabled_optimizers to 'build_side_probe_side';
|
||||
|
||||
query II
|
||||
explain from range(10) r1 right join range(10) r2 using (range)
|
||||
----
|
||||
logical_opt <!REGEX>:.*LEFT.*
|
||||
233
external/duckdb/test/sql/optimizer/plan/test_filter_pushdown.test
vendored
Normal file
233
external/duckdb/test/sql/optimizer/plan/test_filter_pushdown.test
vendored
Normal file
@@ -0,0 +1,233 @@
|
||||
# name: test/sql/optimizer/plan/test_filter_pushdown.test
|
||||
# description: Test filter pushdown
|
||||
# group: [plan]
|
||||
|
||||
statement ok
|
||||
SET default_null_order='nulls_first';
|
||||
|
||||
statement ok
|
||||
PRAGMA enable_verification
|
||||
|
||||
statement ok
|
||||
CREATE TABLE integers(i INTEGER)
|
||||
|
||||
statement ok
|
||||
INSERT INTO integers VALUES (1), (2), (3), (NULL)
|
||||
|
||||
# test filter pushdown into cross product
|
||||
# single filter that matches both sides
|
||||
query II
|
||||
SELECT * FROM integers i1, integers i2 WHERE i1.i=i2.i ORDER BY 1
|
||||
----
|
||||
1 1
|
||||
2 2
|
||||
3 3
|
||||
|
||||
# add filter that matches left side
|
||||
query II
|
||||
SELECT * FROM integers i1, integers i2 WHERE i1.i=i2.i AND i1.i>1 ORDER BY 1
|
||||
----
|
||||
2 2
|
||||
3 3
|
||||
|
||||
# three cross products
|
||||
query III
|
||||
SELECT * FROM integers i1, integers i2, integers i3 WHERE i1.i=i2.i AND i1.i=i3.i AND i1.i>1 ORDER BY 1
|
||||
----
|
||||
2 2 2
|
||||
3 3 3
|
||||
|
||||
# inner join
|
||||
query II
|
||||
SELECT * FROM integers i1 JOIN integers i2 ON i1.i=i2.i WHERE i1.i>1 ORDER BY 1
|
||||
----
|
||||
2 2
|
||||
3 3
|
||||
|
||||
# left outer join
|
||||
# condition on LHS
|
||||
query II
|
||||
SELECT * FROM integers i1 LEFT OUTER JOIN integers i2 ON 1=1 WHERE i1.i>2 ORDER BY 2
|
||||
----
|
||||
3 NULL
|
||||
3 1
|
||||
3 2
|
||||
3 3
|
||||
|
||||
# condition on RHS that eliminates NULL values
|
||||
query II
|
||||
SELECT * FROM integers i1 LEFT OUTER JOIN integers i2 ON 1=0 WHERE i2.i IS NOT NULL ORDER BY 2
|
||||
----
|
||||
|
||||
# more complicated conditions on RHS that eliminates NULL values
|
||||
query II
|
||||
SELECT * FROM integers i1 LEFT OUTER JOIN integers i2 ON 1=0 WHERE i2.i>1 ORDER BY 2
|
||||
----
|
||||
|
||||
query II
|
||||
SELECT * FROM integers i1 LEFT OUTER JOIN integers i2 ON 1=0 WHERE CASE WHEN i2.i IS NULL THEN False ELSE True END ORDER BY 2
|
||||
----
|
||||
|
||||
# conditions on RHS that does not eliminate NULL values
|
||||
query II
|
||||
SELECT DISTINCT * FROM integers i1 LEFT OUTER JOIN integers i2 ON 1=0 WHERE i2.i IS NULL ORDER BY 1
|
||||
----
|
||||
NULL NULL
|
||||
1 NULL
|
||||
2 NULL
|
||||
3 NULL
|
||||
|
||||
# conditions on both sides that guarantees to eliminate null values from RHS
|
||||
query II
|
||||
SELECT * FROM integers i1 LEFT OUTER JOIN integers i2 ON 1=1 WHERE i1.i=i2.i ORDER BY 1
|
||||
----
|
||||
1 1
|
||||
2 2
|
||||
3 3
|
||||
|
||||
# MARK join
|
||||
# transform into semi join
|
||||
query I
|
||||
SELECT * FROM integers WHERE i IN ((SELECT * FROM integers)) ORDER BY i
|
||||
----
|
||||
1
|
||||
2
|
||||
3
|
||||
|
||||
# transform into ANTI join
|
||||
query I
|
||||
SELECT * FROM integers WHERE i NOT IN ((SELECT * FROM integers WHERE i=1)) ORDER BY i
|
||||
----
|
||||
2
|
||||
3
|
||||
|
||||
# condition pushdown
|
||||
query I
|
||||
SELECT * FROM integers WHERE i IN ((SELECT * FROM integers)) AND i<3 ORDER BY i
|
||||
----
|
||||
1
|
||||
2
|
||||
|
||||
query II
|
||||
SELECT * FROM integers i1, integers i2 WHERE i1.i IN ((SELECT * FROM integers)) AND i1.i=i2.i ORDER BY 1
|
||||
----
|
||||
1 1
|
||||
2 2
|
||||
3 3
|
||||
|
||||
# DELIM join
|
||||
# correlated exists: turn into semi join
|
||||
query I
|
||||
SELECT * FROM integers i1 WHERE EXISTS(SELECT i FROM integers WHERE i=i1.i) ORDER BY i1.i
|
||||
----
|
||||
1
|
||||
2
|
||||
3
|
||||
|
||||
# correlated not exists: turn into anti join
|
||||
query I
|
||||
SELECT * FROM integers i1 WHERE NOT EXISTS(SELECT i FROM integers WHERE i=i1.i) ORDER BY i1.i
|
||||
----
|
||||
NULL
|
||||
|
||||
# push condition down delim join
|
||||
query II
|
||||
SELECT * FROM integers i1, integers i2 WHERE i1.i=(SELECT i FROM integers WHERE i1.i=i) AND i1.i=i2.i ORDER BY i1.i
|
||||
----
|
||||
1 1
|
||||
2 2
|
||||
3 3
|
||||
|
||||
# test filter pushdown into subquery
|
||||
query II
|
||||
SELECT * FROM (SELECT i1.i AS a, i2.i AS b FROM integers i1, integers i2) a1 WHERE a=b ORDER BY 1
|
||||
----
|
||||
1 1
|
||||
2 2
|
||||
3 3
|
||||
|
||||
# filter pushdown on subquery with more complicated expression
|
||||
query T
|
||||
SELECT * FROM (SELECT i1.i=i2.i AS cond FROM integers i1, integers i2) a1 WHERE cond ORDER BY 1
|
||||
----
|
||||
1
|
||||
1
|
||||
1
|
||||
|
||||
# filter pushdown into distinct in subquery
|
||||
query II
|
||||
SELECT * FROM (SELECT DISTINCT i1.i AS a, i2.i AS b FROM integers i1, integers i2) res WHERE a=1 AND b=3;
|
||||
----
|
||||
1 3
|
||||
|
||||
# filter pushdown into union in subquery
|
||||
query I
|
||||
SELECT * FROM (SELECT * FROM integers i1 UNION SELECT * FROM integers i2) a WHERE i=3;
|
||||
----
|
||||
3
|
||||
|
||||
# filter pushdown on subquery with window function (cannot be done because it will mess up the ordering)
|
||||
query III
|
||||
SELECT * FROM (SELECT i1.i AS a, i2.i AS b, row_number() OVER (ORDER BY i1.i, i2.i) FROM integers i1, integers i2 WHERE i1.i IS NOT NULL AND i2.i IS NOT NULL) a1 WHERE a=b ORDER BY 1
|
||||
----
|
||||
1 1 1
|
||||
2 2 5
|
||||
3 3 9
|
||||
|
||||
# condition on scalar projection
|
||||
query T
|
||||
SELECT * FROM (SELECT 0=1 AS cond FROM integers i1, integers i2) a1 WHERE cond ORDER BY 1
|
||||
----
|
||||
|
||||
# condition on scalar grouping
|
||||
query T
|
||||
SELECT * FROM (SELECT 0=1 AS cond FROM integers i1, integers i2 GROUP BY 1) a1 WHERE cond ORDER BY 1
|
||||
----
|
||||
|
||||
# Disable IN generation with inequalities
|
||||
statement ok
|
||||
CREATE TABLE cohort (
|
||||
person_id INTEGER,
|
||||
cohort_start_date DATE,
|
||||
cohort_end_date DATE
|
||||
);
|
||||
|
||||
statement ok
|
||||
INSERT INTO cohort (person_id, cohort_start_date, cohort_end_date) VALUES
|
||||
(1, DATE '2021-01-01', DATE '2021-02-15'),
|
||||
(1, DATE '2021-01-01', NULL);
|
||||
|
||||
statement ok
|
||||
CREATE TABLE obs (
|
||||
person_id INTEGER,
|
||||
observation_period_start_date DATE
|
||||
);
|
||||
|
||||
statement ok
|
||||
INSERT INTO obs (person_id, observation_period_start_date) VALUES
|
||||
(1, DATE '2010-01-01'),
|
||||
(2, DATE '2010-01-01');
|
||||
|
||||
query IIII
|
||||
SELECT q01.*
|
||||
FROM (
|
||||
SELECT LHS.*, observation_period_start_date
|
||||
FROM (
|
||||
SELECT q01.*
|
||||
FROM (
|
||||
SELECT
|
||||
person_id,
|
||||
cohort_start_date,
|
||||
COALESCE(cohort_end_date, cohort_start_date) AS cohort_end_date
|
||||
FROM cohort
|
||||
) q01
|
||||
WHERE (cohort_start_date <= cohort_end_date)
|
||||
) LHS
|
||||
INNER JOIN obs
|
||||
ON (LHS.person_id = obs.person_id)
|
||||
) q01
|
||||
WHERE (cohort_end_date >= observation_period_start_date)
|
||||
ORDER BY ALL;
|
||||
----
|
||||
1 2021-01-01 2021-01-01 2010-01-01
|
||||
1 2021-01-01 2021-02-15 2010-01-01
|
||||
52
external/duckdb/test/sql/optimizer/plan/test_filter_pushdown_advanced.test_slow
vendored
Normal file
52
external/duckdb/test/sql/optimizer/plan/test_filter_pushdown_advanced.test_slow
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
# name: test/sql/optimizer/plan/test_filter_pushdown_advanced.test_slow
|
||||
# description: Test filter pushdown with more advanced expressions
|
||||
# group: [plan]
|
||||
|
||||
# in this test we run queries that will take a long time without filter pushdown, but are almost instant with
|
||||
# proper filter pushdown we create two tables with 10K elements each in most tests we cross product them together
|
||||
# in some way to create a "big table" (100M entries) but the filter can be pushed past the cross product in all
|
||||
# cases
|
||||
statement ok
|
||||
CREATE TABLE vals1 AS SELECT i AS i, i AS j FROM range(0, 10000, 1) t1(i)
|
||||
|
||||
statement ok
|
||||
CREATE TABLE vals2(k INTEGER, l INTEGER)
|
||||
|
||||
statement ok
|
||||
INSERT INTO vals2 SELECT * FROM vals1
|
||||
|
||||
# x + 1 = 5001
|
||||
query I
|
||||
SELECT COUNT(*) FROM (SELECT * FROM vals1, vals2) tbl1, (SELECT * FROM vals1, vals2) tbl2 WHERE tbl1.i+1=5001 AND tbl1.i<>5000;
|
||||
----
|
||||
0
|
||||
|
||||
# x - 1 = 4999
|
||||
query I
|
||||
SELECT COUNT(*) FROM (SELECT * FROM vals1, vals2) tbl1, (SELECT * FROM vals1, vals2) tbl2 WHERE tbl1.i-1=4999 AND tbl1.i<>5000;
|
||||
----
|
||||
0
|
||||
|
||||
# x * 2 = 10000
|
||||
query I
|
||||
SELECT COUNT(*) FROM (SELECT * FROM vals1, vals2) tbl1, (SELECT * FROM vals1, vals2) tbl2 WHERE tbl1.i*2=10000 AND tbl1.i<>5000;
|
||||
----
|
||||
0
|
||||
|
||||
# x * 2 = 9999 should always return false (as 9999 % 2 != 0, it's not cleanly divisible)
|
||||
# SELECT COUNT(*) FROM (SELECT * FROM vals1, vals2) tbl1, (SELECT * FROM vals1, vals2) tbl2 WHERE tbl1.i*2=9999;
|
||||
# 0
|
||||
|
||||
# x / 2 = 2500
|
||||
# SELECT COUNT(*) FROM (SELECT * FROM vals1, vals2) tbl1, (SELECT * FROM vals1, vals2) tbl2 WHERE tbl1.i/2=2500 AND tbl1.i<>5000;
|
||||
# 0
|
||||
|
||||
# -x=-5000
|
||||
query I
|
||||
SELECT COUNT(*) FROM (SELECT * FROM vals1, vals2) tbl1, (SELECT * FROM vals1, vals2) tbl2 WHERE -tbl1.i=-5000 AND tbl1.i<>5000;
|
||||
----
|
||||
0
|
||||
|
||||
# x + (1 + 1) = 5002
|
||||
# SELECT COUNT(*) FROM (SELECT * FROM vals1, vals2) tbl1, (SELECT * FROM vals1, vals2) tbl2 WHERE tbl1.i+(1+1)=5002 AND tbl1.i<>5000;
|
||||
# 0
|
||||
78
external/duckdb/test/sql/optimizer/plan/test_filter_pushdown_duplicate.test
vendored
Normal file
78
external/duckdb/test/sql/optimizer/plan/test_filter_pushdown_duplicate.test
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
# name: test/sql/optimizer/plan/test_filter_pushdown_duplicate.test
|
||||
# description: Test moving/duplicating conditions
|
||||
# group: [plan]
|
||||
|
||||
# in this test we run queries that will take a long time without filter pushdown, but are almost instant with
|
||||
# proper filter pushdown we create two tables with 10K elements each in most tests we cross product them together
|
||||
# in some way to create a "big table" (100M entries) but the filter can be pushed past the cross product in all
|
||||
# cases
|
||||
statement ok
|
||||
CREATE TABLE vals1 AS SELECT i AS i, i AS j FROM range(0, 10000, 1) t1(i)
|
||||
|
||||
statement ok
|
||||
CREATE TABLE vals2(k INTEGER, l INTEGER)
|
||||
|
||||
statement ok
|
||||
INSERT INTO vals2 SELECT * FROM vals1
|
||||
|
||||
# move conditions between joins
|
||||
# SELECT * FROM (SELECT * FROM vals1, vals2 WHERE i=3 AND k=5) tbl1 INNER JOIN (SELECT * FROM vals1, vals2) tbl2 ON tbl1.i=tbl2.i AND tbl1.k=tbl2.k;
|
||||
# 3 3 5 5 3 3 5 5
|
||||
|
||||
# SELECT * FROM (SELECT * FROM vals1, vals2 WHERE i>5000) tbl1 INNER JOIN (SELECT * FROM vals1, vals2 WHERE i<5000) tbl2 ON tbl1.i=tbl2.i AND tbl1.k=tbl2.k;
|
||||
# (empty result)
|
||||
|
||||
# SELECT * FROM (SELECT * FROM vals1, vals2 WHERE i>5000) tbl1 INNER JOIN (SELECT * FROM vals1, vals2 WHERE i<5002 AND k=1) tbl2 ON tbl1.i=tbl2.i AND tbl1.k=tbl2.k;
|
||||
# 5001 5001 1 1 5001 5001 1 1
|
||||
|
||||
# left outer join conditions
|
||||
# SELECT * FROM (SELECT * FROM vals1, vals2 WHERE i>5000) tbl1 LEFT OUTER JOIN (SELECT * FROM vals1, vals2) tbl2 ON tbl1.i=tbl2.i AND tbl1.k=tbl2.k WHERE tbl1.i<5002 AND tbl1.k=1;
|
||||
# 5001 5001 1 1 5001 5001 1 1
|
||||
|
||||
# only RHS has conditions
|
||||
# SELECT * FROM (SELECT * FROM vals1, vals2) tbl1 LEFT OUTER JOIN (SELECT * FROM vals1, vals2 WHERE i=3 AND k=5) tbl2 ON tbl1.i=tbl2.i AND tbl1.k=tbl2.k WHERE tbl2.i<5000;
|
||||
# 3 3 5 5 3 3 5 5
|
||||
|
||||
# only RHS has conditions
|
||||
# SELECT COUNT(*) FROM (SELECT * FROM (SELECT * FROM vals1, vals2) tbl1 LEFT OUTER JOIN (SELECT * FROM vals1, vals2 WHERE i=3 AND k=5) tbl2 ON tbl1.i=tbl2.i WHERE tbl1.k<10 AND tbl2.k IS NOT NULL) tbl3;
|
||||
# 10
|
||||
|
||||
# only LHS has conditions
|
||||
# SELECT COUNT(*) FROM (SELECT * FROM vals1, vals2 WHERE i=3 AND k=5) tbl1 LEFT OUTER JOIN (SELECT * FROM vals1, vals2) tbl2 ON tbl1.i=tbl2.i AND tbl1.k=tbl2.k;
|
||||
# 1
|
||||
|
||||
# side channel EXCEPT/INTERSECT
|
||||
# SELECT * FROM vals1, vals2 WHERE i>5000 INTERSECT SELECT * FROM vals1, vals2 WHERE i<5002 AND k=1;
|
||||
# 5001 5001 1 1
|
||||
|
||||
# SELECT * FROM vals1, vals2 WHERE i>5000 AND i<5002 AND k=1 EXCEPT SELECT * FROM vals1, vals2;
|
||||
# (empty result)
|
||||
|
||||
# side channel GROUP conditions
|
||||
# SELECT * FROM (SELECT i, k, MIN(j) FROM vals1, vals2 WHERE i=1 AND k=3 GROUP BY i, k) tbl1 INNER JOIN (SELECT * FROM vals1, vals2) tbl2 ON tbl1.i=tbl2.i AND tbl1.k=tbl2.k;
|
||||
# 1 3 1 1 1 1 3 3
|
||||
|
||||
# conditions in subqueries
|
||||
# uncorrelated subqueries
|
||||
# SELECT * FROM vals1 WHERE i IN (SELECT i FROM vals1, vals2) AND i=3;
|
||||
# 3 3
|
||||
|
||||
# SELECT * FROM vals1 WHERE EXISTS(SELECT i FROM vals1, vals2) AND i=3;
|
||||
# 3 3
|
||||
|
||||
# correlated subqueries
|
||||
# SELECT * FROM vals1 v1 WHERE i IN (SELECT i FROM vals1, vals2 WHERE i=v1.i AND k=v1.i) AND i=3;
|
||||
# 3 3
|
||||
|
||||
# SELECT * FROM vals1 v1 WHERE i IN (SELECT i FROM vals1, vals2 WHERE i=v1.i AND k=v1.i AND k=4) AND i=3;
|
||||
# (empty result)
|
||||
|
||||
# SELECT * FROM vals1 v1 WHERE i IN (SELECT i FROM vals1, vals2 WHERE i=v1.i AND k=v1.i AND k>5000) AND i<5002;
|
||||
# 5001 5001
|
||||
|
||||
# SELECT * FROM vals1 v1 WHERE i=(SELECT i FROM vals1, vals2 WHERE i=v1.i AND k=v1.i) AND i=3;
|
||||
# 3 3
|
||||
|
||||
# SELECT * FROM vals1 v1 WHERE i=(SELECT MIN(i) FROM vals1, vals2 WHERE i=v1.i AND k=v1.i) AND i=3;
|
||||
# 3 3
|
||||
|
||||
241
external/duckdb/test/sql/optimizer/plan/test_filter_pushdown_large.test
vendored
Normal file
241
external/duckdb/test/sql/optimizer/plan/test_filter_pushdown_large.test
vendored
Normal file
@@ -0,0 +1,241 @@
|
||||
# name: test/sql/optimizer/plan/test_filter_pushdown_large.test
|
||||
# description: Test filter pushdown with more data
|
||||
# group: [plan]
|
||||
|
||||
# in this test we run queries that will take a long time without filter pushdown, but are almost instant with
|
||||
# proper filter pushdown we create two tables with 10K elements each in most tests we cross product them together
|
||||
# in some way to create a "big table" (100M entries) but the filter can be pushed past the cross product in all
|
||||
# cases
|
||||
statement ok
|
||||
CREATE TABLE vals1 AS SELECT i AS i, i AS j FROM range(0, 10000, 1) t1(i)
|
||||
|
||||
statement ok
|
||||
CREATE TABLE vals2(k INTEGER, l INTEGER)
|
||||
|
||||
statement ok
|
||||
INSERT INTO vals2 SELECT * FROM vals1
|
||||
|
||||
# pushdown filters into subqueries
|
||||
query II
|
||||
SELECT i, k FROM (SELECT i, k FROM vals1, vals2) tbl1 WHERE i=k AND i<5 ORDER BY i
|
||||
----
|
||||
0 0
|
||||
1 1
|
||||
2 2
|
||||
3 3
|
||||
4 4
|
||||
|
||||
# pushdown past DISTINCT
|
||||
query II
|
||||
SELECT i, k FROM (SELECT DISTINCT i, k FROM vals1, vals2) tbl1 WHERE i=k AND i<5 ORDER BY i
|
||||
----
|
||||
0 0
|
||||
1 1
|
||||
2 2
|
||||
3 3
|
||||
4 4
|
||||
|
||||
# pushdown conditions on group variables
|
||||
query IIR
|
||||
SELECT i, k, SUM(j) FROM vals1, vals2 GROUP BY i, k HAVING i=k AND i<5 ORDER BY i
|
||||
----
|
||||
0 0 0.000000
|
||||
1 1 1.000000
|
||||
2 2 2.000000
|
||||
3 3 3.000000
|
||||
4 4 4.000000
|
||||
|
||||
# also inside subqueries
|
||||
query IIR
|
||||
SELECT i, k, SUM(j) FROM (SELECT * FROM vals1, vals2) tbl1 GROUP BY i, k HAVING i=k AND i<5 ORDER BY i
|
||||
----
|
||||
0 0 0.000000
|
||||
1 1 1.000000
|
||||
2 2 2.000000
|
||||
3 3 3.000000
|
||||
4 4 4.000000
|
||||
|
||||
# and also like this
|
||||
query IIR
|
||||
SELECT i, k, sum FROM (SELECT i, k, SUM(j) AS sum FROM vals1, vals2 GROUP BY i, k) tbl1 WHERE i=k AND i<5 ORDER BY i;
|
||||
----
|
||||
0 0 0.000000
|
||||
1 1 1.000000
|
||||
2 2 2.000000
|
||||
3 3 3.000000
|
||||
4 4 4.000000
|
||||
|
||||
# LEFT OUTER JOIN on constant "true" can be turned into cross product, and after filters can be pushed
|
||||
query IIII
|
||||
SELECT * FROM vals1 LEFT OUTER JOIN vals2 ON 1=1 WHERE i=k AND k=5
|
||||
----
|
||||
5 5 5 5
|
||||
|
||||
# left outer join with equality filter can be turned into INNER JOIN
|
||||
query IIII
|
||||
SELECT * FROM vals1 LEFT OUTER JOIN vals2 ON 1=1 WHERE i=k ORDER BY i LIMIT 5
|
||||
----
|
||||
0 0 0 0
|
||||
1 1 1 1
|
||||
2 2 2 2
|
||||
3 3 3 3
|
||||
4 4 4 4
|
||||
|
||||
# left outer join can be turned into inner join after which elements can be pushed down into RHS
|
||||
query IIIIIIII
|
||||
SELECT * FROM (SELECT * FROM vals1, vals2 WHERE j=5 AND l=5) tbl1 LEFT OUTER JOIN (SELECT * FROM vals1, vals2) tbl2 ON tbl1.i=tbl2.i AND tbl1.k=tbl2.k WHERE tbl2.j=5 AND tbl2.l=5;
|
||||
----
|
||||
5 5 5 5 5 5 5 5
|
||||
|
||||
# filters can be pushed in the LHS of the LEFT OUTER JOIN
|
||||
query IIIIIIII
|
||||
SELECT * FROM (SELECT * FROM vals1, vals2) tbl1 LEFT OUTER JOIN (SELECT * FROM vals1, vals2 WHERE i=5 AND k=10) tbl2 ON tbl1.i=tbl2.i AND tbl1.k=tbl2.k WHERE tbl1.i=5 AND tbl1.k=10
|
||||
----
|
||||
5 5 10 10 5 5 10 10
|
||||
|
||||
# conditions in the ON clause can be pushed down into the RHS
|
||||
query IIIIIIII
|
||||
SELECT * FROM (SELECT * FROM vals1, vals2 WHERE i=5 AND k=5) tbl1 LEFT OUTER JOIN (SELECT * FROM vals1, vals2) tbl2 ON tbl2.i=5 AND tbl2.k=5
|
||||
----
|
||||
5 5 5 5 5 5 5 5
|
||||
|
||||
# also works if condition filters everything
|
||||
query IIIIIIII
|
||||
SELECT * FROM (SELECT * FROM vals1, vals2 WHERE i=5 AND k=5) tbl1 LEFT OUTER JOIN (SELECT * FROM vals1, vals2) tbl2 ON tbl2.i>10000 AND tbl2.k=5
|
||||
----
|
||||
5 5 5 5 NULL NULL NULL NULL
|
||||
|
||||
# we can replicate conditions on the left join predicates on the RHS
|
||||
query IIIIIIII
|
||||
SELECT * FROM (SELECT * FROM vals1, vals2) tbl1 LEFT OUTER JOIN (SELECT * FROM vals1, vals2) tbl2 ON tbl1.i=tbl2.i AND tbl1.k=tbl2.k WHERE tbl1.i=5 AND tbl1.k=10
|
||||
----
|
||||
5 5 10 10 5 5 10 10
|
||||
|
||||
# also multiple conditions
|
||||
query IIIIIIII
|
||||
SELECT * FROM (SELECT * FROM vals1, vals2) tbl1 LEFT OUTER JOIN (SELECT * FROM vals1, vals2) tbl2 ON tbl1.i=tbl2.i AND tbl1.k=tbl2.k WHERE tbl1.i>4 AND tbl1.i<6 AND tbl1.k=10
|
||||
----
|
||||
5 5 10 10 5 5 10 10
|
||||
|
||||
# pushdown union
|
||||
query IIII
|
||||
SELECT * FROM (SELECT * FROM vals1, vals2 UNION SELECT * FROM vals1, vals2) tbl1 WHERE i=3 AND k=5
|
||||
----
|
||||
3 3 5 5
|
||||
|
||||
# pushdown into except
|
||||
query IIII
|
||||
SELECT * FROM (SELECT * FROM vals1, vals2 EXCEPT SELECT * FROM vals1, vals2) tbl1 WHERE i=3 AND k=5
|
||||
----
|
||||
|
||||
query IIII
|
||||
SELECT * FROM (SELECT * FROM vals1, vals2 EXCEPT SELECT * FROM vals1, vals2 WHERE i<>1) tbl1 WHERE i<5 AND k<5 ORDER BY 1, 2, 3, 4;
|
||||
----
|
||||
1 1 0 0
|
||||
1 1 1 1
|
||||
1 1 2 2
|
||||
1 1 3 3
|
||||
1 1 4 4
|
||||
|
||||
# pushdown intersect
|
||||
query IIII
|
||||
SELECT * FROM (SELECT * FROM vals1, vals2 INTERSECT SELECT * FROM vals1, vals2) tbl1 WHERE i=3 AND k=5
|
||||
----
|
||||
3 3 5 5
|
||||
|
||||
# constant condition on scalar projection
|
||||
query T
|
||||
SELECT * FROM (SELECT 0=1 AS cond FROM vals1, vals2) a1 WHERE cond ORDER BY 1
|
||||
----
|
||||
|
||||
# constant condition that is more hidden
|
||||
query I
|
||||
SELECT * FROM (SELECT 1 AS a FROM vals1, vals2) a1 WHERE a=0 ORDER BY 1
|
||||
----
|
||||
|
||||
# condition on scalar grouping
|
||||
query T
|
||||
SELECT * FROM (SELECT 0=1 AS cond FROM vals1, vals2 GROUP BY 1) a1 WHERE cond ORDER BY 1
|
||||
----
|
||||
|
||||
query I
|
||||
SELECT * FROM (SELECT 1 AS a FROM vals1, vals2 GROUP BY a) a1 WHERE a=0 ORDER BY 1
|
||||
----
|
||||
|
||||
# duplicate filters across equivalency sets and pushdown cross product
|
||||
query I
|
||||
SELECT COUNT(*) FROM (SELECT * FROM vals1, vals2) tbl1, (SELECT * FROM vals1, vals2) tbl2 WHERE tbl1.i=tbl1.k AND tbl1.i=tbl2.k AND tbl1.i=tbl2.i AND tbl1.i=5000;
|
||||
----
|
||||
1
|
||||
|
||||
# also push other comparisons
|
||||
query I
|
||||
SELECT COUNT(*) FROM (SELECT * FROM vals1, vals2) tbl1, (SELECT * FROM vals1, vals2) tbl2 WHERE tbl1.i=tbl1.k AND tbl1.i=tbl2.k AND tbl1.i=tbl2.i AND tbl1.i>4999 AND tbl1.i<5001;
|
||||
----
|
||||
1
|
||||
|
||||
# empty result
|
||||
query I
|
||||
SELECT COUNT(*) FROM (SELECT * FROM vals1, vals2) tbl1, (SELECT * FROM vals1, vals2) tbl2 WHERE tbl1.i=5000 AND tbl1.i<>5000;
|
||||
----
|
||||
0
|
||||
|
||||
# also if we have a transitive condition
|
||||
query I
|
||||
SELECT COUNT(*) FROM (SELECT * FROM vals1, vals2) tbl1, (SELECT * FROM vals1, vals2) tbl2 WHERE tbl1.i=5000 AND tbl1.i=tbl2.i AND tbl2.i<>5000;
|
||||
----
|
||||
0
|
||||
|
||||
# useless inequality checks should be pruned
|
||||
query I
|
||||
SELECT COUNT(*) FROM (SELECT * FROM vals1, vals2) tbl1, (SELECT * FROM vals1, vals2) tbl2 WHERE tbl1.i=5000 AND tbl1.i=tbl2.i AND tbl1.i=tbl2.k AND tbl1.i=tbl1.k AND tbl2.i<>5001;
|
||||
----
|
||||
1
|
||||
|
||||
# add many useless predicates
|
||||
query I
|
||||
SELECT COUNT(*) FROM (SELECT * FROM vals1, vals2) tbl1, (SELECT * FROM vals1, vals2) tbl2 WHERE tbl2.i>10 AND tbl1.k>=500 AND tbl2.k<7000 AND tbl2.k<=6000 AND tbl2.k<>8000 AND tbl1.i<>4000 AND tbl1.i=tbl2.i AND tbl1.i=tbl2.k AND tbl1.i=tbl1.k AND tbl1.i=5000;
|
||||
----
|
||||
1
|
||||
|
||||
# FIXME filter equivalence with expressions
|
||||
# SELECT COUNT(*) FROM vals1, vals2 WHERE i+1=5001 AND j=l AND k=i AND l+1=5001
|
||||
# 0
|
||||
|
||||
# SELECT COUNT(*) FROM (SELECT * FROM vals1, vals2 WHERE i+1=5000 AND k+1=5000) tbl1, (SELECT *
|
||||
# FROM vals1, vals2) tbl2 WHERE tbl1.i=tbl2.i AND tbl1.k=tbl2.k;
|
||||
# 0
|
||||
|
||||
# greater than/less than should also be transitive
|
||||
# SELECT COUNT(*) FROM (SELECT * FROM vals1, vals2) tbl1, (SELECT * FROM vals1, vals2) tbl2 WHERE tbl1.i>9997 AND tbl1.k>tbl1.i AND tbl2.i>tbl1.i AND tbl2.k>tbl1.i;
|
||||
# 1
|
||||
|
||||
# equality with constant and then GT
|
||||
# SELECT COUNT(*) FROM (SELECT * FROM vals1, vals2) tbl1, (SELECT * FROM vals1, vals2) tbl2 WHERE tbl1.i=9998 AND tbl1.k=9998 AND tbl2.i>tbl1.i AND tbl2.k>tbl1.k;
|
||||
# 1
|
||||
|
||||
# equality with constant and then LT
|
||||
# SELECT COUNT(*) FROM (SELECT * FROM vals1, vals2) tbl1, (SELECT * FROM vals1, vals2) tbl2 WHERE tbl1.i=1 AND tbl1.k=1 AND tbl2.i<tbl1.i AND tbl2.k<tbl1.k;
|
||||
# 1
|
||||
|
||||
# transitive GT/LT
|
||||
# SELECT COUNT(*) FROM vals1, vals2 WHERE i>4999 AND j<=l AND k>=i AND l<5001
|
||||
# 1
|
||||
|
||||
# these more advanced cases we don't support yet
|
||||
# filter equivalence with expressions
|
||||
# SELECT COUNT(*) FROM vals1 v1, vals1 v2 WHERE v1.i+v2.i=10; IN list
|
||||
# SELECT COUNT(*) FROM (SELECT * FROM vals1, vals2) tbl1,
|
||||
# (SELECT * FROM vals1, vals2) tbl2 WHERE tbl2.k IN (5000, 5001, 5002) AND tbl2.k<5000;
|
||||
# 0
|
||||
|
||||
# CASE expression
|
||||
# SELECT COUNT(*) FROM (SELECT * FROM vals1, vals2) tbl1, (SELECT * FROM vals1, vals2) tbl2
|
||||
# WHERE tbl2.k<5000 AND CASE WHEN (tbl2.k>5000) THEN (tbl2.k=5001) ELSE (tbl2.k=5000) END;
|
||||
# 0
|
||||
|
||||
# OR expression
|
||||
# SELECT COUNT(*) FROM (SELECT * FROM vals1, vals2) tbl1, (SELECT * FROM vals1, vals2) tbl2
|
||||
# WHERE tbl2.k<5000 AND (tbl2.k=5000 OR tbl2.k>5000);
|
||||
# 0
|
||||
|
||||
34
external/duckdb/test/sql/optimizer/plan/test_filter_pushdown_materialized_cte.test
vendored
Normal file
34
external/duckdb/test/sql/optimizer/plan/test_filter_pushdown_materialized_cte.test
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
# name: test/sql/optimizer/plan/test_filter_pushdown_materialized_cte.test
|
||||
# description: Test filter pushdown in materialized CTEs (internal issue #3041)
|
||||
# group: [plan]
|
||||
|
||||
require tpcds
|
||||
|
||||
statement ok
|
||||
call dsdgen(sf=0.01)
|
||||
|
||||
statement ok
|
||||
pragma explain_output='OPTIMIZED_ONLY'
|
||||
|
||||
query II
|
||||
EXPLAIN WITH ss AS MATERIALIZED
|
||||
( SELECT i_manufact_id,
|
||||
sum(ss_ext_sales_price) total_sales
|
||||
FROM store_sales,
|
||||
date_dim,
|
||||
customer_address,
|
||||
item
|
||||
WHERE i_manufact_id IN
|
||||
(SELECT i_manufact_id
|
||||
FROM item
|
||||
WHERE i_category IN ('Electronics'))
|
||||
AND ss_item_sk = i_item_sk
|
||||
AND ss_sold_date_sk = d_date_sk
|
||||
AND d_year = 1998
|
||||
AND d_moy = 5
|
||||
AND ss_addr_sk = ca_address_sk
|
||||
AND ca_gmt_offset = -5
|
||||
GROUP BY i_manufact_id)
|
||||
FROM ss
|
||||
----
|
||||
logical_opt <!REGEX>:.*CROSS_PRODUCT.*
|
||||
33
external/duckdb/test/sql/optimizer/plan/test_table_filter_pushdown.test
vendored
Normal file
33
external/duckdb/test/sql/optimizer/plan/test_table_filter_pushdown.test
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
# name: test/sql/optimizer/plan/test_table_filter_pushdown.test
|
||||
# description: Test Table Filter Push Down Scan
|
||||
# group: [plan]
|
||||
|
||||
statement ok
|
||||
PRAGMA enable_verification
|
||||
|
||||
statement ok
|
||||
CREATE TABLE integers AS SELECT i AS i, i AS j FROM range(0, 100) tbl(i)
|
||||
|
||||
query I
|
||||
SELECT j FROM integers where j = 99
|
||||
----
|
||||
99
|
||||
|
||||
query I
|
||||
SELECT j FROM integers where j = 99 AND i=99
|
||||
----
|
||||
99
|
||||
|
||||
query I
|
||||
SELECT j FROM integers where j = 99 AND i=90
|
||||
----
|
||||
|
||||
query I
|
||||
SELECT count(i) FROM integers where j > 90 and i < 95
|
||||
----
|
||||
4
|
||||
|
||||
query I
|
||||
SELECT count(i) FROM integers where j > 90 and j < 95
|
||||
----
|
||||
4
|
||||
59
external/duckdb/test/sql/optimizer/plan/test_unused_column_after_join.test
vendored
Normal file
59
external/duckdb/test/sql/optimizer/plan/test_unused_column_after_join.test
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
# name: test/sql/optimizer/plan/test_unused_column_after_join.test
|
||||
# description: Test joins with various columns that are only used in the join
|
||||
# group: [plan]
|
||||
|
||||
statement ok
|
||||
PRAGMA enable_verification
|
||||
|
||||
# test columns that are only used in the join (i.e. can be projected out after the join)
|
||||
# create tables
|
||||
statement ok
|
||||
CREATE TABLE test (a INTEGER, b INTEGER);
|
||||
|
||||
statement ok
|
||||
INSERT INTO test VALUES (11, 1), (12, 2), (13, 3)
|
||||
|
||||
statement ok
|
||||
CREATE TABLE test2 (b INTEGER, c INTEGER);
|
||||
|
||||
statement ok
|
||||
INSERT INTO test2 VALUES (1, 10), (1, 20), (2, 30)
|
||||
|
||||
# count of single join
|
||||
query I
|
||||
SELECT COUNT(*) FROM test, test2 WHERE test.b = test2.b
|
||||
----
|
||||
3
|
||||
|
||||
# now a sum
|
||||
query RII
|
||||
SELECT SUM(test.a), MIN(test.a), MAX(test.a) FROM test, test2 WHERE test.b = test2.b
|
||||
----
|
||||
34.000000 11 12
|
||||
|
||||
# count of multi-way join
|
||||
query I
|
||||
SELECT COUNT(*) FROM test a1, test a2, test a3 WHERE a1.b=a2.b AND a2.b=a3.b
|
||||
----
|
||||
3
|
||||
|
||||
# now a sum
|
||||
query R
|
||||
SELECT SUM(a1.a) FROM test a1, test a2, test a3 WHERE a1.b=a2.b AND a2.b=a3.b
|
||||
----
|
||||
36.000000
|
||||
|
||||
# count of multi-way join with filters
|
||||
query I
|
||||
SELECT COUNT(*) FROM test a1, test a2, test a3 WHERE a1.b=a2.b AND a2.b=a3.b AND a1.a=11 AND a2.a=11 AND a3.a=11
|
||||
----
|
||||
1
|
||||
|
||||
# unused columns that become unused because of optimizer
|
||||
query T
|
||||
SELECT (TRUE OR a1.a=a2.b) FROM test a1, test a2 WHERE a1.a=11 AND a2.a>=10
|
||||
----
|
||||
1
|
||||
1
|
||||
1
|
||||
|
||||
Reference in New Issue
Block a user