[GitHub] [age] CapnSpek commented on issue #1219: MERGE does not set properties involving variables
CapnSpek commented on issue #1219: URL: https://github.com/apache/age/issues/1219#issuecomment-1723217422 Some observations: - The same query with `CREATE` instead of `MERGE` works just fine ``` SELECT * FROM cypher('xyz', $$ MATCH (x:Label1{arr:[1,2,3,4]}) CREATE (y:Label2{key1:2, key2:x.arr, key3:3}) RETURN y $$) as (a agtype); ``` - The same query with `MERGE` twice also works just fine ``` SELECT * FROM cypher('xyz', $$ MATCH (x:Label1{arr:[1,2,3,4]}) MERGE (y:Label2{key1:2, key2:x.arr, key3:3}) MERGE (z:Label2{key1:2, key2:x.arr, key3:3}) RETURN y $$) as (a agtype); ``` Next, let us analyze the Query Plan Trees for `MATCH`-`MERGE`, `MATCH`-`CREATE`, and `MATCH`-`MERGE`-`MERGE` queries. - Query plan for `MATCH`-`MERGE`: ``` Custom Scan (Cypher Merge) (cost=0.00..0.00 rows=0 width=32) -> Subquery Scan on _age_default_alias_previous_cypher_clause (cost=0.00..86.02 rows=1 width=32) -> Nested Loop Left Join (cost=0.00..86.00 rows=1 width=96) Join Filter: (z.properties @> agtype_build_map('key1'::text, '2'::agtype, 'key2'::text, agtype_access_operator(VARIADIC ARRAY[_agtype_build_vertex(x.id, _label_name('18201'::oid, x.id), x. properties), '"arr"'::agtype]), 'key3'::text, '3'::agtype)) -> Seq Scan on "Label1" x (cost=0.00..31.00 rows=1 width=40) Filter: (properties @> agtype_build_map('arr'::text, agtype_build_list('1'::agtype, '2'::agtype, '3'::agtype, '4'::agtype))) -> Seq Scan on "Label2" z (cost=0.00..28.00 rows=1200 width=64) (7 rows) ``` - Query plan for `MATCH`-`CREATE`: ``` Custom Scan (Cypher Create) (cost=0.00..0.00 rows=0 width=32) -> Subquery Scan on _age_default_alias_previous_cypher_clause (cost=0.00..31.03 rows=1 width=32) -> Seq Scan on "Label1" x (cost=0.00..31.02 rows=1 width=160) Filter: (properties @> agtype_build_map('arr'::text, agtype_build_list('1'::agtype, '2'::agtype, '3'::agtype, '4'::agtype))) (4 rows) ``` - Query plan for `MATCH`-`MERGE`-`MERGE`: ``` Custom Scan (Cypher Merge) (cost=0.00..0.00 rows=0 width=32) -> Subquery Scan on _age_default_alias_previous_cypher_clause (cost=0.00..49.02 rows=1 width=32) -> Nested Loop Left Join (cost=0.00..49.01 rows=1 width=160) Join Filter: (z.properties @> agtype_build_map('key1'::text, '2'::agtype, 'key2'::text, agtype_access_operator(VARIADIC ARRAY[_age_default_alias_previous_cypher_clause_1.x, '"arr"'::agtype ]), 'key3'::text, '3'::agtype)) -> Custom Scan (Cypher Merge) (cost=0.00..0.00 rows=0 width=64) -> Subquery Scan on _age_default_alias_previous_cypher_clause_1 (cost=0.00..86.02 rows=1 width=64) -> Nested Loop Left Join (cost=0.00..86.01 rows=1 width=96) Join Filter: (y.properties @> agtype_build_map('key1'::text, '2'::agtype, 'key2'::text, agtype_access_operator(VARIADIC ARRAY[_agtype_build_vertex(x.id, _label_name('1820 1'::oid, x.id), x.properties), '"arr"'::agtype]), 'key3'::text, '3'::agtype)) -> Seq Scan on "Label1" x (cost=0.00..31.00 rows=1 width=40) Filter: (properties @> agtype_build_map('arr'::text, agtype_build_list('1'::agtype, '2'::agtype, '3'::agtype, '4'::agtype))) -> Seq Scan on "Label2" y (cost=0.00..28.00 rows=1200 width=64) -> Seq Scan on "Label2" z (cost=0.00..28.00 rows=1200 width=64) (12 rows) ``` Cannot draw a conclusion but maybe it has something to do with this part: `agtype_access_operator(VARIADIC ARRAY[_agtype_build_vertex(x.id, _label_name('18201'::oid, x.id), x. properties)` @ksheroz What do you think? -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: dev-unsubscr...@age.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org
[GitHub] [age] CapnSpek commented on issue #1219: MERGE does not set properties involving variables
CapnSpek commented on issue #1219: URL: https://github.com/apache/age/issues/1219#issuecomment-1723262498 The same query also fails if instead of an array, we have any other datatype. If the setup is changed to ... SELECT * FROM cypher('xyz', $$ CREATE (x:Label1{arr:[1,2,3,4]}) RETURN x $$) as (a agtype); ... And the query to: ``` SELECT * FROM cypher('xyz', $$ MATCH (x:Label1{arr:[1,2,3,4]}) MERGE (y:Label2{key1:2, key2:x.arr, key3:3}) RETURN y $$) as (a agtype); ``` The return value is still `{"id": 1125899906842643, "label": "Label2", "properties": {"key1": 2, "key3": 3}}::vertex` -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: dev-unsubscr...@age.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org
[GitHub] [age] CapnSpek commented on issue #1219: MERGE does not set properties involving variables
CapnSpek commented on issue #1219: URL: https://github.com/apache/age/issues/1219#issuecomment-1739124705 I am not very sure but can `transform_cypher_merge` function have something to do with it? The comments mention this, and the function is also hit during debugging. It is proving to be difficult to trace this bug because there seems to be no particular variable where I can check whether x is being passed or not, and no way to check what would be an SQL equivalent of the cypher query, specially when the query plan trees look fine. Can anyone suggest a way to track the source of this bug? ``` \* * 2. If there is a previous clause then the query will have two subqueries. * The first query will be for the previous clause that we recursively handle. * The second query will be for the path that this MERGE clause defines. The * two subqueries will be joined together using a LATERAL LEFT JOIN with the * previous query on the left and the MERGE path subquery on the right. Like * case 1 the targetList will have all the declared variables and a FuncExpr * that represents the MERGE clause with its needed metadata information, that * will be caught in the planner phase and converted into a path. * * This will allow us to be capable of handling the 2 cases that exist with a * MERGE clause correctly. * * Case 1: the path already exists. In this case we do not need to create * the path and MERGE will simply pass the tuple information up the execution * tree. * * Case 2: the path does not exist. In this case the LEFT part of the join * will not prevent the tuples from the previous clause from being emitted. We * can catch when this happens in the execution phase and create the missing * data, before passing up the execution tree. * * It should be noted that both cases can happen in the same query. If the * MERGE clause references a variable from a previous clause, it could be that * for one tuple the path exists (or there is multiple paths that exist and all * paths must be emitted) and for another the path does not exist. This is * similar to OPTIONAL MATCH, however with the added feature of creating the * path if not there, rather than just emitting NULL. */ ``` -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: dev-unsubscr...@age.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org