Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,8 @@ protected ExecutionStream executeTraversal(
// declared the user wants all distinct paths, so we null out the
// visited set to disable dedup entirely.
assert item.getFilter() != null : "filter guaranteed non-null in recursive branch";
var dedupVisited = item.getFilter().getPathAlias() == null ? visited : null;
var hasPathAlias = item.getFilter().getPathAlias() != null;
var dedupVisited = hasPathAlias ? null : visited;

// Evaluate the starting point against all filters
if (startingPoint != null
Expand All @@ -426,8 +427,10 @@ && matchesRid(iCommandContext, targetRid, startingPoint)) {
if (rs != null) {
// Store traversal metadata so the user can access it via depthAlias/pathAlias
rs.setMetadata("$depth", depth);
rs.setMetadata("$matchPath",
pathToHere == null ? PathNode.emptyPath() : pathToHere.toList());
if (hasPathAlias) {
rs.setMetadata("$matchPath",
pathToHere == null ? PathNode.emptyPath() : pathToHere.toList());
}
result.add(rs);
}
}
Expand Down Expand Up @@ -464,10 +467,10 @@ && matchesRid(iCommandContext, targetRid, startingPoint)) {
}
}

// Build the path by appending the current neighbor — O(1) cons-cell append
// instead of O(depth) ArrayList copy. The PathNode shares structure with
// all ancestor paths and is only materialized to a List when pathAlias is read.
var newPath = new PathNode(origin, pathToHere, depth);
// Only build the path when the user declared a pathAlias — otherwise skip
// all PathNode allocation entirely. For IS2 (no pathAlias) this eliminates
// all path-related allocations across the entire REPLY_OF chain.
var newPath = hasPathAlias ? new PathNode(origin, pathToHere, depth) : null;

// Recursive call with incremented depth, sharing the visited set
var subResult =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2265,6 +2265,59 @@ public void testPathAliasDiamondGraphReturnsAllPaths() {
resultPairs);
}

// Verifies that a WHILE traversal WITHOUT pathAlias produces the same vertices
// and depths as one WITH pathAlias, but does not expose any path property.
// This exercises the optimization that skips PathNode construction entirely
// when no pathAlias is declared (the common case for queries like IS2).
@Test
public void testWhileWithoutPathAliasSkipsPathConstruction() {
var clazz = "testWhileNoPath";
session.execute("CREATE CLASS " + clazz + " EXTENDS V").close();

session.begin();
session.execute("CREATE VERTEX " + clazz + " SET name = 'a'").close();
session.execute("CREATE VERTEX " + clazz + " SET name = 'b'").close();
session.execute("CREATE VERTEX " + clazz + " SET name = 'c'").close();

// Chain: a → b → c
session.execute(
"CREATE EDGE E FROM (SELECT FROM " + clazz + " WHERE name = 'a') "
+ "TO (SELECT FROM " + clazz + " WHERE name = 'b')")
.close();
session.execute(
"CREATE EDGE E FROM (SELECT FROM " + clazz + " WHERE name = 'b') "
+ "TO (SELECT FROM " + clazz + " WHERE name = 'c')")
.close();
session.commit();

// Query with depthAlias only (no pathAlias) — path construction should be skipped
var queryNoPath =
"MATCH { class: " + clazz
+ ", as:start, where:(name = 'a')} --> {as:dest, while:($depth<10),"
+ " depthAlias: d} RETURN dest.name as dname, d";

session.begin();
var result = session.query(queryNoPath);

// Collect (name, depth) pairs — should be: a:0, b:1, c:2
var pairs = new java.util.ArrayList<String>();
while (result.hasNext()) {
var item = result.next();
String dname = item.getProperty("dname");
Integer depth = item.getProperty("d");
Assert.assertNotNull("depthAlias must still be populated", depth);
pairs.add(dname + ":" + depth);
}
result.close();
session.commit();

java.util.Collections.sort(pairs);
Assert.assertEquals(
"WHILE without pathAlias must still traverse and return all reachable vertices",
java.util.List.of("a:0", "b:1", "c:2"),
pairs);
}

@Test
public void testNegativePattern() {
var clazz = "testNegativePattern";
Expand Down