Commit e433bf5a authored by Tom Lane's avatar Tom Lane

If the inputs of a UNION/INTERSECT/EXCEPT construct all agree on the

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.
parent 7a9ef7ee
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -63,6 +63,7 @@ static List *generate_setop_tlist(List *colTypes, int flag,
bool hack_constants, bool hack_constants,
List *input_tlist, List *input_tlist,
List *refnames_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 bool tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK);
static Node *adjust_inherited_attrs_mutator(Node *node, static Node *adjust_inherited_attrs_mutator(Node *node,
adjust_inherited_attrs_context *context); adjust_inherited_attrs_context *context);
...@@ -204,6 +205,7 @@ generate_union_plan(SetOperationStmt *op, Query *parse, ...@@ -204,6 +205,7 @@ generate_union_plan(SetOperationStmt *op, Query *parse,
List *refnames_tlist) List *refnames_tlist)
{ {
List *planlist; List *planlist;
List *tlist;
Plan *plan; Plan *plan;
/* /*
...@@ -218,18 +220,21 @@ generate_union_plan(SetOperationStmt *op, Query *parse, ...@@ -218,18 +220,21 @@ generate_union_plan(SetOperationStmt *op, Query *parse,
op, refnames_tlist)); 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 * 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 * concerned, but we must make it look real anyway for the benefit of
* the next plan level up. * the next plan level up.
*/ */
plan = (Plan *) tlist = generate_setop_tlist(op->colTypes, -1, false,
make_append(planlist,
false,
generate_setop_tlist(op->colTypes, -1, false,
((Plan *) lfirst(planlist))->targetlist, ((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 * For UNION ALL, we just need the Append plan. For UNION, need to
...@@ -237,10 +242,9 @@ generate_union_plan(SetOperationStmt *op, Query *parse, ...@@ -237,10 +242,9 @@ generate_union_plan(SetOperationStmt *op, Query *parse,
*/ */
if (!op->all) if (!op->all)
{ {
List *tlist, List *sortList;
*sortList;
tlist = new_unsorted_tlist(plan->targetlist); tlist = new_unsorted_tlist(tlist);
sortList = addAllTargetsToSortList(NIL, tlist); sortList = addAllTargetsToSortList(NIL, tlist);
plan = make_sortplan(parse, tlist, plan, sortList); plan = make_sortplan(parse, tlist, plan, sortList);
plan = (Plan *) make_unique(tlist, plan, copyObject(sortList)); plan = (Plan *) make_unique(tlist, plan, copyObject(sortList));
...@@ -259,7 +263,8 @@ generate_nonunion_plan(SetOperationStmt *op, Query *parse, ...@@ -259,7 +263,8 @@ generate_nonunion_plan(SetOperationStmt *op, Query *parse,
*rplan, *rplan,
*plan; *plan;
List *tlist, List *tlist,
*sortList; *sortList,
*planlist;
SetOpCmd cmd; SetOpCmd cmd;
/* Recurse on children, ensuring their outputs are marked */ /* Recurse on children, ensuring their outputs are marked */
...@@ -269,9 +274,10 @@ generate_nonunion_plan(SetOperationStmt *op, Query *parse, ...@@ -269,9 +274,10 @@ generate_nonunion_plan(SetOperationStmt *op, Query *parse,
rplan = recurse_set_operations(op->rarg, parse, rplan = recurse_set_operations(op->rarg, parse,
op->colTypes, false, 1, op->colTypes, false, 1,
refnames_tlist); 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 * 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 * concerned, but we must make it look real anyway for the benefit of
...@@ -279,18 +285,21 @@ generate_nonunion_plan(SetOperationStmt *op, Query *parse, ...@@ -279,18 +285,21 @@ generate_nonunion_plan(SetOperationStmt *op, Query *parse,
* flag column is shown as a variable not a constant, else setrefs.c * flag column is shown as a variable not a constant, else setrefs.c
* will get confused. * will get confused.
*/ */
plan = (Plan *) tlist = generate_setop_tlist(op->colTypes, 2, false,
make_append(makeList2(lplan, rplan), lplan->targetlist,
false, refnames_tlist);
generate_setop_tlist(op->colTypes, 2, false, merge_tlist_typmods(tlist, planlist);
lplan->targetlist,
refnames_tlist)); /*
* 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 * Sort the child results, then add a SetOp plan node to generate the
* correct output. * correct output.
*/ */
tlist = new_unsorted_tlist(plan->targetlist); tlist = new_unsorted_tlist(tlist);
sortList = addAllTargetsToSortList(NIL, tlist); sortList = addAllTargetsToSortList(NIL, tlist);
plan = make_sortplan(parse, tlist, plan, sortList); plan = make_sortplan(parse, tlist, plan, sortList);
switch (op->op) switch (op->op)
...@@ -332,9 +341,11 @@ recurse_union_children(Node *setOp, Query *parse, ...@@ -332,9 +341,11 @@ recurse_union_children(Node *setOp, Query *parse,
{ {
/* Same UNION, so fold children into parent's subplan list */ /* Same UNION, so fold children into parent's subplan list */
return nconc(recurse_union_children(op->larg, parse, return nconc(recurse_union_children(op->larg, parse,
top_union, refnames_tlist), top_union,
refnames_tlist),
recurse_union_children(op->rarg, parse, 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, ...@@ -380,6 +391,7 @@ generate_setop_tlist(List *colTypes, int flag,
Oid colType = (Oid) lfirsti(i); Oid colType = (Oid) lfirsti(i);
TargetEntry *inputtle = (TargetEntry *) lfirst(input_tlist); TargetEntry *inputtle = (TargetEntry *) lfirst(input_tlist);
TargetEntry *reftle = (TargetEntry *) lfirst(refnames_tlist); TargetEntry *reftle = (TargetEntry *) lfirst(refnames_tlist);
int32 colTypmod;
Assert(inputtle->resdom->resno == resno); Assert(inputtle->resdom->resno == resno);
Assert(reftle->resdom->resno == resno); Assert(reftle->resdom->resno == resno);
...@@ -399,11 +411,6 @@ generate_setop_tlist(List *colTypes, int flag, ...@@ -399,11 +411,6 @@ generate_setop_tlist(List *colTypes, int flag,
* subquery-scan plans; we don't want phony constants appearing in * subquery-scan plans; we don't want phony constants appearing in
* the output tlists of upper-level nodes! * 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)) if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
expr = inputtle->expr; expr = inputtle->expr;
else else
...@@ -412,10 +419,24 @@ generate_setop_tlist(List *colTypes, int flag, ...@@ -412,10 +419,24 @@ generate_setop_tlist(List *colTypes, int flag,
inputtle->resdom->restype, inputtle->resdom->restype,
inputtle->resdom->restypmod, inputtle->resdom->restypmod,
0); 0);
expr = coerce_to_common_type(NULL, if (inputtle->resdom->restype == colType)
expr, {
colType, /* no coercion needed, and believe the input typmod */
"UNION/INTERSECT/EXCEPT"); 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)); tlist = lappend(tlist, makeTargetEntry(resdom, expr));
input_tlist = lnext(input_tlist); input_tlist = lnext(input_tlist);
refnames_tlist = lnext(refnames_tlist); refnames_tlist = lnext(refnames_tlist);
...@@ -455,6 +476,47 @@ generate_setop_tlist(List *colTypes, int flag, ...@@ -455,6 +476,47 @@ generate_setop_tlist(List *colTypes, int flag,
return tlist; return tlist;
} }
/*
* 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? * Does tlist have same datatypes as requested colTypes?
* *
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment