140 lines
2.8 KiB
SQL
140 lines
2.8 KiB
SQL
# name: test/optimizer/statistics/statistics_is_null.test
|
|
# description: Test filter propagation in IS NULL/IS NOT NULL operands
|
|
# group: [statistics]
|
|
|
|
statement ok
|
|
SET default_null_order='nulls_first';
|
|
|
|
statement ok
|
|
CREATE TABLE integers AS SELECT * FROM (VALUES (1), (2), (3)) tbl(i);
|
|
|
|
statement ok
|
|
CREATE TABLE integers2 AS SELECT * FROM (VALUES (4), (5), (NULL)) tbl(i);
|
|
|
|
statement ok
|
|
PRAGMA explain_output = OPTIMIZED_ONLY;
|
|
|
|
# we can statically determine IS NULL/IS NOT NULL are false, if there are no null values for this column
|
|
query II
|
|
EXPLAIN SELECT i IS NULL FROM integers;
|
|
----
|
|
logical_opt <!REGEX>:.*IS NULL.*
|
|
|
|
query II
|
|
EXPLAIN SELECT i IS NOT NULL FROM integers;
|
|
----
|
|
logical_opt <!REGEX>:.*IS NOT NULL.*
|
|
|
|
# if there are null values, however, we have to execute the operator
|
|
query II
|
|
EXPLAIN SELECT i IS NULL FROM integers2;
|
|
----
|
|
logical_opt <REGEX>:.*IS NULL.*
|
|
|
|
query II
|
|
EXPLAIN SELECT i IS NOT NULL FROM integers2;
|
|
----
|
|
logical_opt <REGEX>:.*IS NOT NULL.*
|
|
|
|
# filters remove null values, so even if the base column contains null values, we don't need to check IS NULL here
|
|
query II
|
|
EXPLAIN SELECT i IS NULL FROM integers2 WHERE i>0;
|
|
----
|
|
logical_opt <!REGEX>:.*IS NULL.*
|
|
|
|
# left/right outer joins with false condition can convert to cross product with constant NULL value,
|
|
# so we don't need to check IS NULL here, since it's always NULL
|
|
query II
|
|
EXPLAIN SELECT i2.i IS NULL FROM integers i1 LEFT JOIN integers i2 ON (false);
|
|
----
|
|
logical_opt <!REGEX>:.*IS NULL.*
|
|
|
|
# full outer joins can introduce nulls, even if the base tables do not contain them
|
|
query II
|
|
EXPLAIN SELECT i1.i IS NULL FROM integers i1 FULL OUTER JOIN integers i2 ON (false);
|
|
----
|
|
logical_opt <REGEX>:.*IS NULL.*
|
|
|
|
# verify that all these queries produce the correct results
|
|
query I
|
|
SELECT i IS NULL FROM integers;
|
|
----
|
|
0
|
|
0
|
|
0
|
|
|
|
query I
|
|
SELECT i IS NOT NULL FROM integers;
|
|
----
|
|
1
|
|
1
|
|
1
|
|
|
|
query I
|
|
SELECT i IS NULL FROM integers2;
|
|
----
|
|
0
|
|
0
|
|
1
|
|
|
|
query I
|
|
SELECT i IS NOT NULL FROM integers2;
|
|
----
|
|
1
|
|
1
|
|
0
|
|
|
|
query I
|
|
SELECT i IS NULL FROM integers2 WHERE i>0;
|
|
----
|
|
0
|
|
0
|
|
|
|
query I
|
|
SELECT i2.i IS NULL FROM integers i1 LEFT JOIN integers i2 ON (false);
|
|
----
|
|
1
|
|
1
|
|
1
|
|
|
|
query I
|
|
SELECT i1.i IS NULL FROM integers i1 FULL OUTER JOIN integers i2 ON (false) ORDER BY i1.i;
|
|
----
|
|
1
|
|
1
|
|
1
|
|
0
|
|
0
|
|
0
|
|
|
|
# FIXME: we don't yet correctly track when columns don't contain valid values
|
|
mode skip
|
|
|
|
statement ok
|
|
CREATE TABLE integers3 AS SELECT * FROM (VALUES (NULL), (NULL), (NULL)) tbl(i);
|
|
|
|
# we can statically determine IS NULL/IS NOT NULL are true, if there are no valid values for this column
|
|
query II
|
|
EXPLAIN SELECT i IS NULL FROM integers3;
|
|
----
|
|
logical_opt <!REGEX>:.*IS NULL.*
|
|
|
|
query II
|
|
EXPLAIN SELECT i IS NOT NULL FROM integers3;
|
|
----
|
|
logical_opt <!REGEX>:.*IS NOT NULL.*
|
|
|
|
query I
|
|
SELECT i IS NULL FROM integers3;
|
|
----
|
|
true
|
|
true
|
|
true
|
|
|
|
query I
|
|
SELECT i IS NOT NULL FROM integers3;
|
|
----
|
|
false
|
|
false
|
|
false
|