parse_relation.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,944 行 · 第 1/4 页

C
1,944
字号
		 * column aliases is reasonable.		 */		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 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));		}		/*		 * 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.		 */		relation_close(rel, NoLock);	}	else if (functyptype == 'b' || functyptype == 'd')	{		/*		 * Must be a base data type, i.e. scalar. Just add one alias		 * column named for the function.		 */		if (numaliases > 1)			ereport(ERROR,					(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),			  errmsg("too many column aliases specified for function %s",					 funcname)));		if (numaliases == 0)			eref->colnames = makeList1(makeString(eref->aliasname));	}	else if (functyptype == 'p' && funcrettype == RECORDOID)	{		List	   *col;		/* Use the column definition list to form the alias list */		eref->colnames = NIL;		foreach(col, coldeflist)		{			ColumnDef  *n = lfirst(col);			char	   *attrname;			attrname = pstrdup(n->colname);			eref->colnames = lappend(eref->colnames, makeString(attrname));		}	}	else		ereport(ERROR,				(errcode(ERRCODE_DATATYPE_MISMATCH),			errmsg("function \"%s\" in FROM has unsupported return type",				   funcname)));	/*----------	 * 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.	 *----------	 */	rte->inh = false;			/* never true for functions */	rte->inFromCl = inFromCl;	rte->checkForRead = true;	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 join to the pstate's range table (p_rtable). * * This is much like addRangeTableEntry() except that it makes a join RTE. */RangeTblEntry *addRangeTableEntryForJoin(ParseState *pstate,						  List *colnames,						  JoinType jointype,						  List *aliasvars,						  Alias *alias,						  bool inFromCl){	RangeTblEntry *rte = makeNode(RangeTblEntry);	Alias	   *eref;	int			numaliases;	rte->rtekind = RTE_JOIN;	rte->relid = InvalidOid;	rte->subquery = NULL;	rte->jointype = jointype;	rte->joinaliasvars = aliasvars;	rte->alias = alias;	eref = alias ? (Alias *) copyObject(alias) : makeAlias("unnamed_join", NIL);	numaliases = length(eref->colnames);	/* fill in any unspecified alias columns */	if (numaliases < length(colnames))	{		while (numaliases-- > 0)			colnames = lnext(colnames);		eref->colnames = nconc(eref->colnames, colnames);	}	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.	 *	 * Joins are never checked for access rights.	 *----------	 */	rte->inh = false;			/* never true for joins */	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;}/* * Has the specified refname been selected FOR UPDATE? */static boolisForUpdate(ParseState *pstate, char *refname){	/* Outer loop to check parent query levels as well as this one */	while (pstate != NULL)	{		if (pstate->p_forUpdate != NIL)		{			if (lfirst(pstate->p_forUpdate) == NULL)			{				/* all tables used in query */				return true;			}			else			{				/* just the named tables */				List	   *l;				foreach(l, pstate->p_forUpdate)				{					char	   *rname = strVal(lfirst(l));					if (strcmp(refname, rname) == 0)						return true;				}			}		}		pstate = pstate->parentParseState;	}	return false;}/* * Add the given RTE as a top-level entry in the pstate's join list * and/or name space list.	(We assume caller has checked for any * namespace conflict.) */voidaddRTEtoQuery(ParseState *pstate, RangeTblEntry *rte,			  bool addToJoinList, bool addToNameSpace){	int			rtindex = RTERangeTablePosn(pstate, rte, NULL);	RangeTblRef *rtr = makeNode(RangeTblRef);	rtr->rtindex = rtindex;	if (addToJoinList)		pstate->p_joinlist = lappend(pstate->p_joinlist, rtr);	if (addToNameSpace)		pstate->p_namespace = lappend(pstate->p_namespace, rtr);}/* * Add a POSTQUEL-style implicit RTE. * * We assume caller has already checked that there is no RTE or join with * a conflicting name. */RangeTblEntry *addImplicitRTE(ParseState *pstate, RangeVar *relation){	RangeTblEntry *rte;	rte = addRangeTableEntry(pstate, relation, NULL, false, false);	addRTEtoQuery(pstate, rte, true, true);	warnAutoRange(pstate, relation);	return rte;}/* expandRTE() * * Given a rangetable entry, create lists of its column names (aliases if * provided, else real names) and Vars for each column.  Only user columns * are considered, since this is primarily used to expand '*' and determine * the contents of JOIN tables. * * If only one of the two kinds of output list is needed, pass NULL for the * output pointer for the unwanted one. */voidexpandRTE(ParseState *pstate, RangeTblEntry *rte,		  List **colnames, List **colvars){	int			rtindex,				sublevels_up,				varattno;	if (colnames)		*colnames = NIL;	if (colvars)		*colvars = NIL;	/* Need the RT index of the entry for creating Vars */	rtindex = RTERangeTablePosn(pstate, rte, &sublevels_up);	switch (rte->rtekind)	{		case RTE_RELATION:			{				/* Ordinary relation RTE */				Relation	rel;				int			maxattrs;				int			numaliases;				rel = heap_open(rte->relid, AccessShareLock);				maxattrs = RelationGetNumberOfAttributes(rel);				numaliases = length(rte->eref->colnames);				for (varattno = 0; varattno < maxattrs; varattno++)				{					Form_pg_attribute attr = rel->rd_att->attrs[varattno];					if (attr->attisdropped)						continue;					if (colnames)					{						char	   *label;						if (varattno < numaliases)							label = strVal(nth(varattno, rte->eref->colnames));						else							label = NameStr(attr->attname);						*colnames = lappend(*colnames, makeString(pstrdup(label)));					}					if (colvars)					{						Var		   *varnode;						varnode = makeVar(rtindex, attr->attnum,										  attr->atttypid, attr->atttypmod,										  sublevels_up);						*colvars = lappend(*colvars, varnode);					}				}				heap_close(rel, AccessShareLock);			}			break;		case RTE_SUBQUERY:			{				/* Subquery RTE */				List	   *aliasp = rte->eref->colnames;				List	   *tlistitem;				varattno = 0;				foreach(tlistitem, rte->subquery->targetList)				{					TargetEntry *te = (TargetEntry *) lfirst(tlistitem);					if (te->resdom->resjunk)						continue;					varattno++;					Assert(varattno == te->resdom->resno);					if (colnames)					{						/* Assume there is one alias per target item */						char	   *label = strVal(lfirst(aliasp));						*colnames = lappend(*colnames, makeString(pstrdup(label)));						aliasp = lnext(aliasp);					}					if (colvars)					{						Var		   *varnode;						varnode = makeVar(rtindex, varattno,										  te->resdom->restype,										  te->resdom->restypmod,										  sublevels_up);						*colvars = lappend(*colvars, varnode);					}				}			}			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);					Relation	rel;					int			maxattrs;					int			numaliases;					if (!OidIsValid(funcrelid)) /* shouldn't happen */						elog(ERROR, "invalid typrelid for complex type %u",							 funcrettype);					rel = relation_open(funcrelid, AccessShareLock);					maxattrs = RelationGetNumberOfAttributes(rel);					numaliases = length(rte->eref->colnames);					for (varattno = 0; varattno < maxattrs; varattno++)					{						Form_pg_attribute attr = rel->rd_att->attrs[varattno];						if (attr->attisdropped)							continue;						if (colnames)						{							char	   *label;							if (varattno < numaliases)								label = strVal(nth(varattno, rte->eref->colnames));							else								label = NameStr(attr->attname);							*colnames = lappend(*colnames, makeString(pstrdup(label)));						}						if (colvars)						{							Var		   *varnode;							varnode = makeVar(rtindex,											  attr->attnum,											  attr->atttypid,											  attr->atttypmod,											  sublevels_up);							*colvars = lappend(*colvars, varnode);						}					}					relation_close(rel, AccessShareLock);				}				else if (functyptype == 'b' || functyptype == 'd')				{					/*					 * Must be a base data type, i.e. scalar					 */					if (colnames)						*colnames = lappend(*colnames,											lfirst(rte->eref->colnames));					if (colvars)					{						Var		   *varnode;						varnode = makeVar(rtindex, 1,										  funcrettype, -1,										  sublevels_up);						*colvars = lappend(*colvars, varnode);					}				}				else if (functyptype == 'p' && funcrettype == RECORDOID)				{					List	   *col;					int			attnum = 0;					foreach(col, coldeflist)					{						ColumnDef  *colDef = lfirst(col);						attnum++;						if (colnames)						{							char	   *attrname;							attrname = pstrdup(colDef->colname);							*colnames = lappend(*colnames, makeString(attrname));						}						if (colvars)						{							Var		   *varnode;							Oid			atttypid;							atttypid = typenameTypeId(colDef->typename);							varnode = makeVar(rtindex,											  attnum,											  atttypid,											  -1,											  sublevels_up);							*colvars = lappend(*colvars, varnode);						}					}				}				else					ereport(ERROR,							(errcode(ERRCODE_DATATYPE_MISMATCH),							 errmsg("function in FROM has unsupported return type")));			}			break;		case RTE_JOIN:			{				/* Join RTE */				List	   *aliasp = rte->eref->colnames;				List	   *aliasvars = rte->joinaliasvars;				varattno = 0;				while (aliasp)				{					Assert(aliasvars);					varattno++;					if (colnames)					{						char	   *label = strVal(lfirst(aliasp));						*colnames = lappend(*colnames, makeString(pstrdup(label)));					}					if (colvars)					{						Node	   *aliasvar = (Node *) lfirst(aliasvars);						Var		   *varnode;						varnode = makeVar(rtindex, varattno,										  exprType(aliasvar),										  exprTypmod(aliasvar),										  sublevels_up);						*colvars = lappend(*colvars, varnode);					}					aliasp = lnext(aliasp);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?