summaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
authorKevin Grittner <kgrittn@postgresql.org>2016-11-04 10:49:50 -0500
committerKevin Grittner <kgrittn@postgresql.org>2016-11-04 10:49:50 -0500
commit8c48375e5f43ebd832f93c9166d1fe0e639ff806 (patch)
tree5115baa716b278c4dcabcf6b22fd446a17eb36d8 /src/backend/parser
parent69d590fffbdcfb50a31a8c78ce87e602002a869f (diff)
Implement syntax for transition tables in AFTER triggers.
This is infrastructure for the complete SQL standard feature. No support is included at this point for execution nodes or PLs. The intent is to add that soon. As this patch leaves things, standard syntax can create tuplestores to contain old and/or new versions of rows affected by a statement. References to these tuplestores are in the TriggerData structure. C triggers can access the tuplestores directly, so they are usable, but they cannot yet be referenced within a SQL statement.
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/gram.y70
1 files changed, 61 insertions, 9 deletions
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 5547fc86586..0ec1cd345b2 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -310,6 +310,9 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <list> TriggerEvents TriggerOneEvent
%type <value> TriggerFuncArg
%type <node> TriggerWhen
+%type <str> TransitionRelName
+%type <boolean> TransitionRowOrTable TransitionOldOrNew
+%type <node> TriggerTransition
%type <list> event_trigger_when_list event_trigger_value_list
%type <defelt> event_trigger_when_item
@@ -374,6 +377,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
create_generic_options alter_generic_options
relation_expr_list dostmt_opt_list
transform_element_list transform_type_list
+ TriggerTransitions TriggerReferencing
%type <list> group_by_list
%type <node> group_by_item empty_grouping_set rollup_clause cube_clause
@@ -610,11 +614,11 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
MAPPING MATCH MATERIALIZED MAXVALUE METHOD MINUTE_P MINVALUE MODE MONTH_P MOVE
- NAME_P NAMES NATIONAL NATURAL NCHAR NEXT NO NONE
+ NAME_P NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NONE
NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF
NULLS_P NUMERIC
- OBJECT_P OF OFF OFFSET OIDS ON ONLY OPERATOR OPTION OPTIONS OR
+ OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OPTIONS OR
ORDER ORDINALITY OUT_P OUTER_P OVER OVERLAPS OVERLAY OWNED OWNER
PARALLEL PARSER PARTIAL PARTITION PASSING PASSWORD PLACING PLANS POLICY
@@ -623,8 +627,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
QUOTE
- RANGE READ REAL REASSIGN RECHECK RECURSIVE REF REFERENCES REFRESH REINDEX
- RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA
+ RANGE READ REAL REASSIGN RECHECK RECURSIVE REF REFERENCES REFERENCING
+ REFRESH REINDEX RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA
RESET RESTART RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP
ROW ROWS RULE
@@ -4748,19 +4752,20 @@ CreateAmStmt: CREATE ACCESS METHOD name TYPE_P INDEX HANDLER handler_name
CreateTrigStmt:
CREATE TRIGGER name TriggerActionTime TriggerEvents ON
- qualified_name TriggerForSpec TriggerWhen
+ qualified_name TriggerReferencing TriggerForSpec TriggerWhen
EXECUTE PROCEDURE func_name '(' TriggerFuncArgs ')'
{
CreateTrigStmt *n = makeNode(CreateTrigStmt);
n->trigname = $3;
n->relation = $7;
- n->funcname = $12;
- n->args = $14;
- n->row = $8;
+ n->funcname = $13;
+ n->args = $15;
+ n->row = $9;
n->timing = $4;
n->events = intVal(linitial($5));
n->columns = (List *) lsecond($5);
- n->whenClause = $9;
+ n->whenClause = $10;
+ n->transitionRels = $8;
n->isconstraint = FALSE;
n->deferrable = FALSE;
n->initdeferred = FALSE;
@@ -4782,6 +4787,7 @@ CreateTrigStmt:
n->events = intVal(linitial($6));
n->columns = (List *) lsecond($6);
n->whenClause = $14;
+ n->transitionRels = NIL;
n->isconstraint = TRUE;
processCASbits($10, @10, "TRIGGER",
&n->deferrable, &n->initdeferred, NULL,
@@ -4834,6 +4840,49 @@ TriggerOneEvent:
{ $$ = list_make2(makeInteger(TRIGGER_TYPE_TRUNCATE), NIL); }
;
+TriggerReferencing:
+ REFERENCING TriggerTransitions { $$ = $2; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+TriggerTransitions:
+ TriggerTransition { $$ = list_make1($1); }
+ | TriggerTransitions TriggerTransition { $$ = lappend($1, $2); }
+ ;
+
+TriggerTransition:
+ TransitionOldOrNew TransitionRowOrTable opt_as TransitionRelName
+ {
+ TriggerTransition *n = makeNode(TriggerTransition);
+ n->name = $4;
+ n->isNew = $1;
+ n->isTable = $2;
+ $$ = (Node *)n;
+ }
+ ;
+
+TransitionOldOrNew:
+ NEW { $$ = TRUE; }
+ | OLD { $$ = FALSE; }
+ ;
+
+TransitionRowOrTable:
+ TABLE { $$ = TRUE; }
+ /*
+ * According to the standard, lack of a keyword here implies ROW.
+ * Support for that would require prohibiting ROW entirely here,
+ * reserving the keyword ROW, and/or requiring AS (instead of
+ * allowing it to be optional, as the standard specifies) as the
+ * next token. Requiring ROW seems cleanest and easiest to
+ * explain.
+ */
+ | ROW { $$ = FALSE; }
+ ;
+
+TransitionRelName:
+ ColId { $$ = $1; }
+ ;
+
TriggerForSpec:
FOR TriggerForOptEach TriggerForType
{
@@ -13810,6 +13859,7 @@ unreserved_keyword:
| MOVE
| NAME_P
| NAMES
+ | NEW
| NEXT
| NO
| NOTHING
@@ -13820,6 +13870,7 @@ unreserved_keyword:
| OF
| OFF
| OIDS
+ | OLD
| OPERATOR
| OPTION
| OPTIONS
@@ -13851,6 +13902,7 @@ unreserved_keyword:
| RECHECK
| RECURSIVE
| REF
+ | REFERENCING
| REFRESH
| REINDEX
| RELATIVE_P