0001-parser-Add-and_patch.txt

text/plain

Filename: 0001-parser-Add-and_patch.txt
Type: text/plain
Part: 0
Message: Re: Row pattern recognition
From 987a3fce6fb7823b42631658079e8ec2d0b432e4 Mon Sep 17 00:00:00 2001
From: Henson Choi <assam258@gmail.com>
Date: Sat, 3 Jan 2026 19:51:38 +0900
Subject: [PATCH] parser: Add "|" and "{}"

---
 src/backend/parser/gram.y | 27 ++++++++++++++++++++++++++-
 src/backend/parser/scan.l |  4 ++--
 2 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 99c27dc178c..bd7c2820265 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -900,7 +900,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %nonassoc	IDENT PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP
 			SET KEYS OBJECT_P SCALAR VALUE_P WITH WITHOUT PATH
 			AFTER INITIAL SEEK PATTERN_P
-%left		Op OPERATOR		/* multi-character ops and user-defined operators */
+%left		Op OPERATOR '|'	/* multi-character ops and user-defined operators */
 %left		'+' '-'
 %left		'*' '/' '%'
 %left		'^'
@@ -16871,6 +16871,7 @@ opt_row_pattern_initial_or_seek:
 row_pattern:
 			row_pattern_term					{ $$ = list_make1($1); }
 			| row_pattern row_pattern_term		{ $$ = lappend($1, $2); }
+			| row_pattern '|' row_pattern_term	{ $$ = lappend($1, $3); /* TODO: mark as alternation */ }
 		;
 
 row_pattern_term:
@@ -16892,6 +16893,27 @@ row_pattern_term:
 
 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "?", (Node *)makeString($1), NULL, @1);
 				}
+			/* {m} - exactly m times */
+			| ColId '{' Iconst '}'
+				{
+					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "{m}", (Node *)makeString($1), (Node *)makeInteger($3), @1);
+				}
+			/* {m,} - at least m times */
+			| ColId '{' Iconst ',' '}'
+				{
+					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "{m,}", (Node *)makeString($1), (Node *)makeInteger($3), @1);
+				}
+			/* {m,n} - between m and n times */
+			| ColId '{' Iconst ',' Iconst '}'
+				{
+					List *bounds = list_make2(makeInteger($3), makeInteger($5));
+					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "{m,n}", (Node *)makeString($1), (Node *)bounds, @1);
+				}
+			/* {,n} - at most n times (0 to n) */
+			| ColId '{' ',' Iconst '}'
+				{
+					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "{,n}", (Node *)makeString($1), (Node *)makeInteger($4), @1);
+				}
 		;
 
 row_pattern_definition_list:
@@ -16953,12 +16975,15 @@ MathOp:		 '+'									{ $$ = "+"; }
 			| LESS_EQUALS							{ $$ = "<="; }
 			| GREATER_EQUALS						{ $$ = ">="; }
 			| NOT_EQUALS							{ $$ = "<>"; }
+			| '|'									{ $$ = "|"; }
 		;
 
 qual_Op:	Op
 					{ $$ = list_make1(makeString($1)); }
 			| OPERATOR '(' any_operator ')'
 					{ $$ = $3; }
+			| '|'
+					{ $$ = list_make1(makeString("|")); }
 		;
 
 qual_all_Op:
diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l
index a67815339b7..c7b984df34c 100644
--- a/src/backend/parser/scan.l
+++ b/src/backend/parser/scan.l
@@ -363,7 +363,7 @@ not_equals		"!="
  * If you change either set, adjust the character lists appearing in the
  * rule for "operator"!
  */
-self			[,()\[\].;\:\+\-\*\/\%\^\<\>\=]
+self			[,()\[\].;\:\+\-\*\/\%\^\<\>\=\|\{\}]
 op_chars		[\~\!\@\#\^\&\|\`\?\+\-\*\/\%\<\>\=]
 operator		{op_chars}+
 
@@ -955,7 +955,7 @@ other			.
 						 * that the "self" rule would have.
 						 */
 						if (nchars == 1 &&
-							strchr(",()[].;:+-*/%^<>=", yytext[0]))
+							strchr(",()[].;:+-*/%^<>=|{}", yytext[0]))
 							return yytext[0];
 						/*
 						 * Likewise, if what we have left is two chars, and
-- 
2.50.1 (Apple Git-155)