From 8619013d84705785c57b311438f25fc7d4f94017 Mon Sep 17 00:00:00 2001 From: Ewan Young 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