1 /*-------------------------------------------------------------------------
2  *
3  * distributed_planner.h
4  *	  General Citus planner code.
5  *
6  * Copyright (c) Citus Data, Inc.
7  *-------------------------------------------------------------------------
8  */
9 
10 #ifndef DISTRIBUTED_PLANNER_H
11 #define DISTRIBUTED_PLANNER_H
12 
13 #include "postgres.h"
14 
15 #include "distributed/pg_version_constants.h"
16 
17 #include "nodes/plannodes.h"
18 
19 #include "nodes/pathnodes.h"
20 
21 #include "distributed/citus_nodes.h"
22 #include "distributed/errormessage.h"
23 #include "distributed/log_utils.h"
24 
25 
26 /* values used by jobs and tasks which do not require identifiers */
27 #define INVALID_JOB_ID 0
28 #define INVALID_TASK_ID 0
29 
30 #define CURSOR_OPT_FORCE_DISTRIBUTED 0x080000
31 
32 
33 /* level of planner calls */
34 extern int PlannerLevel;
35 
36 
37 typedef struct RelationRestrictionContext
38 {
39 	bool allReferenceTables;
40 	List *relationRestrictionList;
41 } RelationRestrictionContext;
42 
43 
44 typedef struct RootPlanParams
45 {
46 	PlannerInfo *root;
47 
48 	/*
49 	 * Copy of root->plan_params. root->plan_params is not preserved in
50 	 * relation_restriction_equivalence, so we need to create a copy.
51 	 */
52 	List *plan_params;
53 } RootPlanParams;
54 
55 typedef struct RelationRestriction
56 {
57 	Index index;
58 	Oid relationId;
59 	bool distributedRelation;
60 	RangeTblEntry *rte;
61 	RelOptInfo *relOptInfo;
62 	PlannerInfo *plannerInfo;
63 
64 	/* list of RootPlanParams for all outer nodes */
65 	List *outerPlanParamsList;
66 
67 	/* list of translated vars, this is copied from postgres since it gets deleted on postgres*/
68 	List *translatedVars;
69 } RelationRestriction;
70 
71 typedef struct JoinRestrictionContext
72 {
73 	List *joinRestrictionList;
74 	bool hasSemiJoin;
75 } JoinRestrictionContext;
76 
77 typedef struct JoinRestriction
78 {
79 	JoinType joinType;
80 	List *joinRestrictInfoList;
81 	PlannerInfo *plannerInfo;
82 	Relids innerrelRelids;
83 	Relids outerrelRelids;
84 } JoinRestriction;
85 
86 typedef struct FastPathRestrictionContext
87 {
88 	bool fastPathRouterQuery;
89 
90 	/*
91 	 * While calculating fastPathRouterQuery, we could sometimes be
92 	 * able to extract the distribution key value as well (such as when
93 	 * there are no prepared statements). Could be NULL when the distribution
94 	 * key contains parameter, so check for it before using.
95 	 */
96 	Const *distributionKeyValue;
97 
98 	/*
99 	 * Set to true when distKey = Param; in the queryTree
100 	 */
101 	bool distributionKeyHasParam;
102 }FastPathRestrictionContext;
103 
104 typedef struct PlannerRestrictionContext
105 {
106 	RelationRestrictionContext *relationRestrictionContext;
107 	JoinRestrictionContext *joinRestrictionContext;
108 
109 	/*
110 	 * When the query is qualified for fast path, we don't have
111 	 * the RelationRestrictionContext and JoinRestrictionContext
112 	 * since those are dependent to calling standard_planner.
113 	 * Instead, we keep this struct to pass some extra information.
114 	 */
115 	FastPathRestrictionContext *fastPathRestrictionContext;
116 	MemoryContext memoryContext;
117 } PlannerRestrictionContext;
118 
119 typedef struct RelationShard
120 {
121 	CitusNode type;
122 	Oid relationId;
123 	uint64 shardId;
124 } RelationShard;
125 
126 typedef struct RelationRowLock
127 {
128 	CitusNode type;
129 	Oid relationId;
130 	LockClauseStrength rowLockStrength;
131 } RelationRowLock;
132 
133 
134 /*
135  * Parameters to be set according to range table entries of a query.
136  */
137 typedef struct RTEListProperties
138 {
139 	bool hasPostgresLocalTable;
140 
141 	bool hasReferenceTable;
142 	bool hasCitusLocalTable;
143 
144 	/* includes hash, append and range partitioned tables */
145 	bool hasDistributedTable;
146 
147 	/* union of hasReferenceTable, hasCitusLocalTable and hasDistributedTable */
148 	bool hasCitusTable;
149 
150 	bool hasMaterializedView;
151 } RTEListProperties;
152 
153 
154 typedef struct DistributedPlanningContext
155 {
156 	/* The parsed query that is given to the planner. It is a slightly modified
157 	 * to work with the standard_planner */
158 	Query *query;
159 
160 	/* A copy of the original parsed query that is given to the planner. This
161 	 * doesn't contain most of the changes that are made to parse. There's one
162 	 * that change that is made for non fast path router queries though, which
163 	 * is the assigning of RTE identities using AssignRTEIdentities. This is
164 	 * NULL for non distributed plans, since those don't need it. */
165 	Query *originalQuery;
166 
167 	/* the cursor options given to the planner */
168 	int cursorOptions;
169 
170 	/* the ParamListInfo that is given to the planner */
171 	ParamListInfo boundParams;
172 
173 	/* Plan created either by standard_planner or by FastPathPlanner */
174 	PlannedStmt *plan;
175 
176 	/* Our custom restriction context */
177 	PlannerRestrictionContext *plannerRestrictionContext;
178 } DistributedPlanningContext;
179 
180 
181 /*
182  * CitusCustomScanPath is injected into the planner during the combine query planning
183  * phase of the logical planner.
184  *
185  * We call out to the standard planner to plan the combine query part for the output of
186  * the logical planner. This makes it easier to implement new sql features into the
187  * logical planner by not having to manually implement the plan creation for the combine
188  * query on the coordinator..
189  */
190 typedef struct CitusCustomScanPath
191 {
192 	CustomPath custom_path;
193 
194 	/*
195 	 * Custom scan node computed by the citus planner that will produce the tuples for the
196 	 * path we are injecting during the planning of the combine query
197 	 */
198 	CustomScan *remoteScan;
199 } CitusCustomScanPath;
200 
201 
202 #if PG_VERSION_NUM >= PG_VERSION_13
203 extern PlannedStmt * distributed_planner(Query *parse,
204 										 const char *query_string,
205 										 int cursorOptions,
206 										 ParamListInfo boundParams);
207 #else
208 extern PlannedStmt * distributed_planner(Query *parse,
209 										 int cursorOptions,
210 										 ParamListInfo boundParams);
211 #endif
212 
213 
214 /*
215  * Common hint message to workaround using postgres local and citus local tables
216  * in distributed queries
217  */
218 #define LOCAL_TABLE_SUBQUERY_CTE_HINT \
219 	"Use CTE's or subqueries to select from local tables and use them in joins"
220 
221 extern List * ExtractRangeTableEntryList(Query *query);
222 extern bool NeedsDistributedPlanning(Query *query);
223 extern List * TranslatedVarsForRteIdentity(int rteIdentity);
224 extern struct DistributedPlan * GetDistributedPlan(CustomScan *node);
225 extern void multi_relation_restriction_hook(PlannerInfo *root, RelOptInfo *relOptInfo,
226 											Index restrictionIndex, RangeTblEntry *rte);
227 extern void multi_join_restriction_hook(PlannerInfo *root,
228 										RelOptInfo *joinrel,
229 										RelOptInfo *outerrel,
230 										RelOptInfo *innerrel,
231 										JoinType jointype,
232 										JoinPathExtraData *extra);
233 extern bool HasUnresolvedExternParamsWalker(Node *expression, ParamListInfo boundParams);
234 extern bool IsModifyCommand(Query *query);
235 extern void EnsurePartitionTableNotReplicated(Oid relationId);
236 extern Node * ResolveExternalParams(Node *inputNode, ParamListInfo boundParams);
237 extern bool IsMultiTaskPlan(struct DistributedPlan *distributedPlan);
238 extern RangeTblEntry * RemoteScanRangeTableEntry(List *columnNameList);
239 extern int GetRTEIdentity(RangeTblEntry *rte);
240 extern bool GetOriginalInh(RangeTblEntry *rte);
241 extern LOCKMODE GetQueryLockMode(Query *query);
242 extern int32 BlessRecordExpression(Expr *expr);
243 extern void DissuadePlannerFromUsingPlan(PlannedStmt *plan);
244 extern PlannedStmt * FinalizePlan(PlannedStmt *localPlan,
245 								  struct DistributedPlan *distributedPlan);
246 extern RTEListProperties * GetRTEListPropertiesForQuery(Query *query);
247 
248 
249 extern struct DistributedPlan * CreateDistributedPlan(uint64 planId, Query *originalQuery,
250 													  Query *query, ParamListInfo
251 													  boundParams, bool
252 													  hasUnresolvedParams,
253 													  PlannerRestrictionContext *
254 													  plannerRestrictionContext);
255 
256 #endif /* DISTRIBUTED_PLANNER_H */
257