prepunion.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 1,422 行 · 第 1/3 页
C
1,422 行
*/static List *generate_setop_tlist(List *colTypes, int flag, Index varno, bool hack_constants, List *input_tlist, List *refnames_tlist){ List *tlist = NIL; int resno = 1; ListCell *i, *j, *k; TargetEntry *tle; Node *expr; j = list_head(input_tlist); k = list_head(refnames_tlist); foreach(i, colTypes) { Oid colType = lfirst_oid(i); TargetEntry *inputtle = (TargetEntry *) lfirst(j); TargetEntry *reftle = (TargetEntry *) lfirst(k); Assert(inputtle->resno == resno); Assert(reftle->resno == resno); Assert(!inputtle->resjunk); Assert(!reftle->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(varno, inputtle->resno, exprType((Node *) inputtle->expr), exprTypmod((Node *) inputtle->expr), 0); if (exprType(expr) != colType) { expr = coerce_to_common_type(NULL, /* no UNKNOWNs here */ expr, colType, "UNION/INTERSECT/EXCEPT"); } tle = makeTargetEntry((Expr *) expr, (AttrNumber) resno++, pstrdup(reftle->resname), false); tlist = lappend(tlist, tle); j = lnext(j); k = lnext(k); } if (flag >= 0) { /* Add a resjunk flag column */ /* flag value is the given constant */ expr = (Node *) makeConst(INT4OID, -1, sizeof(int4), Int32GetDatum(flag), false, true); tle = makeTargetEntry((Expr *) expr, (AttrNumber) resno++, pstrdup("flag"), true); tlist = lappend(tlist, tle); } 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. * The Vars are always generated with varno 0. */static List *generate_append_tlist(List *colTypes, bool flag, List *input_plans, List *refnames_tlist){ List *tlist = NIL; int resno = 1; ListCell *curColType; ListCell *ref_tl_item; int colindex; TargetEntry *tle; Node *expr; ListCell *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(list_length(colTypes) * sizeof(int32)); foreach(planl, input_plans) { Plan *subplan = (Plan *) lfirst(planl); ListCell *subtlist; curColType = list_head(colTypes); colindex = 0; foreach(subtlist, subplan->targetlist) { TargetEntry *subtle = (TargetEntry *) lfirst(subtlist); if (subtle->resjunk) continue; Assert(curColType != NULL); if (exprType((Node *) subtle->expr) == lfirst_oid(curColType)) { /* If first subplan, copy the typmod; else compare */ int32 subtypmod = exprTypmod((Node *) subtle->expr); if (planl == list_head(input_plans)) colTypmods[colindex] = subtypmod; else if (subtypmod != colTypmods[colindex]) colTypmods[colindex] = -1; } else { /* types disagree, so force typmod to -1 */ colTypmods[colindex] = -1; } curColType = lnext(curColType); colindex++; } Assert(curColType == NULL); } /* * Now we can build the tlist for the Append. */ colindex = 0; forboth(curColType, colTypes, ref_tl_item, refnames_tlist) { Oid colType = lfirst_oid(curColType); int32 colTypmod = colTypmods[colindex++]; TargetEntry *reftle = (TargetEntry *) lfirst(ref_tl_item); Assert(reftle->resno == resno); Assert(!reftle->resjunk); expr = (Node *) makeVar(0, resno, colType, colTypmod, 0); tle = makeTargetEntry((Expr *) expr, (AttrNumber) resno++, pstrdup(reftle->resname), false); tlist = lappend(tlist, tle); } if (flag) { /* Add a resjunk flag column */ /* flag value is shown as copied up from subplan */ expr = (Node *) makeVar(0, resno, INT4OID, -1, 0); tle = makeTargetEntry((Expr *) expr, (AttrNumber) resno++, pstrdup("flag"), true); tlist = lappend(tlist, tle); } pfree(colTypmods); return tlist;}/* * 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 *rels_list; ListCell *l; /* * We build a list starting with the given rel and adding all direct and * indirect children. We can use a single list as both the record of * already-found rels and the agenda of rels yet to be scanned for more * children. This is a bit tricky but works because the foreach() macro * doesn't fetch the next list element until the bottom of the loop. */ rels_list = list_make1_oid(parentrel); foreach(l, rels_list) { Oid currentrel = lfirst_oid(l); List *currentchildren; /* Get the direct children of this rel */ 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.) */ rels_list = list_concat_unique_oid(rels_list, currentchildren); } return rels_list;}/* * expand_inherited_tables * Expand each rangetable entry that represents an inheritance set * into an "append relation". At the conclusion of this process, * the "inh" flag is set in all and only those RTEs that are append * relation parents. */voidexpand_inherited_tables(PlannerInfo *root){ Index nrtes; Index rti; ListCell *rl; /* * expand_inherited_rtentry may add RTEs to parse->rtable; there is no * need to scan them since they can't have inh=true. So just scan as far * as the original end of the rtable list. */ nrtes = list_length(root->parse->rtable); rl = list_head(root->parse->rtable); for (rti = 1; rti <= nrtes; rti++) { RangeTblEntry *rte = (RangeTblEntry *) lfirst(rl); expand_inherited_rtentry(root, rte, rti); rl = lnext(rl); }}/* * 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 build AppendRelInfo nodes for all the child tables * and add them to root->append_rel_list. If not, clear the entry's * "inh" flag to prevent later code from looking for AppendRelInfos. * * Note that the original RTE is considered to represent the whole * inheritance set. The first of the generated RTEs is an RTE for the same * table, but with inh = false, to represent the parent table in its role * as a simple member of the inheritance set. * * A childless table is never considered to be an inheritance set; therefore * a parent RTE must always have at least two associated AppendRelInfos. */static voidexpand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti){ Query *parse = root->parse; Oid parentOID; Relation oldrelation; LOCKMODE lockmode; List *inhOIDs; List *appinfos; ListCell *l; /* Does RT entry allow inheritance? */ if (!rte->inh) return; /* Ignore any already-expanded UNION ALL nodes */ if (rte->rtekind != RTE_RELATION) { Assert(rte->rtekind == RTE_SUBQUERY); return; } /* Fast path for common case of childless table */ parentOID = rte->relid; if (!has_subclass(parentOID)) { /* Clear flag before returning */ rte->inh = false; return; } /* 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 (list_length(inhOIDs) < 2) { /* Clear flag before returning */ rte->inh = false; return; } /* * Must open the parent relation to examine its tupdesc. We need not lock * it since the rewriter already obtained at least AccessShareLock on each * relation used in the query. */ oldrelation = heap_open(parentOID, NoLock); /* * However, for each child relation we add to the query, we must obtain an * appropriate lock, because this will be the first use of those relations * in the parse/rewrite/plan pipeline. * * If the parent relation is the query's result relation, then we need * RowExclusiveLock. Otherwise, check to see if the relation is accessed * FOR UPDATE/SHARE or not. We can't just grab AccessShareLock because * then the executor would be trying to upgrade the lock, leading to * possible deadlocks. (This code should match the parser and rewriter.) */ if (rti == parse->resultRelation) lockmode = RowExclusiveLock; else if (get_rowmark(parse, rti)) lockmode = RowShareLock; else lockmode = AccessShareLock; /* Scan the inheritance set and expand it */ appinfos = NIL; foreach(l, inhOIDs) { Oid childOID = lfirst_oid(l); Relation newrelation; RangeTblEntry *childrte; Index childRTindex; AppendRelInfo *appinfo; /* * It is possible that the parent table has children that are temp * tables of other backends. We cannot safely access such tables * (because of buffering issues), and the best thing to do seems to be * to silently ignore them. */ if (childOID != parentOID && isOtherTempNamespace(get_rel_namespace(childOID))) continue; /* Open rel, acquire the appropriate lock type */ if (childOID != parentOID) newrelation = heap_open(childOID, lockmode); else newrelation = oldrelation; /* * Build an RTE for the child, and attach to query's rangetable list. * We copy most fields of the parent's RTE, but replace relation OID, * and set inh = false. */ childrte = copyObject(rte); childrte->relid = childOID; childrte->inh = false; parse->rtable = lappend(parse->rtable, childrte); childRTindex = list_length(parse->rtable); /* * Build an AppendRelInfo for this parent and child. */ appinfo = makeNode(AppendRelInfo); appinfo->parent_relid = rti; appinfo->child_relid = childRTindex; appinfo->parent_reltype = oldrelation->rd_rel->reltype; appinfo->child_reltype = newrelation->rd_rel->reltype; make_inh_translation_lists(oldrelation, newrelation, childRTindex, &appinfo->col_mappings, &appinfo->translated_vars); appinfo->parent_reloid = parentOID; appinfos = lappend(appinfos, appinfo); /* Close child relations, but keep locks */ if (childOID != parentOID) heap_close(newrelation, NoLock); } heap_close(oldrelation, NoLock); /* * If all the children were temp tables, pretend it's a non-inheritance * situation. The duplicate RTE we added for the parent table is * harmless, so we don't bother to get rid of it. */ if (list_length(appinfos) < 2) { /* Clear flag before returning */ rte->inh = false; return; } /* Otherwise, OK to add to root->append_rel_list */ root->append_rel_list = list_concat(root->append_rel_list, appinfos); /* * The executor will check the parent table's access permissions when it * examines the parent's added RTE entry. There's no need to check twice, * so turn off access check bits in the original RTE. */ rte->requiredPerms = 0;}/* * make_inh_translation_lists * Build the lists of translations from parent Vars to child Vars for * an inheritance child. We need both a column number mapping list * and a list of Vars representing the child columns. * * For paranoia's sake, we match type as well as attribute name. */static voidmake_inh_translation_lists(Relation oldrelation, Relation newrelation, Index newvarno, List **col_mappings, List **translated_vars){ List *numbers = NIL; List *vars = NIL; TupleDesc old_tupdesc = RelationGetDescr(oldrelation); TupleDesc new_tupdesc = RelationGetDescr(newrelation); int oldnatts = old_tupdesc->natts; int newnatts = new_tupdesc->natts; int old_attno; for (old_attno = 0; old_attno < oldnatts; old_attno++) { Form_pg_attribute att; char *attname; Oid atttypid; int32 atttypmod; int new_attno; att = old_tupdesc->attrs[old_attno]; if (att->attisdropped) { /* Just put 0/NULL into this list entry */ numbers = lappend_int(numbers, 0);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?