if (!bms_is_empty(var->varnullingrels))
return false;
+ /*
+ * If the Var has a non-default returning type, it could be NULL
+ * regardless of any NOT NULL constraint. For example, OLD.col is NULL
+ * for INSERT, and NEW.col is NULL for DELETE.
+ */
+ if (var->varreturningtype != VAR_RETURNING_DEFAULT)
+ return false;
+
/* system columns cannot be NULL */
if (var->varattno < 0)
return true;
WHERE (foo_1.* = n.*)) AS count;
END
DROP FUNCTION foo_update;
+-- Test that the planner does not fold OLD/NEW IS NULL tests to constants
+-- based on NOT NULL constraints, since OLD is NULL for INSERT and NEW is
+-- NULL for DELETE.
+CREATE TEMP TABLE ret_nn (a int NOT NULL);
+-- INSERT has no OLD row, should return true
+INSERT INTO ret_nn VALUES (1) RETURNING old.a IS NULL;
+ ?column?
+----------
+ t
+(1 row)
+
+-- DELETE has no NEW row, should return true
+DELETE FROM ret_nn WHERE a = 1 RETURNING new.a IS NULL;
+ ?column?
+----------
+ t
+(1 row)
+
+-- MERGE: DELETE should have new.a IS NULL, INSERT should have old.a IS NULL
+INSERT INTO ret_nn VALUES (2);
+MERGE INTO ret_nn USING (VALUES (2), (3)) AS src(a) ON ret_nn.a = src.a
+ WHEN MATCHED THEN DELETE
+ WHEN NOT MATCHED THEN INSERT VALUES (src.a)
+ RETURNING merge_action(), old.a IS NULL, new.a IS NULL;
+ merge_action | ?column? | ?column?
+--------------+----------+----------
+ DELETE | f | t
+ INSERT | t | f
+(2 rows)
+
+DROP TABLE ret_nn;
\sf foo_update
DROP FUNCTION foo_update;
+
+-- Test that the planner does not fold OLD/NEW IS NULL tests to constants
+-- based on NOT NULL constraints, since OLD is NULL for INSERT and NEW is
+-- NULL for DELETE.
+CREATE TEMP TABLE ret_nn (a int NOT NULL);
+
+-- INSERT has no OLD row, should return true
+INSERT INTO ret_nn VALUES (1) RETURNING old.a IS NULL;
+
+-- DELETE has no NEW row, should return true
+DELETE FROM ret_nn WHERE a = 1 RETURNING new.a IS NULL;
+
+-- MERGE: DELETE should have new.a IS NULL, INSERT should have old.a IS NULL
+INSERT INTO ret_nn VALUES (2);
+MERGE INTO ret_nn USING (VALUES (2), (3)) AS src(a) ON ret_nn.a = src.a
+ WHEN MATCHED THEN DELETE
+ WHEN NOT MATCHED THEN INSERT VALUES (src.a)
+ RETURNING merge_action(), old.a IS NULL, new.a IS NULL;
+
+DROP TABLE ret_nn;