2121#include "nodes/nodeFuncs.h"
2222#include "optimizer/pathnode.h"
2323#include "optimizer/planmain.h"
24+ #include "optimizer/planner.h"
2425#include "optimizer/tlist.h"
2526#include "tcop/utility.h"
2627#include "utils/lsyscache.h"
@@ -81,6 +82,10 @@ typedef struct
8182#define fix_scan_list (root , lst , rtoffset ) \
8283 ((List *) fix_scan_expr(root, (Node *) (lst), rtoffset))
8384
85+ static void add_rtes_to_flat_rtable (PlannerInfo * root , bool recursing );
86+ static void flatten_unplanned_rtes (PlannerGlobal * glob , RangeTblEntry * rte );
87+ static bool flatten_rtes_walker (Node * node , PlannerGlobal * glob );
88+ static void add_rte_to_flat_rtable (PlannerGlobal * glob , RangeTblEntry * rte );
8489static Plan * set_plan_refs (PlannerInfo * root , Plan * plan , int rtoffset );
8590static Plan * set_indexonlyscan_references (PlannerInfo * root ,
8691 IndexOnlyScan * plan ,
@@ -196,63 +201,11 @@ set_plan_references(PlannerInfo *root, Plan *plan)
196201 ListCell * lc ;
197202
198203 /*
199- * In the flat rangetable, we zero out substructure pointers that are not
200- * needed by the executor; this reduces the storage space and copying cost
201- * for cached plans. We keep only the alias and eref Alias fields, which
202- * are needed by EXPLAIN, and the selectedCols and modifiedCols bitmaps,
203- * which are needed for executor-startup permissions checking and for
204- * trigger event checking.
204+ * Add all the query's RTEs to the flattened rangetable. The live ones
205+ * will have their rangetable indexes increased by rtoffset. (Additional
206+ * RTEs, not referenced by the Plan tree, might get added after those.)
205207 */
206- foreach (lc , root -> parse -> rtable )
207- {
208- RangeTblEntry * rte = (RangeTblEntry * ) lfirst (lc );
209- RangeTblEntry * newrte ;
210-
211- /* flat copy to duplicate all the scalar fields */
212- newrte = (RangeTblEntry * ) palloc (sizeof (RangeTblEntry ));
213- memcpy (newrte , rte , sizeof (RangeTblEntry ));
214-
215- /* zap unneeded sub-structure */
216- newrte -> subquery = NULL ;
217- newrte -> joinaliasvars = NIL ;
218- newrte -> funcexpr = NULL ;
219- newrte -> funccoltypes = NIL ;
220- newrte -> funccoltypmods = NIL ;
221- newrte -> funccolcollations = NIL ;
222- newrte -> values_lists = NIL ;
223- newrte -> values_collations = NIL ;
224- newrte -> ctecoltypes = NIL ;
225- newrte -> ctecoltypmods = NIL ;
226- newrte -> ctecolcollations = NIL ;
227-
228- glob -> finalrtable = lappend (glob -> finalrtable , newrte );
229-
230- /*
231- * If it's a plain relation RTE, add the table to relationOids.
232- *
233- * We do this even though the RTE might be unreferenced in the plan
234- * tree; this would correspond to cases such as views that were
235- * expanded, child tables that were eliminated by constraint
236- * exclusion, etc. Schema invalidation on such a rel must still force
237- * rebuilding of the plan.
238- *
239- * Note we don't bother to avoid duplicate list entries. We could,
240- * but it would probably cost more cycles than it would save.
241- */
242- if (newrte -> rtekind == RTE_RELATION )
243- glob -> relationOids = lappend_oid (glob -> relationOids ,
244- newrte -> relid );
245- }
246-
247- /*
248- * Check for RT index overflow; it's very unlikely, but if it did happen,
249- * the executor would get confused by varnos that match the special varno
250- * values.
251- */
252- if (IS_SPECIAL_VARNO (list_length (glob -> finalrtable )))
253- ereport (ERROR ,
254- (errcode (ERRCODE_PROGRAM_LIMIT_EXCEEDED ),
255- errmsg ("too many range table entries" )));
208+ add_rtes_to_flat_rtable (root , false);
256209
257210 /*
258211 * Adjust RT indexes of PlanRowMarks and add to final rowmarks list
@@ -279,6 +232,192 @@ set_plan_references(PlannerInfo *root, Plan *plan)
279232 return set_plan_refs (root , plan , rtoffset );
280233}
281234
235+ /*
236+ * Extract RangeTblEntries from the plan's rangetable, and add to flat rtable
237+ *
238+ * This can recurse into subquery plans; "recursing" is true if so.
239+ */
240+ static void
241+ add_rtes_to_flat_rtable (PlannerInfo * root , bool recursing )
242+ {
243+ PlannerGlobal * glob = root -> glob ;
244+ Index rti ;
245+ ListCell * lc ;
246+
247+ /*
248+ * Add the query's own RTEs to the flattened rangetable.
249+ *
250+ * At top level, we must add all RTEs so that their indexes in the
251+ * flattened rangetable match up with their original indexes. When
252+ * recursing, we only care about extracting relation RTEs.
253+ */
254+ foreach (lc , root -> parse -> rtable )
255+ {
256+ RangeTblEntry * rte = (RangeTblEntry * ) lfirst (lc );
257+
258+ if (!recursing || rte -> rtekind == RTE_RELATION )
259+ add_rte_to_flat_rtable (glob , rte );
260+ }
261+
262+ /*
263+ * If there are any dead subqueries, they are not referenced in the Plan
264+ * tree, so we must add RTEs contained in them to the flattened rtable
265+ * separately. (If we failed to do this, the executor would not perform
266+ * expected permission checks for tables mentioned in such subqueries.)
267+ *
268+ * Note: this pass over the rangetable can't be combined with the previous
269+ * one, because that would mess up the numbering of the live RTEs in the
270+ * flattened rangetable.
271+ */
272+ rti = 1 ;
273+ foreach (lc , root -> parse -> rtable )
274+ {
275+ RangeTblEntry * rte = (RangeTblEntry * ) lfirst (lc );
276+
277+ /*
278+ * We should ignore inheritance-parent RTEs: their contents have been
279+ * pulled up into our rangetable already. Also ignore any subquery
280+ * RTEs without matching RelOptInfos, as they likewise have been
281+ * pulled up.
282+ */
283+ if (rte -> rtekind == RTE_SUBQUERY && !rte -> inh )
284+ {
285+ RelOptInfo * rel = root -> simple_rel_array [rti ];
286+
287+ if (rel != NULL )
288+ {
289+ Assert (rel -> relid == rti ); /* sanity check on array */
290+
291+ /*
292+ * The subquery might never have been planned at all, if it
293+ * was excluded on the basis of self-contradictory constraints
294+ * in our query level. In this case apply
295+ * flatten_unplanned_rtes.
296+ *
297+ * If it was planned but the plan is dummy, we assume that it
298+ * has been omitted from our plan tree (see
299+ * set_subquery_pathlist), and recurse to pull up its RTEs.
300+ *
301+ * Otherwise, it should be represented by a SubqueryScan node
302+ * somewhere in our plan tree, and we'll pull up its RTEs when
303+ * we process that plan node.
304+ *
305+ * However, if we're recursing, then we should pull up RTEs
306+ * whether the subplan is dummy or not, because we've found
307+ * that some upper query level is treating this one as dummy,
308+ * and so we won't scan this level's plan tree at all.
309+ */
310+ if (rel -> subplan == NULL )
311+ flatten_unplanned_rtes (glob , rte );
312+ else if (recursing || is_dummy_plan (rel -> subplan ))
313+ {
314+ Assert (rel -> subroot != NULL );
315+ add_rtes_to_flat_rtable (rel -> subroot , true);
316+ }
317+ }
318+ }
319+ rti ++ ;
320+ }
321+ }
322+
323+ /*
324+ * Extract RangeTblEntries from a subquery that was never planned at all
325+ */
326+ static void
327+ flatten_unplanned_rtes (PlannerGlobal * glob , RangeTblEntry * rte )
328+ {
329+ /* Use query_tree_walker to find all RTEs in the parse tree */
330+ (void ) query_tree_walker (rte -> subquery ,
331+ flatten_rtes_walker ,
332+ (void * ) glob ,
333+ QTW_EXAMINE_RTES );
334+ }
335+
336+ static bool
337+ flatten_rtes_walker (Node * node , PlannerGlobal * glob )
338+ {
339+ if (node == NULL )
340+ return false;
341+ if (IsA (node , RangeTblEntry ))
342+ {
343+ RangeTblEntry * rte = (RangeTblEntry * ) node ;
344+
345+ /* As above, we need only save relation RTEs */
346+ if (rte -> rtekind == RTE_RELATION )
347+ add_rte_to_flat_rtable (glob , rte );
348+ return false;
349+ }
350+ if (IsA (node , Query ))
351+ {
352+ /* Recurse into subselects */
353+ return query_tree_walker ((Query * ) node ,
354+ flatten_rtes_walker ,
355+ (void * ) glob ,
356+ QTW_EXAMINE_RTES );
357+ }
358+ return expression_tree_walker (node , flatten_rtes_walker ,
359+ (void * ) glob );
360+ }
361+
362+ /*
363+ * Add (a copy of) the given RTE to the final rangetable
364+ *
365+ * In the flat rangetable, we zero out substructure pointers that are not
366+ * needed by the executor; this reduces the storage space and copying cost
367+ * for cached plans. We keep only the alias and eref Alias fields, which
368+ * are needed by EXPLAIN, and the selectedCols and modifiedCols bitmaps,
369+ * which are needed for executor-startup permissions checking and for
370+ * trigger event checking.
371+ */
372+ static void
373+ add_rte_to_flat_rtable (PlannerGlobal * glob , RangeTblEntry * rte )
374+ {
375+ RangeTblEntry * newrte ;
376+
377+ /* flat copy to duplicate all the scalar fields */
378+ newrte = (RangeTblEntry * ) palloc (sizeof (RangeTblEntry ));
379+ memcpy (newrte , rte , sizeof (RangeTblEntry ));
380+
381+ /* zap unneeded sub-structure */
382+ newrte -> subquery = NULL ;
383+ newrte -> joinaliasvars = NIL ;
384+ newrte -> funcexpr = NULL ;
385+ newrte -> funccoltypes = NIL ;
386+ newrte -> funccoltypmods = NIL ;
387+ newrte -> funccolcollations = NIL ;
388+ newrte -> values_lists = NIL ;
389+ newrte -> values_collations = NIL ;
390+ newrte -> ctecoltypes = NIL ;
391+ newrte -> ctecoltypmods = NIL ;
392+ newrte -> ctecolcollations = NIL ;
393+
394+ glob -> finalrtable = lappend (glob -> finalrtable , newrte );
395+
396+ /*
397+ * Check for RT index overflow; it's very unlikely, but if it did happen,
398+ * the executor would get confused by varnos that match the special varno
399+ * values.
400+ */
401+ if (IS_SPECIAL_VARNO (list_length (glob -> finalrtable )))
402+ ereport (ERROR ,
403+ (errcode (ERRCODE_PROGRAM_LIMIT_EXCEEDED ),
404+ errmsg ("too many range table entries" )));
405+
406+ /*
407+ * If it's a plain relation RTE, add the table to relationOids.
408+ *
409+ * We do this even though the RTE might be unreferenced in the plan tree;
410+ * this would correspond to cases such as views that were expanded, child
411+ * tables that were eliminated by constraint exclusion, etc. Schema
412+ * invalidation on such a rel must still force rebuilding of the plan.
413+ *
414+ * Note we don't bother to avoid making duplicate list entries. We could,
415+ * but it would probably cost more cycles than it would save.
416+ */
417+ if (newrte -> rtekind == RTE_RELATION )
418+ glob -> relationOids = lappend_oid (glob -> relationOids , newrte -> relid );
419+ }
420+
282421/*
283422 * set_plan_refs: recurse through the Plan nodes of a single subquery level
284423 */
0 commit comments