+ double parent_rows;
+ double parent_size;
+ double *parent_attrsizes;
+ int nattrs;
+ ListCell *l;
+
+ /*
+ * Initialize to compute size estimates for whole append relation.
+ *
+ * We handle width estimates by weighting the widths of different child
+ * rels proportionally to their number of rows. This is sensible because
+ * the use of width estimates is mainly to compute the total relation
+ * "footprint" if we have to sort or hash it. To do this, we sum the
+ * total equivalent size (in "double" arithmetic) and then divide by the
+ * total rowcount estimate. This is done separately for the total rel
+ * width and each attribute.
+ *
+ * Note: if you consider changing this logic, beware that child rels could
+ * have zero rows and/or width, if they were excluded by constraints.
+ */
+ parent_rows = 0;
+ parent_size = 0;
+ nattrs = rel->max_attr - rel->min_attr + 1;
+ parent_attrsizes = (double *) palloc0(nattrs * sizeof(double));
+
+ foreach(l, root->append_rel_list)
+ {
+ AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
+ int childRTindex;
+ RangeTblEntry *childRTE;
+ RelOptInfo *childrel;
+ List *childquals;
+ Node *childqual;
+ ListCell *parentvars;
+ ListCell *childvars;
+
+ /* append_rel_list contains all append rels; ignore others */
+ if (appinfo->parent_relid != parentRTindex)
+ continue;
+
+ childRTindex = appinfo->child_relid;
+ childRTE = root->simple_rte_array[childRTindex];
+
+ /*
+ * The child rel's RelOptInfo was already created during
+ * add_base_rels_to_query.
+ */
+ childrel = find_base_rel(root, childRTindex);
+ Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL);
+
+ /*
+ * We have to copy the parent's targetlist and quals to the child,
+ * with appropriate substitution of variables. However, only the
+ * baserestrictinfo quals are needed before we can check for
+ * constraint exclusion; so do that first and then check to see if we
+ * can disregard this child.
+ *
+ * As of 8.4, the child rel's targetlist might contain non-Var
+ * expressions, which means that substitution into the quals could
+ * produce opportunities for const-simplification, and perhaps even
+ * pseudoconstant quals. To deal with this, we strip the RestrictInfo
+ * nodes, do the substitution, do const-simplification, and then
+ * reconstitute the RestrictInfo layer.
+ */
+ childquals = get_all_actual_clauses(rel->baserestrictinfo);
+ childquals = (List *) adjust_appendrel_attrs(root,
+ (Node *) childquals,
+ appinfo);
+ childqual = eval_const_expressions(root, (Node *)
+ make_ands_explicit(childquals));
+ if (childqual && IsA(childqual, Const) &&
+ (((Const *) childqual)->constisnull ||
+ !DatumGetBool(((Const *) childqual)->constvalue)))
+ {
+ /*
+ * Restriction reduces to constant FALSE or constant NULL after
+ * substitution, so this child need not be scanned.
+ */
+ set_dummy_rel_pathlist(childrel);
+ continue;
+ }
+ childquals = make_ands_implicit((Expr *) childqual);
+ childquals = make_restrictinfos_from_actual_clauses(root,
+ childquals);
+ childrel->baserestrictinfo = childquals;
+
+ if (relation_excluded_by_constraints(root, childrel, childRTE))
+ {
+ /*
+ * This child need not be scanned, so we can omit it from the
+ * appendrel.
+ */
+ set_dummy_rel_pathlist(childrel);
+ continue;
+ }
+
+ /*
+ * CE failed, so finish copying/modifying targetlist and join quals.
+ *
+ * Note: the resulting childrel->reltargetlist may contain arbitrary
+ * expressions, which otherwise would not occur in a reltargetlist.
+ * Code that might be looking at an appendrel child must cope with
+ * such. Note in particular that "arbitrary expression" can include
+ * "Var belonging to another relation", due to LATERAL references.
+ */
+ childrel->joininfo = (List *)
+ adjust_appendrel_attrs(root,
+ (Node *) rel->joininfo,
+ appinfo);
+ childrel->reltargetlist = (List *)
+ adjust_appendrel_attrs(root,
+ (Node *) rel->reltargetlist,
+ appinfo);
+
+ /*
+ * We have to make child entries in the EquivalenceClass data
+ * structures as well. This is needed either if the parent
+ * participates in some eclass joins (because we will want to consider
+ * inner-indexscan joins on the individual children) or if the parent
+ * has useful pathkeys (because we should try to build MergeAppend
+ * paths that produce those sort orderings).
+ */
+ if (rel->has_eclass_joins || has_useful_pathkeys(root, rel))
+ add_child_rel_equivalences(root, appinfo, rel, childrel);
+ childrel->has_eclass_joins = rel->has_eclass_joins;
+
+ /*
+ * Note: we could compute appropriate attr_needed data for the child's
+ * variables, by transforming the parent's attr_needed through the
+ * translated_vars mapping. However, currently there's no need
+ * because attr_needed is only examined for base relations not
+ * otherrels. So we just leave the child's attr_needed empty.
+ */
+
+ /*
+ * Compute the child's size.
+ */
+ set_rel_size(root, childrel, childRTindex, childRTE);
+
+ /*
+ * It is possible that constraint exclusion detected a contradiction
+ * within a child subquery, even though we didn't prove one above. If
+ * so, we can skip this child.
+ */
+ if (IS_DUMMY_REL(childrel))
+ continue;
+
+ /*
+ * Accumulate size information from each live child.
+ */
+ if (childrel->rows > 0)
+ {
+ parent_rows += childrel->rows;
+ parent_size += childrel->width * childrel->rows;
+
+ /*
+ * Accumulate per-column estimates too. We need not do anything
+ * for PlaceHolderVars in the parent list. If child expression
+ * isn't a Var, or we didn't record a width estimate for it, we
+ * have to fall back on a datatype-based estimate.
+ *
+ * By construction, child's reltargetlist is 1-to-1 with parent's.
+ */
+ forboth(parentvars, rel->reltargetlist,
+ childvars, childrel->reltargetlist)
+ {
+ Var *parentvar = (Var *) lfirst(parentvars);
+ Node *childvar = (Node *) lfirst(childvars);
+
+ if (IsA(parentvar, Var))
+ {
+ int pndx = parentvar->varattno - rel->min_attr;
+ int32 child_width = 0;
+
+ if (IsA(childvar, Var) &&
+ ((Var *) childvar)->varno == childrel->relid)
+ {
+ int cndx = ((Var *) childvar)->varattno - childrel->min_attr;
+
+ child_width = childrel->attr_widths[cndx];
+ }
+ if (child_width <= 0)
+ child_width = get_typavgwidth(exprType(childvar),
+ exprTypmod(childvar));
+ Assert(child_width > 0);
+ parent_attrsizes[pndx] += child_width * childrel->rows;
+ }
+ }
+ }
+ }