📄 parse_relation.c
字号:
* * "*" is returned if the given attnum is InvalidAttrNumber --- this case * occurs when a Var represents a whole tuple of a relation. */char *get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum){ if (attnum == InvalidAttrNumber) return "*"; /* * If there is a user-written column alias, use it. */ if (rte->alias && attnum > 0 && attnum <= list_length(rte->alias->colnames)) return strVal(list_nth(rte->alias->colnames, attnum - 1)); /* * If the RTE is a relation, go to the system catalogs not the * eref->colnames list. This is a little slower but it will give the * right answer if the column has been renamed since the eref list was * built (which can easily happen for rules). */ if (rte->rtekind == RTE_RELATION) return get_relid_attribute_name(rte->relid, attnum); /* * Otherwise use the column name from eref. There should always be one. */ if (attnum > 0 && attnum <= list_length(rte->eref->colnames)) return strVal(list_nth(rte->eref->colnames, attnum - 1)); /* else caller gave us a bogus attnum */ elog(ERROR, "invalid attnum %d for rangetable entry %s", attnum, rte->eref->aliasname); return NULL; /* keep compiler quiet */}/* * get_rte_attribute_type * Get attribute type information from a RangeTblEntry */voidget_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum, Oid *vartype, int32 *vartypmod){ switch (rte->rtekind) { case RTE_RELATION: { /* Plain relation RTE --- get the attribute's type info */ HeapTuple tp; Form_pg_attribute att_tup; tp = SearchSysCache(ATTNUM, ObjectIdGetDatum(rte->relid), Int16GetDatum(attnum), 0, 0); if (!HeapTupleIsValid(tp)) /* shouldn't happen */ elog(ERROR, "cache lookup failed for attribute %d of relation %u", attnum, rte->relid); att_tup = (Form_pg_attribute) GETSTRUCT(tp); /* * If dropped column, pretend it ain't there. See notes in * scanRTEForColumn. */ if (att_tup->attisdropped) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column \"%s\" of relation \"%s\" does not exist", NameStr(att_tup->attname), get_rel_name(rte->relid)))); *vartype = att_tup->atttypid; *vartypmod = att_tup->atttypmod; ReleaseSysCache(tp); } break; case RTE_SUBQUERY: { /* Subselect RTE --- get type info from subselect's tlist */ TargetEntry *te = get_tle_by_resno(rte->subquery->targetList, attnum); if (te == NULL || te->resjunk) elog(ERROR, "subquery %s does not have attribute %d", rte->eref->aliasname, attnum); *vartype = exprType((Node *) te->expr); *vartypmod = exprTypmod((Node *) te->expr); } 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 */ Form_pg_attribute att_tup; Assert(tupdesc); /* this is probably a can't-happen case */ if (attnum < 1 || attnum > tupdesc->natts) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column %d of relation \"%s\" does not exist", attnum, rte->eref->aliasname))); att_tup = tupdesc->attrs[attnum - 1]; /* * If dropped column, pretend it ain't there. See notes * in scanRTEForColumn. */ if (att_tup->attisdropped) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column \"%s\" of relation \"%s\" does not exist", NameStr(att_tup->attname), rte->eref->aliasname))); *vartype = att_tup->atttypid; *vartypmod = att_tup->atttypmod; } else if (functypclass == TYPEFUNC_SCALAR) { /* Base data type, i.e. scalar */ *vartype = funcrettype; *vartypmod = -1; } else if (functypclass == TYPEFUNC_RECORD) { ColumnDef *colDef = list_nth(rte->coldeflist, attnum - 1); *vartype = typenameTypeId(colDef->typename); *vartypmod = colDef->typename->typmod; } else { /* addRangeTableEntryForFunction should've caught this */ elog(ERROR, "function in FROM has unsupported return type"); } } break; case RTE_JOIN: { /* * Join RTE --- get type info from join RTE's alias variable */ Node *aliasvar; Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars)); aliasvar = (Node *) list_nth(rte->joinaliasvars, attnum - 1); *vartype = exprType(aliasvar); *vartypmod = exprTypmod(aliasvar); } break; default: elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind); }}/* * get_rte_attribute_is_dropped * Check whether attempted attribute ref is to a dropped column */boolget_rte_attribute_is_dropped(RangeTblEntry *rte, AttrNumber attnum){ bool result; switch (rte->rtekind) { case RTE_RELATION: { /* * Plain relation RTE --- get the attribute's catalog entry */ HeapTuple tp; Form_pg_attribute att_tup; tp = SearchSysCache(ATTNUM, ObjectIdGetDatum(rte->relid), Int16GetDatum(attnum), 0, 0); if (!HeapTupleIsValid(tp)) /* shouldn't happen */ elog(ERROR, "cache lookup failed for attribute %d of relation %u", attnum, rte->relid); att_tup = (Form_pg_attribute) GETSTRUCT(tp); result = att_tup->attisdropped; ReleaseSysCache(tp); } break; case RTE_SUBQUERY: /* Subselect RTEs never have dropped columns */ result = false; break; case RTE_JOIN: { /* * A join RTE would not have dropped columns when constructed, * but one in a stored rule might contain columns that were * dropped from the underlying tables, if said columns are * nowhere explicitly referenced in the rule. This will be * signaled to us by a NULL Const in the joinaliasvars list. */ Var *aliasvar; if (attnum <= 0 || attnum > list_length(rte->joinaliasvars)) elog(ERROR, "invalid varattno %d", attnum); aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1); result = IsA(aliasvar, Const); } break; case RTE_FUNCTION: { /* Function RTE */ Oid funcrettype = exprType(rte->funcexpr); Oid funcrelid = typeidTypeRelid(funcrettype); if (OidIsValid(funcrelid)) { /* * Composite data type, i.e. a table's row type * * Same as ordinary relation RTE */ HeapTuple tp; Form_pg_attribute att_tup; tp = SearchSysCache(ATTNUM, ObjectIdGetDatum(funcrelid), Int16GetDatum(attnum), 0, 0); if (!HeapTupleIsValid(tp)) /* shouldn't happen */ elog(ERROR, "cache lookup failed for attribute %d of relation %u", attnum, funcrelid); att_tup = (Form_pg_attribute) GETSTRUCT(tp); result = att_tup->attisdropped; ReleaseSysCache(tp); } else { /* * Must be a base data type, i.e. scalar */ result = false; } } break; default: elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind); result = false; /* keep compiler quiet */ } return result;}/* * Given a targetlist and a resno, return the matching TargetEntry * * Returns NULL if resno is not present in list. * * Note: we need to search, rather than just indexing with list_nth(), * because not all tlists are sorted by resno. */TargetEntry *get_tle_by_resno(List *tlist, AttrNumber resno){ ListCell *l; foreach(l, tlist) { TargetEntry *tle = (TargetEntry *) lfirst(l); if (tle->resno == resno) return tle; } return NULL;}/* * given relation and att name, return id of variable * * This should only be used if the relation is already * heap_open()'ed. Use the cache version get_attnum() * for access to non-opened relations. */intattnameAttNum(Relation rd, const char *attname, bool sysColOK){ int i; for (i = 0; i < rd->rd_rel->relnatts; i++) { Form_pg_attribute att = rd->rd_att->attrs[i]; if (namestrcmp(&(att->attname), attname) == 0 && !att->attisdropped) return i + 1; } if (sysColOK) { if ((i = specialAttNum(attname)) != InvalidAttrNumber) { if (i != ObjectIdAttributeNumber || rd->rd_rel->relhasoids) return i; } } /* on failure */ ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column \"%s\" of relation \"%s\" does not exist", attname, RelationGetRelationName(rd)))); return InvalidAttrNumber; /* keep compiler quiet */}/* specialAttNum() * * Check attribute name to see if it is "special", e.g. "oid". * - thomas 2000-02-07 * * Note: this only discovers whether the name could be a system attribute. * Caller needs to verify that it really is an attribute of the rel, * at least in the case of "oid", which is now optional. */static intspecialAttNum(const char *attname){ Form_pg_attribute sysatt; sysatt = SystemAttributeByName(attname, true /* "oid" will be accepted */ ); if (sysatt != NULL) return sysatt->attnum; return InvalidAttrNumber;}/* * given attribute id, return name of that attribute * * This should only be used if the relation is already * heap_open()'ed. Use the cache version get_atttype() * for access to non-opened relations. */NameattnumAttName(Relation rd, int attid){ if (attid <= 0) { Form_pg_attribute sysatt; sysatt = SystemAttributeDefinition(attid, rd->rd_rel->relhasoids); return &sysatt->attname; } if (attid > rd->rd_att->natts) elog(ERROR, "invalid attribute number %d", attid); return &rd->rd_att->attrs[attid - 1]->attname;}/* * given attribute id, return type of that attribute * * This should only be used if the relation is already * heap_open()'ed. Use the cache version get_atttype() * for access to non-opened relations. */OidattnumTypeId(Relation rd, int attid){ if (attid <= 0) { Form_pg_attribute sysatt; sysatt = SystemAttributeDefinition(attid, rd->rd_rel->relhasoids); return sysatt->atttypid; } if (attid > rd->rd_att->natts) elog(ERROR, "invalid attribute number %d", attid); return rd->rd_att->attrs[attid - 1]->atttypid;}/* * Generate a warning or error about an implicit RTE, if appropriate. * * If ADD_MISSING_FROM is not enabled, raise an error. Otherwise, emit * a warning. */static voidwarnAutoRange(ParseState *pstate, RangeVar *relation){ RangeTblEntry *rte; int sublevels_up; const char *badAlias = NULL; /* * Check to see if there are any potential matches in the query's * rangetable. This affects the message we provide. */ rte = searchRangeTable(pstate, relation); /* * If we found a match that has an alias and the alias is visible in * the namespace, then the problem is probably use of the relation's * real name instead of its alias, ie "SELECT foo.* FROM foo f". * This mistake is common enough to justify a specific hint. * * If we found a match that doesn't meet those criteria, assume the * problem is illegal use of a relation outside its scope, as in the * MySQL-ism "SELECT ... FROM a, b LEFT JOIN c ON (a.x = c.y)". */ if (rte && rte->alias && strcmp(rte->eref->aliasname, relation->relname) != 0 && refnameRangeTblEntry(pstate, NULL, rte->eref->aliasname, &sublevels_up) == rte) badAlias = rte->eref->aliasname; if (!add_missing_from) { if (rte) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_TABLE), errmsg("invalid reference to FROM-clause entry for table \"%s\"", relation->relname), (badAlias ? errhint("Perhaps you meant to reference the table alias \"%s\".", badAlias) : errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.", rte->eref->aliasname)))); else ereport(ERROR, (errcode(ERRCODE_UNDEFINED_TABLE), (pstate->parentParseState ? errmsg("missing FROM-clause entry in subquery for table \"%s\"", relation->relname) : errmsg("missing FROM-clause entry for table \"%s\"", relation->relname)))); } else { /* just issue a warning */ ereport(NOTICE, (errcode(ERRCODE_UNDEFINED_TABLE), (pstate->parentParseState ? errmsg("adding missing FROM-clause entry in subquery for table \"%s\"", relation->relname) : errmsg("adding missing FROM-clause entry for table \"%s\"", relation->relname)), (badAlias ? errhint("Perhaps you meant to reference the table alias \"%s\".", badAlias) : (rte ? errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.", rte->eref->aliasname) : 0)))); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -