From 91ff58c56ec8f57aafe39210460cc33ae0c3349d Mon Sep 17 00:00:00 2001 From: Alex Kwak Date: Mon, 27 Feb 2023 15:26:04 +0900 Subject: [PATCH] fix: Columns not visible when using a VLE. (#609) --- src/backend/parser/parse_graph.c | 57 ++++++++----------- src/test/regress/expected/cypher_dml.out | 68 +++++++++++------------ src/test/regress/expected/cypher_dml2.out | 43 ++++++++++++++ src/test/regress/sql/cypher_dml2.sql | 6 ++ 4 files changed, 105 insertions(+), 69 deletions(-) diff --git a/src/backend/parser/parse_graph.c b/src/backend/parser/parse_graph.c index 738fa8f18a2..57ff4b45437 100644 --- a/src/backend/parser/parse_graph.c +++ b/src/backend/parser/parse_graph.c @@ -184,8 +184,7 @@ static ParseNamespaceItem *transformMatchVLE(ParseState *pstate, List **targetList, bool pathout); static SelectStmt *genVLESubselect(ParseState *pstate, CypherRel *crel, bool out, bool pathout); -static Node *genVLELeftChild(ParseState *pstate, CypherRel *crel, - bool out, bool pathout); +static Node *genVLELeftChild(ParseState *pstate, CypherRel *crel, bool out); static Node *genEdgeSimple(char *aliasname); static Node *genVLEEdgeSubselect(ParseState *pstate, CypherRel *crel, char *aliasname); @@ -1916,7 +1915,7 @@ transformMatchNode(ParseState *pstate, CypherNode *cnode, List **targetList, /* set `ihn` to true because we should scan all derived tables */ nsitem = addRangeTableEntry(pstate, r, alias, r->inh, true); - addNSItemToJoinlist(pstate, nsitem, false); + addNSItemToJoinlist(pstate, nsitem, true); if (varname != NULL || prop_constr) { @@ -2302,6 +2301,8 @@ genVLESubselect(ParseState *pstate, CypherRel *crel, bool out, bool pathout) List *tlist; Node *left; SelectStmt *sel; + Node *vertices_col; + ResTarget *vertices; prev_colname = getEdgeColname(crel, false); prev_col = makeColumnRef(genQualifiedName(VLE_LEFT_ALIAS, prev_colname)); @@ -2328,19 +2329,13 @@ genVLESubselect(ParseState *pstate, CypherRel *crel, bool out, bool pathout) tlist = lappend(tlist, edges); } - if (pathout) - { - Node *vertices_col; - ResTarget *vertices; - - vertices_col = makeColumnRef(genQualifiedName(VLE_LEFT_ALIAS, - VLE_COLNAME_VERTICES)); - vertices = makeResTarget(vertices_col, VLE_COLNAME_VERTICES); - - tlist = lappend(tlist, vertices); - } - - left = genVLELeftChild(pstate, crel, out, pathout); + /* Add Vertices Column */ + vertices_col = makeColumnRef(genQualifiedName(VLE_LEFT_ALIAS, + VLE_COLNAME_VERTICES)); + vertices = makeResTarget(vertices_col, VLE_COLNAME_VERTICES); + tlist = lappend(tlist, vertices); + + left = genVLELeftChild(pstate, crel, out); sel = makeNode(SelectStmt); sel->targetList = tlist; @@ -2395,7 +2390,7 @@ genVLESubselect(ParseState *pstate, CypherRel *crel, bool out, bool pathout) * AS l(start, "end", ids, edges, vertices) */ static Node * -genVLELeftChild(ParseState *pstate, CypherRel *crel, bool out, bool pathout) +genVLELeftChild(ParseState *pstate, CypherRel *crel, bool out) { Node *vid; List *colnames = NIL; @@ -2411,6 +2406,7 @@ genVLELeftChild(ParseState *pstate, CypherRel *crel, bool out, bool pathout) if (isZeroLengthVLE(crel)) { + Node *vtxarr = makeAArrayExpr(NIL, VERTEXARRAYOID); Node *ids; List *values; @@ -2431,13 +2427,8 @@ genVLELeftChild(ParseState *pstate, CypherRel *crel, bool out, bool pathout) colnames = lappend(colnames, makeString(VLE_COLNAME_EDGES)); } - if (pathout) - { - Node *vtxarr = makeAArrayExpr(NIL, VERTEXARRAYOID); - - values = lappend(values, vtxarr); - colnames = lappend(colnames, makeString(VLE_COLNAME_VERTICES)); - } + values = lappend(values, vtxarr); + colnames = lappend(colnames, makeString(VLE_COLNAME_VERTICES)); sel = makeNode(SelectStmt); sel->valuesLists = list_make1(values); @@ -2454,6 +2445,8 @@ genVLELeftChild(ParseState *pstate, CypherRel *crel, bool out, bool pathout) List *tlist = NIL; Node *from; List *where_args = NIL; + ResTarget *vertices; + TypeCast *cast = makeNode(TypeCast); prev_colname = genQualifiedName(NULL, getEdgeColname(crel, false)); prev_col = makeColumnRef(prev_colname); @@ -2478,18 +2471,12 @@ genVLELeftChild(ParseState *pstate, CypherRel *crel, bool out, bool pathout) tlist = lappend(tlist, edges); } - if (pathout) - { - ResTarget *vertices; - TypeCast *cast = makeNode(TypeCast); - - cast->arg = (Node *) makeNullAConst(); - cast->typeName = makeTypeNameFromOid(VERTEXARRAYOID, -1); - cast->location = -1; - vertices = makeResTarget((Node *) cast, VLE_COLNAME_VERTICES); + cast->arg = (Node *) makeNullAConst(); + cast->typeName = makeTypeNameFromOid(VERTEXARRAYOID, -1); + cast->location = -1; + vertices = makeResTarget((Node *) cast, VLE_COLNAME_VERTICES); - tlist = lappend(tlist, vertices); - } + tlist = lappend(tlist, vertices); if (vid != NULL) { diff --git a/src/test/regress/expected/cypher_dml.out b/src/test/regress/expected/cypher_dml.out index ccf09ecd8a6..1e618a2ff38 100644 --- a/src/test/regress/expected/cypher_dml.out +++ b/src/test/regress/expected/cypher_dml.out @@ -1379,8 +1379,8 @@ RETURN x1, x2, l; EXPLAIN (VERBOSE, COSTS OFF) MATCH (a:person {id: 1})-[x:knows*1..2]->(b:person) WITH x[0] AS x1, x[1] AS x2 ORDER BY x2 RETURN x1; - QUERY PLAN ------------------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------- Subquery Scan on _ Output: _.x1 -> Sort @@ -1395,10 +1395,10 @@ WITH x[0] AS x1, x[1] AS x2 ORDER BY x2 RETURN x1; Output: a.id, a.properties Filter: (a.properties.'id'::text = '1'::jsonb) -> Subquery Scan on x - Output: x.start, x."end", x.ids, x.edges + Output: x.start, x."end", x.ids, x.edges, x.vertices -> Graph VLE [1..2] -> Result - Output: a.id, a.id, '{}'::graphid[], '[]'::edge[] + Output: a.id, a.id, '{}'::graphid[], '[]'::edge[], '[]'::vertex[] -> Result Cache Output: b.id Cache Key: x."end" @@ -1410,8 +1410,8 @@ WITH x[0] AS x1, x[1] AS x2 ORDER BY x2 RETURN x1; EXPLAIN (VERBOSE, COSTS OFF) MATCH (a:person {id: 1})-[x:knows*1..2]->(b:person) WITH max(b.id::"numeric") AS id, x[0] AS x RETURN *; - QUERY PLAN ------------------------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------- Subquery Scan on _ Output: cypher_to_jsonb(_.id), _.x -> GroupAggregate @@ -1429,10 +1429,10 @@ WITH max(b.id::"numeric") AS id, x[0] AS x RETURN *; Output: a.id, a.properties Filter: (a.properties.'id'::text = '1'::jsonb) -> Subquery Scan on x - Output: x.start, x."end", x.ids, x.edges + Output: x.start, x."end", x.ids, x.edges, x.vertices -> Graph VLE [1..2] -> Result - Output: a.id, a.id, '{}'::graphid[], '[]'::edge[] + Output: a.id, a.id, '{}'::graphid[], '[]'::edge[], '[]'::vertex[] -> Result Cache Output: b.properties, b.id Cache Key: x."end" @@ -1444,8 +1444,8 @@ WITH max(b.id::"numeric") AS id, x[0] AS x RETURN *; EXPLAIN (VERBOSE, COSTS OFF) MATCH (a:person {id: 1})-[x:knows*1..2]->(b:person) WITH DISTINCT x AS path RETURN *; - QUERY PLAN ------------------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------- Unique Output: x.edges -> Sort @@ -1460,10 +1460,10 @@ WITH DISTINCT x AS path RETURN *; Output: a.id, a.properties Filter: (a.properties.'id'::text = '1'::jsonb) -> Subquery Scan on x - Output: x.start, x."end", x.ids, x.edges + Output: x.start, x."end", x.ids, x.edges, x.vertices -> Graph VLE [1..2] -> Result - Output: a.id, a.id, '{}'::graphid[], '[]'::edge[] + Output: a.id, a.id, '{}'::graphid[], '[]'::edge[], '[]'::vertex[] -> Result Cache Output: b.id Cache Key: x."end" @@ -1475,8 +1475,8 @@ WITH DISTINCT x AS path RETURN *; EXPLAIN (VERBOSE, COSTS OFF) MATCH (a:person {id: 1})-[x:knows*1..2]->(b:person) WITH max(b.id::"numeric") AS id, x AS x RETURN *; - QUERY PLAN ------------------------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------- Subquery Scan on _ Output: cypher_to_jsonb(_.id), _.x -> GroupAggregate @@ -1494,10 +1494,10 @@ WITH max(b.id::"numeric") AS id, x AS x RETURN *; Output: a.id, a.properties Filter: (a.properties.'id'::text = '1'::jsonb) -> Subquery Scan on x - Output: x.start, x."end", x.ids, x.edges + Output: x.start, x."end", x.ids, x.edges, x.vertices -> Graph VLE [1..2] -> Result - Output: a.id, a.id, '{}'::graphid[], '[]'::edge[] + Output: a.id, a.id, '{}'::graphid[], '[]'::edge[], '[]'::vertex[] -> Result Cache Output: b.properties, b.id Cache Key: x."end" @@ -1509,8 +1509,8 @@ WITH max(b.id::"numeric") AS id, x AS x RETURN *; EXPLAIN (VERBOSE, COSTS OFF) MATCH (a:person {id: 1})-[x:knows*1..2]->(b:person) WITH max(length(x)::"numeric") AS x, b.id AS id RETURN *; - QUERY PLAN ------------------------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------------------------- Subquery Scan on _ Output: cypher_to_jsonb(_.x), _.id -> GroupAggregate @@ -1528,10 +1528,10 @@ WITH max(length(x)::"numeric") AS x, b.id AS id RETURN *; Output: a.id, a.properties Filter: (a.properties.'id'::text = '1'::jsonb) -> Subquery Scan on x - Output: x.start, x."end", x.ids, x.edges + Output: x.start, x."end", x.ids, x.edges, x.vertices -> Graph VLE [1..2] -> Result - Output: a.id, a.id, '{}'::graphid[], '[]'::edge[] + Output: a.id, a.id, '{}'::graphid[], '[]'::edge[], '[]'::vertex[] -> Result Cache Output: b.properties, b.id Cache Key: x."end" @@ -1543,8 +1543,8 @@ WITH max(length(x)::"numeric") AS x, b.id AS id RETURN *; EXPLAIN (VERBOSE, COSTS OFF) MATCH (a:person {id: 1})-[x:knows*1..2]->(b:person) RETURN x, x IS NOT NULL, x[0] IS NULL; - QUERY PLAN ----------------------------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------- Nested Loop Output: x.edges, (x.edges IS NOT NULL), (x.edges[1] IS NOT DISTINCT FROM NULL) Inner Unique: true @@ -1554,10 +1554,10 @@ RETURN x, x IS NOT NULL, x[0] IS NULL; Output: a.id, a.properties Filter: (a.properties.'id'::text = '1'::jsonb) -> Subquery Scan on x - Output: x.start, x."end", x.ids, x.edges + Output: x.start, x."end", x.ids, x.edges, x.vertices -> Graph VLE [1..2] -> Result - Output: a.id, a.id, '{}'::graphid[], '[]'::edge[] + Output: a.id, a.id, '{}'::graphid[], '[]'::edge[], '[]'::vertex[] -> Result Cache Output: b.id Cache Key: x."end" @@ -1569,8 +1569,8 @@ RETURN x, x IS NOT NULL, x[0] IS NULL; EXPLAIN (VERBOSE, COSTS OFF) MATCH (a:person {id: 1})-[x:knows*1..2]->(b:person) WHERE x[0] IS NOT NULL RETURN x[0]; - QUERY PLAN ------------------------------------------------------------------------------ + QUERY PLAN +--------------------------------------------------------------------------------------------- Nested Loop Output: x.edges[1] Inner Unique: true @@ -1580,11 +1580,11 @@ WHERE x[0] IS NOT NULL RETURN x[0]; Output: a.id, a.properties Filter: (a.properties.'id'::text = '1'::jsonb) -> Subquery Scan on x - Output: x.start, x."end", x.ids, x.edges + Output: x.start, x."end", x.ids, x.edges, x.vertices Filter: (x.edges[1] IS DISTINCT FROM NULL) -> Graph VLE [1..2] -> Result - Output: a.id, a.id, '{}'::graphid[], '[]'::edge[] + Output: a.id, a.id, '{}'::graphid[], '[]'::edge[], '[]'::vertex[] -> Result Cache Output: b.id Cache Key: x."end" @@ -1601,8 +1601,8 @@ SELECT * FROM ( MATCH (a:person {id: 1})-[x:knows*1..2]->(b:person) RETURN x[1] ) AS foo; - QUERY PLAN ---------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------- Append -> Nested Loop Output: x.edges[1] @@ -1613,11 +1613,11 @@ SELECT * FROM ( Output: a.id, a.properties Filter: (a.properties.'id'::text = '1'::jsonb) -> Subquery Scan on x - Output: x.start, x."end", x.ids, x.edges + Output: x.start, x."end", x.ids, x.edges, x.vertices Filter: (x.edges[1] IS DISTINCT FROM NULL) -> Graph VLE [1..2] -> Result - Output: a.id, a.id, '{}'::graphid[], '[]'::edge[] + Output: a.id, a.id, '{}'::graphid[], '[]'::edge[], '[]'::vertex[] -> Result Cache Output: b.id Cache Key: x."end" @@ -1633,10 +1633,10 @@ SELECT * FROM ( Output: a_1.id, a_1.properties Filter: (a_1.properties.'id'::text = '1'::jsonb) -> Subquery Scan on x_1 - Output: x_1.start, x_1."end", x_1.ids, x_1.edges + Output: x_1.start, x_1."end", x_1.ids, x_1.edges, x_1.vertices -> Graph VLE [1..2] -> Result - Output: a_1.id, a_1.id, '{}'::graphid[], '[]'::edge[] + Output: a_1.id, a_1.id, '{}'::graphid[], '[]'::edge[], '[]'::vertex[] -> Result Cache Output: b_1.id Cache Key: x_1."end" diff --git a/src/test/regress/expected/cypher_dml2.out b/src/test/regress/expected/cypher_dml2.out index c8b313cf267..fc180eb586e 100644 --- a/src/test/regress/expected/cypher_dml2.out +++ b/src/test/regress/expected/cypher_dml2.out @@ -492,6 +492,49 @@ EXPLAIN VERBOSE MATCH p=(a)-[]-(a) RETURN *; Filter: (ag_edge_3."end" = ag_edge_3.start) (20 rows) +-- #609, column does not exists +EXPLAIN MATCH (a),(a)-[*1..1]->(b) RETURN count(a); + QUERY PLAN +------------------------------------------------------------------------------------- + Aggregate (cost=101.16..101.17 rows=1 width=32) + -> Hash Join (cost=37.00..98.16 rows=1200 width=46) + Hash Cond: ("<0000000017>"."end" = b.id) + -> Nested Loop (cost=0.00..58.00 rows=1200 width=54) + -> Seq Scan on ag_vertex a (cost=0.00..22.00 rows=1200 width=46) + -> Subquery Scan on "<0000000017>" (cost=0.00..0.02 rows=1 width=8) + -> Graph VLE [1..1] (cost=0.00..0.01 rows=1 width=0) + -> Result (cost=0.00..0.01 rows=1 width=80) + -> Hash (cost=22.00..22.00 rows=1200 width=8) + -> Seq Scan on ag_vertex b (cost=0.00..22.00 rows=1200 width=8) +(10 rows) + +MATCH (a),(a)-[*1..1]->(b) RETURN count(a); + count +------- + 4 +(1 row) + +EXPLAIN MATCH (a)-[*1..1]->(b) RETURN count(a); + QUERY PLAN +------------------------------------------------------------------------------------- + Aggregate (cost=101.16..101.17 rows=1 width=32) + -> Hash Join (cost=37.00..98.16 rows=1200 width=46) + Hash Cond: ("<0000000019>"."end" = b.id) + -> Nested Loop (cost=0.00..58.00 rows=1200 width=54) + -> Seq Scan on ag_vertex a (cost=0.00..22.00 rows=1200 width=46) + -> Subquery Scan on "<0000000019>" (cost=0.00..0.02 rows=1 width=8) + -> Graph VLE [1..1] (cost=0.00..0.01 rows=1 width=0) + -> Result (cost=0.00..0.01 rows=1 width=80) + -> Hash (cost=22.00..22.00 rows=1200 width=8) + -> Seq Scan on ag_vertex b (cost=0.00..22.00 rows=1200 width=8) +(10 rows) + +MATCH (a)-[*1..1]->(b) RETURN count(a); + count +------- + 4 +(1 row) + DROP GRAPH cypher_dml2 CASCADE; NOTICE: drop cascades to 4 other objects DETAIL: drop cascades to sequence cypher_dml2.ag_label_seq diff --git a/src/test/regress/sql/cypher_dml2.sql b/src/test/regress/sql/cypher_dml2.sql index 6c9a9e733b3..2890cc17638 100644 --- a/src/test/regress/sql/cypher_dml2.sql +++ b/src/test/regress/sql/cypher_dml2.sql @@ -241,4 +241,10 @@ EXPLAIN VERBOSE MATCH (a)-[]-(a) RETURN a; EXPLAIN VERBOSE MATCH (a)-[]-(a) RETURN *; EXPLAIN VERBOSE MATCH p=(a)-[]-(a) RETURN *; +-- #609, column does not exists +EXPLAIN MATCH (a),(a)-[*1..1]->(b) RETURN count(a); +MATCH (a),(a)-[*1..1]->(b) RETURN count(a); +EXPLAIN MATCH (a)-[*1..1]->(b) RETURN count(a); +MATCH (a)-[*1..1]->(b) RETURN count(a); + DROP GRAPH cypher_dml2 CASCADE;