1 /*
2 * This file and its contents are licensed under the Apache License 2.0.
3 * Please see the included NOTICE for copyright information and
4 * LICENSE-APACHE for a copy of the license.
5 */
6 #include <postgres.h>
7 #include <nodes/nodes.h>
8 #include <nodes/extensible.h>
9 #include <nodes/makefuncs.h>
10 #include <nodes/nodeFuncs.h>
11 #include <nodes/readfuncs.h>
12 #include <parser/parsetree.h>
13 #include <utils/rel.h>
14 #include <catalog/pg_type.h>
15 #include <rewrite/rewriteManip.h>
16
17 #include "chunk_dispatch_plan.h"
18 #include "chunk_dispatch_state.h"
19 #include "hypertable.h"
20
21 #include "compat/compat.h"
22
23 /*
24 * Create a ChunkDispatchState node from this plan. This is the full execution
25 * state that replaces the plan node as the plan moves from planning to
26 * execution.
27 */
28 static Node *
create_chunk_dispatch_state(CustomScan * cscan)29 create_chunk_dispatch_state(CustomScan *cscan)
30 {
31 return (Node *) ts_chunk_dispatch_state_create(linitial_oid(cscan->custom_private),
32 linitial(cscan->custom_plans));
33 }
34
35 static CustomScanMethods chunk_dispatch_plan_methods = {
36 .CustomName = "ChunkDispatch",
37 .CreateCustomScanState = create_chunk_dispatch_state,
38 };
39
40 /* Create a chunk dispatch plan node in the form of a CustomScan node. The
41 * purpose of this plan node is to dispatch (route) tuples to the correct chunk
42 * in a hypertable.
43 *
44 * Note that CustomScan nodes cannot be extended (by struct embedding) because
45 * they might be copied, therefore we pass hypertable_relid in the
46 * custom_private field.
47 *
48 * The chunk dispatch plan takes the original tuple-producing subplan, which
49 * was part of a ModifyTable node, and imposes itself between the
50 * ModifyTable plan and the subplan. During execution, the subplan will
51 * produce the new tuples that the chunk dispatch node routes before passing
52 * them up to the ModifyTable node.
53 */
54 static Plan *
chunk_dispatch_plan_create(PlannerInfo * root,RelOptInfo * relopt,CustomPath * best_path,List * tlist,List * clauses,List * custom_plans)55 chunk_dispatch_plan_create(PlannerInfo *root, RelOptInfo *relopt, CustomPath *best_path,
56 List *tlist, List *clauses, List *custom_plans)
57 {
58 ChunkDispatchPath *cdpath = (ChunkDispatchPath *) best_path;
59 CustomScan *cscan = makeNode(CustomScan);
60 ListCell *lc;
61
62 foreach (lc, custom_plans)
63 {
64 Plan *subplan = lfirst(lc);
65
66 cscan->scan.plan.startup_cost += subplan->startup_cost;
67 cscan->scan.plan.total_cost += subplan->total_cost;
68 cscan->scan.plan.plan_rows += subplan->plan_rows;
69 cscan->scan.plan.plan_width += subplan->plan_width;
70 }
71
72 cscan->custom_private = list_make1_oid(cdpath->hypertable_relid);
73 cscan->methods = &chunk_dispatch_plan_methods;
74 cscan->custom_plans = custom_plans;
75 cscan->scan.scanrelid = 0; /* Indicate this is not a real relation we are
76 * scanning */
77 /* The "input" and "output" target lists should be the same */
78 cscan->custom_scan_tlist = tlist;
79 cscan->scan.plan.targetlist = tlist;
80
81 return &cscan->scan.plan;
82 }
83
84 static CustomPathMethods chunk_dispatch_path_methods = {
85 .CustomName = "ChunkDispatchPath",
86 .PlanCustomPath = chunk_dispatch_plan_create,
87 };
88
89 Path *
ts_chunk_dispatch_path_create(PlannerInfo * root,ModifyTablePath * mtpath,Index hypertable_rti,int subpath_index)90 ts_chunk_dispatch_path_create(PlannerInfo *root, ModifyTablePath *mtpath, Index hypertable_rti,
91 int subpath_index)
92 {
93 ChunkDispatchPath *path = (ChunkDispatchPath *) palloc0(sizeof(ChunkDispatchPath));
94 #if PG14_LT
95 Path *subpath = list_nth(mtpath->subpaths, subpath_index);
96 #else
97 Path *subpath = mtpath->subpath;
98 #endif
99 RangeTblEntry *rte = planner_rt_fetch(hypertable_rti, root);
100
101 memcpy(&path->cpath.path, subpath, sizeof(Path));
102 path->cpath.path.type = T_CustomPath;
103 path->cpath.path.pathtype = T_CustomScan;
104 path->cpath.methods = &chunk_dispatch_path_methods;
105 path->cpath.custom_paths = list_make1(subpath);
106 path->mtpath = mtpath;
107 path->hypertable_rti = hypertable_rti;
108 path->hypertable_relid = rte->relid;
109
110 return &path->cpath.path;
111 }
112