setrefs.c

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

C
1,627
字号
				splan->resconstantqual =					fix_scan_expr(glob, splan->resconstantqual, rtoffset);			}			break;		case T_Append:			{				Append	   *splan = (Append *) plan;				/*				 * Append, like Sort et al, doesn't actually evaluate its				 * targetlist or check quals.				 */				set_dummy_tlist_references(plan, rtoffset);				Assert(splan->plan.qual == NIL);				foreach(l, splan->appendplans)				{					lfirst(l) = set_plan_refs(glob,											  (Plan *) lfirst(l),											  rtoffset);				}			}			break;		case T_BitmapAnd:			{				BitmapAnd  *splan = (BitmapAnd *) plan;				/* BitmapAnd works like Append, but has no tlist */				Assert(splan->plan.targetlist == NIL);				Assert(splan->plan.qual == NIL);				foreach(l, splan->bitmapplans)				{					lfirst(l) = set_plan_refs(glob,											  (Plan *) lfirst(l),											  rtoffset);				}			}			break;		case T_BitmapOr:			{				BitmapOr   *splan = (BitmapOr *) plan;				/* BitmapOr works like Append, but has no tlist */				Assert(splan->plan.targetlist == NIL);				Assert(splan->plan.qual == NIL);				foreach(l, splan->bitmapplans)				{					lfirst(l) = set_plan_refs(glob,											  (Plan *) lfirst(l),											  rtoffset);				}			}			break;		default:			elog(ERROR, "unrecognized node type: %d",				 (int) nodeTag(plan));			break;	}	/*	 * Now recurse into child plans, 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.	 */	plan->lefttree = set_plan_refs(glob, plan->lefttree, rtoffset);	plan->righttree = set_plan_refs(glob, plan->righttree, rtoffset);	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(PlannerGlobal *glob,							SubqueryScan *plan,							int rtoffset){	Plan	   *result;	/* First, recursively process the subplan */	plan->subplan = set_plan_references(glob, plan->subplan, plan->subrtable);	/* subrtable is no longer needed in the plan tree */	plan->subrtable = NIL;	if (trivial_subqueryscan(plan))	{		/*		 * We can omit the SubqueryScan node and just pull up the subplan.		 */		ListCell   *lp,				   *lc;		result = plan->subplan;		/* We have to be sure we don't lose any initplans */		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_upper_references() here, because a SubqueryScan will		 * always have been created with correct references to its subplan's		 * outputs to begin with.		 */		plan->scan.scanrelid += rtoffset;		plan->scan.plan.targetlist =			fix_scan_list(glob, plan->scan.plan.targetlist, rtoffset);		plan->scan.plan.qual =			fix_scan_list(glob, plan->scan.plan.qual, rtoffset);		result = (Plan *) plan;	}	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);		TargetEntry *ctle = (TargetEntry *) lfirst(lc);		if (ptle->resjunk != ctle->resjunk)			return false;		/* tlist doesn't match junk status */		/*		 * We accept either a Var referencing the corresponding element of the		 * subplan tlist, or a Const equaling the subplan element. See		 * generate_setop_tlist() for motivation.		 */		if (ptle->expr && IsA(ptle->expr, Var))		{			Var		   *var = (Var *) ptle->expr;			Assert(var->varno == plan->scan.scanrelid);			Assert(var->varlevelsup == 0);			if (var->varattno != attrno)				return false;	/* out of order */		}		else if (ptle->expr && IsA(ptle->expr, Const))		{			if (!equal(ptle->expr, ctle->expr))				return false;		}		else			return false;		attrno++;	}	return true;}/* * copyVar *		Copy a Var node. * * fix_scan_expr and friends do this enough times that it's worth having * a bespoke routine instead of using the generic copyObject() function. */static inline Var *copyVar(Var *var){	Var		   *newvar = (Var *) palloc(sizeof(Var));	*newvar = *var;	return newvar;}/* * fix_scan_expr *		Do set_plan_references processing on a scan-level expression * * This consists of incrementing all Vars' varnos by rtoffset, * looking up operator opcode info for OpExpr and related nodes, * and adding OIDs from regclass Const nodes into glob->relationOids. */static Node *fix_scan_expr(PlannerGlobal *glob, Node *node, int rtoffset){	fix_scan_expr_context context;	context.glob = glob;	context.rtoffset = rtoffset;	if (rtoffset != 0)	{		return fix_scan_expr_mutator(node, &context);	}	else	{		/*		 * If rtoffset == 0, we don't need to change any Vars, which makes		 * it OK to just scribble on the input node tree instead of copying		 * (since the only change, filling in any unset opfuncid fields,		 * is harmless).  This saves just enough cycles to be noticeable on		 * trivial queries.		 */		(void) fix_scan_expr_walker(node, &context);		return node;	}}static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context){	if (node == NULL)		return NULL;	if (IsA(node, Var))	{		Var		   *var = copyVar((Var *) node);		Assert(var->varlevelsup == 0);		/*		 * We should not see any Vars marked INNER, but in a nestloop inner		 * scan there could be OUTER Vars.	Leave them alone.		 */		Assert(var->varno != INNER);		if (var->varno > 0 && var->varno != OUTER)			var->varno += context->rtoffset;		if (var->varnoold > 0)			var->varnoold += context->rtoffset;		return (Node *) var;	}	if (IsA(node, CurrentOfExpr))	{		CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);		Assert(cexpr->cvarno != INNER);		Assert(cexpr->cvarno != OUTER);		cexpr->cvarno += context->rtoffset;		return (Node *) cexpr;	}	/*	 * Since we update opcode info in-place, this part could possibly scribble	 * on the planner's input data structures, but it's OK.	 */	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, NullIfExpr))		set_opfuncid((OpExpr *) node);	/* rely on struct equivalence */	else if (IsA(node, ScalarArrayOpExpr))		set_sa_opfuncid((ScalarArrayOpExpr *) node);	else if (IsA(node, Const))	{		Const	   *con = (Const *) node;		/* Check for regclass reference */		if (ISREGCLASSCONST(con))			context->glob->relationOids =				lappend_oid(context->glob->relationOids,							DatumGetObjectId(con->constvalue));		/* Fall through to let expression_tree_mutator copy it */	}	return expression_tree_mutator(node, fix_scan_expr_mutator,								   (void *) context);}static boolfix_scan_expr_walker(Node *node, fix_scan_expr_context *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, NullIfExpr))		set_opfuncid((OpExpr *) node);	/* rely on struct equivalence */	else if (IsA(node, ScalarArrayOpExpr))		set_sa_opfuncid((ScalarArrayOpExpr *) node);	else if (IsA(node, Const))	{		Const	   *con = (Const *) node;		/* Check for regclass reference */		if (ISREGCLASSCONST(con))			context->glob->relationOids =				lappend_oid(context->glob->relationOids,							DatumGetObjectId(con->constvalue));		return false;	}	return expression_tree_walker(node, fix_scan_expr_walker,								  (void *) context);}/* * set_join_references *	  Modify 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.  Also perform opcode lookup for these *	  expressions. and add regclass OIDs to glob->relationOids. * * 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.  set_inner_join_references does that. */static voidset_join_references(PlannerGlobal *glob, Join *join, int rtoffset){	Plan	   *outer_plan = join->plan.lefttree;	Plan	   *inner_plan = join->plan.righttree;	indexed_tlist *outer_itlist;	indexed_tlist *inner_itlist;	outer_itlist = build_tlist_index(outer_plan->targetlist);	inner_itlist = build_tlist_index(inner_plan->targetlist);	/* All join plans have tlist, qual, and joinqual */	join->plan.targetlist = fix_join_expr(glob,										  join->plan.targetlist,										  outer_itlist,										  inner_itlist,										  (Index) 0,										  rtoffset);	join->plan.qual = fix_join_expr(glob,									join->plan.qual,									outer_itlist,									inner_itlist,									(Index) 0,									rtoffset);	join->joinqual = fix_join_expr(glob,								   join->joinqual,								   outer_itlist,								   inner_itlist,								   (Index) 0,								   rtoffset);	/* Now do join-type-specific stuff */	if (IsA(join, NestLoop))	{		/* This processing is split out to handle possible recursion */		set_inner_join_references(glob, inner_plan, outer_itlist);	}	else if (IsA(join, MergeJoin))	{		MergeJoin  *mj = (MergeJoin *) join;		mj->mergeclauses = fix_join_expr(glob,										 mj->mergeclauses,										 outer_itlist,										 inner_itlist,										 (Index) 0,										 rtoffset);	}	else if (IsA(join, HashJoin))	{		HashJoin   *hj = (HashJoin *) join;		hj->hashclauses = fix_join_expr(glob,										hj->hashclauses,										outer_itlist,										inner_itlist,										(Index) 0,

⌨️ 快捷键说明

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