⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 parse_relation.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
 * * "*" 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 + -