Skip to content

Commit ace7bf7

Browse files
Fixes #2164: Adds support for PostgreSQL 18
1. In PostgreSQL 18, TupleDescAttr is now used to access ScanTuple->tts_tupleDescriptor->attrs since attrs is now replaced by compact_attrs to save on memory in PostgreSQL 18. In PostgreSQL 16, 17 and 18 we have a function TupleDescAttr which allows to acess pg_attrs 2. In PostgreSQL palloc0fast is now merged into palloc0. 3. Few funcitons now reuiqre executor/executor.h and are no longer present in the other includes.
1 parent c75d9e4 commit ace7bf7

File tree

11 files changed

+179
-4
lines changed

11 files changed

+179
-4
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
LOAD 'age';
2+
SET search_path TO ag_catalog;
3+
SELECT create_graph('cypher_path');
4+
NOTICE: graph "cypher_path" has been created
5+
create_graph
6+
--------------
7+
8+
(1 row)
9+
10+
-- Create vertex
11+
SELECT * FROM cypher('cypher_path', $$
12+
CREATE (:label_name_1 {i: 0})
13+
$$) as (a agtype);
14+
a
15+
---
16+
(0 rows)
17+
18+
-- Create a path to test our create, set and delete on.
19+
SELECT *
20+
FROM cypher('cypher_path', $$
21+
CREATE p = (andres {name:'Andres'})-[:WORKS_AT]->(neo)<-[:WORKS_AT]-(michael {name:'Michael'})-[:WORKS_WITH]->(jordan {name: 'Jordan'})
22+
RETURN p
23+
$$) as (p agtype);
24+
p
25+
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
26+
[{"id": 281474976710657, "label": "", "properties": {"name": "Andres"}}::vertex, {"id": 1125899906842626, "label": "WORKS_AT", "end_id": 281474976710658, "start_id": 281474976710657, "properties": {}}::edge, {"id": 281474976710658, "label": "", "properties": {}}::vertex, {"id": 1125899906842625, "label": "WORKS_AT", "end_id": 281474976710658, "start_id": 281474976710659, "properties": {}}::edge, {"id": 281474976710659, "label": "", "properties": {"name": "Michael"}}::vertex, {"id": 1407374883553281, "label": "WORKS_WITH", "end_id": 281474976710660, "start_id": 281474976710659, "properties": {}}::edge, {"id": 281474976710660, "label": "", "properties": {"name": "Jordan"}}::vertex]::path
27+
(1 row)
28+
29+
-- Now delete one of the relationships nodes and the output should be return unchanged.
30+
SELECT *
31+
FROM cypher('cypher_path', $$
32+
MATCH p = ()-[]->()<-[]-()-[]->(j)
33+
DETACH DELETE j
34+
RETURN p
35+
$$) AS (a agtype);
36+
a
37+
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
38+
[{"id": 281474976710657, "label": "", "properties": {"name": "Andres"}}::vertex, {"id": 1125899906842626, "label": "WORKS_AT", "end_id": 281474976710658, "start_id": 281474976710657, "properties": {}}::edge, {"id": 281474976710658, "label": "", "properties": {}}::vertex, {"id": 1125899906842625, "label": "WORKS_AT", "end_id": 281474976710658, "start_id": 281474976710659, "properties": {}}::edge, {"id": 281474976710659, "label": "", "properties": {"name": "Michael"}}::vertex, {"id": 1407374883553281, "label": "WORKS_WITH", "end_id": 281474976710660, "start_id": 281474976710659, "properties": {}}::edge, {"id": 281474976710660, "label": "", "properties": {"name": "Jordan"}}::vertex]::path
39+
(1 row)
40+
41+
-- Now delete one of the edges and the path should be updated but output is still unchanged
42+
SELECT *
43+
FROM cypher('cypher_path', $$
44+
MATCH p = (andres {name: 'Andres'})-[r:WORKS_AT]->(neo)<-[g:WORKS_AT]-(michael {name: 'Michael'})
45+
DELETE g
46+
RETURN p
47+
$$) as (a agtype);
48+
a
49+
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
50+
[{"id": 281474976710657, "label": "", "properties": {"name": "Andres"}}::vertex, {"id": 1125899906842626, "label": "WORKS_AT", "end_id": 281474976710658, "start_id": 281474976710657, "properties": {}}::edge, {"id": 281474976710658, "label": "", "properties": {}}::vertex, {"id": 1125899906842625, "label": "WORKS_AT", "end_id": 281474976710658, "start_id": 281474976710659, "properties": {}}::edge, {"id": 281474976710659, "label": "", "properties": {"name": "Michael"}}::vertex]::path
51+
(1 row)
52+
53+
-- Create a path to test our create, set and delete on.
54+
SELECT *
55+
FROM cypher('cypher_path', $$
56+
CREATE p = (andres {name:'Andres'})-[:CHILLS_AT]->(neo)<-[:CHILLS_SOME_MORE]-(michael {name:'Michael'})
57+
RETURN p
58+
$$) as (p agtype);
59+
p
60+
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
61+
[{"id": 281474976710661, "label": "", "properties": {"name": "Andres"}}::vertex, {"id": 1688849860263937, "label": "CHILLS_AT", "end_id": 281474976710662, "start_id": 281474976710661, "properties": {}}::edge, {"id": 281474976710662, "label": "", "properties": {}}::vertex, {"id": 1970324836974593, "label": "CHILLS_SOME_MORE", "end_id": 281474976710662, "start_id": 281474976710663, "properties": {}}::edge, {"id": 281474976710663, "label": "", "properties": {"name": "Michael"}}::vertex]::path
62+
(1 row)
63+
64+
-- Attempt to delete anything other than vertex or edge. This should fail
65+
SELECT *
66+
FROM cypher('cypher_path', $$
67+
MATCH p = (andres {name: 'Andres'})-[]->()
68+
DELETE p
69+
RETURN p
70+
$$) as (a agtype);
71+
ERROR: DELETE clause can only delete vertices and edges
72+
-- Cleanup
73+
SELECT drop_graph('cypher_path', true);
74+
NOTICE: drop cascades to 7 other objects
75+
DETAIL: drop cascades to table cypher_path._ag_label_vertex
76+
drop cascades to table cypher_path._ag_label_edge
77+
drop cascades to table cypher_path.label_name_1
78+
drop cascades to table cypher_path."WORKS_AT"
79+
drop cascades to table cypher_path."WORKS_WITH"
80+
drop cascades to table cypher_path."CHILLS_AT"
81+
drop cascades to table cypher_path."CHILLS_SOME_MORE"
82+
NOTICE: graph "cypher_path" has been dropped
83+
drop_graph
84+
------------
85+
86+
(1 row)
87+

regress/sql/cypher_path_delete.sql

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
2+
LOAD 'age';
3+
4+
SET search_path TO ag_catalog;
5+
6+
SELECT create_graph('cypher_path');
7+
8+
-- Create vertex
9+
SELECT * FROM cypher('cypher_path', $$
10+
CREATE (:label_name_1 {i: 0})
11+
$$) as (a agtype);
12+
13+
-- Create a path to test our create, set and delete on.
14+
SELECT *
15+
FROM cypher('cypher_path', $$
16+
CREATE p = (andres {name:'Andres'})-[:WORKS_AT]->(neo)<-[:WORKS_AT]-(michael {name:'Michael'})-[:WORKS_WITH]->(jordan {name: 'Jordan'})
17+
RETURN p
18+
$$) as (p agtype);
19+
20+
-- Now delete one of the relationships nodes and the output should be return unchanged.
21+
SELECT *
22+
FROM cypher('cypher_path', $$
23+
MATCH p = ()-[]->()<-[]-()-[]->(j)
24+
DETACH DELETE j
25+
RETURN p
26+
$$) AS (a agtype);
27+
28+
-- Now delete one of the edges and the path should be updated but output is still unchanged
29+
SELECT *
30+
FROM cypher('cypher_path', $$
31+
MATCH p = (andres {name: 'Andres'})-[r:WORKS_AT]->(neo)<-[g:WORKS_AT]-(michael {name: 'Michael'})
32+
DELETE g
33+
RETURN p
34+
$$) as (a agtype);
35+
36+
-- Create a path to test our create, set and delete on.
37+
SELECT *
38+
FROM cypher('cypher_path', $$
39+
CREATE p = (andres {name:'Andres'})-[:CHILLS_AT]->(neo)<-[:CHILLS_SOME_MORE]-(michael {name:'Michael'})
40+
RETURN p
41+
$$) as (p agtype);
42+
43+
-- Attempt to delete anything other than vertex or edge. This should fail
44+
SELECT *
45+
FROM cypher('cypher_path', $$
46+
MATCH p = (andres {name: 'Andres'})-[]->()
47+
DELETE p
48+
RETURN p
49+
$$) as (a agtype);
50+
51+
-- Cleanup
52+
SELECT drop_graph('cypher_path', true);

src/backend/catalog/ag_label.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "catalog/ag_label.h"
3030
#include "commands/label_commands.h"
3131
#include "executor/cypher_utils.h"
32+
#include "executor/executor.h"
3233
#include "utils/ag_cache.h"
3334

3435
/*

src/backend/executor/cypher_create.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
#include "postgres.h"
2121

2222
#include "catalog/ag_label.h"
23+
#include "catalog/indexing.h"
2324
#include "executor/cypher_executor.h"
2425
#include "executor/cypher_utils.h"
26+
#include "executor/executor.h"
2527

2628
static void begin_cypher_create(CustomScanState *node, EState *estate,
2729
int eflags);

src/backend/executor/cypher_delete.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#include "catalog/ag_label.h"
2626
#include "executor/cypher_executor.h"
2727
#include "executor/cypher_utils.h"
28+
#include "executor/executor.h"
29+
#include "pg_config.h"
2830

2931
static void begin_cypher_delete(CustomScanState *node, EState *estate,
3032
int eflags);
@@ -55,6 +57,11 @@ const CustomExecMethods cypher_delete_exec_methods = {DELETE_SCAN_STATE_NAME,
5557
NULL,
5658
NULL};
5759

60+
#if PG_VERSION_NUM >= 18000
61+
#define TUPLE_DESC_ATTR_TYPE_ID TupleDescAttr(tupleDescriptor, entity_position - 1)->atttypid
62+
#else
63+
#define TUPLE_DESC_ATTR_TYPE_ID tupleDescriptor->attrs[entity_position - 1]->atttypid
64+
#endif
5865
/*
5966
* Initialization at the beginning of execution. Setup the child node,
6067
* setup its scan tuple slot and projection info, expression context,
@@ -257,13 +264,15 @@ static agtype_value *extract_entity(CustomScanState *node,
257264
tupleDescriptor = scanTupleSlot->tts_tupleDescriptor;
258265

259266
/* type checking, make sure the entity is an agtype vertex or edge */
260-
if (tupleDescriptor->attrs[entity_position -1].atttypid != AGTYPEOID)
267+
// First make sure the entity is an agtype. this is set per extension. Also, from postgresql 16 onwards use TupleDescAttr so that it works on both attrs and compact_attrs.
268+
if (TUPLE_DESC_ATTR_TYPE_ID != AGTYPEOID)
261269
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
262270
errmsg("DELETE clause can only delete agtype")));
263271

264272
original_entity = DATUM_GET_AGTYPE_P(scanTupleSlot->tts_values[entity_position - 1]);
265273
original_entity_value = get_ith_agtype_value_from_container(&original_entity->root, 0);
266274

275+
// We are not deleting anything other than vertices and edges.
267276
if (original_entity_value->type != AGTV_VERTEX && original_entity_value->type != AGTV_EDGE)
268277
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
269278
errmsg("DELETE clause can only delete vertices and edges")));

src/backend/executor/cypher_merge.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "catalog/ag_label.h"
2323
#include "executor/cypher_executor.h"
2424
#include "executor/cypher_utils.h"
25+
#include "executor/executor.h"
2526
#include "utils/datum.h"
2627

2728
/*

src/backend/executor/cypher_set.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
#include "executor/cypher_executor.h"
2525
#include "executor/cypher_utils.h"
2626

27+
#include "executor/executor.h"
28+
#include "pg_config.h"
2729
static void begin_cypher_set(CustomScanState *node, EState *estate,
2830
int eflags);
2931
static TupleTableSlot *exec_cypher_set(CustomScanState *node);
@@ -49,6 +51,13 @@ const CustomExecMethods cypher_set_exec_methods = {SET_SCAN_STATE_NAME,
4951
NULL,
5052
NULL};
5153

54+
#if PG_VERSION_NUM >= 18000
55+
#define TUPLE_DESC_ATTR_TYPE_ID TupleDescAttr(scanTupleSlot->tts_tupleDescriptor, i)->atttypid
56+
#define TUPLE_DESC_ATTR_TYPE_ID_ENTITY TupleDescAttr(scanTupleSlot->tts_tupleDescriptor, update_item->entity_position - 1)->atttypid
57+
#else
58+
#define TUPLE_DESC_ATTR_TYPE_ID scanTupleSlot->tts_tupleDescriptor->attrs[i]->atttypid
59+
#define TUPLE_DESC_ATTR_TYPE_ID_ENTITY scanTupleSlot->tts_tupleDescriptor->attrs[update_item->entity_position - 1]->atttypid
60+
#endif
5261
static void begin_cypher_set(CustomScanState *node, EState *estate,
5362
int eflags)
5463
{
@@ -310,7 +319,8 @@ static void update_all_paths(CustomScanState *node, graphid id,
310319
agtype_value *original_entity_value;
311320

312321
/* skip nulls */
313-
if (scanTupleSlot->tts_tupleDescriptor->attrs[i].atttypid != AGTYPEOID)
322+
// Starting postgresql version 16, tupleDescriptor->attrs access is not recommended. Instead, we must use tupleDescAttr which handles both compact_attr and attr access.
323+
if (TUPLE_DESC_ATTR_TYPE_ID != AGTYPEOID)
314324
{
315325
continue;
316326
}
@@ -414,7 +424,8 @@ static void process_update_list(CustomScanState *node)
414424
continue;
415425
}
416426

417-
if (scanTupleSlot->tts_tupleDescriptor->attrs[update_item->entity_position -1].atttypid != AGTYPEOID)
427+
// Starting from postgresql 16, we need to use TupleDescAttr for accessing tupleDescriptor because attr is now no longer present under tupleDescriptor and is now compact_attr
428+
if (TUPLE_DESC_ATTR_TYPE_ID_ENTITY != AGTYPEOID)
418429
{
419430
ereport(ERROR,
420431
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),

src/backend/executor/cypher_utils.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "catalog/ag_label.h"
3131
#include "commands/label_commands.h"
3232
#include "executor/cypher_utils.h"
33+
#include "executor/executor.h"
3334
#include "utils/ag_cache.h"
3435

3536
/*

src/backend/nodes/ag_nodes.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "nodes/cypher_readfuncs.h"
2626
#include "nodes/cypher_nodes.h"
2727

28+
#include "utils/palloc.h"
2829
static bool equal_ag_node(const ExtensibleNode *a, const ExtensibleNode *b);
2930

3031
/* This list must match ag_node_tag. */
@@ -156,7 +157,7 @@ ExtensibleNode *_new_ag_node(Size size, ag_node_tag tag)
156157
{
157158
ExtensibleNode *n;
158159

159-
n = (ExtensibleNode *)palloc0fast(size);
160+
n = (ExtensibleNode *)palloc0(size);
160161
n->type = T_ExtensibleNode;
161162
n->extnodename = node_names[tag];
162163

src/backend/parser/cypher_clause.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@
5151
#include "utils/ag_cache.h"
5252
#include "utils/ag_func.h"
5353
#include "utils/ag_guc.h"
54+
#include "nodes/primnodes.h"
55+
#include "pg_config.h"
5456

5557
/*
5658
* Variable string names for makeTargetEntry. As they are going to be variable
@@ -2555,10 +2557,17 @@ static void get_res_cols(ParseState *pstate, ParseNamespaceItem *l_pnsi,
25552557
List *colnames = NIL;
25562558
List *colvars = NIL;
25572559

2560+
#if PG_VERSION_NUM >= 180000
2561+
expandRTE(l_pnsi->p_rte, l_pnsi->p_rtindex, 0, VAR_RETURNING_DEFAULT, -1, false,
2562+
&l_colnames, &l_colvars);
2563+
expandRTE(r_pnsi->p_rte, r_pnsi->p_rtindex, 0, VAR_RETURNING_DEFAULT, -1, false,
2564+
&r_colnames, &r_colvars);
2565+
#else
25582566
expandRTE(l_pnsi->p_rte, l_pnsi->p_rtindex, 0, -1, false,
25592567
&l_colnames, &l_colvars);
25602568
expandRTE(r_pnsi->p_rte, r_pnsi->p_rtindex, 0, -1, false,
25612569
&r_colnames, &r_colvars);
2570+
#endif
25622571

25632572
/* add in all colnames and colvars from the l_rte. */
25642573
*res_colnames = list_concat(*res_colnames, l_colnames);

0 commit comments

Comments
 (0)