mirror of
https://github.com/postgres/postgres.git
synced 2025-05-01 01:04:50 +03:00
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.
This commit is contained in:
parent
7a9ef7ee09
commit
e433bf5a5e
@ -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);
|
||||
@ -455,6 +476,47 @@ generate_setop_tlist(List *colTypes, int flag,
|
||||
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?
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user