/* * 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; }