in src/backend/executor/cypher_create.c [447:604]
static Datum create_vertex(cypher_create_custom_scan_state *css,
cypher_target_node *node, ListCell *next, List *list)
{
bool isNull;
Datum id;
EState *estate = css->css.ss.ps.state;
ExprContext *econtext = css->css.ss.ps.ps_ExprContext;
ResultRelInfo *resultRelInfo = node->resultRelInfo;
TupleTableSlot *elemTupleSlot = node->elemTupleSlot;
TupleTableSlot *scanTupleSlot = econtext->ecxt_scantuple;
Assert(node->type == LABEL_KIND_VERTEX);
/*
* Vertices in a path might already exists. If they do get the id
* to pass to the edges before and after it. Otherwise, insert the
* new vertex into it's table and then pass the id along.
*/
if (CYPHER_TARGET_NODE_INSERT_ENTITY(node->flags))
{
ResultRelInfo **old_estate_es_result_relations = NULL;
/*
* Set estate's result relation to the vertex's result
* relation.
*
* Note: This obliterates what was their previously
*/
/* save the old result relation info */
old_estate_es_result_relations = estate->es_result_relations;
estate->es_result_relations = &resultRelInfo;
ExecClearTuple(elemTupleSlot);
/* get the next graphid for this vertex. */
id = ExecEvalExpr(node->id_expr_state, econtext, &isNull);
elemTupleSlot->tts_values[vertex_tuple_id] = id;
elemTupleSlot->tts_isnull[vertex_tuple_id] = isNull;
/* get the properties for this vertex */
elemTupleSlot->tts_values[vertex_tuple_properties] =
scanTupleSlot->tts_values[node->prop_attr_num];
elemTupleSlot->tts_isnull[vertex_tuple_properties] =
scanTupleSlot->tts_isnull[node->prop_attr_num];
/* Insert the new vertex */
insert_entity_tuple(resultRelInfo, elemTupleSlot, estate);
/* restore the old result relation info */
estate->es_result_relations = old_estate_es_result_relations;
/*
* When the vertex is used by clauses higher in the execution tree
* we need to create a vertex datum. When the vertex is a variable,
* add to the scantuple slot. When the vertex is part of a path
* variable, add to the list.
*/
if (CYPHER_TARGET_NODE_OUTPUT(node->flags))
{
TupleTableSlot *scantuple;
PlanState *ps;
Datum result;
ps = css->css.ss.ps.lefttree;
scantuple = ps->ps_ExprContext->ecxt_scantuple;
/* make the vertex agtype */
result = make_vertex(id, CStringGetDatum(node->label_name),
scanTupleSlot->tts_values[node->prop_attr_num]);
/* append to the path list */
if (CYPHER_TARGET_NODE_IN_PATH(node->flags))
{
css->path_values = lappend(css->path_values,
DatumGetPointer(result));
}
/*
* Put the vertex in the correct spot in the scantuple, so parent
* execution nodes can reference the newly created variable.
*/
if (CYPHER_TARGET_NODE_IS_VARIABLE(node->flags))
{
scantuple->tts_values[node->tuple_position - 1] = result;
scantuple->tts_isnull[node->tuple_position - 1] = false;
}
}
}
else
{
agtype *a;
agtype_value *v;
agtype_value *id_value;
TupleTableSlot *scantuple;
PlanState *ps;
ps = css->css.ss.ps.lefttree;
scantuple = ps->ps_ExprContext->ecxt_scantuple;
/* get the vertex agtype in the scanTupleSlot */
a = DATUM_GET_AGTYPE_P(scantuple->tts_values[node->tuple_position - 1]);
/* Convert to an agtype value */
v = get_ith_agtype_value_from_container(&a->root, 0);
if (v->type != AGTV_VERTEX)
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("agtype must resolve to a vertex")));
}
/* extract the id agtype field */
id_value = GET_AGTYPE_VALUE_OBJECT_VALUE(v, "id");
/* extract the graphid and cast to a Datum */
id = GRAPHID_GET_DATUM(id_value->val.int_value);
/*
* Its possible the variable has already been deleted. There are two
* ways this can happen. One is the query explicitly deleted the
* variable, the is_deleted flag will catch that. However, it is
* possible the user deleted the vertex using another variable name. We
* need to scan the table to find the vertex's current status relative
* to this CREATE clause. If the variable was initially created in this
* clause, we can skip this check, because the transaction system
* guarantees that nothing can happen to that tuple, as far as we are
* concerned with at this time.
*/
if (!SAFE_TO_SKIP_EXISTENCE_CHECK(node->flags))
{
if (!entity_exists(estate, css->graph_oid, DATUM_GET_GRAPHID(id)))
{
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("vertex assigned to variable %s was deleted",
node->variable_name)));
}
}
if (CYPHER_TARGET_NODE_IN_PATH(node->flags))
{
Datum vertex = scanTupleSlot->tts_values[node->tuple_position - 1];
css->path_values = lappend(css->path_values,
DatumGetPointer(vertex));
}
}
/* If the path continues, create the next edge, passing the vertex's id. */
if (next != NULL)
{
create_edge(css, lfirst(next), id, lnext(list, next), list);
}
return id;
}