prepunion.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 1,422 行 · 第 1/3 页

C
1,422
字号
 */static List *generate_setop_tlist(List *colTypes, int flag,					 Index varno,					 bool hack_constants,					 List *input_tlist,					 List *refnames_tlist){	List	   *tlist = NIL;	int			resno = 1;	ListCell   *i,			   *j,			   *k;	TargetEntry *tle;	Node	   *expr;	j = list_head(input_tlist);	k = list_head(refnames_tlist);	foreach(i, colTypes)	{		Oid			colType = lfirst_oid(i);		TargetEntry *inputtle = (TargetEntry *) lfirst(j);		TargetEntry *reftle = (TargetEntry *) lfirst(k);		Assert(inputtle->resno == resno);		Assert(reftle->resno == resno);		Assert(!inputtle->resjunk);		Assert(!reftle->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(varno,									inputtle->resno,									exprType((Node *) inputtle->expr),									exprTypmod((Node *) inputtle->expr),									0);		if (exprType(expr) != colType)		{			expr = coerce_to_common_type(NULL,	/* no UNKNOWNs here */										 expr,										 colType,										 "UNION/INTERSECT/EXCEPT");		}		tle = makeTargetEntry((Expr *) expr,							  (AttrNumber) resno++,							  pstrdup(reftle->resname),							  false);		tlist = lappend(tlist, tle);		j = lnext(j);		k = lnext(k);	}	if (flag >= 0)	{		/* Add a resjunk flag column */		/* flag value is the given constant */		expr = (Node *) makeConst(INT4OID,								  -1,								  sizeof(int4),								  Int32GetDatum(flag),								  false,								  true);		tle = makeTargetEntry((Expr *) expr,							  (AttrNumber) resno++,							  pstrdup("flag"),							  true);		tlist = lappend(tlist, tle);	}	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. * The Vars are always generated with varno 0. */static List *generate_append_tlist(List *colTypes, bool flag,					  List *input_plans,					  List *refnames_tlist){	List	   *tlist = NIL;	int			resno = 1;	ListCell   *curColType;	ListCell   *ref_tl_item;	int			colindex;	TargetEntry *tle;	Node	   *expr;	ListCell   *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(list_length(colTypes) * sizeof(int32));	foreach(planl, input_plans)	{		Plan	   *subplan = (Plan *) lfirst(planl);		ListCell   *subtlist;		curColType = list_head(colTypes);		colindex = 0;		foreach(subtlist, subplan->targetlist)		{			TargetEntry *subtle = (TargetEntry *) lfirst(subtlist);			if (subtle->resjunk)				continue;			Assert(curColType != NULL);			if (exprType((Node *) subtle->expr) == lfirst_oid(curColType))			{				/* If first subplan, copy the typmod; else compare */				int32		subtypmod = exprTypmod((Node *) subtle->expr);				if (planl == list_head(input_plans))					colTypmods[colindex] = subtypmod;				else if (subtypmod != colTypmods[colindex])					colTypmods[colindex] = -1;			}			else			{				/* types disagree, so force typmod to -1 */				colTypmods[colindex] = -1;			}			curColType = lnext(curColType);			colindex++;		}		Assert(curColType == NULL);	}	/*	 * Now we can build the tlist for the Append.	 */	colindex = 0;	forboth(curColType, colTypes, ref_tl_item, refnames_tlist)	{		Oid			colType = lfirst_oid(curColType);		int32		colTypmod = colTypmods[colindex++];		TargetEntry *reftle = (TargetEntry *) lfirst(ref_tl_item);		Assert(reftle->resno == resno);		Assert(!reftle->resjunk);		expr = (Node *) makeVar(0,								resno,								colType,								colTypmod,								0);		tle = makeTargetEntry((Expr *) expr,							  (AttrNumber) resno++,							  pstrdup(reftle->resname),							  false);		tlist = lappend(tlist, tle);	}	if (flag)	{		/* Add a resjunk flag column */		/* flag value is shown as copied up from subplan */		expr = (Node *) makeVar(0,								resno,								INT4OID,								-1,								0);		tle = makeTargetEntry((Expr *) expr,							  (AttrNumber) resno++,							  pstrdup("flag"),							  true);		tlist = lappend(tlist, tle);	}	pfree(colTypmods);	return tlist;}/* * 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	   *rels_list;	ListCell   *l;	/*	 * We build a list starting with the given rel and adding all direct and	 * indirect children.  We can use a single list as both the record of	 * already-found rels and the agenda of rels yet to be scanned for more	 * children.  This is a bit tricky but works because the foreach() macro	 * doesn't fetch the next list element until the bottom of the loop.	 */	rels_list = list_make1_oid(parentrel);	foreach(l, rels_list)	{		Oid			currentrel = lfirst_oid(l);		List	   *currentchildren;		/* Get the direct children of this rel */		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.)		 */		rels_list = list_concat_unique_oid(rels_list, currentchildren);	}	return rels_list;}/* * expand_inherited_tables *		Expand each rangetable entry that represents an inheritance set *		into an "append relation".	At the conclusion of this process, *		the "inh" flag is set in all and only those RTEs that are append *		relation parents. */voidexpand_inherited_tables(PlannerInfo *root){	Index		nrtes;	Index		rti;	ListCell   *rl;	/*	 * expand_inherited_rtentry may add RTEs to parse->rtable; there is no	 * need to scan them since they can't have inh=true.  So just scan as far	 * as the original end of the rtable list.	 */	nrtes = list_length(root->parse->rtable);	rl = list_head(root->parse->rtable);	for (rti = 1; rti <= nrtes; rti++)	{		RangeTblEntry *rte = (RangeTblEntry *) lfirst(rl);		expand_inherited_rtentry(root, rte, rti);		rl = lnext(rl);	}}/* * 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 build AppendRelInfo nodes for all the child tables *		and add them to root->append_rel_list.	If not, clear the entry's *		"inh" flag to prevent later code from looking for AppendRelInfos. * * Note that the original RTE is considered to represent the whole * inheritance set.  The first of the generated RTEs is an RTE for the same * table, but with inh = false, to represent the parent table in its role * as a simple member of the inheritance set. * * A childless table is never considered to be an inheritance set; therefore * a parent RTE must always have at least two associated AppendRelInfos. */static voidexpand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti){	Query	   *parse = root->parse;	Oid			parentOID;	Relation	oldrelation;	LOCKMODE	lockmode;	List	   *inhOIDs;	List	   *appinfos;	ListCell   *l;	/* Does RT entry allow inheritance? */	if (!rte->inh)		return;	/* Ignore any already-expanded UNION ALL nodes */	if (rte->rtekind != RTE_RELATION)	{		Assert(rte->rtekind == RTE_SUBQUERY);		return;	}	/* Fast path for common case of childless table */	parentOID = rte->relid;	if (!has_subclass(parentOID))	{		/* Clear flag before returning */		rte->inh = false;		return;	}	/* 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 (list_length(inhOIDs) < 2)	{		/* Clear flag before returning */		rte->inh = false;		return;	}	/*	 * Must open the parent relation to examine its tupdesc.  We need not lock	 * it since the rewriter already obtained at least AccessShareLock on each	 * relation used in the query.	 */	oldrelation = heap_open(parentOID, NoLock);	/*	 * However, for each child relation we add to the query, we must obtain an	 * appropriate lock, because this will be the first use of those relations	 * in the parse/rewrite/plan pipeline.	 *	 * If the parent relation is the query's result relation, then we need	 * RowExclusiveLock.  Otherwise, check to see if the relation is accessed	 * FOR UPDATE/SHARE or not.  We can't just grab AccessShareLock because	 * then the executor would be trying to upgrade the lock, leading to	 * possible deadlocks.	(This code should match the parser and rewriter.)	 */	if (rti == parse->resultRelation)		lockmode = RowExclusiveLock;	else if (get_rowmark(parse, rti))		lockmode = RowShareLock;	else		lockmode = AccessShareLock;	/* Scan the inheritance set and expand it */	appinfos = NIL;	foreach(l, inhOIDs)	{		Oid			childOID = lfirst_oid(l);		Relation	newrelation;		RangeTblEntry *childrte;		Index		childRTindex;		AppendRelInfo *appinfo;		/*		 * It is possible that the parent table has children that are temp		 * tables of other backends.  We cannot safely access such tables		 * (because of buffering issues), and the best thing to do seems to be		 * to silently ignore them.		 */		if (childOID != parentOID &&			isOtherTempNamespace(get_rel_namespace(childOID)))			continue;		/* Open rel, acquire the appropriate lock type */		if (childOID != parentOID)			newrelation = heap_open(childOID, lockmode);		else			newrelation = oldrelation;		/*		 * Build an RTE for the child, and attach to query's rangetable list.		 * We copy most fields of the parent's RTE, but replace relation OID,		 * and set inh = false.		 */		childrte = copyObject(rte);		childrte->relid = childOID;		childrte->inh = false;		parse->rtable = lappend(parse->rtable, childrte);		childRTindex = list_length(parse->rtable);		/*		 * Build an AppendRelInfo for this parent and child.		 */		appinfo = makeNode(AppendRelInfo);		appinfo->parent_relid = rti;		appinfo->child_relid = childRTindex;		appinfo->parent_reltype = oldrelation->rd_rel->reltype;		appinfo->child_reltype = newrelation->rd_rel->reltype;		make_inh_translation_lists(oldrelation, newrelation, childRTindex,								   &appinfo->col_mappings,								   &appinfo->translated_vars);		appinfo->parent_reloid = parentOID;		appinfos = lappend(appinfos, appinfo);		/* Close child relations, but keep locks */		if (childOID != parentOID)			heap_close(newrelation, NoLock);	}	heap_close(oldrelation, NoLock);	/*	 * If all the children were temp tables, pretend it's a non-inheritance	 * situation.  The duplicate RTE we added for the parent table is	 * harmless, so we don't bother to get rid of it.	 */	if (list_length(appinfos) < 2)	{		/* Clear flag before returning */		rte->inh = false;		return;	}	/* Otherwise, OK to add to root->append_rel_list */	root->append_rel_list = list_concat(root->append_rel_list, appinfos);	/*	 * The executor will check the parent table's access permissions when it	 * examines the parent's added RTE entry.  There's no need to check twice,	 * so turn off access check bits in the original RTE.	 */	rte->requiredPerms = 0;}/* * make_inh_translation_lists *	  Build the lists of translations from parent Vars to child Vars for *	  an inheritance child.  We need both a column number mapping list *	  and a list of Vars representing the child columns. * * For paranoia's sake, we match type as well as attribute name. */static voidmake_inh_translation_lists(Relation oldrelation, Relation newrelation,						   Index newvarno,						   List **col_mappings, List **translated_vars){	List	   *numbers = NIL;	List	   *vars = NIL;	TupleDesc	old_tupdesc = RelationGetDescr(oldrelation);	TupleDesc	new_tupdesc = RelationGetDescr(newrelation);	int			oldnatts = old_tupdesc->natts;	int			newnatts = new_tupdesc->natts;	int			old_attno;	for (old_attno = 0; old_attno < oldnatts; old_attno++)	{		Form_pg_attribute att;		char	   *attname;		Oid			atttypid;		int32		atttypmod;		int			new_attno;		att = old_tupdesc->attrs[old_attno];		if (att->attisdropped)		{			/* Just put 0/NULL into this list entry */			numbers = lappend_int(numbers, 0);

⌨️ 快捷键说明

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