subselect.c

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

C
1,470
字号
		List	   *newargs = NIL;		ListCell   *l;		/* Still at qual top-level */		locContext.isTopQual = context->isTopQual;		foreach(l, ((BoolExpr *) node)->args)		{			Node	   *newarg;			newarg = process_sublinks_mutator(lfirst(l), &locContext);			if (and_clause(newarg))				newargs = list_concat(newargs, ((BoolExpr *) newarg)->args);			else				newargs = lappend(newargs, newarg);		}		return (Node *) make_andclause(newargs);	}	/* otherwise not at qual top-level */	locContext.isTopQual = false;	if (or_clause(node))	{		List	   *newargs = NIL;		ListCell   *l;		foreach(l, ((BoolExpr *) node)->args)		{			Node	   *newarg;			newarg = process_sublinks_mutator(lfirst(l), &locContext);			if (or_clause(newarg))				newargs = list_concat(newargs, ((BoolExpr *) newarg)->args);			else				newargs = lappend(newargs, newarg);		}		return (Node *) make_orclause(newargs);	}	return expression_tree_mutator(node,								   process_sublinks_mutator,								   (void *) &locContext);}/* * SS_finalize_plan - do final sublink processing for a completed Plan. * * This recursively computes the extParam and allParam sets for every Plan * node in the given plan tree.  It also attaches any generated InitPlans * to the top plan node. */voidSS_finalize_plan(PlannerInfo *root, Plan *plan){	Bitmapset  *valid_params,			   *initExtParam,			   *initSetParam;	Cost		initplan_cost;	int			paramid;	ListCell   *l;	/*	 * First, scan the param list to discover the sets of params that are	 * available from outer query levels and my own query level. We do this	 * once to save time in the per-plan recursion steps.  (This calculation	 * is overly generous: it can include a lot of params that actually	 * shouldn't be referenced here.  However, valid_params is just used as	 * a debugging crosscheck, so it's not worth trying to be exact.)	 */	valid_params = NULL;	paramid = 0;	foreach(l, root->glob->paramlist)	{		PlannerParamItem *pitem = (PlannerParamItem *) lfirst(l);		if (pitem->abslevel < root->query_level)		{			/* valid outer-level parameter */			valid_params = bms_add_member(valid_params, paramid);		}		else if (pitem->abslevel == root->query_level &&				 IsA(pitem->item, Param))		{			/* valid local parameter (i.e., a setParam of my child) */			valid_params = bms_add_member(valid_params, paramid);		}		paramid++;	}	/*	 * Now recurse through plan tree.	 */	(void) finalize_plan(root, plan, valid_params);	bms_free(valid_params);	/*	 * Finally, attach any initPlans to the topmost plan node, and add their	 * extParams to the topmost node's, too.  However, any setParams of the	 * initPlans should not be present in the topmost node's extParams, only	 * in its allParams.  (As of PG 8.1, it's possible that some initPlans	 * have extParams that are setParams of other initPlans, so we have to	 * take care of this situation explicitly.)	 *	 * We also add the eval cost of each initPlan to the startup cost of the	 * top node.  This is a conservative overestimate, since in fact each	 * initPlan might be executed later than plan startup, or even not at all.	 */	plan->initPlan = root->init_plans;	root->init_plans = NIL;		/* make sure they're not attached twice */	initExtParam = initSetParam = NULL;	initplan_cost = 0;	foreach(l, plan->initPlan)	{		SubPlan    *initsubplan = (SubPlan *) lfirst(l);		Plan	   *initplan = planner_subplan_get_plan(root, initsubplan);		ListCell   *l2;		initExtParam = bms_add_members(initExtParam, initplan->extParam);		foreach(l2, initsubplan->setParam)		{			initSetParam = bms_add_member(initSetParam, lfirst_int(l2));		}		initplan_cost += get_initplan_cost(root, initsubplan);	}	/* allParam must include all these params */	plan->allParam = bms_add_members(plan->allParam, initExtParam);	plan->allParam = bms_add_members(plan->allParam, initSetParam);	/* extParam must include any child extParam */	plan->extParam = bms_add_members(plan->extParam, initExtParam);	/* but extParam shouldn't include any setParams */	plan->extParam = bms_del_members(plan->extParam, initSetParam);	/* ensure extParam is exactly NULL if it's empty */	if (bms_is_empty(plan->extParam))		plan->extParam = NULL;	plan->startup_cost += initplan_cost;	plan->total_cost += initplan_cost;}/* * Recursive processing of all nodes in the plan tree * * The return value is the computed allParam set for the given Plan node. * This is just an internal notational convenience. */static Bitmapset *finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params){	finalize_primnode_context context;	if (plan == NULL)		return NULL;	context.root = root;	context.paramids = NULL;	/* initialize set to empty */	/*	 * When we call finalize_primnode, context.paramids sets are automatically	 * merged together.  But when recursing to self, we have to do it the hard	 * way.  We want the paramids set to include params in subplans as well as	 * at this level.	 */	/* Find params in targetlist and qual */	finalize_primnode((Node *) plan->targetlist, &context);	finalize_primnode((Node *) plan->qual, &context);	/* Check additional node-type-specific fields */	switch (nodeTag(plan))	{		case T_Result:			finalize_primnode(((Result *) plan)->resconstantqual,							  &context);			break;		case T_IndexScan:			finalize_primnode((Node *) ((IndexScan *) plan)->indexqual,							  &context);			/*			 * we need not look at indexqualorig, since it will have the same			 * param references as indexqual.			 */			break;		case T_BitmapIndexScan:			finalize_primnode((Node *) ((BitmapIndexScan *) plan)->indexqual,							  &context);			/*			 * we need not look at indexqualorig, since it will have the same			 * param references as indexqual.			 */			break;		case T_BitmapHeapScan:			finalize_primnode((Node *) ((BitmapHeapScan *) plan)->bitmapqualorig,							  &context);			break;		case T_TidScan:			finalize_primnode((Node *) ((TidScan *) plan)->tidquals,							  &context);			break;		case T_SubqueryScan:			/*			 * In a SubqueryScan, SS_finalize_plan has already been run on the			 * subplan by the inner invocation of subquery_planner, so there's			 * no need to do it again.	Instead, just pull out the subplan's			 * extParams list, which represents the params it needs from my			 * level and higher levels.			 */			context.paramids = bms_add_members(context.paramids,								 ((SubqueryScan *) plan)->subplan->extParam);			break;		case T_FunctionScan:			finalize_primnode(((FunctionScan *) plan)->funcexpr,							  &context);			break;		case T_ValuesScan:			finalize_primnode((Node *) ((ValuesScan *) plan)->values_lists,							  &context);			break;		case T_Append:			{				ListCell   *l;				foreach(l, ((Append *) plan)->appendplans)				{					context.paramids =						bms_add_members(context.paramids,										finalize_plan(root,													  (Plan *) lfirst(l),													  valid_params));				}			}			break;		case T_BitmapAnd:			{				ListCell   *l;				foreach(l, ((BitmapAnd *) plan)->bitmapplans)				{					context.paramids =						bms_add_members(context.paramids,										finalize_plan(root,													  (Plan *) lfirst(l),													  valid_params));				}			}			break;		case T_BitmapOr:			{				ListCell   *l;				foreach(l, ((BitmapOr *) plan)->bitmapplans)				{					context.paramids =						bms_add_members(context.paramids,										finalize_plan(root,													  (Plan *) lfirst(l),													  valid_params));				}			}			break;		case T_NestLoop:			finalize_primnode((Node *) ((Join *) plan)->joinqual,							  &context);			break;		case T_MergeJoin:			finalize_primnode((Node *) ((Join *) plan)->joinqual,							  &context);			finalize_primnode((Node *) ((MergeJoin *) plan)->mergeclauses,							  &context);			break;		case T_HashJoin:			finalize_primnode((Node *) ((Join *) plan)->joinqual,							  &context);			finalize_primnode((Node *) ((HashJoin *) plan)->hashclauses,							  &context);			break;		case T_Limit:			finalize_primnode(((Limit *) plan)->limitOffset,							  &context);			finalize_primnode(((Limit *) plan)->limitCount,							  &context);			break;		case T_Hash:		case T_Agg:		case T_SeqScan:		case T_Material:		case T_Sort:		case T_Unique:		case T_SetOp:		case T_Group:			break;		default:			elog(ERROR, "unrecognized node type: %d",				 (int) nodeTag(plan));	}	/* Process left and right child plans, if any */	context.paramids = bms_add_members(context.paramids,									   finalize_plan(root,													 plan->lefttree,													 valid_params));	context.paramids = bms_add_members(context.paramids,									   finalize_plan(root,													 plan->righttree,													 valid_params));	/* Now we have all the paramids */	if (!bms_is_subset(context.paramids, valid_params))		elog(ERROR, "plan should not reference subplan's variable");	/*	 * Note: by definition, extParam and allParam should have the same value	 * in any plan node that doesn't have child initPlans.  We set them	 * equal here, and later SS_finalize_plan will update them properly	 * in node(s) that it attaches initPlans to.	 *	 * For speed at execution time, make sure extParam/allParam are actually	 * NULL if they are empty sets.	 */	if (bms_is_empty(context.paramids))	{		plan->extParam = NULL;		plan->allParam = NULL;	}	else	{		plan->extParam = context.paramids;		plan->allParam = bms_copy(context.paramids);	}	return plan->allParam;}/* * finalize_primnode: add IDs of all PARAM_EXEC params appearing in the given * expression tree to the result set. */static boolfinalize_primnode(Node *node, finalize_primnode_context *context){	if (node == NULL)		return false;	if (IsA(node, Param))	{		if (((Param *) node)->paramkind == PARAM_EXEC)		{			int			paramid = ((Param *) node)->paramid;			context->paramids = bms_add_member(context->paramids, paramid);		}		return false;			/* no more to do here */	}	if (is_subplan(node))	{		SubPlan    *subplan = (SubPlan *) node;		Plan	   *plan = planner_subplan_get_plan(context->root, subplan);		ListCell   *lc;		Bitmapset  *subparamids;		/* Recurse into the testexpr, but not into the Plan */		finalize_primnode(subplan->testexpr, context);		/*		 * Remove any param IDs of output parameters of the subplan that were		 * referenced in the testexpr.  These are not interesting for		 * parameter change signaling since we always re-evaluate the subplan.		 * Note that this wouldn't work too well if there might be uses of the		 * same param IDs elsewhere in the plan, but that can't happen because		 * generate_new_param never tries to merge params.		 */		foreach(lc, subplan->paramIds)		{			context->paramids = bms_del_member(context->paramids,											   lfirst_int(lc));		}		/* Also examine args list */		finalize_primnode((Node *) subplan->args, context);		/*		 * Add params needed by the subplan to paramids, but excluding those		 * we will pass down to it.		 */		subparamids = bms_copy(plan->extParam);		foreach(lc, subplan->parParam)		{			subparamids = bms_del_member(subparamids, lfirst_int(lc));		}		context->paramids = bms_join(context->paramids, subparamids);		return false;			/* no more to do here */	}	return expression_tree_walker(node, finalize_primnode,								  (void *) context);}/* * SS_make_initplan_from_plan - given a plan tree, make it an InitPlan * * The plan is expected to return a scalar value of the indicated type. * We build an EXPR_SUBLINK SubPlan node and put it into the initplan * list for the current query level.  A Param that represents the initplan's * output is returned. * * We assume the plan hasn't been put through SS_finalize_plan. */Param *SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan,						   Oid resulttype, int32 resulttypmod){	List	   *saved_init_plans;	SubPlan    *node;	Param	   *prm;	/*	 * We must run SS_finalize_plan(), since that's normally done before a	 * subplan gets put into the initplan list.  However it will try to attach	 * any pre-existing initplans to this one, which we don't want (they are	 * siblings not children of this initplan).  So, a quick kluge to hide	 * them.  (This is something else that could perhaps be cleaner if we did	 * extParam/allParam processing in setrefs.c instead of here?  See notes	 * for materialize_finished_plan.)	 */	saved_init_plans = root->init_plans;	root->init_plans = NIL;	/*	 * Build extParam/allParam sets for plan nodes.	 */	SS_finalize_plan(root, plan);	/* Restore outer initplan list */	root->init_plans = saved_init_plans;	/*	 * Add the subplan and its rtable to the global lists.	 */	root->glob->subplans = lappend(root->glob->subplans,								   plan);	root->glob->subrtables = lappend(root->glob->subrtables,									 root->parse->rtable);	/*	 * Create a SubPlan node and add it to the outer list of InitPlans.	 */	node = makeNode(SubPlan);	node->subLinkType = EXPR_SUBLINK;	node->firstColType = get_first_col_type(plan);	node->plan_id = list_length(root->glob->subplans);	root->init_plans = lappend(root->init_plans, node);	/*	 * The node can't have any inputs (since it's an initplan), so the	 * parParam and args lists remain empty.	 */	/*	 * Make a Param that will be the subplan's output.	 */	prm = generate_new_param(root, resulttype, resulttypmod);	node->setParam = list_make1_int(prm->paramid);	return prm;}

⌨️ 快捷键说明

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