diff options
author | Kevin Grittner <kgrittn@postgresql.org> | 2016-11-04 10:49:50 -0500 |
---|---|---|
committer | Kevin Grittner <kgrittn@postgresql.org> | 2016-11-04 10:49:50 -0500 |
commit | 8c48375e5f43ebd832f93c9166d1fe0e639ff806 (patch) | |
tree | 5115baa716b278c4dcabcf6b22fd446a17eb36d8 /src/backend/parser | |
parent | 69d590fffbdcfb50a31a8c78ce87e602002a869f (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.y | 70 |
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 |