Skip to content

Commit 4e14eae

Browse files
committed
cypher_with: add ORDER BY to non-deterministic RETURN queries
Several cypher_with regression queries RETURN multiple rows without an ORDER BY, so their row order depends on heap/scan order and can vary between runs, build types, and platforms. Add ORDER BY ASC to those queries so the expected output is stable. Ordering keys use id() (a single int64 that bypasses the locale-sensitive string comparison path and is reproducible from the test's deterministic setup order), or the projected path/scalar where that is what the query returns. Where the underlying vertex/edge was dropped by a WITH projection, its id is threaded through as an alias rather than reordering the projection. Full audit of cypher_with: all 23 multi-row result blocks were checked. After this change, every multi-row, non-EXPLAIN RETURN is deterministically ordered. The two remaining unordered multi-row blocks are left as-is: - "RETURN lbl" returns two identical "Person" rows, so order cannot drift; - the 13 EXPLAIN (VERBOSE, COSTS OFF) plan blocks emit a fixed serial plan (no parallel/gather nodes), so their row order is already deterministic. This is a test-only change (regress/sql/cypher_with.sql and regress/expected/cypher_with.out); no extension C code or SQL is modified. Row counts are unchanged (pure reordering). All 37 regression tests pass (installcheck) on PostgreSQL 18.3. Co-authored-by: GitHub Copilot <noreply@github.com> modified: regress/expected/cypher_with.out modified: regress/sql/cypher_with.sql
1 parent 23cbe57 commit 4e14eae

2 files changed

Lines changed: 30 additions & 8 deletions

File tree

regress/expected/cypher_with.out

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,14 @@ SELECT * FROM cypher('cypher_with', $$
5252
MATCH (n)-[e]->(m)
5353
WITH n,e,m
5454
RETURN n,e,m
55+
ORDER BY id(n) ASC, id(e) ASC, id(m) ASC
5556
$$) AS (N1 agtype, edge agtype, N2 agtype);
5657
n1 | edge | n2
5758
--------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------
5859
{"id": 281474976710657, "label": "", "properties": {"age": 36, "name": "Andres"}}::vertex | {"id": 844424930131969, "label": "BLOCKS", "end_id": 281474976710658, "start_id": 281474976710657, "properties": {}}::edge | {"id": 281474976710658, "label": "", "properties": {"age": 25, "name": "Caesar"}}::vertex
59-
{"id": 281474976710659, "label": "", "properties": {"age": 55, "name": "Bossman"}}::vertex | {"id": 844424930131970, "label": "BLOCKS", "end_id": 281474976710660, "start_id": 281474976710659, "properties": {}}::edge | {"id": 281474976710660, "label": "", "properties": {"age": 35, "name": "David"}}::vertex
6060
{"id": 281474976710657, "label": "", "properties": {"age": 36, "name": "Andres"}}::vertex | {"id": 1125899906842625, "label": "KNOWS", "end_id": 281474976710659, "start_id": 281474976710657, "properties": {}}::edge | {"id": 281474976710659, "label": "", "properties": {"age": 55, "name": "Bossman"}}::vertex
6161
{"id": 281474976710658, "label": "", "properties": {"age": 25, "name": "Caesar"}}::vertex | {"id": 1125899906842626, "label": "KNOWS", "end_id": 281474976710661, "start_id": 281474976710658, "properties": {}}::edge | {"id": 281474976710661, "label": "", "properties": {"age": 37, "name": "George"}}::vertex
62+
{"id": 281474976710659, "label": "", "properties": {"age": 55, "name": "Bossman"}}::vertex | {"id": 844424930131970, "label": "BLOCKS", "end_id": 281474976710660, "start_id": 281474976710659, "properties": {}}::edge | {"id": 281474976710660, "label": "", "properties": {"age": 35, "name": "David"}}::vertex
6263
{"id": 281474976710659, "label": "", "properties": {"age": 55, "name": "Bossman"}}::vertex | {"id": 1125899906842627, "label": "KNOWS", "end_id": 281474976710661, "start_id": 281474976710659, "properties": {}}::edge | {"id": 281474976710661, "label": "", "properties": {"age": 37, "name": "George"}}::vertex
6364
{"id": 281474976710660, "label": "", "properties": {"age": 35, "name": "David"}}::vertex | {"id": 1125899906842628, "label": "KNOWS", "end_id": 281474976710657, "start_id": 281474976710660, "properties": {}}::edge | {"id": 281474976710657, "label": "", "properties": {"age": 36, "name": "Andres"}}::vertex
6465
(6 rows)
@@ -68,6 +69,7 @@ SELECT * FROM cypher('cypher_with', $$
6869
MATCH (n)-[e]->(m)
6970
WITH n.name AS n1, e as edge, m.name as n2
7071
RETURN n1,label(edge),n2
72+
ORDER BY id(edge) ASC
7173
$$) AS (start_node agtype,edge agtype, end_node agtype);
7274
start_node | edge | end_node
7375
------------+----------+-----------
@@ -83,13 +85,14 @@ SELECT * FROM cypher('cypher_with',$$
8385
MATCH (person)-[r]->(otherPerson)
8486
WITH *, type(r) AS connectionType
8587
RETURN person.name, connectionType, otherPerson.name
88+
ORDER BY id(person) ASC, id(otherPerson) ASC
8689
$$) AS (start_node agtype, connection agtype, end_node agtype);
8790
start_node | connection | end_node
8891
------------+------------+-----------
8992
"Andres" | "BLOCKS" | "Caesar"
90-
"Bossman" | "BLOCKS" | "David"
9193
"Andres" | "KNOWS" | "Bossman"
9294
"Caesar" | "KNOWS" | "George"
95+
"Bossman" | "BLOCKS" | "David"
9396
"Bossman" | "KNOWS" | "George"
9497
"David" | "KNOWS" | "Andres"
9598
(6 rows)
@@ -109,6 +112,7 @@ MATCH (george {name: 'George'})<-[]-(otherPerson)
109112
WITH otherPerson, toUpper(otherPerson.name) AS upperCaseName
110113
WHERE upperCaseName STARTS WITH 'C'
111114
RETURN otherPerson.name
115+
ORDER BY id(otherPerson) ASC
112116
$$) as (name agtype);
113117
name
114118
----------
@@ -120,6 +124,7 @@ SELECT * FROM cypher('cypher_with', $$
120124
WITH otherPerson, count(*) AS foaf
121125
WHERE foaf > 1
122126
RETURN otherPerson.name
127+
ORDER BY id(otherPerson) ASC
123128
$$) as (name agtype);
124129
name
125130
----------
@@ -131,15 +136,16 @@ SELECT * FROM cypher('cypher_with', $$
131136
WITH p, length(p) AS path_length
132137
WHERE path_length > 1
133138
RETURN p
139+
ORDER BY p ASC
134140
$$) AS (pattern agtype);
135141
pattern
136142
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
137-
[{"id": 281474976710657, "label": "_ag_label_vertex", "properties": {"age": 36, "name": "Andres"}}::vertex, {"id": 1125899906842625, "label": "KNOWS", "end_id": 281474976710659, "start_id": 281474976710657, "properties": {}}::edge, {"id": 281474976710659, "label": "_ag_label_vertex", "properties": {"age": 55, "name": "Bossman"}}::vertex, {"id": 1125899906842627, "label": "KNOWS", "end_id": 281474976710661, "start_id": 281474976710659, "properties": {}}::edge, {"id": 281474976710661, "label": "_ag_label_vertex", "properties": {"age": 37, "name": "George"}}::vertex]::path
138-
[{"id": 281474976710657, "label": "_ag_label_vertex", "properties": {"age": 36, "name": "Andres"}}::vertex, {"id": 1125899906842625, "label": "KNOWS", "end_id": 281474976710659, "start_id": 281474976710657, "properties": {}}::edge, {"id": 281474976710659, "label": "_ag_label_vertex", "properties": {"age": 55, "name": "Bossman"}}::vertex, {"id": 844424930131970, "label": "BLOCKS", "end_id": 281474976710660, "start_id": 281474976710659, "properties": {}}::edge, {"id": 281474976710660, "label": "_ag_label_vertex", "properties": {"age": 35, "name": "David"}}::vertex]::path
139143
[{"id": 281474976710657, "label": "_ag_label_vertex", "properties": {"age": 36, "name": "Andres"}}::vertex, {"id": 844424930131969, "label": "BLOCKS", "end_id": 281474976710658, "start_id": 281474976710657, "properties": {}}::edge, {"id": 281474976710658, "label": "_ag_label_vertex", "properties": {"age": 25, "name": "Caesar"}}::vertex, {"id": 1125899906842626, "label": "KNOWS", "end_id": 281474976710661, "start_id": 281474976710658, "properties": {}}::edge, {"id": 281474976710661, "label": "_ag_label_vertex", "properties": {"age": 37, "name": "George"}}::vertex]::path
144+
[{"id": 281474976710657, "label": "_ag_label_vertex", "properties": {"age": 36, "name": "Andres"}}::vertex, {"id": 1125899906842625, "label": "KNOWS", "end_id": 281474976710659, "start_id": 281474976710657, "properties": {}}::edge, {"id": 281474976710659, "label": "_ag_label_vertex", "properties": {"age": 55, "name": "Bossman"}}::vertex, {"id": 844424930131970, "label": "BLOCKS", "end_id": 281474976710660, "start_id": 281474976710659, "properties": {}}::edge, {"id": 281474976710660, "label": "_ag_label_vertex", "properties": {"age": 35, "name": "David"}}::vertex]::path
145+
[{"id": 281474976710657, "label": "_ag_label_vertex", "properties": {"age": 36, "name": "Andres"}}::vertex, {"id": 1125899906842625, "label": "KNOWS", "end_id": 281474976710659, "start_id": 281474976710657, "properties": {}}::edge, {"id": 281474976710659, "label": "_ag_label_vertex", "properties": {"age": 55, "name": "Bossman"}}::vertex, {"id": 1125899906842627, "label": "KNOWS", "end_id": 281474976710661, "start_id": 281474976710659, "properties": {}}::edge, {"id": 281474976710661, "label": "_ag_label_vertex", "properties": {"age": 37, "name": "George"}}::vertex]::path
140146
[{"id": 281474976710659, "label": "_ag_label_vertex", "properties": {"age": 55, "name": "Bossman"}}::vertex, {"id": 844424930131970, "label": "BLOCKS", "end_id": 281474976710660, "start_id": 281474976710659, "properties": {}}::edge, {"id": 281474976710660, "label": "_ag_label_vertex", "properties": {"age": 35, "name": "David"}}::vertex, {"id": 1125899906842628, "label": "KNOWS", "end_id": 281474976710657, "start_id": 281474976710660, "properties": {}}::edge, {"id": 281474976710657, "label": "_ag_label_vertex", "properties": {"age": 36, "name": "Andres"}}::vertex]::path
141-
[{"id": 281474976710660, "label": "_ag_label_vertex", "properties": {"age": 35, "name": "David"}}::vertex, {"id": 1125899906842628, "label": "KNOWS", "end_id": 281474976710657, "start_id": 281474976710660, "properties": {}}::edge, {"id": 281474976710657, "label": "_ag_label_vertex", "properties": {"age": 36, "name": "Andres"}}::vertex, {"id": 1125899906842625, "label": "KNOWS", "end_id": 281474976710659, "start_id": 281474976710657, "properties": {}}::edge, {"id": 281474976710659, "label": "_ag_label_vertex", "properties": {"age": 55, "name": "Bossman"}}::vertex]::path
142147
[{"id": 281474976710660, "label": "_ag_label_vertex", "properties": {"age": 35, "name": "David"}}::vertex, {"id": 1125899906842628, "label": "KNOWS", "end_id": 281474976710657, "start_id": 281474976710660, "properties": {}}::edge, {"id": 281474976710657, "label": "_ag_label_vertex", "properties": {"age": 36, "name": "Andres"}}::vertex, {"id": 844424930131969, "label": "BLOCKS", "end_id": 281474976710658, "start_id": 281474976710657, "properties": {}}::edge, {"id": 281474976710658, "label": "_ag_label_vertex", "properties": {"age": 25, "name": "Caesar"}}::vertex]::path
148+
[{"id": 281474976710660, "label": "_ag_label_vertex", "properties": {"age": 35, "name": "David"}}::vertex, {"id": 1125899906842628, "label": "KNOWS", "end_id": 281474976710657, "start_id": 281474976710660, "properties": {}}::edge, {"id": 281474976710657, "label": "_ag_label_vertex", "properties": {"age": 36, "name": "Andres"}}::vertex, {"id": 1125899906842625, "label": "KNOWS", "end_id": 281474976710659, "start_id": 281474976710657, "properties": {}}::edge, {"id": 281474976710659, "label": "_ag_label_vertex", "properties": {"age": 55, "name": "Bossman"}}::vertex]::path
143149
(6 rows)
144150

145151
-- MATCH/WHERE with WITH/WHERE
@@ -149,6 +155,7 @@ SELECT * FROM cypher('cypher_with', $$
149155
WITH *
150156
WHERE m.name = 'Andres'
151157
RETURN m.name,label(e),b.name
158+
ORDER BY id(m) ASC, id(e) ASC, id(b) ASC
152159
$$) AS (N1 agtype, edge agtype, N2 agtype);
153160
n1 | edge | n2
154161
----------+---------+-----------
@@ -201,9 +208,10 @@ SELECT * FROM cypher('cypher_with', $$
201208
MATCH (n)-[e]->(m)
202209
WITH n, e, m
203210
WHERE label(e) = 'KNOWS'
204-
WITH n.name as n1, label(e) as edge, m.name as n2
211+
WITH id(e) AS eid, n.name as n1, label(e) as edge, m.name as n2
205212
WHERE n1 = 'Andres'
206213
RETURN n1,edge,n2
214+
ORDER BY eid ASC
207215
$$) AS (N1 agtype, edge agtype, N2 agtype);
208216
n1 | edge | n2
209217
----------+---------+-----------
@@ -217,6 +225,7 @@ SELECT * FROM cypher('cypher_with', $$
217225
WITH x
218226
LIMIT 5
219227
RETURN x
228+
ORDER BY x ASC
220229
$$) as (name agtype);
221230
name
222231
------
@@ -233,11 +242,12 @@ SELECT * FROM cypher('cypher_with', $$
233242
WITH m as start_node, b as end_node
234243
WHERE end_node.name = 'George'
235244
RETURN id(start_node),start_node.name,id(end_node),end_node.name
245+
ORDER BY id(start_node) ASC, id(end_node) ASC
236246
$$) AS (id1 agtype, name1 agtype, id2 agtype, name2 agtype);
237247
id1 | name1 | id2 | name2
238248
-----------------+-----------+-----------------+----------
239-
281474976710659 | "Bossman" | 281474976710661 | "George"
240249
281474976710658 | "Caesar" | 281474976710661 | "George"
250+
281474976710659 | "Bossman" | 281474976710661 | "George"
241251
(2 rows)
242252

243253
-- Expression item must be aliased.
@@ -471,6 +481,7 @@ SELECT * FROM cypher('with_accessor_opt', $$
471481
MATCH (n:Person)
472482
WITH n as m
473483
RETURN m
484+
ORDER BY id(m) ASC
474485
$$) AS (n vertex);
475486
n
476487
---------------------------------------------------------------------

regress/sql/cypher_with.sql

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ SELECT * FROM cypher('cypher_with', $$
4747
MATCH (n)-[e]->(m)
4848
WITH n,e,m
4949
RETURN n,e,m
50+
ORDER BY id(n) ASC, id(e) ASC, id(m) ASC
5051
$$) AS (N1 agtype, edge agtype, N2 agtype);
5152

5253
-- WITH/AS
@@ -55,12 +56,14 @@ SELECT * FROM cypher('cypher_with', $$
5556
MATCH (n)-[e]->(m)
5657
WITH n.name AS n1, e as edge, m.name as n2
5758
RETURN n1,label(edge),n2
59+
ORDER BY id(edge) ASC
5860
$$) AS (start_node agtype,edge agtype, end_node agtype);
5961

6062
SELECT * FROM cypher('cypher_with',$$
6163
MATCH (person)-[r]->(otherPerson)
6264
WITH *, type(r) AS connectionType
6365
RETURN person.name, connectionType, otherPerson.name
66+
ORDER BY id(person) ASC, id(otherPerson) ASC
6467
$$) AS (start_node agtype, connection agtype, end_node agtype);
6568

6669
SELECT * FROM cypher('cypher_with', $$
@@ -75,20 +78,23 @@ MATCH (george {name: 'George'})<-[]-(otherPerson)
7578
WITH otherPerson, toUpper(otherPerson.name) AS upperCaseName
7679
WHERE upperCaseName STARTS WITH 'C'
7780
RETURN otherPerson.name
81+
ORDER BY id(otherPerson) ASC
7882
$$) as (name agtype);
7983

8084
SELECT * FROM cypher('cypher_with', $$
8185
MATCH (david {name: 'David'})-[]-(otherPerson)-[]->()
8286
WITH otherPerson, count(*) AS foaf
8387
WHERE foaf > 1
8488
RETURN otherPerson.name
89+
ORDER BY id(otherPerson) ASC
8590
$$) as (name agtype);
8691

8792
SELECT * FROM cypher('cypher_with', $$
8893
MATCH p = (m)-[*1..2]->(b)
8994
WITH p, length(p) AS path_length
9095
WHERE path_length > 1
9196
RETURN p
97+
ORDER BY p ASC
9298
$$) AS (pattern agtype);
9399

94100
-- MATCH/WHERE with WITH/WHERE
@@ -99,6 +105,7 @@ SELECT * FROM cypher('cypher_with', $$
99105
WITH *
100106
WHERE m.name = 'Andres'
101107
RETURN m.name,label(e),b.name
108+
ORDER BY id(m) ASC, id(e) ASC, id(b) ASC
102109
$$) AS (N1 agtype, edge agtype, N2 agtype);
103110

104111
-- WITH/ORDER BY
@@ -133,9 +140,10 @@ SELECT * FROM cypher('cypher_with', $$
133140
MATCH (n)-[e]->(m)
134141
WITH n, e, m
135142
WHERE label(e) = 'KNOWS'
136-
WITH n.name as n1, label(e) as edge, m.name as n2
143+
WITH id(e) AS eid, n.name as n1, label(e) as edge, m.name as n2
137144
WHERE n1 = 'Andres'
138145
RETURN n1,edge,n2
146+
ORDER BY eid ASC
139147
$$) AS (N1 agtype, edge agtype, N2 agtype);
140148

141149
SELECT * FROM cypher('cypher_with', $$
@@ -145,6 +153,7 @@ SELECT * FROM cypher('cypher_with', $$
145153
WITH x
146154
LIMIT 5
147155
RETURN x
156+
ORDER BY x ASC
148157
$$) as (name agtype);
149158

150159
SELECT * FROM cypher('cypher_with', $$
@@ -154,6 +163,7 @@ SELECT * FROM cypher('cypher_with', $$
154163
WITH m as start_node, b as end_node
155164
WHERE end_node.name = 'George'
156165
RETURN id(start_node),start_node.name,id(end_node),end_node.name
166+
ORDER BY id(start_node) ASC, id(end_node) ASC
157167
$$) AS (id1 agtype, name1 agtype, id2 agtype, name2 agtype);
158168

159169
-- Expression item must be aliased.
@@ -284,6 +294,7 @@ SELECT * FROM cypher('with_accessor_opt', $$
284294
MATCH (n:Person)
285295
WITH n as m
286296
RETURN m
297+
ORDER BY id(m) ASC
287298
$$) AS (n vertex);
288299

289300
SELECT * FROM cypher('with_accessor_opt', $$

0 commit comments

Comments
 (0)