OSDN Git Service

If the inputs of a UNION/INTERSECT/EXCEPT construct all agree on the
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 12 Nov 2001 20:04:20 +0000 (20:04 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 12 Nov 2001 20:04:20 +0000 (20:04 +0000)
typmod of a particular column, mark the output with that same typmod,
not -1 as formerly.  -1 is still used if there is any disagreement.
Part of response to bug#513.

src/backend/optimizer/prep/prepunion.c

index 888edf5..03c06b6 100644 (file)
@@ -14,7 +14,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.68 2001/10/28 06:25:46 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.69 2001/11/12 20:04:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -63,6 +63,7 @@ static List *generate_setop_tlist(List *colTypes, int flag,
                                         bool hack_constants,
                                         List *input_tlist,
                                         List *refnames_tlist);
+static void merge_tlist_typmods(List *tlist, List *planlist);
 static bool tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK);
 static Node *adjust_inherited_attrs_mutator(Node *node,
                                                           adjust_inherited_attrs_context *context);
@@ -204,6 +205,7 @@ generate_union_plan(SetOperationStmt *op, Query *parse,
                                        List *refnames_tlist)
 {
        List       *planlist;
+       List       *tlist;
        Plan       *plan;
 
        /*
@@ -218,18 +220,21 @@ generate_union_plan(SetOperationStmt *op, Query *parse,
                                                                                        op, refnames_tlist));
 
        /*
-        * Append the child results together.
+        * Generate tlist for Append plan node.
         *
         * The tlist for an Append plan isn't important as far as the Append is
         * concerned, but we must make it look real anyway for the benefit of
         * the next plan level up.
         */
-       plan = (Plan *)
-               make_append(planlist,
-                                       false,
-                                       generate_setop_tlist(op->colTypes, -1, false,
+       tlist = generate_setop_tlist(op->colTypes, -1, false,
                                                                 ((Plan *) lfirst(planlist))->targetlist,
-                                                                                refnames_tlist));
+                                                                refnames_tlist);
+       merge_tlist_typmods(tlist, planlist);
+
+       /*
+        * Append the child results together.
+        */
+       plan = (Plan *) make_append(planlist, false, tlist);
 
        /*
         * For UNION ALL, we just need the Append plan.  For UNION, need to
@@ -237,10 +242,9 @@ generate_union_plan(SetOperationStmt *op, Query *parse,
         */
        if (!op->all)
        {
-               List       *tlist,
-                                  *sortList;
+               List       *sortList;
 
-               tlist = new_unsorted_tlist(plan->targetlist);
+               tlist = new_unsorted_tlist(tlist);
                sortList = addAllTargetsToSortList(NIL, tlist);
                plan = make_sortplan(parse, tlist, plan, sortList);
                plan = (Plan *) make_unique(tlist, plan, copyObject(sortList));
@@ -259,7 +263,8 @@ generate_nonunion_plan(SetOperationStmt *op, Query *parse,
                           *rplan,
                           *plan;
        List       *tlist,
-                          *sortList;
+                          *sortList,
+                          *planlist;
        SetOpCmd        cmd;
 
        /* Recurse on children, ensuring their outputs are marked */
@@ -269,9 +274,10 @@ generate_nonunion_plan(SetOperationStmt *op, Query *parse,
        rplan = recurse_set_operations(op->rarg, parse,
                                                                   op->colTypes, false, 1,
                                                                   refnames_tlist);
+       planlist = makeList2(lplan, rplan);
 
        /*
-        * Append the child results together.
+        * Generate tlist for Append plan node.
         *
         * The tlist for an Append plan isn't important as far as the Append is
         * concerned, but we must make it look real anyway for the benefit of
@@ -279,18 +285,21 @@ generate_nonunion_plan(SetOperationStmt *op, Query *parse,
         * flag column is shown as a variable not a constant, else setrefs.c
         * will get confused.
         */
-       plan = (Plan *)
-               make_append(makeList2(lplan, rplan),
-                                       false,
-                                       generate_setop_tlist(op->colTypes, 2, false,
-                                                                                lplan->targetlist,
-                                                                                refnames_tlist));
+       tlist = generate_setop_tlist(op->colTypes, 2, false,
+                                                                lplan->targetlist,
+                                                                refnames_tlist);
+       merge_tlist_typmods(tlist, planlist);
+
+       /*
+        * Append the child results together.
+        */
+       plan = (Plan *) make_append(planlist, false, tlist);
 
        /*
         * Sort the child results, then add a SetOp plan node to generate the
         * correct output.
         */
-       tlist = new_unsorted_tlist(plan->targetlist);
+       tlist = new_unsorted_tlist(tlist);
        sortList = addAllTargetsToSortList(NIL, tlist);
        plan = make_sortplan(parse, tlist, plan, sortList);
        switch (op->op)
@@ -332,9 +341,11 @@ recurse_union_children(Node *setOp, Query *parse,
                {
                        /* Same UNION, so fold children into parent's subplan list */
                        return nconc(recurse_union_children(op->larg, parse,
-                                                                                         top_union, refnames_tlist),
+                                                                                               top_union,
+                                                                                               refnames_tlist),
                                                 recurse_union_children(op->rarg, parse,
-                                                                                        top_union, refnames_tlist));
+                                                                                               top_union,
+                                                                                               refnames_tlist));
                }
        }
 
@@ -380,6 +391,7 @@ generate_setop_tlist(List *colTypes, int flag,
                Oid                     colType = (Oid) lfirsti(i);
                TargetEntry *inputtle = (TargetEntry *) lfirst(input_tlist);
                TargetEntry *reftle = (TargetEntry *) lfirst(refnames_tlist);
+               int32           colTypmod;
 
                Assert(inputtle->resdom->resno == resno);
                Assert(reftle->resdom->resno == resno);
@@ -399,11 +411,6 @@ generate_setop_tlist(List *colTypes, int flag,
                 * subquery-scan plans; we don't want phony constants appearing in
                 * the output tlists of upper-level nodes!
                 */
-               resdom = makeResdom((AttrNumber) resno++,
-                                                       colType,
-                                                       -1,
-                                                       pstrdup(reftle->resdom->resname),
-                                                       false);
                if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
                        expr = inputtle->expr;
                else
@@ -412,10 +419,24 @@ generate_setop_tlist(List *colTypes, int flag,
                                                                        inputtle->resdom->restype,
                                                                        inputtle->resdom->restypmod,
                                                                        0);
-               expr = coerce_to_common_type(NULL,
-                                                                        expr,
-                                                                        colType,
-                                                                        "UNION/INTERSECT/EXCEPT");
+               if (inputtle->resdom->restype == colType)
+               {
+                       /* no coercion needed, and believe the input typmod */
+                       colTypmod = inputtle->resdom->restypmod;
+               }
+               else
+               {
+                       expr = coerce_to_common_type(NULL,
+                                                                                expr,
+                                                                                colType,
+                                                                                "UNION/INTERSECT/EXCEPT");
+                       colTypmod = -1;
+               }
+               resdom = makeResdom((AttrNumber) resno++,
+                                                       colType,
+                                                       colTypmod,
+                                                       pstrdup(reftle->resdom->resname),
+                                                       false);
                tlist = lappend(tlist, makeTargetEntry(resdom, expr));
                input_tlist = lnext(input_tlist);
                refnames_tlist = lnext(refnames_tlist);
@@ -456,6 +477,47 @@ generate_setop_tlist(List *colTypes, int flag,
 }
 
 /*
+ * Merge typmods of a list of set-operation subplans.
+ *
+ * If the inputs all agree on type and typmod of a particular column,
+ * use that typmod; else use -1.  We assume the result tlist has been
+ * initialized with the types and typmods of the first input subplan.
+ */
+static void
+merge_tlist_typmods(List *tlist, List *planlist)
+{
+       List       *planl;
+
+       foreach(planl, planlist)
+       {
+               Plan   *subplan = (Plan *) lfirst(planl);
+               List   *subtlist = subplan->targetlist;
+               List   *restlist;
+
+               foreach(restlist, tlist)
+               {
+                       TargetEntry *restle = (TargetEntry *) lfirst(restlist);
+                       TargetEntry *subtle;
+
+                       if (restle->resdom->resjunk)
+                               continue;
+                       Assert(subtlist != NIL);
+                       subtle = (TargetEntry *) lfirst(subtlist);
+                       while (subtle->resdom->resjunk)
+                       {
+                               subtlist = lnext(subtlist);
+                               Assert(subtlist != NIL);
+                               subtle = (TargetEntry *) lfirst(subtlist);
+                       }
+                       if (restle->resdom->restype != subtle->resdom->restype ||
+                               restle->resdom->restypmod != subtle->resdom->restypmod)
+                               restle->resdom->restypmod = -1;
+                       subtlist = lnext(subtlist);
+               }
+       }
+}
+
+/*
  * Does tlist have same datatypes as requested colTypes?
  *
  * Resjunk columns are ignored if junkOK is true; otherwise presence of