@@ -166,13 +166,10 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
166
166
rel -> cheapest_total_path = NULL ;
167
167
rel -> cheapest_unique_path = NULL ;
168
168
rel -> cheapest_parameterized_paths = NIL ;
169
- rel -> direct_lateral_relids = NULL ;
170
- rel -> lateral_relids = NULL ;
171
169
rel -> relid = relid ;
172
170
rel -> rtekind = rte -> rtekind ;
173
171
/* min_attr, max_attr, attr_needed, attr_widths are set below */
174
172
rel -> lateral_vars = NIL ;
175
- rel -> lateral_referencers = NULL ;
176
173
rel -> indexlist = NIL ;
177
174
rel -> statlist = NIL ;
178
175
rel -> pages = 0 ;
@@ -205,20 +202,44 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
205
202
rel -> partitioned_child_rels = NIL ;
206
203
207
204
/*
208
- * Pass top parent's relids down the inheritance hierarchy. If the parent
209
- * has top_parent_relids set, it's a direct or an indirect child of the
210
- * top parent indicated by top_parent_relids. By extension this child is
211
- * also an indirect child of that parent.
205
+ * Pass assorted information down the inheritance hierarchy.
212
206
*/
213
207
if (parent )
214
208
{
209
+ /*
210
+ * Each direct or indirect child wants to know the relids of its
211
+ * topmost parent.
212
+ */
215
213
if (parent -> top_parent_relids )
216
214
rel -> top_parent_relids = parent -> top_parent_relids ;
217
215
else
218
216
rel -> top_parent_relids = bms_copy (parent -> relids );
217
+
218
+ /*
219
+ * Also propagate lateral-reference information from appendrel parent
220
+ * rels to their child rels. We intentionally give each child rel the
221
+ * same minimum parameterization, even though it's quite possible that
222
+ * some don't reference all the lateral rels. This is because any
223
+ * append path for the parent will have to have the same
224
+ * parameterization for every child anyway, and there's no value in
225
+ * forcing extra reparameterize_path() calls. Similarly, a lateral
226
+ * reference to the parent prevents use of otherwise-movable join rels
227
+ * for each child.
228
+ *
229
+ * It's possible for child rels to have their own children, in which
230
+ * case the topmost parent's lateral info propagates all the way down.
231
+ */
232
+ rel -> direct_lateral_relids = parent -> direct_lateral_relids ;
233
+ rel -> lateral_relids = parent -> lateral_relids ;
234
+ rel -> lateral_referencers = parent -> lateral_referencers ;
219
235
}
220
236
else
237
+ {
221
238
rel -> top_parent_relids = NULL ;
239
+ rel -> direct_lateral_relids = NULL ;
240
+ rel -> lateral_relids = NULL ;
241
+ rel -> lateral_referencers = NULL ;
242
+ }
222
243
223
244
/* Check type of rtable entry */
224
245
switch (rte -> rtekind )
@@ -273,53 +294,80 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
273
294
root -> qual_security_level = Max (root -> qual_security_level ,
274
295
list_length (rte -> securityQuals ));
275
296
297
+ return rel ;
298
+ }
299
+
300
+ /*
301
+ * add_appendrel_other_rels
302
+ * Add "other rel" RelOptInfos for the children of an appendrel baserel
303
+ *
304
+ * "rel" is a relation that (still) has the rte->inh flag set, meaning it
305
+ * has appendrel children listed in root->append_rel_list. We need to build
306
+ * a RelOptInfo for each child relation so that we can plan scans on them.
307
+ * (The parent relation might be a partitioned table, a table with
308
+ * traditional inheritance children, or a flattened UNION ALL subquery.)
309
+ */
310
+ void
311
+ add_appendrel_other_rels (PlannerInfo * root , RelOptInfo * rel , Index rti )
312
+ {
313
+ int cnt_parts = 0 ;
314
+ ListCell * l ;
315
+
276
316
/*
277
- * If this rel is an appendrel parent, recurse to build "other rel"
278
- * RelOptInfos for its children. They are "other rels" because they are
279
- * not in the main join tree, but we will need RelOptInfos to plan access
280
- * to them.
317
+ * If rel is a partitioned table, then we also need to build a part_rels
318
+ * array so that the child RelOptInfos can be conveniently accessed from
319
+ * the parent.
281
320
*/
282
- if (rte -> inh )
321
+ if (rel -> part_scheme != NULL )
283
322
{
284
- ListCell * l ;
285
- int nparts = rel -> nparts ;
286
- int cnt_parts = 0 ;
287
-
288
- if (nparts > 0 )
289
- rel -> part_rels = (RelOptInfo * * )
290
- palloc (sizeof (RelOptInfo * ) * nparts );
323
+ Assert (rel -> nparts > 0 );
324
+ rel -> part_rels = (RelOptInfo * * )
325
+ palloc0 (sizeof (RelOptInfo * ) * rel -> nparts );
326
+ }
291
327
292
- foreach (l , root -> append_rel_list )
293
- {
294
- AppendRelInfo * appinfo = (AppendRelInfo * ) lfirst (l );
295
- RelOptInfo * childrel ;
328
+ foreach (l , root -> append_rel_list )
329
+ {
330
+ AppendRelInfo * appinfo = (AppendRelInfo * ) lfirst (l );
331
+ Index childRTindex = appinfo -> child_relid ;
332
+ RangeTblEntry * childrte ;
333
+ RelOptInfo * childrel ;
296
334
297
- /* append_rel_list contains all append rels; ignore others */
298
- if (appinfo -> parent_relid != relid )
299
- continue ;
335
+ /* append_rel_list contains all append rels; ignore others */
336
+ if (appinfo -> parent_relid != rti )
337
+ continue ;
300
338
301
- childrel = build_simple_rel (root , appinfo -> child_relid ,
302
- rel );
339
+ /* find the child RTE, which should already exist */
340
+ Assert (childRTindex < root -> simple_rel_array_size );
341
+ childrte = root -> simple_rte_array [childRTindex ];
342
+ Assert (childrte != NULL );
303
343
304
- /* Nothing more to do for an unpartitioned table. */
305
- if (!rel -> part_scheme )
306
- continue ;
344
+ /* build child RelOptInfo, and add to main query data structures */
345
+ childrel = build_simple_rel (root , childRTindex , rel );
307
346
308
- /*
309
- * The order of partition OIDs in append_rel_list is the same as
310
- * the order in the PartitionDesc, so the order of part_rels will
311
- * also match the PartitionDesc. See expand_partitioned_rtentry.
312
- */
313
- Assert (cnt_parts < nparts );
314
- rel -> part_rels [cnt_parts ] = childrel ;
315
- cnt_parts ++ ;
347
+ /*
348
+ * If rel is a partitioned table, fill in the part_rels array. The
349
+ * order in which child tables appear in append_rel_list is the same
350
+ * as the order in which they appear in the parent's PartitionDesc, so
351
+ * assigning partitions like this works.
352
+ */
353
+ if (rel -> part_scheme != NULL )
354
+ {
355
+ Assert (cnt_parts < rel -> nparts );
356
+ rel -> part_rels [cnt_parts ++ ] = childrel ;
316
357
}
317
358
318
- /* We should have seen all the child partitions. */
319
- Assert (cnt_parts == nparts );
359
+ /* Child may itself be an inherited relation. */
360
+ if (childrte -> inh )
361
+ {
362
+ /* Only relation and subquery RTEs can have children. */
363
+ Assert (childrte -> rtekind == RTE_RELATION ||
364
+ childrte -> rtekind == RTE_SUBQUERY );
365
+ add_appendrel_other_rels (root , childrel , childRTindex );
366
+ }
320
367
}
321
368
322
- return rel ;
369
+ /* We should have filled all of the part_rels array if it's partitioned */
370
+ Assert (cnt_parts == rel -> nparts );
323
371
}
324
372
325
373
/*
0 commit comments