📄 parse_relation.c
字号:
} return scanRTEForColumn(pstate, rte, colname);}/* * buildRelationAliases * Construct the eref column name list for a relation RTE. * This code is also used for the case of a function RTE returning * a named composite type. * * tupdesc: the physical column information * alias: the user-supplied alias, or NULL if none * eref: the eref Alias to store column names in * * eref->colnames is filled in. Also, alias->colnames is rebuilt to insert * empty strings for any dropped columns, so that it will be one-to-one with * physical column numbers. */static voidbuildRelationAliases(TupleDesc tupdesc, Alias *alias, Alias *eref){ int maxattrs = tupdesc->natts; ListCell *aliaslc; int numaliases; int varattno; int numdropped = 0; Assert(eref->colnames == NIL); if (alias) { aliaslc = list_head(alias->colnames); numaliases = list_length(alias->colnames); /* We'll rebuild the alias colname list */ alias->colnames = NIL; } else { aliaslc = NULL; numaliases = 0; } for (varattno = 0; varattno < maxattrs; varattno++) { Form_pg_attribute attr = tupdesc->attrs[varattno]; Value *attrname; if (attr->attisdropped) { /* Always insert an empty string for a dropped column */ attrname = makeString(pstrdup("")); if (aliaslc) alias->colnames = lappend(alias->colnames, attrname); numdropped++; } else if (aliaslc) { /* Use the next user-supplied alias */ attrname = (Value *) lfirst(aliaslc); aliaslc = lnext(aliaslc); alias->colnames = lappend(alias->colnames, attrname); } else { attrname = makeString(pstrdup(NameStr(attr->attname))); /* we're done with the alias if any */ } eref->colnames = lappend(eref->colnames, attrname); } /* Too many user-supplied aliases? */ if (aliaslc) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("table \"%s\" has %d columns available but %d columns specified", eref->aliasname, maxattrs - numdropped, numaliases)));}/* * buildScalarFunctionAlias * Construct the eref column name list for a function RTE, * when the function returns a scalar type (not composite or RECORD). * * funcexpr: transformed expression tree for the function call * funcname: function name (used only for error message) * alias: the user-supplied alias, or NULL if none * eref: the eref Alias to store column names in * * eref->colnames is filled in. */static voidbuildScalarFunctionAlias(Node *funcexpr, char *funcname, Alias *alias, Alias *eref){ char *pname; Assert(eref->colnames == NIL); /* Use user-specified column alias if there is one. */ if (alias && alias->colnames != NIL) { if (list_length(alias->colnames) != 1) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("too many column aliases specified for function %s", funcname))); eref->colnames = copyObject(alias->colnames); return; } /* * If the expression is a simple function call, and the function has a * single OUT parameter that is named, use the parameter's name. */ if (funcexpr && IsA(funcexpr, FuncExpr)) { pname = get_func_result_name(((FuncExpr *) funcexpr)->funcid); if (pname) { eref->colnames = list_make1(makeString(pname)); return; } } /* * Otherwise use the previously-determined alias (not necessarily the * function name!) */ eref->colnames = list_make1(makeString(eref->aliasname));}/* * Add an entry for a relation to the pstate's range table (p_rtable). * * If pstate is NULL, we just build an RTE and return it without adding it * to an rtable list. * * Note: formerly this checked for refname conflicts, but that's wrong. * Caller is responsible for checking for conflicts in the appropriate scope. */RangeTblEntry *addRangeTableEntry(ParseState *pstate, RangeVar *relation, Alias *alias, bool inh, bool inFromCl){ RangeTblEntry *rte = makeNode(RangeTblEntry); char *refname = alias ? alias->aliasname : relation->relname; LOCKMODE lockmode; Relation rel; rte->rtekind = RTE_RELATION; rte->alias = alias; /* * Get the rel's OID. This access also ensures that we have an up-to-date * relcache entry for the rel. Since this is typically the first access * to a rel in a statement, be careful to get the right access level * depending on whether we're doing SELECT FOR UPDATE/SHARE. */ lockmode = isLockedRel(pstate, refname) ? RowShareLock : AccessShareLock; rel = heap_openrv(relation, lockmode); rte->relid = RelationGetRelid(rel); /* * Build the list of effective column names using user-supplied aliases * and/or actual column names. */ rte->eref = makeAlias(refname, NIL); buildRelationAliases(rel->rd_att, alias, rte->eref); /* * Drop the rel refcount, but keep the access lock till end of transaction * so that the table can't be deleted or have its schema modified * underneath us. */ heap_close(rel, NoLock); /*---------- * 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. * * The initial default on access checks is always check-for-READ-access, * which is the right thing for all except target tables. *---------- */ rte->inh = inh; rte->inFromCl = inFromCl; rte->requiredPerms = ACL_SELECT; rte->checkAsUser = InvalidOid; /* not set-uid by default, either */ /* * 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;}/* * Add an entry for a relation to the pstate's range table (p_rtable). * * This is just like addRangeTableEntry() except that it makes an RTE * given an already-open relation instead of a RangeVar reference. */RangeTblEntry *addRangeTableEntryForRelation(ParseState *pstate, Relation rel, Alias *alias, bool inh, bool inFromCl){ RangeTblEntry *rte = makeNode(RangeTblEntry); char *refname = alias ? alias->aliasname : RelationGetRelationName(rel); rte->rtekind = RTE_RELATION; rte->alias = alias; rte->relid = RelationGetRelid(rel); /* * Build the list of effective column names using user-supplied aliases * and/or actual column names. */ rte->eref = makeAlias(refname, NIL); buildRelationAliases(rel->rd_att, alias, rte->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. * * The initial default on access checks is always check-for-READ-access, * which is the right thing for all except target tables. *---------- */ rte->inh = inh; rte->inFromCl = inFromCl; rte->requiredPerms = ACL_SELECT; rte->checkAsUser = InvalidOid; /* not set-uid by default, either */ /* * 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;}/* * Add an entry for a subquery to the pstate's range table (p_rtable). * * This is just like addRangeTableEntry() except that it makes a subquery RTE. * Note that an alias clause *must* be supplied. */RangeTblEntry *addRangeTableEntryForSubquery(ParseState *pstate, Query *subquery, Alias *alias, bool inFromCl){ RangeTblEntry *rte = makeNode(RangeTblEntry); char *refname = alias->aliasname; Alias *eref; int numaliases; int varattno; ListCell *tlistitem; rte->rtekind = RTE_SUBQUERY; rte->relid = InvalidOid; rte->subquery = subquery; rte->alias = alias; eref = copyObject(alias); numaliases = list_length(eref->colnames); /* fill in any unspecified alias columns */ varattno = 0; foreach(tlistitem, subquery->targetList) { TargetEntry *te = (TargetEntry *) lfirst(tlistitem); if (te->resjunk) continue; varattno++; Assert(varattno == te->resno); if (varattno > numaliases) { char *attrname; attrname = pstrdup(te->resname); eref->colnames = lappend(eref->colnames, makeString(attrname)); } } if (varattno < numaliases) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("table \"%s\" has %d columns available but %d columns specified", refname, varattno, 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. * * Subqueries are never checked for access rights. *---------- */ rte->inh = false; /* never true for subqueries */ 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;}/* * Add an entry for a function to the pstate's range table (p_rtable). * * This is just like addRangeTableEntry() except that it makes a function RTE. */RangeTblEntry *addRangeTableEntryForFunction(ParseState *pstate, char *funcname, Node *funcexpr, RangeFunction *rangefunc, bool inFromCl){ RangeTblEntry *rte = makeNode(RangeTblEntry); TypeFuncClass functypclass; Oid funcrettype; TupleDesc tupdesc; Alias *alias = rangefunc->alias; List *coldeflist = rangefunc->coldeflist; Alias *eref; rte->rtekind = RTE_FUNCTION; rte->relid = InvalidOid; rte->subquery = NULL; rte->funcexpr = funcexpr; rte->coldeflist = coldeflist; rte->alias = alias; eref = makeAlias(alias ? alias->aliasname : funcname, NIL); rte->eref = eref; /* * Now determine if the function returns a simple or composite type. */ functypclass = get_expr_result_type(funcexpr, &funcrettype, &tupdesc); /* * A coldeflist is required if the function returns RECORD and hasn't got * a predetermined record type, and is prohibited otherwise. */ if (coldeflist != NIL) { if (functypclass != TYPEFUNC_RECORD) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("a column definition list is only allowed for functions returning \"record\""))); } else { if (functypclass == TYPEFUNC_RECORD) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("a column definition list is required for functions returning \"record\""))); } if (functypclass == TYPEFUNC_COMPOSITE) { /* Composite data type, e.g. a table's row type */ Assert(tupdesc); /* Build the column alias list */ buildRelationAliases(tupdesc, alias, eref); } else if (functypclass == TYPEFUNC_SCALAR) { /* Base data type, i.e. scalar */ buildScalarFunctionAlias(funcexpr, funcname, alias, eref); } else if (functypclass == TYPEFUNC_RECORD) { ListCell *col; /* Use the column definition list to form the alias list */ foreach(col, coldeflist) { ColumnDef *n = lfirst(col); char *attrname; attrname = pstrdup(n->colname); eref->colnames = lappend(eref->colnames, makeString(attrname)); } } else ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("function \"%s\" in FROM has unsupported return type %s", funcname, format_type_be(funcrettype)))); /*---------- * 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. * * Functions are never checked for access rights (at least, not by * the RTE permissions mechanism). *---------- */ rte->inh = false; /* never true for functions */ 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;}/* * Add an entry for a join to the pstate's range table (p_rtable). * * This is much like addRangeTableEntry() except that it makes a join RTE. */RangeTblEntry *addRangeTableEntryForJoin(ParseState *pstate, List *colnames, JoinType jointype, List *aliasvars, Alias *alias, bool inFromCl){ RangeTblEntry *rte = makeNode(RangeTblEntry); Alias *eref; int numaliases;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -