This is an automated email from the ASF dual-hosted git repository.
MuhammadTahaNaveed 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 f02eda0e perf: VLE terminal-qual rewrite (#2420)
f02eda0e is described below
commit f02eda0e0504bf3e941dd4a05e3060d2f3bb4f04
Author: John Gemignani <[email protected]>
AuthorDate: Mon Jun 1 09:05:49 2026 -0700
perf: VLE terminal-qual rewrite (#2420)
perf: VLE terminal-qual rewrite — emit endpoint equalities instead of SRF
qual functions.
Removes the per-row age_match_vle_terminal_edge and age_match_two_vle_edges
qual functions from VLE query plans. The cypher transformer now emits the
endpoint match as a plain graphid/int8 equality on new SRF output columns,
evaluated by the planner like any other join clause — no detoasting, no
per-row C function dispatch. Stages land as one commit:
S1 Inline start_vid/end_vid in VLE_path_container header
S2 Read VLE qual endpoints from header-only TOAST slice
S4 Emit start_id/end_id as scalar SRF output columns
(age_vle now RETURNS SETOF record with edges/start_id/end_id)
S5 Cypher transformer rewrites terminal-edge match quals as
integer equalities (drops age_match_vle_terminal_edge call)
S6 Cypher transformer emits graphid equality for two-VLE-edge
joins (drops age_match_two_vle_edges call)
Performance (SF3 LDBC SNB, 5 runs/3 warmup, vs clean master baseline_v2):
IC sum 198,958 → 109,322 ms −45.05 % (1.82× end-to-end speedup)
IC1 8,625 → 4,600 ms −46.67 %
IC3 21,239 → 9,784 ms −53.93 %
IC5 21,051 → 5,696 ms −72.94 %
IC6 15,916 → 4,447 ms −72.06 %
IC9 44,839 → 21,161 ms −52.81 %
IC10 13,104 → 2,432 ms −81.44 %
IC11 11,676 → 241 ms −97.93 % (48× speedup)
IC2/4/7/8/12: parity (within ±3.3 %; IC4 is −2.47 %, no regression)
IS sum: 1,009 → 1,004 ms −0.51 % (no VLE traffic)
IU sum: 77 → 71 ms −8.38 % (IU1 −16.09 %; incidental)
Memory: header-only TOAST slice for VLE qual evaluation avoids
detoasting full path containers on every row; reduces per-call
palloc/pfree churn in long DFS paths. No measured RSS change.
Dead-code removal:
- Bodies of age_match_vle_terminal_edge and age_match_two_vle_edges
are gone from age_vle.c (~225 lines). C entry points remain as
error-raising stubs solely so the upgrade-test snapshot loader
(which sources an older 1.7.0_initial SQL against the current
age.so) can resolve the symbols before the immediate ALTER
EXTENSION UPDATE drops them. No regress test references either
function.
- SQL CREATE FUNCTION declarations removed from fresh install
(sql/agtype_typecast.sql).
- DROP FUNCTION IF EXISTS for both qual functions added to the
upgrade script (age--1.7.0--y.y.y.sql).
API change: ag_catalog.age_vle(...) now RETURNS SETOF record with
output columns (edges agtype, start_id graphid, end_id graphid)
instead of RETURNS SETOF agtype. Both 7-arg and 8-arg overloads
are updated in fresh-install (sql/agtype_typecast.sql) and upgrade
(age--1.7.0--y.y.y.sql) paths. age_match_vle_terminal_edge and
age_match_two_vle_edges are dropped on upgrade and absent from
fresh installs. Internal AGE callers are unaffected; external SQL
that called any of these directly must adapt.
Hardening (in response to PR #2420 review feedback):
- cypher_clause.c: terminal-edge and two-VLE-edge join-qual
emission paths now bracket the existing Assert(vle_alias != NULL)
with a runtime ereport(ERROR, ...) so a missing alias produces a
clean error in production builds (where Asserts compile out)
instead of a NULL-deref crash inside makeString().
- age_vle.c: VLE_path_container struct comment now documents that
the layout is transient (consumed within the producing query and
never persisted), so the new start_vid/end_vid fields do not
require an AGT_FBINARY_TYPE_VLE_PATH version bump or backward-
compatible reader. The note also flags the constraint a future
change would need to honor if the container ever became
persistable.
Tested on PostgreSQL 18.3 (REL_18_STABLE): all 34 regression tests
pass (installcheck), warning-free build.
modified: age--1.7.0--y.y.y.sql
modified: regress/expected/cypher_match.out
modified: regress/expected/cypher_vle.out
modified: regress/expected/expr.out
modified: sql/agtype_typecast.sql
modified: src/backend/parser/cypher_clause.c
modified: src/backend/parser/cypher_transform_entity.c
modified: src/backend/utils/adt/age_vle.c
modified: src/include/parser/cypher_transform_entity.h
---
age--1.7.0--y.y.y.sql | 46 ++++
regress/expected/cypher_match.out | 6 +-
regress/expected/cypher_vle.out | 28 +--
regress/expected/expr.out | 64 +++---
sql/agtype_typecast.sql | 31 +--
src/backend/parser/cypher_clause.c | 117 +++++++---
src/backend/parser/cypher_transform_entity.c | 1 +
src/backend/utils/adt/age_vle.c | 310 ++++++++++-----------------
src/include/parser/cypher_transform_entity.h | 11 +
9 files changed, 316 insertions(+), 298 deletions(-)
diff --git a/age--1.7.0--y.y.y.sql b/age--1.7.0--y.y.y.sql
index 52044777..f7ef8066 100644
--- a/age--1.7.0--y.y.y.sql
+++ b/age--1.7.0--y.y.y.sql
@@ -490,3 +490,49 @@ AS 'SELECT $1::text::agtype';
CREATE CAST (jsonb AS agtype)
WITH FUNCTION ag_catalog.jsonb_to_agtype(jsonb);
+
+--
+-- 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 e55ed23c..e99460e5 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 6574e060..27e3bb82 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 4a332a33..23a3af28 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 c29c0a65..abca5e51 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 3083c52e..015c0719 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,107 @@ 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:
+ * <vle_alias>.start_id = prev_node.id
+ * <vle_alias>.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.
+ * Production-build runtime guard. Asserts compile out in
+ * non-debug builds, so a NULL vle_alias would otherwise reach
+ * makeString() and crash the backend during ColumnRef build.
*/
- left_id = (Node *)make_qual(cpstate, prev_node, "id");
+ if (entity->vle_alias == NULL)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("VLE edge entity is missing its alias; cannot
emit terminal-edge join qual")));
+ }
+ 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");
+ /*
+ * Production-build runtime guard for both VLE aliases; see
+ * note above on entity->vle_alias.
+ */
+ if (prev_edge->vle_alias == NULL || entity->vle_alias == NULL)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("VLE edge entity is missing its alias; cannot
emit two-VLE-edge join qual")));
+ }
+ 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 +4945,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 1b2ab0ed..13f73360 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 22c268cd..c312a62e 100644
--- a/src/backend/utils/adt/age_vle.c
+++ b/src/backend/utils/adt/age_vle.c
@@ -140,6 +140,36 @@ 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.
+ *
+ * Persistence note: VLE_path_container is a transient SRF output. It is
+ * consumed within the same query that produces it (by the planner-emitted
+ * endpoint equalities and by age_materialize_vle_path / _vle_edges) and is
+ * never written back to disk. Because no on-disk instance of this layout
+ * can exist, adding fields to the struct does not require a binary
+ * version bump or a backward-compatible decoder. If a future change ever
+ * makes a VLE container persistable (e.g. by allowing it to be returned
+ * directly as agtype and stored in a column), the AGT_FBINARY_TYPE_VLE_PATH
+ * tag must be versioned and the readers (GET_GRAPHID_ARRAY_FROM_CONTAINER
+ * etc.) must branch on the version.
+ */
typedef struct VLE_path_container
{
char vl_len_[4]; /* Do not touch this field! */
@@ -147,6 +177,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 +1453,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 +1567,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 +1610,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 +1835,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 +1987,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 +2075,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 +2337,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 d24d4c37..d0492210 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
{