nocfbot-0052-Handle-row-pattern-navigation-nodes-in-exprTypmod.txt
text/plain
Filename: nocfbot-0052-Handle-row-pattern-navigation-nodes-in-exprTypmod.txt
Type: text/plain
Part: 50
Message:
Re: Row pattern recognition
From 8b325c572b63859781879cf645e7eb87521e1118 Mon Sep 17 00:00:00 2001
From: Henson Choi <assam258@gmail.com>
Date: Fri, 5 Jun 2026 16:52:38 +0900
Subject: [PATCH 52/68] Handle row pattern navigation nodes in exprTypmod and
isSimpleNode
RPRNavExpr, the PREV/NEXT/FIRST/LAST navigation node used in a row
pattern DEFINE clause, was missing from two type-helper switches and
fell through to their defaults.
In exprTypmod() the default returns -1, so the argument's typmod was
dropped. A navigation expression evaluates its argument on another row
without changing its type, so its result has the same type and typmod
as the argument; return the argument's typmod, matching how exprType()
already reports its result type.
In isSimpleNode() the default returns false, which made pretty-printing
wrap a navigation operand in redundant parentheses, for example
val > (PREV(val)). A navigation expression deparses as a function-like
FUNC(..) call that already delimits itself, so it is simple and needs
no extra parentheses; add it to the function-like group.
This affects display and node completeness only; execution and
re-parsing were already correct, as the extra parentheses were still
valid SQL. Add a pretty-mode regression using the two-argument
pg_get_viewdef in rpr_base, a path the existing single-argument
navigation tests did not exercise.
---
src/backend/nodes/nodeFuncs.c | 3 +++
src/backend/utils/adt/ruleutils.c | 1 +
src/test/regress/expected/rpr_base.out | 27 ++++++++++++++++++++++++++
src/test/regress/sql/rpr_base.sql | 13 +++++++++++++
4 files changed, 44 insertions(+)
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 101c03b6ae8..aecf4e4da0a 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -392,6 +392,9 @@ exprTypmod(const Node *expr)
return ((const ArrayCoerceExpr *) expr)->resulttypmod;
case T_CollateExpr:
return exprTypmod((Node *) ((const CollateExpr *) expr)->arg);
+ case T_RPRNavExpr:
+ /* result has the same type/typmod as the argument expression */
+ return exprTypmod((Node *) ((const RPRNavExpr *) expr)->arg);
case T_CaseExpr:
{
/*
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 6237080fb36..2b8439e452e 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -9616,6 +9616,7 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
case T_FuncExpr:
case T_JsonConstructorExpr:
case T_JsonExpr:
+ case T_RPRNavExpr:
/* function-like: name(..) or name[..] */
return true;
diff --git a/src/test/regress/expected/rpr_base.out b/src/test/regress/expected/rpr_base.out
index 4fe7360114f..fa6d101f874 100644
--- a/src/test/regress/expected/rpr_base.out
+++ b/src/test/regress/expected/rpr_base.out
@@ -2488,6 +2488,33 @@ SELECT pg_get_viewdef('rpr_serial_nav6'::regclass);
b AS (NEXT(FIRST(val), (3)::bigint) > 0) );
(1 row)
+-- Pretty deparse: navigation calls are function-like and take no extra parens
+CREATE VIEW rpr_nav_pretty_v AS
+SELECT id, val, count(*) OVER w
+FROM rpr_serial
+WINDOW w AS (ORDER BY id
+ ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
+ PATTERN (A B+)
+ DEFINE A AS TRUE,
+ B AS val > PREV(val) AND PREV(val) IS NOT NULL
+ AND NEXT(val) > FIRST(val)
+ AND PREV(FIRST(val)) > 0);
+SELECT pg_get_viewdef('rpr_nav_pretty_v'::regclass, true);
+ 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 (a b+) +
+ DEFINE +
+ a AS true, +
+ b AS val > PREV(val) AND PREV(val) IS NOT NULL AND NEXT(val) > FIRST(val) AND PREV(FIRST(val)) > 0 );
+(1 row)
+
-- Reluctant {1}? quantifier deparse through ruleutils
CREATE VIEW rpr_quant_reluctant_v AS
SELECT id, val, count(*) OVER w
diff --git a/src/test/regress/sql/rpr_base.sql b/src/test/regress/sql/rpr_base.sql
index c6fcfa3e9ff..e0af7199629 100644
--- a/src/test/regress/sql/rpr_base.sql
+++ b/src/test/regress/sql/rpr_base.sql
@@ -1693,6 +1693,19 @@ WINDOW w AS (ORDER BY id
DEFINE A AS TRUE, B AS NEXT(FIRST(val), 3) > 0);
SELECT pg_get_viewdef('rpr_serial_nav6'::regclass);
+-- Pretty deparse: navigation calls are function-like and take no extra parens
+CREATE VIEW rpr_nav_pretty_v AS
+SELECT id, val, count(*) OVER w
+FROM rpr_serial
+WINDOW w AS (ORDER BY id
+ ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
+ PATTERN (A B+)
+ DEFINE A AS TRUE,
+ B AS val > PREV(val) AND PREV(val) IS NOT NULL
+ AND NEXT(val) > FIRST(val)
+ AND PREV(FIRST(val)) > 0);
+SELECT pg_get_viewdef('rpr_nav_pretty_v'::regclass, true);
+
-- Reluctant {1}? quantifier deparse through ruleutils
CREATE VIEW rpr_quant_reluctant_v AS
SELECT id, val, count(*) OVER w
--
2.50.1 (Apple Git-155)