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