Optimize BooleanTest with non-nullable input

The BooleanTest construct (IS [NOT] TRUE/FALSE/UNKNOWN) treats a NULL
input as the logical value "unknown".  However, when the input is
proven to be non-nullable, this special handling becomes redundant.
In such cases, the construct can be simplified directly to a boolean
expression or a constant.

Author: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: Tender Wang <tndrwang@gmail.com>
Discussion: https://postgr.es/m/CAMbWs49BMAOWvkdSHxpUDnniqJcEcGq3_8dd_5wTR4xrQY8urA@mail.gmail.com
This commit is contained in:
Richard Guo 2026-02-10 10:18:47 +09:00
parent 0a37961254
commit 0aaf0de7fe
3 changed files with 204 additions and 0 deletions

View file

@ -3686,6 +3686,9 @@ eval_const_expressions_mutator(Node *node,
context);
if (arg && IsA(arg, Const))
{
/*
* If arg is Const, simplify to constant.
*/
Const *carg = (Const *) arg;
bool result;
@ -3722,6 +3725,34 @@ eval_const_expressions_mutator(Node *node,
return makeBoolConst(result, false);
}
if (arg && expr_is_nonnullable(context->root, (Expr *) arg, false))
{
/*
* If arg is proven non-nullable, simplify to boolean
* expression or constant.
*/
switch (btest->booltesttype)
{
case IS_TRUE:
case IS_NOT_FALSE:
return arg;
case IS_FALSE:
case IS_NOT_TRUE:
return (Node *) make_notclause((Expr *) arg);
case IS_UNKNOWN:
return makeBoolConst(false, false);
case IS_NOT_UNKNOWN:
return makeBoolConst(true, false);
default:
elog(ERROR, "unrecognized booltesttype: %d",
(int) btest->booltesttype);
break;
}
}
newbtest = makeNode(BooleanTest);
newbtest->arg = (Expr *) arg;

View file

@ -768,3 +768,122 @@ SELECT * FROM dist_tab t1 JOIN dist_tab t2 ON t1.val_nn IS NOT DISTINCT FROM t2.
RESET enable_nestloop;
DROP TABLE dist_tab;
DROP TYPE dist_row_t;
--
-- Test optimization of BooleanTest (IS [NOT] TRUE/FALSE/UNKNOWN) on
-- non-nullable input
--
CREATE TABLE bool_tab (id int, flag_nn boolean NOT NULL, flag_null boolean);
INSERT INTO bool_tab VALUES (1, true, true);
INSERT INTO bool_tab VALUES (2, false, NULL);
CREATE INDEX bool_tab_nn_idx ON bool_tab (flag_nn);
ANALYZE bool_tab;
-- Ensure that the predicate folds to constant FALSE
EXPLAIN (COSTS OFF)
SELECT id FROM bool_tab WHERE flag_nn IS UNKNOWN;
QUERY PLAN
------------------------------
Result
Replaces: Scan on bool_tab
One-Time Filter: false
(3 rows)
SELECT id FROM bool_tab WHERE flag_nn IS UNKNOWN;
id
----
(0 rows)
-- Ensure that the predicate folds to constant TRUE
EXPLAIN (COSTS OFF)
SELECT id FROM bool_tab WHERE flag_nn IS NOT UNKNOWN;
QUERY PLAN
----------------------
Seq Scan on bool_tab
(1 row)
SELECT id FROM bool_tab WHERE flag_nn IS NOT UNKNOWN;
id
----
1
2
(2 rows)
-- Ensure that the predicate folds to flag_nn
EXPLAIN (COSTS OFF)
SELECT id FROM bool_tab WHERE flag_nn IS TRUE;
QUERY PLAN
----------------------
Seq Scan on bool_tab
Filter: flag_nn
(2 rows)
SELECT id FROM bool_tab WHERE flag_nn IS TRUE;
id
----
1
(1 row)
-- Ensure that the predicate folds to flag_nn, and thus can use index scan
SET enable_seqscan TO off;
EXPLAIN (COSTS OFF)
SELECT id FROM bool_tab WHERE flag_nn IS NOT FALSE;
QUERY PLAN
----------------------------------------------
Index Scan using bool_tab_nn_idx on bool_tab
Index Cond: (flag_nn = true)
(2 rows)
SELECT id FROM bool_tab WHERE flag_nn IS NOT FALSE;
id
----
1
(1 row)
RESET enable_seqscan;
-- Ensure that the predicate folds to not flag_nn
EXPLAIN (COSTS OFF)
SELECT id FROM bool_tab WHERE flag_nn IS FALSE;
QUERY PLAN
-------------------------
Seq Scan on bool_tab
Filter: (NOT flag_nn)
(2 rows)
SELECT id FROM bool_tab WHERE flag_nn IS FALSE;
id
----
2
(1 row)
-- Ensure that the predicate folds to not flag_nn, and thus can use index scan
SET enable_seqscan TO off;
EXPLAIN (COSTS OFF)
SELECT id FROM bool_tab WHERE flag_nn IS NOT TRUE;
QUERY PLAN
----------------------------------------------
Index Scan using bool_tab_nn_idx on bool_tab
Index Cond: (flag_nn = false)
(2 rows)
SELECT id FROM bool_tab WHERE flag_nn IS NOT TRUE;
id
----
2
(1 row)
RESET enable_seqscan;
-- Ensure that the predicate is preserved as a BooleanTest
EXPLAIN (COSTS OFF)
SELECT id FROM bool_tab WHERE flag_null IS UNKNOWN;
QUERY PLAN
----------------------------------
Seq Scan on bool_tab
Filter: (flag_null IS UNKNOWN)
(2 rows)
SELECT id FROM bool_tab WHERE flag_null IS UNKNOWN;
id
----
2
(1 row)
DROP TABLE bool_tab;

View file

@ -369,3 +369,57 @@ RESET enable_nestloop;
DROP TABLE dist_tab;
DROP TYPE dist_row_t;
--
-- Test optimization of BooleanTest (IS [NOT] TRUE/FALSE/UNKNOWN) on
-- non-nullable input
--
CREATE TABLE bool_tab (id int, flag_nn boolean NOT NULL, flag_null boolean);
INSERT INTO bool_tab VALUES (1, true, true);
INSERT INTO bool_tab VALUES (2, false, NULL);
CREATE INDEX bool_tab_nn_idx ON bool_tab (flag_nn);
ANALYZE bool_tab;
-- Ensure that the predicate folds to constant FALSE
EXPLAIN (COSTS OFF)
SELECT id FROM bool_tab WHERE flag_nn IS UNKNOWN;
SELECT id FROM bool_tab WHERE flag_nn IS UNKNOWN;
-- Ensure that the predicate folds to constant TRUE
EXPLAIN (COSTS OFF)
SELECT id FROM bool_tab WHERE flag_nn IS NOT UNKNOWN;
SELECT id FROM bool_tab WHERE flag_nn IS NOT UNKNOWN;
-- Ensure that the predicate folds to flag_nn
EXPLAIN (COSTS OFF)
SELECT id FROM bool_tab WHERE flag_nn IS TRUE;
SELECT id FROM bool_tab WHERE flag_nn IS TRUE;
-- Ensure that the predicate folds to flag_nn, and thus can use index scan
SET enable_seqscan TO off;
EXPLAIN (COSTS OFF)
SELECT id FROM bool_tab WHERE flag_nn IS NOT FALSE;
SELECT id FROM bool_tab WHERE flag_nn IS NOT FALSE;
RESET enable_seqscan;
-- Ensure that the predicate folds to not flag_nn
EXPLAIN (COSTS OFF)
SELECT id FROM bool_tab WHERE flag_nn IS FALSE;
SELECT id FROM bool_tab WHERE flag_nn IS FALSE;
-- Ensure that the predicate folds to not flag_nn, and thus can use index scan
SET enable_seqscan TO off;
EXPLAIN (COSTS OFF)
SELECT id FROM bool_tab WHERE flag_nn IS NOT TRUE;
SELECT id FROM bool_tab WHERE flag_nn IS NOT TRUE;
RESET enable_seqscan;
-- Ensure that the predicate is preserved as a BooleanTest
EXPLAIN (COSTS OFF)
SELECT id FROM bool_tab WHERE flag_null IS UNKNOWN;
SELECT id FROM bool_tab WHERE flag_null IS UNKNOWN;
DROP TABLE bool_tab;