Files
email-tracker/external/duckdb/test/optimizer/statistics/statistics_is_null.test
2025-10-24 19:21:19 -05:00

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