context);
/*
- * We can remove null constants from the list. For a
- * non-null constant, if it has not been preceded by any
- * other non-null-constant expressions then it is the
- * result. Otherwise, it's the next argument, but we can
+ * We can remove null constants from the list. For a
+ * nonnullable expression, if it has not been preceded by
+ * any non-null-constant expressions then it is the
+ * result. Otherwise, it's the next argument, but we can
* drop following arguments since they will never be
* reached.
*/
newargs = lappend(newargs, e);
break;
}
+ if (expr_is_nonnullable(context->root, (Expr *) e, false))
+ {
+ if (newargs == NIL)
+ return e; /* first expr */
+ newargs = lappend(newargs, e);
+ break;
+ }
+
newargs = lappend(newargs, e);
}
bool
expr_is_nonnullable(PlannerInfo *root, Expr *expr, bool use_rel_info)
{
- if (IsA(expr, Var))
+ if (IsA(expr, Var) && root)
return var_is_nonnullable(root, (Var *) expr, use_rel_info);
if (IsA(expr, Const))
return !castNode(Const, expr)->constisnull;
a int primary key,
b int generated always as (a * 2),
c int generated always as (10 + 10),
- d int generated always as (coalesce(a, 100)),
- e int
+ d int generated always as (coalesce(f, 100)),
+ e int,
+ f int
);
-insert into gtest32 values (1), (2);
+insert into gtest32 (a, f) values (1, 1), (2, 2);
analyze gtest32;
-- Ensure that nullingrel bits are propagated into the generation expressions
explain (costs off)
-- Ensure that the generation expressions are wrapped into PHVs if needed
explain (verbose, costs off)
select t2.* from gtest32 t1 left join gtest32 t2 on false;
- QUERY PLAN
----------------------------------------------------------------
+ QUERY PLAN
+---------------------------------------------------------------------
Nested Loop Left Join
- Output: t2.a, (t2.a * 2), (20), (COALESCE(t2.a, 100)), t2.e
+ Output: t2.a, (t2.a * 2), (20), (COALESCE(t2.f, 100)), t2.e, t2.f
Join Filter: false
-> Seq Scan on generated_virtual_tests.gtest32 t1
- Output: t1.a, t1.b, t1.c, t1.d, t1.e
+ Output: t1.a, t1.b, t1.c, t1.d, t1.e, t1.f
-> Result
- Output: t2.a, t2.e, 20, COALESCE(t2.a, 100)
+ Output: t2.a, t2.e, t2.f, 20, COALESCE(t2.f, 100)
Replaces: Scan on t2
One-Time Filter: false
(9 rows)
select t2.* from gtest32 t1 left join gtest32 t2 on false;
- a | b | c | d | e
----+---+---+---+---
- | | | |
- | | | |
+ a | b | c | d | e | f
+---+---+---+---+---+---
+ | | | | |
+ | | | | |
(2 rows)
explain (verbose, costs off)
-select * from gtest32 t group by grouping sets (a, b, c, d, e) having c = 20;
- QUERY PLAN
------------------------------------------------------
+select * from gtest32 t group by grouping sets (a, b, c, d, e, f) having c = 20;
+ QUERY PLAN
+--------------------------------------------------------
HashAggregate
- Output: a, ((a * 2)), (20), (COALESCE(a, 100)), e
+ Output: a, ((a * 2)), (20), (COALESCE(f, 100)), e, f
Hash Key: t.a
Hash Key: (t.a * 2)
Hash Key: 20
- Hash Key: COALESCE(t.a, 100)
+ Hash Key: COALESCE(t.f, 100)
Hash Key: t.e
+ Hash Key: t.f
Filter: ((20) = 20)
-> Seq Scan on generated_virtual_tests.gtest32 t
- Output: a, (a * 2), 20, COALESCE(a, 100), e
-(10 rows)
+ Output: a, (a * 2), 20, COALESCE(f, 100), e, f
+(11 rows)
-select * from gtest32 t group by grouping sets (a, b, c, d, e) having c = 20;
- a | b | c | d | e
----+---+----+---+---
- | | 20 | |
+select * from gtest32 t group by grouping sets (a, b, c, d, e, f) having c = 20;
+ a | b | c | d | e | f
+---+---+----+---+---+---
+ | | 20 | | |
(1 row)
-- Ensure that the virtual generated columns in ALTER COLUMN TYPE USING expression are expanded
(2 rows)
DROP TABLE pred_tab;
+--
+-- Test that COALESCE expressions in predicates are simplified using
+-- non-nullable arguments.
+--
+CREATE TABLE pred_tab (a int NOT NULL, b int);
+-- Ensure that constant NULL arguments are dropped
+EXPLAIN (COSTS OFF)
+SELECT * FROM pred_tab WHERE COALESCE(NULL, b, NULL, a) > 1;
+ QUERY PLAN
+--------------------------------
+ Seq Scan on pred_tab
+ Filter: (COALESCE(b, a) > 1)
+(2 rows)
+
+-- Ensure that argument "b*a" is dropped
+EXPLAIN (COSTS OFF)
+SELECT * FROM pred_tab WHERE COALESCE(b, a, b*a) > 1;
+ QUERY PLAN
+--------------------------------
+ Seq Scan on pred_tab
+ Filter: (COALESCE(b, a) > 1)
+(2 rows)
+
+-- Ensure that the entire COALESCE expression is replaced by "a"
+EXPLAIN (COSTS OFF)
+SELECT * FROM pred_tab WHERE COALESCE(a, b) > 1;
+ QUERY PLAN
+----------------------
+ Seq Scan on pred_tab
+ Filter: (a > 1)
+(2 rows)
+
+DROP TABLE pred_tab;
a int primary key,
b int generated always as (a * 2),
c int generated always as (10 + 10),
- d int generated always as (coalesce(a, 100)),
- e int
+ d int generated always as (coalesce(f, 100)),
+ e int,
+ f int
);
-insert into gtest32 values (1), (2);
+insert into gtest32 (a, f) values (1, 1), (2, 2);
analyze gtest32;
-- Ensure that nullingrel bits are propagated into the generation expressions
select t2.* from gtest32 t1 left join gtest32 t2 on false;
explain (verbose, costs off)
-select * from gtest32 t group by grouping sets (a, b, c, d, e) having c = 20;
-select * from gtest32 t group by grouping sets (a, b, c, d, e) having c = 20;
+select * from gtest32 t group by grouping sets (a, b, c, d, e, f) having c = 20;
+select * from gtest32 t group by grouping sets (a, b, c, d, e, f) having c = 20;
-- Ensure that the virtual generated columns in ALTER COLUMN TYPE USING expression are expanded
alter table gtest32 alter column e type bigint using b;
SELECT * FROM pred_tab WHERE a < 3 AND b IS NOT NULL AND c IS NOT NULL;
DROP TABLE pred_tab;
+
+--
+-- Test that COALESCE expressions in predicates are simplified using
+-- non-nullable arguments.
+--
+CREATE TABLE pred_tab (a int NOT NULL, b int);
+
+-- Ensure that constant NULL arguments are dropped
+EXPLAIN (COSTS OFF)
+SELECT * FROM pred_tab WHERE COALESCE(NULL, b, NULL, a) > 1;
+
+-- Ensure that argument "b*a" is dropped
+EXPLAIN (COSTS OFF)
+SELECT * FROM pred_tab WHERE COALESCE(b, a, b*a) > 1;
+
+-- Ensure that the entire COALESCE expression is replaced by "a"
+EXPLAIN (COSTS OFF)
+SELECT * FROM pred_tab WHERE COALESCE(a, b) > 1;
+
+DROP TABLE pred_tab;