@@ -672,6 +672,13 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
672672 json_object_constructor_null_clause_opt
673673 json_array_constructor_null_clause_opt
674674
675+ %type <target> row_pattern_definition
676+ %type <node> opt_row_pattern_common_syntax
677+ row_pattern_term
678+ %type <list> row_pattern_definition_list
679+ row_pattern
680+ %type <ival> opt_row_pattern_skip_to
681+ %type <boolean> opt_row_pattern_initial_or_seek
675682
676683/*
677684 * Non-keyword token types. These are hard-wired into the "flex" lexer.
@@ -715,7 +722,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
715722 CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
716723
717724 DATA_P DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
718- DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DEPENDS DEPTH DESC
725+ DEFERRABLE DEFERRED DEFINE DEFINER DELETE_P DELIMITER DELIMITERS DEPENDS DEPTH DESC
719726 DETACH DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P
720727 DOUBLE_P DROP
721728
@@ -731,7 +738,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
731738 HANDLER HAVING HEADER_P HOLD HOUR_P
732739
733740 IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IMPORT_P IN_P INCLUDE
734- INCLUDING INCREMENT INDENT INDEX INDEXES INHERIT INHERITS INITIALLY INLINE_P
741+ INCLUDING INCREMENT INDENT INDEX INDEXES INHERIT INHERITS INITIAL INITIALLY INLINE_P
735742 INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER
736743 INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION
737744
@@ -756,8 +763,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
756763 ORDER ORDINALITY OTHERS OUT_P OUTER_P
757764 OVER OVERLAPS OVERLAY OVERRIDING OWNED OWNER
758765
759- PARALLEL PARAMETER PARSER PARTIAL PARTITION PASSING PASSWORD PATH
760- PERIOD PLACING PLAN PLANS POLICY
766+ PARALLEL PARAMETER PARSER PARTIAL PARTITION PASSING PASSWORD PAST
767+ PATH PATTERN_P PERIOD PLACING PLAN PLANS POLICY
761768 POSITION PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY
762769 PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROCEDURES PROGRAM PUBLICATION
763770
@@ -768,7 +775,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
768775 RESET RESTART RESTRICT RETURN RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP
769776 ROUTINE ROUTINES ROW ROWS RULE
770777
771- SAVEPOINT SCALAR SCHEMA SCHEMAS SCROLL SEARCH SECOND_P SECURITY SELECT
778+ SAVEPOINT SCALAR SCHEMA SCHEMAS SCROLL SEARCH SECOND_P SECURITY SEEK SELECT
772779 SEQUENCE SEQUENCES
773780 SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHOW
774781 SIMILAR SIMPLE SKIP SMALLINT SNAPSHOT SOME SOURCE SQL_P STABLE STANDALONE_P
@@ -851,8 +858,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
851858 * reference point for a precedence level that we can assign to other
852859 * keywords that lack a natural precedence level.
853860 *
854- * We need to do this for PARTITION, RANGE, ROWS, and GROUPS to support
855- * opt_existing_window_name (see comment there).
861+ * We need to do this for PARTITION, RANGE, ROWS, GROUPS, AFTER, INITIAL,
862+ * SEEK, PATTERN_P to support opt_existing_window_name (see comment there).
856863 *
857864 * The frame_bound productions UNBOUNDED PRECEDING and UNBOUNDED FOLLOWING
858865 * are even messier: since UNBOUNDED is an unreserved keyword (per spec!),
@@ -882,6 +889,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
882889%nonassoc UNBOUNDED NESTED /* ideally would have same precedence as IDENT */
883890%nonassoc IDENT PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP
884891 SET KEYS OBJECT_P SCALAR VALUE_P WITH WITHOUT PATH
892+ AFTER INITIAL SEEK PATTERN_P
885893%left Op OPERATOR /* multi-character ops and user-defined operators */
886894%left ' +' ' -'
887895%left ' *' ' /' ' %'
@@ -16476,7 +16484,8 @@ over_clause: OVER window_specification
1647616484 ;
1647716485
1647816486window_specification : ' (' opt_existing_window_name opt_partition_clause
16479- opt_sort_clause opt_frame_clause ' )'
16487+ opt_sort_clause opt_frame_clause
16488+ opt_row_pattern_common_syntax ' )'
1648016489 {
1648116490 WindowDef *n = makeNode(WindowDef);
1648216491
@@ -16488,20 +16497,21 @@ window_specification: '(' opt_existing_window_name opt_partition_clause
1648816497 n->frameOptions = $5 ->frameOptions;
1648916498 n->startOffset = $5 ->startOffset;
1649016499 n->endOffset = $5 ->endOffset;
16500+ n->rpCommonSyntax = (RPCommonSyntax *)$6 ;
1649116501 n->location = @1 ;
1649216502 $$ = n;
1649316503 }
1649416504 ;
1649516505
1649616506/*
16497- * If we see PARTITION, RANGE, ROWS or GROUPS as the first token after the '('
16498- * of a window_specification, we want the assumption to be that there is
16499- * no existing_window_name; but those keywords are unreserved and so could
16500- * be ColIds. We fix this by making them have the same precedence as IDENT
16501- * and giving the empty production here a slightly higher precedence, so
16502- * that the shift/reduce conflict is resolved in favor of reducing the rule.
16503- * These keywords are thus precluded from being an existing_window_name but
16504- * are not reserved for any other purpose.
16507+ * If we see PARTITION, RANGE, ROWS, GROUPS, AFTER, INITIAL, SEEK or PATTERN_P
16508+ * as the first token after the '(' of a window_specification, we want the
16509+ * assumption to be that there is no existing_window_name; but those keywords
16510+ * are unreserved and so could be ColIds. We fix this by making them have the
16511+ * same precedence as IDENT and giving the empty production here a slightly
16512+ * higher precedence, so that the shift/reduce conflict is resolved in favor
16513+ * of reducing the rule. These keywords are thus precluded from being an
16514+ * existing_window_name but are not reserved for any other purpose.
1650516515 */
1650616516opt_existing_window_name : ColId { $$ = $1 ; }
1650716517 | /* EMPTY*/ %prec Op { $$ = NULL ; }
@@ -16670,6 +16680,76 @@ opt_window_exclusion_clause:
1667016680 | /* EMPTY*/ { $$ = 0 ; }
1667116681 ;
1667216682
16683+ opt_row_pattern_common_syntax :
16684+ opt_row_pattern_skip_to opt_row_pattern_initial_or_seek
16685+ PATTERN_P ' (' row_pattern ' )'
16686+ DEFINE row_pattern_definition_list
16687+ {
16688+ RPCommonSyntax *n = makeNode(RPCommonSyntax);
16689+ n->rpSkipTo = $1 ;
16690+ n->initial = $2 ;
16691+ n->rpPatterns = $5 ;
16692+ n->rpDefs = $8 ;
16693+ $$ = (Node *) n;
16694+ }
16695+ | /* EMPTY*/ { $$ = NULL ; }
16696+ ;
16697+
16698+ opt_row_pattern_skip_to :
16699+ AFTER MATCH SKIP TO NEXT ROW
16700+ {
16701+ $$ = ST_NEXT_ROW;
16702+ }
16703+ | AFTER MATCH SKIP PAST LAST_P ROW
16704+ {
16705+ $$ = ST_PAST_LAST_ROW;
16706+ }
16707+ | /* EMPTY*/
16708+ {
16709+ $$ = ST_PAST_LAST_ROW;
16710+ }
16711+ ;
16712+
16713+ opt_row_pattern_initial_or_seek :
16714+ INITIAL { $$ = true ; }
16715+ | SEEK
16716+ {
16717+ ereport (ERROR,
16718+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
16719+ errmsg(" SEEK is not supported" ),
16720+ errhint(" Use INITIAL instead." ),
16721+ parser_errposition(@1 )));
16722+ }
16723+ | /* EMPTY*/ { $$ = true ; }
16724+ ;
16725+
16726+ row_pattern :
16727+ row_pattern_term { $$ = list_make1($1 ); }
16728+ | row_pattern row_pattern_term { $$ = lappend($1 , $2 ); }
16729+ ;
16730+
16731+ row_pattern_term :
16732+ ColId { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, " " , (Node *)makeString($1 ), NULL , @1 ); }
16733+ | ColId ' *' { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, " *" , (Node *)makeString($1 ), NULL , @1 ); }
16734+ | ColId ' +' { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, " +" , (Node *)makeString($1 ), NULL , @1 ); }
16735+ | ColId ' ?' { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, " ?" , (Node *)makeString($1 ), NULL , @1 ); }
16736+ ;
16737+
16738+ row_pattern_definition_list :
16739+ row_pattern_definition { $$ = list_make1($1 ); }
16740+ | row_pattern_definition_list ' ,' row_pattern_definition { $$ = lappend($1 , $3 ); }
16741+ ;
16742+
16743+ row_pattern_definition :
16744+ ColId AS a_expr
16745+ {
16746+ $$ = makeNode(ResTarget);
16747+ $$ ->name = $1 ;
16748+ $$ ->indirection = NIL;
16749+ $$ ->val = (Node *) $3 ;
16750+ $$ ->location = @1 ;
16751+ }
16752+ ;
1667316753
1667416754/*
1667516755 * Supporting nonterminals for expressions.
@@ -17873,6 +17953,7 @@ unreserved_keyword:
1787317953 | INDEXES
1787417954 | INHERIT
1787517955 | INHERITS
17956+ | INITIAL
1787617957 | INLINE_P
1787717958 | INPUT_P
1787817959 | INSENSITIVE
@@ -17946,7 +18027,9 @@ unreserved_keyword:
1794618027 | PARTITION
1794718028 | PASSING
1794818029 | PASSWORD
18030+ | PAST
1794918031 | PATH
18032+ | PATTERN_P
1795018033 | PERIOD
1795118034 | PLAN
1795218035 | PLANS
@@ -17999,6 +18082,7 @@ unreserved_keyword:
1799918082 | SEARCH
1800018083 | SECOND_P
1800118084 | SECURITY
18085+ | SEEK
1800218086 | SEQUENCE
1800318087 | SEQUENCES
1800418088 | SERIALIZABLE
@@ -18221,6 +18305,7 @@ reserved_keyword:
1822118305 | CURRENT_USER
1822218306 | DEFAULT
1822318307 | DEFERRABLE
18308+ | DEFINE
1822418309 | DESC
1822518310 | DISTINCT
1822618311 | DO
@@ -18384,6 +18469,7 @@ bare_label_keyword:
1838418469 | DEFAULTS
1838518470 | DEFERRABLE
1838618471 | DEFERRED
18472+ | DEFINE
1838718473 | DEFINER
1838818474 | DELETE_P
1838918475 | DELIMITER
@@ -18462,6 +18548,7 @@ bare_label_keyword:
1846218548 | INDEXES
1846318549 | INHERIT
1846418550 | INHERITS
18551+ | INITIAL
1846518552 | INITIALLY
1846618553 | INLINE_P
1846718554 | INNER_P
@@ -18573,7 +18660,9 @@ bare_label_keyword:
1857318660 | PARTITION
1857418661 | PASSING
1857518662 | PASSWORD
18663+ | PAST
1857618664 | PATH
18665+ | PATTERN_P
1857718666 | PERIOD
1857818667 | PLACING
1857918668 | PLAN
@@ -18632,6 +18721,7 @@ bare_label_keyword:
1863218721 | SCROLL
1863318722 | SEARCH
1863418723 | SECURITY
18724+ | SEEK
1863518725 | SELECT
1863618726 | SEQUENCE
1863718727 | SEQUENCES
0 commit comments