Skip to content

#4095 fix(cypher): anonymous directed rel patterns must not reuse the same edge - #4115

Merged
robfrank merged 2 commits into
mainfrom
fix/4095-directed-rel-reuse-isomorphism
May 6, 2026
Merged

#4095 fix(cypher): anonymous directed rel patterns must not reuse the same edge#4115
robfrank merged 2 commits into
mainfrom
fix/4095-directed-rel-reuse-isomorphism

Conversation

@robfrank

@robfrank robfrank commented May 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Fixes Consecutive directed relationship patterns may reuse the same relationship #4095 (companion to Consecutive undirected relationship patterns may reuse the same relationship #4096): consecutive anonymous relationship patterns in the same MATCH clause could reuse the same physical edge, producing spurious rows like (Alice, Bob, Alice) for (s)<-[:KNOWS]-(f)-[:KNOWS]->(d).
  • The Consecutive undirected relationship patterns may reuse the same relationship #4096 fix tracked named relationship variables in relVarsPerClause. Anonymous rels (rel.getVariable() == null) were never added, so sameClausePrecedingRelVars stayed empty and the per-row isomorphism check in ExpandAll.collectUsedEdgeRids had nothing to compare against. Same root pattern as the legacy MatchRelationshipStep handles via computeHopEdgeTrackingNeeds + synthetic " relN" names.
  • ExpandAll now has an edgeTrackingVar field that stashes the edge in the row under a synthetic property name even when edgeVariable is null. CypherOptimizer.computeNeedsEdgeTracking flags anonymous hops whose edge types overlap with a sibling hop in the same MATCH clause, and buildExpansionChain assigns each one a synthetic " anon_e_N" name, sets it on the operator before addTargetLabelFilter wraps it, and registers it in relVarsPerClause for subsequent hops.

Test plan

  • New Issue4095DirectedRelReuseIsomorphismTest (4 tests): diverging + converging row count + aggregate count
  • Issue4096UndirectedRelReuseIsomorphismTest still passes (named-variable path unchanged)
  • Issue4006BoundRelVarPathIsomorphismTest still passes
  • All 6572 Cypher tests pass with no regressions

… same edge

In the optimizer path, only named relationship variables were tracked in
relVarsPerClause for same-clause isomorphism, so anonymous multi-hop
patterns like (s)<-[:KNOWS]-(f)-[:KNOWS]->(d) could bind the same
physical edge to both slots.

ExpandAll gains an edgeTrackingVar field that, when set, stashes the edge
in the row under a synthetic property name even with no user variable.
CypherOptimizer.computeNeedsEdgeTracking flags anonymous hops whose edge
types overlap with a sibling hop in the same MATCH clause, and
buildExpansionChain assigns a synthetic name to each, sets it on the
ExpandAll, and registers it in relVarsPerClause so subsequent hops apply
the existing isomorphism check.
@codacy-production

codacy-production Bot commented May 6, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 17 complexity

Metric Results
Complexity 17

View in Codacy

🟢 Coverage 90.00% diff coverage · -7.76% coverage variation

Metric Results
Coverage variation -7.76% coverage variation
Diff coverage 90.00% diff coverage

View coverage diff in Codacy

Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (c1814a7) 123556 90737 73.44%
Head commit (fb92b57) 154945 (+31389) 101770 (+11033) 65.68% (-7.76%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#4115) 40 36 90.00%

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@robfrank robfrank added this to the 26.5.1 milestone May 6, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request addresses GitHub issue #4095 by enforcing Cypher relationship uniqueness for anonymous relationship variables within the same MATCH clause. It introduces a mechanism in CypherOptimizer to identify relationships requiring tracking and implements synthetic variable generation to store these edges in the ExpandAll operator. A comprehensive regression test suite is also added. Feedback was provided regarding the efficiency of the relationship type overlap detection logic in CypherOptimizer, suggesting a Map-based approach to replace the current nested loops for better performance and readability.

Comment on lines +257 to +269
outer:
for (int i = 0; i < clauseRels.size(); i++) {
for (int j = 0; j < clauseRels.size(); j++) {
if (i == j)
continue;
for (final String type : clauseRels.get(i).getTypes()) {
if (clauseRels.get(j).getTypes().contains(type)) {
needs.add(clauseRels.get(i));
continue outer;
}
}
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The logic to find relationships with overlapping types can be implemented more efficiently and readably. The current implementation uses nested loops with a complexity that is roughly quadratic in the number of relationships per clause, which could be slow for complex queries with many relationships.

A more efficient and declarative approach would be to use a map to group relationships by their types. This avoids the nested loops and manual index management, improving both performance and readability.

      final Map<String, List<LogicalRelationship>> relationshipsByType = new HashMap<>();
      for (final LogicalRelationship rel : clauseRels) {
        for (final String type : rel.getTypes()) {
          relationshipsByType.computeIfAbsent(type, k -> new ArrayList<>()).add(rel);
        }
      }

      for (final List<LogicalRelationship> rels : relationshipsByType.values()) {
        if (rels.size() > 1) {
          needs.addAll(rels);
        }
      }

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Applied. Replaced the nested per-clause loop with a Map<String, List<LogicalRelationship>> type-bucket pass: each rel is added to the bucket of every type it declares, then any bucket with size > 1 contributes its rels to the tracking set. Linear in (rels x types) and clearly intent-revealing. The hasUntyped short-circuit stays — an empty getTypes() would otherwise never enter any bucket, but semantically an untyped hop overlaps with everything.

@claude

claude Bot commented May 6, 2026

Copy link
Copy Markdown

Code Review: #4095 fix - Anonymous directed rel patterns isomorphism

Overall: Solid, well-scoped fix with good test coverage. A few edge cases worth discussing.


What this PR does

Fixes Cypher relationship isomorphism enforcement for anonymous (unnamed) relationship variables in ExpandAll. Previously, (s)<-[:KNOWS]-(f)-[:KNOWS]->(d) could return rows where both hops bound the same physical edge (e.g. (Alice, Bob, Alice)) because anonymous rels were never registered in relVarsPerClause and the per-row uniqueness set was always empty.

The fix follows the same pattern as the existing named-variable fix (#4096): assign synthetic " anon_e_N" names to anonymous hops that need tracking, store the edge under that name in the result row, and register it in relVarsPerClause so subsequent hops compare against it in collectUsedEdgeRids.


Correctness

computeNeedsEdgeTracking logic is sound. Grouping by clauseIndex, short-circuiting on untyped, and the outer: label for early exit are all correct. The conservative "all rels in clause when any is untyped" approach avoids false negatives.

One potential gap - ExpandInto path not handled:

In buildExpansionChain, the new tracking block is inside the else branch (ExpandAll-only). If an anonymous rel is promoted to ExpandInto (both endpoints already bound), the edge is not stored in the row for downstream hops to check. ExpandInto has isSameClauseEdgeReuse but only guards against its own reuse, not tracking the edge for subsequent hops. This is a pre-existing limitation (not introduced here), but a follow-up issue is warranted - a 3+ hop pattern like (a)-[:T]->(b)<-[:T]-(c)-[:T]->(d) could hit this if b and c are already bound.


Minor code observations

Synthetic vars in RETURN *: The " anon_e_N" tracking vars are stored as row properties and never cleaned up. If a query uses RETURN *, those synthetic properties (two leading spaces) could appear in the output. Worth confirming the projection step strips them or documenting the behaviour.

computeNeedsEdgeTracking adds named rels to needs when any is untyped. Named rels in needs are harmless (the rel.getVariable() == null guard prevents acting on them), but filtering to anonymous-only would make the intent clearer without changing behaviour.

O(N^2) type intersection in computeNeedsEdgeTracking: Fine at plan-build time for typical patterns. A brief comment noting this is planning-time cost only would help future readers.


Test coverage

Coverage is good for the primary cases (diverging/converging with row count and aggregate assertions).

Missing scenarios worth considering before merge:

  1. 3+ hop same-type chain: (a)-[:T]->(b)-[:T]->(c)-[:T]->(d) - all three hops anonymous, same type. Exercises syntheticEdgeVarCounter > 1 and verifies all three edges are distinct.

  2. Mixed named + anonymous in same clause: MATCH (a)-[r:T]->(b)-[:T]->(c) - confirms the two tracking paths (existing named-var + new synthetic) do not interfere.

  3. Cross-clause reuse still permitted: MATCH (a)-[:T]->(b) MATCH (c)-[:T]->(d) should still allow the same physical edge in both clauses. Valid Cypher cross-clause reuse must not be blocked.


Summary

The fix is correct for the primary case, uses the established synthetic-variable convention consistently, and the tests clearly document the bug and expected behaviour. The ExpandInto gap for anonymous rels is pre-existing and should get a tracked follow-up issue. Adding the 3-hop and mixed-variable test cases would meaningfully harden coverage before merge.

Replace nested per-clause overlap loop with a Map<String, List<Rel>>
type-bucket pass. Same semantics, linear in (rels x types) instead of
quadratic in rels.

Tests added:
- 3-hop anonymous same-type chain (multiple synthetic counters)
- mixed named + anonymous in same MATCH (both tracking paths coexist)
- cross-clause anonymous edge reuse remains permitted (not blocked)
@robfrank

robfrank commented May 6, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed in fb92b57:

Test additions (all 3 suggested scenarios):

  • threeHopAnonymousSameTypeChainHasDistinctEdges - 4-vertex linear chain with 3 anonymous KNOWS hops; verifies multiple synthetic counters yield distinct edges
  • mixedNamedAndAnonymousSameClauseBindsDistinctEdges - one named (r) and one anonymous KNOWS slot in the same clause; both tracking paths coexist correctly
  • crossClauseAnonymousEdgeReuseIsAllowed - two separate MATCH clauses; same physical edge legitimately fills both, count returns 4 (not blocked)

computeNeedsEdgeTracking complexity: Refactored per Gemini's suggestion to a Map<String, List<LogicalRelationship>> type-bucket pass. Now O(rels × types) instead of O(rels²).

Named rels in needs (cosmetic): With the bucket refactor this is moot — buckets now produce the actual overlapping pairs, and the optimizer's (rel.getVariable() == null || rel.getVariable().isEmpty()) guard at the call site already filters down to anonymous-only. Named rels in the set never act on it.

ExpandInto 3+ hop gap: Acknowledged as pre-existing and out of this PR's scope. The 3-hop test only hits ExpandAll because no endpoint is bound from a separate clause. Worth a follow-up issue, agreed.

RETURN * synthetic-var bleed: Confirmed pre-existing — the legacy MatchRelationshipStep path uses the same " relN" two-leading-spaces convention with the same propagation behavior. FinalProjectionStep doesn't strip them. Worth a separate cleanup (filter prop.startsWith(" ") in the returnAll block) but unrelated to this fix's correctness.

@claude

claude Bot commented May 6, 2026

Copy link
Copy Markdown

Code Review: #4095 fix - Anonymous directed rel patterns isomorphism

Overall: Well-implemented fix, correct approach, test coverage is stronger than the PR description suggests. A few follow-up items worth tracking.


What this PR does

Fixes Cypher relationship isomorphism enforcement for anonymous (unnamed) relationship variables in ExpandAll. Previously, a pattern like (s)<-[:KNOWS]-(f)-[:KNOWS]->(d) could return rows where both hops bound the same physical edge (e.g. (Alice, Bob, Alice)) because anonymous rels were never registered in relVarsPerClause, leaving sameClausePrecedingRelVars empty for every hop and making the collectUsedEdgeRids isomorphism check a no-op.

The fix follows the same approach as the named-variable fix (#4096): compute which hops need tracking at plan-build time (computeNeedsEdgeTracking), assign synthetic " anon_e_N" names to qualifying anonymous hops, store the edge under that name in the result row, and register the synthetic name in relVarsPerClause so subsequent hops include it in collectUsedEdgeRids.


Correctness

The core fix is correct. Specific points:

  • computeNeedsEdgeTracking logic is sound. Grouping by clauseIndex, short-circuiting when any hop is untyped (conservative but correct - untyped matches any edge type so all hops in the clause may collide), and falling back to per-type overlap detection are all appropriate.

  • Ordering in buildExpansionChain is correct. The synthetic var block runs before addTargetLabelFilter wraps currentOp, which is required since addTargetLabelFilter may wrap the ExpandAll in another operator. The comment // Must run before addTargetLabelFilter wraps currentOp. makes this clear.

  • Synthetic vars don't leak to query results. The " anon_e_N" prefix (two leading spaces) is not a valid Cypher identifier and cannot appear in any RETURN clause. FinalProjectionStep filters result rows to only explicitly returned variables, so synthetic tracking properties are automatically dropped before results reach the caller. The RETURN * concern raised in earlier reviews is not an issue - RETURN * expands to explicitly declared query variables, not to all row properties.


One gap: ExpandInto path not covered

In buildExpansionChain, the new tracking block is inside the else branch (ExpandAll-only):

} else {
    currentOp = createExpandAllOperator(rel, currentOp, boundVariables, sameClausePreceding);

    // new block - only runs when currentOp is ExpandAll
    if ((rel.getVariable() == null || rel.getVariable().isEmpty())
        && needsEdgeTracking.contains(rel)
        && currentOp instanceof ExpandAll expand) { ... }
}

If an anonymous hop is promoted to ExpandInto (both endpoints already bound at plan time), the edge is not stashed in the row, so subsequent hops in the same clause cannot detect the reuse. This is a pre-existing limitation not introduced by this PR, and the fix correctly handles the common unbounded-hop case. However, a 3+ hop pattern where one anonymous hop resolves to ExpandInto could still produce spurious rows. A follow-up issue to address ExpandInto tracking parity is recommended to keep the work visible.


Minor observations

computeNeedsEdgeTracking adds named rels to needs when untyped: When hasUntyped == true, needs.addAll(clauseRels) includes both named and anonymous rels. Named rels are harmless (the rel.getVariable() == null guard prevents acting on them in buildExpansionChain), but filtering to anonymous-only would make intent clearer:

// Current
needs.addAll(clauseRels);

// Clearer (same behaviour)
for (final LogicalRelationship r : clauseRels)
    if (r.getVariable() == null || r.getVariable().isEmpty())
        needs.add(r);

This is a very minor readability point - not a bug.

PR description says "4 tests" but the test class has 7. The description lists "diverging + converging row count + aggregate count" (4 tests), but Issue4095DirectedRelReuseIsomorphismTest actually contains:

  1. divergingAnonymousDirectedDoesNotReuseRelationship
  2. convergingAnonymousDirectedDoesNotReuseRelationship
  3. divergingAnonymousDirectedCountIsCorrect
  4. convergingAnonymousDirectedCountIsCorrect
  5. threeHopAnonymousSameTypeChainHasDistinctEdges - exercises syntheticEdgeVarCounter > 1
  6. mixedNamedAndAnonymousSameClauseBindsDistinctEdges - verifies named + anonymous tracking coexist
  7. crossClauseAnonymousEdgeReuseIsAllowed - confirms cross-clause reuse remains valid

Tests 5-7 cover the cases that are most likely to regress from future optimizer changes. The PR description underrepresents the coverage.


Test coverage

Coverage is comprehensive and well-structured. The cross-clause test (crossClauseAnonymousEdgeReuseIsAllowed) is particularly valuable - it locks in the expected count (4 rows) with a comment explaining the arithmetic, which makes future regressions immediately diagnosable.

The @BeforeEach/@AfterEach lifecycle management with database.drop() is correct and consistent with the project test pattern.


Summary

The fix is correct, complete for the unbounded-hop case, and well-tested. The ExpandInto gap is the only remaining correctness risk, and it is pre-existing. I'd suggest filing a follow-up issue for ExpandInto parity and then this is ready to merge.

@codecov

codecov Bot commented May 6, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.50000% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.48%. Comparing base (c1814a7) to head (fb92b57).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
...db/query/opencypher/optimizer/CypherOptimizer.java 80.55% 4 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4115      +/-   ##
==========================================
+ Coverage   64.46%   64.48%   +0.02%     
==========================================
  Files        1623     1623              
  Lines      123556   123596      +40     
  Branches    26303    26316      +13     
==========================================
+ Hits        79652    79704      +52     
+ Misses      32850    32826      -24     
- Partials    11054    11066      +12     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@robfrank
robfrank merged commit 7ce2cd0 into main May 6, 2026
28 of 31 checks passed
lvca added a commit that referenced this pull request May 6, 2026
Fixed issues:
- #4095 (consecutive directed relationship slots reuse the same edge): already fixed in current main by commit 7ce2cd0 #4095 fix(cypher): anonymous directed rel patterns must not reuse the same edge (#4115). Added 1 regression test as a guard.
- #4094 (CALL db.labels() YIELD label nullifies carried variables): already fixed in current main. Added 1 regression test as a guard.
- #4105 (node label-union pattern (n:A|B) matches no rows): fixed. The parser was extracting the labels into a list but losing the OR semantics, so the executor treated :A|B like :A:B. 2 regression tests pass.
- #4093 (backslash dropped from string literals): fixed. The string-literal decoder treated unknown escape sequences as "remove the backslash". 4 regression tests pass.
tae898 pushed a commit to humemai/arcadedb-embedded-python that referenced this pull request May 10, 2026
tae898 pushed a commit to humemai/arcadedb-embedded-python that referenced this pull request May 10, 2026
Fixed issues:
- ArcadeData#4095 (consecutive directed relationship slots reuse the same edge): already fixed in current main by commit 7ce2cd0 ArcadeData#4095 fix(cypher): anonymous directed rel patterns must not reuse the same edge (ArcadeData#4115). Added 1 regression test as a guard.
- ArcadeData#4094 (CALL db.labels() YIELD label nullifies carried variables): already fixed in current main. Added 1 regression test as a guard.
- ArcadeData#4105 (node label-union pattern (n:A|B) matches no rows): fixed. The parser was extracting the labels into a list but losing the OR semantics, so the executor treated :A|B like :A:B. 2 regression tests pass.
- ArcadeData#4093 (backslash dropped from string literals): fixed. The string-literal decoder treated unknown escape sequences as "remove the backslash". 4 regression tests pass.
robfrank added a commit that referenced this pull request May 12, 2026
robfrank pushed a commit that referenced this pull request May 12, 2026
Fixed issues:
- #4095 (consecutive directed relationship slots reuse the same edge): already fixed in current main by commit 7ce2cd0 #4095 fix(cypher): anonymous directed rel patterns must not reuse the same edge (#4115). Added 1 regression test as a guard.
- #4094 (CALL db.labels() YIELD label nullifies carried variables): already fixed in current main. Added 1 regression test as a guard.
- #4105 (node label-union pattern (n:A|B) matches no rows): fixed. The parser was extracting the labels into a list but losing the OR semantics, so the executor treated :A|B like :A:B. 2 regression tests pass.
- #4093 (backslash dropped from string literals): fixed. The string-literal decoder treated unknown escape sequences as "remove the backslash". 4 regression tests pass.

(cherry picked from commit 53e34e5)
tae898 pushed a commit to humemai/arcadedb-embedded-python that referenced this pull request Jun 28, 2026
… 2.67.0 to 2.68.0 [skip ci]

Bumps [com.google.api.grpc:proto-google-common-protos](https://github.com/googleapis/sdk-platform-java) from 2.67.0 to 2.68.0.
Release notes

*Sourced from [com.google.api.grpc:proto-google-common-protos's releases](https://github.com/googleapis/sdk-platform-java/releases).*

> v2.68.0
> -------
>
> [2.68.0](googleapis/sdk-platform-java@v2.67.0...v2.68.0) (2026-03-17)
> ------------------------------------------------------------------------------------------------
>
> ### Features
>
> * Add client request duration metric. ([ArcadeData#4132](https://redirect.github.com/googleapis/sdk-platform-java/issues/4132)) ([6a76397](googleapis/sdk-platform-java@6a76397))
> * Add more attributes to golden signals metrics. ([ArcadeData#4135](https://redirect.github.com/googleapis/sdk-platform-java/issues/4135)) ([59d0624](googleapis/sdk-platform-java@59d0624))
> * **gax-httpjson:** add HttpJsonErrorParser utility ([ArcadeData#4137](https://redirect.github.com/googleapis/sdk-platform-java/issues/4137)) ([a1b7565](googleapis/sdk-platform-java@a1b7565))
> * **generator:** add extra allowed modules that will not be removed from the monorepo if they are present ([ArcadeData#4124](https://redirect.github.com/googleapis/sdk-platform-java/issues/4124)) ([774fe6e](googleapis/sdk-platform-java@774fe6e))
> * **o11y:** introduce `gcp.client.repo` and `gcp.client.artifact` attributes ([ArcadeData#4120](https://redirect.github.com/googleapis/sdk-platform-java/issues/4120)) ([105f644](googleapis/sdk-platform-java@105f644))
> * **o11y:** Introduce `rpc.system.name` and `rpc.method` in gRPC ([ArcadeData#4121](https://redirect.github.com/googleapis/sdk-platform-java/issues/4121)) ([7ab6d2e](googleapis/sdk-platform-java@7ab6d2e))
> * **o11y:** introduce server.port attribute ([ArcadeData#4128](https://redirect.github.com/googleapis/sdk-platform-java/issues/4128)) ([56aa343](googleapis/sdk-platform-java@56aa343))
>
> ### Bug Fixes
>
> * add null checks for ApiTracerFactory in ClientContext ([ArcadeData#4122](https://redirect.github.com/googleapis/sdk-platform-java/issues/4122)) ([4b3dbe2](googleapis/sdk-platform-java@4b3dbe2))
> * Decrease log level for directpath warnings outside GCE ([ArcadeData#4139](https://redirect.github.com/googleapis/sdk-platform-java/issues/4139)) ([c9651e7](googleapis/sdk-platform-java@c9651e7))
> * **gax-grpc:** add pick\_first fallback to direct path service config ([ArcadeData#4143](https://redirect.github.com/googleapis/sdk-platform-java/issues/4143)) ([b150fe9](googleapis/sdk-platform-java@b150fe9))
> * Populate method level attributes in metrics recording ([ArcadeData#4149](https://redirect.github.com/googleapis/sdk-platform-java/issues/4149)) ([7b7e6c9](googleapis/sdk-platform-java@7b7e6c9))
> * suppress warnings in generated projects for non-idiomatic durations ([ArcadeData#4119](https://redirect.github.com/googleapis/sdk-platform-java/issues/4119)) ([4206e6e](googleapis/sdk-platform-java@4206e6e))
> * Use ServiceName + MethodName as the regex for Otel ([ArcadeData#2543](https://redirect.github.com/googleapis/sdk-platform-java/issues/2543)) ([b9ae73f](googleapis/sdk-platform-java@b9ae73f))
>
> ### Documentation
>
> * **hermetic\_build:** fix config field name in readme ([ArcadeData#4130](https://redirect.github.com/googleapis/sdk-platform-java/issues/4130)) ([a0c8f67](googleapis/sdk-platform-java@a0c8f67))


Changelog

*Sourced from [com.google.api.grpc:proto-google-common-protos's changelog](https://github.com/googleapis/sdk-platform-java/blob/main/CHANGELOG.md).*

> [2.68.0](googleapis/sdk-platform-java@v2.67.0...v2.68.0) (2026-03-17)
> ------------------------------------------------------------------------------------------------
>
> ### Features
>
> * Add client request duration metric. ([ArcadeData#4132](https://redirect.github.com/googleapis/sdk-platform-java/issues/4132)) ([6a76397](googleapis/sdk-platform-java@6a76397))
> * Add more attributes to golden signals metrics. ([ArcadeData#4135](https://redirect.github.com/googleapis/sdk-platform-java/issues/4135)) ([59d0624](googleapis/sdk-platform-java@59d0624))
> * **gax-httpjson:** add HttpJsonErrorParser utility ([ArcadeData#4137](https://redirect.github.com/googleapis/sdk-platform-java/issues/4137)) ([a1b7565](googleapis/sdk-platform-java@a1b7565))
> * **generator:** add extra allowed modules that will not be removed from the monorepo if they are present ([ArcadeData#4124](https://redirect.github.com/googleapis/sdk-platform-java/issues/4124)) ([774fe6e](googleapis/sdk-platform-java@774fe6e))
> * **o11y:** introduce `gcp.client.repo` and `gcp.client.artifact` attributes ([ArcadeData#4120](https://redirect.github.com/googleapis/sdk-platform-java/issues/4120)) ([105f644](googleapis/sdk-platform-java@105f644))
> * **o11y:** Introduce `rpc.system.name` and `rpc.method` in gRPC ([ArcadeData#4121](https://redirect.github.com/googleapis/sdk-platform-java/issues/4121)) ([7ab6d2e](googleapis/sdk-platform-java@7ab6d2e))
> * **o11y:** introduce server.port attribute ([ArcadeData#4128](https://redirect.github.com/googleapis/sdk-platform-java/issues/4128)) ([56aa343](googleapis/sdk-platform-java@56aa343))
>
> ### Bug Fixes
>
> * add null checks for ApiTracerFactory in ClientContext ([ArcadeData#4122](https://redirect.github.com/googleapis/sdk-platform-java/issues/4122)) ([4b3dbe2](googleapis/sdk-platform-java@4b3dbe2))
> * Decrease log level for directpath warnings outside GCE ([ArcadeData#4139](https://redirect.github.com/googleapis/sdk-platform-java/issues/4139)) ([c9651e7](googleapis/sdk-platform-java@c9651e7))
> * **gax-grpc:** add pick\_first fallback to direct path service config ([ArcadeData#4143](https://redirect.github.com/googleapis/sdk-platform-java/issues/4143)) ([b150fe9](googleapis/sdk-platform-java@b150fe9))
> * Populate method level attributes in metrics recording ([ArcadeData#4149](https://redirect.github.com/googleapis/sdk-platform-java/issues/4149)) ([7b7e6c9](googleapis/sdk-platform-java@7b7e6c9))
> * suppress warnings in generated projects for non-idiomatic durations ([ArcadeData#4119](https://redirect.github.com/googleapis/sdk-platform-java/issues/4119)) ([4206e6e](googleapis/sdk-platform-java@4206e6e))
> * Use ServiceName + MethodName as the regex for Otel ([ArcadeData#2543](https://redirect.github.com/googleapis/sdk-platform-java/issues/2543)) ([b9ae73f](googleapis/sdk-platform-java@b9ae73f))
>
> ### Documentation
>
> * **hermetic\_build:** fix config field name in readme ([ArcadeData#4130](https://redirect.github.com/googleapis/sdk-platform-java/issues/4130)) ([a0c8f67](googleapis/sdk-platform-java@a0c8f67))


Commits

* [`7eca195`](googleapis/sdk-platform-java@7eca195) chore(main): release 2.68.0 ([ArcadeData#4123](https://redirect.github.com/googleapis/sdk-platform-java/issues/4123))
* [`7b7e6c9`](googleapis/sdk-platform-java@7b7e6c9) fix: Populate method level attributes in metrics recording ([ArcadeData#4149](https://redirect.github.com/googleapis/sdk-platform-java/issues/4149))
* [`c9651e7`](googleapis/sdk-platform-java@c9651e7) fix: Decrease log level for directpath warnings outside GCE ([ArcadeData#4139](https://redirect.github.com/googleapis/sdk-platform-java/issues/4139))
* [`55df486`](googleapis/sdk-platform-java@55df486) build(deps): bump black from 24.8.0 to 26.3.1 in /hermetic\_build/common ([ArcadeData#4138](https://redirect.github.com/googleapis/sdk-platform-java/issues/4138))
* [`15c8abf`](googleapis/sdk-platform-java@15c8abf) chore(deps): update upper bound dependencies file ([ArcadeData#4146](https://redirect.github.com/googleapis/sdk-platform-java/issues/4146))
* [`8be3f9d`](googleapis/sdk-platform-java@8be3f9d) chore: update googleapis commit at Thu Feb 19 03:02:27 UTC 2026 ([ArcadeData#4115](https://redirect.github.com/googleapis/sdk-platform-java/issues/4115))
* [`b150fe9`](googleapis/sdk-platform-java@b150fe9) fix(gax-grpc): add pick\_first fallback to direct path service config ([ArcadeData#4143](https://redirect.github.com/googleapis/sdk-platform-java/issues/4143))
* [`4a24d92`](googleapis/sdk-platform-java@4a24d92) build: disable SonarCloud for fork pull requests ([ArcadeData#4142](https://redirect.github.com/googleapis/sdk-platform-java/issues/4142))
* [`59d0624`](googleapis/sdk-platform-java@59d0624) feat: Add more attributes to golden signals metrics. ([ArcadeData#4135](https://redirect.github.com/googleapis/sdk-platform-java/issues/4135))
* [`0275698`](googleapis/sdk-platform-java@0275698) chore: extract channel builder for internal use ([ArcadeData#4136](https://redirect.github.com/googleapis/sdk-platform-java/issues/4136))
* Additional commits viewable in [compare view](googleapis/sdk-platform-java@v2.67.0...v2.68.0)
  
[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility\_score?dependency-name=com.google.api.grpc:proto-google-common-protos&package-manager=maven&previous-version=2.67.0&new-version=2.68.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
  
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot show  ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
tae898 pushed a commit to humemai/arcadedb-embedded-python that referenced this pull request Jun 28, 2026
tae898 pushed a commit to humemai/arcadedb-embedded-python that referenced this pull request Jun 28, 2026
Fixed issues:
- ArcadeData#4095 (consecutive directed relationship slots reuse the same edge): already fixed in current main by commit 8fbecb7 ArcadeData#4095 fix(cypher): anonymous directed rel patterns must not reuse the same edge (ArcadeData#4115). Added 1 regression test as a guard.
- ArcadeData#4094 (CALL db.labels() YIELD label nullifies carried variables): already fixed in current main. Added 1 regression test as a guard.
- ArcadeData#4105 (node label-union pattern (n:A|B) matches no rows): fixed. The parser was extracting the labels into a list but losing the OR semantics, so the executor treated :A|B like :A:B. 2 regression tests pass.
- ArcadeData#4093 (backslash dropped from string literals): fixed. The string-literal decoder treated unknown escape sequences as "remove the backslash". 4 regression tests pass.
@lvca
lvca deleted the fix/4095-directed-rel-reuse-isomorphism branch July 3, 2026 20:18
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.

Consecutive directed relationship patterns may reuse the same relationship

1 participant