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