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

📄 subselect.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
			if (use_material)				node->plan = plan = materialize_finished_plan(plan);		}		/* Convert the lefthand exprs and oper OIDs into executable exprs */		node->exprs = convert_sublink_opers(lefthand,											slink->operOids,											plan->targetlist,											0,											&node->paramIds);		/*		 * Make node->args from parParam.		 */		args = NIL;		foreach(l, node->parParam)		{			PlannerParamItem *pitem = list_nth(PlannerParamList, lfirst_int(l));			/*			 * The Var or Aggref has already been adjusted to have the correct			 * varlevelsup or agglevelsup.	We probably don't even need to			 * copy it again, but be safe.			 */			args = lappend(args, copyObject(pitem->item));		}		node->args = args;		result = (Node *) node;	}	return result;}/* * convert_sublink_opers: given a lefthand-expressions list and a list of * operator OIDs, build a list of actually executable expressions.	The * righthand sides of the expressions are Params or Vars representing the * results of the sub-select. * * If rtindex is 0, we build Params to represent the sub-select outputs. * The paramids of the Params created are returned in the *righthandIds list. * * If rtindex is not 0, we build Vars using that rtindex as varno.	Copies * of the Var nodes are returned in *righthandIds (this is a bit of a type * cheat, but we can get away with it). */static List *convert_sublink_opers(List *lefthand, List *operOids,					  List *targetlist, int rtindex,					  List **righthandIds){	List	   *result = NIL;	ListCell   *l,			   *lefthand_item,			   *tlist_item;	*righthandIds = NIL;	lefthand_item = list_head(lefthand);	tlist_item = list_head(targetlist);	foreach(l, operOids)	{		Oid			opid = lfirst_oid(l);		Node	   *leftop = (Node *) lfirst(lefthand_item);		TargetEntry *te = (TargetEntry *) lfirst(tlist_item);		Node	   *rightop;		Operator	tup;		Assert(!te->resjunk);		if (rtindex)		{			/* Make the Var node representing the subplan's result */			rightop = (Node *) makeVar(rtindex,									   te->resno,									   exprType((Node *) te->expr),									   exprTypmod((Node *) te->expr),									   0);			/*			 * Copy it for caller.	NB: we need a copy to avoid having			 * doubly-linked substructure in the modified parse tree.			 */			*righthandIds = lappend(*righthandIds, copyObject(rightop));		}		else		{			/* Make the Param node representing the subplan's result */			Param	   *prm;			prm = generate_new_param(exprType((Node *) te->expr),									 exprTypmod((Node *) te->expr));			/* Record its ID */			*righthandIds = lappend_int(*righthandIds, prm->paramid);			rightop = (Node *) prm;		}		/* Look up the operator to pass to make_op_expr */		tup = SearchSysCache(OPEROID,							 ObjectIdGetDatum(opid),							 0, 0, 0);		if (!HeapTupleIsValid(tup))			elog(ERROR, "cache lookup failed for operator %u", opid);		/*		 * Make the expression node.		 *		 * Note: we use make_op_expr in case runtime type conversion function		 * calls must be inserted for this operator!  (But we are not		 * expecting to have to resolve unknown Params, so it's okay to pass a		 * null pstate.)		 */		result = lappend(result,						 make_op_expr(NULL,									  tup,									  leftop,									  rightop,									  exprType(leftop),									  exprType((Node *) te->expr)));		ReleaseSysCache(tup);		lefthand_item = lnext(lefthand_item);		tlist_item = lnext(tlist_item);	}	return result;}/* * subplan_is_hashable: decide whether we can implement a subplan by hashing * * Caution: the SubPlan node is not completely filled in yet.  We can rely * on its plan and parParam fields, however. */static boolsubplan_is_hashable(SubLink *slink, SubPlan *node){	double		subquery_size;	ListCell   *l;	/*	 * The sublink type must be "= ANY" --- that is, an IN operator. (We	 * require the operator name to be unqualified, which may be overly	 * paranoid, or may not be.)  XXX since we also check that the operators	 * are hashable, the test on operator name may be redundant?	 */	if (slink->subLinkType != ANY_SUBLINK)		return false;	if (list_length(slink->operName) != 1 ||		strcmp(strVal(linitial(slink->operName)), "=") != 0)		return false;	/*	 * The subplan must not have any direct correlation vars --- else we'd	 * have to recompute its output each time, so that the hashtable wouldn't	 * gain anything.	 */	if (node->parParam != NIL)		return false;	/*	 * The estimated size of the subquery result must fit in work_mem. (XXX	 * what about hashtable overhead?)	 */	subquery_size = node->plan->plan_rows *		(MAXALIGN(node->plan->plan_width) + MAXALIGN(sizeof(HeapTupleData)));	if (subquery_size > work_mem * 1024L)		return false;	/*	 * The combining operators must be hashable, strict, and self-commutative.	 * The need for hashability is obvious, since we want to use hashing.	 * Without strictness, behavior in the presence of nulls is too	 * unpredictable.  (We actually must assume even more than plain	 * strictness, see nodeSubplan.c for details.)	And commutativity ensures	 * that the left and right datatypes are the same; this allows us to	 * assume that the combining operators are equality for the righthand	 * datatype, so that they can be used to compare righthand tuples as well	 * as comparing lefthand to righthand tuples.  (This last restriction	 * could be relaxed by using two different sets of operators with the hash	 * table, but there is no obvious usefulness to that at present.)	 */	foreach(l, slink->operOids)	{		Oid			opid = lfirst_oid(l);		HeapTuple	tup;		Form_pg_operator optup;		tup = SearchSysCache(OPEROID,							 ObjectIdGetDatum(opid),							 0, 0, 0);		if (!HeapTupleIsValid(tup))			elog(ERROR, "cache lookup failed for operator %u", opid);		optup = (Form_pg_operator) GETSTRUCT(tup);		if (!optup->oprcanhash || optup->oprcom != opid ||			!func_strict(optup->oprcode))		{			ReleaseSysCache(tup);			return false;		}		ReleaseSysCache(tup);	}	return true;}/* * convert_IN_to_join: can we convert an IN SubLink to join style? * * The caller has found a SubLink at the top level of WHERE, but has not * checked the properties of the SubLink at all.  Decide whether it is * appropriate to process this SubLink in join style.  If not, return NULL. * If so, build the qual clause(s) to replace the SubLink, and return them. * * Side effects of a successful conversion include adding the SubLink's * subselect to the query's rangetable and adding an InClauseInfo node to * its in_info_list. */Node *convert_IN_to_join(PlannerInfo *root, SubLink *sublink){	Query	   *parse = root->parse;	Query	   *subselect = (Query *) sublink->subselect;	Relids		left_varnos;	int			rtindex;	RangeTblEntry *rte;	RangeTblRef *rtr;	InClauseInfo *ininfo;	List	   *exprs;	/*	 * The sublink type must be "= ANY" --- that is, an IN operator. (We	 * require the operator name to be unqualified, which may be overly	 * paranoid, or may not be.)	 */	if (sublink->subLinkType != ANY_SUBLINK)		return NULL;	if (list_length(sublink->operName) != 1 ||		strcmp(strVal(linitial(sublink->operName)), "=") != 0)		return NULL;	/*	 * The sub-select must not refer to any Vars of the parent query. (Vars of	 * higher levels should be okay, though.)	 */	if (contain_vars_of_level((Node *) subselect, 1))		return NULL;	/*	 * The left-hand expressions must contain some Vars of the current query,	 * else it's not gonna be a join.	 */	left_varnos = pull_varnos((Node *) sublink->lefthand);	if (bms_is_empty(left_varnos))		return NULL;	/*	 * The left-hand expressions mustn't be volatile.  (Perhaps we should test	 * the combining operators, too?  We'd only need to point the function	 * directly at the sublink ...)	 */	if (contain_volatile_functions((Node *) sublink->lefthand))		return NULL;	/*	 * Okay, pull up the sub-select into top range table and jointree.	 *	 * We rely here on the assumption that the outer query has no references	 * to the inner (necessarily true, other than the Vars that we build	 * below). Therefore this is a lot easier than what pull_up_subqueries has	 * to go through.	 */	rte = addRangeTableEntryForSubquery(NULL,										subselect,										makeAlias("IN_subquery", NIL),										false);	parse->rtable = lappend(parse->rtable, rte);	rtindex = list_length(parse->rtable);	rtr = makeNode(RangeTblRef);	rtr->rtindex = rtindex;	parse->jointree->fromlist = lappend(parse->jointree->fromlist, rtr);	/*	 * Now build the InClauseInfo node.	 */	ininfo = makeNode(InClauseInfo);	ininfo->lefthand = left_varnos;	ininfo->righthand = bms_make_singleton(rtindex);	root->in_info_list = lappend(root->in_info_list, ininfo);	/*	 * Build the result qual expressions.  As a side effect,	 * 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));	/*	 * Because make_subplan() could return an AND or OR clause, we have to	 * take steps to preserve AND/OR flatness of a qual.  We assume the input	 * has been AND/OR flattened and so we need no recursion here.	 *	 * If we recurse down through anything other than an AND node, we are	 * definitely not at top qual level anymore.  (Due to the coding here, we	 * will not get called on the List subnodes of an AND, so no check is	 * needed for List.)	 */	if (and_clause(node))	{		List	   *newargs = NIL;		ListCell   *l;		/* Still at qual top-level */		locTopQual = *isTopQual;		foreach(l, ((BoolExpr *) node)->args)		{			Node	   *newarg;			newarg = process_sublinks_mutator(lfirst(l),											  (void *) &locTopQual);			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 */	locTopQual = false;	if (or_clause(node))	{

⌨️ 快捷键说明

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