Skip to content

Commit c61e26e

Browse files
committed
Add support for ALTER RULE ... RENAME TO.
Ali Dar, reviewed by Dean Rasheed.
1 parent f806c19 commit c61e26e

File tree

12 files changed

+322
-16
lines changed

12 files changed

+322
-16
lines changed

doc/src/sgml/ref/allfiles.sgml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Complete list of usable sgml source files in this directory.
2525
<!ENTITY alterOperatorClass SYSTEM "alter_opclass.sgml">
2626
<!ENTITY alterOperatorFamily SYSTEM "alter_opfamily.sgml">
2727
<!ENTITY alterRole SYSTEM "alter_role.sgml">
28+
<!ENTITY alterRule SYSTEM "alter_rule.sgml">
2829
<!ENTITY alterSchema SYSTEM "alter_schema.sgml">
2930
<!ENTITY alterServer SYSTEM "alter_server.sgml">
3031
<!ENTITY alterSequence SYSTEM "alter_sequence.sgml">

doc/src/sgml/ref/alter_rule.sgml

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<!--
2+
doc/src/sgml/ref/alter_rule.sgml
3+
PostgreSQL documentation
4+
-->
5+
6+
<refentry id="SQL-ALTERRULE">
7+
<refmeta>
8+
<refentrytitle>ALTER RULE</refentrytitle>
9+
<manvolnum>7</manvolnum>
10+
<refmiscinfo>SQL - Language Statements</refmiscinfo>
11+
</refmeta>
12+
13+
<refnamediv>
14+
<refname>ALTER RULE</refname>
15+
<refpurpose>change the definition of a rule</refpurpose>
16+
</refnamediv>
17+
18+
<indexterm zone="sql-alterrule">
19+
<primary>ALTER RULE</primary>
20+
</indexterm>
21+
22+
<refsynopsisdiv>
23+
<synopsis>
24+
ALTER RULE <replaceable class="PARAMETER">name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> RENAME TO <replaceable class="PARAMETER">new_name</replaceable>
25+
</synopsis>
26+
</refsynopsisdiv>
27+
28+
<refsect1>
29+
<title>Description</title>
30+
31+
<para>
32+
<command>ALTER RULE</command> changes properties of an existing
33+
rule. Currently, the only available action is to change the rule's name.
34+
</para>
35+
36+
<para>
37+
To use <command>ALTER RULE</command>, you must own the table or view that
38+
the rule applies to.
39+
</para>
40+
</refsect1>
41+
42+
<refsect1>
43+
<title>Parameters</title>
44+
45+
<variablelist>
46+
<varlistentry>
47+
<term><replaceable class="PARAMETER">name</replaceable></term>
48+
<listitem>
49+
<para>
50+
The name of an existing rule to alter.
51+
</para>
52+
</listitem>
53+
</varlistentry>
54+
55+
<varlistentry>
56+
<term><replaceable class="PARAMETER">table_name</replaceable></term>
57+
<listitem>
58+
<para>
59+
The name (optionally schema-qualified) of the table or view that the
60+
rule applies to.
61+
</para>
62+
</listitem>
63+
</varlistentry>
64+
65+
<varlistentry>
66+
<term><replaceable class="PARAMETER">new_name</replaceable></term>
67+
<listitem>
68+
<para>
69+
The new name for the rule.
70+
</para>
71+
</listitem>
72+
</varlistentry>
73+
</variablelist>
74+
</refsect1>
75+
76+
<refsect1>
77+
<title>Examples</title>
78+
79+
<para>
80+
To rename an existing rule:
81+
<programlisting>
82+
ALTER RULE notify_all ON emp RENAME TO notify_me;
83+
</programlisting></para>
84+
</refsect1>
85+
86+
<refsect1>
87+
<title>Compatibility</title>
88+
89+
<para>
90+
<command>ALTER RULE</command> is a
91+
<productname>PostgreSQL</productname> language extension, as is the
92+
entire query rewrite system.
93+
</para>
94+
</refsect1>
95+
96+
<refsect1>
97+
<title>See Also</title>
98+
99+
<simplelist type="inline">
100+
<member><xref linkend="sql-createrule"></member>
101+
<member><xref linkend="sql-droprule"></member>
102+
</simplelist>
103+
</refsect1>
104+
105+
</refentry>

doc/src/sgml/ref/create_rule.sgml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,4 +284,14 @@ UPDATE mytable SET name = 'foo' WHERE id = 42;
284284
entire query rewrite system.
285285
</para>
286286
</refsect1>
287+
288+
<refsect1>
289+
<title>See Also</title>
290+
291+
<simplelist type="inline">
292+
<member><xref linkend="sql-alterrule"></member>
293+
<member><xref linkend="sql-droprule"></member>
294+
</simplelist>
295+
</refsect1>
296+
287297
</refentry>

doc/src/sgml/ref/drop_rule.sgml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,9 @@ DROP RULE newrule ON mytable;
103103
<title>Compatibility</title>
104104

105105
<para>
106-
There is no <command>DROP RULE</command> statement in the SQL standard.
106+
<command>DROP RULE</command> is a
107+
<productname>PostgreSQL</productname> language extension, as is the
108+
entire query rewrite system.
107109
</para>
108110
</refsect1>
109111

@@ -112,6 +114,7 @@ DROP RULE newrule ON mytable;
112114

113115
<simplelist type="inline">
114116
<member><xref linkend="sql-createrule"></member>
117+
<member><xref linkend="sql-alterrule"></member>
115118
</simplelist>
116119
</refsect1>
117120

doc/src/sgml/reference.sgml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
&alterOperatorClass;
5454
&alterOperatorFamily;
5555
&alterRole;
56+
&alterRule;
5657
&alterSchema;
5758
&alterSequence;
5859
&alterServer;

src/backend/commands/alter.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#include "commands/user.h"
5252
#include "parser/parse_func.h"
5353
#include "miscadmin.h"
54+
#include "rewrite/rewriteDefine.h"
5455
#include "tcop/utility.h"
5556
#include "utils/builtins.h"
5657
#include "utils/fmgroids.h"
@@ -324,6 +325,10 @@ ExecRenameStmt(RenameStmt *stmt)
324325
case OBJECT_ATTRIBUTE:
325326
return renameatt(stmt);
326327

328+
case OBJECT_RULE:
329+
return RenameRewriteRule(stmt->relation, stmt->subname,
330+
stmt->newname);
331+
327332
case OBJECT_TRIGGER:
328333
return renametrig(stmt);
329334

src/backend/parser/gram.y

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7003,6 +7003,16 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
70037003
n->missing_ok = true;
70047004
$$ = (Node *)n;
70057005
}
7006+
| ALTER RULE name ON qualified_name RENAME TO name
7007+
{
7008+
RenameStmt *n = makeNode(RenameStmt);
7009+
n->renameType = OBJECT_RULE;
7010+
n->relation = $5;
7011+
n->subname = $3;
7012+
n->newname = $8;
7013+
n->missing_ok = false;
7014+
$$ = (Node *)n;
7015+
}
70067016
| ALTER TRIGGER name ON qualified_name RENAME TO name
70077017
{
70087018
RenameStmt *n = makeNode(RenameStmt);

src/backend/rewrite/rewriteDefine.c

Lines changed: 86 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -751,38 +751,99 @@ EnableDisableRule(Relation rel, const char *rulename,
751751
}
752752

753753

754+
/*
755+
* Perform permissions and integrity checks before acquiring a relation lock.
756+
*/
757+
static void
758+
RangeVarCallbackForRenameRule(const RangeVar *rv, Oid relid, Oid oldrelid,
759+
void *arg)
760+
{
761+
HeapTuple tuple;
762+
Form_pg_class form;
763+
764+
tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
765+
if (!HeapTupleIsValid(tuple))
766+
return; /* concurrently dropped */
767+
form = (Form_pg_class) GETSTRUCT(tuple);
768+
769+
/* only tables and views can have rules */
770+
if (form->relkind != RELKIND_RELATION && form->relkind != RELKIND_VIEW)
771+
ereport(ERROR,
772+
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
773+
errmsg("\"%s\" is not a table or view", rv->relname)));
774+
775+
if (!allowSystemTableMods && IsSystemClass(form))
776+
ereport(ERROR,
777+
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
778+
errmsg("permission denied: \"%s\" is a system catalog",
779+
rv->relname)));
780+
781+
/* you must own the table to rename one of its rules */
782+
if (!pg_class_ownercheck(relid, GetUserId()))
783+
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, rv->relname);
784+
785+
ReleaseSysCache(tuple);
786+
}
787+
754788
/*
755789
* Rename an existing rewrite rule.
756-
*
757-
* This is unused code at the moment. Note that it lacks a permissions check.
758790
*/
759-
#ifdef NOT_USED
760-
void
761-
RenameRewriteRule(Oid owningRel, const char *oldName,
791+
Oid
792+
RenameRewriteRule(RangeVar *relation, const char *oldName,
762793
const char *newName)
763794
{
795+
Oid relid;
796+
Relation targetrel;
764797
Relation pg_rewrite_desc;
765798
HeapTuple ruletup;
799+
Form_pg_rewrite ruleform;
800+
Oid ruleOid;
766801

802+
/*
803+
* Look up name, check permissions, and acquire lock (which we will NOT
804+
* release until end of transaction).
805+
*/
806+
relid = RangeVarGetRelidExtended(relation, AccessExclusiveLock,
807+
false, false,
808+
RangeVarCallbackForRenameRule,
809+
NULL);
810+
811+
/* Have lock already, so just need to build relcache entry. */
812+
targetrel = relation_open(relid, NoLock);
813+
814+
/* Prepare to modify pg_rewrite */
767815
pg_rewrite_desc = heap_open(RewriteRelationId, RowExclusiveLock);
768816

817+
/* Fetch the rule's entry (it had better exist) */
769818
ruletup = SearchSysCacheCopy2(RULERELNAME,
770-
ObjectIdGetDatum(owningRel),
819+
ObjectIdGetDatum(relid),
771820
PointerGetDatum(oldName));
772821
if (!HeapTupleIsValid(ruletup))
773822
ereport(ERROR,
774823
(errcode(ERRCODE_UNDEFINED_OBJECT),
775824
errmsg("rule \"%s\" for relation \"%s\" does not exist",
776-
oldName, get_rel_name(owningRel))));
825+
oldName, RelationGetRelationName(targetrel))));
826+
ruleform = (Form_pg_rewrite) GETSTRUCT(ruletup);
827+
ruleOid = HeapTupleGetOid(ruletup);
777828

778-
/* should not already exist */
779-
if (IsDefinedRewriteRule(owningRel, newName))
829+
/* rule with the new name should not already exist */
830+
if (IsDefinedRewriteRule(relid, newName))
780831
ereport(ERROR,
781832
(errcode(ERRCODE_DUPLICATE_OBJECT),
782833
errmsg("rule \"%s\" for relation \"%s\" already exists",
783-
newName, get_rel_name(owningRel))));
834+
newName, RelationGetRelationName(targetrel))));
835+
836+
/*
837+
* We disallow renaming ON SELECT rules, because they should always be
838+
* named "_RETURN".
839+
*/
840+
if (ruleform->ev_type == CMD_SELECT + '0')
841+
ereport(ERROR,
842+
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
843+
errmsg("renaming an ON SELECT rule is not allowed")));
784844

785-
namestrcpy(&(((Form_pg_rewrite) GETSTRUCT(ruletup))->rulename), newName);
845+
/* OK, do the update */
846+
namestrcpy(&(ruleform->rulename), newName);
786847

787848
simple_heap_update(pg_rewrite_desc, &ruletup->t_self, ruletup);
788849

@@ -791,6 +852,18 @@ RenameRewriteRule(Oid owningRel, const char *oldName,
791852

792853
heap_freetuple(ruletup);
793854
heap_close(pg_rewrite_desc, RowExclusiveLock);
794-
}
795855

796-
#endif
856+
/*
857+
* Invalidate relation's relcache entry so that other backends (and this
858+
* one too!) are sent SI message to make them rebuild relcache entries.
859+
* (Ideally this should happen automatically...)
860+
*/
861+
CacheInvalidateRelcache(targetrel);
862+
863+
/*
864+
* Close rel, but keep exclusive lock!
865+
*/
866+
relation_close(targetrel, NoLock);
867+
868+
return ruleOid;
869+
}

src/bin/psql/tab-complete.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,15 @@ static const SchemaQuery Query_for_list_of_views = {
624624
" (SELECT conrelid FROM pg_catalog.pg_constraint "\
625625
" WHERE pg_catalog.quote_ident(conname)='%s')"
626626

627+
/* the silly-looking length condition is just to eat up the current word */
628+
#define Query_for_list_of_tables_for_rule \
629+
"SELECT pg_catalog.quote_ident(relname) "\
630+
" FROM pg_catalog.pg_class"\
631+
" WHERE (%d = pg_catalog.length('%s'))"\
632+
" AND oid IN "\
633+
" (SELECT ev_class FROM pg_catalog.pg_rewrite "\
634+
" WHERE pg_catalog.quote_ident(rulename)='%s')"
635+
627636
/* the silly-looking length condition is just to eat up the current word */
628637
#define Query_for_list_of_tables_for_trigger \
629638
"SELECT pg_catalog.quote_ident(relname) "\
@@ -925,7 +934,7 @@ psql_completion(char *text, int start, int end)
925934
{"AGGREGATE", "COLLATION", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN",
926935
"EXTENSION", "FOREIGN DATA WRAPPER", "FOREIGN TABLE", "FUNCTION",
927936
"GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "OPERATOR",
928-
"ROLE", "SCHEMA", "SERVER", "SEQUENCE", "TABLE",
937+
"ROLE", "RULE", "SCHEMA", "SERVER", "SEQUENCE", "TABLE",
929938
"TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE",
930939
"USER", "USER MAPPING FOR", "VIEW", NULL};
931940

@@ -1259,6 +1268,26 @@ psql_completion(char *text, int start, int end)
12591268

12601269
COMPLETE_WITH_LIST(list_ALTERVIEW);
12611270
}
1271+
1272+
/* ALTER RULE <name>, add ON */
1273+
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
1274+
pg_strcasecmp(prev2_wd, "RULE") == 0)
1275+
COMPLETE_WITH_CONST("ON");
1276+
1277+
/* If we have ALTER RULE <name> ON, then add the correct tablename */
1278+
else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
1279+
pg_strcasecmp(prev3_wd, "RULE") == 0 &&
1280+
pg_strcasecmp(prev_wd, "ON") == 0)
1281+
{
1282+
completion_info_charp = prev2_wd;
1283+
COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_rule);
1284+
}
1285+
1286+
/* ALTER RULE <name> ON <name> */
1287+
else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
1288+
pg_strcasecmp(prev4_wd, "RULE") == 0)
1289+
COMPLETE_WITH_CONST("RENAME TO");
1290+
12621291
/* ALTER TRIGGER <name>, add ON */
12631292
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
12641293
pg_strcasecmp(prev2_wd, "TRIGGER") == 0)

src/include/rewrite/rewriteDefine.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ extern Oid DefineQueryRewrite(char *rulename,
3232
bool replace,
3333
List *action);
3434

35-
extern void RenameRewriteRule(Oid owningRel, const char *oldName,
35+
extern Oid RenameRewriteRule(RangeVar *relation, const char *oldName,
3636
const char *newName);
3737

3838
extern void setRuleCheckAsUser(Node *node, Oid userid);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy