/*
|
* Licensed to the Apache Software Foundation (ASF) under one
|
* or more contributor license agreements. See the NOTICE file
|
* distributed with this work for additional information
|
* regarding copyright ownership. The ASF licenses this file
|
* to you under the Apache License, Version 2.0 (the
|
* "License"); you may not use this file except in compliance
|
* with the License. You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing,
|
* software distributed under the License is distributed on an
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
* KIND, either express or implied. See the License for the
|
* specific language governing permissions and limitations
|
* under the License.
|
*/
|
|
#include "postgres.h"
|
|
#include "nodes/extensible.h"
|
#include "nodes/nodes.h"
|
#include "nodes/pg_list.h"
|
#include "nodes/plannodes.h"
|
|
#include "executor/cypher_executor.h"
|
#include "optimizer/cypher_createplan.h"
|
|
const CustomScanMethods cypher_create_plan_methods = {
|
"Cypher Create", create_cypher_create_plan_state};
|
const CustomScanMethods cypher_set_plan_methods = {
|
"Cypher Set", create_cypher_set_plan_state};
|
const CustomScanMethods cypher_delete_plan_methods = {
|
"Cypher Delete", create_cypher_delete_plan_state};
|
const CustomScanMethods cypher_merge_plan_methods = {
|
"Cypher Merge", create_cypher_merge_plan_state};
|
|
Plan *plan_cypher_create_path(PlannerInfo *root, RelOptInfo *rel,
|
CustomPath *best_path, List *tlist,
|
List *clauses, List *custom_plans)
|
{
|
CustomScan *cs;
|
Plan *subplan = linitial(custom_plans);
|
|
cs = makeNode(CustomScan);
|
|
cs->scan.plan.startup_cost = best_path->path.startup_cost;
|
cs->scan.plan.total_cost = best_path->path.total_cost;
|
|
cs->scan.plan.plan_rows = best_path->path.rows;
|
cs->scan.plan.plan_width = 0;
|
|
cs->scan.plan.parallel_aware = best_path->path.parallel_aware;
|
cs->scan.plan.parallel_safe = best_path->path.parallel_safe;
|
|
cs->scan.plan.plan_node_id = 0; // Set later in set_plan_refs
|
cs->scan.plan.targetlist = tlist;
|
cs->scan.plan.qual = NIL;
|
cs->scan.plan.lefttree = NULL;
|
cs->scan.plan.righttree = NULL;
|
cs->scan.plan.initPlan = NIL;
|
|
cs->scan.plan.extParam = NULL;
|
cs->scan.plan.allParam = NULL;
|
|
cs->scan.scanrelid = 0;
|
|
cs->flags = best_path->flags;
|
|
cs->custom_plans = custom_plans;
|
cs->custom_exprs = NIL;
|
cs->custom_private = best_path->custom_private;
|
cs->custom_scan_tlist = subplan->targetlist;
|
cs->custom_relids = NULL;
|
cs->methods = &cypher_create_plan_methods;
|
|
return (Plan *)cs;
|
}
|
|
Plan *plan_cypher_set_path(PlannerInfo *root, RelOptInfo *rel,
|
CustomPath *best_path, List *tlist,
|
List *clauses, List *custom_plans)
|
{
|
CustomScan *cs;
|
Plan *subplan = linitial(custom_plans);
|
|
cs = makeNode(CustomScan);
|
|
cs->scan.plan.startup_cost = best_path->path.startup_cost;
|
cs->scan.plan.total_cost = best_path->path.total_cost;
|
|
cs->scan.plan.plan_rows = best_path->path.rows;
|
cs->scan.plan.plan_width = 0;
|
|
cs->scan.plan.parallel_aware = best_path->path.parallel_aware;
|
cs->scan.plan.parallel_safe = best_path->path.parallel_safe;
|
|
cs->scan.plan.plan_node_id = 0; // Set later in set_plan_refs
|
cs->scan.plan.targetlist = tlist;
|
cs->scan.plan.qual = NIL;
|
cs->scan.plan.lefttree = NULL;
|
cs->scan.plan.righttree = NULL;
|
cs->scan.plan.initPlan = NIL;
|
|
cs->scan.plan.extParam = NULL;
|
cs->scan.plan.allParam = NULL;
|
|
cs->scan.scanrelid = 0;
|
|
cs->flags = best_path->flags;
|
|
cs->custom_plans = custom_plans;
|
cs->custom_exprs = NIL;
|
cs->custom_private = best_path->custom_private;
|
cs->custom_scan_tlist = subplan->targetlist;
|
|
cs->custom_relids = NULL;
|
cs->methods = &cypher_set_plan_methods;
|
|
return (Plan *)cs;
|
}
|
|
/*
|
* Coverts the Scan node representing the DELETE clause
|
* to the delete Plan node
|
*/
|
Plan *plan_cypher_delete_path(PlannerInfo *root, RelOptInfo *rel,
|
CustomPath *best_path, List *tlist,
|
List *clauses, List *custom_plans)
|
{
|
CustomScan *cs;
|
Plan *subplan = linitial(custom_plans);
|
|
cs = makeNode(CustomScan);
|
|
cs->scan.plan.startup_cost = best_path->path.startup_cost;
|
cs->scan.plan.total_cost = best_path->path.total_cost;
|
|
cs->scan.plan.plan_rows = best_path->path.rows;
|
cs->scan.plan.plan_width = 0;
|
|
cs->scan.plan.parallel_aware = best_path->path.parallel_aware;
|
cs->scan.plan.parallel_safe = best_path->path.parallel_safe;
|
|
cs->scan.plan.plan_node_id = 0; // Set later in set_plan_refs
|
/*
|
* the scan list of the delete node, used for its ScanTupleSlot used
|
* by its parent in the execution phase.
|
*/
|
cs->scan.plan.targetlist = tlist;
|
cs->scan.plan.qual = NIL;
|
cs->scan.plan.lefttree = NULL;
|
cs->scan.plan.righttree = NULL;
|
cs->scan.plan.initPlan = NIL;
|
|
cs->scan.plan.extParam = NULL;
|
cs->scan.plan.allParam = NULL;
|
|
/*
|
* We do not want Postgres to assume we are scanning a table, postgres'
|
* optimizer will make assumptions about our targetlist that are false
|
*/
|
cs->scan.scanrelid = 0;
|
|
cs->flags = best_path->flags;
|
|
// child plan nodes are here, Postgres processed them for us.
|
cs->custom_plans = custom_plans;
|
cs->custom_exprs = NIL;
|
// transfer delete metadata needed by the DELETE clause.
|
cs->custom_private = best_path->custom_private;
|
/*
|
* the scan list of the delete node's children, used for ScanTupleSlot
|
* in execution.
|
*/
|
cs->custom_scan_tlist = subplan->targetlist;
|
|
cs->custom_relids = NULL;
|
cs->methods = &cypher_delete_plan_methods;
|
|
return (Plan *)cs;
|
}
|
|
/*
|
* Coverts the Scan node representing the MERGE clause
|
* to the merge Plan node
|
*/
|
Plan *plan_cypher_merge_path(PlannerInfo *root, RelOptInfo *rel,
|
CustomPath *best_path, List *tlist,
|
List *clauses, List *custom_plans)
|
{
|
CustomScan *cs;
|
Plan *subplan = linitial(custom_plans);
|
|
cs = makeNode(CustomScan);
|
|
cs->scan.plan.startup_cost = best_path->path.startup_cost;
|
cs->scan.plan.total_cost = best_path->path.total_cost;
|
|
cs->scan.plan.plan_rows = best_path->path.rows;
|
cs->scan.plan.plan_width = 0;
|
|
cs->scan.plan.parallel_aware = best_path->path.parallel_aware;
|
cs->scan.plan.parallel_safe = best_path->path.parallel_safe;
|
|
cs->scan.plan.plan_node_id = 0; // Set later in set_plan_refs
|
/*
|
* the scan list of the merge node, used for its ScanTupleSlot used
|
* by its parent in the execution phase.
|
*/
|
cs->scan.plan.targetlist = tlist;
|
cs->scan.plan.qual = NIL;
|
cs->scan.plan.lefttree = NULL;
|
cs->scan.plan.righttree = NULL;
|
cs->scan.plan.initPlan = NIL;
|
|
cs->scan.plan.extParam = NULL;
|
cs->scan.plan.allParam = NULL;
|
|
/*
|
* We do not want Postgres to assume we are scanning a table, postgres'
|
* optimizer will make assumptions about our targetlist that are false
|
*/
|
cs->scan.scanrelid = 0;
|
|
cs->flags = best_path->flags;
|
|
// child plan nodes are here, Postgres processed them for us.
|
cs->custom_plans = custom_plans;
|
cs->custom_exprs = NIL;
|
// transfer delete metadata needed by the MERGE clause.
|
cs->custom_private = best_path->custom_private;
|
/*
|
* the scan list of the merge node's children, used for ScanTupleSlot
|
* in execution.
|
*/
|
cs->custom_scan_tlist = subplan->targetlist;
|
|
cs->custom_relids = NULL;
|
cs->methods = &cypher_merge_plan_methods;
|
|
return (Plan *)cs;
|
}
|