From 8619013d84705785c57b311438f25fc7d4f94017 Mon Sep 17 00:00:00 2001
From: Ewan Young <kdbase.hack@gmail.com>
Date: Wed, 17 Jun 2026 00:40:40 +0800
Subject: [PATCH v1] Reject aggregates, window functions, and SRFs in
 GRAPH_TABLE COLUMNS

The COLUMNS list of a GRAPH_TABLE query was parsed with
EXPR_KIND_SELECT_TARGET, which permits aggregate functions, window
functions, and set-returning functions.  GRAPH_TABLE has no machinery
to evaluate them, though: the rewriter copies the COLUMNS target list
verbatim into a freshly built subquery whose hasAggs/hasWindowFuncs
flags are never set, so the planner builds no Agg/WindowAgg node and
the Aggref/WindowFunc reaches the executor.  This triggers an assertion
failure ("ecxt_aggvalues != NULL"), or "Aggref found in non-Agg plan
node" on a non-assert build, for otherwise parser-accepted SQL such as

    SELECT max(c) FROM GRAPH_TABLE
        (g MATCH (x IS v) COLUMNS (count(*) AS c));

Introduce a dedicated expression kind, EXPR_KIND_GRAPH_TABLE_COLUMNS,
and reject aggregates, grouping operations, window functions, and
set-returning functions there, as is done for other clauses that cannot
support them.  Column-reference and subquery handling is unchanged
(subqueries are still rejected as before).
---
 src/backend/parser/parse_agg.c            | 10 ++++++++++
 src/backend/parser/parse_clause.c         |  2 +-
 src/backend/parser/parse_expr.c           |  4 ++++
 src/backend/parser/parse_func.c           |  3 +++
 src/backend/parser/parse_graphtable.c     |  2 +-
 src/include/parser/parse_node.h           |  1 +
 src/test/regress/expected/graph_table.out | 13 +++++++++++++
 src/test/regress/sql/graph_table.sql      |  4 ++++
 8 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index acb933392de..2f26092c9ec 100644
--- a/src/backend/parser/parse_agg.c
+++ b/src/backend/parser/parse_agg.c
@@ -599,6 +599,13 @@ check_agglevels_and_constraints(ParseState *pstate, Node *expr)
 				err = _("grouping operations are not allowed in property definition expressions");
 
 			break;
+		case EXPR_KIND_GRAPH_TABLE_COLUMNS:
+			if (isAgg)
+				err = _("aggregate functions are not allowed in GRAPH_TABLE COLUMNS");
+			else
+				err = _("grouping operations are not allowed in GRAPH_TABLE COLUMNS");
+
+			break;
 
 			/*
 			 * There is intentionally no default: case here, so that the
@@ -1042,6 +1049,9 @@ transformWindowFuncCall(ParseState *pstate, WindowFunc *wfunc,
 		case EXPR_KIND_PROPGRAPH_PROPERTY:
 			err = _("window functions are not allowed in property definition expressions");
 			break;
+		case EXPR_KIND_GRAPH_TABLE_COLUMNS:
+			err = _("window functions are not allowed in GRAPH_TABLE COLUMNS");
+			break;
 		case EXPR_KIND_FOR_PORTION:
 			err = _("window functions are not allowed in FOR PORTION OF expressions");
 			break;
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 5fe5257b019..26945b4f0b5 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -981,7 +981,7 @@ transformRangeGraphTable(ParseState *pstate, RangeGraphTable *rgt)
 		TargetEntry *te;
 		char	   *colname;
 
-		colexpr = transformExpr(pstate, rt->val, EXPR_KIND_SELECT_TARGET);
+		colexpr = transformExpr(pstate, rt->val, EXPR_KIND_GRAPH_TABLE_COLUMNS);
 
 		if (rt->name)
 			colname = rt->name;
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 9adc9d4c0f6..f7571d5e3d0 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -578,6 +578,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
 		case EXPR_KIND_COPY_WHERE:
 		case EXPR_KIND_GENERATED_COLUMN:
 		case EXPR_KIND_CYCLE_MARK:
+		case EXPR_KIND_GRAPH_TABLE_COLUMNS:
 		case EXPR_KIND_PROPGRAPH_PROPERTY:
 			/* okay */
 			break;
@@ -1843,6 +1844,7 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
 		case EXPR_KIND_VALUES:
 		case EXPR_KIND_VALUES_SINGLE:
 		case EXPR_KIND_CYCLE_MARK:
+		case EXPR_KIND_GRAPH_TABLE_COLUMNS:
 			/* okay */
 			break;
 		case EXPR_KIND_CHECK_CONSTRAINT:
@@ -3253,6 +3255,8 @@ ParseExprKindName(ParseExprKind exprKind)
 			return "CYCLE";
 		case EXPR_KIND_PROPGRAPH_PROPERTY:
 			return "property definition expression";
+		case EXPR_KIND_GRAPH_TABLE_COLUMNS:
+			return "GRAPH_TABLE COLUMNS";
 		case EXPR_KIND_FOR_PORTION:
 			return "FOR PORTION OF";
 
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 2e4cc1de50d..0b08714ae2f 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -2787,6 +2787,9 @@ check_srf_call_placement(ParseState *pstate, Node *last_srf, int location)
 		case EXPR_KIND_PROPGRAPH_PROPERTY:
 			err = _("set-returning functions are not allowed in property definition expressions");
 			break;
+		case EXPR_KIND_GRAPH_TABLE_COLUMNS:
+			err = _("set-returning functions are not allowed in GRAPH_TABLE COLUMNS");
+			break;
 		case EXPR_KIND_FOR_PORTION:
 			err = _("set-returning functions are not allowed in FOR PORTION OF expressions");
 			break;
diff --git a/src/backend/parser/parse_graphtable.c b/src/backend/parser/parse_graphtable.c
index 73fbfb541f7..8ddf183bbb5 100644
--- a/src/backend/parser/parse_graphtable.c
+++ b/src/backend/parser/parse_graphtable.c
@@ -92,7 +92,7 @@ transformGraphTablePropertyRef(ParseState *pstate, ColumnRef *cref)
 
 		if (IsA(field1, A_Star) || IsA(field2, A_Star))
 		{
-			if (pstate->p_expr_kind == EXPR_KIND_SELECT_TARGET)
+			if (pstate->p_expr_kind == EXPR_KIND_GRAPH_TABLE_COLUMNS)
 				ereport(ERROR,
 						errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 						errmsg("\"*\" is not supported here"),
diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h
index f7f4ba6c2a8..c98f87a4f31 100644
--- a/src/include/parser/parse_node.h
+++ b/src/include/parser/parse_node.h
@@ -84,6 +84,7 @@ typedef enum ParseExprKind
 	EXPR_KIND_GENERATED_COLUMN, /* generation expression for a column */
 	EXPR_KIND_CYCLE_MARK,		/* cycle mark value */
 	EXPR_KIND_PROPGRAPH_PROPERTY,	/* derived property expression */
+	EXPR_KIND_GRAPH_TABLE_COLUMNS,	/* GRAPH_TABLE COLUMNS expression */
 } ParseExprKind;
 
 
diff --git a/src/test/regress/expected/graph_table.out b/src/test/regress/expected/graph_table.out
index 70d986e8ab0..9701086ef0f 100644
--- a/src/test/regress/expected/graph_table.out
+++ b/src/test/regress/expected/graph_table.out
@@ -455,6 +455,19 @@ SELECT * FROM GRAPH_TABLE (myshop MATCH (c IS customers WHERE c.* IS NOT NULL)-[
 ERROR:  "*" not allowed here
 LINE 1: ...M GRAPH_TABLE (myshop MATCH (c IS customers WHERE c.* IS NOT...
                                                              ^
+-- aggregate, window, and set-returning functions are not allowed in COLUMNS
+SELECT * FROM GRAPH_TABLE (myshop MATCH (c IS customers) COLUMNS (count(*) AS num));
+ERROR:  aggregate functions are not allowed in GRAPH_TABLE COLUMNS
+LINE 1: ...APH_TABLE (myshop MATCH (c IS customers) COLUMNS (count(*) A...
+                                                             ^
+SELECT * FROM GRAPH_TABLE (myshop MATCH (c IS customers) COLUMNS (row_number() OVER () AS rn));
+ERROR:  window functions are not allowed in GRAPH_TABLE COLUMNS
+LINE 1: ...APH_TABLE (myshop MATCH (c IS customers) COLUMNS (row_number...
+                                                             ^
+SELECT * FROM GRAPH_TABLE (myshop MATCH (c IS customers) COLUMNS (generate_series(1, 2) AS gs));
+ERROR:  set-returning functions are not allowed in GRAPH_TABLE COLUMNS
+LINE 1: ...APH_TABLE (myshop MATCH (c IS customers) COLUMNS (generate_s...
+                                                             ^
 -- consecutive element patterns with same kind
 SELECT * FROM GRAPH_TABLE (g1 MATCH ()() COLUMNS (1 as one));
 ERROR:  adjacent vertex patterns are not supported
diff --git a/src/test/regress/sql/graph_table.sql b/src/test/regress/sql/graph_table.sql
index 0b44f70d7e7..04a01e9c365 100644
--- a/src/test/regress/sql/graph_table.sql
+++ b/src/test/regress/sql/graph_table.sql
@@ -302,6 +302,10 @@ SELECT * FROM GRAPH_TABLE (g1 MATCH (src IS el1 | vl1)-[conn]->(dest) COLUMNS (c
 SELECT * FROM GRAPH_TABLE (myshop MATCH (c IS customers WHERE c.address = 'US')-[IS customer_orders]->(o IS orders) COLUMNS (c.*));
 -- star anywhere else is not allowed as a property reference
 SELECT * FROM GRAPH_TABLE (myshop MATCH (c IS customers WHERE c.* IS NOT NULL)-[IS customer_orders]->(o IS orders) COLUMNS (c.name));
+-- aggregate, window, and set-returning functions are not allowed in COLUMNS
+SELECT * FROM GRAPH_TABLE (myshop MATCH (c IS customers) COLUMNS (count(*) AS num));
+SELECT * FROM GRAPH_TABLE (myshop MATCH (c IS customers) COLUMNS (row_number() OVER () AS rn));
+SELECT * FROM GRAPH_TABLE (myshop MATCH (c IS customers) COLUMNS (generate_series(1, 2) AS gs));
 -- consecutive element patterns with same kind
 SELECT * FROM GRAPH_TABLE (g1 MATCH ()() COLUMNS (1 as one));
 SELECT * FROM GRAPH_TABLE (g1 MATCH -> COLUMNS (1 AS one));
-- 
2.47.3

