Skip to content

Add shortest_path / all_shortest_paths SRFs#2430

Open
jrgemignani wants to merge 1 commit into
apache:masterfrom
jrgemignani:shortest_path_1
Open

Add shortest_path / all_shortest_paths SRFs#2430
jrgemignani wants to merge 1 commit into
apache:masterfrom
jrgemignani:shortest_path_1

Conversation

@jrgemignani
Copy link
Copy Markdown
Contributor

Add two C set-returning functions that compute unweighted (hop-count) shortest paths over the cached global graph adjacency via BFS, callable both at the SQL top level and inside a cypher() RETURN:

  • age_shortest_path(...) -> the single shortest path (0 or 1 rows)
  • age_all_shortest_paths(...) -> every shortest path, one per row

The signature follows the natural Cypher argument order (graph, start, end, edge_types, direction, min_hops, max_hops), registered in sql/agtype_typecast.sql (install) and age--1.7.0--y.y.y.sql (upgrade). Unimplemented parameters fail loudly: multiple relationship types and a non-zero min_hops raise ERRCODE_FEATURE_NOT_SUPPORTED. A single edge type (string or one-element array) is honored, and a NULL endpoint yields no rows per Cypher null semantics (wrong-typed endpoints / NULL graph still error).

To call the SRFs inside a cypher() RETURN, transform_cypher_return now sets query->hasTargetSRFs (it was the only results-producing clause that didn't, so the planner never added a ProjectSet node), and transform_FuncCall auto-prepends the graph name for snake_case shortest_path / all_shortest_paths. camelCase names are reserved for the future native grammar.

Robustness:

  • BFS guards against non-existent endpoints (returns 0 rows instead of crashing) and honors CHECK_FOR_INTERRUPTS.
  • An unknown edge label now matches no edges instead of silently traversing all of them (get_label_relation returns InvalidOid).
  • manage_GRAPH_global_contexts no longer self-deadlocks: its process-local mutex is released via PG_TRY/PG_CATCH if the critical section errors.

Adds the age_shortest_path regression test (directed/undirected, label filtering, parallel edges, self-loops, max_hops, the not-supported stubs, NULL and non-existent endpoint/graph guards). 37/37 installcheck pass.

Co-authored-by: Claude noreply@anthropic.com

modified: Makefile
modified: age--1.7.0--y.y.y.sql
new file: regress/expected/age_shortest_path.out
new file: regress/sql/age_shortest_path.sql
modified: sql/agtype_typecast.sql
modified: src/backend/parser/cypher_clause.c
modified: src/backend/parser/cypher_expr.c
modified: src/backend/utils/adt/age_global_graph.c
modified: src/backend/utils/adt/age_vle.c

Add two C set-returning functions that compute unweighted (hop-count)
shortest paths over the cached global graph adjacency via BFS, callable
both at the SQL top level and inside a cypher() RETURN:

  - age_shortest_path(...)       -> the single shortest path (0 or 1 rows)
  - age_all_shortest_paths(...)  -> every shortest path, one per row

The signature follows the natural Cypher argument order
(graph, start, end, edge_types, direction, min_hops, max_hops), registered
in sql/agtype_typecast.sql (install) and age--1.7.0--y.y.y.sql (upgrade).
Unimplemented parameters fail loudly: multiple relationship types and a
non-zero min_hops raise ERRCODE_FEATURE_NOT_SUPPORTED. A single edge type
(string or one-element array) is honored, and a NULL endpoint yields no
rows per Cypher null semantics (wrong-typed endpoints / NULL graph still
error).

To call the SRFs inside a cypher() RETURN, transform_cypher_return now sets
query->hasTargetSRFs (it was the only results-producing clause that didn't,
so the planner never added a ProjectSet node), and transform_FuncCall
auto-prepends the graph name for snake_case shortest_path /
all_shortest_paths. camelCase names are reserved for the future native
grammar.

Robustness:
  - BFS guards against non-existent endpoints (returns 0 rows instead of
    crashing) and honors CHECK_FOR_INTERRUPTS.
  - An unknown edge label now matches no edges instead of silently
    traversing all of them (get_label_relation returns InvalidOid).
  - manage_GRAPH_global_contexts no longer self-deadlocks: its process-local
    mutex is released via PG_TRY/PG_CATCH if the critical section errors.

Adds the age_shortest_path regression test (directed/undirected, label
filtering, parallel edges, self-loops, max_hops, the not-supported stubs,
NULL and non-existent endpoint/graph guards). 37/37 installcheck pass.

Co-authored-by: Claude noreply@anthropic.com

modified:   Makefile
modified:   age--1.7.0--y.y.y.sql
new file:   regress/expected/age_shortest_path.out
new file:   regress/sql/age_shortest_path.sql
modified:   sql/agtype_typecast.sql
modified:   src/backend/parser/cypher_clause.c
modified:   src/backend/parser/cypher_expr.c
modified:   src/backend/utils/adt/age_global_graph.c
modified:   src/backend/utils/adt/age_vle.c
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants