subselect.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,118 行 · 第 1/3 页

C
1,118
字号
	 * ininfo->sub_targetlist is filled with a list of Vars	 * representing the subselect outputs.	 */	exprs = convert_sublink_opers(sublink->lefthand,								  sublink->operOids,								  subselect->targetList,								  rtindex,								  &ininfo->sub_targetlist);	return (Node *) make_ands_explicit(exprs);}/* * Replace correlation vars (uplevel vars) with Params. * * Uplevel aggregates are replaced, too. * * Note: it is critical that this runs immediately after SS_process_sublinks. * Since we do not recurse into the arguments of uplevel aggregates, they will * get copied to the appropriate subplan args list in the parent query with * uplevel vars not replaced by Params, but only adjusted in level (see * replace_outer_agg).	That's exactly what we want for the vars of the parent * level --- but if an aggregate's argument contains any further-up variables, * they have to be replaced with Params in their turn.	That will happen when * the parent level runs SS_replace_correlation_vars.  Therefore it must do * so after expanding its sublinks to subplans.  And we don't want any steps * in between, else those steps would never get applied to the aggregate * argument expressions, either in the parent or the child level. */Node *SS_replace_correlation_vars(Node *expr){	/* No setup needed for tree walk, so away we go */	return replace_correlation_vars_mutator(expr, NULL);}static Node *replace_correlation_vars_mutator(Node *node, void *context){	if (node == NULL)		return NULL;	if (IsA(node, Var))	{		if (((Var *) node)->varlevelsup > 0)			return (Node *) replace_outer_var((Var *) node);	}	if (IsA(node, Aggref))	{		if (((Aggref *) node)->agglevelsup > 0)			return (Node *) replace_outer_agg((Aggref *) node);	}	return expression_tree_mutator(node,								   replace_correlation_vars_mutator,								   context);}/* * Expand SubLinks to SubPlans in the given expression. * * The isQual argument tells whether or not this expression is a WHERE/HAVING * qualifier expression.  If it is, any sublinks appearing at top level need * not distinguish FALSE from UNKNOWN return values. */Node *SS_process_sublinks(Node *expr, bool isQual){	/* The only context needed is the initial are-we-in-a-qual flag */	return process_sublinks_mutator(expr, &isQual);}static Node *process_sublinks_mutator(Node *node, bool *isTopQual){	bool		locTopQual;	if (node == NULL)		return NULL;	if (IsA(node, SubLink))	{		SubLink    *sublink = (SubLink *) node;		List	   *lefthand;		/*		 * First, recursively process the lefthand-side expressions, if		 * any.		 */		locTopQual = false;		lefthand = (List *)			process_sublinks_mutator((Node *) sublink->lefthand, &locTopQual);		/*		 * Now build the SubPlan node and make the expr to return.		 */		return make_subplan(sublink, lefthand, *isTopQual);	}	/*	 * We should never see a SubPlan expression in the input (since this	 * is the very routine that creates 'em to begin with).  We shouldn't	 * find ourselves invoked directly on a Query, either.	 */	Assert(!is_subplan(node));	Assert(!IsA(node, Query));	/*	 * If we recurse down through anything other than a List node, we are	 * definitely not at top qual level anymore.	 */	if (IsA(node, List))		locTopQual = *isTopQual;	else		locTopQual = false;	return expression_tree_mutator(node,								   process_sublinks_mutator,								   (void *) &locTopQual);}/* * 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. */voidSS_finalize_plan(Plan *plan, List *rtable){	Bitmapset  *outer_params = NULL;	Bitmapset  *valid_params = NULL;	int			paramid;	List	   *lst;	/*	 * 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.	 */	paramid = 0;	foreach(lst, PlannerParamList)	{		PlannerParamItem *pitem = (PlannerParamItem *) lfirst(lst);		if (pitem->abslevel < PlannerQueryLevel)		{			/* valid outer-level parameter */			outer_params = bms_add_member(outer_params, paramid);			valid_params = bms_add_member(valid_params, paramid);		}		else if (pitem->abslevel == PlannerQueryLevel &&				 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(plan, rtable, outer_params, valid_params);	bms_free(outer_params);	bms_free(valid_params);}/* * 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(Plan *plan, List *rtable,			  Bitmapset *outer_params, Bitmapset *valid_params){	finalize_primnode_context context;	List	   *lst;	if (plan == NULL)		return NULL;	context.paramids = NULL;	/* initialize set to empty */	context.outer_params = outer_params;	/*	 * 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)->indxqual,							  &context);			/*			 * we need not look at indxqualorig, since it will have the			 * same param references as indxqual.			 */			break;		case T_TidScan:			finalize_primnode((Node *) ((TidScan *) plan)->tideval,							  &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:			{				RangeTblEntry *rte;				rte = rt_fetch(((FunctionScan *) plan)->scan.scanrelid,							   rtable);				Assert(rte->rtekind == RTE_FUNCTION);				finalize_primnode(rte->funcexpr, &context);			}			break;		case T_Append:			foreach(lst, ((Append *) plan)->appendplans)			{				context.paramids =					bms_add_members(context.paramids,									finalize_plan((Plan *) lfirst(lst),												  rtable,												  outer_params,												  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:			finalize_primnode((Node *) ((Hash *) plan)->hashkeys,							  &context);			break;		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(plan->lefttree,													 rtable,													 outer_params,													 valid_params));	context.paramids = bms_add_members(context.paramids,									   finalize_plan(plan->righttree,													 rtable,													 outer_params,													 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");	plan->extParam = bms_intersect(context.paramids, outer_params);	plan->allParam = context.paramids;	/*	 * For speed at execution time, make sure extParam/allParam are	 * actually NULL if they are empty sets.	 */	if (bms_is_empty(plan->extParam))	{		bms_free(plan->extParam);		plan->extParam = NULL;	}	if (bms_is_empty(plan->allParam))	{		bms_free(plan->allParam);		plan->allParam = NULL;	}	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 = (int) ((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;		/* Add outer-level params needed by the subplan to paramids */		context->paramids = bms_join(context->paramids,								   bms_intersect(subplan->plan->extParam,												 context->outer_params));		/* fall through to recurse into subplan args */	}	return expression_tree_walker(node, finalize_primnode,								  (void *) context);}

⌨️ 快捷键说明

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