v41-0003-Row-pattern-recognition-patch-rewriter.patch
application/octet-stream
Filename: v41-0003-Row-pattern-recognition-patch-rewriter.patch
Type: application/octet-stream
Part: 2
Message:
Re: Row pattern recognition
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v41-0003
Subject: Row pattern recognition patch (rewriter).
| File | + | − |
|---|---|---|
| src/backend/utils/adt/ruleutils.c | 172 | 0 |
From bf056619b91c64b198624d21d86b31cb238b699f Mon Sep 17 00:00:00 2001
From: Tatsuo Ishii <ishii@postgresql.org>
Date: Tue, 20 Jan 2026 19:00:01 +0900
Subject: [PATCH v41 3/8] Row pattern recognition patch (rewriter).
---
src/backend/utils/adt/ruleutils.c | 172 ++++++++++++++++++++++++++++++
1 file changed, 172 insertions(+)
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 033b625f3fc..89cf8f2f1ad 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -438,6 +438,12 @@ 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 append_pattern_quantifier(StringInfo buf, RPRPatternNode *node);
+static void get_rule_pattern_node(RPRPatternNode *node, deparse_context *context);
+static void get_rule_pattern(RPRPatternNode *rpPattern, bool force_colno,
+ deparse_context *context);
+static void get_rule_define(List *defineClause, 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);
@@ -6744,6 +6750,127 @@ get_rule_orderby(List *orderList, List *targetList,
}
}
+/*
+ * Helper function to append quantifier string for pattern node
+ */
+static void
+append_pattern_quantifier(StringInfo buf, RPRPatternNode *node)
+{
+ bool has_quantifier = true;
+
+ if (node->min == 1 && node->max == 1)
+ {
+ /* {1,1} = no quantifier */
+ has_quantifier = false;
+ }
+ else if (node->min == 0 && node->max == INT_MAX)
+ appendStringInfoChar(buf, '*');
+ else if (node->min == 1 && node->max == INT_MAX)
+ appendStringInfoChar(buf, '+');
+ else if (node->min == 0 && node->max == 1)
+ appendStringInfoChar(buf, '?');
+ else if (node->max == INT_MAX)
+ appendStringInfo(buf, "{%d,}", node->min);
+ else if (node->min == node->max)
+ appendStringInfo(buf, "{%d}", node->min);
+ else
+ appendStringInfo(buf, "{%d,%d}", node->min, node->max);
+
+ if (node->reluctant && has_quantifier)
+ appendStringInfoChar(buf, '?');
+}
+
+/*
+ * Recursive helper to display RPRPatternNode tree
+ */
+static void
+get_rule_pattern_node(RPRPatternNode *node, deparse_context *context)
+{
+ StringInfo buf = context->buf;
+ ListCell *lc;
+ const char *sep;
+
+ if (node == NULL)
+ return;
+
+ switch (node->nodeType)
+ {
+ case RPR_PATTERN_VAR:
+ appendStringInfoString(buf, node->varName);
+ append_pattern_quantifier(buf, node);
+ break;
+
+ case RPR_PATTERN_SEQ:
+ sep = "";
+ foreach(lc, node->children)
+ {
+ appendStringInfoString(buf, sep);
+ get_rule_pattern_node((RPRPatternNode *) lfirst(lc), context);
+ sep = " ";
+ }
+ break;
+
+ case RPR_PATTERN_ALT:
+ sep = "";
+ foreach(lc, node->children)
+ {
+ appendStringInfoString(buf, sep);
+ get_rule_pattern_node((RPRPatternNode *) lfirst(lc), context);
+ sep = " | ";
+ }
+ break;
+
+ case RPR_PATTERN_GROUP:
+ appendStringInfoChar(buf, '(');
+ sep = "";
+ foreach(lc, node->children)
+ {
+ appendStringInfoString(buf, sep);
+ get_rule_pattern_node((RPRPatternNode *) lfirst(lc), context);
+ sep = " ";
+ }
+ appendStringInfoChar(buf, ')');
+ append_pattern_quantifier(buf, node);
+ break;
+ }
+}
+
+/*
+ * Display a PATTERN clause.
+ */
+static void
+get_rule_pattern(RPRPatternNode *rpPattern, bool force_colno,
+ deparse_context *context)
+{
+ StringInfo buf = context->buf;
+
+ appendStringInfoChar(buf, '(');
+ get_rule_pattern_node(rpPattern, context);
+ appendStringInfoChar(buf, ')');
+}
+
+/*
+ * Display a DEFINE clause.
+ */
+static void
+get_rule_define(List *defineClause, bool force_colno, deparse_context *context)
+{
+ StringInfo buf = context->buf;
+ const char *sep;
+ ListCell *lc_def;
+
+ sep = " ";
+
+ foreach(lc_def, defineClause)
+ {
+ TargetEntry *te = (TargetEntry *) lfirst(lc_def);
+
+ appendStringInfo(buf, "%s%s AS ", sep, te->resname);
+ get_rule_expr((Node *) te->expr, context, false);
+ sep = ",\n ";
+ }
+}
+
/*
* Display a WINDOW clause.
*
@@ -6824,6 +6951,7 @@ get_rule_windowspec(WindowClause *wc, List *targetList,
get_rule_orderby(wc->orderClause, targetList, false, context);
needspace = true;
}
+
/* framing clause is never inherited, so print unless it's default */
if (wc->frameOptions & FRAMEOPTION_NONDEFAULT)
{
@@ -6832,7 +6960,51 @@ get_rule_windowspec(WindowClause *wc, List *targetList,
get_window_frame_options(wc->frameOptions,
wc->startOffset, wc->endOffset,
context);
+ needspace = true;
+ }
+
+ /* RPR */
+ if (wc->rpSkipTo == ST_NEXT_ROW)
+ {
+ if (needspace)
+ appendStringInfoChar(buf, ' ');
+ appendStringInfoString(buf,
+ "\n AFTER MATCH SKIP TO NEXT ROW ");
+ needspace = true;
+ }
+ else if (wc->rpSkipTo == ST_PAST_LAST_ROW)
+ {
+ if (needspace)
+ appendStringInfoChar(buf, ' ');
+ appendStringInfoString(buf,
+ "\n AFTER MATCH SKIP PAST LAST ROW ");
+ needspace = true;
+ }
+ if (wc->initial)
+ {
+ if (needspace)
+ appendStringInfoChar(buf, ' ');
+ appendStringInfoString(buf, "\n INITIAL");
+ needspace = true;
}
+ if (wc->rpPattern)
+ {
+ if (needspace)
+ appendStringInfoChar(buf, ' ');
+ appendStringInfoString(buf, "\n PATTERN ");
+ get_rule_pattern(wc->rpPattern, false, context);
+ needspace = true;
+ }
+
+ if (wc->defineClause)
+ {
+ if (needspace)
+ appendStringInfoChar(buf, ' ');
+ appendStringInfoString(buf, "\n DEFINE\n");
+ get_rule_define(wc->defineClause, false, context);
+ appendStringInfoChar(buf, ' ');
+ }
+
appendStringInfoChar(buf, ')');
}
--
2.43.0