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

📄 prepunion.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 3 页
字号:
	 *	 * Note we disallow any resjunk columns in child results.  This is	 * necessary since the Append node that implements the union won't do	 * any projection, and upper levels will get confused if some of our	 * output tuples have junk and some don't.  This case only arises when	 * we have an EXCEPT or INTERSECT as child, else there won't be	 * resjunk anyway.	 */	return makeList1(recurse_set_operations(setOp, parse,											top_union->colTypes, false,											-1, refnames_tlist));}/* * Generate targetlist for a set-operation plan node * * colTypes: column datatypes for non-junk columns * flag: -1 if no flag column needed, 0 or 1 to create a const flag column * hack_constants: true to copy up constants (see comments in code) * input_tlist: targetlist of this node's input node * refnames_tlist: targetlist to take column names from */static List *generate_setop_tlist(List *colTypes, int flag,					 bool hack_constants,					 List *input_tlist,					 List *refnames_tlist){	List	   *tlist = NIL;	int			resno = 1;	List	   *i;	Resdom	   *resdom;	Node	   *expr;	foreach(i, colTypes)	{		Oid			colType = lfirsto(i);		TargetEntry *inputtle = (TargetEntry *) lfirst(input_tlist);		TargetEntry *reftle = (TargetEntry *) lfirst(refnames_tlist);		int32		colTypmod;		Assert(inputtle->resdom->resno == resno);		Assert(reftle->resdom->resno == resno);		Assert(!inputtle->resdom->resjunk);		Assert(!reftle->resdom->resjunk);		/*		 * Generate columns referencing input columns and having		 * appropriate data types and column names.  Insert datatype		 * coercions where necessary.		 *		 * HACK: constants in the input's targetlist are copied up as-is		 * rather than being referenced as subquery outputs.  This is		 * mainly to ensure that when we try to coerce them to the output		 * column's datatype, the right things happen for UNKNOWN		 * constants.  But do this only at the first level of		 * subquery-scan plans; we don't want phony constants appearing in		 * the output tlists of upper-level nodes!		 */		if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))			expr = (Node *) inputtle->expr;		else			expr = (Node *) makeVar(0,									inputtle->resdom->resno,									inputtle->resdom->restype,									inputtle->resdom->restypmod,									0);		if (inputtle->resdom->restype == colType)		{			/* no coercion needed, and believe the input typmod */			colTypmod = inputtle->resdom->restypmod;		}		else		{			expr = coerce_to_common_type(NULL,	/* no UNKNOWNs here */										 expr,										 colType,										 "UNION/INTERSECT/EXCEPT");			colTypmod = -1;		}		resdom = makeResdom((AttrNumber) resno++,							colType,							colTypmod,							pstrdup(reftle->resdom->resname),							false);		tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr));		input_tlist = lnext(input_tlist);		refnames_tlist = lnext(refnames_tlist);	}	if (flag >= 0)	{		/* Add a resjunk flag column */		resdom = makeResdom((AttrNumber) resno++,							INT4OID,							-1,							pstrdup("flag"),							true);		/* flag value is the given constant */		expr = (Node *) makeConst(INT4OID,								  sizeof(int4),								  Int32GetDatum(flag),								  false,								  true);		tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr));	}	return tlist;}/* * Generate targetlist for a set-operation Append node * * colTypes: column datatypes for non-junk columns * flag: true to create a flag column copied up from subplans * input_plans: list of sub-plans of the Append * refnames_tlist: targetlist to take column names from * * The entries in the Append's targetlist should always be simple Vars; * we just have to make sure they have the right datatypes and typmods. */static List *generate_append_tlist(List *colTypes, bool flag,					  List *input_plans,					  List *refnames_tlist){	List	   *tlist = NIL;	int			resno = 1;	List	   *curColType;	int			colindex;	Resdom	   *resdom;	Node	   *expr;	List	   *planl;	int32	   *colTypmods;	/*	 * First extract typmods to use.	 *	 * If the inputs all agree on type and typmod of a particular column, use	 * that typmod; else use -1.	 */	colTypmods = (int32 *) palloc(length(colTypes) * sizeof(int32));	foreach(planl, input_plans)	{		Plan	   *subplan = (Plan *) lfirst(planl);		List	   *subtlist;		curColType = colTypes;		colindex = 0;		foreach(subtlist, subplan->targetlist)		{			TargetEntry *subtle = (TargetEntry *) lfirst(subtlist);			if (subtle->resdom->resjunk)				continue;			Assert(curColType != NIL);			if (subtle->resdom->restype == lfirsto(curColType))			{				/* If first subplan, copy the typmod; else compare */				if (planl == input_plans)					colTypmods[colindex] = subtle->resdom->restypmod;				else if (subtle->resdom->restypmod != colTypmods[colindex])					colTypmods[colindex] = -1;			}			else			{				/* types disagree, so force typmod to -1 */				colTypmods[colindex] = -1;			}			curColType = lnext(curColType);			colindex++;		}		Assert(curColType == NIL);	}	/*	 * Now we can build the tlist for the Append.	 */	colindex = 0;	foreach(curColType, colTypes)	{		Oid			colType = lfirsto(curColType);		int32		colTypmod = colTypmods[colindex++];		TargetEntry *reftle = (TargetEntry *) lfirst(refnames_tlist);		Assert(reftle->resdom->resno == resno);		Assert(!reftle->resdom->resjunk);		expr = (Node *) makeVar(0,								resno,								colType,								colTypmod,								0);		resdom = makeResdom((AttrNumber) resno++,							colType,							colTypmod,							pstrdup(reftle->resdom->resname),							false);		tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr));		refnames_tlist = lnext(refnames_tlist);	}	if (flag)	{		/* Add a resjunk flag column */		resdom = makeResdom((AttrNumber) resno++,							INT4OID,							-1,							pstrdup("flag"),							true);		/* flag value is shown as copied up from subplan */		expr = (Node *) makeVar(0,								resdom->resno,								INT4OID,								-1,								0);		tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr));	}	pfree(colTypmods);	return tlist;}/* * Does tlist have same datatypes as requested colTypes? * * Resjunk columns are ignored if junkOK is true; otherwise presence of * a resjunk column will always cause a 'false' result. */static booltlist_same_datatypes(List *tlist, List *colTypes, bool junkOK){	List	   *i;	foreach(i, tlist)	{		TargetEntry *tle = (TargetEntry *) lfirst(i);		if (tle->resdom->resjunk)		{			if (!junkOK)				return false;		}		else		{			if (colTypes == NIL)				return false;			if (tle->resdom->restype != lfirsto(colTypes))				return false;			colTypes = lnext(colTypes);		}	}	if (colTypes != NIL)		return false;	return true;}/* * find_all_inheritors - *		Returns a list of relation OIDs including the given rel plus *		all relations that inherit from it, directly or indirectly. */List *find_all_inheritors(Oid parentrel){	List	   *examined_relids = NIL;	List	   *unexamined_relids = makeListo1(parentrel);	/*	 * While the queue of unexamined relids is nonempty, remove the first	 * element, mark it examined, and find its direct descendants. NB:	 * cannot use foreach(), since we modify the queue inside loop.	 */	while (unexamined_relids != NIL)	{		Oid			currentrel = lfirsto(unexamined_relids);		List	   *currentchildren;		unexamined_relids = lnext(unexamined_relids);		examined_relids = lappendo(examined_relids, currentrel);		currentchildren = find_inheritance_children(currentrel);		/*		 * Add to the queue only those children not already seen. This		 * avoids making duplicate entries in case of multiple inheritance		 * paths from the same parent.	(It'll also keep us from getting		 * into an infinite loop, though theoretically there can't be any		 * cycles in the inheritance graph anyway.)		 */		currentchildren = set_differenceo(currentchildren, examined_relids);		unexamined_relids = set_uniono(unexamined_relids, currentchildren);	}	return examined_relids;}/* * expand_inherited_rtentry *		Check whether a rangetable entry represents an inheritance set. *		If so, add entries for all the child tables to the query's *		rangetable, and return an integer list of RT indexes for the *		whole inheritance set (parent and children). *		If not, return NIL. * * When dup_parent is false, the initially given RT index is part of the * returned list (if any).	When dup_parent is true, the given RT index * is *not* in the returned list; a duplicate RTE will be made for the * parent table. * * A childless table is never considered to be an inheritance set; therefore * the result will never be a one-element list.  It'll be either empty * or have two or more elements. * * NOTE: after this routine executes, the specified RTE will always have * its inh flag cleared, whether or not there were any children.  This * ensures we won't expand the same RTE twice, which would otherwise occur * for the case of an inherited UPDATE/DELETE target relation. * * XXX probably should convert the result type to Relids? */List *expand_inherited_rtentry(Query *parse, Index rti, bool dup_parent){	RangeTblEntry *rte = rt_fetch(rti, parse->rtable);	Oid			parentOID;	List	   *inhOIDs;	List	   *inhRTIs;	List	   *l;	/* Does RT entry allow inheritance? */	if (!rte->inh)		return NIL;	Assert(rte->rtekind == RTE_RELATION);	/* Always clear the parent's inh flag, see above comments */	rte->inh = false;	/* Fast path for common case of childless table */	parentOID = rte->relid;	if (!has_subclass(parentOID))		return NIL;	/* Scan for all members of inheritance set */	inhOIDs = find_all_inheritors(parentOID);	/*	 * Check that there's at least one descendant, else treat as no-child	 * case.  This could happen despite above has_subclass() check, if	 * table once had a child but no longer does.	 */	if (lnext(inhOIDs) == NIL)		return NIL;	/* OK, it's an inheritance set; expand it */	if (dup_parent)		inhRTIs = NIL;	else

⌨️ 快捷键说明

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