apache / apache/age

Order comparisons between values of different types may return a boolean instead of `null`.

Open
#2,387 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
C
Stars
4.8k
Forks
523
Avg merge
1d 2h
Merged PRs (30d)
9

Description

**Describe the bug**
Order comparisons between values of different types may return a boolean instead of `null`.

In the minimized repro below, Apache AGE evaluates `30 > 'Rex'` as `true` and `30 < 'Rex'` as `false`.

On both Neo4j and Memgraph, the same expressions evaluate to `null`.

This suggests Apache AGE is applying a cross-type ordering for `>` / `<` comparisons where other Cypher implementations treat the comparison result as null.

**How are you accessing AGE (Command line, driver, etc.)?**
- PostgreSQL `cypher(...)` wrapper through the local Python differential-testing harness
- Reproducible directly in `psql` inside the Docker container

**What data setup do we need to do?**
No graph data is required beyond creating an empty graph:

```pgsql
SELECT create_graph('fuzz_graph');
```

**What is the necessary configuration info needed?**
- Plain Apache AGE Docker image was enough
- Docker image in local repro: `apache/age`
- AGE extension version: `1.7.0`
- PostgreSQL version: `18.1`
- Graph name used in repro: `fuzz_graph`
- No extra extensions or special configuration were required

**What is the command that caused the error?**
```pgsql
SELECT * FROM cypher('fuzz_graph', $$
RETURN 30 > 'Rex' AS gt,
30 < 'Rex' AS lt,
30 = 'Rex' AS eq
$$) AS (gt agtype, lt agtype, eq agtype);
```

Returned result on AGE:
```text
gt | lt | eq
-----+-------+------
true | false | false
```

**Expected behavior**
The equality result `30 = 'Rex'` being `false` is fine, but the ordering comparisons should evaluate to `null` rather than `true` / `false`.

Expected result:

```text
gt | lt | eq
-----+------+------
null | null | false
```

Neo4j returns:

```text
gt | lt | eq
-----+------+------
null | null | false
```

Memgraph returns the same result.

**Environment (please complete the following information):**
- Version: Apache AGE `1.7.0`
- PostgreSQL: `18.1`
- Host OS: Windows
- Architecture: x86_64
- Deployment: Docker

**Additional context**
The same difference also reproduces when the values come from graph properties instead of literals:

```pgsql
SELECT * FROM cypher('fuzz_graph', $$
CREATE (:Person {name:'Alice', age:30}),
(:Dog {name:'Rex'})
$$) AS (v agtype);

SELECT * FROM cypher('fuzz_graph', $$
MATCH (person:Person), (dog:Dog)
WHERE person.name = 'Alice' AND dog.name = 'Rex'
RETURN person.age > dog.name AS v
$$) AS (v agtype);
```

Apache AGE returns:

```text
true
```

while Neo4j and Memgraph both return:

```text
null
```

This issue was first found during automated Neo4j-vs-AGE differential testing in a larger query:

```cypher
MATCH (person:Person)
WHERE COUNT { (person)-[:HAS_DOG]->(dog:Dog) WHERE person.age > dog.name } > 0
OPTIONAL MATCH (person)-[:HAS_DOG]->(dog:Dog)
RETURN DISTINCT person.name AS name, collect(dog.name) AS dogNames
ORDER BY name
LIMIT 2
```

After minimization, the same semantic difference still reproduces with the direct literal comparison above.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.