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

📄 setrefs.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * setrefs.c *	  Post-processing of a completed plan tree: fix references to subplan *	  vars, and compute regproc values for operators * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.117.2.1 2005/11/22 18:23:11 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "nodes/makefuncs.h"#include "optimizer/clauses.h"#include "optimizer/planmain.h"#include "optimizer/tlist.h"#include "optimizer/var.h"#include "parser/parse_expr.h"#include "parser/parsetree.h"#include "utils/lsyscache.h"typedef struct{	Index		varno;			/* RT index of Var */	AttrNumber	varattno;		/* attr number of Var */	AttrNumber	resno;			/* TLE position of Var */} tlist_vinfo;typedef struct{	List	   *tlist;			/* underlying target list */	int			num_vars;		/* number of plain Var tlist entries */	bool		has_non_vars;	/* are there non-plain-Var entries? */	/* array of num_vars entries: */	tlist_vinfo vars[1];		/* VARIABLE LENGTH ARRAY */} indexed_tlist;				/* VARIABLE LENGTH STRUCT */typedef struct{	List	   *rtable;	indexed_tlist *outer_itlist;	indexed_tlist *inner_itlist;	Index		acceptable_rel;} join_references_context;typedef struct{	indexed_tlist *subplan_itlist;	Index		subvarno;} replace_vars_with_subplan_refs_context;static Plan *set_subqueryscan_references(SubqueryScan *plan, List *rtable);static bool trivial_subqueryscan(SubqueryScan *plan);static void adjust_plan_varnos(Plan *plan, int rtoffset);static void adjust_expr_varnos(Node *node, int rtoffset);static bool adjust_expr_varnos_walker(Node *node, int *context);static void fix_expr_references(Plan *plan, Node *node);static bool fix_expr_references_walker(Node *node, void *context);static void set_join_references(Join *join, List *rtable);static void set_inner_join_references(Plan *inner_plan,						  List *rtable,						  indexed_tlist *outer_itlist);static void set_uppernode_references(Plan *plan, Index subvarno);static indexed_tlist *build_tlist_index(List *tlist);static Var *search_indexed_tlist_for_var(Var *var,							 indexed_tlist *itlist,							 Index newvarno);static Var *search_indexed_tlist_for_non_var(Node *node,								 indexed_tlist *itlist,								 Index newvarno);static List *join_references(List *clauses,				List *rtable,				indexed_tlist *outer_itlist,				indexed_tlist *inner_itlist,				Index acceptable_rel);static Node *join_references_mutator(Node *node,						join_references_context *context);static Node *replace_vars_with_subplan_refs(Node *node,							   indexed_tlist *subplan_itlist,							   Index subvarno);static Node *replace_vars_with_subplan_refs_mutator(Node *node,							replace_vars_with_subplan_refs_context *context);static bool fix_opfuncids_walker(Node *node, void *context);static void set_sa_opfuncid(ScalarArrayOpExpr *opexpr);/***************************************************************************** * *		SUBPLAN REFERENCES * *****************************************************************************//* * set_plan_references * * This is the final processing pass of the planner/optimizer.	The plan * tree is complete; we just have to adjust some representational details * for the convenience of the executor.  We update Vars in upper plan nodes * to refer to the outputs of their subplans, and we compute regproc OIDs * for operators (ie, we look up the function that implements each op). * * We also perform one final optimization step, which is to delete * SubqueryScan plan nodes that aren't doing anything useful (ie, have * no qual and a no-op targetlist).  The reason for doing this last is that * it can't readily be done before set_plan_references, because it would * break set_uppernode_references: the Vars in the subquery's top tlist * won't match up with the Vars in the outer plan tree.  The SubqueryScan * serves a necessary function as a buffer between outer query and subquery * variable numbering ... but the executor doesn't care about that, only the * planner. * * set_plan_references recursively traverses the whole plan tree. * * The return value is normally the same Plan node passed in, but can be * different when the passed-in Plan is a SubqueryScan we decide isn't needed. * * Note: to delete a SubqueryScan, we have to renumber Vars in its child nodes * and append the modified subquery rangetable to the outer rangetable. * Therefore "rtable" is an in/out argument and really should be declared * "List **".  But in the interest of notational simplicity we don't do that. * (Since rtable can't be NIL if there's a SubqueryScan, the list header * address won't change when we append a subquery rangetable.) */Plan *set_plan_references(Plan *plan, List *rtable){	ListCell   *l;	if (plan == NULL)		return NULL;	/*	 * Plan-type-specific fixes	 */	switch (nodeTag(plan))	{		case T_SeqScan:			fix_expr_references(plan, (Node *) plan->targetlist);			fix_expr_references(plan, (Node *) plan->qual);			break;		case T_IndexScan:			fix_expr_references(plan, (Node *) plan->targetlist);			fix_expr_references(plan, (Node *) plan->qual);			fix_expr_references(plan,								(Node *) ((IndexScan *) plan)->indexqual);			fix_expr_references(plan,								(Node *) ((IndexScan *) plan)->indexqualorig);			break;		case T_BitmapIndexScan:			/* no need to fix targetlist and qual */			Assert(plan->targetlist == NIL);			Assert(plan->qual == NIL);			fix_expr_references(plan,							 (Node *) ((BitmapIndexScan *) plan)->indexqual);			fix_expr_references(plan,						 (Node *) ((BitmapIndexScan *) plan)->indexqualorig);			break;		case T_BitmapHeapScan:			fix_expr_references(plan, (Node *) plan->targetlist);			fix_expr_references(plan, (Node *) plan->qual);			fix_expr_references(plan,						 (Node *) ((BitmapHeapScan *) plan)->bitmapqualorig);			break;		case T_TidScan:			fix_expr_references(plan, (Node *) plan->targetlist);			fix_expr_references(plan, (Node *) plan->qual);			fix_expr_references(plan,								(Node *) ((TidScan *) plan)->tideval);			break;		case T_SubqueryScan:			/* Needs special treatment, see comments below */			return set_subqueryscan_references((SubqueryScan *) plan, rtable);		case T_FunctionScan:			{				RangeTblEntry *rte;				fix_expr_references(plan, (Node *) plan->targetlist);				fix_expr_references(plan, (Node *) plan->qual);				rte = rt_fetch(((FunctionScan *) plan)->scan.scanrelid,							   rtable);				Assert(rte->rtekind == RTE_FUNCTION);				fix_expr_references(plan, rte->funcexpr);			}			break;		case T_NestLoop:			set_join_references((Join *) plan, rtable);			fix_expr_references(plan, (Node *) plan->targetlist);			fix_expr_references(plan, (Node *) plan->qual);			fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);			break;		case T_MergeJoin:			set_join_references((Join *) plan, rtable);			fix_expr_references(plan, (Node *) plan->targetlist);			fix_expr_references(plan, (Node *) plan->qual);			fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);			fix_expr_references(plan,								(Node *) ((MergeJoin *) plan)->mergeclauses);			break;		case T_HashJoin:			set_join_references((Join *) plan, rtable);			fix_expr_references(plan, (Node *) plan->targetlist);			fix_expr_references(plan, (Node *) plan->qual);			fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);			fix_expr_references(plan,								(Node *) ((HashJoin *) plan)->hashclauses);			break;		case T_Hash:		case T_Material:		case T_Sort:		case T_Unique:		case T_SetOp:			/*			 * These plan types don't actually bother to evaluate their			 * targetlists (because they just return their unmodified input			 * tuples).  The optimizer is lazy about creating really valid			 * targetlists for them --- it tends to just put in a pointer to			 * the child plan node's tlist.  Hence, we leave the tlist alone.			 * In particular, we do not want to process subplans in the tlist,			 * since we will likely end up reprocessing subplans that also			 * appear in lower levels of the plan tree!			 *			 * Since these plan types don't check quals either, we should not			 * find any qual expression attached to them.			 */			Assert(plan->qual == NIL);			break;		case T_Limit:			/*			 * Like the plan types above, Limit doesn't evaluate its tlist or			 * quals.  It does have live expressions for limit/offset,			 * however.			 */			Assert(plan->qual == NIL);			fix_expr_references(plan, ((Limit *) plan)->limitOffset);			fix_expr_references(plan, ((Limit *) plan)->limitCount);			break;		case T_Agg:		case T_Group:			set_uppernode_references(plan, (Index) 0);			fix_expr_references(plan, (Node *) plan->targetlist);			fix_expr_references(plan, (Node *) plan->qual);			break;		case T_Result:			/*			 * Result may or may not have a subplan; no need to fix up subplan			 * references if it hasn't got one...			 *			 * XXX why does Result use a different subvarno from Agg/Group?			 */			if (plan->lefttree != NULL)				set_uppernode_references(plan, (Index) OUTER);			fix_expr_references(plan, (Node *) plan->targetlist);			fix_expr_references(plan, (Node *) plan->qual);			fix_expr_references(plan, ((Result *) plan)->resconstantqual);			break;		case T_Append:			/*			 * Append, like Sort et al, doesn't actually evaluate its			 * targetlist or check quals, and we haven't bothered to give it			 * its own tlist copy. So, don't fix targetlist/qual. But do			 * recurse into child plans.			 */			Assert(plan->qual == NIL);			foreach(l, ((Append *) plan)->appendplans)				lfirst(l) = set_plan_references((Plan *) lfirst(l), rtable);			break;		case T_BitmapAnd:			/* BitmapAnd works like Append, but has no tlist */			Assert(plan->targetlist == NIL);			Assert(plan->qual == NIL);			foreach(l, ((BitmapAnd *) plan)->bitmapplans)				lfirst(l) = set_plan_references((Plan *) lfirst(l), rtable);			break;		case T_BitmapOr:			/* BitmapOr works like Append, but has no tlist */			Assert(plan->targetlist == NIL);			Assert(plan->qual == NIL);			foreach(l, ((BitmapOr *) plan)->bitmapplans)				lfirst(l) = set_plan_references((Plan *) lfirst(l), rtable);			break;		default:			elog(ERROR, "unrecognized node type: %d",				 (int) nodeTag(plan));			break;	}	/*	 * Now recurse into child plans and initplans, if any	 *	 * NOTE: it is essential that we recurse into child plans AFTER we set	 * subplan references in this plan's tlist and quals.  If we did the	 * reference-adjustments bottom-up, then we would fail to match this	 * plan's var nodes against the already-modified nodes of the children.	 * Fortunately, that consideration doesn't apply to SubPlan nodes; else	 * we'd need two passes over the expression trees.	 */	plan->lefttree = set_plan_references(plan->lefttree, rtable);	plan->righttree = set_plan_references(plan->righttree, rtable);	foreach(l, plan->initPlan)	{		SubPlan    *sp = (SubPlan *) lfirst(l);		Assert(IsA(sp, SubPlan));		sp->plan = set_plan_references(sp->plan, sp->rtable);	}	return plan;}/* * set_subqueryscan_references *		Do set_plan_references processing on a SubqueryScan * * We try to strip out the SubqueryScan entirely; if we can't, we have * to do the normal processing on it. */static Plan *set_subqueryscan_references(SubqueryScan *plan, List *rtable){	Plan	   *result;	RangeTblEntry *rte;	ListCell   *l;	/* First, recursively process the subplan */	rte = rt_fetch(plan->scan.scanrelid, rtable);	Assert(rte->rtekind == RTE_SUBQUERY);	plan->subplan = set_plan_references(plan->subplan,										rte->subquery->rtable);	/*	 * We have to process any initplans too; set_plan_references can't do it	 * for us because of the possibility of double-processing.	 */	foreach(l, plan->scan.plan.initPlan)	{		SubPlan    *sp = (SubPlan *) lfirst(l);		Assert(IsA(sp, SubPlan));		sp->plan = set_plan_references(sp->plan, sp->rtable);	}	if (trivial_subqueryscan(plan))	{		/*		 * We can omit the SubqueryScan node and just pull up the subplan. We		 * have to merge its rtable into the outer rtable, which means		 * adjusting varnos throughout the subtree.		 */		int			rtoffset = list_length(rtable);		List	   *sub_rtable;		ListCell   *lp,				   *lc;		sub_rtable = copyObject(rte->subquery->rtable);		range_table_walker(sub_rtable,						   adjust_expr_varnos_walker,						   (void *) &rtoffset,						   QTW_IGNORE_RT_SUBQUERIES);		rtable = list_concat(rtable, sub_rtable);		/*		 * we have to copy the subplan to make sure there are no duplicately		 * linked nodes in it, else adjust_plan_varnos might increment some		 * varnos twice		 */		result = copyObject(plan->subplan);		adjust_plan_varnos(result, rtoffset);		result->initPlan = list_concat(plan->scan.plan.initPlan,									   result->initPlan);		/*		 * We also have to transfer the SubqueryScan's result-column names		 * into the subplan, else columns sent to client will be improperly		 * labeled if this is the topmost plan level.  Copy the "source		 * column" information too.		 */		forboth(lp, plan->scan.plan.targetlist, lc, result->targetlist)		{			TargetEntry *ptle = (TargetEntry *) lfirst(lp);			TargetEntry *ctle = (TargetEntry *) lfirst(lc);			ctle->resname = ptle->resname;			ctle->resorigtbl = ptle->resorigtbl;			ctle->resorigcol = ptle->resorigcol;		}	}	else	{		/*		 * Keep the SubqueryScan node.	We have to do the processing that		 * set_plan_references would otherwise have done on it.  Notice we do		 * not do set_uppernode_references() here, because a SubqueryScan will		 * always have been created with correct references to its subplan's		 * outputs to begin with.		 */		result = (Plan *) plan;		fix_expr_references(result, (Node *) result->targetlist);		fix_expr_references(result, (Node *) result->qual);	}	return result;}/* * trivial_subqueryscan *		Detect whether a SubqueryScan can be deleted from the plan tree. * * We can delete it if it has no qual to check and the targetlist just * regurgitates the output of the child plan. */static booltrivial_subqueryscan(SubqueryScan *plan){	int			attrno;	ListCell   *lp,			   *lc;	if (plan->scan.plan.qual != NIL)		return false;	if (list_length(plan->scan.plan.targetlist) !=		list_length(plan->subplan->targetlist))		return false;			/* tlists not same length */	attrno = 1;	forboth(lp, plan->scan.plan.targetlist, lc, plan->subplan->targetlist)	{		TargetEntry *ptle = (TargetEntry *) lfirst(lp);

⌨️ 快捷键说明

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