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

   ### Apache AGE version
   
   Observed on Docker image:
   
   ```text
   docker pull apache/age:latest
   Pulled: 2026-07-09
   
   Apache AGE: PG18
   
   Endpoint:
   postgres://127.0.0.1:5432
   ```
   
   ### How are you accessing AGE
   
   psql and Python `psycopg2` driver
   
   ### Environment
   
   * Host OS: Linux `5.4.0-216-generic`
   * Deployment: Docker `apache/age:latest`
   * Query interface: psql and psycopg2
   * Query language: Cypher via `ag_catalog.cypher`
   * Configuration: default AGE on PostgreSQL 18
   * Differential comparison targets:
   
     * Neo4j `2026.05.0`
   
   ### Description
   
   AGE's `tail()` function returns `null` when the result should be an empty 
list.
   
   The issue occurs for:
   
   ```cypher
   tail([1])
   tail([])
   ```
   
   Both should return `[]`.
   
   `tail()` is a list-returning function: it returns all elements of the input 
list except the first one. Therefore, dropping the only element from `[1]` 
should produce an empty list, and applying `tail()` to an already empty list 
should also produce an empty list.
   
   Neo4j returns `[]` for both cases.
   
   ### Setup
   
   ```pgsql
   LOAD 'age';
   SET search_path = ag_catalog, '$user', public;
   SELECT * FROM ag_catalog.create_graph('test_graph');
   ```
   
   ### Failing queries
   
   ```pgsql
   SELECT * FROM cypher('test_graph', $$
     RETURN tail([1]) AS r
   $$) AS (r agtype);
   ```
   
   AGE returns:
   
   ```text
   r = null
   ```
   
   Expected:
   
   ```text
   r = []
   ```
   
   ```pgsql
   SELECT * FROM cypher('test_graph', $$
     RETURN tail([]) AS r
   $$) AS (r agtype);
   ```
   
   AGE returns:
   
   ```text
   r = null
   ```
   
   Expected:
   
   ```text
   r = []
   ```
   
   ### Control queries
   
   #### Normal `tail()` works
   
   ```pgsql
   SELECT * FROM cypher('test_graph', $$
     RETURN tail([1,2,3]) AS r
   $$) AS (r agtype);
   ```
   
   AGE returns:
   
   ```text
   r = [2, 3]
   ```
   
   This is correct.
   
   #### `tail(null)` should return `null`
   
   ```pgsql
   SELECT * FROM cypher('test_graph', $$
     RETURN tail(null) AS r
   $$) AS (r agtype);
   ```
   
   Expected:
   
   ```text
   r = null
   ```
   
   This distinguishes null input from empty-list output.
   
   #### Other list functions show the expected boundary behavior
   
   ```pgsql
   SELECT * FROM cypher('test_graph', $$
     RETURN reverse([]) AS r
   $$) AS (r agtype);
   ```
   
   AGE returns:
   
   ```text
   r = []
   ```
   
   This is correct: a list-returning function applied to an empty list returns 
an empty list.
   
   ```pgsql
   SELECT * FROM cypher('test_graph', $$
     RETURN head([]) AS r
   $$) AS (r agtype);
   ```
   
   AGE returns:
   
   ```text
   r = null
   ```
   
   This is correct: `head()` returns an element, and there is no element in an 
empty list.
   
   ```pgsql
   SELECT * FROM cypher('test_graph', $$
     RETURN last([]) AS r
   $$) AS (r agtype);
   ```
   
   AGE returns:
   
   ```text
   r = null
   ```
   
   This is correct: `last()` returns an element, and there is no element in an 
empty list.
   
   ### Cross-engine comparison
   
   | Expression      | Apache AGE | Neo4j `2026.05.0` |
   | --------------- | ---------: | ----------------: |
   | `tail([1])`     |     `null` |              `[]` |
   | `tail([])`      |     `null` |              `[]` |
   | `tail([1,2,3])` |    `[2,3]` |           `[2,3]` |
   | `tail(null)`    |     `null` |            `null` |
   | `reverse([])`   |       `[]` |              `[]` |
   | `head([])`      |     `null` |            `null` |
   | `last([])`      |     `null` |            `null` |
   
   ### Impact
   
   This can silently change query logic when `tail()` is used in list pipelines.
   
   For example:
   
   ```pgsql
   SELECT * FROM cypher('test_graph', $$
     RETURN size(tail([1])) AS r
   $$) AS (r agtype);
   ```
   
   Expected:
   
   ```text
   r = 0
   ```
   
   AGE may return `null` because `tail([1])` returns `null`.
   
   This also affects predicates and CASE expressions that distinguish an empty 
list from `null`.
   
   ### Summary
   
   `tail()` should return an empty list when all elements are removed from the 
input list. AGE currently returns `null` for `tail([1])` and `tail([])`, even 
though it correctly returns lists for non-empty outputs such as `tail([1,2,3])`.
   


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