Skip to content

Commit fee0fa2

Browse files
authored
Implement unified vertex table architecture (#2278)
NOTE: This PR was built with AI tools and a human. Implemented a unified vertex table architecture to be built off of. Key changes: Replaced per-label vertex tables with a single _ag_label_vertex table containing columns: id (graphid), properties (agtype), labels (oid). * Fixed vertex operations (CREATE, MATCH, SET, DELETE, VLE) to use unified _ag_label_vertex table instead of label-specific tables. * Fixed vertex label display: Added _label_name_from_table_oid() function to extract label names from the labels column OID rather than parsing graphid values (which is table-per-label specific) * Fixed graphid generation: Updated transform_cypher_node() in cypher_clause.c to use label_relation instead of default_vertex_relation when building id expressions, ensuring labeled vertices receive label-specific sequence values in their id. * Disconnected all label id extraction from the vertex ids. This makes all operations independent of the vertex id, except for as an id. * Fixed regression tests. Differences with regression tests are due to - * Non-ordered output being reordered due to the new unified table. * Different query plans with explain due to the new unified table. * Displaying specific vertex label tables instead of the unified table. modified: Makefile modified: regress/expected/age_global_graph.out modified: regress/expected/age_load.out modified: regress/expected/cypher_create.out modified: regress/expected/cypher_delete.out modified: regress/expected/cypher_match.out modified: regress/expected/cypher_merge.out modified: regress/expected/cypher_remove.out modified: regress/expected/cypher_set.out modified: regress/expected/cypher_subquery.out modified: regress/expected/cypher_vle.out modified: regress/expected/expr.out modified: regress/expected/graph_generation.out modified: regress/expected/index.out modified: regress/expected/list_comprehension.out new file: regress/expected/unified_vertex_table.out modified: regress/sql/age_global_graph.sql modified: regress/sql/age_load.sql modified: regress/sql/cypher_create.sql modified: regress/sql/cypher_set.sql modified: regress/sql/graph_generation.sql modified: regress/sql/index.sql new file: regress/sql/unified_vertex_table.sql modified: sql/age_main.sql modified: src/backend/catalog/ag_label.c modified: src/backend/commands/label_commands.c modified: src/backend/executor/cypher_create.c modified: src/backend/executor/cypher_delete.c modified: src/backend/executor/cypher_merge.c modified: src/backend/executor/cypher_set.c modified: src/backend/executor/cypher_utils.c modified: src/backend/nodes/cypher_copyfuncs.c modified: src/backend/nodes/cypher_outfuncs.c modified: src/backend/nodes/cypher_readfuncs.c modified: src/backend/parser/cypher_clause.c modified: src/backend/utils/adt/age_global_graph.c modified: src/backend/utils/adt/age_vle.c modified: src/backend/utils/adt/agtype.c modified: src/backend/utils/load/ag_load_labels.c modified: src/backend/utils/load/age_load.c modified: src/include/catalog/ag_label.h modified: src/include/commands/label_commands.h modified: src/include/executor/cypher_utils.h modified: src/include/nodes/cypher_nodes.h modified: regress/expected/pgvector.out modified: regress/sql/pgvector.sql
1 parent a44ca12 commit fee0fa2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1549
-701
lines changed

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ REGRESS = scan \
112112
name_validation \
113113
jsonb_operators \
114114
list_comprehension \
115-
map_projection
115+
map_projection \
116+
unified_vertex_table
116117

117118
ifneq ($(EXTRA_TESTS),)
118119
REGRESS += $(EXTRA_TESTS)

regress/expected/age_global_graph.out

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -203,9 +203,9 @@ SELECT * FROM cypher('ag_graph_2', $$ MATCH (a:Person), (b:Person) WHERE a.name
203203
SELECT * FROM cypher('ag_graph_1', $$ MATCH (n) RETURN vertex_stats(n) $$) AS (result agtype);
204204
result
205205
-----------------------------------------------------------------------------------------------
206+
{"id": 844424930131969, "label": "vertex1", "in_degree": 0, "out_degree": 0, "self_loops": 0}
206207
{"id": 281474976710657, "label": "", "in_degree": 0, "out_degree": 0, "self_loops": 0}
207208
{"id": 281474976710658, "label": "", "in_degree": 0, "out_degree": 0, "self_loops": 0}
208-
{"id": 844424930131969, "label": "vertex1", "in_degree": 0, "out_degree": 0, "self_loops": 0}
209209
(3 rows)
210210

211211
--should return 1 vertice and 1 label
@@ -288,14 +288,14 @@ SELECT * FROM cypher('ag_graph_1', $$ MATCH (u)-[]->(v) MERGE (v)-[:stalks]->(u)
288288
SELECT * FROM cypher('ag_graph_1', $$ MATCH (u)-[e]->(v) RETURN u, e, v $$) 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": 281474976710662, "label": "", "properties": {"id": 281474976710662, "name": "v"}}::vertex | {"id": 1407374883553281, "label": "stalks", "end_id": 281474976710661, "start_id": 281474976710662, "properties": {}}::edge | {"id": 281474976710661, "label": "", "properties": {"id": 281474976710661, "name": "u"}}::vertex
296+
{"id": 281474976710660, "label": "", "properties": {"id": 281474976710660, "name": "v"}}::vertex | {"id": 1407374883553282, "label": "stalks", "end_id": 281474976710659, "start_id": 281474976710660, "properties": {}}::edge | {"id": 281474976710659, "label": "", "properties": {"id": 281474976710659, "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?
@@ -306,7 +306,7 @@ SELECT * FROM cypher('ag_graph_1', $$ RETURN graph_stats('ag_graph_1') $$) AS (r
306306
(1 row)
307307

308308
-- remove some vertices
309-
SELECT * FROM ag_graph_1._ag_label_vertex;
309+
SELECT id, properties FROM ag_graph_1._ag_label_vertex order by id;
310310
id | properties
311311
-----------------+--------------------------------------
312312
281474976710657 | {}
@@ -325,7 +325,7 @@ SELECT * FROM ag_graph_1._ag_label_vertex;
325325
DELETE FROM ag_graph_1._ag_label_vertex WHERE id::text = '281474976710661';
326326
DELETE FROM ag_graph_1._ag_label_vertex WHERE id::text = '281474976710662';
327327
DELETE FROM ag_graph_1._ag_label_vertex WHERE id::text = '281474976710664';
328-
SELECT * FROM ag_graph_1._ag_label_vertex;
328+
SELECT id, properties FROM ag_graph_1._ag_label_vertex order by id;
329329
id | properties
330330
-----------------+--------------------------------------
331331
281474976710657 | {}
@@ -345,8 +345,8 @@ SELECT * FROM ag_graph_1._ag_label_edge;
345345
1125899906842626 | 281474976710661 | 281474976710662 | {}
346346
1125899906842627 | 281474976710663 | 281474976710664 | {}
347347
1125899906842628 | 281474976710665 | 281474976710666 | {}
348-
1407374883553281 | 281474976710660 | 281474976710659 | {}
349-
1407374883553282 | 281474976710662 | 281474976710661 | {}
348+
1407374883553281 | 281474976710662 | 281474976710661 | {}
349+
1407374883553282 | 281474976710660 | 281474976710659 | {}
350350
1407374883553283 | 281474976710664 | 281474976710663 | {}
351351
1407374883553284 | 281474976710666 | 281474976710665 | {}
352352
(8 rows)
@@ -357,7 +357,7 @@ WARNING: edge: [id: 1125899906842626, start: 281474976710661, end: 281474976710
357357
WARNING: ignored malformed or dangling edge
358358
WARNING: edge: [id: 1125899906842627, start: 281474976710663, end: 281474976710664, label: knows] end vertex not found
359359
WARNING: ignored malformed or dangling edge
360-
WARNING: edge: [id: 1407374883553282, start: 281474976710662, end: 281474976710661, label: stalks] start and end vertices not found
360+
WARNING: edge: [id: 1407374883553281, start: 281474976710662, end: 281474976710661, label: stalks] start and end vertices not found
361361
WARNING: ignored malformed or dangling edge
362362
WARNING: edge: [id: 1407374883553283, start: 281474976710664, end: 281474976710663, label: stalks] start vertex not found
363363
WARNING: ignored malformed or dangling edge

regress/expected/age_load.out

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,15 @@ WHERE table_schema = 'agload_test_graph' ORDER BY table_name ASC;
125125
contrib_regression | agload_test_graph | has_city | BASE TABLE
126126
(5 rows)
127127

128-
SELECT COUNT(*) FROM agload_test_graph."Country";
128+
SELECT COUNT(*) FROM agload_test_graph._ag_label_vertex
129+
WHERE labels = 'agload_test_graph."Country"'::regclass::oid;
129130
count
130131
-------
131132
54
132133
(1 row)
133134

134-
SELECT COUNT(*) FROM agload_test_graph."City";
135+
SELECT COUNT(*) FROM agload_test_graph._ag_label_vertex
136+
WHERE labels = 'agload_test_graph."City"'::regclass::oid;
135137
count
136138
-------
137139
72485
@@ -194,19 +196,22 @@ SELECT load_labels_from_file('agload_test_graph', 'City2',
194196

195197
(1 row)
196198

197-
SELECT COUNT(*) FROM agload_test_graph."Country2";
199+
SELECT COUNT(*) FROM agload_test_graph._ag_label_vertex
200+
WHERE labels = 'agload_test_graph."Country2"'::regclass::oid;
198201
count
199202
-------
200203
53
201204
(1 row)
202205

203-
SELECT COUNT(*) FROM agload_test_graph."City2";
206+
SELECT COUNT(*) FROM agload_test_graph._ag_label_vertex
207+
WHERE labels = 'agload_test_graph."City2"'::regclass::oid;
204208
count
205209
-------
206210
72485
207211
(1 row)
208212

209-
SELECT id FROM agload_test_graph."Country" LIMIT 10;
213+
SELECT id FROM agload_test_graph._ag_label_vertex
214+
WHERE labels = 'agload_test_graph."Country"'::regclass::oid LIMIT 10;
210215
id
211216
-----------------
212217
844424930131969
@@ -221,7 +226,8 @@ SELECT id FROM agload_test_graph."Country" LIMIT 10;
221226
844424930132023
222227
(10 rows)
223228

224-
SELECT id FROM agload_test_graph."Country2" LIMIT 10;
229+
SELECT id FROM agload_test_graph._ag_label_vertex
230+
WHERE labels = 'agload_test_graph."Country2"'::regclass::oid LIMIT 10;
225231
id
226232
------------------
227233
1688849860263937
@@ -238,7 +244,7 @@ SELECT id FROM agload_test_graph."Country2" LIMIT 10;
238244

239245
-- Should return 2 rows for Country with same properties, but different ids
240246
SELECT * FROM cypher('agload_test_graph', $$MATCH(n:Country {iso2 : 'BE'})
241-
RETURN id(n), n.name, n.iso2 $$) as ("id(n)" agtype, "n.name" agtype, "n.iso2" agtype);
247+
RETURN id(n), n.name, n.iso2 ORDER BY id(n) $$) as ("id(n)" agtype, "n.name" agtype, "n.iso2" agtype);
242248
id(n) | n.name | n.iso2
243249
-----------------+-----------+--------
244250
844424930131990 | "Belgium" | "BE"
@@ -247,15 +253,15 @@ SELECT * FROM cypher('agload_test_graph', $$MATCH(n:Country {iso2 : 'BE'})
247253

248254
-- Should return 1 row
249255
SELECT * FROM cypher('agload_test_graph', $$MATCH(n:Country2 {iso2 : 'BE'})
250-
RETURN id(n), n.name, n.iso2 $$) as ("id(n)" agtype, "n.name" agtype, "n.iso2" agtype);
256+
RETURN id(n), n.name, n.iso2 ORDER BY id(n) $$) as ("id(n)" agtype, "n.name" agtype, "n.iso2" agtype);
251257
id(n) | n.name | n.iso2
252258
------------------+-----------+--------
253259
1688849860263942 | "Belgium" | "BE"
254260
(1 row)
255261

256262
-- Should return 2 rows for Country with same properties, but different ids
257263
SELECT * FROM cypher('agload_test_graph', $$MATCH(n:Country {iso2 : 'AT'})
258-
RETURN id(n), n.name, n.iso2 $$) as ("id(n)" agtype, "n.name" agtype, "n.iso2" agtype);
264+
RETURN id(n), n.name, n.iso2 ORDER BY id(n) $$) as ("id(n)" agtype, "n.name" agtype, "n.iso2" agtype);
259265
id(n) | n.name | n.iso2
260266
-----------------+-----------+--------
261267
844424930131983 | "Austria" | "AT"
@@ -264,7 +270,7 @@ SELECT * FROM cypher('agload_test_graph', $$MATCH(n:Country {iso2 : 'AT'})
264270

265271
-- Should return 1 row
266272
SELECT * FROM cypher('agload_test_graph', $$MATCH(n:Country2 {iso2 : 'AT'})
267-
RETURN id(n), n.name, n.iso2 $$) as ("id(n)" agtype, "n.name" agtype, "n.iso2" agtype);
273+
RETURN id(n), n.name, n.iso2 ORDER BY id(n) $$) as ("id(n)" agtype, "n.name" agtype, "n.iso2" agtype);
268274
id(n) | n.name | n.iso2
269275
------------------+-----------+--------
270276
1688849860263940 | "Austria" | "AT"
@@ -275,6 +281,7 @@ SELECT * FROM cypher('agload_test_graph', $$
275281
MATCH (u:Country {region : "Europe"})
276282
WHERE u.name =~ 'Cro.*'
277283
RETURN id(u), u.name, u.region
284+
ORDER BY id(u)
278285
$$) AS ("id(u)" agtype, result_1 agtype, result_2 agtype);
279286
id(u) | result_1 | result_2
280287
-----------------+-----------+----------

regress/expected/cypher_create.out

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,8 @@ SELECT * FROM cypher_create.e;
133133
1125899906842634 | 844424930131987 | 844424930131988 | {"id": "paths, edge two"}
134134
(10 rows)
135135

136-
SELECT * FROM cypher_create.v;
136+
SELECT id, properties FROM cypher_create._ag_label_vertex
137+
WHERE labels = 'cypher_create.v'::regclass::oid;
137138
id | properties
138139
-----------------+------------------------------------
139140
844424930131969 | {}
@@ -331,7 +332,8 @@ $$) as (a agtype);
331332
---
332333
(0 rows)
333334

334-
SELECT * FROM cypher_create.n_var;
335+
SELECT id, properties FROM cypher_create._ag_label_vertex
336+
WHERE labels = 'cypher_create.n_var'::regclass::oid;
335337
id | properties
336338
------------------+--------------------
337339
1407374883553281 | {"name": "Node A"}
@@ -393,25 +395,6 @@ SELECT * FROM cypher('cypher_create', $$MATCH (n) RETURN n$$) AS (n agtype);
393395
n
394396
-------------------------------------------------------------------------------------------------
395397
{"id": 281474976710657, "label": "", "properties": {}}::vertex
396-
{"id": 281474976710658, "label": "", "properties": {}}::vertex
397-
{"id": 281474976710659, "label": "", "properties": {}}::vertex
398-
{"id": 281474976710660, "label": "", "properties": {}}::vertex
399-
{"id": 281474976710661, "label": "", "properties": {}}::vertex
400-
{"id": 281474976710662, "label": "", "properties": {}}::vertex
401-
{"id": 281474976710663, "label": "", "properties": {}}::vertex
402-
{"id": 281474976710664, "label": "", "properties": {}}::vertex
403-
{"id": 281474976710665, "label": "", "properties": {}}::vertex
404-
{"id": 281474976710666, "label": "", "properties": {}}::vertex
405-
{"id": 281474976710667, "label": "", "properties": {}}::vertex
406-
{"id": 281474976710668, "label": "", "properties": {}}::vertex
407-
{"id": 281474976710669, "label": "", "properties": {}}::vertex
408-
{"id": 281474976710670, "label": "", "properties": {}}::vertex
409-
{"id": 281474976710671, "label": "", "properties": {}}::vertex
410-
{"id": 281474976710672, "label": "", "properties": {}}::vertex
411-
{"id": 281474976710673, "label": "", "properties": {}}::vertex
412-
{"id": 281474976710674, "label": "", "properties": {"id": 0}}::vertex
413-
{"id": 281474976710675, "label": "", "properties": {}}::vertex
414-
{"id": 281474976710676, "label": "", "properties": {}}::vertex
415398
{"id": 844424930131969, "label": "v", "properties": {}}::vertex
416399
{"id": 844424930131970, "label": "v", "properties": {}}::vertex
417400
{"id": 844424930131971, "label": "v", "properties": {"key": "value"}}::vertex
@@ -438,6 +421,25 @@ SELECT * FROM cypher('cypher_create', $$MATCH (n) RETURN n$$) AS (n agtype);
438421
{"id": 1970324836974593, "label": "n_other_node", "properties": {}}::vertex
439422
{"id": 1970324836974594, "label": "n_other_node", "properties": {}}::vertex
440423
{"id": 1970324836974595, "label": "n_other_node", "properties": {}}::vertex
424+
{"id": 281474976710658, "label": "", "properties": {}}::vertex
425+
{"id": 281474976710659, "label": "", "properties": {}}::vertex
426+
{"id": 281474976710660, "label": "", "properties": {}}::vertex
427+
{"id": 281474976710661, "label": "", "properties": {}}::vertex
428+
{"id": 281474976710662, "label": "", "properties": {}}::vertex
429+
{"id": 281474976710663, "label": "", "properties": {}}::vertex
430+
{"id": 281474976710664, "label": "", "properties": {}}::vertex
431+
{"id": 281474976710665, "label": "", "properties": {}}::vertex
432+
{"id": 281474976710666, "label": "", "properties": {}}::vertex
433+
{"id": 281474976710667, "label": "", "properties": {}}::vertex
434+
{"id": 281474976710668, "label": "", "properties": {}}::vertex
435+
{"id": 281474976710669, "label": "", "properties": {}}::vertex
436+
{"id": 281474976710670, "label": "", "properties": {}}::vertex
437+
{"id": 281474976710671, "label": "", "properties": {}}::vertex
438+
{"id": 281474976710672, "label": "", "properties": {}}::vertex
439+
{"id": 281474976710673, "label": "", "properties": {}}::vertex
440+
{"id": 281474976710674, "label": "", "properties": {"id": 0}}::vertex
441+
{"id": 281474976710675, "label": "", "properties": {}}::vertex
442+
{"id": 281474976710676, "label": "", "properties": {}}::vertex
441443
(46 rows)
442444

443445
-- prepared statements

regress/expected/cypher_delete.out

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -535,10 +535,10 @@ SELECT * FROM cypher('cypher_delete', $$MATCH p=()-[]->() RETURN p$$) AS (a agty
535535
SELECT * FROM cypher('cypher_delete', $$MATCH(n) DELETE n RETURN n$$) AS (a agtype);
536536
a
537537
-----------------------------------------------------------------
538-
{"id": 281474976710657, "label": "", "properties": {}}::vertex
539-
{"id": 281474976710658, "label": "", "properties": {}}::vertex
540538
{"id": 844424930132012, "label": "v", "properties": {}}::vertex
539+
{"id": 281474976710657, "label": "", "properties": {}}::vertex
541540
{"id": 844424930132013, "label": "v", "properties": {}}::vertex
541+
{"id": 281474976710658, "label": "", "properties": {}}::vertex
542542
(4 rows)
543543

544544
--Test 24
@@ -710,8 +710,8 @@ SELECT * FROM cypher('detach_delete', $$ MATCH ()-[e]->() RETURN e.name $$) as (
710710
-------
711711
"ab"
712712
"cd"
713-
"am"
714713
"nm"
714+
"am"
715715
"pq"
716716
(5 rows)
717717

0 commit comments

Comments
 (0)