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

📄 parse_clause.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
		}		ereport(ERROR,				(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),		/* translator: %s is name of a SQL construct, eg ORDER BY */				 errmsg("%s position %d is not in select list",						clauseText[clause], target_pos)));	}	/*	 * Otherwise, we have an expression (this is a Postgres extension not	 * found in SQL92).  Convert the untransformed node to a transformed	 * expression, and search for a match in the tlist. NOTE: it doesn't	 * really matter whether there is more than one match.	Also, we are	 * willing to match a resjunk target here, though the above cases must	 * ignore resjunk targets.	 */	expr = transformExpr(pstate, node);	foreach(tl, *tlist)	{		TargetEntry *tle = (TargetEntry *) lfirst(tl);		if (equal(expr, tle->expr))			return tle;	}	/*	 * If no matches, construct a new target entry which is appended to the	 * end of the target list.	This target is given resjunk = TRUE so that it	 * will not be projected into the final tuple.	 */	target_result = transformTargetEntry(pstate, node, expr, NULL, true);	*tlist = lappend(*tlist, target_result);	return target_result;}/* * transformGroupClause - *	  transform a GROUP BY clause * * GROUP BY items will be added to the targetlist (as resjunk columns) * if not already present, so the targetlist must be passed by reference. */List *transformGroupClause(ParseState *pstate, List *grouplist,					 List **targetlist, List *sortClause){	List	   *glist = NIL;	ListCell   *gl;	ListCell   *sortItem;	sortItem = list_head(sortClause);	foreach(gl, grouplist)	{		TargetEntry *tle;		Oid			restype;		Oid			ordering_op;		GroupClause *grpcl;		tle = findTargetlistEntry(pstate, lfirst(gl),								  targetlist, GROUP_CLAUSE);		/* avoid making duplicate grouplist entries */		if (targetIsInSortList(tle, glist))			continue;		/* if tlist item is an UNKNOWN literal, change it to TEXT */		restype = exprType((Node *) tle->expr);		if (restype == UNKNOWNOID)		{			tle->expr = (Expr *) coerce_type(pstate, (Node *) tle->expr,											 restype, TEXTOID, -1,											 COERCION_IMPLICIT,											 COERCE_IMPLICIT_CAST);			restype = TEXTOID;		}		/*		 * If the GROUP BY clause matches the ORDER BY clause, we want to		 * adopt the ordering operators from the latter rather than using the		 * default ops.  This allows "GROUP BY foo ORDER BY foo DESC" to be		 * done with only one sort step.  Note we are assuming that any		 * user-supplied ordering operator will bring equal values together,		 * which is all that GROUP BY needs.		 */		if (sortItem &&			((SortClause *) lfirst(sortItem))->tleSortGroupRef ==			tle->ressortgroupref)		{			ordering_op = ((SortClause *) lfirst(sortItem))->sortop;			sortItem = lnext(sortItem);		}		else		{			ordering_op = ordering_oper_opid(restype);			sortItem = NULL;	/* disregard ORDER BY once match fails */		}		grpcl = makeNode(GroupClause);		grpcl->tleSortGroupRef = assignSortGroupRef(tle, *targetlist);		grpcl->sortop = ordering_op;		glist = lappend(glist, grpcl);	}	return glist;}/* * transformSortClause - *	  transform an ORDER BY clause * * ORDER BY items will be added to the targetlist (as resjunk columns) * if not already present, so the targetlist must be passed by reference. */List *transformSortClause(ParseState *pstate,					List *orderlist,					List **targetlist,					bool resolveUnknown){	List	   *sortlist = NIL;	ListCell   *olitem;	foreach(olitem, orderlist)	{		SortBy	   *sortby = lfirst(olitem);		TargetEntry *tle;		tle = findTargetlistEntry(pstate, sortby->node,								  targetlist, ORDER_CLAUSE);		sortlist = addTargetToSortList(pstate, tle,									   sortlist, *targetlist,									   sortby->sortby_kind,									   sortby->useOp,									   resolveUnknown);	}	return sortlist;}/* * transformDistinctClause - *	  transform a DISTINCT or DISTINCT ON clause * * Since we may need to add items to the query's sortClause list, that list * is passed by reference.	Likewise for the targetlist. */List *transformDistinctClause(ParseState *pstate, List *distinctlist,						List **targetlist, List **sortClause){	List	   *result = NIL;	ListCell   *slitem;	ListCell   *dlitem;	/* No work if there was no DISTINCT clause */	if (distinctlist == NIL)		return NIL;	if (linitial(distinctlist) == NULL)	{		/* We had SELECT DISTINCT */		/*		 * All non-resjunk elements from target list that are not already in		 * the sort list should be added to it.  (We don't really care what		 * order the DISTINCT fields are checked in, so we can leave the		 * user's ORDER BY spec alone, and just add additional sort keys to it		 * to ensure that all targetlist items get sorted.)		 */		*sortClause = addAllTargetsToSortList(pstate,											  *sortClause,											  *targetlist,											  true);		/*		 * Now, DISTINCT list consists of all non-resjunk sortlist items.		 * Actually, all the sortlist items had better be non-resjunk!		 * Otherwise, user wrote SELECT DISTINCT with an ORDER BY item that		 * does not appear anywhere in the SELECT targetlist, and we can't		 * implement that with only one sorting pass...		 */		foreach(slitem, *sortClause)		{			SortClause *scl = (SortClause *) lfirst(slitem);			TargetEntry *tle = get_sortgroupclause_tle(scl, *targetlist);			if (tle->resjunk)				ereport(ERROR,						(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),						 errmsg("for SELECT DISTINCT, ORDER BY expressions must appear in select list")));			else				result = lappend(result, copyObject(scl));		}	}	else	{		/* We had SELECT DISTINCT ON (expr, ...) */		/*		 * If the user writes both DISTINCT ON and ORDER BY, then the two		 * expression lists must match (until one or the other runs out).		 * Otherwise the ORDER BY requires a different sort order than the		 * DISTINCT does, and we can't implement that with only one sort pass		 * (and if we do two passes, the results will be rather		 * unpredictable). However, it's OK to have more DISTINCT ON		 * expressions than ORDER BY expressions; we can just add the extra		 * DISTINCT values to the sort list, much as we did above for ordinary		 * DISTINCT fields.		 *		 * Actually, it'd be OK for the common prefixes of the two lists to		 * match in any order, but implementing that check seems like more		 * trouble than it's worth.		 */		ListCell   *nextsortlist = list_head(*sortClause);		foreach(dlitem, distinctlist)		{			TargetEntry *tle;			tle = findTargetlistEntry(pstate, lfirst(dlitem),									  targetlist, DISTINCT_ON_CLAUSE);			if (nextsortlist != NULL)			{				SortClause *scl = (SortClause *) lfirst(nextsortlist);				if (tle->ressortgroupref != scl->tleSortGroupRef)					ereport(ERROR,							(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),							 errmsg("SELECT DISTINCT ON expressions must match initial ORDER BY expressions")));				result = lappend(result, copyObject(scl));				nextsortlist = lnext(nextsortlist);			}			else			{				*sortClause = addTargetToSortList(pstate, tle,												  *sortClause, *targetlist,												  SORTBY_ASC, NIL, true);				/*				 * Probably, the tle should always have been added at the end				 * of the sort list ... but search to be safe.				 */				foreach(slitem, *sortClause)				{					SortClause *scl = (SortClause *) lfirst(slitem);					if (tle->ressortgroupref == scl->tleSortGroupRef)					{						result = lappend(result, copyObject(scl));						break;					}				}				if (slitem == NULL)		/* should not happen */					elog(ERROR, "failed to add DISTINCT ON clause to target list");			}		}	}	return result;}/* * addAllTargetsToSortList *		Make sure all non-resjunk targets in the targetlist are in the *		ORDER BY list, adding the not-yet-sorted ones to the end of the list. *		This is typically used to help implement SELECT DISTINCT. * * See addTargetToSortList for info about pstate and resolveUnknown inputs. * * Returns the updated ORDER BY list. */List *addAllTargetsToSortList(ParseState *pstate, List *sortlist,						List *targetlist, bool resolveUnknown){	ListCell   *l;	foreach(l, targetlist)	{		TargetEntry *tle = (TargetEntry *) lfirst(l);		if (!tle->resjunk)			sortlist = addTargetToSortList(pstate, tle,										   sortlist, targetlist,										   SORTBY_ASC, NIL,										   resolveUnknown);	}	return sortlist;}/* * addTargetToSortList *		If the given targetlist entry isn't already in the ORDER BY list, *		add it to the end of the list, using the sortop with given name *		or the default sort operator if opname == NIL. * * If resolveUnknown is TRUE, convert TLEs of type UNKNOWN to TEXT.  If not, * do nothing (which implies the search for a sort operator will fail). * pstate should be provided if resolveUnknown is TRUE, but can be NULL * otherwise. * * Returns the updated ORDER BY list. */List *addTargetToSortList(ParseState *pstate, TargetEntry *tle,					List *sortlist, List *targetlist,					int sortby_kind, List *sortby_opname,					bool resolveUnknown){	/* avoid making duplicate sortlist entries */	if (!targetIsInSortList(tle, sortlist))	{		SortClause *sortcl = makeNode(SortClause);		Oid			restype = exprType((Node *) tle->expr);		/* if tlist item is an UNKNOWN literal, change it to TEXT */		if (restype == UNKNOWNOID && resolveUnknown)		{			tle->expr = (Expr *) coerce_type(pstate, (Node *) tle->expr,											 restype, TEXTOID, -1,											 COERCION_IMPLICIT,											 COERCE_IMPLICIT_CAST);			restype = TEXTOID;		}		sortcl->tleSortGroupRef = assignSortGroupRef(tle, targetlist);		switch (sortby_kind)		{			case SORTBY_ASC:				sortcl->sortop = ordering_oper_opid(restype);				break;			case SORTBY_DESC:				sortcl->sortop = reverse_ordering_oper_opid(restype);				break;			case SORTBY_USING:				Assert(sortby_opname != NIL);				sortcl->sortop = compatible_oper_opid(sortby_opname,													  restype,													  restype,													  false);				break;			default:				elog(ERROR, "unrecognized sortby_kind: %d", sortby_kind);				break;		}		sortlist = lappend(sortlist, sortcl);	}	return sortlist;}/* * assignSortGroupRef *	  Assign the targetentry an unused ressortgroupref, if it doesn't *	  already have one.  Return the assigned or pre-existing refnumber. * * 'tlist' is the targetlist containing (or to contain) the given targetentry. */IndexassignSortGroupRef(TargetEntry *tle, List *tlist){	Index		maxRef;	ListCell   *l;	if (tle->ressortgroupref)	/* already has one? */		return tle->ressortgroupref;	/* easiest way to pick an unused refnumber: max used + 1 */	maxRef = 0;	foreach(l, tlist)	{		Index		ref = ((TargetEntry *) lfirst(l))->ressortgroupref;		if (ref > maxRef)			maxRef = ref;	}	tle->ressortgroupref = maxRef + 1;	return tle->ressortgroupref;}/* * targetIsInSortList *		Is the given target item already in the sortlist? * * Works for both SortClause and GroupClause lists.  Note that the main * reason we need this routine (and not just a quick test for nonzeroness * of ressortgroupref) is that a TLE might be in only one of the lists. */booltargetIsInSortList(TargetEntry *tle, List *sortList){	Index		ref = tle->ressortgroupref;	ListCell   *l;	/* no need to scan list if tle has no marker */	if (ref == 0)		return false;	foreach(l, sortList)	{		SortClause *scl = (SortClause *) lfirst(l);		if (scl->tleSortGroupRef == ref)			return true;	}	return false;}

⌨️ 快捷键说明

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