crprashant commented on code in PR #2417:
URL: https://github.com/apache/age/pull/2417#discussion_r3376522298
##########
Makefile:
##########
@@ -183,7 +183,8 @@ REGRESS = scan \
direct_field_access \
security \
reserved_keyword_alias \
- agtype_jsonb_cast
+ agtype_jsonb_cast \\
+ containment_selectivity
Review Comment:
Fixed. The double backslash was an artifact of the rebase conflict
resolution. Restored a single trailing backslash so the REGRESS continuation
chains correctly: \gtype_jsonb_cast \\\ then \containment_selectivity\.
Verified the Makefile parses (make no longer reports 'missing separator') and
both test names are in the REGRESS list.
##########
age--1.7.0--y.y.y.sql:
##########
@@ -464,6 +464,1841 @@ $$;
-- agtype <-> jsonb bidirectional casts
--
+-- agtype -> jsonb (explicit)
+-- Uses json intermediate (agtype_to_json -> json::jsonb) because agtype
+-- extends jsonb's binary format with types (AGTV_INTEGER, AGTV_FLOAT,
+-- AGTV_VERTEX, AGTV_EDGE, AGTV_PATH) that jsonb does not recognize.
+CREATE FUNCTION ag_catalog.agtype_to_jsonb(agtype)
+ RETURNS jsonb
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'SELECT ag_catalog.agtype_to_json(--
+-- agtype <-> jsonb bidirectional casts
+--
+
+-- agtype -> jsonb (explicit)
+-- Uses json intermediate (agtype_to_json -> json::jsonb) because agtype
+-- extends jsonb's binary format with types (AGTV_INTEGER, AGTV_FLOAT,
+-- AGTV_VERTEX, AGTV_EDGE, AGTV_PATH) that jsonb does not recognize.
+CREATE FUNCTION ag_catalog.agtype_to_jsonb(agtype)
+ RETURNS jsonb
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'SELECT ag_catalog.agtype_to_json($1)::jsonb';
+
+CREATE CAST (agtype AS jsonb)
+ WITH FUNCTION ag_catalog.agtype_to_jsonb(agtype);
+
+-- jsonb -> agtype (explicit)
+CREATE FUNCTION ag_catalog.jsonb_to_agtype(jsonb)
+ RETURNS agtype
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+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';
+
+--
+-- Composite types for vertex and edge
+--
+CREATE TYPE ag_catalog.vertex AS (
+ id graphid,
+ label agtype,
+ properties agtype
+);
+
+CREATE TYPE ag_catalog.edge AS (
+ id graphid,
+ label agtype,
+ end_id graphid,
+ start_id graphid,
+ properties agtype
+);
+
+--
+-- vertex/edge to agtype cast functions
+--
+CREATE FUNCTION ag_catalog.vertex_to_agtype(vertex)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_agtype(edge)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Implicit casts from vertex/edge to agtype
+--
+CREATE CAST (vertex AS agtype)
+ WITH FUNCTION ag_catalog.vertex_to_agtype(vertex)
+AS IMPLICIT;
+
+CREATE CAST (edge AS agtype)
+ WITH FUNCTION ag_catalog.edge_to_agtype(edge)
+AS IMPLICIT;
+
+CREATE FUNCTION ag_catalog.vertex_to_json(vertex)
+ RETURNS json
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_json(edge)
+ RETURNS json
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE CAST (vertex AS json)
+ WITH FUNCTION ag_catalog.vertex_to_json(vertex);
+
+CREATE CAST (edge AS json)
+ WITH FUNCTION ag_catalog.edge_to_json(edge);
+
+CREATE FUNCTION ag_catalog.vertex_to_jsonb(vertex)
+ RETURNS jsonb
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_jsonb(edge)
+ RETURNS jsonb
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE CAST (vertex AS jsonb)
+ WITH FUNCTION ag_catalog.vertex_to_jsonb(vertex);
+
+CREATE CAST (edge AS jsonb)
+ WITH FUNCTION ag_catalog.edge_to_jsonb(edge);
+
+--
+-- Equality operators for vertex and edge (compare by id)
+--
+CREATE FUNCTION ag_catalog.vertex_eq(vertex, vertex)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id = $2.id $$;
+
+CREATE OPERATOR = (
+ FUNCTION = ag_catalog.vertex_eq,
+ LEFTARG = vertex,
+ RIGHTARG = vertex,
+ COMMUTATOR = =,
+ NEGATOR = <>,
+ RESTRICT = eqsel,
+ JOIN = eqjoinsel
+);
+
+CREATE FUNCTION ag_catalog.vertex_ne(vertex, vertex)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id <> $2.id $$;
+
+CREATE OPERATOR <> (
+ FUNCTION = ag_catalog.vertex_ne,
+ LEFTARG = vertex,
+ RIGHTARG = vertex,
+ COMMUTATOR = <>,
+ NEGATOR = =,
+ RESTRICT = neqsel,
+ JOIN = neqjoinsel
+);
+
+CREATE FUNCTION ag_catalog.edge_eq(edge, edge)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id = $2.id $$;
+
+CREATE OPERATOR = (
+ FUNCTION = ag_catalog.edge_eq,
+ LEFTARG = edge,
+ RIGHTARG = edge,
+ COMMUTATOR = =,
+ NEGATOR = <>,
+ RESTRICT = eqsel,
+ JOIN = eqjoinsel
+);
+
+CREATE FUNCTION ag_catalog.edge_ne(edge, edge)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id <> $2.id $$;
+
+CREATE OPERATOR <> (
+ FUNCTION = ag_catalog.edge_ne,
+ LEFTARG = edge,
+ RIGHTARG = edge,
+ COMMUTATOR = <>,
+ NEGATOR = =,
+ RESTRICT = neqsel,
+ JOIN = neqjoinsel
+);
+
+--
+-- Drop and recreate _label_name with new return type (cstring -> agtype)
+--
+DROP FUNCTION IF EXISTS ag_catalog._label_name(oid, graphid);
+
+CREATE FUNCTION ag_catalog._label_name(graph_oid oid, graphid)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Drop and recreate _agtype_build_vertex with new signature (cstring ->
agtype for label)
+--
+DROP FUNCTION IF EXISTS ag_catalog._agtype_build_vertex(graphid, cstring,
agtype);
+
+CREATE FUNCTION ag_catalog._agtype_build_vertex(graphid, agtype, agtype)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+CALLED ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Drop and recreate _agtype_build_edge with new signature (cstring -> agtype
for label)
+--
+DROP FUNCTION IF EXISTS ag_catalog._agtype_build_edge(graphid, graphid,
graphid, cstring, agtype);
+
+CREATE FUNCTION ag_catalog._agtype_build_edge(graphid, graphid, graphid,
+ agtype, agtype)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+CALLED ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Helper function for optimized startNode/endNode
+--
+CREATE FUNCTION ag_catalog._get_vertex_by_graphid(text, graphid)
+ RETURNS agtype
+ LANGUAGE c
+ STABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+-- Internal selftest for the agehash open-addressing hashtable. Returns "OK"
+-- on success or "FAIL: ..." with a diagnostic message. Intended for the
+-- agehash regression test only.
+CREATE FUNCTION ag_catalog._agehash_self_test()
+ RETURNS text
+ LANGUAGE c
+ VOLATILE
+ PARALLEL UNSAFE
+AS 'MODULE_PATHNAME';)::jsonb';
+
+CREATE CAST (agtype AS jsonb)
+ WITH FUNCTION ag_catalog.agtype_to_jsonb(agtype);
+
+-- jsonb -> agtype (explicit)
+CREATE FUNCTION ag_catalog.jsonb_to_agtype(jsonb)
+ RETURNS agtype
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'SELECT --
+-- agtype <-> jsonb bidirectional casts
+--
+
+-- agtype -> jsonb (explicit)
+-- Uses json intermediate (agtype_to_json -> json::jsonb) because agtype
+-- extends jsonb's binary format with types (AGTV_INTEGER, AGTV_FLOAT,
+-- AGTV_VERTEX, AGTV_EDGE, AGTV_PATH) that jsonb does not recognize.
+CREATE FUNCTION ag_catalog.agtype_to_jsonb(agtype)
+ RETURNS jsonb
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'SELECT ag_catalog.agtype_to_json($1)::jsonb';
+
+CREATE CAST (agtype AS jsonb)
+ WITH FUNCTION ag_catalog.agtype_to_jsonb(agtype);
+
+-- jsonb -> agtype (explicit)
+CREATE FUNCTION ag_catalog.jsonb_to_agtype(jsonb)
+ RETURNS agtype
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+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';
+
+--
+-- Composite types for vertex and edge
+--
+CREATE TYPE ag_catalog.vertex AS (
+ id graphid,
+ label agtype,
+ properties agtype
+);
+
+CREATE TYPE ag_catalog.edge AS (
+ id graphid,
+ label agtype,
+ end_id graphid,
+ start_id graphid,
+ properties agtype
+);
+
+--
+-- vertex/edge to agtype cast functions
+--
+CREATE FUNCTION ag_catalog.vertex_to_agtype(vertex)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_agtype(edge)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Implicit casts from vertex/edge to agtype
+--
+CREATE CAST (vertex AS agtype)
+ WITH FUNCTION ag_catalog.vertex_to_agtype(vertex)
+AS IMPLICIT;
+
+CREATE CAST (edge AS agtype)
+ WITH FUNCTION ag_catalog.edge_to_agtype(edge)
+AS IMPLICIT;
+
+CREATE FUNCTION ag_catalog.vertex_to_json(vertex)
+ RETURNS json
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_json(edge)
+ RETURNS json
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE CAST (vertex AS json)
+ WITH FUNCTION ag_catalog.vertex_to_json(vertex);
+
+CREATE CAST (edge AS json)
+ WITH FUNCTION ag_catalog.edge_to_json(edge);
+
+CREATE FUNCTION ag_catalog.vertex_to_jsonb(vertex)
+ RETURNS jsonb
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_jsonb(edge)
+ RETURNS jsonb
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE CAST (vertex AS jsonb)
+ WITH FUNCTION ag_catalog.vertex_to_jsonb(vertex);
+
+CREATE CAST (edge AS jsonb)
+ WITH FUNCTION ag_catalog.edge_to_jsonb(edge);
+
+--
+-- Equality operators for vertex and edge (compare by id)
+--
+CREATE FUNCTION ag_catalog.vertex_eq(vertex, vertex)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id = $2.id $$;
+
+CREATE OPERATOR = (
+ FUNCTION = ag_catalog.vertex_eq,
+ LEFTARG = vertex,
+ RIGHTARG = vertex,
+ COMMUTATOR = =,
+ NEGATOR = <>,
+ RESTRICT = eqsel,
+ JOIN = eqjoinsel
+);
+
+CREATE FUNCTION ag_catalog.vertex_ne(vertex, vertex)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id <> $2.id $$;
+
+CREATE OPERATOR <> (
+ FUNCTION = ag_catalog.vertex_ne,
+ LEFTARG = vertex,
+ RIGHTARG = vertex,
+ COMMUTATOR = <>,
+ NEGATOR = =,
+ RESTRICT = neqsel,
+ JOIN = neqjoinsel
+);
+
+CREATE FUNCTION ag_catalog.edge_eq(edge, edge)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id = $2.id $$;
+
+CREATE OPERATOR = (
+ FUNCTION = ag_catalog.edge_eq,
+ LEFTARG = edge,
+ RIGHTARG = edge,
+ COMMUTATOR = =,
+ NEGATOR = <>,
+ RESTRICT = eqsel,
+ JOIN = eqjoinsel
+);
+
+CREATE FUNCTION ag_catalog.edge_ne(edge, edge)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id <> $2.id $$;
+
+CREATE OPERATOR <> (
+ FUNCTION = ag_catalog.edge_ne,
+ LEFTARG = edge,
+ RIGHTARG = edge,
+ COMMUTATOR = <>,
+ NEGATOR = =,
+ RESTRICT = neqsel,
+ JOIN = neqjoinsel
+);
+
+--
+-- Drop and recreate _label_name with new return type (cstring -> agtype)
+--
+DROP FUNCTION IF EXISTS ag_catalog._label_name(oid, graphid);
+
+CREATE FUNCTION ag_catalog._label_name(graph_oid oid, graphid)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Drop and recreate _agtype_build_vertex with new signature (cstring ->
agtype for label)
+--
+DROP FUNCTION IF EXISTS ag_catalog._agtype_build_vertex(graphid, cstring,
agtype);
+
+CREATE FUNCTION ag_catalog._agtype_build_vertex(graphid, agtype, agtype)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+CALLED ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Drop and recreate _agtype_build_edge with new signature (cstring -> agtype
for label)
+--
+DROP FUNCTION IF EXISTS ag_catalog._agtype_build_edge(graphid, graphid,
graphid, cstring, agtype);
+
+CREATE FUNCTION ag_catalog._agtype_build_edge(graphid, graphid, graphid,
+ agtype, agtype)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+CALLED ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Helper function for optimized startNode/endNode
+--
+CREATE FUNCTION ag_catalog._get_vertex_by_graphid(text, graphid)
+ RETURNS agtype
+ LANGUAGE c
+ STABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+-- Internal selftest for the agehash open-addressing hashtable. Returns "OK"
+-- on success or "FAIL: ..." with a diagnostic message. Intended for the
+-- agehash regression test only.
+CREATE FUNCTION ag_catalog._agehash_self_test()
+ RETURNS text
+ LANGUAGE c
+ VOLATILE
+ PARALLEL UNSAFE
+AS 'MODULE_PATHNAME';::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';
+
+--
+-- Composite types for vertex and edge
+--
+CREATE TYPE ag_catalog.vertex AS (
+ id graphid,
+ label agtype,
+ properties agtype
+);
+
+CREATE TYPE ag_catalog.edge AS (
+ id graphid,
+ label agtype,
+ end_id graphid,
+ start_id graphid,
+ properties agtype
+);
+
+--
+-- vertex/edge to agtype cast functions
+--
+CREATE FUNCTION ag_catalog.vertex_to_agtype(vertex)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_agtype(edge)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Implicit casts from vertex/edge to agtype
+--
+CREATE CAST (vertex AS agtype)
+ WITH FUNCTION ag_catalog.vertex_to_agtype(vertex)
+AS IMPLICIT;
+
+CREATE CAST (edge AS agtype)
+ WITH FUNCTION ag_catalog.edge_to_agtype(edge)
+AS IMPLICIT;
+
+CREATE FUNCTION ag_catalog.vertex_to_json(vertex)
+ RETURNS json
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_json(edge)
+ RETURNS json
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE CAST (vertex AS json)
+ WITH FUNCTION ag_catalog.vertex_to_json(vertex);
+
+CREATE CAST (edge AS json)
+ WITH FUNCTION ag_catalog.edge_to_json(edge);
+
+CREATE FUNCTION ag_catalog.vertex_to_jsonb(vertex)
+ RETURNS jsonb
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_jsonb(edge)
+ RETURNS jsonb
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE CAST (vertex AS jsonb)
+ WITH FUNCTION ag_catalog.vertex_to_jsonb(vertex);
+
+CREATE CAST (edge AS jsonb)
+ WITH FUNCTION ag_catalog.edge_to_jsonb(edge);
+
+--
+-- Equality operators for vertex and edge (compare by id)
+--
+CREATE FUNCTION ag_catalog.vertex_eq(vertex, vertex)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $ SELECT --
+-- agtype <-> jsonb bidirectional casts
+--
+
+-- agtype -> jsonb (explicit)
+-- Uses json intermediate (agtype_to_json -> json::jsonb) because agtype
+-- extends jsonb's binary format with types (AGTV_INTEGER, AGTV_FLOAT,
+-- AGTV_VERTEX, AGTV_EDGE, AGTV_PATH) that jsonb does not recognize.
+CREATE FUNCTION ag_catalog.agtype_to_jsonb(agtype)
+ RETURNS jsonb
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'SELECT ag_catalog.agtype_to_json($1)::jsonb';
+
+CREATE CAST (agtype AS jsonb)
+ WITH FUNCTION ag_catalog.agtype_to_jsonb(agtype);
+
+-- jsonb -> agtype (explicit)
+CREATE FUNCTION ag_catalog.jsonb_to_agtype(jsonb)
+ RETURNS agtype
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+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';
+
+--
+-- Composite types for vertex and edge
+--
+CREATE TYPE ag_catalog.vertex AS (
+ id graphid,
+ label agtype,
+ properties agtype
+);
+
+CREATE TYPE ag_catalog.edge AS (
+ id graphid,
+ label agtype,
+ end_id graphid,
+ start_id graphid,
+ properties agtype
+);
+
+--
+-- vertex/edge to agtype cast functions
+--
+CREATE FUNCTION ag_catalog.vertex_to_agtype(vertex)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_agtype(edge)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Implicit casts from vertex/edge to agtype
+--
+CREATE CAST (vertex AS agtype)
+ WITH FUNCTION ag_catalog.vertex_to_agtype(vertex)
+AS IMPLICIT;
+
+CREATE CAST (edge AS agtype)
+ WITH FUNCTION ag_catalog.edge_to_agtype(edge)
+AS IMPLICIT;
+
+CREATE FUNCTION ag_catalog.vertex_to_json(vertex)
+ RETURNS json
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_json(edge)
+ RETURNS json
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE CAST (vertex AS json)
+ WITH FUNCTION ag_catalog.vertex_to_json(vertex);
+
+CREATE CAST (edge AS json)
+ WITH FUNCTION ag_catalog.edge_to_json(edge);
+
+CREATE FUNCTION ag_catalog.vertex_to_jsonb(vertex)
+ RETURNS jsonb
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_jsonb(edge)
+ RETURNS jsonb
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE CAST (vertex AS jsonb)
+ WITH FUNCTION ag_catalog.vertex_to_jsonb(vertex);
+
+CREATE CAST (edge AS jsonb)
+ WITH FUNCTION ag_catalog.edge_to_jsonb(edge);
+
+--
+-- Equality operators for vertex and edge (compare by id)
+--
+CREATE FUNCTION ag_catalog.vertex_eq(vertex, vertex)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id = $2.id $$;
+
+CREATE OPERATOR = (
+ FUNCTION = ag_catalog.vertex_eq,
+ LEFTARG = vertex,
+ RIGHTARG = vertex,
+ COMMUTATOR = =,
+ NEGATOR = <>,
+ RESTRICT = eqsel,
+ JOIN = eqjoinsel
+);
+
+CREATE FUNCTION ag_catalog.vertex_ne(vertex, vertex)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id <> $2.id $$;
+
+CREATE OPERATOR <> (
+ FUNCTION = ag_catalog.vertex_ne,
+ LEFTARG = vertex,
+ RIGHTARG = vertex,
+ COMMUTATOR = <>,
+ NEGATOR = =,
+ RESTRICT = neqsel,
+ JOIN = neqjoinsel
+);
+
+CREATE FUNCTION ag_catalog.edge_eq(edge, edge)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id = $2.id $$;
+
+CREATE OPERATOR = (
+ FUNCTION = ag_catalog.edge_eq,
+ LEFTARG = edge,
+ RIGHTARG = edge,
+ COMMUTATOR = =,
+ NEGATOR = <>,
+ RESTRICT = eqsel,
+ JOIN = eqjoinsel
+);
+
+CREATE FUNCTION ag_catalog.edge_ne(edge, edge)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id <> $2.id $$;
+
+CREATE OPERATOR <> (
+ FUNCTION = ag_catalog.edge_ne,
+ LEFTARG = edge,
+ RIGHTARG = edge,
+ COMMUTATOR = <>,
+ NEGATOR = =,
+ RESTRICT = neqsel,
+ JOIN = neqjoinsel
+);
+
+--
+-- Drop and recreate _label_name with new return type (cstring -> agtype)
+--
+DROP FUNCTION IF EXISTS ag_catalog._label_name(oid, graphid);
+
+CREATE FUNCTION ag_catalog._label_name(graph_oid oid, graphid)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Drop and recreate _agtype_build_vertex with new signature (cstring ->
agtype for label)
+--
+DROP FUNCTION IF EXISTS ag_catalog._agtype_build_vertex(graphid, cstring,
agtype);
+
+CREATE FUNCTION ag_catalog._agtype_build_vertex(graphid, agtype, agtype)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+CALLED ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Drop and recreate _agtype_build_edge with new signature (cstring -> agtype
for label)
+--
+DROP FUNCTION IF EXISTS ag_catalog._agtype_build_edge(graphid, graphid,
graphid, cstring, agtype);
+
+CREATE FUNCTION ag_catalog._agtype_build_edge(graphid, graphid, graphid,
+ agtype, agtype)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+CALLED ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Helper function for optimized startNode/endNode
+--
+CREATE FUNCTION ag_catalog._get_vertex_by_graphid(text, graphid)
+ RETURNS agtype
+ LANGUAGE c
+ STABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+-- Internal selftest for the agehash open-addressing hashtable. Returns "OK"
+-- on success or "FAIL: ..." with a diagnostic message. Intended for the
+-- agehash regression test only.
+CREATE FUNCTION ag_catalog._agehash_self_test()
+ RETURNS text
+ LANGUAGE c
+ VOLATILE
+ PARALLEL UNSAFE
+AS 'MODULE_PATHNAME';.id =
Review Comment:
Resolved — this stray fragment was part of the same rebase garbling of
age--1.7.0--y.y.y.sql. The file has been regenerated from the pristine master
version with only the ALTER OPERATOR block appended, so the
_agehash_self_test() function now ends cleanly at \AS 'MODULE_PATHNAME';\ with
no trailing text.
##########
age--1.7.0--y.y.y.sql:
##########
@@ -464,6 +464,1841 @@ $$;
-- agtype <-> jsonb bidirectional casts
--
+-- agtype -> jsonb (explicit)
+-- Uses json intermediate (agtype_to_json -> json::jsonb) because agtype
+-- extends jsonb's binary format with types (AGTV_INTEGER, AGTV_FLOAT,
+-- AGTV_VERTEX, AGTV_EDGE, AGTV_PATH) that jsonb does not recognize.
+CREATE FUNCTION ag_catalog.agtype_to_jsonb(agtype)
+ RETURNS jsonb
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'SELECT ag_catalog.agtype_to_json(--
+-- agtype <-> jsonb bidirectional casts
+--
+
+-- agtype -> jsonb (explicit)
+-- Uses json intermediate (agtype_to_json -> json::jsonb) because agtype
+-- extends jsonb's binary format with types (AGTV_INTEGER, AGTV_FLOAT,
+-- AGTV_VERTEX, AGTV_EDGE, AGTV_PATH) that jsonb does not recognize.
+CREATE FUNCTION ag_catalog.agtype_to_jsonb(agtype)
+ RETURNS jsonb
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'SELECT ag_catalog.agtype_to_json($1)::jsonb';
+
+CREATE CAST (agtype AS jsonb)
+ WITH FUNCTION ag_catalog.agtype_to_jsonb(agtype);
+
+-- jsonb -> agtype (explicit)
+CREATE FUNCTION ag_catalog.jsonb_to_agtype(jsonb)
+ RETURNS agtype
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+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';
+
+--
+-- Composite types for vertex and edge
+--
+CREATE TYPE ag_catalog.vertex AS (
+ id graphid,
+ label agtype,
+ properties agtype
+);
+
+CREATE TYPE ag_catalog.edge AS (
+ id graphid,
+ label agtype,
+ end_id graphid,
+ start_id graphid,
+ properties agtype
+);
+
+--
+-- vertex/edge to agtype cast functions
+--
+CREATE FUNCTION ag_catalog.vertex_to_agtype(vertex)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_agtype(edge)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Implicit casts from vertex/edge to agtype
+--
+CREATE CAST (vertex AS agtype)
+ WITH FUNCTION ag_catalog.vertex_to_agtype(vertex)
+AS IMPLICIT;
+
+CREATE CAST (edge AS agtype)
+ WITH FUNCTION ag_catalog.edge_to_agtype(edge)
+AS IMPLICIT;
+
+CREATE FUNCTION ag_catalog.vertex_to_json(vertex)
+ RETURNS json
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_json(edge)
+ RETURNS json
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE CAST (vertex AS json)
+ WITH FUNCTION ag_catalog.vertex_to_json(vertex);
+
+CREATE CAST (edge AS json)
+ WITH FUNCTION ag_catalog.edge_to_json(edge);
+
+CREATE FUNCTION ag_catalog.vertex_to_jsonb(vertex)
+ RETURNS jsonb
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_jsonb(edge)
+ RETURNS jsonb
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE CAST (vertex AS jsonb)
+ WITH FUNCTION ag_catalog.vertex_to_jsonb(vertex);
+
+CREATE CAST (edge AS jsonb)
+ WITH FUNCTION ag_catalog.edge_to_jsonb(edge);
+
+--
+-- Equality operators for vertex and edge (compare by id)
+--
+CREATE FUNCTION ag_catalog.vertex_eq(vertex, vertex)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id = $2.id $$;
+
+CREATE OPERATOR = (
+ FUNCTION = ag_catalog.vertex_eq,
+ LEFTARG = vertex,
+ RIGHTARG = vertex,
+ COMMUTATOR = =,
+ NEGATOR = <>,
+ RESTRICT = eqsel,
+ JOIN = eqjoinsel
+);
+
+CREATE FUNCTION ag_catalog.vertex_ne(vertex, vertex)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id <> $2.id $$;
+
+CREATE OPERATOR <> (
+ FUNCTION = ag_catalog.vertex_ne,
+ LEFTARG = vertex,
+ RIGHTARG = vertex,
+ COMMUTATOR = <>,
+ NEGATOR = =,
+ RESTRICT = neqsel,
+ JOIN = neqjoinsel
+);
+
+CREATE FUNCTION ag_catalog.edge_eq(edge, edge)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id = $2.id $$;
+
+CREATE OPERATOR = (
+ FUNCTION = ag_catalog.edge_eq,
+ LEFTARG = edge,
+ RIGHTARG = edge,
+ COMMUTATOR = =,
+ NEGATOR = <>,
+ RESTRICT = eqsel,
+ JOIN = eqjoinsel
+);
+
+CREATE FUNCTION ag_catalog.edge_ne(edge, edge)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id <> $2.id $$;
+
+CREATE OPERATOR <> (
+ FUNCTION = ag_catalog.edge_ne,
+ LEFTARG = edge,
+ RIGHTARG = edge,
+ COMMUTATOR = <>,
+ NEGATOR = =,
+ RESTRICT = neqsel,
+ JOIN = neqjoinsel
+);
+
+--
+-- Drop and recreate _label_name with new return type (cstring -> agtype)
+--
+DROP FUNCTION IF EXISTS ag_catalog._label_name(oid, graphid);
+
+CREATE FUNCTION ag_catalog._label_name(graph_oid oid, graphid)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Drop and recreate _agtype_build_vertex with new signature (cstring ->
agtype for label)
+--
+DROP FUNCTION IF EXISTS ag_catalog._agtype_build_vertex(graphid, cstring,
agtype);
+
+CREATE FUNCTION ag_catalog._agtype_build_vertex(graphid, agtype, agtype)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+CALLED ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Drop and recreate _agtype_build_edge with new signature (cstring -> agtype
for label)
+--
+DROP FUNCTION IF EXISTS ag_catalog._agtype_build_edge(graphid, graphid,
graphid, cstring, agtype);
+
+CREATE FUNCTION ag_catalog._agtype_build_edge(graphid, graphid, graphid,
+ agtype, agtype)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+CALLED ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Helper function for optimized startNode/endNode
+--
+CREATE FUNCTION ag_catalog._get_vertex_by_graphid(text, graphid)
+ RETURNS agtype
+ LANGUAGE c
+ STABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+-- Internal selftest for the agehash open-addressing hashtable. Returns "OK"
+-- on success or "FAIL: ..." with a diagnostic message. Intended for the
+-- agehash regression test only.
+CREATE FUNCTION ag_catalog._agehash_self_test()
+ RETURNS text
+ LANGUAGE c
+ VOLATILE
+ PARALLEL UNSAFE
+AS 'MODULE_PATHNAME';)::jsonb';
+
+CREATE CAST (agtype AS jsonb)
+ WITH FUNCTION ag_catalog.agtype_to_jsonb(agtype);
+
+-- jsonb -> agtype (explicit)
+CREATE FUNCTION ag_catalog.jsonb_to_agtype(jsonb)
+ RETURNS agtype
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'SELECT --
+-- agtype <-> jsonb bidirectional casts
+--
+
+-- agtype -> jsonb (explicit)
+-- Uses json intermediate (agtype_to_json -> json::jsonb) because agtype
+-- extends jsonb's binary format with types (AGTV_INTEGER, AGTV_FLOAT,
+-- AGTV_VERTEX, AGTV_EDGE, AGTV_PATH) that jsonb does not recognize.
+CREATE FUNCTION ag_catalog.agtype_to_jsonb(agtype)
+ RETURNS jsonb
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'SELECT ag_catalog.agtype_to_json($1)::jsonb';
+
+CREATE CAST (agtype AS jsonb)
+ WITH FUNCTION ag_catalog.agtype_to_jsonb(agtype);
+
+-- jsonb -> agtype (explicit)
+CREATE FUNCTION ag_catalog.jsonb_to_agtype(jsonb)
+ RETURNS agtype
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+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';
+
+--
+-- Composite types for vertex and edge
+--
+CREATE TYPE ag_catalog.vertex AS (
+ id graphid,
+ label agtype,
+ properties agtype
+);
+
+CREATE TYPE ag_catalog.edge AS (
+ id graphid,
+ label agtype,
+ end_id graphid,
+ start_id graphid,
+ properties agtype
+);
+
+--
+-- vertex/edge to agtype cast functions
+--
+CREATE FUNCTION ag_catalog.vertex_to_agtype(vertex)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_agtype(edge)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Implicit casts from vertex/edge to agtype
+--
+CREATE CAST (vertex AS agtype)
+ WITH FUNCTION ag_catalog.vertex_to_agtype(vertex)
+AS IMPLICIT;
+
+CREATE CAST (edge AS agtype)
+ WITH FUNCTION ag_catalog.edge_to_agtype(edge)
+AS IMPLICIT;
+
+CREATE FUNCTION ag_catalog.vertex_to_json(vertex)
+ RETURNS json
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_json(edge)
+ RETURNS json
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE CAST (vertex AS json)
+ WITH FUNCTION ag_catalog.vertex_to_json(vertex);
+
+CREATE CAST (edge AS json)
+ WITH FUNCTION ag_catalog.edge_to_json(edge);
+
+CREATE FUNCTION ag_catalog.vertex_to_jsonb(vertex)
+ RETURNS jsonb
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_jsonb(edge)
+ RETURNS jsonb
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE CAST (vertex AS jsonb)
+ WITH FUNCTION ag_catalog.vertex_to_jsonb(vertex);
+
+CREATE CAST (edge AS jsonb)
+ WITH FUNCTION ag_catalog.edge_to_jsonb(edge);
+
+--
+-- Equality operators for vertex and edge (compare by id)
+--
+CREATE FUNCTION ag_catalog.vertex_eq(vertex, vertex)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id = $2.id $$;
+
+CREATE OPERATOR = (
+ FUNCTION = ag_catalog.vertex_eq,
+ LEFTARG = vertex,
+ RIGHTARG = vertex,
+ COMMUTATOR = =,
+ NEGATOR = <>,
+ RESTRICT = eqsel,
+ JOIN = eqjoinsel
+);
+
+CREATE FUNCTION ag_catalog.vertex_ne(vertex, vertex)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id <> $2.id $$;
+
+CREATE OPERATOR <> (
+ FUNCTION = ag_catalog.vertex_ne,
+ LEFTARG = vertex,
+ RIGHTARG = vertex,
+ COMMUTATOR = <>,
+ NEGATOR = =,
+ RESTRICT = neqsel,
+ JOIN = neqjoinsel
+);
+
+CREATE FUNCTION ag_catalog.edge_eq(edge, edge)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id = $2.id $$;
+
+CREATE OPERATOR = (
+ FUNCTION = ag_catalog.edge_eq,
+ LEFTARG = edge,
+ RIGHTARG = edge,
+ COMMUTATOR = =,
+ NEGATOR = <>,
+ RESTRICT = eqsel,
+ JOIN = eqjoinsel
+);
+
+CREATE FUNCTION ag_catalog.edge_ne(edge, edge)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id <> $2.id $$;
+
+CREATE OPERATOR <> (
+ FUNCTION = ag_catalog.edge_ne,
+ LEFTARG = edge,
+ RIGHTARG = edge,
+ COMMUTATOR = <>,
+ NEGATOR = =,
+ RESTRICT = neqsel,
+ JOIN = neqjoinsel
+);
+
+--
+-- Drop and recreate _label_name with new return type (cstring -> agtype)
+--
+DROP FUNCTION IF EXISTS ag_catalog._label_name(oid, graphid);
+
+CREATE FUNCTION ag_catalog._label_name(graph_oid oid, graphid)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Drop and recreate _agtype_build_vertex with new signature (cstring ->
agtype for label)
+--
+DROP FUNCTION IF EXISTS ag_catalog._agtype_build_vertex(graphid, cstring,
agtype);
+
+CREATE FUNCTION ag_catalog._agtype_build_vertex(graphid, agtype, agtype)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+CALLED ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Drop and recreate _agtype_build_edge with new signature (cstring -> agtype
for label)
+--
+DROP FUNCTION IF EXISTS ag_catalog._agtype_build_edge(graphid, graphid,
graphid, cstring, agtype);
+
+CREATE FUNCTION ag_catalog._agtype_build_edge(graphid, graphid, graphid,
+ agtype, agtype)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+CALLED ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Helper function for optimized startNode/endNode
+--
+CREATE FUNCTION ag_catalog._get_vertex_by_graphid(text, graphid)
+ RETURNS agtype
+ LANGUAGE c
+ STABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+-- Internal selftest for the agehash open-addressing hashtable. Returns "OK"
+-- on success or "FAIL: ..." with a diagnostic message. Intended for the
+-- agehash regression test only.
+CREATE FUNCTION ag_catalog._agehash_self_test()
+ RETURNS text
+ LANGUAGE c
+ VOLATILE
+ PARALLEL UNSAFE
+AS 'MODULE_PATHNAME';::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';
+
+--
+-- Composite types for vertex and edge
+--
+CREATE TYPE ag_catalog.vertex AS (
+ id graphid,
+ label agtype,
+ properties agtype
+);
+
+CREATE TYPE ag_catalog.edge AS (
+ id graphid,
+ label agtype,
+ end_id graphid,
+ start_id graphid,
+ properties agtype
+);
+
+--
+-- vertex/edge to agtype cast functions
+--
+CREATE FUNCTION ag_catalog.vertex_to_agtype(vertex)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_agtype(edge)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Implicit casts from vertex/edge to agtype
+--
+CREATE CAST (vertex AS agtype)
+ WITH FUNCTION ag_catalog.vertex_to_agtype(vertex)
+AS IMPLICIT;
+
+CREATE CAST (edge AS agtype)
+ WITH FUNCTION ag_catalog.edge_to_agtype(edge)
+AS IMPLICIT;
+
+CREATE FUNCTION ag_catalog.vertex_to_json(vertex)
+ RETURNS json
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_json(edge)
+ RETURNS json
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE CAST (vertex AS json)
+ WITH FUNCTION ag_catalog.vertex_to_json(vertex);
+
+CREATE CAST (edge AS json)
+ WITH FUNCTION ag_catalog.edge_to_json(edge);
+
+CREATE FUNCTION ag_catalog.vertex_to_jsonb(vertex)
+ RETURNS jsonb
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_jsonb(edge)
+ RETURNS jsonb
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE CAST (vertex AS jsonb)
+ WITH FUNCTION ag_catalog.vertex_to_jsonb(vertex);
+
+CREATE CAST (edge AS jsonb)
+ WITH FUNCTION ag_catalog.edge_to_jsonb(edge);
+
+--
+-- Equality operators for vertex and edge (compare by id)
+--
+CREATE FUNCTION ag_catalog.vertex_eq(vertex, vertex)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $ SELECT --
+-- agtype <-> jsonb bidirectional casts
+--
+
+-- agtype -> jsonb (explicit)
+-- Uses json intermediate (agtype_to_json -> json::jsonb) because agtype
+-- extends jsonb's binary format with types (AGTV_INTEGER, AGTV_FLOAT,
+-- AGTV_VERTEX, AGTV_EDGE, AGTV_PATH) that jsonb does not recognize.
+CREATE FUNCTION ag_catalog.agtype_to_jsonb(agtype)
+ RETURNS jsonb
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'SELECT ag_catalog.agtype_to_json($1)::jsonb';
+
+CREATE CAST (agtype AS jsonb)
+ WITH FUNCTION ag_catalog.agtype_to_jsonb(agtype);
+
+-- jsonb -> agtype (explicit)
+CREATE FUNCTION ag_catalog.jsonb_to_agtype(jsonb)
+ RETURNS agtype
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+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';
+
+--
+-- Composite types for vertex and edge
+--
+CREATE TYPE ag_catalog.vertex AS (
+ id graphid,
+ label agtype,
+ properties agtype
+);
+
+CREATE TYPE ag_catalog.edge AS (
+ id graphid,
+ label agtype,
+ end_id graphid,
+ start_id graphid,
+ properties agtype
+);
+
+--
+-- vertex/edge to agtype cast functions
+--
+CREATE FUNCTION ag_catalog.vertex_to_agtype(vertex)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_agtype(edge)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Implicit casts from vertex/edge to agtype
+--
+CREATE CAST (vertex AS agtype)
+ WITH FUNCTION ag_catalog.vertex_to_agtype(vertex)
+AS IMPLICIT;
+
+CREATE CAST (edge AS agtype)
+ WITH FUNCTION ag_catalog.edge_to_agtype(edge)
+AS IMPLICIT;
+
+CREATE FUNCTION ag_catalog.vertex_to_json(vertex)
+ RETURNS json
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_json(edge)
+ RETURNS json
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE CAST (vertex AS json)
+ WITH FUNCTION ag_catalog.vertex_to_json(vertex);
+
+CREATE CAST (edge AS json)
+ WITH FUNCTION ag_catalog.edge_to_json(edge);
+
+CREATE FUNCTION ag_catalog.vertex_to_jsonb(vertex)
+ RETURNS jsonb
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog.edge_to_jsonb(edge)
+ RETURNS jsonb
+ LANGUAGE c
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE CAST (vertex AS jsonb)
+ WITH FUNCTION ag_catalog.vertex_to_jsonb(vertex);
+
+CREATE CAST (edge AS jsonb)
+ WITH FUNCTION ag_catalog.edge_to_jsonb(edge);
+
+--
+-- Equality operators for vertex and edge (compare by id)
+--
+CREATE FUNCTION ag_catalog.vertex_eq(vertex, vertex)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id = $2.id $$;
+
+CREATE OPERATOR = (
+ FUNCTION = ag_catalog.vertex_eq,
+ LEFTARG = vertex,
+ RIGHTARG = vertex,
+ COMMUTATOR = =,
+ NEGATOR = <>,
+ RESTRICT = eqsel,
+ JOIN = eqjoinsel
+);
+
+CREATE FUNCTION ag_catalog.vertex_ne(vertex, vertex)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id <> $2.id $$;
+
+CREATE OPERATOR <> (
+ FUNCTION = ag_catalog.vertex_ne,
+ LEFTARG = vertex,
+ RIGHTARG = vertex,
+ COMMUTATOR = <>,
+ NEGATOR = =,
+ RESTRICT = neqsel,
+ JOIN = neqjoinsel
+);
+
+CREATE FUNCTION ag_catalog.edge_eq(edge, edge)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id = $2.id $$;
+
+CREATE OPERATOR = (
+ FUNCTION = ag_catalog.edge_eq,
+ LEFTARG = edge,
+ RIGHTARG = edge,
+ COMMUTATOR = =,
+ NEGATOR = <>,
+ RESTRICT = eqsel,
+ JOIN = eqjoinsel
+);
+
+CREATE FUNCTION ag_catalog.edge_ne(edge, edge)
+ RETURNS boolean
+ LANGUAGE sql
+ IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS $$ SELECT $1.id <> $2.id $$;
+
+CREATE OPERATOR <> (
+ FUNCTION = ag_catalog.edge_ne,
+ LEFTARG = edge,
+ RIGHTARG = edge,
+ COMMUTATOR = <>,
+ NEGATOR = =,
+ RESTRICT = neqsel,
+ JOIN = neqjoinsel
+);
+
+--
+-- Drop and recreate _label_name with new return type (cstring -> agtype)
+--
+DROP FUNCTION IF EXISTS ag_catalog._label_name(oid, graphid);
+
+CREATE FUNCTION ag_catalog._label_name(graph_oid oid, graphid)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Drop and recreate _agtype_build_vertex with new signature (cstring ->
agtype for label)
+--
+DROP FUNCTION IF EXISTS ag_catalog._agtype_build_vertex(graphid, cstring,
agtype);
+
+CREATE FUNCTION ag_catalog._agtype_build_vertex(graphid, agtype, agtype)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+CALLED ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Drop and recreate _agtype_build_edge with new signature (cstring -> agtype
for label)
+--
+DROP FUNCTION IF EXISTS ag_catalog._agtype_build_edge(graphid, graphid,
graphid, cstring, agtype);
+
+CREATE FUNCTION ag_catalog._agtype_build_edge(graphid, graphid, graphid,
+ agtype, agtype)
+ RETURNS agtype
+ LANGUAGE c
+ IMMUTABLE
+CALLED ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+--
+-- Helper function for optimized startNode/endNode
+--
+CREATE FUNCTION ag_catalog._get_vertex_by_graphid(text, graphid)
+ RETURNS agtype
+ LANGUAGE c
+ STABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+-- Internal selftest for the agehash open-addressing hashtable. Returns "OK"
+-- on success or "FAIL: ..." with a diagnostic message. Intended for the
+-- agehash regression test only.
+CREATE FUNCTION ag_catalog._agehash_self_test()
+ RETURNS text
+ LANGUAGE c
+ VOLATILE
+ PARALLEL UNSAFE
+AS 'MODULE_PATHNAME';.id =
+--
+-- Issue #2356: restore lightweight selectivity functions for containment
+-- and key-existence operators.
+--
+-- The PG14+ branches of AGE bound RESTRICT=matchingsel / JOIN=matchingjoinsel
+-- on @>, <@, @>>, <<@, ?, ?|, ?&. matchingsel is built for pattern operators
+-- (LIKE / regex) and invokes the operator's underlying support function on
+-- pg_statistic MCVs during planning. For agtype that re-runs agtype_contains
+-- per MCV, which can dominate planning time on point queries (TPS regression
+-- reported on PG18). PostgreSQL core itself binds @>/<@/? on jsonb to
+-- contsel/contjoinsel for the same reason; this aligns AGE with that
+-- precedent.
+--
+ALTER OPERATOR ag_catalog.@>(agtype, agtype)
+ SET (RESTRICT = contsel, JOIN = contjoinsel);
+ALTER OPERATOR ag_catalog.<@(agtype, agtype)
+ SET (RESTRICT = contsel, JOIN = contjoinsel);
+ALTER OPERATOR ag_catalog.@>>(agtype, agtype)
+ SET (RESTRICT = contsel, JOIN = contjoinsel);
+ALTER OPERATOR ag_catalog.<<@(agtype, agtype)
+ SET (RESTRICT = contsel, JOIN = contjoinsel);
+ALTER OPERATOR ag_catalog.?(agtype, text)
+ SET (RESTRICT = contsel, JOIN = contjoinsel);
+ALTER OPERATOR ag_catalog.?(agtype, agtype)
+ SET (RESTRICT = contsel, JOIN = contjoinsel);
+ALTER OPERATOR ag_catalog.?|(agtype, text[])
+ SET (RESTRICT = contsel, JOIN = contjoinsel);
+ALTER OPERATOR ag_catalog.?|(agtype, agtype)
+ SET (RESTRICT = contsel, JOIN = contjoinsel);
+ALTER OPERATOR ag_catalog.?&(agtype, text[])
+ SET (RESTRICT = contsel, JOIN = contjoinsel);
+ALTER OPERATOR ag_catalog.?&(agtype, agtype)
+ SET (RESTRICT = contsel, JOIN = contjoinsel);.id $;
Review Comment:
Resolved with the same file regeneration. There is no longer any trailing
garbage — the final statement is \ALTER OPERATOR ag_catalog.?&(agtype, agtype)
SET (RESTRICT = contsel, JOIN = contjoinsel);\ ending cleanly at the semicolon.
The full diff vs master is now exactly the 34-line selectivity block.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]