From 3e5b4e74ca179c92126f668c3391a8cff3edacb2 Mon Sep 17 00:00:00 2001 From: waterWang <672684719@qq.com> Date: Sun, 23 Aug 2026 20:43:55 +0800 Subject: [PATCH] fix: exclude internal VLE helper vars from RETURN * expansion (#2540) When a variable-length edge pattern assigns internal helper column names via create_unique_name(AGE_DEFAULT_PREFIX"vle_function_{start,end}_var") in cypher_gram.y, those columns land in the namespace and are picked up by RETURN * expansion (ExpandAllTables -> expand_pnsi_attrs). The SRF is then invoked with one column more than the caller's column definition list declares, producing: ERROR: return row and column definition list do not match e.g. MATCH p = ()-[*1]->(n:End {id: 2}) RETURN * AS (p agtype, n agtype) Filter out the internal VLE helper columns in expand_pnsi_attrs the same way hidden vars/aliases are already excluded. Regression-tested with make installcheck: 41/43 pass (age_load/age_upgrade fail for pre-existing environment reasons unrelated to this change). --- src/backend/parser/cypher_item.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/backend/parser/cypher_item.c b/src/backend/parser/cypher_item.c index c2feb2720..90db06172 100644 --- a/src/backend/parser/cypher_item.c +++ b/src/backend/parser/cypher_item.c @@ -183,6 +183,7 @@ static List *expand_pnsi_attrs(ParseState *pstate, ParseNamespaceItem *pnsi, List *te_list = NIL; int var_prefix_len = strlen(AGE_DEFAULT_VARNAME_PREFIX); int alias_prefix_len = strlen(AGE_DEFAULT_ALIAS_PREFIX); + int vle_prefix_len = strlen(AGE_DEFAULT_PREFIX "vle_function_"); vars = expandNSItemVars(pstate, pnsi, sublevels_up, location, &names); @@ -212,6 +213,16 @@ static List *expand_pnsi_attrs(ParseState *pstate, ParseNamespaceItem *pnsi, if (strncmp(AGE_DEFAULT_ALIAS_PREFIX, label, alias_prefix_len) == 0) continue; + /* + * Skip the internal VLE helper columns (created in cypher_gram.y via + * create_unique_name(AGE_DEFAULT_PREFIX"vle_function_{start,end}_var")). + * These feed the vle() SRF's start/end bound vars and are visible in + * the namespace, but they are implementation details and must not show + * up in RETURN * projections alongside the user's variables. + */ + if (strncmp(AGE_DEFAULT_PREFIX "vle_function_", label, vle_prefix_len) == 0) + continue; + /* add this variable to the list */ te = makeTargetEntry((Expr *)varnode, (AttrNumber)pstate->p_next_resno++, label, false);