Skip to content

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

@Silence6666668

Description

@Silence6666668

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:

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?

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:

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:

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

Neo4j returns:

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:

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:

true

while Neo4j and Memgraph both return:

null

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

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions