You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@age.apache.org by "shulei5831sl (via GitHub)" <gi...@apache.org> on 2026/07/09 13:43:54 UTC
[I] `tail([1])` and `tail([])` return `null` instead of `[]` [age]
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: dev-unsubscribe@age.apache.org.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org