diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index 9e271c3..85703b6 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -107,6 +107,10 @@ ExecRenameStmt(RenameStmt *stmt) RenameRole(stmt->subname, stmt->newname); break; + case OBJECT_RULE: + RenameRewriteRule(stmt->relation, stmt->subname, stmt->newname); + break; + case OBJECT_SCHEMA: RenameSchema(stmt->subname, stmt->newname); break; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index ad98b36..e993c5a 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -7028,6 +7028,16 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name n->missing_ok = false; $$ = (Node *)n; } + | ALTER RULE name ON any_name RENAME TO name + { + RenameStmt *n = makeNode(RenameStmt); + n->renameType = OBJECT_RULE; + n->relation = makeRangeVarFromAnyName($5, @5, yyscanner); + n->subname = $3; + n->newname = $8; + n->missing_ok = false; + $$ = (Node *)n; + } | ALTER USER RoleId RENAME TO RoleId { RenameStmt *n = makeNode(RenameStmt); diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c index 55b0fed..d8d0dd6 100644 --- a/src/backend/rewrite/rewriteDefine.c +++ b/src/backend/rewrite/rewriteDefine.c @@ -750,35 +750,55 @@ EnableDisableRule(Relation rel, const char *rulename, /* * Rename an existing rewrite rule. - * - * This is unused code at the moment. Note that it lacks a permissions check. */ -#ifdef NOT_USED void -RenameRewriteRule(Oid owningRel, const char *oldName, +RenameRewriteRule(RangeVar* relation, const char *oldName, const char *newName) { Relation pg_rewrite_desc; HeapTuple ruletup; + Oid owningRel; + + owningRel = RangeVarGetRelid(relation, AccessExclusiveLock, false); + + /* + * check if user has permission to rename rule on this relation. + */ + if (!pg_class_ownercheck(owningRel, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, + get_rel_name(owningRel)); pg_rewrite_desc = heap_open(RewriteRelationId, RowExclusiveLock); ruletup = SearchSysCacheCopy2(RULERELNAME, ObjectIdGetDatum(owningRel), PointerGetDatum(oldName)); + + /* old rule should already exist */ if (!HeapTupleIsValid(ruletup)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("rule \"%s\" for relation \"%s\" does not exist", oldName, get_rel_name(owningRel)))); - /* should not already exist */ + /* rule with the new name should not already exist */ if (IsDefinedRewriteRule(owningRel, newName)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("rule \"%s\" for relation \"%s\" already exists", newName, get_rel_name(owningRel)))); + /* ON SELECT rule must always be named "_RETURN" */ + if (((Form_pg_rewrite) GETSTRUCT(ruletup))->ev_type - '0' == CMD_SELECT) + { + if (strcmp(newName, ViewSelectRuleName) != 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("view rule for \"%s\" must be named \"%s\"", + get_rel_name(owningRel), + ViewSelectRuleName))); + } + namestrcpy(&(((Form_pg_rewrite) GETSTRUCT(ruletup))->rulename), newName); simple_heap_update(pg_rewrite_desc, &ruletup->t_self, ruletup); @@ -789,5 +809,3 @@ RenameRewriteRule(Oid owningRel, const char *oldName, heap_freetuple(ruletup); heap_close(pg_rewrite_desc, RowExclusiveLock); } - -#endif diff --git a/src/include/rewrite/rewriteDefine.h b/src/include/rewrite/rewriteDefine.h index 6061725..d7e0def 100644 --- a/src/include/rewrite/rewriteDefine.h +++ b/src/include/rewrite/rewriteDefine.h @@ -32,7 +32,7 @@ extern void DefineQueryRewrite(char *rulename, bool replace, List *action); -extern void RenameRewriteRule(Oid owningRel, const char *oldName, +extern void RenameRewriteRule(RangeVar* relation, const char *oldName, const char *newName); extern void setRuleCheckAsUser(Node *node, Oid userid);