Skip to content

Commit a29e281

Browse files
Fix nondeterministic age_global_graph regression test (#2365)
The age_global_graph test had two issues that could cause intermittent failures: 1. Nondeterministic warning output: The graph_stats() call on a graph with deliberately deleted vertices produces WARNING messages for dangling edges. These warnings are emitted by iterating edge label tables (knows, stalks), and the iteration order is not guaranteed. Since PostgreSQL WARNING messages cannot be caught or counted from SQL (only ERROR and above are catchable via PL/pgSQL exception handling), we suppress them with SET client_min_messages = error. The suppressed warnings are documented verbatim in comments. The graph_stats() result row still validates correct dangling-edge handling. 2. Nondeterministic row ordering: Multiple MATCH...RETURN queries returned multi-row results without ORDER BY, relying on scan order. Added ORDER BY id(u), id(v), id(e), id(n), or id(a) as appropriate to all MATCH...RETURN queries for future-proofing, even those currently returning a single row. Files changed: regress/sql/age_global_graph.sql regress/expected/age_global_graph.out Co-authored-by: GitHub Copilot <noreply@github.com>
1 parent 90c33eb commit a29e281

2 files changed

Lines changed: 64 additions & 38 deletions

File tree

regress/expected/age_global_graph.out

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -44,27 +44,27 @@ SELECT * FROM cypher('ag_graph_3', $$ CREATE (v:vertex3) RETURN v $$) AS (v agt
4444
(1 row)
4545

4646
-- load contexts using the vertex_stats command
47-
SELECT * FROM cypher('ag_graph_3', $$ MATCH (u) RETURN vertex_stats(u) $$) AS (result agtype);
47+
SELECT * FROM cypher('ag_graph_3', $$ MATCH (u) RETURN vertex_stats(u) ORDER BY id(u) $$) AS (result agtype);
4848
result
4949
-----------------------------------------------------------------------------------------------
5050
{"id": 844424930131969, "label": "vertex3", "in_degree": 0, "out_degree": 0, "self_loops": 0}
5151
(1 row)
5252

53-
SELECT * FROM cypher('ag_graph_2', $$ MATCH (u) RETURN vertex_stats(u) $$) AS (result agtype);
53+
SELECT * FROM cypher('ag_graph_2', $$ MATCH (u) RETURN vertex_stats(u) ORDER BY id(u) $$) AS (result agtype);
5454
result
5555
-----------------------------------------------------------------------------------------------
5656
{"id": 844424930131969, "label": "vertex2", "in_degree": 0, "out_degree": 0, "self_loops": 0}
5757
(1 row)
5858

59-
SELECT * FROM cypher('ag_graph_1', $$ MATCH (u) RETURN vertex_stats(u) $$) AS (result agtype);
59+
SELECT * FROM cypher('ag_graph_1', $$ MATCH (u) RETURN vertex_stats(u) ORDER BY id(u) $$) AS (result agtype);
6060
result
6161
-----------------------------------------------------------------------------------------------
6262
{"id": 844424930131969, "label": "vertex1", "in_degree": 0, "out_degree": 0, "self_loops": 0}
6363
(1 row)
6464

6565
--- loading undefined contexts
6666
--- should throw exception - graph "ag_graph_4" does not exist
67-
SELECT * FROM cypher('ag_graph_4', $$ MATCH (u) RETURN vertex_stats(u) $$) AS (result agtype);
67+
SELECT * FROM cypher('ag_graph_4', $$ MATCH (u) RETURN vertex_stats(u) ORDER BY id(u) $$) AS (result agtype);
6868
ERROR: graph "ag_graph_4" does not exist
6969
LINE 1: SELECT * FROM cypher('ag_graph_4', $$ MATCH (u) RETURN verte...
7070
^
@@ -130,19 +130,19 @@ LINE 1: SELECT * FROM cypher('ag_graph_4', $$ RETURN delete_global_g...
130130
-- delete_GRAPH_global_contexts
131131
--
132132
-- load contexts again
133-
SELECT * FROM cypher('ag_graph_3', $$ MATCH (u) RETURN vertex_stats(u) $$) AS (result agtype);
133+
SELECT * FROM cypher('ag_graph_3', $$ MATCH (u) RETURN vertex_stats(u) ORDER BY id(u) $$) AS (result agtype);
134134
result
135135
-----------------------------------------------------------------------------------------------
136136
{"id": 844424930131969, "label": "vertex3", "in_degree": 0, "out_degree": 0, "self_loops": 0}
137137
(1 row)
138138

139-
SELECT * FROM cypher('ag_graph_2', $$ MATCH (u) RETURN vertex_stats(u) $$) AS (result agtype);
139+
SELECT * FROM cypher('ag_graph_2', $$ MATCH (u) RETURN vertex_stats(u) ORDER BY id(u) $$) AS (result agtype);
140140
result
141141
-----------------------------------------------------------------------------------------------
142142
{"id": 844424930131969, "label": "vertex2", "in_degree": 0, "out_degree": 0, "self_loops": 0}
143143
(1 row)
144144

145-
SELECT * FROM cypher('ag_graph_1', $$ MATCH (u) RETURN vertex_stats(u) $$) AS (result agtype);
145+
SELECT * FROM cypher('ag_graph_1', $$ MATCH (u) RETURN vertex_stats(u) ORDER BY id(u) $$) AS (result agtype);
146146
result
147147
-----------------------------------------------------------------------------------------------
148148
{"id": 844424930131969, "label": "vertex1", "in_degree": 0, "out_degree": 0, "self_loops": 0}
@@ -193,14 +193,14 @@ SELECT * FROM cypher('ag_graph_2', $$ CREATE (:Person) $$) as (v agtype);
193193
(0 rows)
194194

195195
---adding edges between nodes
196-
SELECT * FROM cypher('ag_graph_2', $$ MATCH (a:Person), (b:Person) WHERE a.name = 'A' AND b.name = 'B' CREATE (a)-[e:RELTYPE]->(b) RETURN e $$) as (e agtype);
196+
SELECT * FROM cypher('ag_graph_2', $$ MATCH (a:Person), (b:Person) WHERE a.name = 'A' AND b.name = 'B' CREATE (a)-[e:RELTYPE]->(b) RETURN e ORDER BY id(e) $$) as (e agtype);
197197
e
198198
---
199199
(0 rows)
200200

201201
--checking if vertex stats have been updated along with the new label
202202
--should return 3 vertices
203-
SELECT * FROM cypher('ag_graph_1', $$ MATCH (n) RETURN vertex_stats(n) $$) AS (result agtype);
203+
SELECT * FROM cypher('ag_graph_1', $$ MATCH (n) RETURN vertex_stats(n) ORDER BY id(n) $$) AS (result agtype);
204204
result
205205
-----------------------------------------------------------------------------------------------
206206
{"id": 281474976710657, "label": "", "in_degree": 0, "out_degree": 0, "self_loops": 0}
@@ -209,7 +209,7 @@ SELECT * FROM cypher('ag_graph_1', $$ MATCH (n) RETURN vertex_stats(n) $$) AS (r
209209
(3 rows)
210210

211211
--should return 1 vertice and 1 label
212-
SELECT * FROM cypher('ag_graph_2', $$ MATCH (a) RETURN vertex_stats(a) $$) AS (result agtype);
212+
SELECT * FROM cypher('ag_graph_2', $$ MATCH (a) RETURN vertex_stats(a) ORDER BY id(a) $$) AS (result agtype);
213213
result
214214
-----------------------------------------------------------------------------------------------
215215
{"id": 844424930131969, "label": "vertex2", "in_degree": 0, "out_degree": 0, "self_loops": 0}
@@ -271,7 +271,7 @@ SELECT * FROM cypher('ag_graph_1', $$ MATCH (u)-[]->(v) SET u.id = id(u)
271271
SET v.id = id(v)
272272
SET u.name = 'u'
273273
SET v.name = 'v'
274-
RETURN u,v $$) AS (u agtype, v agtype);
274+
RETURN u,v ORDER BY id(u), id(v) $$) AS (u agtype, v agtype);
275275
u | v
276276
--------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------
277277
{"id": 281474976710659, "label": "", "properties": {"id": 281474976710659, "name": "u"}}::vertex | {"id": 281474976710660, "label": "", "properties": {"id": 281474976710660, "name": "v"}}::vertex
@@ -285,17 +285,17 @@ SELECT * FROM cypher('ag_graph_1', $$ MATCH (u)-[]->(v) MERGE (v)-[:stalks]->(u)
285285
--------
286286
(0 rows)
287287

288-
SELECT * FROM cypher('ag_graph_1', $$ MATCH (u)-[e]->(v) RETURN u, e, v $$) AS (u agtype, e agtype, v agtype);
288+
SELECT * FROM cypher('ag_graph_1', $$ MATCH (u)-[e]->(v) RETURN u, e, v ORDER BY id(e) $$) AS (u agtype, e agtype, v agtype);
289289
u | e | v
290290
--------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------
291-
{"id": 281474976710660, "label": "", "properties": {"id": 281474976710660, "name": "v"}}::vertex | {"id": 1407374883553281, "label": "stalks", "end_id": 281474976710659, "start_id": 281474976710660, "properties": {}}::edge | {"id": 281474976710659, "label": "", "properties": {"id": 281474976710659, "name": "u"}}::vertex
292291
{"id": 281474976710659, "label": "", "properties": {"id": 281474976710659, "name": "u"}}::vertex | {"id": 1125899906842625, "label": "knows", "end_id": 281474976710660, "start_id": 281474976710659, "properties": {}}::edge | {"id": 281474976710660, "label": "", "properties": {"id": 281474976710660, "name": "v"}}::vertex
293-
{"id": 281474976710662, "label": "", "properties": {"id": 281474976710662, "name": "v"}}::vertex | {"id": 1407374883553282, "label": "stalks", "end_id": 281474976710661, "start_id": 281474976710662, "properties": {}}::edge | {"id": 281474976710661, "label": "", "properties": {"id": 281474976710661, "name": "u"}}::vertex
294292
{"id": 281474976710661, "label": "", "properties": {"id": 281474976710661, "name": "u"}}::vertex | {"id": 1125899906842626, "label": "knows", "end_id": 281474976710662, "start_id": 281474976710661, "properties": {}}::edge | {"id": 281474976710662, "label": "", "properties": {"id": 281474976710662, "name": "v"}}::vertex
295-
{"id": 281474976710664, "label": "", "properties": {"id": 281474976710664, "name": "v"}}::vertex | {"id": 1407374883553283, "label": "stalks", "end_id": 281474976710663, "start_id": 281474976710664, "properties": {}}::edge | {"id": 281474976710663, "label": "", "properties": {"id": 281474976710663, "name": "u"}}::vertex
296293
{"id": 281474976710663, "label": "", "properties": {"id": 281474976710663, "name": "u"}}::vertex | {"id": 1125899906842627, "label": "knows", "end_id": 281474976710664, "start_id": 281474976710663, "properties": {}}::edge | {"id": 281474976710664, "label": "", "properties": {"id": 281474976710664, "name": "v"}}::vertex
297-
{"id": 281474976710666, "label": "", "properties": {"id": 281474976710666, "name": "v"}}::vertex | {"id": 1407374883553284, "label": "stalks", "end_id": 281474976710665, "start_id": 281474976710666, "properties": {}}::edge | {"id": 281474976710665, "label": "", "properties": {"id": 281474976710665, "name": "u"}}::vertex
298294
{"id": 281474976710665, "label": "", "properties": {"id": 281474976710665, "name": "u"}}::vertex | {"id": 1125899906842628, "label": "knows", "end_id": 281474976710666, "start_id": 281474976710665, "properties": {}}::edge | {"id": 281474976710666, "label": "", "properties": {"id": 281474976710666, "name": "v"}}::vertex
295+
{"id": 281474976710660, "label": "", "properties": {"id": 281474976710660, "name": "v"}}::vertex | {"id": 1407374883553281, "label": "stalks", "end_id": 281474976710659, "start_id": 281474976710660, "properties": {}}::edge | {"id": 281474976710659, "label": "", "properties": {"id": 281474976710659, "name": "u"}}::vertex
296+
{"id": 281474976710662, "label": "", "properties": {"id": 281474976710662, "name": "v"}}::vertex | {"id": 1407374883553282, "label": "stalks", "end_id": 281474976710661, "start_id": 281474976710662, "properties": {}}::edge | {"id": 281474976710661, "label": "", "properties": {"id": 281474976710661, "name": "u"}}::vertex
297+
{"id": 281474976710664, "label": "", "properties": {"id": 281474976710664, "name": "v"}}::vertex | {"id": 1407374883553283, "label": "stalks", "end_id": 281474976710663, "start_id": 281474976710664, "properties": {}}::edge | {"id": 281474976710663, "label": "", "properties": {"id": 281474976710663, "name": "u"}}::vertex
298+
{"id": 281474976710666, "label": "", "properties": {"id": 281474976710666, "name": "v"}}::vertex | {"id": 1407374883553284, "label": "stalks", "end_id": 281474976710665, "start_id": 281474976710666, "properties": {}}::edge | {"id": 281474976710665, "label": "", "properties": {"id": 281474976710665, "name": "u"}}::vertex
299299
(8 rows)
300300

301301
-- what is there now?
@@ -351,21 +351,30 @@ SELECT * FROM ag_graph_1._ag_label_edge;
351351
1407374883553284 | 281474976710666 | 281474976710665 | {}
352352
(8 rows)
353353

354-
-- there should be warning messages
354+
-- The graph_stats query below will produce warnings for the dangling edges
355+
-- created by the DELETE commands above. The warnings appear in nondeterministic
356+
-- order because they come from iterating edge label tables (knows, stalks),
357+
-- so we suppress them with client_min_messages. Without suppression, the
358+
-- output would include these warnings (in some order):
359+
--
360+
-- WARNING: edge: [id: 1125899906842626, start: 281474976710661, end: 281474976710662, label: knows] start and end vertices not found
361+
-- WARNING: ignored malformed or dangling edge
362+
-- WARNING: edge: [id: 1125899906842627, start: 281474976710663, end: 281474976710664, label: knows] end vertex not found
363+
-- WARNING: ignored malformed or dangling edge
364+
-- WARNING: edge: [id: 1407374883553282, start: 281474976710662, end: 281474976710661, label: stalks] start and end vertices not found
365+
-- WARNING: ignored malformed or dangling edge
366+
-- WARNING: edge: [id: 1407374883553283, start: 281474976710664, end: 281474976710663, label: stalks] start vertex not found
367+
-- WARNING: ignored malformed or dangling edge
368+
--
369+
-- The result row validates that graph_stats handled the dangling edges correctly.
370+
SET client_min_messages = error;
355371
SELECT * FROM cypher('ag_graph_1', $$ RETURN graph_stats('ag_graph_1') $$) AS (result agtype);
356-
WARNING: edge: [id: 1125899906842626, start: 281474976710661, end: 281474976710662, label: knows] start and end vertices not found
357-
WARNING: ignored malformed or dangling edge
358-
WARNING: edge: [id: 1125899906842627, start: 281474976710663, end: 281474976710664, label: knows] end vertex not found
359-
WARNING: ignored malformed or dangling edge
360-
WARNING: edge: [id: 1407374883553282, start: 281474976710662, end: 281474976710661, label: stalks] start and end vertices not found
361-
WARNING: ignored malformed or dangling edge
362-
WARNING: edge: [id: 1407374883553283, start: 281474976710664, end: 281474976710663, label: stalks] start vertex not found
363-
WARNING: ignored malformed or dangling edge
364372
result
365373
--------------------------------------------------------------------------
366374
{"graph": "ag_graph_1", "num_loaded_edges": 8, "num_loaded_vertices": 8}
367375
(1 row)
368376

377+
RESET client_min_messages;
369378
--drop graphs
370379
SELECT * FROM drop_graph('ag_graph_1', true);
371380
NOTICE: drop cascades to 5 other objects

regress/sql/age_global_graph.sql

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ SELECT * FROM create_graph('ag_graph_3');
1616
SELECT * FROM cypher('ag_graph_3', $$ CREATE (v:vertex3) RETURN v $$) AS (v agtype);
1717

1818
-- load contexts using the vertex_stats command
19-
SELECT * FROM cypher('ag_graph_3', $$ MATCH (u) RETURN vertex_stats(u) $$) AS (result agtype);
20-
SELECT * FROM cypher('ag_graph_2', $$ MATCH (u) RETURN vertex_stats(u) $$) AS (result agtype);
21-
SELECT * FROM cypher('ag_graph_1', $$ MATCH (u) RETURN vertex_stats(u) $$) AS (result agtype);
19+
SELECT * FROM cypher('ag_graph_3', $$ MATCH (u) RETURN vertex_stats(u) ORDER BY id(u) $$) AS (result agtype);
20+
SELECT * FROM cypher('ag_graph_2', $$ MATCH (u) RETURN vertex_stats(u) ORDER BY id(u) $$) AS (result agtype);
21+
SELECT * FROM cypher('ag_graph_1', $$ MATCH (u) RETURN vertex_stats(u) ORDER BY id(u) $$) AS (result agtype);
2222

2323
--- loading undefined contexts
2424
--- should throw exception - graph "ag_graph_4" does not exist
25-
SELECT * FROM cypher('ag_graph_4', $$ MATCH (u) RETURN vertex_stats(u) $$) AS (result agtype);
25+
SELECT * FROM cypher('ag_graph_4', $$ MATCH (u) RETURN vertex_stats(u) ORDER BY id(u) $$) AS (result agtype);
2626

2727
--- delete with invalid parameter
2828
---should return false
@@ -55,9 +55,9 @@ SELECT * FROM cypher('ag_graph_4', $$ RETURN delete_global_graphs('ag_graph_4')
5555
--
5656

5757
-- load contexts again
58-
SELECT * FROM cypher('ag_graph_3', $$ MATCH (u) RETURN vertex_stats(u) $$) AS (result agtype);
59-
SELECT * FROM cypher('ag_graph_2', $$ MATCH (u) RETURN vertex_stats(u) $$) AS (result agtype);
60-
SELECT * FROM cypher('ag_graph_1', $$ MATCH (u) RETURN vertex_stats(u) $$) AS (result agtype);
58+
SELECT * FROM cypher('ag_graph_3', $$ MATCH (u) RETURN vertex_stats(u) ORDER BY id(u) $$) AS (result agtype);
59+
SELECT * FROM cypher('ag_graph_2', $$ MATCH (u) RETURN vertex_stats(u) ORDER BY id(u) $$) AS (result agtype);
60+
SELECT * FROM cypher('ag_graph_1', $$ MATCH (u) RETURN vertex_stats(u) ORDER BY id(u) $$) AS (result agtype);
6161

6262
-- delete all graph contexts
6363
-- should return true
@@ -81,14 +81,14 @@ SELECT * FROM cypher('ag_graph_1', $$ CREATE (n), (m) $$) as (v agtype);
8181
SELECT * FROM cypher('ag_graph_2', $$ CREATE (:Person) $$) as (v agtype);
8282

8383
---adding edges between nodes
84-
SELECT * FROM cypher('ag_graph_2', $$ MATCH (a:Person), (b:Person) WHERE a.name = 'A' AND b.name = 'B' CREATE (a)-[e:RELTYPE]->(b) RETURN e $$) as (e agtype);
84+
SELECT * FROM cypher('ag_graph_2', $$ MATCH (a:Person), (b:Person) WHERE a.name = 'A' AND b.name = 'B' CREATE (a)-[e:RELTYPE]->(b) RETURN e ORDER BY id(e) $$) as (e agtype);
8585

8686
--checking if vertex stats have been updated along with the new label
8787
--should return 3 vertices
88-
SELECT * FROM cypher('ag_graph_1', $$ MATCH (n) RETURN vertex_stats(n) $$) AS (result agtype);
88+
SELECT * FROM cypher('ag_graph_1', $$ MATCH (n) RETURN vertex_stats(n) ORDER BY id(n) $$) AS (result agtype);
8989

9090
--should return 1 vertice and 1 label
91-
SELECT * FROM cypher('ag_graph_2', $$ MATCH (a) RETURN vertex_stats(a) $$) AS (result agtype);
91+
SELECT * FROM cypher('ag_graph_2', $$ MATCH (a) RETURN vertex_stats(a) ORDER BY id(a) $$) AS (result agtype);
9292

9393
--
9494
-- graph_stats command
@@ -109,9 +109,9 @@ SELECT * FROM cypher('ag_graph_1', $$ MATCH (u)-[]->(v) SET u.id = id(u)
109109
SET v.id = id(v)
110110
SET u.name = 'u'
111111
SET v.name = 'v'
112-
RETURN u,v $$) AS (u agtype, v agtype);
112+
RETURN u,v ORDER BY id(u), id(v) $$) AS (u agtype, v agtype);
113113
SELECT * FROM cypher('ag_graph_1', $$ MATCH (u)-[]->(v) MERGE (v)-[:stalks]->(u) $$) AS (result agtype);
114-
SELECT * FROM cypher('ag_graph_1', $$ MATCH (u)-[e]->(v) RETURN u, e, v $$) AS (u agtype, e agtype, v agtype);
114+
SELECT * FROM cypher('ag_graph_1', $$ MATCH (u)-[e]->(v) RETURN u, e, v ORDER BY id(e) $$) AS (u agtype, e agtype, v agtype);
115115
-- what is there now?
116116
SELECT * FROM cypher('ag_graph_1', $$ RETURN graph_stats('ag_graph_1') $$) AS (result agtype);
117117
-- remove some vertices
@@ -121,8 +121,25 @@ DELETE FROM ag_graph_1._ag_label_vertex WHERE id::text = '281474976710662';
121121
DELETE FROM ag_graph_1._ag_label_vertex WHERE id::text = '281474976710664';
122122
SELECT * FROM ag_graph_1._ag_label_vertex;
123123
SELECT * FROM ag_graph_1._ag_label_edge;
124-
-- there should be warning messages
124+
-- The graph_stats query below will produce warnings for the dangling edges
125+
-- created by the DELETE commands above. The warnings appear in nondeterministic
126+
-- order because they come from iterating edge label tables (knows, stalks),
127+
-- so we suppress them with client_min_messages. Without suppression, the
128+
-- output would include these warnings (in some order):
129+
--
130+
-- WARNING: edge: [id: 1125899906842626, start: 281474976710661, end: 281474976710662, label: knows] start and end vertices not found
131+
-- WARNING: ignored malformed or dangling edge
132+
-- WARNING: edge: [id: 1125899906842627, start: 281474976710663, end: 281474976710664, label: knows] end vertex not found
133+
-- WARNING: ignored malformed or dangling edge
134+
-- WARNING: edge: [id: 1407374883553282, start: 281474976710662, end: 281474976710661, label: stalks] start and end vertices not found
135+
-- WARNING: ignored malformed or dangling edge
136+
-- WARNING: edge: [id: 1407374883553283, start: 281474976710664, end: 281474976710663, label: stalks] start vertex not found
137+
-- WARNING: ignored malformed or dangling edge
138+
--
139+
-- The result row validates that graph_stats handled the dangling edges correctly.
140+
SET client_min_messages = error;
125141
SELECT * FROM cypher('ag_graph_1', $$ RETURN graph_stats('ag_graph_1') $$) AS (result agtype);
142+
RESET client_min_messages;
126143

127144
--drop graphs
128145

0 commit comments

Comments
 (0)