4
4
* definitions of rel_pathlist and join_pathlist hooks
5
5
*
6
6
* Copyright (c) 2016, Postgres Professional
7
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
8
+ * Portions Copyright (c) 1994, Regents of the University of California
7
9
*
8
10
* ------------------------------------------------------------------------
9
11
*/
38
40
((path)->param_info && bms_overlap(PATH_REQ_OUTER(path), (rel)->relids))
39
41
40
42
43
+ static inline bool
44
+ allow_star_schema_join (PlannerInfo * root ,
45
+ Path * outer_path ,
46
+ Path * inner_path )
47
+ {
48
+ Relids innerparams = PATH_REQ_OUTER (inner_path );
49
+ Relids outerrelids = outer_path -> parent -> relids ;
50
+
51
+ /*
52
+ * It's a star-schema case if the outer rel provides some but not all of
53
+ * the inner rel's parameterization.
54
+ */
55
+ return (bms_overlap (innerparams , outerrelids ) &&
56
+ bms_nonempty_difference (innerparams , outerrelids ));
57
+ }
58
+
59
+
41
60
set_join_pathlist_hook_type set_join_pathlist_next = NULL ;
42
61
set_rel_pathlist_hook_type set_rel_pathlist_hook_next = NULL ;
43
62
planner_hook_type planner_hook_next = NULL ;
@@ -59,8 +78,7 @@ pathman_join_pathlist_hook(PlannerInfo *root,
59
78
JoinType saved_jointype = jointype ;
60
79
RangeTblEntry * inner_rte = root -> simple_rte_array [innerrel -> relid ];
61
80
const PartRelationInfo * inner_prel ;
62
- List * pathkeys = NIL ,
63
- * joinclauses ,
81
+ List * joinclauses ,
64
82
* otherclauses ;
65
83
ListCell * lc ;
66
84
WalkerContext context ;
@@ -124,7 +142,8 @@ pathman_join_pathlist_hook(PlannerInfo *root,
124
142
* inner ;
125
143
NestPath * nest_path ; /* NestLoop we're creating */
126
144
ParamPathInfo * ppi ; /* parameterization info */
127
- Relids inner_required ; /* required paremeterization relids */
145
+ Relids required_nestloop ,
146
+ required_inner ;
128
147
List * filtered_joinclauses = NIL ,
129
148
* saved_ppi_list ;
130
149
ListCell * rinfo_lc ;
@@ -151,16 +170,17 @@ pathman_join_pathlist_hook(PlannerInfo *root,
151
170
if (saved_jointype == JOIN_UNIQUE_INNER )
152
171
return ;
153
172
154
- /* Make innerrel path depend on outerrel's column */
155
- inner_required = bms_union (PATH_REQ_OUTER ((Path * ) cur_inner_path ),
156
- bms_make_singleton (outerrel -> relid ));
173
+
174
+ /* Make inner path depend on outerrel's columns */
175
+ required_inner = bms_union (PATH_REQ_OUTER ((Path * ) cur_inner_path ),
176
+ outerrel -> relids );
157
177
158
178
/* Preserve existing ppis built by get_appendrel_parampathinfo() */
159
179
saved_ppi_list = innerrel -> ppilist ;
160
180
161
181
/* Get the ParamPathInfo for a parameterized path */
162
182
innerrel -> ppilist = NIL ;
163
- ppi = get_baserel_parampathinfo (root , innerrel , inner_required );
183
+ ppi = get_baserel_parampathinfo (root , innerrel , required_inner );
164
184
innerrel -> ppilist = saved_ppi_list ;
165
185
166
186
/* Skip ppi->ppi_clauses don't reference partition attribute */
@@ -173,17 +193,34 @@ pathman_join_pathlist_hook(PlannerInfo *root,
173
193
if (!inner )
174
194
return ; /* could not build it, retreat! */
175
195
196
+
197
+ required_nestloop = calc_nestloop_required_outer (outer , inner );
198
+
199
+ /*
200
+ * Check to see if proposed path is still parameterized, and reject if the
201
+ * parameterization wouldn't be sensible --- unless allow_star_schema_join
202
+ * says to allow it anyway. Also, we must reject if have_dangerous_phv
203
+ * doesn't like the look of it, which could only happen if the nestloop is
204
+ * still parameterized.
205
+ */
206
+ if (required_nestloop &&
207
+ ((!bms_overlap (required_nestloop , extra -> param_source_rels ) &&
208
+ !allow_star_schema_join (root , outer , inner )) ||
209
+ have_dangerous_phv (root , outer -> parent -> relids , required_inner )))
210
+ return ;
211
+
212
+
176
213
initial_cost_nestloop (root , & workspace , jointype ,
177
214
outer , inner , /* built paths */
178
215
extra -> sjinfo , & extra -> semifactors );
179
216
180
- pathkeys = build_join_pathkeys (root , joinrel , jointype , outer -> pathkeys );
181
-
182
217
nest_path = create_nestloop_path (root , joinrel , jointype , & workspace ,
183
218
extra -> sjinfo , & extra -> semifactors ,
184
219
outer , inner , extra -> restrictlist ,
185
- pathkeys ,
186
- calc_nestloop_required_outer (outer , inner ));
220
+ build_join_pathkeys (root , joinrel ,
221
+ jointype ,
222
+ outer -> pathkeys ),
223
+ required_nestloop );
187
224
188
225
/* Discard all clauses that are to be evaluated by 'inner' */
189
226
foreach (rinfo_lc , extra -> restrictlist )
@@ -196,16 +233,15 @@ pathman_join_pathlist_hook(PlannerInfo *root,
196
233
}
197
234
198
235
/*
199
- * Override 'rows' value produced by standard estimator.
236
+ * NOTE: Override 'rows' value produced by standard estimator.
200
237
* Currently we use get_parameterized_joinrel_size() since
201
238
* it works just fine, but this might change some day.
202
239
*/
203
- nest_path -> path .rows = get_parameterized_joinrel_size_compat (root ,
204
- joinrel ,
205
- outer ,
206
- inner ,
207
- extra -> sjinfo ,
208
- filtered_joinclauses );
240
+ nest_path -> path .rows =
241
+ get_parameterized_joinrel_size_compat (root , joinrel ,
242
+ outer , inner ,
243
+ extra -> sjinfo ,
244
+ filtered_joinclauses );
209
245
210
246
/* Finally we can add the new NestLoop path */
211
247
add_path (joinrel , (Path * ) nest_path );
0 commit comments