*
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.170 2008/04/01 00:48:33 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.171 2008/06/27 03:56:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
+#include <math.h>
+
 #ifdef OPTIMIZER_DEBUG
 #include "nodes/print.h"
 #endif
 {
    int         parentRTindex = rti;
    List       *subpaths = NIL;
+   double      parent_rows;
+   double      parent_size;
+   double     *parent_attrsizes;
+   int         nattrs;
    ListCell   *l;
 
    /*
                 errmsg("SELECT FOR UPDATE/SHARE is not supported for inheritance queries")));
 
    /*
-    * Initialize to compute size estimates for whole append relation
+    * 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.
     */
-   rel->rows = 0;
-   rel->width = 0;
+   parent_rows = 0;
+   parent_size = 0;
+   nattrs = rel->max_attr - rel->min_attr + 1;
+   parent_attrsizes = (double *) palloc0(nattrs * sizeof(double));
 
    /*
     * Generate access paths for each member relation, and pick the cheapest
            subpaths = lappend(subpaths, childpath);
 
        /*
-        * Propagate size information from the child back to the parent. For
-        * simplicity, we use the largest widths from any child as the parent
-        * estimates.  (If you want to change this, beware of child
-        * attr_widths[] entries that haven't been set and are still 0.)
+        * Accumulate size information from each child.
         */
-       rel->rows += childrel->rows;
-       if (childrel->width > rel->width)
-           rel->width = childrel->width;
-
-       forboth(parentvars, rel->reltargetlist,
-               childvars, childrel->reltargetlist)
+       if (childrel->rows > 0)
        {
-           Var        *parentvar = (Var *) lfirst(parentvars);
-           Var        *childvar = (Var *) lfirst(childvars);
+           parent_rows += childrel->rows;
+           parent_size += childrel->width * childrel->rows;
 
-           if (IsA(parentvar, Var) &&
-               IsA(childvar, Var))
+           forboth(parentvars, rel->reltargetlist,
+                   childvars, childrel->reltargetlist)
            {
-               int         pndx = parentvar->varattno - rel->min_attr;
-               int         cndx = childvar->varattno - childrel->min_attr;
+               Var        *parentvar = (Var *) lfirst(parentvars);
+               Var        *childvar = (Var *) lfirst(childvars);
 
-               if (childrel->attr_widths[cndx] > rel->attr_widths[pndx])
-                   rel->attr_widths[pndx] = childrel->attr_widths[cndx];
+               if (IsA(parentvar, Var) &&
+                   IsA(childvar, Var))
+               {
+                   int         pndx = parentvar->varattno - rel->min_attr;
+                   int         cndx = childvar->varattno - childrel->min_attr;
+
+                   parent_attrsizes[pndx] += childrel->attr_widths[cndx] * childrel->rows;
+               }
            }
        }
    }
 
+   /*
+    * Save the finished size estimates.
+    */
+   rel->rows = parent_rows;
+   if (parent_rows > 0)
+   {
+       int     i;
+
+       rel->width = rint(parent_size / parent_rows);
+       for (i = 0; i < nattrs; i++)
+           rel->attr_widths[i] = rint(parent_attrsizes[i] / parent_rows);
+   }
+   else
+       rel->width = 0;         /* attr_widths should be zero already */
+
    /*
     * Set "raw tuples" count equal to "rows" for the appendrel; needed
     * because some places assume rel->tuples is valid for any baserel.
     */
-   rel->tuples = rel->rows;
+   rel->tuples = parent_rows;
+
+   pfree(parent_attrsizes);
 
    /*
     * Finally, build Append path and install it as the only access path for
 
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.240 2008/04/17 21:22:14 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.241 2008/06/27 03:56:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include <limits.h>
+#include <math.h>
 
 #include "access/skey.h"
 #include "nodes/makefuncs.h"
 {
    Append     *node = makeNode(Append);
    Plan       *plan = &node->plan;
+   double      total_size;
    ListCell   *subnode;
 
    /*
    plan->startup_cost = 0;
    plan->total_cost = 0;
    plan->plan_rows = 0;
-   plan->plan_width = 0;
+   total_size = 0;
    foreach(subnode, appendplans)
    {
        Plan       *subplan = (Plan *) lfirst(subnode);
            plan->startup_cost = subplan->startup_cost;
        plan->total_cost += subplan->total_cost;
        plan->plan_rows += subplan->plan_rows;
-       if (plan->plan_width < subplan->plan_width)
-           plan->plan_width = subplan->plan_width;
+       total_size += subplan->plan_width * subplan->plan_rows;
    }
+   if (plan->plan_rows > 0)
+       plan->plan_width = rint(total_size / plan->plan_rows);
+   else
+       plan->plan_width = 0;
 
    plan->targetlist = tlist;
    plan->qual = NIL;