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

📄 subselect.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * subselect.c *	  Planning routines for subselects and parameters. * * Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.18.2.2 1999/08/02 06:27:03 scrappy Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "catalog/pg_type.h"#include "nodes/makefuncs.h"#include "nodes/nodeFuncs.h"#include "optimizer/clauses.h"#include "optimizer/planner.h"#include "optimizer/subselect.h"int			PlannerQueryLevel;	/* level of current query */List	   *PlannerInitPlan;	/* init subplans for current query */List	   *PlannerParamVar;	/* to get Var from Param->paramid */int			PlannerPlanId;		/* to assign unique ID to subquery plans *//*-------------------- * PlannerParamVar is a list of Var nodes, wherein the n'th entry * (n counts from 0) corresponds to Param->paramid = n.  The Var nodes * are ordinary except for one thing: their varlevelsup field does NOT * have the usual interpretation of "subplan levels out from current". * Instead, it contains the absolute plan level, with the outermost * plan being level 1 and nested plans having higher level numbers. * This nonstandardness is useful because we don't have to run around * and update the list elements when we enter or exit a subplan * recursion level.  But we must pay attention not to confuse this * meaning with the normal meaning of varlevelsup. *-------------------- *//* * Create a new entry in the PlannerParamVar list, and return its index. * * var contains the data to be copied, except for varlevelsup which * is set from the absolute level value given by varlevel. */static int_new_param(Var *var, int varlevel){	List	   *last;	int			i = 0;	if (PlannerParamVar == NULL)		last = PlannerParamVar = makeNode(List);	else	{		for (last = PlannerParamVar;;)		{			i++;			if (lnext(last) == NULL)				break;			last = lnext(last);		}		lnext(last) = makeNode(List);		last = lnext(last);	}	lnext(last) = NULL;	lfirst(last) = makeVar(var->varno, var->varattno, var->vartype,				var->vartypmod, varlevel, var->varnoold, var->varoattno);	return i;}/* * Generate a Param node to replace the given Var, * which is expected to have varlevelsup > 0 (ie, it is not local). */static Param *_replace_var(Var *var){	List	   *ppv;	Param	   *retval;	int			varlevel;	int			i;	Assert(var->varlevelsup > 0 && var->varlevelsup < PlannerQueryLevel);	varlevel = PlannerQueryLevel - var->varlevelsup;	/*	 * If there's already a PlannerParamVar entry for this same Var,	 * just use it.  NOTE: in situations involving UNION or inheritance,	 * it is possible for the same varno/varlevel to refer to different RTEs	 * in different parts of the parsetree, so that different fields might	 * end up sharing the same Param number.  As long as we check the vartype	 * as well, I believe that this sort of aliasing will cause no trouble.	 * The correct field should get stored into the Param slot at execution	 * in each part of the tree.	 */	i = 0;	foreach(ppv, PlannerParamVar)	{		Var	   *pvar = lfirst(ppv);		if (pvar->varno == var->varno &&			pvar->varattno == var->varattno &&			pvar->varlevelsup == varlevel &&			pvar->vartype == var->vartype)			break;		i++;	}	if (! ppv)	{		/* Nope, so make a new one */		i = _new_param(var, varlevel);	}	retval = makeNode(Param);	retval->paramkind = PARAM_EXEC;	retval->paramid = (AttrNumber) i;	retval->paramtype = var->vartype;	return retval;}static Node *_make_subplan(SubLink *slink){	SubPlan    *node = makeNode(SubPlan);	Plan	   *plan;	List	   *lst;	Node	   *result;	List	   *saved_ip = PlannerInitPlan;	PlannerInitPlan = NULL;	PlannerQueryLevel++;		/* we becomes child */	node->plan = plan = union_planner((Query *) slink->subselect);	/*	 * Assign subPlan, extParam and locParam to plan nodes. At the moment,	 * SS_finalize_plan doesn't handle initPlan-s and so we assigne them	 * to the topmost plan node and take care about its extParam too.	 */	(void) SS_finalize_plan(plan);	plan->initPlan = PlannerInitPlan;	/* Create extParam list as union of InitPlan-s' lists */	foreach(lst, PlannerInitPlan)	{		List	   *lp;		foreach(lp, ((SubPlan *) lfirst(lst))->plan->extParam)		{			if (!intMember(lfirsti(lp), plan->extParam))				plan->extParam = lappendi(plan->extParam, lfirsti(lp));		}	}	/* and now we are parent again */	PlannerInitPlan = saved_ip;	PlannerQueryLevel--;	node->plan_id = PlannerPlanId++;	node->rtable = ((Query *) slink->subselect)->rtable;	node->sublink = slink;	slink->subselect = NULL;	/* cool ?! */	/* make parParam list of params coming from current query level */	foreach(lst, plan->extParam)	{		Var		   *var = nth(lfirsti(lst), PlannerParamVar);		/* note varlevelsup is absolute level number */		if (var->varlevelsup == PlannerQueryLevel)			node->parParam = lappendi(node->parParam, lfirsti(lst));	}	/*	 * Un-correlated or undirect correlated plans of EXISTS or EXPR types	 * can be used as initPlans...	 */	if (node->parParam == NULL && slink->subLinkType == EXPR_SUBLINK)	{		int			i = 0;		/* transform right side of all sublink Oper-s into Param */		foreach(lst, slink->oper)		{			List	   *rside = lnext(((Expr *) lfirst(lst))->args);			TargetEntry *te = nth(i, plan->targetlist);			Var		   *var = makeVar(0, 0, te->resdom->restype,									  te->resdom->restypmod,									  0, 0, 0);			Param	   *prm = makeNode(Param);			prm->paramkind = PARAM_EXEC;			prm->paramid = (AttrNumber) _new_param(var, PlannerQueryLevel);			prm->paramtype = var->vartype;			lfirst(rside) = prm;			node->setParam = lappendi(node->setParam, prm->paramid);			pfree(var);			i++;		}		PlannerInitPlan = lappend(PlannerInitPlan, node);		if (i > 1)			result = (Node *) ((slink->useor) ? make_orclause(slink->oper) :							   make_andclause(slink->oper));		else			result = (Node *) lfirst(slink->oper);	}	else if (node->parParam == NULL && slink->subLinkType == EXISTS_SUBLINK)	{		Var		   *var = makeVar(0, 0, BOOLOID, -1, 0, 0, 0);		Param	   *prm = makeNode(Param);		prm->paramkind = PARAM_EXEC;		prm->paramid = (AttrNumber) _new_param(var, PlannerQueryLevel);		prm->paramtype = var->vartype;		node->setParam = lappendi(node->setParam, prm->paramid);		pfree(var);		PlannerInitPlan = lappend(PlannerInitPlan, node);		result = (Node *) prm;	}	else	{		/* make expression of SUBPLAN type */		Expr	   *expr = makeNode(Expr);		List	   *args = NIL;		int			i = 0;		expr->typeOid = BOOLOID;		expr->opType = SUBPLAN_EXPR;		expr->oper = (Node *) node;		/*		 * Make expr->args from parParam. Left sides of sublink Oper-s are		 * handled by optimizer directly... Also, transform right side of		 * sublink Oper-s into Const.		 */		foreach(lst, node->parParam)		{			Var		   *var = nth(lfirsti(lst), PlannerParamVar);			var = (Var *) copyObject(var);			/* Must fix absolute-level varlevelsup from the			 * PlannerParamVar entry.  But since var is at current			 * subplan level, this is easy:			 */			var->varlevelsup = 0;			args = lappend(args, var);		}		foreach(lst, slink->oper)		{			List	   *rside = lnext(((Expr *) lfirst(lst))->args);			TargetEntry *te = nth(i, plan->targetlist);			Const	   *con = makeConst(te->resdom->restype,										0, 0, true, 0, 0, 0);			lfirst(rside) = con;			i++;		}		expr->args = args;		result = (Node *) expr;	}	return result;}static List *set_unioni(List *l1, List *l2){	if (l1 == NULL)		return l2;	if (l2 == NULL)		return l1;	return nconc(l1, set_differencei(l2, l1));}typedef struct finalize_primnode_results {	List	*subplans;			/* List of subplans found in expr */	List	*paramids;			/* List of PARAM_EXEC paramids found */} finalize_primnode_results;static bool finalize_primnode_walker(Node *node,									 finalize_primnode_results *results);static voidfinalize_primnode(Node *expr, finalize_primnode_results *results){	results->subplans = NIL;	/* initialize */	results->paramids = NIL;	(void) finalize_primnode_walker(expr, results);}static boolfinalize_primnode_walker(Node *node,						 finalize_primnode_results *results){	if (node == NULL)		return false;	if (IsA(node, Param))	{		if (((Param *) node)->paramkind == PARAM_EXEC)		{			int		paramid = (int) ((Param *) node)->paramid;			if (! intMember(paramid, results->paramids))				results->paramids = lconsi(paramid, results->paramids);		}		return false;			/* no more to do here */	}	if (is_subplan(node))

⌨️ 快捷键说明

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