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