*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.70 2002/03/01 06:01:20 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.71 2002/03/05 05:10:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
bool hack_constants,
List *input_tlist,
List *refnames_tlist);
-static void merge_tlist_typmods(List *tlist, List *planlist);
+static List *generate_append_tlist(List *colTypes, bool flag,
+ List *input_plans,
+ List *refnames_tlist);
static bool tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK);
static Node *adjust_inherited_attrs_mutator(Node *node,
adjust_inherited_attrs_context *context);
*
* XXX you don't really want to know about this: setrefs.c will apply
* replace_vars_with_subplan_refs() to the Result node's tlist.
- * This would fail if the input plan's non-resjunk tlist entries
- * were not all simple Vars equal() to the referencing Vars
- * generated by generate_setop_tlist(). However, since the input
- * plan was generated by generate_union_plan() or
- * generate_nonunion_plan(), the referencing Vars will equal the
- * tlist entries they reference. Ugly but I don't feel like making
- * that code more general right now.
+ * This would fail if the Vars generated by generate_setop_tlist()
+ * were not exactly equal() to the corresponding tlist entries of
+ * the subplan. However, since the subplan was generated by
+ * generate_union_plan() or generate_nonunion_plan(), and hence its
+ * tlist was generated by generate_append_tlist(), this will work.
*/
if (flag >= 0 ||
!tlist_same_datatypes(plan->targetlist, colTypes, junkOK))
* concerned, but we must make it look real anyway for the benefit of
* the next plan level up.
*/
- tlist = generate_setop_tlist(op->colTypes, -1, false,
- ((Plan *) lfirst(planlist))->targetlist,
- refnames_tlist);
- merge_tlist_typmods(tlist, planlist);
+ tlist = generate_append_tlist(op->colTypes, false,
+ planlist, refnames_tlist);
/*
* Append the child results together.
* flag column is shown as a variable not a constant, else setrefs.c
* will get confused.
*/
- tlist = generate_setop_tlist(op->colTypes, 2, false,
- lplan->targetlist,
- refnames_tlist);
- merge_tlist_typmods(tlist, planlist);
+ tlist = generate_append_tlist(op->colTypes, true,
+ planlist, refnames_tlist);
/*
* Append the child results together.
* Generate targetlist for a set-operation plan node
*
* colTypes: column datatypes for non-junk columns
- * flag: -1 if no flag column needed, 0 or 1 to create a const flag column,
- * 2 to create a variable flag column
+ * flag: -1 if no flag column needed, 0 or 1 to create a const flag column
* hack_constants: true to copy up constants (see comments in code)
* input_tlist: targetlist of this node's input node
* refnames_tlist: targetlist to take column names from
-1,
pstrdup("flag"),
true);
- if (flag <= 1)
- {
- /* flag value is the given constant */
- expr = (Node *) makeConst(INT4OID,
- sizeof(int4),
- Int32GetDatum(flag),
- false,
- true,
- false,
- false);
- }
- else
- {
- /* flag value is being copied up from subplan */
- expr = (Node *) makeVar(0,
- resdom->resno,
- INT4OID,
- -1,
- 0);
- }
+ /* flag value is the given constant */
+ expr = (Node *) makeConst(INT4OID,
+ sizeof(int4),
+ Int32GetDatum(flag),
+ false,
+ true,
+ false,
+ false);
tlist = lappend(tlist, makeTargetEntry(resdom, expr));
}
}
/*
- * Merge typmods of a list of set-operation subplans.
+ * Generate targetlist for a set-operation Append node
+ *
+ * colTypes: column datatypes for non-junk columns
+ * flag: true to create a flag column copied up from subplans
+ * input_plans: list of sub-plans of the Append
+ * refnames_tlist: targetlist to take column names from
*
- * 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.
+ * The entries in the Append's targetlist should always be simple Vars;
+ * we just have to make sure they have the right datatypes and typmods.
*/
-static void
-merge_tlist_typmods(List *tlist, List *planlist)
+static List *
+generate_append_tlist(List *colTypes, bool flag,
+ List *input_plans,
+ List *refnames_tlist)
{
+ List *tlist = NIL;
+ int resno = 1;
+ List *curColType;
+ int colindex;
+ Resdom *resdom;
+ Node *expr;
List *planl;
+ int32 *colTypmods;
+
+ /*
+ * First extract typmods to use.
+ *
+ * If the inputs all agree on type and typmod of a particular column,
+ * use that typmod; else use -1.
+ */
+ colTypmods = (int32 *) palloc(length(colTypes) * sizeof(int32));
- foreach(planl, planlist)
+ foreach(planl, input_plans)
{
Plan *subplan = (Plan *) lfirst(planl);
- List *subtlist = subplan->targetlist;
- List *restlist;
+ List *subtlist;
- foreach(restlist, tlist)
+ curColType = colTypes;
+ colindex = 0;
+ foreach(subtlist, subplan->targetlist)
{
- TargetEntry *restle = (TargetEntry *) lfirst(restlist);
- TargetEntry *subtle;
+ TargetEntry *subtle = (TargetEntry *) lfirst(subtlist);
- if (restle->resdom->resjunk)
+ if (subtle->resdom->resjunk)
continue;
- Assert(subtlist != NIL);
- subtle = (TargetEntry *) lfirst(subtlist);
- while (subtle->resdom->resjunk)
+ Assert(curColType != NIL);
+ if (subtle->resdom->restype == (Oid) lfirsti(curColType))
{
- subtlist = lnext(subtlist);
- Assert(subtlist != NIL);
- subtle = (TargetEntry *) lfirst(subtlist);
+ /* If first subplan, copy the typmod; else compare */
+ if (planl == input_plans)
+ colTypmods[colindex] = subtle->resdom->restypmod;
+ else if (subtle->resdom->restypmod != colTypmods[colindex])
+ colTypmods[colindex] = -1;
}
- if (restle->resdom->restype != subtle->resdom->restype ||
- restle->resdom->restypmod != subtle->resdom->restypmod)
- restle->resdom->restypmod = -1;
- subtlist = lnext(subtlist);
+ else
+ {
+ /* types disagree, so force typmod to -1 */
+ colTypmods[colindex] = -1;
+ }
+ curColType = lnext(curColType);
+ colindex++;
}
+ Assert(curColType == NIL);
}
+
+ /*
+ * Now we can build the tlist for the Append.
+ */
+ colindex = 0;
+ foreach(curColType, colTypes)
+ {
+ Oid colType = (Oid) lfirsti(curColType);
+ int32 colTypmod = colTypmods[colindex++];
+ TargetEntry *reftle = (TargetEntry *) lfirst(refnames_tlist);
+
+ Assert(reftle->resdom->resno == resno);
+ Assert(!reftle->resdom->resjunk);
+ expr = (Node *) makeVar(0,
+ resno,
+ colType,
+ colTypmod,
+ 0);
+ resdom = makeResdom((AttrNumber) resno++,
+ colType,
+ colTypmod,
+ pstrdup(reftle->resdom->resname),
+ false);
+ tlist = lappend(tlist, makeTargetEntry(resdom, expr));
+ refnames_tlist = lnext(refnames_tlist);
+ }
+
+ if (flag)
+ {
+ /* Add a resjunk flag column */
+ resdom = makeResdom((AttrNumber) resno++,
+ INT4OID,
+ -1,
+ pstrdup("flag"),
+ true);
+ /* flag value is shown as copied up from subplan */
+ expr = (Node *) makeVar(0,
+ resdom->resno,
+ INT4OID,
+ -1,
+ 0);
+ tlist = lappend(tlist, makeTargetEntry(resdom, expr));
+ }
+
+ pfree(colTypmods);
+
+ return tlist;
}
/*