if (expr_is_nonnullable(&subroot, expr, NOTNULL_SOURCE_CATALOG))
continue;
- if (IsA(expr, Var))
+ /* Note we can only prove things about this query's own Vars */
+ if (IsA(expr, Var) && ((Var *) expr)->varlevelsup == 0)
{
Var *var = (Var *) expr;
----+-----
(0 rows)
+-- No ANTI JOIN: the sub-select's output is an upper-level Var, so the
+-- sub-select's own quals tell us nothing about its nullability
+INSERT INTO null_tab VALUES (1, NULL);
+INSERT INTO not_null_tab VALUES (2, 2);
+EXPLAIN (COSTS OFF)
+SELECT * FROM null_tab t1
+WHERE COALESCE(t1.id, -1) NOT IN
+ (SELECT t1.val FROM not_null_tab t2 WHERE t2.val IS NOT NULL);
+ QUERY PLAN
+----------------------------------------------------------------------------
+ Seq Scan on null_tab t1
+ Filter: (NOT (ANY (COALESCE(id, '-1'::integer) = (SubPlan any_1).col1)))
+ SubPlan any_1
+ -> Seq Scan on not_null_tab t2
+(4 rows)
+
+-- NOT IN with NULL on inner side should return no rows
+SELECT * FROM null_tab t1
+WHERE COALESCE(t1.id, -1) NOT IN
+ (SELECT t1.val FROM not_null_tab t2 WHERE t2.val IS NOT NULL);
+ id | val
+----+-----
+(0 rows)
+
ROLLBACK;
SELECT * FROM not_null_tab
WHERE id NOT IN (SELECT id FROM notnull_notvalid_tab);
+-- No ANTI JOIN: the sub-select's output is an upper-level Var, so the
+-- sub-select's own quals tell us nothing about its nullability
+INSERT INTO null_tab VALUES (1, NULL);
+INSERT INTO not_null_tab VALUES (2, 2);
+
+EXPLAIN (COSTS OFF)
+SELECT * FROM null_tab t1
+WHERE COALESCE(t1.id, -1) NOT IN
+ (SELECT t1.val FROM not_null_tab t2 WHERE t2.val IS NOT NULL);
+
+-- NOT IN with NULL on inner side should return no rows
+SELECT * FROM null_tab t1
+WHERE COALESCE(t1.id, -1) NOT IN
+ (SELECT t1.val FROM not_null_tab t2 WHERE t2.val IS NOT NULL);
+
ROLLBACK;