shulei5831sl opened a new issue, #2473:
URL: https://github.com/apache/age/issues/2473

   ### Apache AGE version
   
   Observed with the official Docker image:
   
   ```text
   Image: apache/age:latest
   Apache AGE: 1.7.0
   PostgreSQL: 18.1
   ```
   
   ### Environment
   
   - Deployment: Docker
   - Query interface: PostgreSQL SQL client
   - Query language: Cypher through `cypher()`
   - Differential comparison targets:
     - Neo4j `2026.05`
     - Neo4j `5.26`
     - Memgraph `3.11.0`
     - FalkorDB `4.18.11`
   
   ### Description
   
   A standalone `OPTIONAL MATCH` returns zero rows when its pattern does not
   match.
   
   `OPTIONAL MATCH` should preserve its input row and bind variables introduced
   by the unmatched optional pattern to `null`. At the beginning of a query,
   there is an implicit initial input row. Therefore, a standalone unmatched
   `OPTIONAL MATCH` should return one null-filled row.
   
   Apache AGE instead drops the initial row and returns an empty result.
   
   When the same `OPTIONAL MATCH` follows a successful `MATCH`, AGE correctly
   preserves the preceding row and binds the unmatched variable to `null`.
   The issue therefore appears specific to the initial input row of a standalone
   `OPTIONAL MATCH`.
   
   ### Steps to reproduce
   
   Use an existing empty graph named `test_graph`.
   
   #### Test 1: standalone `OPTIONAL MATCH`
   
   ```sql
   SELECT *
   FROM cypher('test_graph', $$
     OPTIONAL MATCH (n:DefinitelyMissing)
     RETURN n AS result
   $$) AS (result agtype);
   ```
   
   ### Expected behavior
   
   The query should return one row:
   
   ```text
   result
   ------
   null
   ```
   
   Equivalent logical result:
   
   ```text
   [{result: null}]
   ```
   
   ### Actual behavior
   
   Apache AGE returns zero rows:
   
   ```text
   []
   ```
   
   The initial input row is lost when the optional pattern does not match.
   
   ### Control: `OPTIONAL MATCH` after a successful `MATCH`
   
   Create one seed node:
   
   ```sql
   SELECT *
   FROM cypher('test_graph', $$
     CREATE (:V1 {val: 1})
   $$) AS (result agtype);
   ```
   
   Run an unmatched `OPTIONAL MATCH` after matching the seed node:
   
   ```sql
   SELECT *
   FROM cypher('test_graph', $$
     MATCH (v:V1 {val: 1})
     OPTIONAL MATCH (n:DefinitelyMissing)
     RETURN v.val AS seed, n AS result
   $$) AS (seed agtype, result agtype);
   ```
   
   Apache AGE correctly returns:
   
   ```text
   seed | result
   -----+-------
   1    | null
   ```
   
   This shows that AGE implements null-preserving behavior correctly when an
   input row is supplied by a preceding `MATCH`. The failure occurs when
   `OPTIONAL MATCH` is the first clause and must operate on the query's initial
   input row.
   
   ### Cross-engine comparison
   
   | Engine | Standalone unmatched `OPTIONAL MATCH` |
   |---|---|
   | Neo4j `2026.05` | One row: `{result: null}` |
   | Neo4j `5.26` | One row: `{result: null}` |
   | Memgraph `3.11.0` | One row: `{result: null}` |
   | FalkorDB `4.18.11` | One row: `{result: null}` |
   | Apache AGE `1.7.0` | Zero rows |
   
   ### Why this looks like a bug
   
   The following two query shapes should apply the same null-preserving
   `OPTIONAL MATCH` semantics:
   
   ```cypher
   OPTIONAL MATCH (n:DefinitelyMissing)
   RETURN n
   ```
   
   and:
   
   ```cypher
   MATCH (v:V1)
   OPTIONAL MATCH (n:DefinitelyMissing)
   RETURN v, n
   ```
   
   In the second query, AGE correctly preserves each incoming row and binds
   `n` to `null`.
   
   In the first query, the query begins with one implicit input row. AGE should
   preserve that row in the same way, but instead removes it entirely.
   
   This suggests that the standalone `OPTIONAL MATCH` execution path starts
   with an empty input relation rather than the required single initial row.
   
   ### Related but distinct issue
   
   Apache AGE issue #2378 reports a different `OPTIONAL MATCH` null-preservation
   problem involving a preceding `MATCH` and correlated subquery predicates.
   
   This report is distinct because:
   
   - there is no preceding clause;
   - there is no correlated subquery;
   - no graph data is required for the failing query;
   - the failure is specifically the loss of the initial input row for a
     standalone `OPTIONAL MATCH`.


-- 
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]

Reply via email to