This is an automated email from the ASF dual-hosted git repository.
mtaha pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/age.git
The following commit(s) were added to refs/heads/master by this push:
new 56a92d8c Fix Issue 1884: Ambiguous column reference (#2306)
56a92d8c is described below
commit 56a92d8c1be364e07bac51665a362ca91957194b
Author: John Gemignani <[email protected]>
AuthorDate: Sun Jan 18 10:02:55 2026 -0800
Fix Issue 1884: Ambiguous column reference (#2306)
Fix Issue 1884: Ambiguous column reference and invalid AGT header
errors.
Note: This PR was created with AI tools and a human, or 2.
This commit addresses two related bugs that occur when using SET to store
graph elements (vertices, edges, paths) as property values:
Issue 1884 - "column reference is ambiguous" error:
When a Cypher query uses the same variable in both the SET expression RHS
and the RETURN clause (e.g., SET n.prop = n RETURN n), PostgreSQL would
report "column reference is ambiguous" because the variable appeared in
multiple subqueries without proper qualification.
Solution: The fix for this issue was already in place through the target
entry naming scheme that qualifies column references.
"Invalid AGT header value" offset error:
When deserializing nested VERTEX, EDGE, or PATH values stored in properties,
the system would fail with errors like "Invalid AGT header value:
0x00000041".
This occurred because ag_serialize_extended_type() did not include alignment
padding (padlen) in the agtentry length calculation for these types, while
fill_agtype_value() uses INTALIGN() when reading, causing offset mismatch.
Solution: Modified ag_serialize_extended_type() in agtype_ext.c to include
padlen in the agtentry length for VERTEX, EDGE, and PATH cases, matching
the existing pattern used for INTEGER, FLOAT, and NUMERIC types:
*agtentry = AGTENTRY_IS_AGTYPE | (padlen + (AGTENTRY_OFFLENMASK & ...));
This ensures the serialized length accounts for alignment padding, allowing
correct deserialization of nested graph elements.
Appropriate regression tests were added to verify the fixes.
Co-authored by: Zainab Saad <[email protected]>
modified: regress/expected/cypher_set.out
modified: regress/sql/cypher_set.sql
modified: src/backend/parser/cypher_clause.c
modified: src/backend/utils/adt/agtype_ext.c
---
regress/expected/cypher_set.out | 266 +++++++++++++++++++++++++++++++++++++
regress/sql/cypher_set.sql | 164 +++++++++++++++++++++++
src/backend/parser/cypher_clause.c | 19 ++-
src/backend/utils/adt/agtype_ext.c | 8 +-
4 files changed, 451 insertions(+), 6 deletions(-)
diff --git a/regress/expected/cypher_set.out b/regress/expected/cypher_set.out
index 1d24a7f9..239234ed 100644
--- a/regress/expected/cypher_set.out
+++ b/regress/expected/cypher_set.out
@@ -988,6 +988,245 @@ SELECT * FROM cypher('issue_1634', $$ MATCH (u) DELETE
(u) $$) AS (u agtype);
---
(0 rows)
+--
+-- Issue 1884: column reference is ambiguous when using same variable in
+-- SET expression and RETURN clause
+--
+-- These tests cover:
+-- 1. "column reference is ambiguous" error when variable is used in both
+-- SET expression RHS (e.g., SET n.prop = n) and RETURN clause
+-- 2. "Invalid AGT header value" error caused by incorrect offset calculation
+-- when nested VERTEX/EDGE/PATH values are serialized in properties
+--
+-- Tests use isolated data to keep output manageable and avoid cumulative
nesting
+--
+SELECT * FROM create_graph('issue_1884');
+NOTICE: graph "issue_1884" has been created
+ create_graph
+--------------
+
+(1 row)
+
+-- ============================================================================
+-- Test Group A: Basic "column reference is ambiguous" fix (Issue 1884)
+-- ============================================================================
+-- Test A1: Core issue - SET n.prop = n with RETURN n (the original bug)
+SELECT * FROM cypher('issue_1884', $$
+ CREATE (n:TestA1 {name: 'A1'})
+ SET n.self = n
+ RETURN n
+$$) AS (result agtype);
+
result
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ {"id": 844424930131969, "label": "TestA1", "properties": {"name": "A1",
"self": {"id": 844424930131969, "label": "TestA1", "properties": {"name":
"A1"}}::vertex}}::vertex
+(1 row)
+
+-- Test A2: Multiple variables in SET and RETURN
+SELECT * FROM cypher('issue_1884', $$
+ CREATE (a:TestA2 {name: 'A'})-[e:LINK {w: 1}]->(b:TestA2 {name: 'B'})
+ SET a.edge = e, b.edge = e
+ RETURN a, e, b
+$$) AS (a agtype, e agtype, b agtype);
+
a
|
e
|
b
[...]
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------
[...]
+ {"id": 1125899906842625, "label": "TestA2", "properties": {"edge": {"id":
1407374883553281, "label": "LINK", "end_id": 1125899906842626, "start_id":
1125899906842625, "properties": {"w": 1}}::edge, "name": "A"}}::vertex | {"id":
1407374883553281, "label": "LINK", "end_id": 1125899906842626, "start_id":
1125899906842625, "properties": {"w": 1}}::edge | {"id": 1125899906842626,
"label": "TestA2", "properties": {"edge": {"id": 1407374883553281, "label":
"LINK", "end_id": 1125899906842626, [...]
+(1 row)
+
+-- Test A3: SET edge property to node reference
+SELECT * FROM cypher('issue_1884', $$
+ CREATE (a:TestA3 {name: 'X'})-[e:REL]->(b:TestA3 {name: 'Y'})
+ SET e.src = a, e.dst = b
+ RETURN e
+$$) AS (e agtype);
+
e
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ {"id": 1970324836974593, "label": "REL", "end_id": 1688849860263938,
"start_id": 1688849860263937, "properties": {"dst": {"id": 1688849860263938,
"label": "TestA3", "properties": {"name": "Y"}}::vertex, "src": {"id":
1688849860263937, "label": "TestA3", "properties": {"name":
"X"}}::vertex}}::edge
+(1 row)
+
+-- ============================================================================
+-- Test Group B: Nested VERTEX/EDGE/PATH serialization (offset error fix)
+-- ============================================================================
+-- Test B1: Vertex nested in vertex property (tests VERTEX serialization)
+SELECT * FROM cypher('issue_1884', $$
+ CREATE (n:TestB1 {val: 1})
+ SET n.copy = n
+ RETURN n
+$$) AS (result agtype);
+
result
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ {"id": 2251799813685249, "label": "TestB1", "properties": {"val": 1, "copy":
{"id": 2251799813685249, "label": "TestB1", "properties": {"val":
1}}::vertex}}::vertex
+(1 row)
+
+-- Verify nested vertex can be read back
+SELECT * FROM cypher('issue_1884', $$
+ MATCH (n:TestB1)
+ RETURN n.copy
+$$) AS (copy agtype);
+ copy
+-------------------------------------------------------------------------------
+ {"id": 2251799813685249, "label": "TestB1", "properties": {"val": 1}}::vertex
+(1 row)
+
+-- Test B2: Edge nested in node property (tests EDGE serialization)
+SELECT * FROM cypher('issue_1884', $$
+ CREATE (a:TestB2 {name: 'start'})-[e:B2REL {x: 100}]->(b:TestB2 {name:
'end'})
+ SET a.myEdge = e
+ RETURN a
+$$) AS (a agtype);
+
a
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ {"id": 2533274790395905, "label": "TestB2", "properties": {"name": "start",
"myEdge": {"id": 2814749767106561, "label": "B2REL", "end_id":
2533274790395906, "start_id": 2533274790395905, "properties": {"x":
100}}::edge}}::vertex
+(1 row)
+
+-- Verify nested edge can be read back
+SELECT * FROM cypher('issue_1884', $$
+ MATCH (n:TestB2 {name: 'start'})
+ RETURN n.myEdge
+$$) AS (edge agtype);
+ edge
+--------------------------------------------------------------------------------------------------------------------------------------
+ {"id": 2814749767106561, "label": "B2REL", "end_id": 2533274790395906,
"start_id": 2533274790395905, "properties": {"x": 100}}::edge
+(1 row)
+
+-- Test B3: Path nested in node property (tests PATH serialization)
+-- First create the pattern
+SELECT * FROM cypher('issue_1884', $$
+ CREATE (a:TestB3)-[e:B3REL]->(b:TestB3)
+ RETURN a
+$$) AS (a agtype);
+ a
+-----------------------------------------------------------------------
+ {"id": 3096224743817217, "label": "TestB3", "properties": {}}::vertex
+(1 row)
+
+-- Then match the path and set it (MATCH only sees committed data)
+SELECT * FROM cypher('issue_1884', $$
+ MATCH p = (a:TestB3)-[e:B3REL]->(b:TestB3)
+ SET a.myPath = p
+ RETURN a
+$$) AS (a agtype);
+
a
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ {"id": 3096224743817217, "label": "TestB3", "properties": {"myPath": [{"id":
3096224743817217, "label": "TestB3", "properties": {}}::vertex, {"id":
3377699720527873, "label": "B3REL", "end_id": 3096224743817218, "start_id":
3096224743817217, "properties": {}}::edge, {"id": 3096224743817218, "label":
"TestB3", "properties": {}}::vertex]::path}}::vertex
+(1 row)
+
+-- Verify nested path can be read back
+SELECT * FROM cypher('issue_1884', $$
+ MATCH (n:TestB3)
+ WHERE n.myPath IS NOT NULL
+ RETURN n.myPath
+$$) AS (path agtype);
+
path
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ [{"id": 3096224743817217, "label": "TestB3", "properties": {}}::vertex,
{"id": 3377699720527873, "label": "B3REL", "end_id": 3096224743817218,
"start_id": 3096224743817217, "properties": {}}::edge, {"id": 3096224743817218,
"label": "TestB3", "properties": {}}::vertex]::path
+(1 row)
+
+-- ============================================================================
+-- Test Group C: Nested structures in arrays and maps
+-- ============================================================================
+-- Test C1: Vertex in array
+SELECT * FROM cypher('issue_1884', $$
+ CREATE (n:TestC1 {tag: 'arrtest'})
+ SET n.arr = [n]
+ RETURN n
+$$) AS (result agtype);
+
result
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ {"id": 3659174697238529, "label": "TestC1", "properties": {"arr": [{"id":
3659174697238529, "label": "TestC1", "properties": {"tag":
"arrtest"}}::vertex], "tag": "arrtest"}}::vertex
+(1 row)
+
+-- Verify array with nested vertex
+SELECT * FROM cypher('issue_1884', $$
+ MATCH (n:TestC1)
+ RETURN n.arr[0]
+$$) AS (elem agtype);
+ elem
+---------------------------------------------------------------------------------------
+ {"id": 3659174697238529, "label": "TestC1", "properties": {"tag":
"arrtest"}}::vertex
+(1 row)
+
+-- Test C2: Vertex in map
+SELECT * FROM cypher('issue_1884', $$
+ CREATE (n:TestC2 {tag: 'maptest'})
+ SET n.obj = {node: n}
+ RETURN n
+$$) AS (result agtype);
+
result
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ {"id": 3940649673949185, "label": "TestC2", "properties": {"obj": {"node":
{"id": 3940649673949185, "label": "TestC2", "properties": {"tag":
"maptest"}}::vertex}, "tag": "maptest"}}::vertex
+(1 row)
+
+-- Verify map with nested vertex
+SELECT * FROM cypher('issue_1884', $$
+ MATCH (n:TestC2)
+ RETURN n.obj.node
+$$) AS (node agtype);
+ node
+---------------------------------------------------------------------------------------
+ {"id": 3940649673949185, "label": "TestC2", "properties": {"tag":
"maptest"}}::vertex
+(1 row)
+
+-- ============================================================================
+-- Test Group D: MERGE and CREATE with self-reference
+-- ============================================================================
+-- Test D1: MERGE with SET self-reference
+SELECT * FROM cypher('issue_1884', $$
+ MERGE (n:TestD1 {name: 'merged'})
+ SET n.ref = n
+ RETURN n
+$$) AS (result agtype);
+
result
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ {"id": 4222124650659841, "label": "TestD1", "properties": {"ref": {"id":
4222124650659841, "label": "TestD1", "properties": {"name": "merged"}}::vertex,
"name": "merged"}}::vertex
+(1 row)
+
+-- Test D2: CREATE with SET self-reference
+SELECT * FROM cypher('issue_1884', $$
+ CREATE (n:TestD2 {name: 'created'})
+ SET n.ref = n
+ RETURN n
+$$) AS (result agtype);
+
result
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ {"id": 4503599627370497, "label": "TestD2", "properties": {"ref": {"id":
4503599627370497, "label": "TestD2", "properties": {"name":
"created"}}::vertex, "name": "created"}}::vertex
+(1 row)
+
+-- ============================================================================
+-- Test Group E: Functions with variable references
+-- ============================================================================
+-- Test E1: id() and label() functions
+SELECT * FROM cypher('issue_1884', $$
+ CREATE (n:TestE1 {name: 'functest'})
+ SET n.myId = id(n), n.myLabel = label(n)
+ RETURN n
+$$) AS (result agtype);
+ result
+----------------------------------------------------------------------------------------------------------------------------------------
+ {"id": 4785074604081153, "label": "TestE1", "properties": {"myId":
4785074604081153, "name": "functest", "myLabel": "TestE1"}}::vertex
+(1 row)
+
+-- Test E2: nodes() and relationships() with path
+-- First create the pattern
+SELECT * FROM cypher('issue_1884', $$
+ CREATE (a:TestE2)-[e:E2REL]->(b:TestE2)
+ RETURN a
+$$) AS (a agtype);
+ a
+-----------------------------------------------------------------------
+ {"id": 5066549580791809, "label": "TestE2", "properties": {}}::vertex
+(1 row)
+
+-- Then match the path and extract nodes/relationships (MATCH only sees
committed data)
+SELECT * FROM cypher('issue_1884', $$
+ MATCH p = (a:TestE2)-[e:E2REL]->(b:TestE2)
+ SET a.pathNodes = nodes(p), a.pathRels = relationships(p)
+ RETURN a
+$$) AS (a agtype);
+
a
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ {"id": 5066549580791809, "label": "TestE2", "properties": {"pathRels":
[{"id": 5348024557502465, "label": "E2REL", "end_id": 5066549580791810,
"start_id": 5066549580791809, "properties": {}}::edge], "pathNodes": [{"id":
5066549580791809, "label": "TestE2", "properties": {}}::vertex, {"id":
5066549580791810, "label": "TestE2", "properties": {}}::vertex]}}::vertex
+(1 row)
+
--
-- Clean up
--
@@ -1038,6 +1277,33 @@ NOTICE: graph "issue_1634" has been dropped
(1 row)
+SELECT drop_graph('issue_1884', true);
+NOTICE: drop cascades to 19 other objects
+DETAIL: drop cascades to table issue_1884._ag_label_vertex
+drop cascades to table issue_1884._ag_label_edge
+drop cascades to table issue_1884."TestA1"
+drop cascades to table issue_1884."TestA2"
+drop cascades to table issue_1884."LINK"
+drop cascades to table issue_1884."TestA3"
+drop cascades to table issue_1884."REL"
+drop cascades to table issue_1884."TestB1"
+drop cascades to table issue_1884."TestB2"
+drop cascades to table issue_1884."B2REL"
+drop cascades to table issue_1884."TestB3"
+drop cascades to table issue_1884."B3REL"
+drop cascades to table issue_1884."TestC1"
+drop cascades to table issue_1884."TestC2"
+drop cascades to table issue_1884."TestD1"
+drop cascades to table issue_1884."TestD2"
+drop cascades to table issue_1884."TestE1"
+drop cascades to table issue_1884."TestE2"
+drop cascades to table issue_1884."E2REL"
+NOTICE: graph "issue_1884" has been dropped
+ drop_graph
+------------
+
+(1 row)
+
--
-- End
--
diff --git a/regress/sql/cypher_set.sql b/regress/sql/cypher_set.sql
index a2667153..e745d5d6 100644
--- a/regress/sql/cypher_set.sql
+++ b/regress/sql/cypher_set.sql
@@ -379,6 +379,169 @@ SELECT * FROM cypher('issue_1634', $$ MERGE (v:PERSION
{id: '1'})
SELECT * FROM cypher('issue_1634', $$ MATCH (u) DELETE (u) $$) AS (u agtype);
+--
+-- Issue 1884: column reference is ambiguous when using same variable in
+-- SET expression and RETURN clause
+--
+-- These tests cover:
+-- 1. "column reference is ambiguous" error when variable is used in both
+-- SET expression RHS (e.g., SET n.prop = n) and RETURN clause
+-- 2. "Invalid AGT header value" error caused by incorrect offset calculation
+-- when nested VERTEX/EDGE/PATH values are serialized in properties
+--
+-- Tests use isolated data to keep output manageable and avoid cumulative
nesting
+--
+SELECT * FROM create_graph('issue_1884');
+
+-- ============================================================================
+-- Test Group A: Basic "column reference is ambiguous" fix (Issue 1884)
+-- ============================================================================
+
+-- Test A1: Core issue - SET n.prop = n with RETURN n (the original bug)
+SELECT * FROM cypher('issue_1884', $$
+ CREATE (n:TestA1 {name: 'A1'})
+ SET n.self = n
+ RETURN n
+$$) AS (result agtype);
+
+-- Test A2: Multiple variables in SET and RETURN
+SELECT * FROM cypher('issue_1884', $$
+ CREATE (a:TestA2 {name: 'A'})-[e:LINK {w: 1}]->(b:TestA2 {name: 'B'})
+ SET a.edge = e, b.edge = e
+ RETURN a, e, b
+$$) AS (a agtype, e agtype, b agtype);
+
+-- Test A3: SET edge property to node reference
+SELECT * FROM cypher('issue_1884', $$
+ CREATE (a:TestA3 {name: 'X'})-[e:REL]->(b:TestA3 {name: 'Y'})
+ SET e.src = a, e.dst = b
+ RETURN e
+$$) AS (e agtype);
+
+-- ============================================================================
+-- Test Group B: Nested VERTEX/EDGE/PATH serialization (offset error fix)
+-- ============================================================================
+
+-- Test B1: Vertex nested in vertex property (tests VERTEX serialization)
+SELECT * FROM cypher('issue_1884', $$
+ CREATE (n:TestB1 {val: 1})
+ SET n.copy = n
+ RETURN n
+$$) AS (result agtype);
+
+-- Verify nested vertex can be read back
+SELECT * FROM cypher('issue_1884', $$
+ MATCH (n:TestB1)
+ RETURN n.copy
+$$) AS (copy agtype);
+
+-- Test B2: Edge nested in node property (tests EDGE serialization)
+SELECT * FROM cypher('issue_1884', $$
+ CREATE (a:TestB2 {name: 'start'})-[e:B2REL {x: 100}]->(b:TestB2 {name:
'end'})
+ SET a.myEdge = e
+ RETURN a
+$$) AS (a agtype);
+
+-- Verify nested edge can be read back
+SELECT * FROM cypher('issue_1884', $$
+ MATCH (n:TestB2 {name: 'start'})
+ RETURN n.myEdge
+$$) AS (edge agtype);
+
+-- Test B3: Path nested in node property (tests PATH serialization)
+-- First create the pattern
+SELECT * FROM cypher('issue_1884', $$
+ CREATE (a:TestB3)-[e:B3REL]->(b:TestB3)
+ RETURN a
+$$) AS (a agtype);
+
+-- Then match the path and set it (MATCH only sees committed data)
+SELECT * FROM cypher('issue_1884', $$
+ MATCH p = (a:TestB3)-[e:B3REL]->(b:TestB3)
+ SET a.myPath = p
+ RETURN a
+$$) AS (a agtype);
+
+-- Verify nested path can be read back
+SELECT * FROM cypher('issue_1884', $$
+ MATCH (n:TestB3)
+ WHERE n.myPath IS NOT NULL
+ RETURN n.myPath
+$$) AS (path agtype);
+
+-- ============================================================================
+-- Test Group C: Nested structures in arrays and maps
+-- ============================================================================
+
+-- Test C1: Vertex in array
+SELECT * FROM cypher('issue_1884', $$
+ CREATE (n:TestC1 {tag: 'arrtest'})
+ SET n.arr = [n]
+ RETURN n
+$$) AS (result agtype);
+
+-- Verify array with nested vertex
+SELECT * FROM cypher('issue_1884', $$
+ MATCH (n:TestC1)
+ RETURN n.arr[0]
+$$) AS (elem agtype);
+
+-- Test C2: Vertex in map
+SELECT * FROM cypher('issue_1884', $$
+ CREATE (n:TestC2 {tag: 'maptest'})
+ SET n.obj = {node: n}
+ RETURN n
+$$) AS (result agtype);
+
+-- Verify map with nested vertex
+SELECT * FROM cypher('issue_1884', $$
+ MATCH (n:TestC2)
+ RETURN n.obj.node
+$$) AS (node agtype);
+
+-- ============================================================================
+-- Test Group D: MERGE and CREATE with self-reference
+-- ============================================================================
+
+-- Test D1: MERGE with SET self-reference
+SELECT * FROM cypher('issue_1884', $$
+ MERGE (n:TestD1 {name: 'merged'})
+ SET n.ref = n
+ RETURN n
+$$) AS (result agtype);
+
+-- Test D2: CREATE with SET self-reference
+SELECT * FROM cypher('issue_1884', $$
+ CREATE (n:TestD2 {name: 'created'})
+ SET n.ref = n
+ RETURN n
+$$) AS (result agtype);
+
+-- ============================================================================
+-- Test Group E: Functions with variable references
+-- ============================================================================
+
+-- Test E1: id() and label() functions
+SELECT * FROM cypher('issue_1884', $$
+ CREATE (n:TestE1 {name: 'functest'})
+ SET n.myId = id(n), n.myLabel = label(n)
+ RETURN n
+$$) AS (result agtype);
+
+-- Test E2: nodes() and relationships() with path
+-- First create the pattern
+SELECT * FROM cypher('issue_1884', $$
+ CREATE (a:TestE2)-[e:E2REL]->(b:TestE2)
+ RETURN a
+$$) AS (a agtype);
+
+-- Then match the path and extract nodes/relationships (MATCH only sees
committed data)
+SELECT * FROM cypher('issue_1884', $$
+ MATCH p = (a:TestE2)-[e:E2REL]->(b:TestE2)
+ SET a.pathNodes = nodes(p), a.pathRels = relationships(p)
+ RETURN a
+$$) AS (a agtype);
+
--
-- Clean up
--
@@ -387,6 +550,7 @@ DROP FUNCTION set_test;
SELECT drop_graph('cypher_set', true);
SELECT drop_graph('cypher_set_1', true);
SELECT drop_graph('issue_1634', true);
+SELECT drop_graph('issue_1884', true);
--
-- End
diff --git a/src/backend/parser/cypher_clause.c
b/src/backend/parser/cypher_clause.c
index a5413bda..515f8c1d 100644
--- a/src/backend/parser/cypher_clause.c
+++ b/src/backend/parser/cypher_clause.c
@@ -71,6 +71,7 @@
#define AGE_VARNAME_MERGE_CLAUSE AGE_DEFAULT_VARNAME_PREFIX"merge_clause"
#define AGE_VARNAME_ID AGE_DEFAULT_VARNAME_PREFIX"id"
#define AGE_VARNAME_SET_CLAUSE AGE_DEFAULT_VARNAME_PREFIX"set_clause"
+#define AGE_VARNAME_SET_VALUE AGE_DEFAULT_VARNAME_PREFIX"set_value"
/*
* In the transformation stage, we need to track
@@ -1911,10 +1912,24 @@ cypher_update_information
*transform_cypher_set_item_list(
((cypher_map*)set_item->expr)->keep_null = set_item->is_add;
}
- /* create target entry for the new property value */
+ /*
+ * Create target entry for the new property value.
+ *
+ * We use a hidden variable name (AGE_VARNAME_SET_VALUE) for the
+ * SET expression value to prevent column name conflicts. This is
+ * necessary when the same variable is used on both the LHS and RHS
+ * of a SET clause (e.g., SET n.prop = n). Without this, the column
+ * name derived from the expression (e.g., "n") would duplicate the
+ * existing column name from the MATCH clause, causing a "column
+ * reference is ambiguous" error in subsequent clauses like RETURN.
+ *
+ * The hidden variable name will be filtered out by expand_pnsi_attrs
+ * when the targetlist is expanded for subsequent clauses.
+ */
item->prop_position = (AttrNumber)pstate->p_next_resno;
target_item = transform_cypher_item(cpstate, set_item->expr, NULL,
- EXPR_KIND_SELECT_TARGET, NULL,
+ EXPR_KIND_SELECT_TARGET,
+ AGE_VARNAME_SET_VALUE,
false);
if (nodeTag(target_item->expr) == T_Aggref)
diff --git a/src/backend/utils/adt/agtype_ext.c
b/src/backend/utils/adt/agtype_ext.c
index 8fc6600d..7a0ea991 100644
--- a/src/backend/utils/adt/agtype_ext.c
+++ b/src/backend/utils/adt/agtype_ext.c
@@ -89,7 +89,7 @@ bool ag_serialize_extended_type(StringInfo buffer, agtentry
*agtentry,
object_ae += pad_buffer_to_int(buffer);
*agtentry = AGTENTRY_IS_AGTYPE |
- ((AGTENTRY_OFFLENMASK & (int)object_ae) + AGT_HEADER_SIZE);
+ (padlen + (AGTENTRY_OFFLENMASK & (int)object_ae) +
AGT_HEADER_SIZE);
break;
}
@@ -109,7 +109,7 @@ bool ag_serialize_extended_type(StringInfo buffer, agtentry
*agtentry,
object_ae += pad_buffer_to_int(buffer);
*agtentry = AGTENTRY_IS_AGTYPE |
- ((AGTENTRY_OFFLENMASK & (int)object_ae) + AGT_HEADER_SIZE);
+ (padlen + (AGTENTRY_OFFLENMASK & (int)object_ae) +
AGT_HEADER_SIZE);
break;
}
@@ -129,7 +129,7 @@ bool ag_serialize_extended_type(StringInfo buffer, agtentry
*agtentry,
object_ae += pad_buffer_to_int(buffer);
*agtentry = AGTENTRY_IS_AGTYPE |
- ((AGTENTRY_OFFLENMASK & (int)object_ae) + AGT_HEADER_SIZE);
+ (padlen + (AGTENTRY_OFFLENMASK & (int)object_ae) +
AGT_HEADER_SIZE);
break;
}
@@ -175,7 +175,7 @@ void ag_deserialize_extended_type(char *base_addr, uint32
offset,
break;
default:
- elog(ERROR, "Invalid AGT header value.");
+ ereport(ERROR, (errmsg("Invalid AGT header value: 0x%08x",
agt_header)));
}
}