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 + -
显示快捷键?