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

📄 setrefs.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * setrefs.c *	  Post-processing of a completed plan tree: fix references to subplan *	  vars, and compute regproc values for operators * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.97.4.1 2004/05/11 13:15:23 tgl 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/parsetree.h"#include "utils/lsyscache.h"typedef struct{	List	   *rtable;	List	   *outer_tlist;	List	   *inner_tlist;	Index		acceptable_rel;	bool		tlists_have_non_vars;} join_references_context;typedef struct{	Index		subvarno;	List	   *subplan_targetlist;	bool		tlist_has_non_vars;} replace_vars_with_subplan_refs_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_uppernode_references(Plan *plan, Index subvarno);static bool targetlist_has_non_vars(List *tlist);static List *join_references(List *clauses,				List *rtable,				List *outer_tlist,				List *inner_tlist,				Index acceptable_rel,				bool tlists_have_non_vars);static Node *join_references_mutator(Node *node,						join_references_context *context);static Node *replace_vars_with_subplan_refs(Node *node,							   Index subvarno,							   List *subplan_targetlist,							   bool tlist_has_non_vars);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). * *	  set_plan_references recursively traverses the whole plan tree. * * Returns nothing of interest, but modifies internal fields of nodes. */voidset_plan_references(Plan *plan, List *rtable){	List	   *pl;	if (plan == NULL)		return;	/*	 * 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)->indxqual);			fix_expr_references(plan,							(Node *) ((IndexScan *) plan)->indxqualorig);			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:			{				RangeTblEntry *rte;				/*				 * 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.				 */				fix_expr_references(plan, (Node *) plan->targetlist);				fix_expr_references(plan, (Node *) plan->qual);				/* Recurse into subplan too */				rte = rt_fetch(((SubqueryScan *) plan)->scan.scanrelid,							   rtable);				Assert(rte->rtekind == RTE_SUBQUERY);				set_plan_references(((SubqueryScan *) plan)->subplan,									rte->subquery->rtable);			}			break;		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:			/*			 * Hash does not evaluate its targetlist or quals, so don't			 * touch those (see comments below).  But we do need to fix			 * its hashkeys.  The hashkeys are a little bizarre because			 * they need to match the hashclauses of the parent HashJoin			 * node, so we use join_references to fix them.			 */			((Hash *) plan)->hashkeys =				join_references(((Hash *) plan)->hashkeys,								rtable,								NIL,								plan->lefttree->targetlist,								(Index) 0,					targetlist_has_non_vars(plan->lefttree->targetlist));			fix_expr_references(plan,								(Node *) ((Hash *) plan)->hashkeys);			break;		case T_Material:		case T_Sort:		case T_Unique:		case T_SetOp:			/*			 * These plan types don't actually bother to evaluate their			 * targetlists or quals (because they just return their			 * unmodified input tuples).  The optimizer is lazy about			 * creating really valid targetlists for them.	Best to just			 * leave the targetlist alone.	In particular, we do not want			 * to process subplans for them, since we will likely end up			 * reprocessing subplans that also appear in lower levels of			 * the plan tree!			 */			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.			 */			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 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.			 */			foreach(pl, ((Append *) plan)->appendplans)				set_plan_references((Plan *) lfirst(pl), 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.	 */	set_plan_references(plan->lefttree, rtable);	set_plan_references(plan->righttree, rtable);	foreach(pl, plan->initPlan)	{		SubPlan    *sp = (SubPlan *) lfirst(pl);		Assert(IsA(sp, SubPlan));		set_plan_references(sp->plan, sp->rtable);	}}/* * fix_expr_references *	  Do final cleanup on expressions (targetlists or quals). * * This consists of looking up operator opcode info for OpExpr nodes * and recursively performing set_plan_references on subplans. * * The Plan argument is currently unused, but might be needed again someday. */static voidfix_expr_references(Plan *plan, Node *node){	/* This tree walk requires no special setup, so away we go... */	fix_expr_references_walker(node, NULL);}static boolfix_expr_references_walker(Node *node, void *context){	if (node == NULL)		return false;	if (IsA(node, OpExpr))		set_opfuncid((OpExpr *) node);	else if (IsA(node, DistinctExpr))		set_opfuncid((OpExpr *) node);	/* rely on struct equivalence */	else if (IsA(node, ScalarArrayOpExpr))		set_sa_opfuncid((ScalarArrayOpExpr *) node);	else if (IsA(node, NullIfExpr))		set_opfuncid((OpExpr *) node);	/* rely on struct equivalence */	else if (IsA(node, SubPlan))	{		SubPlan    *sp = (SubPlan *) node;		set_plan_references(sp->plan, sp->rtable);	}	return expression_tree_walker(node, fix_expr_references_walker, context);}/* * set_join_references *	  Modifies the target list and quals of a join node to reference its *	  subplans, by setting the varnos to OUTER or INNER and setting attno *	  values to the result domain number of either the corresponding outer *	  or inner join tuple item. * * In the case of a nestloop with inner indexscan, we will also need to * apply the same transformation to any outer vars appearing in the * quals of the child indexscan. * *	'join' is a join plan node *	'rtable' is the associated range table */static voidset_join_references(Join *join, List *rtable){	Plan	   *outer_plan = join->plan.lefttree;	Plan	   *inner_plan = join->plan.righttree;	List	   *outer_tlist = outer_plan->targetlist;	List	   *inner_tlist = inner_plan->targetlist;	bool		tlists_have_non_vars;	tlists_have_non_vars = targetlist_has_non_vars(outer_tlist) ||		targetlist_has_non_vars(inner_tlist);	/* All join plans have tlist, qual, and joinqual */	join->plan.targetlist = join_references(join->plan.targetlist,											rtable,											outer_tlist,											inner_tlist,											(Index) 0,											tlists_have_non_vars);	join->plan.qual = join_references(join->plan.qual,									  rtable,									  outer_tlist,									  inner_tlist,									  (Index) 0,									  tlists_have_non_vars);	join->joinqual = join_references(join->joinqual,									 rtable,									 outer_tlist,									 inner_tlist,									 (Index) 0,									 tlists_have_non_vars);	/* Now do join-type-specific stuff */	if (IsA(join, NestLoop))	{		if (IsA(inner_plan, IndexScan))		{			/*			 * An index is being used to reduce the number of tuples			 * scanned in the inner relation.  If there are join clauses			 * being used with the index, we must update their outer-rel			 * var nodes to refer to the outer side of the join.			 */			IndexScan  *innerscan = (IndexScan *) inner_plan;			List	   *indxqualorig = innerscan->indxqualorig;			/* No work needed if indxqual refers only to its own rel... */			if (NumRelids((Node *) indxqualorig) > 1)			{				Index		innerrel = innerscan->scan.scanrelid;				/* only refs to outer vars get changed in the inner qual */				innerscan->indxqualorig = join_references(indxqualorig,														  rtable,														  outer_tlist,														  NIL,														  innerrel,												   tlists_have_non_vars);				innerscan->indxqual = join_references(innerscan->indxqual,													  rtable,													  outer_tlist,													  NIL,													  innerrel,												   tlists_have_non_vars);				/*				 * We must fix the inner qpqual too, if it has join				 * clauses (this could happen if the index is lossy: some				 * indxquals may get rechecked as qpquals).				 */

⌨️ 快捷键说明

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