{
Query *parse = root->parse;
int parentRTindex = parse->resultRelation;
- Bitmapset *resultRTindexes = NULL;
+ Bitmapset *resultRTindexes;
+ Bitmapset *subqueryRTindexes;
+ Bitmapset *modifiableARIindexes;
int nominalRelation = -1;
List *final_rtable = NIL;
int save_rel_array_size = 0;
List *returningLists = NIL;
List *rowMarks;
ListCell *lc;
+ Index rti;
Assert(parse->commandType != CMD_INSERT);
* subqueries during planning, and so we must create copies of them too,
* except where they are target relations, which will each only be used in
* a single plan.
+ *
+ * To begin with, we'll need a bitmapset of the target relation relids.
*/
- resultRTindexes = bms_add_member(resultRTindexes, parentRTindex);
+ resultRTindexes = bms_make_singleton(parentRTindex);
foreach(lc, root->append_rel_list)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
appinfo->child_relid);
}
+ /*
+ * Now, generate a bitmapset of the relids of the subquery RTEs, including
+ * security-barrier RTEs that will become subqueries, as just explained.
+ */
+ subqueryRTindexes = NULL;
+ rti = 1;
+ foreach(lc, parse->rtable)
+ {
+ RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
+
+ if (rte->rtekind == RTE_SUBQUERY ||
+ (rte->securityQuals != NIL &&
+ !bms_is_member(rti, resultRTindexes)))
+ subqueryRTindexes = bms_add_member(subqueryRTindexes, rti);
+ rti++;
+ }
+
+ /*
+ * Next, we want to identify which AppendRelInfo items contain references
+ * to any of the aforesaid subquery RTEs. These items will need to be
+ * copied and modified to adjust their subquery references; whereas the
+ * other ones need not be touched. It's worth being tense over this
+ * because we can usually avoid processing most of the AppendRelInfo
+ * items, thereby saving O(N^2) space and time when the target is a large
+ * inheritance tree. We can identify AppendRelInfo items by their
+ * child_relid, since that should be unique within the list.
+ */
+ modifiableARIindexes = NULL;
+ if (subqueryRTindexes != NULL)
+ {
+ foreach(lc, root->append_rel_list)
+ {
+ AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
+
+ if (bms_is_member(appinfo->parent_relid, subqueryRTindexes) ||
+ bms_is_member(appinfo->child_relid, subqueryRTindexes) ||
+ bms_overlap(pull_varnos((Node *) appinfo->translated_vars),
+ subqueryRTindexes))
+ modifiableARIindexes = bms_add_member(modifiableARIindexes,
+ appinfo->child_relid);
+ }
+ }
+
+ /*
+ * And now we can get on with generating a plan for each child table.
+ */
foreach(lc, root->append_rel_list)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
PlannerInfo subroot;
Plan *subplan;
- Index rti;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
/*
* The append_rel_list likewise might contain references to subquery
* RTEs (if any subqueries were flattenable UNION ALLs). So prepare
- * to apply ChangeVarNodes to that, too.
+ * to apply ChangeVarNodes to that, too. As explained above, we only
+ * want to copy items that actually contain such references; the rest
+ * can just get linked into the subroot's append_rel_list.
+ *
+ * If we know there are no such references, we can just use the outer
+ * append_rel_list unmodified.
*/
- subroot.append_rel_list = (List *) copyObject(root->append_rel_list);
+ if (modifiableARIindexes != NULL)
+ {
+ ListCell *lc2;
+
+ subroot.append_rel_list = NIL;
+ foreach(lc2, root->append_rel_list)
+ {
+ AppendRelInfo *appinfo2 = (AppendRelInfo *) lfirst(lc2);
+
+ if (bms_is_member(appinfo2->child_relid, modifiableARIindexes))
+ appinfo2 = (AppendRelInfo *) copyObject(appinfo2);
+
+ subroot.append_rel_list = lappend(subroot.append_rel_list,
+ appinfo2);
+ }
+ }
/*
* Add placeholders to the child Query's rangetable list to fill the
/*
* If this isn't the first child Query, generate duplicates of all
- * subquery RTEs, and adjust Var numbering to reference the
- * duplicates. To simplify the loop logic, we scan the original rtable
- * not the copy just made by adjust_appendrel_attrs; that should be OK
- * since subquery RTEs couldn't contain any references to the target
- * rel.
+ * subquery (or subquery-to-be) RTEs, and adjust Var numbering to
+ * reference the duplicates. To simplify the loop logic, we scan the
+ * original rtable not the copy just made by adjust_appendrel_attrs;
+ * that should be OK since subquery RTEs couldn't contain any
+ * references to the target rel.
*/
- if (final_rtable != NIL)
+ if (final_rtable != NIL && subqueryRTindexes != NULL)
{
ListCell *lr;
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lr);
- /*
- * Copy subquery RTEs and RTEs with security barrier quals
- * that will be turned into subqueries, except those that are
- * target relations.
- */
- if (rte->rtekind == RTE_SUBQUERY ||
- (rte->securityQuals != NIL &&
- !bms_is_member(rti, resultRTindexes)))
+ if (bms_is_member(rti, subqueryRTindexes))
{
Index newrti;
newrti = list_length(subroot.parse->rtable) + 1;
ChangeVarNodes((Node *) subroot.parse, rti, newrti, 0);
ChangeVarNodes((Node *) subroot.rowMarks, rti, newrti, 0);
- ChangeVarNodes((Node *) subroot.append_rel_list, rti, newrti, 0);
+ /* Skip processing unchanging parts of append_rel_list */
+ if (modifiableARIindexes != NULL)
+ {
+ ListCell *lc2;
+
+ foreach(lc2, subroot.append_rel_list)
+ {
+ AppendRelInfo *appinfo2 = (AppendRelInfo *) lfirst(lc2);
+
+ if (bms_is_member(appinfo2->child_relid,
+ modifiableARIindexes))
+ ChangeVarNodes((Node *) appinfo2, rti, newrti, 0);
+ }
+ }
rte = copyObject(rte);
ChangeVarNodes((Node *) rte->securityQuals, rti, newrti, 0);
subroot.parse->rtable = lappend(subroot.parse->rtable,