📄 prepunion.c
字号:
* * Note we disallow any resjunk columns in child results. This is * necessary since the Append node that implements the union won't do * any projection, and upper levels will get confused if some of our * output tuples have junk and some don't. This case only arises when * we have an EXCEPT or INTERSECT as child, else there won't be * resjunk anyway. */ return makeList1(recurse_set_operations(setOp, parse, top_union->colTypes, false, -1, refnames_tlist));}/* * 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 * 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 */static List *generate_setop_tlist(List *colTypes, int flag, bool hack_constants, List *input_tlist, List *refnames_tlist){ List *tlist = NIL; int resno = 1; List *i; Resdom *resdom; Node *expr; foreach(i, colTypes) { Oid colType = lfirsto(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); Assert(!inputtle->resdom->resjunk); Assert(!reftle->resdom->resjunk); /* * Generate columns referencing input columns and having * appropriate data types and column names. Insert datatype * coercions where necessary. * * HACK: constants in the input's targetlist are copied up as-is * rather than being referenced as subquery outputs. This is * mainly to ensure that when we try to coerce them to the output * column's datatype, the right things happen for UNKNOWN * constants. But do this only at the first level of * subquery-scan plans; we don't want phony constants appearing in * the output tlists of upper-level nodes! */ if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const)) expr = (Node *) inputtle->expr; else expr = (Node *) makeVar(0, inputtle->resdom->resno, inputtle->resdom->restype, inputtle->resdom->restypmod, 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, /* no UNKNOWNs here */ expr, colType, "UNION/INTERSECT/EXCEPT"); colTypmod = -1; } resdom = makeResdom((AttrNumber) resno++, colType, colTypmod, pstrdup(reftle->resdom->resname), false); tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr)); input_tlist = lnext(input_tlist); refnames_tlist = lnext(refnames_tlist); } if (flag >= 0) { /* Add a resjunk flag column */ resdom = makeResdom((AttrNumber) resno++, INT4OID, -1, pstrdup("flag"), true); /* flag value is the given constant */ expr = (Node *) makeConst(INT4OID, sizeof(int4), Int32GetDatum(flag), false, true); tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr)); } return tlist;}/* * 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 * * 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 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, input_plans) { Plan *subplan = (Plan *) lfirst(planl); List *subtlist; curColType = colTypes; colindex = 0; foreach(subtlist, subplan->targetlist) { TargetEntry *subtle = (TargetEntry *) lfirst(subtlist); if (subtle->resdom->resjunk) continue; Assert(curColType != NIL); if (subtle->resdom->restype == lfirsto(curColType)) { /* 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; } 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 = lfirsto(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 *) 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 *) expr)); } pfree(colTypmods); return tlist;}/* * Does tlist have same datatypes as requested colTypes? * * Resjunk columns are ignored if junkOK is true; otherwise presence of * a resjunk column will always cause a 'false' result. */static booltlist_same_datatypes(List *tlist, List *colTypes, bool junkOK){ List *i; foreach(i, tlist) { TargetEntry *tle = (TargetEntry *) lfirst(i); if (tle->resdom->resjunk) { if (!junkOK) return false; } else { if (colTypes == NIL) return false; if (tle->resdom->restype != lfirsto(colTypes)) return false; colTypes = lnext(colTypes); } } if (colTypes != NIL) return false; return true;}/* * find_all_inheritors - * Returns a list of relation OIDs including the given rel plus * all relations that inherit from it, directly or indirectly. */List *find_all_inheritors(Oid parentrel){ List *examined_relids = NIL; List *unexamined_relids = makeListo1(parentrel); /* * While the queue of unexamined relids is nonempty, remove the first * element, mark it examined, and find its direct descendants. NB: * cannot use foreach(), since we modify the queue inside loop. */ while (unexamined_relids != NIL) { Oid currentrel = lfirsto(unexamined_relids); List *currentchildren; unexamined_relids = lnext(unexamined_relids); examined_relids = lappendo(examined_relids, currentrel); currentchildren = find_inheritance_children(currentrel); /* * Add to the queue only those children not already seen. This * avoids making duplicate entries in case of multiple inheritance * paths from the same parent. (It'll also keep us from getting * into an infinite loop, though theoretically there can't be any * cycles in the inheritance graph anyway.) */ currentchildren = set_differenceo(currentchildren, examined_relids); unexamined_relids = set_uniono(unexamined_relids, currentchildren); } return examined_relids;}/* * expand_inherited_rtentry * Check whether a rangetable entry represents an inheritance set. * If so, add entries for all the child tables to the query's * rangetable, and return an integer list of RT indexes for the * whole inheritance set (parent and children). * If not, return NIL. * * When dup_parent is false, the initially given RT index is part of the * returned list (if any). When dup_parent is true, the given RT index * is *not* in the returned list; a duplicate RTE will be made for the * parent table. * * A childless table is never considered to be an inheritance set; therefore * the result will never be a one-element list. It'll be either empty * or have two or more elements. * * NOTE: after this routine executes, the specified RTE will always have * its inh flag cleared, whether or not there were any children. This * ensures we won't expand the same RTE twice, which would otherwise occur * for the case of an inherited UPDATE/DELETE target relation. * * XXX probably should convert the result type to Relids? */List *expand_inherited_rtentry(Query *parse, Index rti, bool dup_parent){ RangeTblEntry *rte = rt_fetch(rti, parse->rtable); Oid parentOID; List *inhOIDs; List *inhRTIs; List *l; /* Does RT entry allow inheritance? */ if (!rte->inh) return NIL; Assert(rte->rtekind == RTE_RELATION); /* Always clear the parent's inh flag, see above comments */ rte->inh = false; /* Fast path for common case of childless table */ parentOID = rte->relid; if (!has_subclass(parentOID)) return NIL; /* Scan for all members of inheritance set */ inhOIDs = find_all_inheritors(parentOID); /* * Check that there's at least one descendant, else treat as no-child * case. This could happen despite above has_subclass() check, if * table once had a child but no longer does. */ if (lnext(inhOIDs) == NIL) return NIL; /* OK, it's an inheritance set; expand it */ if (dup_parent) inhRTIs = NIL; else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -