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
|
* 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,
|
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
*/
|
*/
|
||||||
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,
|
|||||||
*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,
|
|||||||
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,
|
|||||||
* 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),
|
|
||||||
false,
|
|
||||||
generate_setop_tlist(op->colTypes, 2, false,
|
|
||||||
lplan->targetlist,
|
lplan->targetlist,
|
||||||
refnames_tlist));
|
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
|
* 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,
|
|||||||
{
|
{
|
||||||
/* 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,
|
|||||||
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,
|
|||||||
* 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,
|
|||||||
inputtle->resdom->restype,
|
inputtle->resdom->restype,
|
||||||
inputtle->resdom->restypmod,
|
inputtle->resdom->restypmod,
|
||||||
0);
|
0);
|
||||||
|
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 = coerce_to_common_type(NULL,
|
||||||
expr,
|
expr,
|
||||||
colType,
|
colType,
|
||||||
"UNION/INTERSECT/EXCEPT");
|
"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,
|
|||||||
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?
|
||||||
*
|
*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user