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

📄 parse_clause.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 2 页
字号:
					if (target_result != NULL)						elog(ERROR, "%s BY '%s' is ambiguous", clauseText[clause], name);					else						target_result = target;					/* Stay in loop to check for ambiguity */				}				break;			case T_Ident:				if (strcmp(resname, name) == 0)				{					/*					 * Check for only 1 table & ORDER BY  -ambiguity does					 * not matter here					 */					if (clause == ORDER_CLAUSE && relCnt == 1)						return target;					if (target_result != NULL)						elog(ERROR, "%s BY '%s' is ambiguous", clauseText[clause], name);					else						target_result = target;					/* Stay in loop to check for ambiguity	*/				}				break;			case T_A_Const:				if (target_pos == targetlist_pos)				{					/* Can't be ambigious and we got what we came for  */					return target;				}				break;			case T_FuncCall:			case T_A_Expr:				if (equal(expr, target->expr))				{					/*					 * Check for only 1 table & ORDER BY  -ambiguity does					 * not matter here					 */					if (clause == ORDER_CLAUSE)						return target;					if (target_result != NULL)						elog(ERROR, "GROUP BY has ambiguous expression");					else						target_result = target;				}				break;			default:				elog(ERROR, "Illegal %s BY node = %d", clauseText[clause], nodeTag(node));		}	}	/*	 * If no matches, construct a new target entry which is appended to	 * the end of the target list.	 This target is set to be  resjunk =	 * TRUE so that it will not be projected into the final tuple.	 */	if (target_result == NULL)	{		switch (nodeTag(node))		{			case T_Attr:				target_result = MakeTargetEntryIdent(pstate, node,										 &((Attr *) node)->relname, NULL,										 ((Attr *) node)->relname, true);				lappend(tlist, target_result);				break;			case T_Ident:				target_result = MakeTargetEntryIdent(pstate, node,										   &((Ident *) node)->name, NULL,										   ((Ident *) node)->name, true);				lappend(tlist, target_result);				break;			case T_A_Const:				/*				 * If we got this far, then must have been an out-of-range				 * column number				 */				elog(ERROR, "%s BY position %d is not in target list", clauseText[clause], target_pos);				break;			case T_FuncCall:			case T_A_Expr:				target_result = MakeTargetEntryExpr(pstate, "resjunk", expr, false, true);				lappend(tlist, target_result);				break;			default:				elog(ERROR, "Illegal %s BY node = %d", clauseText[clause], nodeTag(node));				break;		}	}	return target_result;}/* * transformGroupClause - *	  transform a Group By clause * */List *transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist){	List	   *glist = NIL,			   *gl = NIL;	while (grouplist != NIL)	{		GroupClause *grpcl = makeNode(GroupClause);		TargetEntry *restarget;		Resdom	   *resdom;		restarget = findTargetlistEntry(pstate, lfirst(grouplist), targetlist, GROUP_CLAUSE);		resdom = restarget->resdom;		grpcl->grpOpoid = oprid(oper("<",									 resdom->restype,									 resdom->restype, false));		if (glist == NIL)		{			int			groupref = length(glist) + 1;			restarget->resdom->resgroupref = groupref;			grpcl->tleGroupref = groupref;			gl = glist = lcons(grpcl, NIL);		}		else		{			List	   *i;			foreach(i, glist)			{				GroupClause *gcl = (GroupClause *) lfirst(i);				if (equal(get_groupclause_expr(gcl, targetlist),						  restarget->expr))					break;			}			if (i == NIL)		/* not in grouplist already */			{				int			groupref = length(glist) + 1;				restarget->resdom->resgroupref = groupref;				grpcl->tleGroupref = groupref;				lnext(gl) = lcons(grpcl, NIL);				gl = lnext(gl);			}			else				pfree(grpcl);	/* get rid of this */		}		grouplist = lnext(grouplist);	}	return glist;}/* * transformSortClause - *	  transform an Order By clause * */List *transformSortClause(ParseState *pstate,					List *orderlist,					List *sortlist,					List *targetlist,					char *uniqueFlag){	List	   *s = NIL;	while (orderlist != NIL)	{		SortGroupBy *sortby = lfirst(orderlist);		SortClause *sortcl = makeNode(SortClause);		TargetEntry *restarget;		Resdom	   *resdom;		restarget = findTargetlistEntry(pstate, sortby->node, targetlist, ORDER_CLAUSE);		sortcl->resdom = resdom = restarget->resdom;		/*		 * if we have InvalidOid, then this is a NULL field and don't need		 * to sort		 */		if (resdom->restype == InvalidOid)			resdom->restype = INT4OID;		sortcl->opoid = oprid(oper(sortby->useOp,								   resdom->restype,								   resdom->restype, false));		if (sortlist == NIL)			s = sortlist = lcons(sortcl, NIL);		else		{			List	   *i;			foreach(i, sortlist)			{				SortClause *scl = (SortClause *) lfirst(i);				if (scl->resdom == sortcl->resdom)					break;			}			if (i == NIL)		/* not in sortlist already */			{				lnext(s) = lcons(sortcl, NIL);				s = lnext(s);			}			else				pfree(sortcl);	/* get rid of this */		}		orderlist = lnext(orderlist);	}	if (uniqueFlag)	{		List	   *i;		if (uniqueFlag[0] == '*')		{			/*			 * concatenate all elements from target list that are not			 * already in the sortby list			 */			foreach(i, targetlist)			{				TargetEntry *tlelt = (TargetEntry *) lfirst(i);				s = sortlist;				while (s != NIL)				{					SortClause *sortcl = lfirst(s);					/*					 * We use equal() here because we are called for UNION					 * from the optimizer, and at that point, the sort					 * clause resdom pointers don't match the target list					 * resdom pointers					 */					if (equal(sortcl->resdom, tlelt->resdom))						break;					s = lnext(s);				}				if (s == NIL)				{					/* not a member of the sortclauses yet */					SortClause *sortcl = makeNode(SortClause);					if (tlelt->resdom->restype == InvalidOid)						tlelt->resdom->restype = INT4OID;					sortcl->resdom = tlelt->resdom;					sortcl->opoid = any_ordering_op(tlelt->resdom->restype);					sortlist = lappend(sortlist, sortcl);				}			}		}		else		{			TargetEntry *tlelt = NULL;			char	   *uniqueAttrName = uniqueFlag;			/* only create sort clause with the specified unique attribute */			foreach(i, targetlist)			{				tlelt = (TargetEntry *) lfirst(i);				if (strcmp(tlelt->resdom->resname, uniqueAttrName) == 0)					break;			}			if (i == NIL)				elog(ERROR, "All fields in the UNIQUE ON clause must appear in the target list");			foreach(s, sortlist)			{				SortClause *sortcl = lfirst(s);				if (sortcl->resdom == tlelt->resdom)					break;			}			if (s == NIL)			{				/* not a member of the sortclauses yet */				SortClause *sortcl = makeNode(SortClause);				sortcl->resdom = tlelt->resdom;				sortcl->opoid = any_ordering_op(tlelt->resdom->restype);				sortlist = lappend(sortlist, sortcl);			}		}	}	return sortlist;}/* transformUnionClause() * Transform a UNION clause. * Note that the union clause is actually a fully-formed select structure. * So, it is evaluated as a select, then the resulting target fields *	are matched up to ensure correct types in the results. * The select clause parsing is done recursively, so the unions are evaluated *	right-to-left. One might want to look at all columns from all clauses before *	trying to coerce, but unless we keep track of the call depth we won't know *	when to do this because of the recursion. * Let's just try matching in pairs for now (right to left) and see if it works. * - thomas 1998-05-22 */#ifdef NOT_USEDstatic List *transformUnionClause(List *unionClause, List *targetlist){	List	   *union_list = NIL;	List	   *qlist,			   *qlist_item;	if (unionClause)	{		/* recursion */		qlist = parse_analyze(unionClause, NULL);		foreach(qlist_item, qlist)		{			Query	   *query = (Query *) lfirst(qlist_item);			List	   *prev_target = targetlist;			List	   *next_target;			int			prev_len = 0,						next_len = 0;			foreach(prev_target, targetlist)				if (!((TargetEntry *) lfirst(prev_target))->resdom->resjunk)				prev_len++;			foreach(next_target, query->targetList)				if (!((TargetEntry *) lfirst(next_target))->resdom->resjunk)				next_len++;			if (prev_len != next_len)				elog(ERROR, "Each UNION clause must have the same number of columns");			foreach(next_target, query->targetList)			{				Oid			itype;				Oid			otype;				otype = ((TargetEntry *) lfirst(prev_target))->resdom->restype;				itype = ((TargetEntry *) lfirst(next_target))->resdom->restype;				/* one or both is a NULL column? then don't convert... */				if (otype == InvalidOid)				{					/* propagate a known type forward, if available */					if (itype != InvalidOid)						((TargetEntry *) lfirst(prev_target))->resdom->restype = itype;#if FALSE					else					{						((TargetEntry *) lfirst(prev_target))->resdom->restype = UNKNOWNOID;						((TargetEntry *) lfirst(next_target))->resdom->restype = UNKNOWNOID;					}#endif				}				else if (itype == InvalidOid)				{				}				/* they don't match in type? then convert... */				else if (itype != otype)				{					Node	   *expr;					expr = ((TargetEntry *) lfirst(next_target))->expr;					expr = CoerceTargetExpr(NULL, expr, itype, otype);					if (expr == NULL)					{						elog(ERROR, "Unable to transform %s to %s"							 "\n\tEach UNION clause must have compatible target types",							 typeidTypeName(itype),							 typeidTypeName(otype));					}					((TargetEntry *) lfirst(next_target))->expr = expr;					((TargetEntry *) lfirst(next_target))->resdom->restype = otype;				}				/* both are UNKNOWN? then evaluate as text... */				else if (itype == UNKNOWNOID)				{					((TargetEntry *) lfirst(next_target))->resdom->restype = TEXTOID;					((TargetEntry *) lfirst(prev_target))->resdom->restype = TEXTOID;				}				prev_target = lnext(prev_target);			}			union_list = lappend(union_list, query);		}		return union_list;	}	else		return NIL;}#endif

⌨️ 快捷键说明

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