From 73e6e6732dff4515146e1ad4de3d31c67006d8c0 Mon Sep 17 00:00:00 2001 From: Henson Choi Date: Mon, 10 Aug 2026 16:33:49 +0900 Subject: [PATCH] Reject PERMUTE and keep a pattern variable of that name quoted The row pattern permutation is not implemented. Without the keyword the standard spelling PERMUTE (A, B) parses as a pattern variable named permute followed by a group, so it fails with an unrelated complaint about an undefined variable. Add PERMUTE as an unreserved keyword and a grammar rule that rejects it, so the spelling is diagnosed for what it is. That makes permute ambiguous in one position: an unquoted permute followed by "(" is now read as the unsupported syntax. quote_identifier() leaves an unreserved keyword bare, so a pattern variable of that name would deparse into text the parser rejects. Add quote_pattern_variable(), which quotes it, and use it in both the rewriter and the EXPLAIN printer so the two spellings of a pattern agree. A DEFINE entry needs no such treatment, since a name there is always followed by AS and cannot start the construct; the same variable may therefore print bare in DEFINE and quoted in PATTERN. While adding a permute column to the keyword-name table, drop the stray comment above its seek column: nothing in that column list raises an error, and SEEK's own rejection is tested separately. --- doc/src/sgml/ref/select.sgml | 5 +- src/backend/commands/explain.c | 2 +- src/backend/executor/README.rpr | 4 + src/backend/parser/gram.y | 26 +++- src/backend/utils/adt/ruleutils.c | 30 +++- src/include/parser/kwlist.h | 1 + src/include/utils/ruleutils.h | 1 + src/test/regress/expected/rpr_base.out | 187 ++++++++++++++++++++++++- src/test/regress/sql/rpr_base.sql | 119 +++++++++++++++- 9 files changed, 358 insertions(+), 17 deletions(-) diff --git a/doc/src/sgml/ref/select.sgml b/doc/src/sgml/ref/select.sgml index 044c4b6c45a..cb50cc9112a 100644 --- a/doc/src/sgml/ref/select.sgml +++ b/doc/src/sgml/ref/select.sgml @@ -1167,7 +1167,10 @@ DEFINE definition_variable_name AS ??, {n,m}?) are supported. The exclusion ({- and -}) - is not supported. + and the permutation (PERMUTE) are not supported. + PERMUTE is recognized wherever + a ( follows it, so a pattern variable of that name has + to be written "permute" in that position. Patterns can be grouped using parentheses, and alternation (OR) can be expressed using the vertical bar |. For example, (A B)+ matches one or more repetitions diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index b11dc493fdf..aaf865f9961 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -3036,7 +3036,7 @@ deparse_rpr_node(RPRPattern *pattern, int idx, int limit, StringInfo buf) { Assert(elem->varId < pattern->numVars); appendStringInfoString(buf, - quote_identifier(pattern->varNames[elem->varId])); + quote_pattern_variable(pattern->varNames[elem->varId])); append_rpr_quantifier(buf, elem); return idx + 1; } diff --git a/src/backend/executor/README.rpr b/src/backend/executor/README.rpr index c862c28a1a0..c8443a9d831 100644 --- a/src/backend/executor/README.rpr +++ b/src/backend/executor/README.rpr @@ -91,6 +91,10 @@ Example: This pattern matches "a span where prices rise consecutively then drop." +PERMUTE is not supported (the parser raises an error). Its syntax is in the +grammar so that the standard spelling is diagnosed rather than read as a +pattern variable followed by a group; write the alternations out instead. + Chapter II Overall Processing Pipeline ============================================================================ diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index fdd0f2f4ec3..c6878e7850f 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -739,7 +739,7 @@ static bool rpr_is_quantifier_token(const char *tok); row_pattern row_pattern_alt row_pattern_seq row_pattern_term row_pattern_primary row_pattern_quantifier_opt -%type row_pattern_definition_list +%type row_pattern_definition_list row_pattern_permute_list %type opt_row_pattern_skip_to %type opt_row_pattern_initial_or_seek @@ -827,7 +827,7 @@ static bool rpr_is_quantifier_token(const char *tok); OVER OVERLAPS OVERLAY OVERRIDING OWNED OWNER PARALLEL PARAMETER PARSER PARTIAL PARTITION PARTITIONS PASSING PASSWORD PAST PATH - PATTERN_P PERIOD PLACING PLAN PLANS POLICY PORTION + PATTERN_P PERIOD PERMUTE PLACING PLAN PLANS POLICY PORTION POSITION PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROCEDURES PROGRAM PROPERTIES PROPERTY PUBLICATION @@ -951,11 +951,14 @@ static bool rpr_is_quantifier_token(const char *tok); * * Like the UNBOUNDED PRECEDING/FOLLOWING case, NESTED is assigned a lower * precedence than PATH to fix ambiguity in the json_table production. + * + * PERMUTE gets the same treatment as CUBE and ROLLUP, so that PERMUTE '(' + * shifts rather than reducing PERMUTE to a pattern variable. */ %nonassoc UNBOUNDED NESTED /* ideally would have same precedence as IDENT */ %nonassoc IDENT PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP SET KEYS OBJECT_P SCALAR TO USING VALUE_P WITH WITHOUT PATH - AFTER INITIAL_P SEEK PATTERN_P + AFTER INITIAL_P SEEK PATTERN_P PERMUTE %left Op OPERATOR RIGHT_ARROW '|' /* multi-character ops and user-defined operators */ %left '+' '-' %left '*' '/' '%' @@ -17816,6 +17819,21 @@ row_pattern_primary: n->location = @1; $$ = (Node *) n; } + | PERMUTE '(' row_pattern_permute_list ')' + { + ereport(ERROR, + errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("PERMUTE is not supported"), + errhint("Write the alternations out instead, or write \"permute\" to use it as a pattern variable."), + parser_errposition(@1)); + $$ = NULL; /* keep compiler quiet */ + } + ; + +row_pattern_permute_list: + row_pattern { $$ = list_make1($1); } + | row_pattern_permute_list ',' row_pattern + { $$ = lappend($1, $3); } ; row_pattern_quantifier_opt: @@ -19589,6 +19607,7 @@ unreserved_keyword: | PATH | PATTERN_P | PERIOD + | PERMUTE | PLAN | PLANS | POLICY @@ -20238,6 +20257,7 @@ bare_label_keyword: | PATH | PATTERN_P | PERIOD + | PERMUTE | PLACING | PLAN | PLANS diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 2ee9928de2c..d16af6b059c 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -7152,6 +7152,28 @@ append_pattern_quantifier(StringInfo buf, RPRPatternNode *node) } } +/* + * quote_pattern_variable + * Like quote_identifier(), but also quotes PERMUTE. + * + * PERMUTE is unreserved, so quote_identifier() leaves it bare, but a bare + * permute followed by '(' in a PATTERN would be re-read as the unsupported + * PERMUTE syntax. + * + * EXPLAIN deparses the compiled pattern with its own printer, so it calls + * this too; both spellings of a pattern must agree. + */ +const char * +quote_pattern_variable(const char *varName) +{ + const char *result = quote_identifier(varName); + + if (result == varName && strcmp(varName, "permute") == 0) + result = psprintf("\"%s\"", varName); + + return result; +} + /* * Recursive helper to display RPRPatternNode tree */ @@ -7166,7 +7188,7 @@ get_rule_pattern_node(RPRPatternNode *node, deparse_context *context) switch (node->nodeType) { case RPR_PATTERN_VAR: - appendStringInfoString(buf, quote_identifier(node->varName)); + appendStringInfoString(buf, quote_pattern_variable(node->varName)); append_pattern_quantifier(buf, node); break; @@ -7237,6 +7259,12 @@ get_rule_define(List *defineClause, deparse_context *context) */ context->inRPRDefine = true; + /* + * A name here is always followed by AS and so cannot start a PERMUTE + * construct, which is why plain quote_identifier() is enough: the same + * variable may print bare here and quoted in the PATTERN. + */ + foreach_node(TargetEntry, te, defineClause) { appendStringInfo(buf, "%s%s AS ", sep, quote_identifier(te->resname)); diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index d140d5a94a7..cf711d97ec3 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -353,6 +353,7 @@ PG_KEYWORD("past", PAST, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("path", PATH, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("pattern", PATTERN_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("period", PERIOD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("permute", PERMUTE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("plan", PLAN, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD, BARE_LABEL) diff --git a/src/include/utils/ruleutils.h b/src/include/utils/ruleutils.h index 25c05e2f649..b89276554be 100644 --- a/src/include/utils/ruleutils.h +++ b/src/include/utils/ruleutils.h @@ -48,6 +48,7 @@ extern char *get_window_frame_options_for_explain(int frameOptions, Node *endOffset, List *dpcontext, bool forceprefix); +extern const char *quote_pattern_variable(const char *varName); extern char *generate_collation_name(Oid collid); extern char *generate_opclass_name(Oid opclass); extern char *get_range_partbound_string(List *bound_datums); diff --git a/src/test/regress/expected/rpr_base.out b/src/test/regress/expected/rpr_base.out index 7da38b2384a..13ee5628c2e 100644 --- a/src/test/regress/expected/rpr_base.out +++ b/src/test/regress/expected/rpr_base.out @@ -42,24 +42,24 @@ SET client_min_messages = WARNING; -- Keyword Usage Tests -- ============================================================ -- RPR keywords as column names --- Keywords: define, initial, past, pattern, seek +-- Keywords: define, initial, past, pattern, permute, seek CREATE TABLE rpr_keywords ( id INT, define INT, -- DEFINE keyword initial INT, -- INITIAL keyword past INT, -- PAST keyword pattern INT, -- PATTERN keyword + permute INT, -- PERMUTE keyword seek INT, -- SEEK keyword --- ERROR: SEEK is not supported skip INT -- SKIP keyword (pre-existing) ); -INSERT INTO rpr_keywords VALUES (1, 10, 20, 30, 40, 50, 60); -SELECT id, define, initial, past, pattern, seek, skip +INSERT INTO rpr_keywords VALUES (1, 10, 20, 30, 40, 45, 50, 60); +SELECT id, define, initial, past, pattern, permute, seek, skip FROM rpr_keywords ORDER BY id; - id | define | initial | past | pattern | seek | skip -----+--------+---------+------+---------+------+------ - 1 | 10 | 20 | 30 | 40 | 50 | 60 + id | define | initial | past | pattern | permute | seek | skip +----+--------+---------+------+---------+---------+------+------ + 1 | 10 | 20 | 30 | 40 | 45 | 50 | 60 (1 row) DROP TABLE rpr_keywords; @@ -2955,6 +2955,152 @@ LINE 6: SEEK ^ HINT: Use INITIAL instead. DROP TABLE rpr_seek; +-- PERMUTE +CREATE TABLE rpr_permute (id INT, val INT); +INSERT INTO rpr_permute VALUES (1, 10); +-- PERMUTE syntax is recognized, but the feature is not supported +SELECT COUNT(*) OVER w +FROM rpr_permute +WINDOW w AS ( + ORDER BY id + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + PATTERN (PERMUTE(A)) + DEFINE A AS val > 0 +); +ERROR: PERMUTE is not supported +LINE 6: PATTERN (PERMUTE(A)) + ^ +HINT: Write the alternations out instead, or write "permute" to use it as a pattern variable. +-- rejected the same way for a list, and for sub-patterns of any shape +SELECT COUNT(*) OVER w +FROM rpr_permute +WINDOW w AS ( + ORDER BY id + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + PATTERN (PERMUTE(A+ B, C | D)) + DEFINE A AS val > 0, B AS val > 1, C AS val > 2, D AS val > 3 +); +ERROR: PERMUTE is not supported +LINE 6: PATTERN (PERMUTE(A+ B, C | D)) + ^ +HINT: Write the alternations out instead, or write "permute" to use it as a pattern variable. +-- PERMUTE stays unreserved, so it is still usable as a pattern variable +SELECT COUNT(*) OVER w +FROM rpr_permute +WINDOW w AS ( + ORDER BY id + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + PATTERN (PERMUTE A) + DEFINE PERMUTE AS val > 5, A AS val > 0 +); + count +------- + 0 +(1 row) + +-- Except immediately before a group: PERMUTE shifts on "(" whether or not a +-- comma follows, so such a variable lands on the not-supported error, and for +-- that user the alternations advice is beside the point. The hint has to name +-- the way out too. +SELECT COUNT(*) OVER w +FROM rpr_permute +WINDOW w AS ( + ORDER BY id + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + PATTERN (PERMUTE (A | B)) + DEFINE PERMUTE AS val > 5, A AS val > 0, B AS val > 9 +); +ERROR: PERMUTE is not supported +LINE 6: PATTERN (PERMUTE (A | B)) + ^ +HINT: Write the alternations out instead, or write "permute" to use it as a pattern variable. +-- quoted, the same query runs +SELECT COUNT(*) OVER w +FROM rpr_permute +WINDOW w AS ( + ORDER BY id + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + PATTERN ("permute" (A | B)) + DEFINE PERMUTE AS val > 5, A AS val > 0, B AS val > 9 +); + count +------- + 0 +(1 row) + +-- Deparse must quote such a variable, or a view holding one would reparse as +-- the PERMUTE syntax; other variables stay unquoted +CREATE VIEW rpr_permute_v AS + SELECT COUNT(*) OVER w AS cnt FROM rpr_permute + WINDOW w AS ( + ORDER BY id + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + PATTERN ("permute" (A)) + DEFINE PERMUTE AS val > 5, A AS val > 0 + ); +SELECT pg_get_viewdef('rpr_permute_v'::regclass); + pg_get_viewdef +------------------------------------------------------------------------------ + SELECT count(*) OVER w AS cnt + + FROM rpr_permute + + WINDOW w AS (ORDER BY id ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + + AFTER MATCH SKIP PAST LAST ROW + + INITIAL + + PATTERN ("permute" (a)) + + DEFINE + + permute AS (val > 5), + + a AS (val > 0) ); +(1 row) + +-- Quoted even where no group follows: the deparser quotes the name wherever +-- it appears rather than looking ahead for the "(" that would make it +-- ambiguous +CREATE VIEW rpr_permute_v2 AS + SELECT COUNT(*) OVER w AS cnt FROM rpr_permute + WINDOW w AS ( + ORDER BY id + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + PATTERN (PERMUTE A) + DEFINE PERMUTE AS val > 5, A AS val > 0 + ); +SELECT pg_get_viewdef('rpr_permute_v2'::regclass); + pg_get_viewdef +------------------------------------------------------------------------------ + SELECT count(*) OVER w AS cnt + + FROM rpr_permute + + WINDOW w AS (ORDER BY id ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + + AFTER MATCH SKIP PAST LAST ROW + + INITIAL + + PATTERN ("permute" a) + + DEFINE + + permute AS (val > 5), + + a AS (val > 0) ); +(1 row) + +-- EXPLAIN deparses the compiled pattern with a printer of its own, so it has +-- to quote the same names ruleutils does. The alternation keeps the group +-- from being flattened away, which is what puts a "(" after the variable. +EXPLAIN (COSTS OFF) +SELECT COUNT(*) OVER w +FROM rpr_permute +WINDOW w AS ( + ORDER BY id + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + PATTERN ("permute" (A | B)) + DEFINE PERMUTE AS val > 5, A AS val > 0, B AS val > 9 +); + QUERY PLAN +------------------------------------------------------------------------------- + WindowAgg + Window: w AS (ORDER BY id ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + Pattern: "permute" (a | b) + -> Sort + Sort Key: id + -> Seq Scan on rpr_permute +(6 rows) + +DROP VIEW rpr_permute_v, rpr_permute_v2; +DROP TABLE rpr_permute; -- ============================================================ -- Serialization/Deserialization Tests -- ============================================================ @@ -3487,6 +3633,33 @@ SELECT pg_get_viewdef('rpr_serial_quoted'::regclass); "Up" AS (val > PREV(val)) ); (1 row) +-- Quoting the deparser adds on its own: permute is unreserved, so the stored +-- rule holds a plain name and only the deparser knows it has to come back +-- quoted. Restoring this view is what proves it does. +CREATE VIEW rpr_serial_permute AS +SELECT id, val, count(*) OVER w +FROM rpr_serial +WINDOW w AS (ORDER BY id + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + PATTERN ("permute" (A | B)) + DEFINE PERMUTE AS val > 0, A AS val > 10, B AS val > 20); +SELECT pg_get_viewdef('rpr_serial_permute'::regclass); + pg_get_viewdef +------------------------------------------------------------------------------ + SELECT id, + + val, + + count(*) OVER w AS count + + FROM rpr_serial + + WINDOW w AS (ORDER BY id ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + + AFTER MATCH SKIP PAST LAST ROW + + INITIAL + + PATTERN ("permute" (a | b)) + + DEFINE + + permute AS (val > 0), + + a AS (val > 10), + + b AS (val > 20) ); +(1 row) + -- Inline OVER round-trip: inline window spec (no WINDOW alias) deparses inside OVER (...) CREATE VIEW rpr_serial_inline_over AS SELECT id, val, diff --git a/src/test/regress/sql/rpr_base.sql b/src/test/regress/sql/rpr_base.sql index 1ecd329dbfd..f0204fbea39 100644 --- a/src/test/regress/sql/rpr_base.sql +++ b/src/test/regress/sql/rpr_base.sql @@ -45,7 +45,7 @@ SET client_min_messages = WARNING; -- ============================================================ -- RPR keywords as column names --- Keywords: define, initial, past, pattern, seek +-- Keywords: define, initial, past, pattern, permute, seek CREATE TABLE rpr_keywords ( id INT, @@ -53,14 +53,14 @@ CREATE TABLE rpr_keywords ( initial INT, -- INITIAL keyword past INT, -- PAST keyword pattern INT, -- PATTERN keyword + permute INT, -- PERMUTE keyword seek INT, -- SEEK keyword --- ERROR: SEEK is not supported skip INT -- SKIP keyword (pre-existing) ); -INSERT INTO rpr_keywords VALUES (1, 10, 20, 30, 40, 50, 60); +INSERT INTO rpr_keywords VALUES (1, 10, 20, 30, 40, 45, 50, 60); -SELECT id, define, initial, past, pattern, seek, skip +SELECT id, define, initial, past, pattern, permute, seek, skip FROM rpr_keywords ORDER BY id; @@ -2025,6 +2025,105 @@ WINDOW w AS ( DROP TABLE rpr_seek; +-- PERMUTE + +CREATE TABLE rpr_permute (id INT, val INT); +INSERT INTO rpr_permute VALUES (1, 10); + +-- PERMUTE syntax is recognized, but the feature is not supported +SELECT COUNT(*) OVER w +FROM rpr_permute +WINDOW w AS ( + ORDER BY id + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + PATTERN (PERMUTE(A)) + DEFINE A AS val > 0 +); + +-- rejected the same way for a list, and for sub-patterns of any shape +SELECT COUNT(*) OVER w +FROM rpr_permute +WINDOW w AS ( + ORDER BY id + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + PATTERN (PERMUTE(A+ B, C | D)) + DEFINE A AS val > 0, B AS val > 1, C AS val > 2, D AS val > 3 +); + +-- PERMUTE stays unreserved, so it is still usable as a pattern variable +SELECT COUNT(*) OVER w +FROM rpr_permute +WINDOW w AS ( + ORDER BY id + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + PATTERN (PERMUTE A) + DEFINE PERMUTE AS val > 5, A AS val > 0 +); + +-- Except immediately before a group: PERMUTE shifts on "(" whether or not a +-- comma follows, so such a variable lands on the not-supported error, and for +-- that user the alternations advice is beside the point. The hint has to name +-- the way out too. +SELECT COUNT(*) OVER w +FROM rpr_permute +WINDOW w AS ( + ORDER BY id + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + PATTERN (PERMUTE (A | B)) + DEFINE PERMUTE AS val > 5, A AS val > 0, B AS val > 9 +); + +-- quoted, the same query runs +SELECT COUNT(*) OVER w +FROM rpr_permute +WINDOW w AS ( + ORDER BY id + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + PATTERN ("permute" (A | B)) + DEFINE PERMUTE AS val > 5, A AS val > 0, B AS val > 9 +); + +-- Deparse must quote such a variable, or a view holding one would reparse as +-- the PERMUTE syntax; other variables stay unquoted +CREATE VIEW rpr_permute_v AS + SELECT COUNT(*) OVER w AS cnt FROM rpr_permute + WINDOW w AS ( + ORDER BY id + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + PATTERN ("permute" (A)) + DEFINE PERMUTE AS val > 5, A AS val > 0 + ); +SELECT pg_get_viewdef('rpr_permute_v'::regclass); + +-- Quoted even where no group follows: the deparser quotes the name wherever +-- it appears rather than looking ahead for the "(" that would make it +-- ambiguous +CREATE VIEW rpr_permute_v2 AS + SELECT COUNT(*) OVER w AS cnt FROM rpr_permute + WINDOW w AS ( + ORDER BY id + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + PATTERN (PERMUTE A) + DEFINE PERMUTE AS val > 5, A AS val > 0 + ); +SELECT pg_get_viewdef('rpr_permute_v2'::regclass); + +-- EXPLAIN deparses the compiled pattern with a printer of its own, so it has +-- to quote the same names ruleutils does. The alternation keeps the group +-- from being flattened away, which is what puts a "(" after the variable. +EXPLAIN (COSTS OFF) +SELECT COUNT(*) OVER w +FROM rpr_permute +WINDOW w AS ( + ORDER BY id + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + PATTERN ("permute" (A | B)) + DEFINE PERMUTE AS val > 5, A AS val > 0, B AS val > 9 +); + +DROP VIEW rpr_permute_v, rpr_permute_v2; +DROP TABLE rpr_permute; + -- ============================================================ -- Serialization/Deserialization Tests -- ============================================================ @@ -2258,6 +2357,18 @@ WINDOW w AS (ORDER BY id DEFINE "Start" AS TRUE, "Up" AS val > PREV(val)); SELECT pg_get_viewdef('rpr_serial_quoted'::regclass); +-- Quoting the deparser adds on its own: permute is unreserved, so the stored +-- rule holds a plain name and only the deparser knows it has to come back +-- quoted. Restoring this view is what proves it does. +CREATE VIEW rpr_serial_permute AS +SELECT id, val, count(*) OVER w +FROM rpr_serial +WINDOW w AS (ORDER BY id + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + PATTERN ("permute" (A | B)) + DEFINE PERMUTE AS val > 0, A AS val > 10, B AS val > 20); +SELECT pg_get_viewdef('rpr_serial_permute'::regclass); + -- Inline OVER round-trip: inline window spec (no WINDOW alias) deparses inside OVER (...) CREATE VIEW rpr_serial_inline_over AS SELECT id, val,