parse_relation.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,944 行 · 第 1/4 页
C
1,944 行
*/ if (result) return result; /* * If the RTE represents a real table, consider system column names. */ if (rte->rtekind == RTE_RELATION) { /* quick check to see if name could be a system column */ attnum = specialAttNum(colname); if (attnum != InvalidAttrNumber) { /* now check to see if column actually is defined */ if (SearchSysCacheExists(ATTNUM, ObjectIdGetDatum(rte->relid), Int16GetDatum(attnum), 0, 0)) { result = (Node *) make_var(pstate, rte, attnum); rte->checkForRead = true; } } } return result;}/* * colNameToVar * Search for an unqualified column name. * If found, return the appropriate Var node (or expression). * If not found, return NULL. If the name proves ambiguous, raise error. * If localonly is true, only names in the innermost query are considered. */Node *colNameToVar(ParseState *pstate, char *colname, bool localonly){ Node *result = NULL; ParseState *orig_pstate = pstate; int levels_up = 0; while (pstate != NULL) { List *ns; /* * We need to look only at top-level namespace items, and even for * those, ignore RTEs that are marked as not inFromCl and not the * query's target relation. */ foreach(ns, pstate->p_namespace) { Node *nsnode = (Node *) lfirst(ns); Node *newresult = NULL; if (IsA(nsnode, RangeTblRef)) { int varno = ((RangeTblRef *) nsnode)->rtindex; RangeTblEntry *rte = rt_fetch(varno, pstate->p_rtable); if (!rte->inFromCl && rte != pstate->p_target_rangetblentry) continue; /* use orig_pstate here to get the right sublevels_up */ newresult = scanRTEForColumn(orig_pstate, rte, colname); } else if (IsA(nsnode, JoinExpr)) { int varno = ((JoinExpr *) nsnode)->rtindex; RangeTblEntry *rte = rt_fetch(varno, pstate->p_rtable); /* joins are always inFromCl, so no need to check */ /* use orig_pstate here to get the right sublevels_up */ newresult = scanRTEForColumn(orig_pstate, rte, colname); } else elog(ERROR, "unrecognized node type: %d", (int) nodeTag(nsnode)); if (newresult) { if (result) ereport(ERROR, (errcode(ERRCODE_AMBIGUOUS_COLUMN), errmsg("column reference \"%s\" is ambiguous", colname))); result = newresult; } } if (result != NULL || localonly) break; /* found, or don't want to look at parent */ pstate = pstate->parentParseState; levels_up++; } return result;}/* * qualifiedNameToVar * Search for a qualified column name: either refname.colname or * schemaname.relname.colname. * * If found, return the appropriate Var node. * If not found, return NULL. If the name proves ambiguous, raise error. */Node *qualifiedNameToVar(ParseState *pstate, char *schemaname, char *refname, char *colname, bool implicitRTEOK){ RangeTblEntry *rte; int sublevels_up; rte = refnameRangeTblEntry(pstate, schemaname, refname, &sublevels_up); if (rte == NULL) { if (!implicitRTEOK) return NULL; rte = addImplicitRTE(pstate, makeRangeVar(schemaname, refname)); } return scanRTEForColumn(pstate, rte, colname);}/* * 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; Alias *eref; int maxattrs; int numaliases; int varattno; 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. */ lockmode = isForUpdate(pstate, refname) ? RowShareLock : AccessShareLock; rel = heap_openrv(relation, lockmode); rte->relid = RelationGetRelid(rel); eref = alias ? (Alias *) copyObject(alias) : makeAlias(refname, NIL); numaliases = length(eref->colnames); /* * Since the rel is open anyway, let's check that the number of column * aliases is reasonable. - Thomas 2000-02-04 */ maxattrs = RelationGetNumberOfAttributes(rel); if (maxattrs < numaliases) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("table \"%s\" has %d columns available but %d columns specified", RelationGetRelationName(rel), maxattrs, numaliases))); /* fill in any unspecified alias columns using actual column names */ for (varattno = numaliases; varattno < maxattrs; varattno++) { char *attrname; attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname)); eref->colnames = lappend(eref->colnames, makeString(attrname)); } rte->eref = 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 read/write 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->checkForRead = true; rte->checkForWrite = false; 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 a relation OID instead of a RangeVar reference. * * Note that an alias clause *must* be supplied. */RangeTblEntry *addRangeTableEntryForRelation(ParseState *pstate, Oid relid, Alias *alias, bool inh, bool inFromCl){ RangeTblEntry *rte = makeNode(RangeTblEntry); char *refname = alias->aliasname; LOCKMODE lockmode; Relation rel; Alias *eref; int maxattrs; int numaliases; int varattno; rte->rtekind = RTE_RELATION; rte->alias = alias; /* * Get the rel's relcache entry. This access 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. */ lockmode = isForUpdate(pstate, refname) ? RowShareLock : AccessShareLock; rel = heap_open(relid, lockmode); rte->relid = relid; eref = (Alias *) copyObject(alias); numaliases = length(eref->colnames); /* * Since the rel is open anyway, let's check that the number of column * aliases is reasonable. - Thomas 2000-02-04 */ maxattrs = RelationGetNumberOfAttributes(rel); if (maxattrs < numaliases) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("table \"%s\" has %d columns available but %d columns specified", RelationGetRelationName(rel), maxattrs, numaliases))); /* fill in any unspecified alias columns using actual column names */ for (varattno = numaliases; varattno < maxattrs; varattno++) { char *attrname; attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname)); eref->colnames = lappend(eref->colnames, makeString(attrname)); } rte->eref = 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 read/write 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->checkForRead = true; rte->checkForWrite = false; 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; List *tlistitem; rte->rtekind = RTE_SUBQUERY; rte->relid = InvalidOid; rte->subquery = subquery; rte->alias = alias; eref = copyObject(alias); numaliases = length(eref->colnames); /* fill in any unspecified alias columns */ varattno = 0; foreach(tlistitem, subquery->targetList) { TargetEntry *te = (TargetEntry *) lfirst(tlistitem); if (te->resdom->resjunk) continue; varattno++; Assert(varattno == te->resdom->resno); if (varattno > numaliases) { char *attrname; attrname = pstrdup(te->resdom->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 read/write access rights. * * Subqueries are never checked for access rights. *---------- */ rte->inh = false; /* never true for subqueries */ rte->inFromCl = inFromCl; rte->checkForRead = false; rte->checkForWrite = false; 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); Oid funcrettype = exprType(funcexpr); char functyptype; Alias *alias = rangefunc->alias; List *coldeflist = rangefunc->coldeflist; Alias *eref; int numaliases; int varattno; rte->rtekind = RTE_FUNCTION; rte->relid = InvalidOid; rte->subquery = NULL; rte->funcexpr = funcexpr; rte->coldeflist = coldeflist; rte->alias = alias; eref = alias ? (Alias *) copyObject(alias) : makeAlias(funcname, NIL); rte->eref = eref; numaliases = length(eref->colnames); /* * Now determine if the function returns a simple or composite type, * and check/add column aliases. */ if (coldeflist != NIL) { /* * we *only* allow a coldeflist for functions returning a RECORD * pseudo-type */ if (funcrettype != RECORDOID) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("a column definition list is only allowed for functions returning \"record\""))); } else { /* * ... and a coldeflist is *required* for functions returning a * RECORD pseudo-type */ if (funcrettype == RECORDOID) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("a column definition list is required for functions returning \"record\""))); } functyptype = get_typtype(funcrettype); if (functyptype == 'c') { /* * Named composite data type, i.e. a table's row type */ Oid funcrelid = typeidTypeRelid(funcrettype); Relation rel; int maxattrs; if (!OidIsValid(funcrelid)) /* shouldn't happen if typtype is * 'c' */ elog(ERROR, "invalid typrelid for complex type %u", funcrettype); /* * Get the rel's relcache entry. This access ensures that we have * an up-to-date relcache entry for the rel. */ rel = relation_open(funcrelid, AccessShareLock); /* * Since the rel is open anyway, let's check that the number of
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?