setrefs.c

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

C
1,627
字号
/*------------------------------------------------------------------------- * * setrefs.c *	  Post-processing of a completed plan tree: fix references to subplan *	  vars, compute regproc values for operators, etc * * Portions Copyright (c) 1996-2008, 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.141.2.1 2008/06/17 14:51:38 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "catalog/pg_type.h"#include "nodes/makefuncs.h"#include "optimizer/clauses.h"#include "optimizer/planmain.h"#include "optimizer/tlist.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{	PlannerGlobal *glob;	int			rtoffset;} fix_scan_expr_context;typedef struct{	PlannerGlobal *glob;	indexed_tlist *outer_itlist;	indexed_tlist *inner_itlist;	Index		acceptable_rel;	int			rtoffset;} fix_join_expr_context;typedef struct{	PlannerGlobal *glob;	indexed_tlist *subplan_itlist;	int			rtoffset;} fix_upper_expr_context;/* * Check if a Const node is a regclass value.  We accept plain OID too, * since a regclass Const will get folded to that type if it's an argument * to oideq or similar operators.  (This might result in some extraneous * values in a plan's list of relation dependencies, but the worst result * would be occasional useless replans.) */#define ISREGCLASSCONST(con) \	(((con)->consttype == REGCLASSOID || (con)->consttype == OIDOID) && \	 !(con)->constisnull)#define fix_scan_list(glob, lst, rtoffset) \	((List *) fix_scan_expr(glob, (Node *) (lst), rtoffset))static Plan *set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset);static Plan *set_subqueryscan_references(PlannerGlobal *glob,							SubqueryScan *plan,							int rtoffset);static bool trivial_subqueryscan(SubqueryScan *plan);static Node *fix_scan_expr(PlannerGlobal *glob, Node *node, int rtoffset);static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context);static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context);static void set_join_references(PlannerGlobal *glob, Join *join, int rtoffset);static void set_inner_join_references(PlannerGlobal *glob, Plan *inner_plan,						  indexed_tlist *outer_itlist);static void set_upper_references(PlannerGlobal *glob, Plan *plan, int rtoffset);static void set_dummy_tlist_references(Plan *plan, int rtoffset);static indexed_tlist *build_tlist_index(List *tlist);static Var *search_indexed_tlist_for_var(Var *var,							 indexed_tlist *itlist,							 Index newvarno,							 int rtoffset);static Var *search_indexed_tlist_for_non_var(Node *node,								 indexed_tlist *itlist,								 Index newvarno);static List *fix_join_expr(PlannerGlobal *glob,			  List *clauses,			  indexed_tlist *outer_itlist,			  indexed_tlist *inner_itlist,			  Index acceptable_rel, int rtoffset);static Node *fix_join_expr_mutator(Node *node,					  fix_join_expr_context *context);static Node *fix_upper_expr(PlannerGlobal *glob,			   Node *node,			   indexed_tlist *subplan_itlist,			   int rtoffset);static Node *fix_upper_expr_mutator(Node *node,					   fix_upper_expr_context *context);static bool fix_opfuncids_walker(Node *node, void *context);/***************************************************************************** * *		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: * * 1. We flatten the various subquery rangetables into a single list, and * zero out RangeTblEntry fields that are not useful to the executor. * * 2. We adjust Vars in scan nodes to be consistent with the flat rangetable. * * 3. We adjust Vars in upper plan nodes to refer to the outputs of their * subplans. * * 4. We compute regproc OIDs for operators (ie, we look up the function * that implements each op). * * 5. We create a list of OIDs of relations that the plan depends on. * This will be used by plancache.c to drive invalidation of cached plans. * (Someday we might want to generalize this to include other types of * objects, but for now tracking relations seems to solve most problems.) * * 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_upper_references: the Vars in the subquery's top tlist * wouldn'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 after we've flattened the rangetable this is * no longer a problem, since then there's only one rtindex namespace. * * set_plan_references recursively traverses the whole plan tree. * * Inputs: *	glob: global data for planner run *	plan: the topmost node of the plan *	rtable: the rangetable for the current subquery * * 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. * * The flattened rangetable entries are appended to glob->finalrtable, and * the list of relation OIDs is appended to glob->relationOids. * * Notice that we modify Plan nodes in-place, but use expression_tree_mutator * to process targetlist and qual expressions.	We can assume that the Plan * nodes were just built by the planner and are not multiply referenced, but * it's not so safe to assume that for expression tree nodes. */Plan *set_plan_references(PlannerGlobal *glob, Plan *plan, List *rtable){	int			rtoffset = list_length(glob->finalrtable);	ListCell   *lc;	/*	 * In the flat rangetable, we zero out substructure pointers that are not	 * needed by the executor; this reduces the storage space and copying cost	 * for cached plans.  We keep only the alias and eref Alias fields, which	 * are needed by EXPLAIN.	 */	foreach(lc, rtable)	{		RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);		RangeTblEntry *newrte;		/* flat copy to duplicate all the scalar fields */		newrte = (RangeTblEntry *) palloc(sizeof(RangeTblEntry));		memcpy(newrte, rte, sizeof(RangeTblEntry));		/* zap unneeded sub-structure */		newrte->subquery = NULL;		newrte->funcexpr = NULL;		newrte->funccoltypes = NIL;		newrte->funccoltypmods = NIL;		newrte->values_lists = NIL;		newrte->joinaliasvars = NIL;		glob->finalrtable = lappend(glob->finalrtable, newrte);		/*		 * If it's a plain relation RTE, add the table to relationOids.		 *		 * We do this even though the RTE might be unreferenced in the plan		 * tree; this would correspond to cases such as views that were		 * expanded, child tables that were eliminated by constraint		 * exclusion, etc.	Schema invalidation on such a rel must still force		 * rebuilding of the plan.		 *		 * Note we don't bother to avoid duplicate list entries.  We could,		 * but it would probably cost more cycles than it would save.		 */		if (newrte->rtekind == RTE_RELATION)			glob->relationOids = lappend_oid(glob->relationOids,											 newrte->relid);	}	/* Now fix the Plan tree */	return set_plan_refs(glob, plan, rtoffset);}/* * set_plan_refs: recurse through the Plan nodes of a single subquery level */static Plan *set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset){	ListCell   *l;	if (plan == NULL)		return NULL;	/*	 * Plan-type-specific fixes	 */	switch (nodeTag(plan))	{		case T_SeqScan:			{				SeqScan    *splan = (SeqScan *) plan;				splan->scanrelid += rtoffset;				splan->plan.targetlist =					fix_scan_list(glob, splan->plan.targetlist, rtoffset);				splan->plan.qual =					fix_scan_list(glob, splan->plan.qual, rtoffset);			}			break;		case T_IndexScan:			{				IndexScan  *splan = (IndexScan *) plan;				splan->scan.scanrelid += rtoffset;				splan->scan.plan.targetlist =					fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset);				splan->scan.plan.qual =					fix_scan_list(glob, splan->scan.plan.qual, rtoffset);				splan->indexqual =					fix_scan_list(glob, splan->indexqual, rtoffset);				splan->indexqualorig =					fix_scan_list(glob, splan->indexqualorig, rtoffset);			}			break;		case T_BitmapIndexScan:			{				BitmapIndexScan *splan = (BitmapIndexScan *) plan;				splan->scan.scanrelid += rtoffset;				/* no need to fix targetlist and qual */				Assert(splan->scan.plan.targetlist == NIL);				Assert(splan->scan.plan.qual == NIL);				splan->indexqual =					fix_scan_list(glob, splan->indexqual, rtoffset);				splan->indexqualorig =					fix_scan_list(glob, splan->indexqualorig, rtoffset);			}			break;		case T_BitmapHeapScan:			{				BitmapHeapScan *splan = (BitmapHeapScan *) plan;				splan->scan.scanrelid += rtoffset;				splan->scan.plan.targetlist =					fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset);				splan->scan.plan.qual =					fix_scan_list(glob, splan->scan.plan.qual, rtoffset);				splan->bitmapqualorig =					fix_scan_list(glob, splan->bitmapqualorig, rtoffset);			}			break;		case T_TidScan:			{				TidScan    *splan = (TidScan *) plan;				splan->scan.scanrelid += rtoffset;				splan->scan.plan.targetlist =					fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset);				splan->scan.plan.qual =					fix_scan_list(glob, splan->scan.plan.qual, rtoffset);				splan->tidquals =					fix_scan_list(glob, splan->tidquals, rtoffset);			}			break;		case T_SubqueryScan:			/* Needs special treatment, see comments below */			return set_subqueryscan_references(glob,											   (SubqueryScan *) plan,											   rtoffset);		case T_FunctionScan:			{				FunctionScan *splan = (FunctionScan *) plan;				splan->scan.scanrelid += rtoffset;				splan->scan.plan.targetlist =					fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset);				splan->scan.plan.qual =					fix_scan_list(glob, splan->scan.plan.qual, rtoffset);				splan->funcexpr =					fix_scan_expr(glob, splan->funcexpr, rtoffset);			}			break;		case T_ValuesScan:			{				ValuesScan *splan = (ValuesScan *) plan;				splan->scan.scanrelid += rtoffset;				splan->scan.plan.targetlist =					fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset);				splan->scan.plan.qual =					fix_scan_list(glob, splan->scan.plan.qual, rtoffset);				splan->values_lists =					fix_scan_list(glob, splan->values_lists, rtoffset);			}			break;		case T_NestLoop:		case T_MergeJoin:		case T_HashJoin:			set_join_references(glob, (Join *) plan, rtoffset);			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.	Even though the targetlist won't be used by the			 * executor, we fix it up for possible use by EXPLAIN (not to			 * mention ease of debugging --- wrong varnos are very confusing).			 */			set_dummy_tlist_references(plan, rtoffset);			/*			 * 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:			{				Limit	   *splan = (Limit *) plan;				/*				 * Like the plan types above, Limit doesn't evaluate its tlist				 * or quals.  It does have live expressions for limit/offset,				 * however; and those cannot contain subplan variable refs, so				 * fix_scan_expr works for them.				 */				set_dummy_tlist_references(plan, rtoffset);				Assert(splan->plan.qual == NIL);				splan->limitOffset =					fix_scan_expr(glob, splan->limitOffset, rtoffset);				splan->limitCount =					fix_scan_expr(glob, splan->limitCount, rtoffset);			}			break;		case T_Agg:		case T_Group:			set_upper_references(glob, plan, rtoffset);			break;		case T_Result:			{				Result	   *splan = (Result *) plan;				/*				 * Result may or may not have a subplan; if not, it's more				 * like a scan node than an upper node.				 */				if (splan->plan.lefttree != NULL)					set_upper_references(glob, plan, rtoffset);				else				{					splan->plan.targetlist =						fix_scan_list(glob, splan->plan.targetlist, rtoffset);					splan->plan.qual =						fix_scan_list(glob, splan->plan.qual, rtoffset);				}				/* resconstantqual can't contain any subplan variable refs */

⌨️ 快捷键说明

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