Skip to content

Commit 3e8affd

Browse files
committed
Update
1 parent fb2d95f commit 3e8affd

8 files changed

Lines changed: 171 additions & 87 deletions

File tree

postgraph--0.1.0.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ CREATE FUNCTION build_edge(graphid, graphid, graphid, oid, gtype)
347347
RETURNS edge
348348
LANGUAGE c
349349
STABLE
350-
RETURNS NULL ON NULL INPUT
350+
CALLED ON NULL INPUT
351351
PARALLEL SAFE
352352
AS 'MODULE_PATHNAME';
353353

regress/sql/cypher_create.sql

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,23 @@ MATCH ()-[]->() RETURN 1;
6161

6262
MATCH ()<-[]-() RETURN 1;
6363

64+
MATCH ()<-[q]-() RETURN 1;
65+
66+
67+
MATCH ()<-[q]-() RETURN q;
68+
69+
MATCH (e)<-[q]-() RETURN q, e;
70+
71+
/*
72+
MATCH (a)-[]->() RETURN a;
73+
74+
MATCH (a)<-[]-() RETURN a;
75+
76+
77+
MATCH ()-[]->(a) RETURN a;
78+
79+
MATCH ()<-[]-(a) RETURN a;
80+
*/
6481
SELECT * FROM cypher_create._ag_label_vertex;
6582

6683
SELECT * FROM cypher_create._adj__adj__ag_label_vertex;

src/backend/executor/cypher_create.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,9 @@ static TupleTableSlot *exec_cypher_create(CustomScanState *csnode)
323323
ExecClearTuple(elemTupleSlot);
324324

325325
// get the next graphid for this vertex.
326-
elemTupleSlot->tts_values[0] = css->edge_ids[0][i-1];
326+
elemTupleSlot->tts_values[0] = css->edge_ids[0][i];
327327
elemTupleSlot->tts_isnull[0] = false;
328-
328+
329329
elemTupleSlot->tts_values[1] = css->vertex_ids[0][i];
330330
elemTupleSlot->tts_isnull[1] = false;
331331

src/backend/parser/cypher_clause.c

Lines changed: 93 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ static char *make_endid_alias(char *var_name);
8888

8989
static Node *make_vertex_expr(cypher_parsestate *cpstate, ParseNamespaceItem *pnsi);
9090
static Node *make_edge_expr(cypher_parsestate *cpstate, ParseNamespaceItem *pnsi);
91+
static Node *make_vertex_expr_with_edge(cypher_parsestate *cpstate, ParseNamespaceItem *pnsi, ParseNamespaceItem *edge_pnsi);
9192

9293
List *
9394
transform_window_definitions(ParseState *pstate, List *windowdefs, List **targetlist);
@@ -253,16 +254,39 @@ static Node *make_vertex_expr(cypher_parsestate *cpstate, ParseNamespaceItem *pn
253254
}
254255

255256

257+
static Node *make_vertex_expr_with_edge(cypher_parsestate *cpstate, ParseNamespaceItem *pnsi, ParseNamespaceItem *edge_pnsi) {
258+
ParseState *pstate = (ParseState *)cpstate;
259+
260+
Oid func_oid = get_ag_func_oid("build_vertex", 3, GRAPHIDOID, OIDOID, GTYPEOID);
261+
262+
Node *id = scanNSItemForColumn(pstate, edge_pnsi, 0, "endid", -1);
263+
264+
Const *graph_oid_const = makeConst(OIDOID, -1, InvalidOid, sizeof(Oid),
265+
ObjectIdGetDatum(cpstate->graph_oid), false, true);
266+
267+
Node * props = scanNSItemForColumn(pstate, pnsi, 0, AG_VERTEX_COLNAME_PROPERTIES, -1);
268+
269+
List *args = list_make3(id, graph_oid_const, props);
270+
271+
FuncExpr *func_expr = makeFuncExpr(func_oid, VERTEXOID, args, InvalidOid, InvalidOid, COERCE_EXPLICIT_CALL);
272+
func_expr->location = -1;
273+
274+
275+
return (Node *)func_expr;
276+
}
277+
278+
279+
256280
static Node *make_edge_expr(cypher_parsestate *cpstate, ParseNamespaceItem *pnsi) {
257281
ParseState *pstate = (ParseState *)cpstate;
258282

259283
Oid func_oid = get_ag_func_oid("build_edge", 5, GRAPHIDOID, GRAPHIDOID, GRAPHIDOID, OIDOID, GTYPEOID);
260284

261285
Node *id = scanNSItemForColumn(pstate, pnsi, 0, AG_EDGE_COLNAME_ID, -1);
262286

263-
Node *start_id = scanNSItemForColumn(pstate, pnsi, 0, AG_EDGE_COLNAME_START_ID, -1);
287+
Node *start_id = scanNSItemForColumn(pstate, pnsi, 0, "startid", -1);
264288

265-
Node *end_id = scanNSItemForColumn(pstate, pnsi, 0, AG_EDGE_COLNAME_END_ID, -1);
289+
Node *end_id = scanNSItemForColumn(pstate, pnsi, 0, "endid", -1);
266290

267291
Const *graph_oid_const = makeConst(OIDOID, -1, InvalidOid, sizeof(Oid),
268292
ObjectIdGetDatum(cpstate->graph_oid), false, true);
@@ -1067,34 +1091,6 @@ static Node *transform_srf_function(cypher_parsestate *cpstate, Node *n, RangeTb
10671091
}
10681092

10691093

1070-
static Node *transform_VLE_Function(cypher_parsestate *cpstate, Node *n, RangeTblEntry **top_rte, int *top_rti, List **namespace) {
1071-
ParseState *pstate = &cpstate->pstate;
1072-
1073-
Assert(IsA(n, RangeFunction));
1074-
1075-
if (IsA(n, RangeFunction)) {
1076-
RangeTblRef *rtr;
1077-
RangeTblEntry *rte;
1078-
ParseNamespaceItem *nsitem;
1079-
int rtindex;
1080-
1081-
nsitem = transformRangeFunction(cpstate, (RangeFunction *) n);
1082-
rte = nsitem->p_rte;
1083-
rtindex = list_length(pstate->p_rtable);
1084-
Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
1085-
*top_rte = rte;
1086-
*top_rti = rtindex;
1087-
*namespace = list_make1(nsitem);
1088-
rtr = makeNode(RangeTblRef);
1089-
rtr->rtindex = rtindex;
1090-
return (Node *) rtr;
1091-
}
1092-
1093-
return NULL;
1094-
}
1095-
1096-
1097-
10981094

10991095
// setNamespaceLateralState - subroutine to update LATERAL flags in a namespace list.
11001096
static void setNamespaceLateralState(List *namespace, bool lateral_only, bool lateral_ok) {
@@ -1163,9 +1159,9 @@ add_vertex_to_query(cypher_parsestate *cpstate, Query *query, cypher_node *node)
11631159
{
11641160
ParseState *pstate = (ParseState *)cpstate;
11651161

1166-
bool has_variable = false;
1162+
node->has_variable = false;
11671163
if (node->name)
1168-
has_variable = true;
1164+
node->has_variable = true;
11691165
else
11701166
node->name = get_next_default_alias(cpstate);
11711167

@@ -1196,9 +1192,9 @@ add_vertex_retrieval_to_query(cypher_parsestate *cpstate, Query *query, cypher_n
11961192
{
11971193
ParseState *pstate = (ParseState *)cpstate;
11981194

1199-
bool has_variable = false;
1195+
node->has_variable = false;
12001196
if (node->name)
1201-
has_variable = true;
1197+
node->has_variable = true;
12021198
else {
12031199
node->in_join_tree = false;
12041200
return NULL;
@@ -1236,10 +1232,9 @@ add_edge_to_query(cypher_parsestate *cpstate, Query *query, cypher_relationship
12361232
{
12371233
ParseState *pstate = (ParseState *)cpstate;
12381234

1235+
edge->has_variable = false;
12391236
if (edge->name)
1240-
ereport(ERROR,
1241-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1242-
errmsg("MATCH variable names are not supported")));
1237+
edge->has_variable = true;
12431238
else
12441239
edge->name = get_next_default_alias(cpstate);
12451240

@@ -1266,7 +1261,8 @@ static void add_all_fields_to_target_list(cypher_parsestate *cpstate, Query *que
12661261
ParseState *pstate = (ParseState *)cpstate;
12671262

12681263
// left vertex id field
1269-
query->targetList = lappend(query->targetList,
1264+
if (left_vertex->in_join_tree) {
1265+
query->targetList = lappend(query->targetList,
12701266
makeTargetEntry(
12711267
edge->dir == CYPHER_REL_DIR_RIGHT ?
12721268
scanNSItemForColumn(pstate, left_vertex->pnsi, 0, AG_VERTEX_COLNAME_ID, -1) :
@@ -1275,22 +1271,24 @@ static void add_all_fields_to_target_list(cypher_parsestate *cpstate, Query *que
12751271
make_id_alias(left_vertex->name),
12761272
false));
12771273

1278-
// Vertex expression
1279-
if (left_vertex->has_variable) {
12801274
query->targetList = lappend(query->targetList,
12811275
makeTargetEntry(
12821276
scanNSItemForColumn(pstate, left_vertex->pnsi, 0, AG_VERTEX_COLNAME_PROPERTIES, -1),
12831277
pstate->p_next_resno++,
12841278
make_property_alias(left_vertex->name),
12851279
false));
1286-
/*
1287-
query->targetList = lappend(query->targetList,
1288-
makeTargetEntry(
1289-
(Expr *)make_vertex_expr(cpstate, left_vertex->pnsi),
1290-
pstate->p_next_resno++,
1291-
left_vertex->name,
1292-
false));
1293-
*/
1280+
1281+
// Vertex expression
1282+
if (left_vertex->has_variable)
1283+
query->targetList = lappend(query->targetList,
1284+
makeTargetEntry(
1285+
edge->dir == CYPHER_REL_DIR_LEFT ?
1286+
(Expr *)make_vertex_expr_with_edge(cpstate, left_vertex->pnsi, edge->pnsi) :
1287+
(Expr *)make_vertex_expr(cpstate, left_vertex->pnsi),
1288+
pstate->p_next_resno++,
1289+
left_vertex->name,
1290+
false));
1291+
12941292
}
12951293

12961294
// id field
@@ -1326,24 +1324,44 @@ static void add_all_fields_to_target_list(cypher_parsestate *cpstate, Query *que
13261324
false));
13271325

13281326
// id field
1329-
query->targetList = lappend(query->targetList,
1327+
if (edge->has_variable)
1328+
query->targetList = lappend(query->targetList,
1329+
makeTargetEntry(
1330+
(Expr *)make_edge_expr(cpstate, edge->pnsi),
1331+
pstate->p_next_resno++,
1332+
edge->name,
1333+
false));
1334+
1335+
// properties field
1336+
if (right_vertex->in_join_tree){
1337+
query->targetList = lappend(query->targetList,
13301338
makeTargetEntry(
13311339
edge->dir == CYPHER_REL_DIR_RIGHT ?
13321340
scanNSItemForColumn(pstate, edge->pnsi, 0, AG_EDGE_COLNAME_END_ID, -1) :
13331341
scanNSItemForColumn(pstate, right_vertex->pnsi, 0, AG_VERTEX_COLNAME_ID, -1),
13341342
pstate->p_next_resno++,
1335-
make_id_alias(left_vertex->name),
1343+
make_id_alias(right_vertex->name),
13361344
false));
13371345

1338-
// properties field
1339-
if (right_vertex->in_join_tree)
13401346
query->targetList = lappend(query->targetList,
13411347
makeTargetEntry(
13421348
scanNSItemForColumn(pstate, right_vertex->pnsi, 0, AG_VERTEX_COLNAME_PROPERTIES, -1),
13431349
pstate->p_next_resno++,
13441350
make_property_alias(right_vertex->name),
13451351
false));
13461352

1353+
// Vertex expression
1354+
if (right_vertex->has_variable)
1355+
query->targetList = lappend(query->targetList,
1356+
makeTargetEntry(
1357+
edge->dir == CYPHER_REL_DIR_RIGHT ?
1358+
(Expr *)make_vertex_expr_with_edge(cpstate, right_vertex->pnsi, edge->pnsi) :
1359+
(Expr *)make_vertex_expr(cpstate, right_vertex->pnsi),
1360+
pstate->p_next_resno++,
1361+
right_vertex->name,
1362+
false));
1363+
}
1364+
13471365
}
13481366

13491367
static void transform_match_pattern(cypher_parsestate *cpstate, Query *query, List *pattern, Node *where) {
@@ -1414,6 +1432,29 @@ static void transform_match_pattern(cypher_parsestate *cpstate, Query *query, Li
14141432

14151433
node->pnsi = add_vertex_retrieval_to_query(cpstate, query, node, edge->pnsi);
14161434

1435+
// SELECT fields
1436+
add_all_fields_to_target_list(cpstate,
1437+
query,
1438+
(cypher_node *)linitial(path->path),
1439+
(cypher_relationship *)lsecond(path->path),
1440+
(cypher_node *)lthird(path->path));
1441+
} else if( ((cypher_relationship *)lsecond(path->path))->dir == CYPHER_REL_DIR_LEFT) {
1442+
ListCell *path_cell;
1443+
1444+
// left vertex FROM item
1445+
cypher_node *node = lthird(path->path);
1446+
node->pnsi = add_vertex_to_query(cpstate, query, node);
1447+
1448+
1449+
// edge FROM item
1450+
cypher_relationship *edge = lsecond(path->path);
1451+
edge->pnsi = add_edge_to_query(cpstate, query, edge, node->pnsi);
1452+
1453+
// right vertex FROM item
1454+
node = linitial(path->path);
1455+
1456+
node->pnsi = add_vertex_retrieval_to_query(cpstate, query, node, edge->pnsi);
1457+
14171458
// SELECT fields
14181459
add_all_fields_to_target_list(cpstate,
14191460
query,

src/backend/utils/adt/edge.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,14 @@ build_edge(PG_FUNCTION_ARGS) {
133133
graphid end_id = AG_GETARG_GRAPHID(2);
134134
Oid graph_oid = PG_GETARG_OID(3);
135135
//char *label = PG_GETARG_CSTRING(3);
136-
gtype *properties = AG_GET_ARG_GTYPE_P(4);
137136

138-
if (!AGT_ROOT_IS_OBJECT(properties))
139-
PG_RETURN_NULL();
140-
137+
gtype *properties = NULL;
138+
if (!PG_ARGISNULL(4)) {
139+
properties = AG_GET_ARG_GTYPE_P(4);
140+
141+
if (!AGT_ROOT_IS_OBJECT(properties))
142+
PG_RETURN_NULL();
143+
}
141144
AG_RETURN_EDGE(create_edge(id, start_id, end_id, graph_oid, properties));
142145
}
143146

@@ -162,6 +165,17 @@ create_edge(graphid id,graphid start_id,graphid end_id, Oid graph_oid, gtype *pr
162165
append_to_buffer(&buffer, (char *)&graph_oid, sizeof(Oid));
163166

164167
// properties
168+
// properties
169+
if (properties == NULL) {
170+
gtype_in_state result;
171+
172+
memset(&result, 0, sizeof(gtype_in_state));
173+
174+
push_gtype_value(&result.parse_state, WGT_BEGIN_OBJECT, NULL);
175+
result.res = push_gtype_value(&result.parse_state, WGT_END_OBJECT, NULL);
176+
177+
properties = gtype_value_to_gtype(result.res);
178+
}
165179
append_to_buffer(&buffer, properties, VARSIZE(properties));
166180

167181
edge *v = (edge *)buffer.data;

0 commit comments

Comments
 (0)