📄 parse_relation.c
字号:
rte->rtekind = RTE_JOIN; rte->relid = InvalidOid; rte->subquery = NULL; rte->jointype = jointype; rte->joinaliasvars = aliasvars; rte->alias = alias; eref = alias ? (Alias *) copyObject(alias) : makeAlias("unnamed_join", NIL); numaliases = list_length(eref->colnames); /* fill in any unspecified alias columns */ if (numaliases < list_length(colnames)) eref->colnames = list_concat(eref->colnames, list_copy_tail(colnames, numaliases)); rte->eref = eref; /*---------- * Flags: * - this RTE should be expanded to include descendant tables, * - this RTE is in the FROM clause, * - this RTE should be checked for appropriate access rights. * * Joins are never checked for access rights. *---------- */ rte->inh = false; /* never true for joins */ rte->inFromCl = inFromCl; rte->requiredPerms = 0; rte->checkAsUser = InvalidOid; /* * Add completed RTE to pstate's range table list, but not to join list * nor namespace --- caller must do that if appropriate. */ if (pstate != NULL) pstate->p_rtable = lappend(pstate->p_rtable, rte); return rte;}/* * Has the specified refname been selected FOR UPDATE/FOR SHARE? */static boolisLockedRel(ParseState *pstate, char *refname){ /* Outer loop to check parent query levels as well as this one */ while (pstate != NULL) { if (pstate->p_locking_clause) { if (pstate->p_locking_clause->lockedRels == NIL) { /* all tables used in query */ return true; } else { /* just the named tables */ ListCell *l; foreach(l, pstate->p_locking_clause->lockedRels) { char *rname = strVal(lfirst(l)); if (strcmp(refname, rname) == 0) return true; } } } pstate = pstate->parentParseState; } return false;}/* * Add the given RTE as a top-level entry in the pstate's join list * and/or name space lists. (We assume caller has checked for any * namespace conflicts.) */voidaddRTEtoQuery(ParseState *pstate, RangeTblEntry *rte, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace){ if (addToJoinList) { int rtindex = RTERangeTablePosn(pstate, rte, NULL); RangeTblRef *rtr = makeNode(RangeTblRef); rtr->rtindex = rtindex; pstate->p_joinlist = lappend(pstate->p_joinlist, rtr); } if (addToRelNameSpace) pstate->p_relnamespace = lappend(pstate->p_relnamespace, rte); if (addToVarNameSpace) pstate->p_varnamespace = lappend(pstate->p_varnamespace, rte);}/* * Add a POSTQUEL-style implicit RTE. * * We assume caller has already checked that there is no RTE or join with * a conflicting name. */RangeTblEntry *addImplicitRTE(ParseState *pstate, RangeVar *relation){ RangeTblEntry *rte; /* issue warning or error as needed */ warnAutoRange(pstate, relation); /* * Note that we set inFromCl true, so that the RTE will be listed * explicitly if the parsetree is ever decompiled by ruleutils.c. This * provides a migration path for views/rules that were originally written * with implicit-RTE syntax. */ rte = addRangeTableEntry(pstate, relation, NULL, false, true); /* Add to joinlist and relnamespace, but not varnamespace */ addRTEtoQuery(pstate, rte, true, true, false); return rte;}/* * expandRTE -- expand the columns of a rangetable entry * * This creates lists of an RTE's column names (aliases if provided, else * real names) and Vars for each column. Only user columns are considered. * If include_dropped is FALSE then dropped columns are omitted from the * results. If include_dropped is TRUE then empty strings and NULL constants * (not Vars!) are returned for dropped columns. * * rtindex and sublevels_up are the varno and varlevelsup values to use * in the created Vars. Ordinarily rtindex should match the actual position * of the RTE in its rangetable. * * The output lists go into *colnames and *colvars. * If only one of the two kinds of output list is needed, pass NULL for the * output pointer for the unwanted one. */voidexpandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, bool include_dropped, List **colnames, List **colvars){ int varattno; if (colnames) *colnames = NIL; if (colvars) *colvars = NIL; switch (rte->rtekind) { case RTE_RELATION: /* Ordinary relation RTE */ expandRelation(rte->relid, rte->eref, rtindex, sublevels_up, include_dropped, colnames, colvars); break; case RTE_SUBQUERY: { /* Subquery RTE */ ListCell *aliasp_item = list_head(rte->eref->colnames); ListCell *tlistitem; varattno = 0; foreach(tlistitem, rte->subquery->targetList) { TargetEntry *te = (TargetEntry *) lfirst(tlistitem); if (te->resjunk) continue; varattno++; Assert(varattno == te->resno); if (colnames) { /* Assume there is one alias per target item */ char *label = strVal(lfirst(aliasp_item)); *colnames = lappend(*colnames, makeString(pstrdup(label))); aliasp_item = lnext(aliasp_item); } if (colvars) { Var *varnode; varnode = makeVar(rtindex, varattno, exprType((Node *) te->expr), exprTypmod((Node *) te->expr), sublevels_up); *colvars = lappend(*colvars, varnode); } } } break; case RTE_FUNCTION: { /* Function RTE */ TypeFuncClass functypclass; Oid funcrettype; TupleDesc tupdesc; functypclass = get_expr_result_type(rte->funcexpr, &funcrettype, &tupdesc); if (functypclass == TYPEFUNC_COMPOSITE) { /* Composite data type, e.g. a table's row type */ Assert(tupdesc); expandTupleDesc(tupdesc, rte->eref, rtindex, sublevels_up, include_dropped, colnames, colvars); } else if (functypclass == TYPEFUNC_SCALAR) { /* Base data type, i.e. scalar */ if (colnames) *colnames = lappend(*colnames, linitial(rte->eref->colnames)); if (colvars) { Var *varnode; varnode = makeVar(rtindex, 1, funcrettype, -1, sublevels_up); *colvars = lappend(*colvars, varnode); } } else if (functypclass == TYPEFUNC_RECORD) { List *coldeflist = rte->coldeflist; ListCell *col; int attnum = 0; foreach(col, coldeflist) { ColumnDef *colDef = lfirst(col); attnum++; if (colnames) { char *attrname; attrname = pstrdup(colDef->colname); *colnames = lappend(*colnames, makeString(attrname)); } if (colvars) { Var *varnode; Oid atttypid; atttypid = typenameTypeId(colDef->typename); varnode = makeVar(rtindex, attnum, atttypid, colDef->typename->typmod, sublevels_up); *colvars = lappend(*colvars, varnode); } } } else { /* addRangeTableEntryForFunction should've caught this */ elog(ERROR, "function in FROM has unsupported return type"); } } break; case RTE_JOIN: { /* Join RTE */ ListCell *colname; ListCell *aliasvar; Assert(list_length(rte->eref->colnames) == list_length(rte->joinaliasvars)); varattno = 0; forboth(colname, rte->eref->colnames, aliasvar, rte->joinaliasvars) { Node *avar = (Node *) lfirst(aliasvar); varattno++; /* * During ordinary parsing, there will never be any * deleted columns in the join; but we have to check since * this routine is also used by the rewriter, and joins * found in stored rules might have join columns for * since-deleted columns. This will be signaled by a NULL * Const in the alias-vars list. */ if (IsA(avar, Const)) { if (include_dropped) { if (colnames) *colnames = lappend(*colnames, makeString(pstrdup(""))); if (colvars) *colvars = lappend(*colvars, copyObject(avar)); } continue; } if (colnames) { char *label = strVal(lfirst(colname)); *colnames = lappend(*colnames, makeString(pstrdup(label))); } if (colvars) { Var *varnode; varnode = makeVar(rtindex, varattno, exprType(avar), exprTypmod(avar), sublevels_up); *colvars = lappend(*colvars, varnode); } } } break; default: elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind); }}/* * expandRelation -- expandRTE subroutine */static voidexpandRelation(Oid relid, Alias *eref, int rtindex, int sublevels_up, bool include_dropped, List **colnames, List **colvars){ Relation rel; /* Get the tupledesc and turn it over to expandTupleDesc */ rel = relation_open(relid, AccessShareLock); expandTupleDesc(rel->rd_att, eref, rtindex, sublevels_up, include_dropped, colnames, colvars); relation_close(rel, AccessShareLock);}/* * expandTupleDesc -- expandRTE subroutine */static voidexpandTupleDesc(TupleDesc tupdesc, Alias *eref, int rtindex, int sublevels_up, bool include_dropped, List **colnames, List **colvars){ int maxattrs = tupdesc->natts; int numaliases = list_length(eref->colnames); int varattno; for (varattno = 0; varattno < maxattrs; varattno++) { Form_pg_attribute attr = tupdesc->attrs[varattno]; if (attr->attisdropped) { if (include_dropped) { if (colnames) *colnames = lappend(*colnames, makeString(pstrdup(""))); if (colvars) { /* * can't use atttypid here, but it doesn't really matter * what type the Const claims to be. */ *colvars = lappend(*colvars, makeNullConst(INT4OID)); } } continue; } if (colnames) { char *label; if (varattno < numaliases) label = strVal(list_nth(eref->colnames, varattno)); else label = NameStr(attr->attname); *colnames = lappend(*colnames, makeString(pstrdup(label))); } if (colvars) { Var *varnode; varnode = makeVar(rtindex, attr->attnum, attr->atttypid, attr->atttypmod, sublevels_up); *colvars = lappend(*colvars, varnode); } }}/* * expandRelAttrs - * Workhorse for "*" expansion: produce a list of targetentries * for the attributes of the rte * * As with expandRTE, rtindex/sublevels_up determine the varno/varlevelsup * fields of the Vars produced. pstate->p_next_resno determines the resnos * assigned to the TLEs. */List *expandRelAttrs(ParseState *pstate, RangeTblEntry *rte, int rtindex, int sublevels_up){ List *names, *vars; ListCell *name, *var; List *te_list = NIL; expandRTE(rte, rtindex, sublevels_up, false, &names, &vars); forboth(name, names, var, vars) { char *label = strVal(lfirst(name)); Node *varnode = (Node *) lfirst(var); TargetEntry *te; te = makeTargetEntry((Expr *) varnode, (AttrNumber) pstate->p_next_resno++, label, false); te_list = lappend(te_list, te); } Assert(name == NULL && var == NULL); /* lists not the same length? */ return te_list;}/* * get_rte_attribute_name * Get an attribute name from a RangeTblEntry * * This is unlike get_attname() because we use aliases if available. * In particular, it will work on an RTE for a subselect or join, whereas * get_attname() only works on real relations.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -