Skip to content

Commit 58b0a8e

Browse files
committed
Support Vertex and Edge Variables in CREATE
1 parent 5656047 commit 58b0a8e

File tree

8 files changed

+227
-377
lines changed

8 files changed

+227
-377
lines changed

postgraph--0.1.0.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3531,6 +3531,7 @@ CREATE FUNCTION gtype_in_operator(gtype, gtype)
35313531
RETURNS bool
35323532
LANGUAGE c
35333533
IMMUTABLE
3534+
RETURNS NULL ON NULL INPUT
35343535
PARALLEL SAFE
35353536
AS 'MODULE_PATHNAME';
35363537

regress/sql/cypher_create.sql

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,23 @@ CREATE (a)-[]->();
5252

5353
CREATE (a)-[]->() RETURN a;
5454

55+
CREATE (a)-[]->(b) RETURN a;
56+
57+
CREATE (a {msg: 'hello vertex out'}) RETURN a;
58+
59+
CREATE (a {msg: 'hello vertex out'}) RETURN a.msg;
60+
61+
CREATE (a {msg: 'hello vertex out'})-[]->(b) RETURN a;
62+
63+
64+
CREATE (a)-[e]->(b) RETURN e;
65+
66+
CREATE (a)-[e {msg: 'hello edge'}]->(b) RETURN e;
67+
68+
69+
CREATE ()-[{msg: 'hello edge'}]->();
70+
SELECT * FROM cypher_create._adj__ag_label_vertex;
71+
5572
CREATE ()-[:elabel]->();
5673

5774
MATCH ()-[]->() RETURN 1;

src/backend/executor/cypher_create.c

Lines changed: 114 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -133,13 +133,13 @@ static void begin_cypher_create(CustomScanState *node, EState *estate, int eflag
133133
ExecGetResultType(node->ss.ps.lefttree),
134134
&TTSOpsHeapTuple);
135135

136-
/*
136+
137137
if (!CYPHER_CLAUSE_IS_TERMINAL(css->flags)) {
138138
TupleDesc tupdesc = node->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
139139

140140
ExecAssignProjectionInfo(&node->ss.ps, tupdesc);
141141
}
142-
*/
142+
143143

144144
if (list_length(css->pattern) != 1)
145145
ereport(ERROR, (errmsg_internal("executor create found a multi pattern")));
@@ -203,111 +203,141 @@ static TupleTableSlot *exec_cypher_create(CustomScanState *csnode)
203203
EState *estate = css->css.ss.ps.state;
204204
ExprContext *econtext = css->css.ss.ps.ps_ExprContext;
205205

206+
while (true) {
207+
RollbackCmdId(estate);
208+
TupleTableSlot *return_slot = ExecProcNode(csnode->ss.ps.lefttree);
209+
AdvanceCmdId(estate);
210+
211+
if (TupIsNull(return_slot))
212+
return return_slot;
213+
// if ((return_slot->tts_flags = return_slot & TTS_FLAG_EMPTY))
214+
// return NULL;
215+
econtext->ecxt_scantuple =
216+
csnode->ss.ps.lefttree->ps_ProjInfo->pi_exprContext->ecxt_scantuple;
217+
TupleTableSlot *slot = econtext->ecxt_scantuple;//csnode->ss.ps.lefttree->ps_ProjInfo->pi_exprContext->ecxt_scantuple;
218+
//slot->tts_ops->materialize(slot);
219+
220+
if (list_length(css->pattern) != 1)
221+
ereport(ERROR, (errmsg_internal("executor create found a multi pattern")));
222+
223+
cypher_create_path *path = linitial(css->pattern);
224+
225+
ListCell *lc;
226+
int i = 1;
227+
foreach(lc, path->target_nodes) {
228+
cypher_target_node *node = (cypher_target_node *)lfirst(lc);
229+
bool isNull;
230+
if(i % 2 == 1)
231+
css->vertex_ids[0][i/2] = ExecEvalExpr(node->id_expr_state, econtext, &isNull);
232+
else {
233+
css->edge_ids[0][(i-1)/2] = ExecEvalExpr(node->id_expr_state, econtext, &isNull);
234+
235+
}
236+
i++;
237+
}
206238

207-
RollbackCmdId(estate);
208-
TupleTableSlot *slot = ExecProcNode(csnode->ss.ps.lefttree);
209-
AdvanceCmdId(estate);
239+
for (int i = 0; i < list_length(path->target_nodes)/2 + 1; i++) {
240+
cypher_target_node *node = (cypher_target_node *)list_nth(path->target_nodes, i * 2);
241+
242+
ResultRelInfo *resultRelInfo = node->resultRelInfo;
243+
TupleTableSlot *elemTupleSlot = node->elemTupleSlot;
210244

211-
slot = csnode->ss.ps.lefttree->ps_ProjInfo->pi_exprContext->ecxt_scantuple;
212-
slot->tts_ops->materialize(slot);
213-
if (list_length(css->pattern) != 1)
214-
ereport(ERROR, (errmsg_internal("executor create found a multi pattern")));
245+
ResultRelInfo **old_estate_es_result_relations_info = NULL;
215246

216-
cypher_create_path *path = linitial(css->pattern);
247+
/* save the old result relation info */
248+
old_estate_es_result_relations_info = estate->es_result_relations;
217249

218-
ListCell *lc;
219-
int i = 1;
220-
foreach(lc, path->target_nodes) {
221-
cypher_target_node *node = (cypher_target_node *)lfirst(lc);
222-
bool isNull;
223-
if(i % 2 == 1)
224-
css->vertex_ids[0][i/2] = ExecEvalExpr(node->id_expr_state, econtext, &isNull);
225-
else {
226-
css->edge_ids[0][(i-1)/2] = ExecEvalExpr(node->id_expr_state, econtext, &isNull);
227-
228-
}
229-
i++;
230-
231-
}
250+
estate->es_result_relations = &resultRelInfo;
232251

233-
for (int i = 0; i < list_length(path->target_nodes)/2 + 1; i++) {
234-
cypher_target_node *node = (cypher_target_node *)list_nth(path->target_nodes, i * 2);
235-
236-
ResultRelInfo *resultRelInfo = node->resultRelInfo;
237-
TupleTableSlot *elemTupleSlot = node->elemTupleSlot;
252+
ExecClearTuple(elemTupleSlot);
253+
254+
// get the next graphid for this vertex.
255+
elemTupleSlot->tts_values[0] = css->vertex_ids[0][i];
256+
elemTupleSlot->tts_isnull[0] = false;
257+
if (node->id_attr_num != InvalidAttrNumber) {
258+
slot->tts_values[node->id_attr_num - 1] = GRAPHID_GET_DATUM(css->vertex_ids[0][i]);
259+
slot->tts_isnull[node->id_attr_num - 1] = false;
260+
}
238261

239-
ResultRelInfo **old_estate_es_result_relations_info = NULL;
262+
// get the properties for this vertex
263+
if (node->prop_attr_num == InvalidAttrNumber) {
264+
elemTupleSlot->tts_values[1] = NULL;
265+
elemTupleSlot->tts_isnull[1] = true;
266+
} else {
267+
elemTupleSlot->tts_values[1] = slot->tts_values[node->prop_attr_num - 1];
268+
elemTupleSlot->tts_isnull[1] = slot->tts_isnull[node->prop_attr_num - 1];
269+
}
240270

241-
/* save the old result relation info */
242-
old_estate_es_result_relations_info = estate->es_result_relations;
271+
if (node->tuple_position != InvalidAttrNumber) {
272+
slot->tts_values[node->tuple_position - 1] = VERTEX_GET_DATUM(create_vertex(
273+
slot->tts_values[node->id_attr_num - 1],
274+
css->graph_oid,
275+
elemTupleSlot->tts_isnull[1] ? NULL : DATUM_GET_GTYPE_P(elemTupleSlot->tts_values[1])));
276+
slot->tts_isnull[node->tuple_position - 1] = false;
277+
}
243278

244-
estate->es_result_relations = &resultRelInfo;
279+
// Insert the new vertex
280+
insert_entity_tuple(resultRelInfo, elemTupleSlot, estate);
245281

246-
ExecClearTuple(elemTupleSlot);
247282

248-
// get the next graphid for this vertex.
249-
elemTupleSlot->tts_values[0] = css->vertex_ids[0][i];
250-
elemTupleSlot->tts_isnull[0] = false;
251-
if (node->id_attr_num != InvalidAttrNumber) {
252-
slot->tts_values[node->id_attr_num - 1] = GRAPHID_GET_DATUM(css->vertex_ids[0][i]);
253-
slot->tts_isnull[node->id_attr_num - 1] = false;
254-
}
283+
if (list_length(path->target_nodes) > 1 && i < (list_length(path->target_nodes)/2)) {
255284

256-
// get the properties for this vertex
257-
if (node->prop_attr_num == InvalidAttrNumber) {
258-
elemTupleSlot->tts_values[1] = NULL;
259-
elemTupleSlot->tts_isnull[1] = true;
260-
} else {
261-
elemTupleSlot->tts_values[1] = slot->tts_values[node->prop_attr_num - 1];
262-
elemTupleSlot->tts_isnull[1] = slot->tts_isnull[node->prop_attr_num - 1];
263-
}
285+
286+
resultRelInfo = node->adj_resultRelInfo;
287+
elemTupleSlot = node->adj_elemTupleSlot;
264288

265-
if (node->tuple_position != InvalidAttrNumber) {
266-
create_vertex(
267-
GRAPHID_GET_DATUM(slot->tts_values[node->id_attr_num - 1]),
268-
css->graph_oid,
269-
node->prop_attr_num == InvalidAttrNumber? NULL: DATUM_GET_GTYPE_P(slot->tts_values[node->prop_attr_num - 1]));
270-
}
289+
estate->es_result_relations = &resultRelInfo;
271290

272-
// Insert the new vertex
273-
insert_entity_tuple(resultRelInfo, elemTupleSlot, estate);
291+
ExecClearTuple(elemTupleSlot);
292+
cypher_target_node *node = (cypher_target_node *)list_nth(path->target_nodes, (i * 2) + 1);
293+
// get the next graphid for this vertex.
294+
elemTupleSlot->tts_values[0] = css->edge_ids[0][i];
295+
elemTupleSlot->tts_isnull[0] = false;
296+
297+
elemTupleSlot->tts_values[1] = css->vertex_ids[0][node->dir == CYPHER_REL_DIR_RIGHT ? i : i + 1];
298+
elemTupleSlot->tts_isnull[1] = false;
299+
300+
elemTupleSlot->tts_values[2] = css->vertex_ids[0][node->dir == CYPHER_REL_DIR_RIGHT ? i + 1 : i];
301+
elemTupleSlot->tts_isnull[2] = false;
274302

275-
if (list_length(path->target_nodes) > 1 && i < (list_length(path->target_nodes)/2)) {
276-
resultRelInfo = node->adj_resultRelInfo;
277-
elemTupleSlot = node->adj_elemTupleSlot;
278303

279-
estate->es_result_relations = &resultRelInfo;
304+
if (node->prop_attr_num == InvalidAttrNumber) {
305+
elemTupleSlot->tts_values[3] = NULL;
306+
elemTupleSlot->tts_isnull[3] = true;
307+
} else {
308+
//TupleTableSlot *scanTupleSlot = econtext->ecxt_scantuple;
309+
elemTupleSlot->tts_values[3] = slot->tts_values[node->prop_attr_num - 1];
310+
elemTupleSlot->tts_isnull[3] = slot->tts_isnull[node->prop_attr_num - 1];
311+
}
280312

281-
ExecClearTuple(elemTupleSlot);
313+
// Insert the new vertex
314+
insert_entity_tuple(resultRelInfo, elemTupleSlot, estate);
282315

283-
// get the next graphid for this vertex.
284-
elemTupleSlot->tts_values[0] = css->edge_ids[0][i];
285-
elemTupleSlot->tts_isnull[0] = false;
286-
287-
elemTupleSlot->tts_values[1] = css->vertex_ids[0][node->dir == CYPHER_REL_DIR_RIGHT ? i : i + 1];
288-
elemTupleSlot->tts_isnull[1] = false;
289-
290-
elemTupleSlot->tts_values[2] = css->vertex_ids[0][node->dir == CYPHER_REL_DIR_RIGHT ? i + 1 : i];
291-
elemTupleSlot->tts_isnull[2] = false;
292316

317+
if (node->tuple_position != InvalidAttrNumber) {
318+
slot->tts_values[node->tuple_position - 1] = EDGE_GET_DATUM(create_edge(
319+
css->edge_ids[0][i],
320+
css->vertex_ids[0][node->dir == CYPHER_REL_DIR_RIGHT ? i : i + 1],
321+
css->vertex_ids[0][node->dir == CYPHER_REL_DIR_RIGHT ? i + 1 : i],
322+
css->graph_oid,
323+
elemTupleSlot->tts_isnull[3] ? NULL : DATUM_GET_GTYPE_P(elemTupleSlot->tts_values[3])));
324+
slot->tts_isnull[node->tuple_position - 1] = false;
325+
}
293326

294-
if (node->prop_attr_num == InvalidAttrNumber) {
295-
elemTupleSlot->tts_values[3] = NULL;
296-
elemTupleSlot->tts_isnull[3] = true;
297-
} else {
298-
//TupleTableSlot *scanTupleSlot = econtext->ecxt_scantuple;
299-
elemTupleSlot->tts_values[3] = slot->tts_values[node->prop_attr_num - 1];
300-
elemTupleSlot->tts_isnull[3] = slot->tts_isnull[node->prop_attr_num - 1];
301327
}
328+
/* restore the old result relation info */
329+
estate->es_result_relations = old_estate_es_result_relations_info;
330+
}
302331

303-
// Insert the new vertex
304-
insert_entity_tuple(resultRelInfo, elemTupleSlot, estate);
332+
// if(CYPHER_CLAUSE_IS_TERMINAL(css->flags))
333+
// return NULL;
334+
if(!CYPHER_CLAUSE_IS_TERMINAL(css->flags)) {
335+
econtext->ecxt_scantuple = ExecProject(csnode->ss.ps.lefttree->ps_ProjInfo);
336+
return ExecProject(csnode->ss.ps.ps_ProjInfo);
337+
// return return_slot;
305338
}
306-
/* restore the old result relation info */
307-
estate->es_result_relations = old_estate_es_result_relations_info;
308-
}
309339

310-
return NULL;
340+
}
311341
}
312342

313343
static void end_cypher_create(CustomScanState *node)

0 commit comments

Comments
 (0)