diff --git a/age--1.7.0--y.y.y.sql b/age--1.7.0--y.y.y.sql index a3cdea279..8f4b1fb07 100644 --- a/age--1.7.0--y.y.y.sql +++ b/age--1.7.0--y.y.y.sql @@ -459,3 +459,50 @@ BEGIN END LOOP; END; $$; + + +-- +-- S4: VLE SRF signature change +-- +-- The age_vle SRF now emits start_id and end_id as scalar graphid columns +-- alongside the existing `edges` column. This allows the cypher transformer +-- to rewrite terminal-edge match quals as plain integer equalities, +-- removing the per-row age_match_vle_terminal_edge and age_match_two_vle_edges +-- function calls from VLE query plans. Both qual functions are dropped. +-- +-- BREAKING CHANGE for any external SQL that called age_vle(...) directly +-- and relied on `RETURNS SETOF agtype`, or called age_match_vle_terminal_edge +-- / age_match_two_vle_edges directly. Internal AGE callers (the cypher +-- transformer) are not affected. +-- +DROP FUNCTION IF EXISTS ag_catalog.age_match_vle_terminal_edge(variadic "any"); +DROP FUNCTION IF EXISTS ag_catalog.age_match_two_vle_edges(agtype, agtype); + +DROP FUNCTION IF EXISTS ag_catalog.age_vle(agtype, agtype, agtype, agtype, + agtype, agtype, agtype); +DROP FUNCTION IF EXISTS ag_catalog.age_vle(agtype, agtype, agtype, agtype, + agtype, agtype, agtype, agtype); + +CREATE FUNCTION ag_catalog.age_vle(IN agtype, IN agtype, IN agtype, IN agtype, + IN agtype, IN agtype, IN agtype, + OUT edges agtype, + OUT start_id graphid, + OUT end_id graphid) + RETURNS SETOF record +LANGUAGE C +STABLE +CALLED ON NULL INPUT +PARALLEL UNSAFE +AS 'MODULE_PATHNAME'; + +CREATE FUNCTION ag_catalog.age_vle(IN agtype, IN agtype, IN agtype, IN agtype, + IN agtype, IN agtype, IN agtype, IN agtype, + OUT edges agtype, + OUT start_id graphid, + OUT end_id graphid) + RETURNS SETOF record +LANGUAGE C +STABLE +CALLED ON NULL INPUT +PARALLEL UNSAFE +AS 'MODULE_PATHNAME'; diff --git a/regress/expected/cypher_match.out b/regress/expected/cypher_match.out index e55ed23c3..e99460e5b 100644 --- a/regress/expected/cypher_match.out +++ b/regress/expected/cypher_match.out @@ -2784,13 +2784,13 @@ SELECT * FROM cypher('cypher_match', $$ MATCH p=()-[*]->() RETURN length(p) $$) length -------- 1 - 2 1 + 2 1 1 2 - 1 2 + 1 (8 rows) SELECT * FROM cypher('cypher_match', $$ MATCH p=()-[*]->() WHERE length(p) > 1 RETURN length(p) $$) as (length agtype); @@ -2812,8 +2812,8 @@ SELECT * FROM cypher('cypher_match', $$ MATCH p=()-[*]->() WHERE size(nodes(p)) SELECT * FROM cypher('cypher_match', $$ MATCH (n {name:'Dave'}) MATCH p=()-[*]->() WHERE nodes(p)[0] = n RETURN length(p) $$) as (length agtype); length -------- - 1 2 + 1 (2 rows) SELECT * FROM cypher('cypher_match', $$ MATCH p1=(n {name:'Dave'})-[]->() MATCH p2=()-[*]->() WHERE p2=p1 RETURN p2=p1 $$) as (path agtype); diff --git a/regress/expected/cypher_vle.out b/regress/expected/cypher_vle.out index 6574e0608..27e3bb822 100644 --- a/regress/expected/cypher_vle.out +++ b/regress/expected/cypher_vle.out @@ -508,37 +508,37 @@ SELECT * FROM cypher('cypher_vle', $$MATCH p=(u)-[e*0..0]->(v) RETURN id(u), p, SELECT * FROM cypher('cypher_vle', $$MATCH p=()-[*0..0]->()-[]->() RETURN p $$) AS (p agtype); p ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - [{"id": 1407374883553282, "label": "middle", "properties": {}}::vertex, {"id": 2533274790395906, "label": "bypass_edge", "end_id": 844424930131969, "start_id": 1407374883553282, "properties": {"name": "bypass edge", "number": 2, "packages": [1, 3, 5, 7], "dangerous": {"type": "poisons", "level": "all"}}}::edge, {"id": 844424930131969, "label": "begin", "properties": {}}::vertex]::path [{"id": 844424930131969, "label": "begin", "properties": {}}::vertex, {"id": 1125899906842628, "label": "edge", "end_id": 1407374883553281, "start_id": 844424930131969, "properties": {"name": "main edge", "number": 1, "dangerous": {"type": "all", "level": "all"}}}::edge, {"id": 1407374883553281, "label": "middle", "properties": {}}::vertex]::path - [{"id": 1407374883553281, "label": "middle", "properties": {}}::vertex, {"id": 1970324836974593, "label": "self_loop", "end_id": 1407374883553281, "start_id": 1407374883553281, "properties": {"name": "self loop", "number": 1, "dangerous": {"type": "all", "level": "all"}}}::edge, {"id": 1407374883553281, "label": "middle", "properties": {}}::vertex]::path [{"id": 844424930131969, "label": "begin", "properties": {}}::vertex, {"id": 2251799813685249, "label": "alternate_edge", "end_id": 1407374883553281, "start_id": 844424930131969, "properties": {"name": "alternate edge", "number": 1, "packages": [2, 4, 6], "dangerous": {"type": "poisons", "level": "all"}}}::edge, {"id": 1407374883553281, "label": "middle", "properties": {}}::vertex]::path - [{"id": 1407374883553283, "label": "middle", "properties": {}}::vertex, {"id": 2251799813685253, "label": "alternate_edge", "end_id": 1407374883553282, "start_id": 1407374883553283, "properties": {"name": "backup edge", "number": 2, "packages": [1, 3, 5, 7]}}::edge, {"id": 1407374883553282, "label": "middle", "properties": {}}::vertex]::path + [{"id": 1407374883553281, "label": "middle", "properties": {}}::vertex, {"id": 1970324836974593, "label": "self_loop", "end_id": 1407374883553281, "start_id": 1407374883553281, "properties": {"name": "self loop", "number": 1, "dangerous": {"type": "all", "level": "all"}}}::edge, {"id": 1407374883553281, "label": "middle", "properties": {}}::vertex]::path [{"id": 1407374883553281, "label": "middle", "properties": {}}::vertex, {"id": 1125899906842627, "label": "edge", "end_id": 1407374883553282, "start_id": 1407374883553281, "properties": {"name": "main edge", "number": 2, "packages": [2, 4, 6], "dangerous": {"type": "all", "level": "all"}}}::edge, {"id": 1407374883553282, "label": "middle", "properties": {}}::vertex]::path [{"id": 1407374883553282, "label": "middle", "properties": {}}::vertex, {"id": 1125899906842626, "label": "edge", "end_id": 1407374883553283, "start_id": 1407374883553282, "properties": {"name": "main edge", "number": 3, "dangerous": {"type": "all", "level": "all"}}}::edge, {"id": 1407374883553283, "label": "middle", "properties": {}}::vertex]::path [{"id": 1407374883553282, "label": "middle", "properties": {}}::vertex, {"id": 2251799813685250, "label": "alternate_edge", "end_id": 1407374883553283, "start_id": 1407374883553282, "properties": {"name": "alternate edge", "number": 2, "packages": [2, 4, 6], "dangerous": {"type": "poisons", "level": "all"}}}::edge, {"id": 1407374883553283, "label": "middle", "properties": {}}::vertex]::path - [{"id": 1688849860263937, "label": "end", "properties": {}}::vertex, {"id": 2251799813685252, "label": "alternate_edge", "end_id": 1407374883553283, "start_id": 1688849860263937, "properties": {"name": "backup edge", "number": 1, "packages": [1, 3, 5, 7]}}::edge, {"id": 1407374883553283, "label": "middle", "properties": {}}::vertex]::path - [{"id": 1407374883553283, "label": "middle", "properties": {}}::vertex, {"id": 2251799813685251, "label": "alternate_edge", "end_id": 1688849860263937, "start_id": 1407374883553283, "properties": {"name": "alternate edge", "number": 3, "packages": [2, 4, 6], "dangerous": {"type": "poisons", "level": "all"}}}::edge, {"id": 1688849860263937, "label": "end", "properties": {}}::vertex]::path [{"id": 1407374883553282, "label": "middle", "properties": {}}::vertex, {"id": 2533274790395905, "label": "bypass_edge", "end_id": 1688849860263937, "start_id": 1407374883553282, "properties": {"name": "bypass edge", "number": 1, "packages": [1, 3, 5, 7]}}::edge, {"id": 1688849860263937, "label": "end", "properties": {}}::vertex]::path - [{"id": 1688849860263937, "label": "end", "properties": {}}::vertex, {"id": 1970324836974594, "label": "self_loop", "end_id": 1688849860263937, "start_id": 1688849860263937, "properties": {"name": "self loop", "number": 2, "dangerous": {"type": "all", "level": "all"}}}::edge, {"id": 1688849860263937, "label": "end", "properties": {}}::vertex]::path + [{"id": 1407374883553282, "label": "middle", "properties": {}}::vertex, {"id": 2533274790395906, "label": "bypass_edge", "end_id": 844424930131969, "start_id": 1407374883553282, "properties": {"name": "bypass edge", "number": 2, "packages": [1, 3, 5, 7], "dangerous": {"type": "poisons", "level": "all"}}}::edge, {"id": 844424930131969, "label": "begin", "properties": {}}::vertex]::path [{"id": 1407374883553283, "label": "middle", "properties": {}}::vertex, {"id": 1125899906842625, "label": "edge", "end_id": 1688849860263937, "start_id": 1407374883553283, "properties": {"name": "main edge", "number": 4, "dangerous": {"type": "all", "level": "all"}}}::edge, {"id": 1688849860263937, "label": "end", "properties": {}}::vertex]::path + [{"id": 1407374883553283, "label": "middle", "properties": {}}::vertex, {"id": 2251799813685251, "label": "alternate_edge", "end_id": 1688849860263937, "start_id": 1407374883553283, "properties": {"name": "alternate edge", "number": 3, "packages": [2, 4, 6], "dangerous": {"type": "poisons", "level": "all"}}}::edge, {"id": 1688849860263937, "label": "end", "properties": {}}::vertex]::path + [{"id": 1407374883553283, "label": "middle", "properties": {}}::vertex, {"id": 2251799813685253, "label": "alternate_edge", "end_id": 1407374883553282, "start_id": 1407374883553283, "properties": {"name": "backup edge", "number": 2, "packages": [1, 3, 5, 7]}}::edge, {"id": 1407374883553282, "label": "middle", "properties": {}}::vertex]::path + [{"id": 1688849860263937, "label": "end", "properties": {}}::vertex, {"id": 2251799813685252, "label": "alternate_edge", "end_id": 1407374883553283, "start_id": 1688849860263937, "properties": {"name": "backup edge", "number": 1, "packages": [1, 3, 5, 7]}}::edge, {"id": 1407374883553283, "label": "middle", "properties": {}}::vertex]::path + [{"id": 1688849860263937, "label": "end", "properties": {}}::vertex, {"id": 1970324836974594, "label": "self_loop", "end_id": 1688849860263937, "start_id": 1688849860263937, "properties": {"name": "self loop", "number": 2, "dangerous": {"type": "all", "level": "all"}}}::edge, {"id": 1688849860263937, "label": "end", "properties": {}}::vertex]::path (13 rows) SELECT * FROM cypher('cypher_vle', $$MATCH p=()-[]->()-[*0..0]->() RETURN p $$) AS (p agtype); p ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + [{"id": 1407374883553282, "label": "middle", "properties": {}}::vertex, {"id": 2533274790395906, "label": "bypass_edge", "end_id": 844424930131969, "start_id": 1407374883553282, "properties": {"name": "bypass edge", "number": 2, "packages": [1, 3, 5, 7], "dangerous": {"type": "poisons", "level": "all"}}}::edge, {"id": 844424930131969, "label": "begin", "properties": {}}::vertex]::path [{"id": 844424930131969, "label": "begin", "properties": {}}::vertex, {"id": 1125899906842628, "label": "edge", "end_id": 1407374883553281, "start_id": 844424930131969, "properties": {"name": "main edge", "number": 1, "dangerous": {"type": "all", "level": "all"}}}::edge, {"id": 1407374883553281, "label": "middle", "properties": {}}::vertex]::path - [{"id": 844424930131969, "label": "begin", "properties": {}}::vertex, {"id": 2251799813685249, "label": "alternate_edge", "end_id": 1407374883553281, "start_id": 844424930131969, "properties": {"name": "alternate edge", "number": 1, "packages": [2, 4, 6], "dangerous": {"type": "poisons", "level": "all"}}}::edge, {"id": 1407374883553281, "label": "middle", "properties": {}}::vertex]::path [{"id": 1407374883553281, "label": "middle", "properties": {}}::vertex, {"id": 1970324836974593, "label": "self_loop", "end_id": 1407374883553281, "start_id": 1407374883553281, "properties": {"name": "self loop", "number": 1, "dangerous": {"type": "all", "level": "all"}}}::edge, {"id": 1407374883553281, "label": "middle", "properties": {}}::vertex]::path + [{"id": 844424930131969, "label": "begin", "properties": {}}::vertex, {"id": 2251799813685249, "label": "alternate_edge", "end_id": 1407374883553281, "start_id": 844424930131969, "properties": {"name": "alternate edge", "number": 1, "packages": [2, 4, 6], "dangerous": {"type": "poisons", "level": "all"}}}::edge, {"id": 1407374883553281, "label": "middle", "properties": {}}::vertex]::path [{"id": 1407374883553281, "label": "middle", "properties": {}}::vertex, {"id": 1125899906842627, "label": "edge", "end_id": 1407374883553282, "start_id": 1407374883553281, "properties": {"name": "main edge", "number": 2, "packages": [2, 4, 6], "dangerous": {"type": "all", "level": "all"}}}::edge, {"id": 1407374883553282, "label": "middle", "properties": {}}::vertex]::path + [{"id": 1407374883553283, "label": "middle", "properties": {}}::vertex, {"id": 2251799813685253, "label": "alternate_edge", "end_id": 1407374883553282, "start_id": 1407374883553283, "properties": {"name": "backup edge", "number": 2, "packages": [1, 3, 5, 7]}}::edge, {"id": 1407374883553282, "label": "middle", "properties": {}}::vertex]::path [{"id": 1407374883553282, "label": "middle", "properties": {}}::vertex, {"id": 1125899906842626, "label": "edge", "end_id": 1407374883553283, "start_id": 1407374883553282, "properties": {"name": "main edge", "number": 3, "dangerous": {"type": "all", "level": "all"}}}::edge, {"id": 1407374883553283, "label": "middle", "properties": {}}::vertex]::path [{"id": 1407374883553282, "label": "middle", "properties": {}}::vertex, {"id": 2251799813685250, "label": "alternate_edge", "end_id": 1407374883553283, "start_id": 1407374883553282, "properties": {"name": "alternate edge", "number": 2, "packages": [2, 4, 6], "dangerous": {"type": "poisons", "level": "all"}}}::edge, {"id": 1407374883553283, "label": "middle", "properties": {}}::vertex]::path - [{"id": 1407374883553282, "label": "middle", "properties": {}}::vertex, {"id": 2533274790395905, "label": "bypass_edge", "end_id": 1688849860263937, "start_id": 1407374883553282, "properties": {"name": "bypass edge", "number": 1, "packages": [1, 3, 5, 7]}}::edge, {"id": 1688849860263937, "label": "end", "properties": {}}::vertex]::path - [{"id": 1407374883553282, "label": "middle", "properties": {}}::vertex, {"id": 2533274790395906, "label": "bypass_edge", "end_id": 844424930131969, "start_id": 1407374883553282, "properties": {"name": "bypass edge", "number": 2, "packages": [1, 3, 5, 7], "dangerous": {"type": "poisons", "level": "all"}}}::edge, {"id": 844424930131969, "label": "begin", "properties": {}}::vertex]::path - [{"id": 1407374883553283, "label": "middle", "properties": {}}::vertex, {"id": 1125899906842625, "label": "edge", "end_id": 1688849860263937, "start_id": 1407374883553283, "properties": {"name": "main edge", "number": 4, "dangerous": {"type": "all", "level": "all"}}}::edge, {"id": 1688849860263937, "label": "end", "properties": {}}::vertex]::path - [{"id": 1407374883553283, "label": "middle", "properties": {}}::vertex, {"id": 2251799813685251, "label": "alternate_edge", "end_id": 1688849860263937, "start_id": 1407374883553283, "properties": {"name": "alternate edge", "number": 3, "packages": [2, 4, 6], "dangerous": {"type": "poisons", "level": "all"}}}::edge, {"id": 1688849860263937, "label": "end", "properties": {}}::vertex]::path - [{"id": 1407374883553283, "label": "middle", "properties": {}}::vertex, {"id": 2251799813685253, "label": "alternate_edge", "end_id": 1407374883553282, "start_id": 1407374883553283, "properties": {"name": "backup edge", "number": 2, "packages": [1, 3, 5, 7]}}::edge, {"id": 1407374883553282, "label": "middle", "properties": {}}::vertex]::path [{"id": 1688849860263937, "label": "end", "properties": {}}::vertex, {"id": 2251799813685252, "label": "alternate_edge", "end_id": 1407374883553283, "start_id": 1688849860263937, "properties": {"name": "backup edge", "number": 1, "packages": [1, 3, 5, 7]}}::edge, {"id": 1407374883553283, "label": "middle", "properties": {}}::vertex]::path + [{"id": 1407374883553283, "label": "middle", "properties": {}}::vertex, {"id": 1125899906842625, "label": "edge", "end_id": 1688849860263937, "start_id": 1407374883553283, "properties": {"name": "main edge", "number": 4, "dangerous": {"type": "all", "level": "all"}}}::edge, {"id": 1688849860263937, "label": "end", "properties": {}}::vertex]::path [{"id": 1688849860263937, "label": "end", "properties": {}}::vertex, {"id": 1970324836974594, "label": "self_loop", "end_id": 1688849860263937, "start_id": 1688849860263937, "properties": {"name": "self loop", "number": 2, "dangerous": {"type": "all", "level": "all"}}}::edge, {"id": 1688849860263937, "label": "end", "properties": {}}::vertex]::path + [{"id": 1407374883553283, "label": "middle", "properties": {}}::vertex, {"id": 2251799813685251, "label": "alternate_edge", "end_id": 1688849860263937, "start_id": 1407374883553283, "properties": {"name": "alternate edge", "number": 3, "packages": [2, 4, 6], "dangerous": {"type": "poisons", "level": "all"}}}::edge, {"id": 1688849860263937, "label": "end", "properties": {}}::vertex]::path + [{"id": 1407374883553282, "label": "middle", "properties": {}}::vertex, {"id": 2533274790395905, "label": "bypass_edge", "end_id": 1688849860263937, "start_id": 1407374883553282, "properties": {"name": "bypass edge", "number": 1, "packages": [1, 3, 5, 7]}}::edge, {"id": 1688849860263937, "label": "end", "properties": {}}::vertex]::path (13 rows) -- @@ -598,9 +598,9 @@ SELECT * FROM cypher('mygraph', $$ $$) AS (g5 agtype); g5 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - [{"id": 844424930131969, "label": "Node", "properties": {"name": "a"}}::vertex, {"id": 1125899906842627, "label": "Edge", "end_id": 844424930131971, "start_id": 844424930131969, "properties": {}}::edge, {"id": 844424930131971, "label": "Node", "properties": {"name": "b"}}::vertex]::path [{"id": 844424930131969, "label": "Node", "properties": {"name": "a"}}::vertex, {"id": 1125899906842627, "label": "Edge", "end_id": 844424930131971, "start_id": 844424930131969, "properties": {}}::edge, {"id": 844424930131971, "label": "Node", "properties": {"name": "b"}}::vertex, {"id": 1125899906842626, "label": "Edge", "end_id": 844424930131970, "start_id": 844424930131971, "properties": {}}::edge, {"id": 844424930131970, "label": "Node", "properties": {"name": "c"}}::vertex]::path [{"id": 844424930131971, "label": "Node", "properties": {"name": "b"}}::vertex, {"id": 1125899906842626, "label": "Edge", "end_id": 844424930131970, "start_id": 844424930131971, "properties": {}}::edge, {"id": 844424930131970, "label": "Node", "properties": {"name": "c"}}::vertex]::path + [{"id": 844424930131969, "label": "Node", "properties": {"name": "a"}}::vertex, {"id": 1125899906842627, "label": "Edge", "end_id": 844424930131971, "start_id": 844424930131969, "properties": {}}::edge, {"id": 844424930131971, "label": "Node", "properties": {"name": "b"}}::vertex]::path (3 rows) SELECT drop_graph('mygraph', true); @@ -1027,9 +1027,9 @@ SELECT * FROM cypher('issue_1043', $$ CREATE (n)-[:KNOWS {n:'hello'}]->({n:'hell SELECT * FROM cypher('issue_1043', $$ MATCH (x)<-[y *]-(),({n:y[0].n}) RETURN x $$) as (a agtype); a ---------------------------------------------------------------------------- - {"id": 281474976710658, "label": "", "properties": {"n": "hello"}}::vertex {"id": 281474976710658, "label": "", "properties": {"n": "hello"}}::vertex {"id": 281474976710660, "label": "", "properties": {"n": "hello"}}::vertex + {"id": 281474976710658, "label": "", "properties": {"n": "hello"}}::vertex {"id": 281474976710660, "label": "", "properties": {"n": "hello"}}::vertex (4 rows) diff --git a/regress/expected/expr.out b/regress/expected/expr.out index 4a332a335..23a3af28a 100644 --- a/regress/expected/expr.out +++ b/regress/expected/expr.out @@ -8354,11 +8354,11 @@ $$) AS (vle_array agtype); vle_array -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] - [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] + [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] + [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] - [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] (6 rows) SELECT * FROM cypher('expr', $$ @@ -8368,8 +8368,8 @@ SELECT * FROM cypher('expr', $$ $$) AS (vle_array agtype); vle_array -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] + [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] (2 rows) SELECT * FROM cypher('expr', $$ @@ -8388,12 +8388,12 @@ SELECT * FROM cypher('expr', $$ $$) AS (vle_array agtype); vle_array -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] - [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] + [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] + [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] - [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] + [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] (6 rows) -- head @@ -8403,11 +8403,11 @@ SELECT * FROM cypher('expr', $$ $$) AS (head agtype); head --------------------------------------------------------------------------------------------------------------------------- - {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge - {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge + {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge + {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge (6 rows) @@ -8418,12 +8418,12 @@ SELECT * FROM cypher('expr', $$ $$) AS (head agtype); head -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] - [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] + [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] + [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] - [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] + [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] (6 rows) SELECT * FROM cypher('expr', $$ @@ -8433,12 +8433,12 @@ SELECT * FROM cypher('expr', $$ $$) AS (head agtype); head -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] - [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] + [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] + [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] - [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] + [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] (6 rows) SELECT * FROM cypher('expr', $$ @@ -8459,11 +8459,11 @@ $$) AS (head agtype); head --------------------------------------------------------------------------------------------------------------------------- {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge - {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge + {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge - {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge + {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge (6 rows) SELECT * FROM cypher('expr', $$ @@ -8473,9 +8473,9 @@ SELECT * FROM cypher('expr', $$ $$) AS (head agtype); head ----------------------------------------------------------------------------------------------------------------------------- - [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] + [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] (4 rows) @@ -8486,12 +8486,12 @@ SELECT * FROM cypher('expr', $$ $$) AS (head agtype); head -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] - [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] + [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] + [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] - [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] + [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] (6 rows) SELECT * FROM cypher('expr', $$ @@ -8522,11 +8522,11 @@ $$) AS (head agtype); head -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] - [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] + [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] + [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] - [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] (6 rows) SELECT * FROM cypher('expr', $$ @@ -8537,11 +8537,11 @@ $$) AS (head agtype); head -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] - [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] + [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] + [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] - [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] (6 rows) SELECT * FROM cypher('expr', $$ @@ -8552,11 +8552,11 @@ $$) AS (head agtype); head -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] - [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] + [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] + [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] - [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] (6 rows) -- reverse @@ -8567,11 +8567,11 @@ $$) as (u agtype); u -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] - [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] + [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] + [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] - [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] (6 rows) SELECT * FROM cypher('expr', $$ @@ -8581,12 +8581,12 @@ SELECT * FROM cypher('expr', $$ $$) as (u agtype); u -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] - [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] + [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] + [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] - [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] + [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] (6 rows) -- IN operator @@ -8611,8 +8611,8 @@ $$) AS (a agtype); a -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge] - [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] + [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626, "properties": {}}::edge] (3 rows) SELECT * FROM cypher('expr', $$ diff --git a/sql/agtype_typecast.sql b/sql/agtype_typecast.sql index c29c0a657..abca5e518 100644 --- a/sql/agtype_typecast.sql +++ b/sql/agtype_typecast.sql @@ -70,10 +70,14 @@ PARALLEL SAFE AS 'MODULE_PATHNAME'; -- original VLE function definition +-- S4: emit start_id/end_id as scalar columns to enable transformer rewrite +-- of terminal-edge quals as integer equalities (see PERF_VLE_TERMINAL_QUAL_PLAN). CREATE FUNCTION ag_catalog.age_vle(IN agtype, IN agtype, IN agtype, IN agtype, IN agtype, IN agtype, IN agtype, - OUT edges agtype) - RETURNS SETOF agtype + OUT edges agtype, + OUT start_id graphid, + OUT end_id graphid) + RETURNS SETOF record LANGUAGE C STABLE CALLED ON NULL INPUT @@ -84,8 +88,10 @@ AS 'MODULE_PATHNAME'; -- caching mechanism to coexist with the previous VLE version. CREATE FUNCTION ag_catalog.age_vle(IN agtype, IN agtype, IN agtype, IN agtype, IN agtype, IN agtype, IN agtype, IN agtype, - OUT edges agtype) - RETURNS SETOF agtype + OUT edges agtype, + OUT start_id graphid, + OUT end_id graphid) + RETURNS SETOF record LANGUAGE C STABLE CALLED ON NULL INPUT @@ -100,15 +106,6 @@ CREATE FUNCTION ag_catalog.age_build_vle_match_edge(agtype, agtype) PARALLEL SAFE AS 'MODULE_PATHNAME'; --- function to match a terminal vle edge -CREATE FUNCTION ag_catalog.age_match_vle_terminal_edge(variadic "any") - RETURNS boolean - LANGUAGE C - STABLE -CALLED ON NULL INPUT -PARALLEL SAFE -AS 'MODULE_PATHNAME'; - -- function to create an AGTV_PATH from a VLE_path_container CREATE FUNCTION ag_catalog.age_materialize_vle_path(agtype) RETURNS agtype @@ -135,14 +132,6 @@ RETURNS NULL ON NULL INPUT PARALLEL SAFE AS 'MODULE_PATHNAME'; -CREATE FUNCTION ag_catalog.age_match_two_vle_edges(agtype, agtype) - RETURNS boolean - LANGUAGE C - STABLE -RETURNS NULL ON NULL INPUT -PARALLEL SAFE -AS 'MODULE_PATHNAME'; - -- list functions CREATE FUNCTION ag_catalog.age_keys(agtype) RETURNS agtype diff --git a/src/backend/parser/cypher_clause.c b/src/backend/parser/cypher_clause.c index 3083c52e1..40ea1b92b 100644 --- a/src/backend/parser/cypher_clause.c +++ b/src/backend/parser/cypher_clause.c @@ -3982,10 +3982,6 @@ static List *make_join_condition_for_edge(cypher_parsestate *cpstate, { Node *left_id = NULL; Node *right_id = NULL; - String *ag_catalog = makeString("ag_catalog"); - String *func_name; - List *qualified_func_name; - List *args = NIL; List *quals = NIL; /* @@ -3998,56 +3994,86 @@ static List *make_join_condition_for_edge(cypher_parsestate *cpstate, } /* - * If the previous node and the next node are in the join tree, we need - * to create the age_match_vle_terminal_edge to compare the vle returned - * results against the two nodes. + * S5: if the previous and next nodes are both in the join tree, + * emit two graphid equality A_Exprs: + * .start_id = prev_node.id + * .end_id = next_node.id + * This replaces the historical per-row + * age_match_vle_terminal_edge(prev.id, next.id, edges) + * function call with plain integer (int8) equality quals on the + * SRF's S4 output columns. The planner can now drive the join + * directly on these keys (HashJoin hash keys, NestLoop index + * conditions where indexed). */ if (prev_node->in_join_tree) { - func_name = makeString("age_match_vle_terminal_edge"); - qualified_func_name = list_make2(ag_catalog, func_name); + ColumnRef *cr_start; + ColumnRef *cr_end; + A_Expr *eq_start; + A_Expr *eq_end; - /* - * Get the vertex's id and pass to the function. Pass in NULL - * otherwise. - */ - left_id = (Node *)make_qual(cpstate, prev_node, "id"); + Assert(entity->vle_alias != NULL); + + cr_start = makeNode(ColumnRef); + cr_start->fields = list_make2(makeString(entity->vle_alias), + makeString("start_id")); + cr_start->location = -1; + + cr_end = makeNode(ColumnRef); + cr_end->fields = list_make2(makeString(entity->vle_alias), + makeString("end_id")); + cr_end->location = -1; + + left_id = (Node *)make_qual(cpstate, prev_node, "id"); right_id = (Node *)make_qual(cpstate, next_node, "id"); - /* create the argument list */ - args = list_make3(left_id, right_id, entity->expr); + eq_start = makeSimpleA_Expr(AEXPR_OP, "=", + (Node *)cr_start, left_id, -1); + eq_end = makeSimpleA_Expr(AEXPR_OP, "=", + (Node *)cr_end, right_id, -1); - /* add to quals */ - quals = lappend(quals, makeFuncCall(qualified_func_name, args, - COERCE_EXPLICIT_CALL, -1)); + quals = lappend(quals, eq_start); + quals = lappend(quals, eq_end); } /* - * When the previous node is not in the join tree, but there is a vle - * edge before that join, then we need to compare this vle's start node - * against the previous vle's end node. No need to check the next edge, - * because that would be redundant. + * S6: when the previous node is not in the join tree but there is + * a vle edge before that join, emit a single graphid equality + * connecting the two VLE SRFs: + * + * prev_vle.end_id = this_vle.start_id + * + * This replaces the per-row age_match_two_vle_edges(prev, this) + * function call with a plain int8 equality on the S4 scalar + * output columns of both age_vle SRFs. No detoasting of either + * VLE_path_container is needed. */ if (!prev_node->in_join_tree && prev_edge != NULL && prev_edge->type == ENT_VLE_EDGE) { - List *qualified_name; - String *match_qual; - FuncCall *fc; + ColumnRef *cr_prev_end; + ColumnRef *cr_this_start; + A_Expr *eq_chain; - match_qual = makeString("age_match_two_vle_edges"); + Assert(prev_edge->vle_alias != NULL); + Assert(entity->vle_alias != NULL); - /* make the qualified function name */ - qualified_name = list_make2(ag_catalog, match_qual); + cr_prev_end = makeNode(ColumnRef); + cr_prev_end->fields = list_make2(makeString(prev_edge->vle_alias), + makeString("end_id")); + cr_prev_end->location = -1; - /* make the args */ - args = list_make2(prev_edge->expr, entity->expr); + cr_this_start = makeNode(ColumnRef); + cr_this_start->fields = list_make2(makeString(entity->vle_alias), + makeString("start_id")); + cr_this_start->location = -1; - /* create the function call */ - fc = makeFuncCall(qualified_name, args, COERCE_EXPLICIT_CALL, -1); + eq_chain = makeSimpleA_Expr(AEXPR_OP, "=", + (Node *)cr_prev_end, + (Node *)cr_this_start, -1); - quals = lappend(quals, fc); + quals = lappend(quals, eq_chain); } return quals; @@ -4898,6 +4924,12 @@ static transform_entity *transform_VLE_edge_entity(cypher_parsestate *cpstate, vle_entity = make_transform_entity(cpstate, ENT_VLE_EDGE, (Node *)rel, (Expr *)var); + /* + * S5: stash the auto-generated alias name so make_join_condition_for_edge + * can build ColumnRefs for the SRF's start_id/end_id output columns. + */ + vle_entity->vle_alias = alias->aliasname; + /* return the vle entity */ return vle_entity; } diff --git a/src/backend/parser/cypher_transform_entity.c b/src/backend/parser/cypher_transform_entity.c index 1b2ab0edd..13f733608 100644 --- a/src/backend/parser/cypher_transform_entity.c +++ b/src/backend/parser/cypher_transform_entity.c @@ -52,6 +52,7 @@ transform_entity *make_transform_entity(cypher_parsestate *cpstate, entity->declared_in_current_clause = true; entity->expr = expr; entity->in_join_tree = expr != NULL; + entity->vle_alias = NULL; return entity; } diff --git a/src/backend/utils/adt/age_vle.c b/src/backend/utils/adt/age_vle.c index 22c268cdf..0436b56d4 100644 --- a/src/backend/utils/adt/age_vle.c +++ b/src/backend/utils/adt/age_vle.c @@ -140,6 +140,25 @@ typedef struct VLE_local_context * structure is set up to contains a BINARY container that can be accessed by * functions that need to process the path. */ +/* + * Layout (offsets, with int64 alignment): + * + * 0: vl_len_[4] varlena length header (int32 + pad) + * 4: header AGT_FBINARY | AGT_FBINARY_TYPE_VLE_PATH + * 8: graph_oid source graph oid + * 12: (4 bytes pad) int64 alignment + * 16: graphid_array_size number of graphids in the path + * 24: container_size_bytes total bytes of this container + * 32: start_vid redundant cache of graphid_array[0] + * 40: end_vid redundant cache of + * graphid_array[graphid_array_size - 1] + * 48: graphid_array_data flexible array start + * + * start_vid / end_vid are populated whenever the container is built and let + * downstream consumers (the age_vle SRF's start_id/end_id output columns) + * read the join endpoints without traversing the (potentially toasted) + * variadic payload. + */ typedef struct VLE_path_container { char vl_len_[4]; /* Do not touch this field! */ @@ -147,6 +166,8 @@ typedef struct VLE_path_container uint32 graph_oid; int64 graphid_array_size; int64 container_size_bytes; + graphid start_vid; + graphid end_vid; graphid graphid_array_data; } VLE_path_container; @@ -1421,9 +1442,11 @@ static VLE_path_container *create_VLE_path_container(int64 path_size) * One for both the header and graph oid (they are both 32 bits). * One for the size of the graphid_array_size. * One for the container_size_bytes. + * One for start_vid (Stage 1: inline endpoint cache). + * One for end_vid (Stage 1: inline endpoint cache). * */ - container_size_bytes = sizeof(graphid) * (path_size + 4); + container_size_bytes = sizeof(graphid) * (path_size + 6); /* allocate the container */ vpc = palloc0(container_size_bytes); @@ -1533,6 +1556,13 @@ static VLE_path_container *build_VLE_path_container(VLE_local_context *vlelctx) graphid_array[index+1] = vid; } + /* + * Stage 1: cache endpoints in the fixed header so the join qual can read + * them without touching the (possibly toasted) graphid array. + */ + vpc->start_vid = graphid_array[0]; + vpc->end_vid = graphid_array[vpc->graphid_array_size - 1]; + /* return the container */ return vpc; } @@ -1569,6 +1599,12 @@ static VLE_path_container *build_VLE_zero_container(VLE_local_context *vlelctx) vid = vlelctx->vsid; graphid_array[0] = vid; + /* + * Stage 1: zero-edge container; start and end are both the start vertex. + */ + vpc->start_vid = vid; + vpc->end_vid = vid; + return vpc; } @@ -1788,6 +1824,26 @@ Datum age_vle(PG_FUNCTION_ARGS) /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); + /* + * S4: capture the result tuple descriptor. age_vle now emits a + * composite (edges, start_id, end_id) row, so we need a blessed + * TupleDesc that survives across SRF calls. + */ + { + TupleDesc tupdesc; + MemoryContext tdesc_oldctx; + + tdesc_oldctx = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("age_vle: function returning record called in context that cannot accept type record"))); + } + funcctx->tuple_desc = BlessTupleDesc(tupdesc); + MemoryContextSwitchTo(tdesc_oldctx); + } + /* build the local vle context */ vlelctx = build_local_vle_context(fcinfo, funcctx); @@ -1920,8 +1976,24 @@ Datum age_vle(PG_FUNCTION_ARGS) vpc = build_VLE_zero_container(vlelctx); } - /* return the result and signal that the function is not yet done */ - SRF_RETURN_NEXT(funcctx, PointerGetDatum(vpc)); + /* + * S4: emit a composite (edges, start_id, end_id) row. The + * scalar endpoint columns let the cypher transformer (S5) + * rewrite terminal-edge quals as integer equalities, removing + * the per-row age_match_vle_terminal_edge function call. + */ + { + Datum values[3]; + bool nulls[3] = {false, false, false}; + HeapTuple tuple; + + values[0] = PointerGetDatum(vpc); + values[1] = GRAPHID_GET_DATUM(vpc->start_vid); + values[2] = GRAPHID_GET_DATUM(vpc->end_vid); + + tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); + SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); + } } /* otherwise, we are done and we need to cleanup and signal done */ else @@ -1992,66 +2064,31 @@ agtype_value *agtv_materialize_vle_path(agtype *agt_arg_vpc) return agtv_path; } -/* PG function to match 2 VLE edges */ +/* + * age_match_two_vle_edges and age_match_vle_terminal_edge are retained as + * stub C symbols only. The cypher transformer no longer emits calls to + * either function: terminal-edge match quals are now plain graphid + * equalities on the age_vle SRF's start_id/end_id output columns + * (Stages S4/S5/S6 of the VLE terminal-qual rewrite). + * + * The corresponding SQL declarations have been removed from fresh + * installs (sql/agtype_typecast.sql) and are DROP'd by the upgrade + * script (age--1.7.0--y.y.y.sql). These C entry points exist solely so + * the upgrade-test machinery, which loads an older "1.7.0_initial" SQL + * snapshot against the current age.so, can resolve the symbols before + * the immediate ALTER EXTENSION UPDATE drops them. They should never + * be reachable from any committed SQL path. + */ PG_FUNCTION_INFO_V1(age_match_two_vle_edges); Datum age_match_two_vle_edges(PG_FUNCTION_ARGS) { - agtype *agt_arg_vpc = NULL; - VLE_path_container *left_path = NULL, *right_path = NULL; - graphid *left_array, *right_array; - int left_array_size; - - /* - * If either argument is NULL, return FALSE. This can occur in - * OPTIONAL MATCH (LEFT JOIN) contexts where a preceding clause - * produced no results. - */ - if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) - { - PG_RETURN_BOOL(false); - } - - /* get the VLE_path_container argument */ - agt_arg_vpc = AG_GET_ARG_AGTYPE_P(0); - - if (!AGT_ROOT_IS_BINARY(agt_arg_vpc) || - AGT_ROOT_BINARY_FLAGS(agt_arg_vpc) != AGT_FBINARY_TYPE_VLE_PATH) - { - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("argument 1 of age_match_two_vle_edges must be a VLE_Path_Container"))); - } - - /* cast argument as a VLE_Path_Container and extract graphid array */ - left_path = (VLE_path_container *)agt_arg_vpc; - left_array_size = left_path->graphid_array_size; - left_array = GET_GRAPHID_ARRAY_FROM_CONTAINER(left_path); - - PG_FREE_IF_COPY(agt_arg_vpc, 0); - - agt_arg_vpc = AG_GET_ARG_AGTYPE_P(1); - - if (!AGT_ROOT_IS_BINARY(agt_arg_vpc) || - AGT_ROOT_BINARY_FLAGS(agt_arg_vpc) != AGT_FBINARY_TYPE_VLE_PATH) - { - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("argument 2 of age_match_two_vle_edges must be a VLE_Path_Container"))); - } - - /* cast argument as a VLE_Path_Container and extract graphid array */ - right_path = (VLE_path_container *)agt_arg_vpc; - right_array = GET_GRAPHID_ARRAY_FROM_CONTAINER(right_path); - - PG_FREE_IF_COPY(agt_arg_vpc, 1); - - if (left_array[left_array_size - 1] != right_array[0]) - { - PG_RETURN_BOOL(false); - } - - PG_RETURN_BOOL(true); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("age_match_two_vle_edges() is removed; " + "VLE endpoint matching is now handled by the planner via " + "the age_vle SRF's start_id/end_id output columns"))); + PG_RETURN_BOOL(false); } /* @@ -2289,147 +2326,17 @@ Datum age_materialize_vle_path(PG_FUNCTION_ARGS) PG_RETURN_POINTER(agt_materialize_vle_path(agt_arg_vpc)); } -/* - * PG function to take a VLE_path_container and return whether the supplied end - * vertex (target/veid) matches against the last edge in the VLE path. The VLE - * path is encoded in a BINARY container. - */ +/* Stub: see comment on age_match_two_vle_edges above. */ PG_FUNCTION_INFO_V1(age_match_vle_terminal_edge); Datum age_match_vle_terminal_edge(PG_FUNCTION_ARGS) { - VLE_path_container *vpc = NULL; - agtype *agt_arg_vsid = NULL; - agtype *agt_arg_veid = NULL; - agtype *agt_arg_path = NULL; - agtype_value *agtv_temp = NULL; - graphid vsid = 0; - graphid veid = 0; - graphid *gida = NULL; - int gidasize = 0; - Oid type0, type1; - - /* check argument count */ - if (PG_NARGS() != 3) - { - ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("age_match_vle_terminal_edge() invalid number of arguments"))); - } - - /* - * If any argument is NULL, return FALSE. This can occur when this - * function is used as a join qual in an OPTIONAL MATCH (LEFT JOIN) - * where a preceding OPTIONAL MATCH produced no results. Returning - * FALSE allows PostgreSQL to produce the correct NULL-extended rows. - */ - if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2)) - { - PG_RETURN_BOOL(false); - } - - /* get the vpc */ - agt_arg_path = DATUM_GET_AGTYPE_P(PG_GETARG_DATUM(2)); - - /* if the vpc is an agtype NULL, return FALSE */ - if (is_agtype_null(agt_arg_path)) - { - PG_RETURN_BOOL(false); - } - - /* - * The vpc (path) must be a binary container and the type of the object in - * the container must be an AGT_FBINARY_TYPE_VLE_PATH. - */ - Assert(AGT_ROOT_IS_BINARY(agt_arg_path)); - Assert(AGT_ROOT_BINARY_FLAGS(agt_arg_path) == AGT_FBINARY_TYPE_VLE_PATH); - - /* get the container */ - vpc = (VLE_path_container *)agt_arg_path; - - /* get the graphid array from the container */ - gida = GET_GRAPHID_ARRAY_FROM_CONTAINER(vpc); - - /* get the gida array size */ - gidasize = vpc->graphid_array_size; - - /* verify the minimum size is 3 or 1 */ - Assert(gidasize >= 3 || gidasize == 1); - - /* - * Get argument types directly instead of using extract_variadic_args. - * This avoids the expensive exprType/get_call_expr_argtype overhead - * on every call. Cache the types in fn_extra on first invocation. - */ - if (fcinfo->flinfo->fn_extra == NULL) - { - Oid *cached_types = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - 2 * sizeof(Oid)); - cached_types[0] = get_fn_expr_argtype(fcinfo->flinfo, 0); - cached_types[1] = get_fn_expr_argtype(fcinfo->flinfo, 1); - fcinfo->flinfo->fn_extra = cached_types; - } - type0 = ((Oid *)fcinfo->flinfo->fn_extra)[0]; - type1 = ((Oid *)fcinfo->flinfo->fn_extra)[1]; - - /* get the vsid */ - if (type0 == AGTYPEOID) - { - agt_arg_vsid = DATUM_GET_AGTYPE_P(PG_GETARG_DATUM(0)); - - if (!is_agtype_null(agt_arg_vsid)) - { - agtv_temp = - get_ith_agtype_value_from_container(&agt_arg_vsid->root, 0); - - Assert(agtv_temp->type == AGTV_INTEGER); - vsid = agtv_temp->val.int_value; - } - else - { - PG_RETURN_BOOL(false); - } - } - else if (type0 == GRAPHIDOID) - { - vsid = DATUM_GET_GRAPHID(PG_GETARG_DATUM(0)); - } - else - { - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("match_vle_terminal_edge() argument 1 must be an agtype integer or a graphid"))); - } - - /* get the veid */ - if (type1 == AGTYPEOID) - { - agt_arg_veid = DATUM_GET_AGTYPE_P(PG_GETARG_DATUM(1)); - - if (!is_agtype_null(agt_arg_veid)) - { - agtv_temp = get_ith_agtype_value_from_container(&agt_arg_veid->root, - 0); - Assert(agtv_temp->type == AGTV_INTEGER); - veid = agtv_temp->val.int_value; - } - else - { - PG_RETURN_BOOL(false); - } - } - else if (type1 == GRAPHIDOID) - { - veid = DATUM_GET_GRAPHID(PG_GETARG_DATUM(1)); - } - else - { - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("match_vle_terminal_edge() argument 2 must be an agtype integer or a graphid"))); - } - - /* compare the path beginning or end points */ - PG_RETURN_BOOL(gida[0] == vsid && veid == gida[gidasize - 1]); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("age_match_vle_terminal_edge() is removed; " + "VLE endpoint matching is now handled by the planner via " + "the age_vle SRF's start_id/end_id output columns"))); + PG_RETURN_BOOL(false); } /* PG helper function to build an agtype (Datum) edge for matching */ diff --git a/src/include/parser/cypher_transform_entity.h b/src/include/parser/cypher_transform_entity.h index d24d4c372..d0492210f 100644 --- a/src/include/parser/cypher_transform_entity.h +++ b/src/include/parser/cypher_transform_entity.h @@ -75,6 +75,17 @@ typedef struct * declared by itself or a previous clause. */ bool declared_in_current_clause; + + /* + * S5: for ENT_VLE_EDGE entities, the auto-generated alias of the + * RangeFunction added to the FROM clause for the age_vle SRF. + * Used to build ColumnRefs for the SRF's start_id/end_id output + * columns when emitting the terminal-edge join quals as plain + * graphid equality A_Exprs (replacing the per-row + * age_match_vle_terminal_edge function call). NULL for non-VLE + * entities. + */ + char *vle_alias; /* The parse data structure that we transformed */ union {