Skip to content

Commit 7338257

Browse files
committed
Start Reimplementing MERGE Clause
1 parent de43f3e commit 7338257

File tree

8 files changed

+1039
-32
lines changed

8 files changed

+1039
-32
lines changed

Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ OBJS = src/backend/postgraph.o \
2626
src/backend/commands/graph_commands.o \
2727
src/backend/commands/label_commands.o \
2828
src/backend/executor/cypher_create.o \
29+
src/backend/executor/cypher_merge.o \
2930
src/backend/nodes/ag_nodes.o \
3031
src/backend/nodes/cypher_copyfuncs.o \
3132
src/backend/nodes/cypher_outfuncs.o \
@@ -68,7 +69,8 @@ EXTENSION = postgraph
6869
DATA = postgraph--0.1.0.sql
6970

7071
REGRESS = new_cypher \
71-
cypher_create
72+
cypher_create \
73+
cypher_merge
7274

7375
srcdir=`pwd`
7476
POSTGIS_DIR ?= postgis_dir

src/backend/optimizer/cypher_createplan.c

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929

3030
const CustomScanMethods cypher_create_plan_methods = {
3131
"Cypher Create", create_cypher_create_plan_state};
32-
32+
const CustomScanMethods cypher_merge_plan_methods = {
33+
"Cypher Merge", create_cypher_merge_plan_state};
3334

3435
Plan *plan_cypher_create_path(PlannerInfo *root, RelOptInfo *rel,
3536
CustomPath *best_path, List *tlist,
@@ -72,3 +73,64 @@ Plan *plan_cypher_create_path(PlannerInfo *root, RelOptInfo *rel,
7273

7374
return (Plan *)cs;
7475
}
76+
77+
/*
78+
* Coverts the Scan node representing the delete clause
79+
* to the merge Plan node
80+
*/
81+
Plan *plan_cypher_merge_path(PlannerInfo *root, RelOptInfo *rel,
82+
CustomPath *best_path, List *tlist,
83+
List *clauses, List *custom_plans)
84+
{
85+
CustomScan *cs;
86+
Plan *subplan = linitial(custom_plans);
87+
88+
cs = makeNode(CustomScan);
89+
90+
cs->scan.plan.startup_cost = best_path->path.startup_cost;
91+
cs->scan.plan.total_cost = best_path->path.total_cost;
92+
93+
cs->scan.plan.plan_rows = best_path->path.rows;
94+
cs->scan.plan.plan_width = 0;
95+
96+
cs->scan.plan.parallel_aware = best_path->path.parallel_aware;
97+
cs->scan.plan.parallel_safe = best_path->path.parallel_safe;
98+
99+
cs->scan.plan.plan_node_id = 0; // Set later in set_plan_refs
100+
/*
101+
* the scan list of the delete node, used for its ScanTupleSlot used
102+
* by its parent in the execution phase.
103+
*/
104+
cs->scan.plan.targetlist = tlist;
105+
cs->scan.plan.qual = NIL;
106+
cs->scan.plan.lefttree = NULL;
107+
cs->scan.plan.righttree = NULL;
108+
cs->scan.plan.initPlan = NIL;
109+
110+
cs->scan.plan.extParam = NULL;
111+
cs->scan.plan.allParam = NULL;
112+
113+
/*
114+
* We do not want Postgres to assume we are scanning a table, postgres'
115+
* optimizer will make assumptions about our targetlist that are false
116+
*/
117+
cs->scan.scanrelid = 0;
118+
119+
cs->flags = best_path->flags;
120+
121+
// child plan nodes are here, Postgres processed them for us.
122+
cs->custom_plans = custom_plans;
123+
cs->custom_exprs = NIL;
124+
// transfer delete metadata needed by the delete clause.
125+
cs->custom_private = best_path->custom_private;
126+
/*
127+
* the scan list of the merge node's children, used for ScanTupleSlot
128+
* in execution.
129+
*/
130+
cs->custom_scan_tlist = subplan->targetlist;
131+
132+
cs->custom_relids = NULL;
133+
cs->methods = &cypher_merge_plan_methods;
134+
135+
return (Plan *)cs;
136+
}

src/backend/optimizer/cypher_pathnode.c

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828

2929
const CustomPathMethods cypher_create_path_methods = {
3030
CREATE_PATH_NAME, plan_cypher_create_path, NULL};
31-
31+
const CustomPathMethods cypher_merge_path_methods = {
32+
MERGE_PATH_NAME, plan_cypher_merge_path, NULL};
3233

3334
CustomPath *create_cypher_create_path(PlannerInfo *root, RelOptInfo *rel,
3435
List *custom_private)
@@ -65,3 +66,46 @@ CustomPath *create_cypher_create_path(PlannerInfo *root, RelOptInfo *rel,
6566

6667
return cp;
6768
}
69+
70+
/*
71+
* Creates a Delete Path. Makes the original path a child of the new
72+
* path. We leave it to the caller to replace the pathlist of the rel.
73+
*/
74+
CustomPath *create_cypher_merge_path(PlannerInfo *root, RelOptInfo *rel,
75+
List *custom_private)
76+
{
77+
CustomPath *cp;
78+
79+
cp = makeNode(CustomPath);
80+
81+
cp->path.pathtype = T_CustomScan;
82+
83+
cp->path.parent = rel;
84+
cp->path.pathtarget = rel->reltarget;
85+
86+
cp->path.param_info = NULL;
87+
88+
// Do not allow parallel methods
89+
cp->path.parallel_aware = false;
90+
cp->path.parallel_safe = false;
91+
cp->path.parallel_workers = 0;
92+
93+
cp->path.rows = 0;
94+
cp->path.startup_cost = 0;
95+
cp->path.total_cost = 0;
96+
97+
// No output ordering for basic SET
98+
cp->path.pathkeys = NULL;
99+
100+
// Disable all custom flags for now
101+
cp->flags = 0;
102+
103+
// Make the original paths the children of the new path
104+
cp->custom_paths = rel->pathlist;
105+
// Store the metadata Delete will need in the execution phase.
106+
cp->custom_private = custom_private;
107+
// Tells Postgres how to turn this path to the correct CustomScan
108+
cp->methods = &cypher_merge_path_methods;
109+
110+
return cp;
111+
}

src/backend/optimizer/cypher_paths.c

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ static void set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti,
4444
static cypher_clause_kind get_cypher_clause_kind(RangeTblEntry *rte);
4545
static void handle_cypher_create_clause(PlannerInfo *root, RelOptInfo *rel,
4646
Index rti, RangeTblEntry *rte);
47-
47+
static void handle_cypher_merge_clause(PlannerInfo *root, RelOptInfo *rel,
48+
Index rti, RangeTblEntry *rte);
4849
void set_rel_pathlist_init(void)
4950
{
5051
prev_set_rel_pathlist_hook = set_rel_pathlist_hook;
@@ -59,6 +60,7 @@ void set_rel_pathlist_fini(void)
5960
static void set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti,
6061
RangeTblEntry *rte)
6162
{
63+
6264
if (prev_set_rel_pathlist_hook)
6365
prev_set_rel_pathlist_hook(root, rel, rti, rte);
6466

@@ -67,6 +69,9 @@ static void set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti,
6769
case CYPHER_CLAUSE_CREATE:
6870
handle_cypher_create_clause(root, rel, rti, rte);
6971
break;
72+
case CYPHER_CLAUSE_MERGE:
73+
handle_cypher_merge_clause(root, rel, rti, rte);
74+
break;
7075
case CYPHER_CLAUSE_NONE:
7176
break;
7277
default:
@@ -103,6 +108,8 @@ static cypher_clause_kind get_cypher_clause_kind(RangeTblEntry *rte)
103108

104109
if (is_oid_ag_func(fe->funcid, CREATE_CLAUSE_FUNCTION_NAME))
105110
return CYPHER_CLAUSE_CREATE;
111+
else if (is_oid_ag_func(fe->funcid, MERGE_CLAUSE_FUNCTION_NAME))
112+
return CYPHER_CLAUSE_MERGE;
106113
else
107114
return CYPHER_CLAUSE_NONE;
108115
}
@@ -130,3 +137,27 @@ static void handle_cypher_create_clause(PlannerInfo *root, RelOptInfo *rel,
130137
// Add the new path to the rel.
131138
add_path(rel, (Path *)cp);
132139
}
140+
141+
// replace all possible paths with our CustomPath
142+
static void handle_cypher_merge_clause(PlannerInfo *root, RelOptInfo *rel,
143+
Index rti, RangeTblEntry *rte)
144+
{
145+
TargetEntry *te;
146+
FuncExpr *fe;
147+
List *custom_private;
148+
CustomPath *cp;
149+
150+
// Add the pattern to the CustomPath
151+
te = (TargetEntry *)llast(rte->subquery->targetList);
152+
fe = (FuncExpr *)te->expr;
153+
// pass the const that holds the data structure to the path.
154+
custom_private = fe->args;
155+
156+
cp = create_cypher_merge_path(root, rel, custom_private);
157+
158+
// Discard any pre-existing paths
159+
rel->pathlist = NIL;
160+
rel->partial_pathlist = NIL;
161+
162+
add_path(rel, (Path *)cp);
163+
}

0 commit comments

Comments
 (0)