On Sat, 09 Dec 2023 07:22:58 +0900 (JST) Tatsuo Ishii <is...@sraoss.co.jp> wrote:
> > On 04.12.23 12:40, Tatsuo Ishii wrote: > >> diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y > >> index d631ac89a9..5a77fca17f 100644 > >> --- a/src/backend/parser/gram.y > >> +++ b/src/backend/parser/gram.y > >> @@ -251,6 +251,8 @@ static Node *makeRecursiveViewSelect(char > >> *relname, List *aliases, Node *query); > >> DefElem *defelt; > >> SortBy *sortby; > >> WindowDef *windef; > >> + RPCommonSyntax *rpcom; > >> + RPSubsetItem *rpsubset; > >> JoinExpr *jexpr; > >> IndexElem *ielem; > >> StatsElem *selem; > >> @@ -278,6 +280,7 @@ static Node *makeRecursiveViewSelect(char > >> *relname, List *aliases, Node *query); > >> MergeWhenClause *mergewhen; > >> struct KeyActions *keyactions; > >> struct KeyAction *keyaction; > >> + RPSkipTo skipto; > >> } > >> %type <node> stmt toplevel_stmt schema_stmt routine_body_stmt > > > > It is usually not the style to add an entry for every node type to the > > %union. Otherwise, we'd have hundreds of entries in there. > > Ok, I have removed the node types and used existing node types. Also > I have moved RPR related %types to same place to make it easier to know > what are added by RPR. > > >> @@ -866,6 +878,7 @@ static Node *makeRecursiveViewSelect(char > >> *relname, List *aliases, Node *query); > >> %nonassoc UNBOUNDED /* ideally would have same precedence as IDENT */ > >> %nonassoc IDENT PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE > >> %ROLLUP > >> SET KEYS OBJECT_P SCALAR VALUE_P WITH WITHOUT > >> +%nonassoc MEASURES AFTER INITIAL SEEK PATTERN_P > >> %left Op OPERATOR /* multi-character ops and user-defined operators */ > >> %left '+' '-' > >> %left '*' '/' '%' > > > > It was recently discussed that these %nonassoc should ideally all have > > the same precedence. Did you consider that here? > > No, I didn't realize it. Thanks for pointing it out. I have removed > %nonassoc so that MEASURES etc. have the same precedence as IDENT etc. > > Attached is the new diff of gram.y against master branch. Thank you very much for providing the patch for the RPR implementation. After applying the v12-patches, I noticed an issue that the rpr related parts in window clauses were not displayed in the view definitions (the definition column of pg_views). To address this, I have taken the liberty of adding an additional patch that modifies the relevant rewriter source code. I have attached the rewriter patch for your review and would greatly appreciate your feedback. Thank you for your time and consideration. -- SRA OSS LLC Ningwei Chen <c...@sraoss.co.jp> TEL: 03-5979-2701 FAX: 03-5979-2702
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 0b2a164057..baded88201 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -428,6 +428,10 @@ static void get_rule_groupingset(GroupingSet *gset, List *targetlist, bool omit_parens, deparse_context *context); static void get_rule_orderby(List *orderList, List *targetList, bool force_colno, deparse_context *context); +static void get_rule_pattern(List *patternVariable, List *patternRegexp, + bool force_colno, deparse_context *context); +static void get_rule_define(List *defineClause, List *patternVariables, + bool force_colno, deparse_context *context); static void get_rule_windowclause(Query *query, deparse_context *context); static void get_rule_windowspec(WindowClause *wc, List *targetList, deparse_context *context); @@ -6459,6 +6463,64 @@ get_rule_orderby(List *orderList, List *targetList, } } +/* + * Display a PATTERN clause. + */ +static void +get_rule_pattern(List *patternVariable, List *patternRegexp, + bool force_colno, deparse_context *context) +{ + StringInfo buf = context->buf; + const char *sep; + ListCell *lc_var, *lc_reg = list_head(patternRegexp); + + sep = ""; + appendStringInfoChar(buf, '('); + foreach(lc_var, patternVariable) + { + char *variable = strVal((String *) lfirst(lc_var)); + char *regexp = NULL; + + if (lc_reg != NULL) + { + regexp = strVal((String *) lfirst(lc_reg)); + lc_reg = lnext(patternRegexp, lc_reg); + } + + appendStringInfo(buf, "%s%s", sep, variable); + if (regexp != NULL) + appendStringInfoString(buf, regexp); + + sep = " "; + } + appendStringInfoChar(buf, ')'); +} + +/* + * Display a DEFINE clause. + */ +static void +get_rule_define(List *defineClause, List *patternVariables, + bool force_colno, deparse_context *context) +{ + StringInfo buf = context->buf; + const char *sep; + ListCell *lc_var, *lc_def; + + sep = " "; + Assert(list_length(patternVariables) == list_length(defineClause)); + + forboth(lc_var, patternVariables, lc_def, defineClause) + { + char *varName = strVal(lfirst(lc_var)); + TargetEntry *te = (TargetEntry *) lfirst(lc_def); + + appendStringInfo(buf, "%s%s AS ", sep, varName); + get_rule_expr((Node *) te->expr, context, false); + sep = ",\n "; + } +} + /* * Display a WINDOW clause. * @@ -6596,6 +6658,34 @@ get_rule_windowspec(WindowClause *wc, List *targetList, appendStringInfoString(buf, "EXCLUDE GROUP "); else if (wc->frameOptions & FRAMEOPTION_EXCLUDE_TIES) appendStringInfoString(buf, "EXCLUDE TIES "); + /* RPR */ + if (wc->rpSkipTo == ST_NEXT_ROW) + appendStringInfoString(buf, "\n AFTER MATCH SKIP TO NEXT ROW "); + else if (wc->rpSkipTo == ST_PAST_LAST_ROW) + appendStringInfoString(buf, "\n AFTER MATCH SKIP PAST LAST ROW "); + else if (wc->rpSkipTo == ST_FIRST_VARIABLE) + appendStringInfo(buf, "\n AFTER MATCH SKIP TO FIRST %s ", wc->rpSkipVariable); + else if (wc->rpSkipTo == ST_LAST_VARIABLE) + appendStringInfo(buf, "\n AFTER MATCH SKIP TO LAST %s ", wc->rpSkipVariable); + else if (wc->rpSkipTo == ST_VARIABLE) + appendStringInfo(buf, "\n AFTER MATCH SKIP TO %s ", wc->rpSkipVariable); + + if (wc->initial) + appendStringInfoString(buf, "\n INITIAL"); + + if (wc->patternVariable) + { + appendStringInfoString(buf, "\n PATTERN "); + get_rule_pattern(wc->patternVariable, wc->patternRegexp, false, context); + } + + if (wc->defineClause) + { + appendStringInfoString(buf, "\n DEFINE\n"); + get_rule_define(wc->defineClause, wc->patternVariable, false, context); + appendStringInfoChar(buf, ' '); + } + /* we will now have a trailing space; remove it */ buf->len--; } diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index 2b4c36a15f..104c0105c5 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -3851,6 +3851,9 @@ transformRPR(ParseState *pstate, WindowClause *wc, WindowDef *windef, List **tar /* Transform AFTER MACH SKIP TO clause */ wc->rpSkipTo = windef->rpCommonSyntax->rpSkipTo; + /* Transform AFTER MACH SKIP TO variable */ + wc->rpSkipVariable = windef->rpCommonSyntax->rpSkipVariable; + /* Transform SEEK or INITIAL clause */ wc->initial = windef->rpCommonSyntax->initial; diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 5a9b162463..64e9df0a48 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1554,6 +1554,7 @@ typedef struct WindowClause bool copiedOrder pg_node_attr(query_jumble_ignore); /* Row Pattern AFTER MACH SKIP clause */ RPSkipTo rpSkipTo; /* Row Pattern Skip To type */ + char *rpSkipVariable;/* Row Pattern Skip To variable */ bool initial; /* true if <row pattern initial or seek> is initial */ /* Row Pattern DEFINE clause (list of TargetEntry) */ List *defineClause;