Skip to content

Commit 9446718

Browse files
committed
Previous patch to mark UNION outputs with common typmod (if any) breaks
three-or-more-way UNIONs, as per example from Josh Berkus. Cause is a fragile assumption that one tlist's entries will exactly match another. Restructure code to make that assumption a little less fragile.
1 parent 17b6baf commit 9446718

File tree

1 file changed

+118
-62
lines changed

1 file changed

+118
-62
lines changed

src/backend/optimizer/prep/prepunion.c

Lines changed: 118 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
*
1515
*
1616
* IDENTIFICATION
17-
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.70 2002/03/01 06:01:20 tgl Exp $
17+
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.71 2002/03/05 05:10:24 tgl Exp $
1818
*
1919
*-------------------------------------------------------------------------
2020
*/
@@ -63,7 +63,9 @@ static List *generate_setop_tlist(List *colTypes, int flag,
6363
bool hack_constants,
6464
List *input_tlist,
6565
List *refnames_tlist);
66-
static void merge_tlist_typmods(List *tlist, List *planlist);
66+
static List *generate_append_tlist(List *colTypes, bool flag,
67+
List *input_plans,
68+
List *refnames_tlist);
6769
static bool tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK);
6870
static Node *adjust_inherited_attrs_mutator(Node *node,
6971
adjust_inherited_attrs_context *context);
@@ -169,13 +171,11 @@ recurse_set_operations(Node *setOp, Query *parse,
169171
*
170172
* XXX you don't really want to know about this: setrefs.c will apply
171173
* replace_vars_with_subplan_refs() to the Result node's tlist.
172-
* This would fail if the input plan's non-resjunk tlist entries
173-
* were not all simple Vars equal() to the referencing Vars
174-
* generated by generate_setop_tlist(). However, since the input
175-
* plan was generated by generate_union_plan() or
176-
* generate_nonunion_plan(), the referencing Vars will equal the
177-
* tlist entries they reference. Ugly but I don't feel like making
178-
* that code more general right now.
174+
* This would fail if the Vars generated by generate_setop_tlist()
175+
* were not exactly equal() to the corresponding tlist entries of
176+
* the subplan. However, since the subplan was generated by
177+
* generate_union_plan() or generate_nonunion_plan(), and hence its
178+
* tlist was generated by generate_append_tlist(), this will work.
179179
*/
180180
if (flag >= 0 ||
181181
!tlist_same_datatypes(plan->targetlist, colTypes, junkOK))
@@ -226,10 +226,8 @@ generate_union_plan(SetOperationStmt *op, Query *parse,
226226
* concerned, but we must make it look real anyway for the benefit of
227227
* the next plan level up.
228228
*/
229-
tlist = generate_setop_tlist(op->colTypes, -1, false,
230-
((Plan *) lfirst(planlist))->targetlist,
231-
refnames_tlist);
232-
merge_tlist_typmods(tlist, planlist);
229+
tlist = generate_append_tlist(op->colTypes, false,
230+
planlist, refnames_tlist);
233231

234232
/*
235233
* Append the child results together.
@@ -285,10 +283,8 @@ generate_nonunion_plan(SetOperationStmt *op, Query *parse,
285283
* flag column is shown as a variable not a constant, else setrefs.c
286284
* will get confused.
287285
*/
288-
tlist = generate_setop_tlist(op->colTypes, 2, false,
289-
lplan->targetlist,
290-
refnames_tlist);
291-
merge_tlist_typmods(tlist, planlist);
286+
tlist = generate_append_tlist(op->colTypes, true,
287+
planlist, refnames_tlist);
292288

293289
/*
294290
* Append the child results together.
@@ -368,8 +364,7 @@ recurse_union_children(Node *setOp, Query *parse,
368364
* Generate targetlist for a set-operation plan node
369365
*
370366
* colTypes: column datatypes for non-junk columns
371-
* flag: -1 if no flag column needed, 0 or 1 to create a const flag column,
372-
* 2 to create a variable flag column
367+
* flag: -1 if no flag column needed, 0 or 1 to create a const flag column
373368
* hack_constants: true to copy up constants (see comments in code)
374369
* input_tlist: targetlist of this node's input node
375370
* refnames_tlist: targetlist to take column names from
@@ -450,71 +445,132 @@ generate_setop_tlist(List *colTypes, int flag,
450445
-1,
451446
pstrdup("flag"),
452447
true);
453-
if (flag <= 1)
454-
{
455-
/* flag value is the given constant */
456-
expr = (Node *) makeConst(INT4OID,
457-
sizeof(int4),
458-
Int32GetDatum(flag),
459-
false,
460-
true,
461-
false,
462-
false);
463-
}
464-
else
465-
{
466-
/* flag value is being copied up from subplan */
467-
expr = (Node *) makeVar(0,
468-
resdom->resno,
469-
INT4OID,
470-
-1,
471-
0);
472-
}
448+
/* flag value is the given constant */
449+
expr = (Node *) makeConst(INT4OID,
450+
sizeof(int4),
451+
Int32GetDatum(flag),
452+
false,
453+
true,
454+
false,
455+
false);
473456
tlist = lappend(tlist, makeTargetEntry(resdom, expr));
474457
}
475458

476459
return tlist;
477460
}
478461

479462
/*
480-
* Merge typmods of a list of set-operation subplans.
463+
* Generate targetlist for a set-operation Append node
464+
*
465+
* colTypes: column datatypes for non-junk columns
466+
* flag: true to create a flag column copied up from subplans
467+
* input_plans: list of sub-plans of the Append
468+
* refnames_tlist: targetlist to take column names from
481469
*
482-
* If the inputs all agree on type and typmod of a particular column,
483-
* use that typmod; else use -1. We assume the result tlist has been
484-
* initialized with the types and typmods of the first input subplan.
470+
* The entries in the Append's targetlist should always be simple Vars;
471+
* we just have to make sure they have the right datatypes and typmods.
485472
*/
486-
static void
487-
merge_tlist_typmods(List *tlist, List *planlist)
473+
static List *
474+
generate_append_tlist(List *colTypes, bool flag,
475+
List *input_plans,
476+
List *refnames_tlist)
488477
{
478+
List *tlist = NIL;
479+
int resno = 1;
480+
List *curColType;
481+
int colindex;
482+
Resdom *resdom;
483+
Node *expr;
489484
List *planl;
485+
int32 *colTypmods;
486+
487+
/*
488+
* First extract typmods to use.
489+
*
490+
* If the inputs all agree on type and typmod of a particular column,
491+
* use that typmod; else use -1.
492+
*/
493+
colTypmods = (int32 *) palloc(length(colTypes) * sizeof(int32));
490494

491-
foreach(planl, planlist)
495+
foreach(planl, input_plans)
492496
{
493497
Plan *subplan = (Plan *) lfirst(planl);
494-
List *subtlist = subplan->targetlist;
495-
List *restlist;
498+
List *subtlist;
496499

497-
foreach(restlist, tlist)
500+
curColType = colTypes;
501+
colindex = 0;
502+
foreach(subtlist, subplan->targetlist)
498503
{
499-
TargetEntry *restle = (TargetEntry *) lfirst(restlist);
500-
TargetEntry *subtle;
504+
TargetEntry *subtle = (TargetEntry *) lfirst(subtlist);
501505

502-
if (restle->resdom->resjunk)
506+
if (subtle->resdom->resjunk)
503507
continue;
504-
Assert(subtlist != NIL);
505-
subtle = (TargetEntry *) lfirst(subtlist);
506-
while (subtle->resdom->resjunk)
508+
Assert(curColType != NIL);
509+
if (subtle->resdom->restype == (Oid) lfirsti(curColType))
507510
{
508-
subtlist = lnext(subtlist);
509-
Assert(subtlist != NIL);
510-
subtle = (TargetEntry *) lfirst(subtlist);
511+
/* If first subplan, copy the typmod; else compare */
512+
if (planl == input_plans)
513+
colTypmods[colindex] = subtle->resdom->restypmod;
514+
else if (subtle->resdom->restypmod != colTypmods[colindex])
515+
colTypmods[colindex] = -1;
511516
}
512-
if (restle->resdom->restype != subtle->resdom->restype ||
513-
restle->resdom->restypmod != subtle->resdom->restypmod)
514-
restle->resdom->restypmod = -1;
515-
subtlist = lnext(subtlist);
517+
else
518+
{
519+
/* types disagree, so force typmod to -1 */
520+
colTypmods[colindex] = -1;
521+
}
522+
curColType = lnext(curColType);
523+
colindex++;
516524
}
525+
Assert(curColType == NIL);
517526
}
527+
528+
/*
529+
* Now we can build the tlist for the Append.
530+
*/
531+
colindex = 0;
532+
foreach(curColType, colTypes)
533+
{
534+
Oid colType = (Oid) lfirsti(curColType);
535+
int32 colTypmod = colTypmods[colindex++];
536+
TargetEntry *reftle = (TargetEntry *) lfirst(refnames_tlist);
537+
538+
Assert(reftle->resdom->resno == resno);
539+
Assert(!reftle->resdom->resjunk);
540+
expr = (Node *) makeVar(0,
541+
resno,
542+
colType,
543+
colTypmod,
544+
0);
545+
resdom = makeResdom((AttrNumber) resno++,
546+
colType,
547+
colTypmod,
548+
pstrdup(reftle->resdom->resname),
549+
false);
550+
tlist = lappend(tlist, makeTargetEntry(resdom, expr));
551+
refnames_tlist = lnext(refnames_tlist);
552+
}
553+
554+
if (flag)
555+
{
556+
/* Add a resjunk flag column */
557+
resdom = makeResdom((AttrNumber) resno++,
558+
INT4OID,
559+
-1,
560+
pstrdup("flag"),
561+
true);
562+
/* flag value is shown as copied up from subplan */
563+
expr = (Node *) makeVar(0,
564+
resdom->resno,
565+
INT4OID,
566+
-1,
567+
0);
568+
tlist = lappend(tlist, makeTargetEntry(resdom, expr));
569+
}
570+
571+
pfree(colTypmods);
572+
573+
return tlist;
518574
}
519575

520576
/*

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy