While playing around with rules and MERGE, I noticed that there is a
bug in the way that it detects whether the target table has rules ---
it uses rd_rel->relhasrules, which can be incorrect, since it might be
set for a table that doesn't currently have rules, but did in the
recent past.
So it actually needs to examine rd_rules. Technically, I think that it
would be sufficient to just test whether rd_rules is non-NULL, but I
think it's more robust and readable to check rd_rules->numLocks, as in
the attached patch.
Regards,
Dean
diff --git a/src/backend/parser/parse_merge.c b/src/backend/parser/parse_merge.c
new file mode 100644
index 7913523..62c2ff6
--- a/src/backend/parser/parse_merge.c
+++ b/src/backend/parser/parse_merge.c
@@ -182,7 +182,8 @@ transformMergeStmt(ParseState *pstate, M
errmsg("cannot execute MERGE on relation \"%s\"",
RelationGetRelationName(pstate->p_target_relation)),
errdetail_relkind_not_supported(pstate->p_target_relation->rd_rel->relkind)));
- if (pstate->p_target_relation->rd_rel->relhasrules)
+ if (pstate->p_target_relation->rd_rules != NULL &&
+ pstate->p_target_relation->rd_rules->numLocks > 0)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot execute MERGE on relation \"%s\"",
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
new file mode 100644
index 624d0e5..ad1a8c9
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -3532,6 +3532,30 @@ MERGE INTO rule_merge2 t USING (SELECT 1
DELETE
WHEN NOT MATCHED THEN
INSERT VALUES (s.a, '');
+SELECT * FROM rule_merge2;
+ a | b
+---+---
+ 1 |
+(1 row)
+
+-- and should be ok after dropping rules
+DROP RULE rule1 ON rule_merge1;
+DROP RULE rule2 ON rule_merge1;
+DROP RULE rule3 ON rule_merge1;
+MERGE INTO rule_merge1 t USING (SELECT 1 AS a) s
+ ON t.a = s.a
+ WHEN MATCHED AND t.a < 2 THEN
+ UPDATE SET b = b || ' updated by merge, had rules'
+ WHEN MATCHED AND t.a > 2 THEN
+ DELETE
+ WHEN NOT MATCHED THEN
+ INSERT VALUES (s.a, 'had rules');
+SELECT * FROM rule_merge1;
+ a | b
+---+-----------
+ 1 | had rules
+(1 row)
+
--
-- Test enabling/disabling
--
diff --git a/src/test/regress/sql/rules.sql b/src/test/regress/sql/rules.sql
new file mode 100644
index bfb5f3b..8a728be
--- a/src/test/regress/sql/rules.sql
+++ b/src/test/regress/sql/rules.sql
@@ -1264,6 +1264,21 @@ MERGE INTO rule_merge2 t USING (SELECT 1
DELETE
WHEN NOT MATCHED THEN
INSERT VALUES (s.a, '');
+SELECT * FROM rule_merge2;
+
+-- and should be ok after dropping rules
+DROP RULE rule1 ON rule_merge1;
+DROP RULE rule2 ON rule_merge1;
+DROP RULE rule3 ON rule_merge1;
+MERGE INTO rule_merge1 t USING (SELECT 1 AS a) s
+ ON t.a = s.a
+ WHEN MATCHED AND t.a < 2 THEN
+ UPDATE SET b = b || ' updated by merge, had rules'
+ WHEN MATCHED AND t.a > 2 THEN
+ DELETE
+ WHEN NOT MATCHED THEN
+ INSERT VALUES (s.a, 'had rules');
+SELECT * FROM rule_merge1;
--
-- Test enabling/disabling