parse_relation.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,944 行 · 第 1/4 页
C
1,944 行
aliasvars = lnext(aliasvars); } Assert(aliasvars == NIL); } break; default: elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind); }}/* * expandRelAttrs - * Workhorse for "*" expansion: produce a list of targetentries * for the attributes of the rte */List *expandRelAttrs(ParseState *pstate, RangeTblEntry *rte){ List *names, *vars; List *te_list = NIL; expandRTE(pstate, rte, &names, &vars); while (names) { char *label = strVal(lfirst(names)); Node *varnode = (Node *) lfirst(vars); TargetEntry *te = makeNode(TargetEntry); te->resdom = makeResdom((AttrNumber) pstate->p_next_resno++, exprType(varnode), exprTypmod(varnode), label, false); te->expr = (Expr *) varnode; te_list = lappend(te_list, te); names = lnext(names); vars = lnext(vars); } Assert(vars == NIL); /* lists not 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. * * "*" 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 <= length(rte->alias->colnames)) return strVal(nth(attnum - 1, rte->alias->colnames)); /* * 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 <= length(rte->eref->colnames)) return strVal(nth(attnum - 1, rte->eref->colnames)); /* 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->resdom->resjunk) elog(ERROR, "subquery %s does not have attribute %d", rte->eref->aliasname, attnum); *vartype = te->resdom->restype; *vartypmod = te->resdom->restypmod; } break; case RTE_FUNCTION: { /* Function RTE */ Oid funcrettype = exprType(rte->funcexpr); char functyptype = get_typtype(funcrettype); List *coldeflist = rte->coldeflist; if (functyptype == 'c') { /* * Composite data type, i.e. a table's row type Same * as ordinary relation RTE */ Oid funcrelid = typeidTypeRelid(funcrettype); HeapTuple tp; Form_pg_attribute att_tup; if (!OidIsValid(funcrelid)) /* shouldn't happen */ elog(ERROR, "invalid typrelid for complex type %u", funcrettype); 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); /* * 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(funcrelid)))); *vartype = att_tup->atttypid; *vartypmod = att_tup->atttypmod; ReleaseSysCache(tp); } else if (functyptype == 'b' || functyptype == 'd') { /* * Must be a base data type, i.e. scalar */ *vartype = funcrettype; *vartypmod = -1; } else if (functyptype == 'p' && funcrettype == RECORDOID) { ColumnDef *colDef = nth(attnum - 1, coldeflist); *vartype = typenameTypeId(colDef->typename); *vartypmod = -1; } else ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("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 <= length(rte->joinaliasvars)); aliasvar = (Node *) nth(attnum - 1, rte->joinaliasvars); *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 */static boolget_rte_attribute_is_dropped(RangeTblEntry *rte, AttrNumber attnum){ bool result; 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); result = att_tup->attisdropped; ReleaseSysCache(tp); } break; case RTE_SUBQUERY: case RTE_JOIN: /* Subselect and join RTEs never have dropped columns */ result = false; 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 nth(), because * not all tlists are sorted by resno. */TargetEntry *get_tle_by_resno(List *tlist, AttrNumber resno){ List *i; foreach(i, tlist) { TargetEntry *tle = (TargetEntry *) lfirst(i); if (tle->resdom->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. * * Our current theory on warnings is that we should allow "SELECT foo.*" * but warn about a mixture of explicit and implicit RTEs. */static voidwarnAutoRange(ParseState *pstate, RangeVar *relation){ bool foundInFromCl = false; List *temp; if (!add_missing_from) { if (pstate->parentParseState != NULL) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_TABLE), errmsg("missing FROM-clause entry in subquery for table \"%s\"", relation->relname))); else ereport(ERROR, (errcode(ERRCODE_UNDEFINED_TABLE), errmsg("missing FROM-clause entry for table \"%s\"", relation->relname))); } foreach(temp, pstate->p_rtable) { RangeTblEntry *rte = lfirst(temp); if (rte->inFromCl) { foundInFromCl = true; break; } } if (foundInFromCl) { if (pstate->parentParseState != NULL) ereport(NOTICE, (errcode(ERRCODE_UNDEFINED_TABLE), errmsg("adding missing FROM-clause entry in subquery for table \"%s\"", relation->relname))); else ereport(NOTICE, (errcode(ERRCODE_UNDEFINED_TABLE), errmsg("adding missing FROM-clause entry for table \"%s\"", relation->relname))); }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?