Skip to content

Commit 908d7b2

Browse files
authored
Return an empty list from tail() for empty and singleton lists (#2399)
age_tail() in src/backend/utils/adt/agtype.c had an explicit early return that mapped both the empty-list and the singleton-list cases to SQL NULL: count = AGT_ROOT_COUNT(agt_arg); /* if we have an empty list or only one element in the list, return null */ if (count <= 1) { PG_RETURN_NULL(); } The Cypher specification (and Neo4j / Memgraph) both define tail(list) as "the list without its first element". For a zero-or-one-element input that is an empty list [], not null. Differential tests against Neo4j surface this divergence immediately. Remove the early return. The loop below already iterates from i=1 so it naturally emits [] for count <= 1 and emits the correct tail for the general case. No behaviour change for count >= 2. Tests and expected output are updated to match the new, spec-correct result.
1 parent 6c40838 commit 908d7b2

3 files changed

Lines changed: 9 additions & 9 deletions

File tree

regress/expected/expr.out

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8039,17 +8039,17 @@ SELECT * FROM cypher('list', $$ RETURN tail(["a","b","c","d","e"]) $$) AS (tail
80398039
["b", "c", "d", "e"]
80408040
(1 row)
80418041

8042-
-- should return null
8042+
-- should return an empty list
80438043
SELECT * FROM cypher('list', $$ RETURN tail([1]) $$) AS (tail agtype);
80448044
tail
80458045
------
8046-
8046+
[]
80478047
(1 row)
80488048

80498049
SELECT * FROM cypher('list', $$ RETURN tail([]) $$) AS (tail agtype);
80508050
tail
80518051
------
8052-
8052+
[]
80538053
(1 row)
80548054

80558055
-- should throw errors

regress/sql/expr.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3269,7 +3269,7 @@ SELECT * from cypher('list', $$RETURN range(0, -10.0, -3.0)$$) as (range agtype)
32693269
-- should return the last elements of the list
32703270
SELECT * FROM cypher('list', $$ RETURN tail([1,2,3,4,5]) $$) AS (tail agtype);
32713271
SELECT * FROM cypher('list', $$ RETURN tail(["a","b","c","d","e"]) $$) AS (tail agtype);
3272-
-- should return null
3272+
-- should return an empty list
32733273
SELECT * FROM cypher('list', $$ RETURN tail([1]) $$) AS (tail agtype);
32743274
SELECT * FROM cypher('list', $$ RETURN tail([]) $$) AS (tail agtype);
32753275
-- should throw errors

src/backend/utils/adt/agtype.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6056,11 +6056,11 @@ Datum age_tail(PG_FUNCTION_ARGS)
60566056

60576057
count = AGT_ROOT_COUNT(agt_arg);
60586058

6059-
/* if we have an empty list or only one element in the list, return null */
6060-
if (count <= 1)
6061-
{
6062-
PG_RETURN_NULL();
6063-
}
6059+
/*
6060+
* For an empty or singleton list, tail() returns an empty list. The loop
6061+
* below already produces that result (i starts at 1 so nothing is pushed
6062+
* when count <= 1), so we do not special-case the count here.
6063+
*/
60646064

60656065
/* clear the result structure */
60666066
MemSet(&agis_result, 0, sizeof(agtype_in_state));

0 commit comments

Comments
 (0)