Don't treat NEW and OLD as reserved words anymore. For the purposes of rules

it works just as well to have them be ordinary identifiers, and this gets rid
of a number of ugly special cases.  Plus we aren't interfering with non-rule
usage of these names.

catversion bump because the names change internally in stored rules.
This commit is contained in:
Tom Lane 2009-11-05 23:24:27 +00:00
parent 45d7e04fce
commit 593f4b854a
18 changed files with 84 additions and 156 deletions

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/keywords.sgml,v 2.26 2009/09/22 23:43:37 tgl Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/keywords.sgml,v 2.27 2009/11/05 23:24:22 tgl Exp $ -->
<appendix id="sql-keywords-appendix"> <appendix id="sql-keywords-appendix">
<title><acronym>SQL</acronym> Key Words</title> <title><acronym>SQL</acronym> Key Words</title>
@ -3089,7 +3089,7 @@
</row> </row>
<row> <row>
<entry><token>NEW</token></entry> <entry><token>NEW</token></entry>
<entry>reserved</entry> <entry></entry>
<entry>reserved</entry> <entry>reserved</entry>
<entry>reserved</entry> <entry>reserved</entry>
<entry>reserved</entry> <entry>reserved</entry>
@ -3393,7 +3393,7 @@
</row> </row>
<row> <row>
<entry><token>OLD</token></entry> <entry><token>OLD</token></entry>
<entry>reserved</entry> <entry></entry>
<entry>reserved</entry> <entry>reserved</entry>
<entry>reserved</entry> <entry>reserved</entry>
<entry>reserved</entry> <entry>reserved</entry>

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/rules.sgml,v 1.52 2008/12/16 03:12:08 momjian Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/rules.sgml,v 1.53 2009/11/05 23:24:22 tgl Exp $ -->
<chapter id="rules"> <chapter id="rules">
<title>The Rule System</title> <title>The Rule System</title>
@ -435,8 +435,7 @@ CREATE VIEW shoe_ready AS
<note> <note>
<para> <para>
The two extra range The two extra range
table entries for <literal>NEW</> and <literal>OLD</> (named <literal>*NEW*</> and <literal>*OLD*</> for table entries for <literal>NEW</> and <literal>OLD</> that you can see in
historical reasons in the printed query tree) you can see in
the <structname>pg_rewrite</structname> entry aren't of interest the <structname>pg_rewrite</structname> entry aren't of interest
for <command>SELECT</command> rules. for <command>SELECT</command> rules.
</para> </para>
@ -504,7 +503,7 @@ SELECT shoelace.sl_name, shoelace.sl_avail,
SELECT s.sl_name, s.sl_avail, SELECT s.sl_name, s.sl_avail,
s.sl_color, s.sl_len, s.sl_unit, s.sl_color, s.sl_len, s.sl_unit,
s.sl_len * u.un_fact AS sl_len_cm s.sl_len * u.un_fact AS sl_len_cm
FROM shoelace *OLD*, shoelace *NEW*, FROM shoelace old, shoelace new,
shoelace_data s, unit u shoelace_data s, unit u
WHERE s.sl_unit = u.un_name; WHERE s.sl_unit = u.un_name;
</programlisting> </programlisting>
@ -531,7 +530,7 @@ SELECT shoelace.sl_name, shoelace.sl_avail,
</programlisting> </programlisting>
There is one difference however: the subquery's range table has two There is one difference however: the subquery's range table has two
extra entries <literal>shoelace *OLD*</> and <literal>shoelace *NEW*</>. These entries don't extra entries <literal>shoelace old</> and <literal>shoelace new</>. These entries don't
participate directly in the query, since they aren't referenced by participate directly in the query, since they aren't referenced by
the subquery's join tree or target list. The rewriter uses them the subquery's join tree or target list. The rewriter uses them
to store the access privilege check information that was originally present to store the access privilege check information that was originally present
@ -546,7 +545,7 @@ SELECT shoelace.sl_name, shoelace.sl_avail,
the remaining range-table entries in the top query (in this example there the remaining range-table entries in the top query (in this example there
are no more), and it will recursively check the range-table entries in are no more), and it will recursively check the range-table entries in
the added subquery to see if any of them reference views. (But it the added subquery to see if any of them reference views. (But it
won't expand <literal>*OLD*</> or <literal>*NEW*</> &mdash; otherwise we'd have infinite recursion!) won't expand <literal>old</> or <literal>new</> &mdash; otherwise we'd have infinite recursion!)
In this example, there are no rewrite rules for <literal>shoelace_data</> or <literal>unit</>, In this example, there are no rewrite rules for <literal>shoelace_data</> or <literal>unit</>,
so rewriting is complete and the above is the final result given to so rewriting is complete and the above is the final result given to
the planner. the planner.
@ -1073,15 +1072,15 @@ NEW.sl_avail &lt;&gt; OLD.sl_avail
<programlisting> <programlisting>
INSERT INTO shoelace_log VALUES ( INSERT INTO shoelace_log VALUES (
*NEW*.sl_name, *NEW*.sl_avail, new.sl_name, new.sl_avail,
current_user, current_timestamp ) current_user, current_timestamp )
FROM shoelace_data *NEW*, shoelace_data *OLD*; FROM shoelace_data new, shoelace_data old;
</programlisting> </programlisting>
(This looks a little strange since you cannot normally write (This looks a little strange since you cannot normally write
<literal>INSERT ... VALUES ... FROM</>. The <literal>FROM</> <literal>INSERT ... VALUES ... FROM</>. The <literal>FROM</>
clause here is just to indicate that there are range-table entries clause here is just to indicate that there are range-table entries
in the query tree for <literal>*NEW*</> and <literal>*OLD*</>. in the query tree for <literal>new</> and <literal>old</>.
These are needed so that they can be referenced by variables in These are needed so that they can be referenced by variables in
the <command>INSERT</command> command's query tree.) the <command>INSERT</command> command's query tree.)
</para> </para>
@ -1094,9 +1093,9 @@ INSERT INTO shoelace_log VALUES (
<programlisting> <programlisting>
INSERT INTO shoelace_log VALUES ( INSERT INTO shoelace_log VALUES (
*NEW*.sl_name, *NEW*.sl_avail, new.sl_name, new.sl_avail,
current_user, current_timestamp ) current_user, current_timestamp )
FROM shoelace_data *NEW*, shoelace_data *OLD*, FROM shoelace_data new, shoelace_data old,
<emphasis>shoelace_data shoelace_data</emphasis>; <emphasis>shoelace_data shoelace_data</emphasis>;
</programlisting> </programlisting>
@ -1105,11 +1104,11 @@ INSERT INTO shoelace_log VALUES (
<programlisting> <programlisting>
INSERT INTO shoelace_log VALUES ( INSERT INTO shoelace_log VALUES (
*NEW*.sl_name, *NEW*.sl_avail, new.sl_name, new.sl_avail,
current_user, current_timestamp ) current_user, current_timestamp )
FROM shoelace_data *NEW*, shoelace_data *OLD*, FROM shoelace_data new, shoelace_data old,
shoelace_data shoelace_data shoelace_data shoelace_data
<emphasis>WHERE *NEW*.sl_avail &lt;&gt; *OLD*.sl_avail</emphasis>; <emphasis>WHERE new.sl_avail &lt;&gt; old.sl_avail</emphasis>;
</programlisting> </programlisting>
(This looks even stranger, since <literal>INSERT ... VALUES</> doesn't have (This looks even stranger, since <literal>INSERT ... VALUES</> doesn't have
@ -1125,11 +1124,11 @@ INSERT INTO shoelace_log VALUES (
<programlisting> <programlisting>
INSERT INTO shoelace_log VALUES ( INSERT INTO shoelace_log VALUES (
*NEW*.sl_name, *NEW*.sl_avail, new.sl_name, new.sl_avail,
current_user, current_timestamp ) current_user, current_timestamp )
FROM shoelace_data *NEW*, shoelace_data *OLD*, FROM shoelace_data new, shoelace_data old,
shoelace_data shoelace_data shoelace_data shoelace_data
WHERE *NEW*.sl_avail &lt;&gt; *OLD*.sl_avail WHERE new.sl_avail &lt;&gt; old.sl_avail
<emphasis>AND shoelace_data.sl_name = 'sl7'</emphasis>; <emphasis>AND shoelace_data.sl_name = 'sl7'</emphasis>;
</programlisting> </programlisting>
</para> </para>
@ -1143,9 +1142,9 @@ INSERT INTO shoelace_log VALUES (
INSERT INTO shoelace_log VALUES ( INSERT INTO shoelace_log VALUES (
<emphasis>shoelace_data.sl_name</emphasis>, <emphasis>6</emphasis>, <emphasis>shoelace_data.sl_name</emphasis>, <emphasis>6</emphasis>,
current_user, current_timestamp ) current_user, current_timestamp )
FROM shoelace_data *NEW*, shoelace_data *OLD*, FROM shoelace_data new, shoelace_data old,
shoelace_data shoelace_data shoelace_data shoelace_data
WHERE <emphasis>6</emphasis> &lt;&gt; *OLD*.sl_avail WHERE <emphasis>6</emphasis> &lt;&gt; old.sl_avail
AND shoelace_data.sl_name = 'sl7'; AND shoelace_data.sl_name = 'sl7';
</programlisting> </programlisting>
@ -1158,7 +1157,7 @@ INSERT INTO shoelace_log VALUES (
INSERT INTO shoelace_log VALUES ( INSERT INTO shoelace_log VALUES (
shoelace_data.sl_name, 6, shoelace_data.sl_name, 6,
current_user, current_timestamp ) current_user, current_timestamp )
FROM shoelace_data *NEW*, shoelace_data *OLD*, FROM shoelace_data new, shoelace_data old,
shoelace_data shoelace_data shoelace_data shoelace_data
WHERE 6 &lt;&gt; <emphasis>shoelace_data.sl_avail</emphasis> WHERE 6 &lt;&gt; <emphasis>shoelace_data.sl_avail</emphasis>
AND shoelace_data.sl_name = 'sl7'; AND shoelace_data.sl_name = 'sl7';
@ -1455,7 +1454,7 @@ SELECT shoelace_arrive.arr_name, shoelace_arrive.arr_quant
UPDATE shoelace UPDATE shoelace
SET sl_avail = shoelace.sl_avail + shoelace_arrive.arr_quant SET sl_avail = shoelace.sl_avail + shoelace_arrive.arr_quant
FROM shoelace_arrive shoelace_arrive, shoelace_ok shoelace_ok, FROM shoelace_arrive shoelace_arrive, shoelace_ok shoelace_ok,
shoelace_ok *OLD*, shoelace_ok *NEW*, shoelace_ok old, shoelace_ok new,
shoelace shoelace shoelace shoelace
WHERE shoelace.sl_name = shoelace_arrive.arr_name; WHERE shoelace.sl_name = shoelace_arrive.arr_name;
</programlisting> </programlisting>
@ -1473,9 +1472,9 @@ UPDATE shoelace_data
sl_len = shoelace.sl_len, sl_len = shoelace.sl_len,
sl_unit = shoelace.sl_unit sl_unit = shoelace.sl_unit
FROM shoelace_arrive shoelace_arrive, shoelace_ok shoelace_ok, FROM shoelace_arrive shoelace_arrive, shoelace_ok shoelace_ok,
shoelace_ok *OLD*, shoelace_ok *NEW*, shoelace_ok old, shoelace_ok new,
shoelace shoelace, shoelace *OLD*, shoelace shoelace, shoelace old,
shoelace *NEW*, shoelace_data shoelace_data shoelace new, shoelace_data shoelace_data
WHERE shoelace.sl_name = shoelace_arrive.arr_name WHERE shoelace.sl_name = shoelace_arrive.arr_name
AND shoelace_data.sl_name = shoelace.sl_name; AND shoelace_data.sl_name = shoelace.sl_name;
</programlisting> </programlisting>
@ -1493,10 +1492,10 @@ UPDATE shoelace_data
sl_len = s.sl_len, sl_len = s.sl_len,
sl_unit = s.sl_unit sl_unit = s.sl_unit
FROM shoelace_arrive shoelace_arrive, shoelace_ok shoelace_ok, FROM shoelace_arrive shoelace_arrive, shoelace_ok shoelace_ok,
shoelace_ok *OLD*, shoelace_ok *NEW*, shoelace_ok old, shoelace_ok new,
shoelace shoelace, shoelace *OLD*, shoelace shoelace, shoelace old,
shoelace *NEW*, shoelace_data shoelace_data, shoelace new, shoelace_data shoelace_data,
shoelace *OLD*, shoelace *NEW*, shoelace old, shoelace new,
shoelace_data s, unit u shoelace_data s, unit u
WHERE s.sl_name = shoelace_arrive.arr_name WHERE s.sl_name = shoelace_arrive.arr_name
AND shoelace_data.sl_name = s.sl_name; AND shoelace_data.sl_name = s.sl_name;
@ -1512,12 +1511,12 @@ SELECT s.sl_name,
current_user, current_user,
current_timestamp current_timestamp
FROM shoelace_arrive shoelace_arrive, shoelace_ok shoelace_ok, FROM shoelace_arrive shoelace_arrive, shoelace_ok shoelace_ok,
shoelace_ok *OLD*, shoelace_ok *NEW*, shoelace_ok old, shoelace_ok new,
shoelace shoelace, shoelace *OLD*, shoelace shoelace, shoelace old,
shoelace *NEW*, shoelace_data shoelace_data, shoelace new, shoelace_data shoelace_data,
shoelace *OLD*, shoelace *NEW*, shoelace old, shoelace new,
shoelace_data s, unit u, shoelace_data s, unit u,
shoelace_data *OLD*, shoelace_data *NEW* shoelace_data old, shoelace_data new
shoelace_log shoelace_log shoelace_log shoelace_log
WHERE s.sl_name = shoelace_arrive.arr_name WHERE s.sl_name = shoelace_arrive.arr_name
AND shoelace_data.sl_name = s.sl_name AND shoelace_data.sl_name = s.sl_name

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/syntax.sgml,v 1.137 2009/10/08 02:39:16 tgl Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/syntax.sgml,v 1.138 2009/11/05 23:24:22 tgl Exp $ -->
<chapter id="sql-syntax"> <chapter id="sql-syntax">
<title>SQL Syntax</title> <title>SQL Syntax</title>
@ -1312,10 +1312,7 @@ SELECT 3 OPERATOR(pg_catalog.+) 4;
<para> <para>
<replaceable>correlation</replaceable> is the name of a <replaceable>correlation</replaceable> is the name of a
table (possibly qualified with a schema name), or an alias for a table table (possibly qualified with a schema name), or an alias for a table
defined by means of a <literal>FROM</literal> clause, or one of defined by means of a <literal>FROM</literal> clause.
the key words <literal>NEW</literal> or <literal>OLD</literal>.
(<literal>NEW</literal> and <literal>OLD</literal> can only appear in rewrite rules,
while other correlation names can be used in any SQL statement.)
The correlation name and separating dot can be omitted if the column name The correlation name and separating dot can be omitted if the column name
is unique across all the tables being used in the current query. (See also <xref linkend="queries">.) is unique across all the tables being used in the current query. (See also <xref linkend="queries">.)
</para> </para>

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.118 2009/10/13 00:53:07 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.119 2009/11/05 23:24:23 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -361,10 +361,10 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
* OLD first, then NEW.... * OLD first, then NEW....
*/ */
rt_entry1 = addRangeTableEntryForRelation(NULL, viewRel, rt_entry1 = addRangeTableEntryForRelation(NULL, viewRel,
makeAlias("*OLD*", NIL), makeAlias("old", NIL),
false, false); false, false);
rt_entry2 = addRangeTableEntryForRelation(NULL, viewRel, rt_entry2 = addRangeTableEntryForRelation(NULL, viewRel,
makeAlias("*NEW*", NIL), makeAlias("new", NIL),
false, false); false, false);
/* Must override addRangeTableEntry's default access-check flags */ /* Must override addRangeTableEntry's default access-check flags */
rt_entry1->requiredPerms = 0; rt_entry1->requiredPerms = 0;

View File

@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.687 2009/11/04 23:15:08 tgl Exp $ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.688 2009/11/05 23:24:23 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
@ -254,7 +254,7 @@ static TypeName *TableFuncTypeName(List *columns);
%type <list> TriggerEvents TriggerOneEvent %type <list> TriggerEvents TriggerOneEvent
%type <value> TriggerFuncArg %type <value> TriggerFuncArg
%type <str> relation_name copy_file_name %type <str> copy_file_name
database_name access_method_clause access_method attr_name database_name access_method_clause access_method attr_name
index_name name file_name cluster_index_specification index_name name file_name cluster_index_specification
@ -263,7 +263,7 @@ static TypeName *TableFuncTypeName(List *columns);
%type <range> qualified_name OptConstrFromTable %type <range> qualified_name OptConstrFromTable
%type <str> all_Op MathOp SpecialRuleRelation %type <str> all_Op MathOp
%type <str> iso_level opt_encoding %type <str> iso_level opt_encoding
%type <node> grantee %type <node> grantee
@ -502,11 +502,11 @@ static TypeName *TableFuncTypeName(List *columns);
MAPPING MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE MAPPING MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
NAME_P NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NOCREATEDB NAME_P NAMES NATIONAL NATURAL NCHAR NEXT NO NOCREATEDB
NOCREATEROLE NOCREATEUSER NOINHERIT NOLOGIN_P NONE NOSUPERUSER NOCREATEROLE NOCREATEUSER NOINHERIT NOLOGIN_P NONE NOSUPERUSER
NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF NULLS_P NUMERIC NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF NULLS_P NUMERIC
OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OPTIONS OR OBJECT_P OF OFF OFFSET OIDS ON ONLY OPERATOR OPTION OPTIONS OR
ORDER OUT_P OUTER_P OVER OVERLAPS OVERLAY OWNED OWNER ORDER OUT_P OUTER_P OVER OVERLAPS OVERLAY OWNED OWNER
PARSER PARTIAL PARTITION PASSWORD PLACING PLANS POSITION PARSER PARTIAL PARTITION PASSWORD PLACING PLANS POSITION
@ -5886,20 +5886,18 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
*****************************************************************************/ *****************************************************************************/
RuleStmt: CREATE opt_or_replace RULE name AS RuleStmt: CREATE opt_or_replace RULE name AS
{ pg_yyget_extra(yyscanner)->QueryIsRule = TRUE; }
ON event TO qualified_name where_clause ON event TO qualified_name where_clause
DO opt_instead RuleActionList DO opt_instead RuleActionList
{ {
RuleStmt *n = makeNode(RuleStmt); RuleStmt *n = makeNode(RuleStmt);
n->replace = $2; n->replace = $2;
n->relation = $10; n->relation = $9;
n->rulename = $4; n->rulename = $4;
n->whereClause = $11; n->whereClause = $10;
n->event = $8; n->event = $7;
n->instead = $13; n->instead = $12;
n->actions = $14; n->actions = $13;
$$ = (Node *)n; $$ = (Node *)n;
pg_yyget_extra(yyscanner)->QueryIsRule = FALSE;
} }
; ;
@ -10109,16 +10107,11 @@ case_arg: a_expr { $$ = $1; }
| /*EMPTY*/ { $$ = NULL; } | /*EMPTY*/ { $$ = NULL; }
; ;
/* columnref: ColId
* columnref starts with relation_name not ColId, so that OLD and NEW
* references can be accepted. Note that when there are more than two
* dotted names, the first name is not actually a relation name...
*/
columnref: relation_name
{ {
$$ = makeColumnRef($1, NIL, @1, yyscanner); $$ = makeColumnRef($1, NIL, @1, yyscanner);
} }
| relation_name indirection | ColId indirection
{ {
$$ = makeColumnRef($1, $2, @1, yyscanner); $$ = makeColumnRef($1, $2, @1, yyscanner);
} }
@ -10258,11 +10251,6 @@ target_el: a_expr AS ColLabel
* *
*****************************************************************************/ *****************************************************************************/
relation_name:
SpecialRuleRelation { $$ = $1; }
| ColId { $$ = $1; }
;
qualified_name_list: qualified_name_list:
qualified_name { $$ = list_make1($1); } qualified_name { $$ = list_make1($1); }
| qualified_name_list ',' qualified_name { $$ = lappend($1, $3); } | qualified_name_list ',' qualified_name { $$ = lappend($1, $3); }
@ -10276,7 +10264,7 @@ qualified_name_list:
* which may contain subscripts, and reject that case in the C code. * which may contain subscripts, and reject that case in the C code.
*/ */
qualified_name: qualified_name:
relation_name ColId
{ {
$$ = makeNode(RangeVar); $$ = makeNode(RangeVar);
$$->catalogname = NULL; $$->catalogname = NULL;
@ -10284,7 +10272,7 @@ qualified_name:
$$->relname = $1; $$->relname = $1;
$$->location = @1; $$->location = @1;
} }
| relation_name indirection | ColId indirection
{ {
check_qualified_name($2, yyscanner); check_qualified_name($2, yyscanner);
$$ = makeNode(RangeVar); $$ = makeNode(RangeVar);
@ -10343,7 +10331,7 @@ file_name: Sconst { $$ = $1; };
*/ */
func_name: type_function_name func_name: type_function_name
{ $$ = list_make1(makeString($1)); } { $$ = list_make1(makeString($1)); }
| relation_name indirection | ColId indirection
{ {
$$ = check_func_name(lcons(makeString($1), $2), $$ = check_func_name(lcons(makeString($1), $2),
yyscanner); yyscanner);
@ -10912,12 +10900,10 @@ reserved_keyword:
| LIMIT | LIMIT
| LOCALTIME | LOCALTIME
| LOCALTIMESTAMP | LOCALTIMESTAMP
| NEW
| NOT | NOT
| NULL_P | NULL_P
| OFF | OFF
| OFFSET | OFFSET
| OLD
| ON | ON
| ONLY | ONLY
| OR | OR
@ -10946,30 +10932,6 @@ reserved_keyword:
| WITH | WITH
; ;
SpecialRuleRelation:
OLD
{
if (pg_yyget_extra(yyscanner)->QueryIsRule)
$$ = "*OLD*";
else
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("OLD used in query that is not in a rule"),
parser_errposition(@1)));
}
| NEW
{
if (pg_yyget_extra(yyscanner)->QueryIsRule)
$$ = "*NEW*";
else
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("NEW used in query that is not in a rule"),
parser_errposition(@1)));
}
;
%% %%
/* /*
@ -11461,7 +11423,6 @@ void
parser_init(base_yy_extra_type *yyext) parser_init(base_yy_extra_type *yyext)
{ {
yyext->parsetree = NIL; /* in case grammar forgets to set it */ yyext->parsetree = NIL; /* in case grammar forgets to set it */
yyext->QueryIsRule = FALSE;
} }
/* /*

View File

@ -19,7 +19,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.28 2009/10/13 00:53:08 tgl Exp $ * $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.29 2009/11/05 23:24:24 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1549,10 +1549,10 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
* qualification. * qualification.
*/ */
oldrte = addRangeTableEntryForRelation(pstate, rel, oldrte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("*OLD*", NIL), makeAlias("old", NIL),
false, false); false, false);
newrte = addRangeTableEntryForRelation(pstate, rel, newrte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("*NEW*", NIL), makeAlias("new", NIL),
false, false); false, false);
/* Must override addRangeTableEntry's default access-check flags */ /* Must override addRangeTableEntry's default access-check flags */
oldrte->requiredPerms = 0; oldrte->requiredPerms = 0;
@ -1653,10 +1653,10 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
* them in the joinlist. * them in the joinlist.
*/ */
oldrte = addRangeTableEntryForRelation(sub_pstate, rel, oldrte = addRangeTableEntryForRelation(sub_pstate, rel,
makeAlias("*OLD*", NIL), makeAlias("old", NIL),
false, false); false, false);
newrte = addRangeTableEntryForRelation(sub_pstate, rel, newrte = addRangeTableEntryForRelation(sub_pstate, rel,
makeAlias("*NEW*", NIL), makeAlias("new", NIL),
false, false); false, false);
oldrte->requiredPerms = 0; oldrte->requiredPerms = 0;
newrte->requiredPerms = 0; newrte->requiredPerms = 0;

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.138 2009/06/11 14:49:01 momjian Exp $ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.139 2009/11/05 23:24:24 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -601,9 +601,9 @@ checkRuleResultList(List *targetList, TupleDesc resultDesc, bool isSelect)
* Recursively scan a query or expression tree and set the checkAsUser * Recursively scan a query or expression tree and set the checkAsUser
* field to the given userid in all rtable entries. * field to the given userid in all rtable entries.
* *
* Note: for a view (ON SELECT rule), the checkAsUser field of the *OLD* * Note: for a view (ON SELECT rule), the checkAsUser field of the OLD
* RTE entry will be overridden when the view rule is expanded, and the * RTE entry will be overridden when the view rule is expanded, and the
* checkAsUser field of the *NEW* entry is irrelevant because that entry's * checkAsUser field of the NEW entry is irrelevant because that entry's
* requiredPerms bits will always be zero. However, for other types of rules * requiredPerms bits will always be zero. However, for other types of rules
* it's important to set these fields to match the rule owner. So we just set * it's important to set these fields to match the rule owner. So we just set
* them always. * them always.

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.191 2009/10/28 17:36:50 tgl Exp $ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.192 2009/11/05 23:24:24 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -325,7 +325,7 @@ rewriteRuleAction(Query *parsetree,
OffsetVarNodes((Node *) sub_action, rt_length, 0); OffsetVarNodes((Node *) sub_action, rt_length, 0);
OffsetVarNodes(rule_qual, rt_length, 0); OffsetVarNodes(rule_qual, rt_length, 0);
/* but references to *OLD* should point at original rt_index */ /* but references to OLD should point at original rt_index */
ChangeVarNodes((Node *) sub_action, ChangeVarNodes((Node *) sub_action,
PRS2_OLD_VARNO + rt_length, rt_index, 0); PRS2_OLD_VARNO + rt_length, rt_index, 0);
ChangeVarNodes(rule_qual, ChangeVarNodes(rule_qual,
@ -1190,7 +1190,7 @@ ApplyRetrieveRule(Query *parsetree,
/* /*
* We move the view's permission check data down to its rangetable. The * We move the view's permission check data down to its rangetable. The
* checks will actually be done against the *OLD* entry therein. * checks will actually be done against the OLD entry therein.
*/ */
subrte = rt_fetch(PRS2_OLD_VARNO, rule_action->rtable); subrte = rt_fetch(PRS2_OLD_VARNO, rule_action->rtable);
Assert(subrte->relid == relation->rd_id); Assert(subrte->relid == relation->rd_id);

View File

@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.124 2009/10/26 02:26:38 tgl Exp $ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.125 2009/11/05 23:24:24 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -940,15 +940,15 @@ getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
/* /*
* Currently, this is ONLY applied to rule-action queries, and so we * Currently, this is ONLY applied to rule-action queries, and so we
* expect to find the *OLD* and *NEW* placeholder entries in the given * expect to find the OLD and NEW placeholder entries in the given
* query. If they're not there, it must be an INSERT/SELECT in which * query. If they're not there, it must be an INSERT/SELECT in which
* they've been pushed down to the SELECT. * they've been pushed down to the SELECT.
*/ */
if (list_length(parsetree->rtable) >= 2 && if (list_length(parsetree->rtable) >= 2 &&
strcmp(rt_fetch(PRS2_OLD_VARNO, parsetree->rtable)->eref->aliasname, strcmp(rt_fetch(PRS2_OLD_VARNO, parsetree->rtable)->eref->aliasname,
"*OLD*") == 0 && "old") == 0 &&
strcmp(rt_fetch(PRS2_NEW_VARNO, parsetree->rtable)->eref->aliasname, strcmp(rt_fetch(PRS2_NEW_VARNO, parsetree->rtable)->eref->aliasname,
"*NEW*") == 0) "new") == 0)
return parsetree; return parsetree;
Assert(parsetree->jointree && IsA(parsetree->jointree, FromExpr)); Assert(parsetree->jointree && IsA(parsetree->jointree, FromExpr));
if (list_length(parsetree->jointree->fromlist) != 1) if (list_length(parsetree->jointree->fromlist) != 1)
@ -962,9 +962,9 @@ getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
elog(ERROR, "expected to find SELECT subquery"); elog(ERROR, "expected to find SELECT subquery");
if (list_length(selectquery->rtable) >= 2 && if (list_length(selectquery->rtable) >= 2 &&
strcmp(rt_fetch(PRS2_OLD_VARNO, selectquery->rtable)->eref->aliasname, strcmp(rt_fetch(PRS2_OLD_VARNO, selectquery->rtable)->eref->aliasname,
"*OLD*") == 0 && "old") == 0 &&
strcmp(rt_fetch(PRS2_NEW_VARNO, selectquery->rtable)->eref->aliasname, strcmp(rt_fetch(PRS2_NEW_VARNO, selectquery->rtable)->eref->aliasname,
"*NEW*") == 0) "new") == 0)
{ {
if (subquery_ptr) if (subquery_ptr)
*subquery_ptr = &(selectrte->subquery); *subquery_ptr = &(selectrte->subquery);

View File

@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.313 2009/10/28 18:51:56 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.314 2009/11/05 23:24:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -3572,14 +3572,7 @@ get_variable(Var *var, int levelsup, bool showstar, deparse_context *context)
if (schemaname) if (schemaname)
appendStringInfo(buf, "%s.", appendStringInfo(buf, "%s.",
quote_identifier(schemaname)); quote_identifier(schemaname));
appendStringInfoString(buf, quote_identifier(refname));
if (strcmp(refname, "*NEW*") == 0)
appendStringInfoString(buf, "new");
else if (strcmp(refname, "*OLD*") == 0)
appendStringInfoString(buf, "old");
else
appendStringInfoString(buf, quote_identifier(refname));
if (attname || showstar) if (attname || showstar)
appendStringInfoChar(buf, '.'); appendStringInfoChar(buf, '.');
} }

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.549 2009/11/04 23:47:04 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.550 2009/11/05 23:24:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200911041 #define CATALOG_VERSION_NO 200911051
#endif #endif

View File

@ -11,7 +11,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/parser/gramparse.h,v 1.48 2009/09/22 23:52:53 petere Exp $ * $PostgreSQL: pgsql/src/include/parser/gramparse.h,v 1.49 2009/11/05 23:24:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -93,8 +93,6 @@ typedef struct base_yy_extra_type
*/ */
List *parsetree; /* final parse result is delivered here */ List *parsetree; /* final parse result is delivered here */
bool QueryIsRule; /* signals we are parsing CREATE RULE */
} base_yy_extra_type; } base_yy_extra_type;
/* /*

View File

@ -11,7 +11,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/include/parser/kwlist.h,v 1.5 2009/10/12 20:39:42 tgl Exp $ * $PostgreSQL: pgsql/src/include/parser/kwlist.h,v 1.6 2009/11/05 23:24:27 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -239,7 +239,6 @@ PG_KEYWORD("names", NAMES, UNRESERVED_KEYWORD)
PG_KEYWORD("national", NATIONAL, COL_NAME_KEYWORD) PG_KEYWORD("national", NATIONAL, COL_NAME_KEYWORD)
PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD) PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD)
PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD) PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD)
PG_KEYWORD("new", NEW, RESERVED_KEYWORD)
PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD) PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD)
PG_KEYWORD("no", NO, UNRESERVED_KEYWORD) PG_KEYWORD("no", NO, UNRESERVED_KEYWORD)
PG_KEYWORD("nocreatedb", NOCREATEDB, UNRESERVED_KEYWORD) PG_KEYWORD("nocreatedb", NOCREATEDB, UNRESERVED_KEYWORD)
@ -263,7 +262,6 @@ PG_KEYWORD("of", OF, UNRESERVED_KEYWORD)
PG_KEYWORD("off", OFF, RESERVED_KEYWORD) PG_KEYWORD("off", OFF, RESERVED_KEYWORD)
PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD) PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD)
PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD) PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD)
PG_KEYWORD("old", OLD, RESERVED_KEYWORD)
PG_KEYWORD("on", ON, RESERVED_KEYWORD) PG_KEYWORD("on", ON, RESERVED_KEYWORD)
PG_KEYWORD("only", ONLY, RESERVED_KEYWORD) PG_KEYWORD("only", ONLY, RESERVED_KEYWORD)
PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD) PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD)

View File

@ -1,4 +1,4 @@
/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.addons,v 1.5 2009/08/14 13:28:22 meskes Exp $ */ /* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.addons,v 1.6 2009/11/05 23:24:27 tgl Exp $ */
ECPG: stmtClosePortalStmt block ECPG: stmtClosePortalStmt block
{ {
@ -377,12 +377,6 @@ ECPG: FetchStmtMOVEname rule
add_additional_variables($3, false); add_additional_variables($3, false);
$$ = cat_str(3, make_str("fetch"), $2, $3); $$ = cat_str(3, make_str("fetch"), $2, $3);
} }
ECPG: SpecialRuleRelationOLD addon
if (!QueryIsRule)
mmerror(PARSE_ERROR, ET_ERROR, "OLD used in query that is not in a rule");
ECPG: SpecialRuleRelationNEW addon
if (!QueryIsRule)
mmerror(PARSE_ERROR, ET_ERROR, "NEW used in query that is not in a rule");
ECPG: select_limitLIMITselect_limit_value','select_offset_value block ECPG: select_limitLIMITselect_limit_value','select_offset_value block
{ {
mmerror(PARSE_ERROR, ET_WARNING, "no longer supported LIMIT #,# syntax passed to server"); mmerror(PARSE_ERROR, ET_WARNING, "no longer supported LIMIT #,# syntax passed to server");

View File

@ -1,4 +1,4 @@
/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.header,v 1.9 2009/09/08 04:25:00 tgl Exp $ */ /* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.header,v 1.10 2009/11/05 23:24:27 tgl Exp $ */
/* Copyright comment */ /* Copyright comment */
%{ %{
@ -37,7 +37,7 @@ int ecpg_informix_var = 0;
char *connection = NULL; char *connection = NULL;
char *input_filename = NULL; char *input_filename = NULL;
static int QueryIsRule = 0, FoundInto = 0; static int FoundInto = 0;
static int initializer = 0; static int initializer = 0;
static int pacounter = 1; static int pacounter = 1;
static char pacounter_buffer[sizeof(int) * CHAR_BIT * 10 / 3]; /* a rough guess at the size we need */ static char pacounter_buffer[sizeof(int) * CHAR_BIT * 10 / 3]; /* a rough guess at the size we need */

View File

@ -1,4 +1,4 @@
/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.trailer,v 1.12 2009/09/22 23:43:42 tgl Exp $ */ /* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.trailer,v 1.13 2009/11/05 23:24:27 tgl Exp $ */
statements: /*EMPTY*/ statements: /*EMPTY*/
| statements statement | statements statement
@ -28,16 +28,6 @@ CreateAsStmt: CREATE OptTemp TABLE create_as_target AS {FoundInto = 0;} SelectSt
} }
; ;
RuleStmt: CREATE opt_or_replace RULE name AS
{QueryIsRule = 1;}
ON event TO qualified_name where_clause
DO opt_instead RuleActionList
{
QueryIsRule=0;
$$ = cat_str(12, make_str("create"), $2, make_str("rule"), $4, make_str("as on"), $8, make_str("to"), $10, $11, make_str("do"), $13, $14);
}
;
at: AT connection_object at: AT connection_object
{ {
connection = $2; connection = $2;

View File

@ -1,4 +1,4 @@
/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.type,v 1.1 2008/11/14 10:03:33 meskes Exp $ */ /* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.type,v 1.2 2009/11/05 23:24:27 tgl Exp $ */
%type <str> ECPGAllocateDescr %type <str> ECPGAllocateDescr
%type <str> ECPGCKeywords %type <str> ECPGCKeywords
%type <str> ECPGColId %type <str> ECPGColId
@ -90,7 +90,6 @@
%type <str> precision %type <str> precision
%type <str> prepared_name %type <str> prepared_name
%type <str> quoted_ident_stringvar %type <str> quoted_ident_stringvar
%type <str> RuleStmt
%type <str> s_struct_union %type <str> s_struct_union
%type <str> server %type <str> server
%type <str> server_name %type <str> server_name

View File

@ -1,5 +1,5 @@
#!/usr/bin/perl #!/usr/bin/perl
# $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/parse.pl,v 1.3 2009/01/29 09:38:38 petere Exp $ # $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/parse.pl,v 1.4 2009/11/05 23:24:27 tgl Exp $
# parser generater for ecpg # parser generater for ecpg
# call with backend parser as stdin # call with backend parser as stdin
# #
@ -51,7 +51,6 @@ $replace_types{'stmtblock'} = 'ignore';
$replace_types{'stmtmulti'} = 'ignore'; $replace_types{'stmtmulti'} = 'ignore';
$replace_types{'CreateAsStmt'} = 'ignore'; $replace_types{'CreateAsStmt'} = 'ignore';
$replace_types{'DeallocateStmt'} = 'ignore'; $replace_types{'DeallocateStmt'} = 'ignore';
$replace_types{'RuleStmt'} = 'ignore';
$replace_types{'ColLabel'} = 'ignore'; $replace_types{'ColLabel'} = 'ignore';
$replace_types{'unreserved_keyword'} = 'ignore'; $replace_types{'unreserved_keyword'} = 'ignore';
$replace_types{'Sconst'} = 'ignore'; $replace_types{'Sconst'} = 'ignore';