initsplan.c

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

C
1,362
字号
/*------------------------------------------------------------------------- * * initsplan.c *	  Target list, qualification, joininfo initialization routines * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.138.2.2 2008/06/27 20:54:45 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "catalog/pg_operator.h"#include "catalog/pg_type.h"#include "optimizer/clauses.h"#include "optimizer/cost.h"#include "optimizer/joininfo.h"#include "optimizer/pathnode.h"#include "optimizer/paths.h"#include "optimizer/planmain.h"#include "optimizer/prep.h"#include "optimizer/restrictinfo.h"#include "optimizer/var.h"#include "parser/parse_expr.h"#include "parser/parse_oper.h"#include "utils/builtins.h"#include "utils/lsyscache.h"#include "utils/syscache.h"/* These parameters are set by GUC */int			from_collapse_limit;int			join_collapse_limit;static List *deconstruct_recurse(PlannerInfo *root, Node *jtnode,					bool below_outer_join,					Relids *qualscope, Relids *inner_join_rels);static OuterJoinInfo *make_outerjoininfo(PlannerInfo *root,				   Relids left_rels, Relids right_rels,				   Relids inner_join_rels,				   bool is_full_join, Node *clause);static void distribute_qual_to_rels(PlannerInfo *root, Node *clause,						bool is_deduced,						bool below_outer_join,						Relids qualscope,						Relids ojscope,						Relids outerjoin_nonnullable);static bool check_outerjoin_delay(PlannerInfo *root, Relids *relids_p,					  bool is_pushed_down);static void check_mergejoinable(RestrictInfo *restrictinfo);static void check_hashjoinable(RestrictInfo *restrictinfo);/***************************************************************************** * *	 JOIN TREES * *****************************************************************************//* * add_base_rels_to_query * *	  Scan the query's jointree and create baserel RelOptInfos for all *	  the base relations (ie, table, subquery, and function RTEs) *	  appearing in the jointree. * * The initial invocation must pass root->parse->jointree as the value of * jtnode.	Internally, the function recurses through the jointree. * * At the end of this process, there should be one baserel RelOptInfo for * every non-join RTE that is used in the query.  Therefore, this routine * is the only place that should call build_simple_rel with reloptkind * RELOPT_BASEREL.	(Note: build_simple_rel recurses internally to build * "other rel" RelOptInfos for the members of any appendrels we find here.) */voidadd_base_rels_to_query(PlannerInfo *root, Node *jtnode){	if (jtnode == NULL)		return;	if (IsA(jtnode, RangeTblRef))	{		int			varno = ((RangeTblRef *) jtnode)->rtindex;		(void) build_simple_rel(root, varno, RELOPT_BASEREL);	}	else if (IsA(jtnode, FromExpr))	{		FromExpr   *f = (FromExpr *) jtnode;		ListCell   *l;		foreach(l, f->fromlist)			add_base_rels_to_query(root, lfirst(l));	}	else if (IsA(jtnode, JoinExpr))	{		JoinExpr   *j = (JoinExpr *) jtnode;		add_base_rels_to_query(root, j->larg);		add_base_rels_to_query(root, j->rarg);	}	else		elog(ERROR, "unrecognized node type: %d",			 (int) nodeTag(jtnode));}/***************************************************************************** * *	 TARGET LISTS * *****************************************************************************//* * build_base_rel_tlists *	  Add targetlist entries for each var needed in the query's final tlist *	  to the appropriate base relations. * * We mark such vars as needed by "relation 0" to ensure that they will * propagate up through all join plan steps. */voidbuild_base_rel_tlists(PlannerInfo *root, List *final_tlist){	List	   *tlist_vars = pull_var_clause((Node *) final_tlist, false);	if (tlist_vars != NIL)	{		add_vars_to_targetlist(root, tlist_vars, bms_make_singleton(0));		list_free(tlist_vars);	}}/* * add_IN_vars_to_tlists *	  Add targetlist entries for each var needed in InClauseInfo entries *	  to the appropriate base relations. * * Normally this is a waste of time because scanning of the WHERE clause * will have added them.  But it is possible that eval_const_expressions() * simplified away all references to the vars after the InClauseInfos were * made.  We need the IN's righthand-side vars to be available at the join * anyway, in case we try to unique-ify the subselect's outputs.  (The only * known case that provokes this is "WHERE false AND foo IN (SELECT ...)". * We don't try to be very smart about such cases, just correct.) */voidadd_IN_vars_to_tlists(PlannerInfo *root){	ListCell   *l;	foreach(l, root->in_info_list)	{		InClauseInfo *ininfo = (InClauseInfo *) lfirst(l);		List	   *in_vars;		in_vars = pull_var_clause((Node *) ininfo->sub_targetlist, false);		if (in_vars != NIL)		{			add_vars_to_targetlist(root, in_vars,								   bms_union(ininfo->lefthand,											 ininfo->righthand));			list_free(in_vars);		}	}}/* * add_vars_to_targetlist *	  For each variable appearing in the list, add it to the owning *	  relation's targetlist if not already present, and mark the variable *	  as being needed for the indicated join (or for final output if *	  where_needed includes "relation 0"). */voidadd_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed){	ListCell   *temp;	Assert(!bms_is_empty(where_needed));	foreach(temp, vars)	{		Var		   *var = (Var *) lfirst(temp);		RelOptInfo *rel = find_base_rel(root, var->varno);		int			attrno = var->varattno;		Assert(attrno >= rel->min_attr && attrno <= rel->max_attr);		attrno -= rel->min_attr;		if (bms_is_empty(rel->attr_needed[attrno]))		{			/* Variable not yet requested, so add to reltargetlist */			/* XXX is copyObject necessary here? */			rel->reltargetlist = lappend(rel->reltargetlist, copyObject(var));		}		rel->attr_needed[attrno] = bms_add_members(rel->attr_needed[attrno],												   where_needed);	}}/***************************************************************************** * *	  JOIN TREE PROCESSING * *****************************************************************************//* * deconstruct_jointree *	  Recursively scan the query's join tree for WHERE and JOIN/ON qual *	  clauses, and add these to the appropriate restrictinfo and joininfo *	  lists belonging to base RelOptInfos.	Also, add OuterJoinInfo nodes *	  to root->oj_info_list for any outer joins appearing in the query tree. *	  Return a "joinlist" data structure showing the join order decisions *	  that need to be made by make_one_rel(). * * The "joinlist" result is a list of items that are either RangeTblRef * jointree nodes or sub-joinlists.  All the items at the same level of * joinlist must be joined in an order to be determined by make_one_rel() * (note that legal orders may be constrained by OuterJoinInfo nodes). * A sub-joinlist represents a subproblem to be planned separately. Currently * sub-joinlists arise only from FULL OUTER JOIN or when collapsing of * subproblems is stopped by join_collapse_limit or from_collapse_limit. * * NOTE: when dealing with inner joins, it is appropriate to let a qual clause * be evaluated at the lowest level where all the variables it mentions are * available.  However, we cannot push a qual down into the nullable side(s) * of an outer join since the qual might eliminate matching rows and cause a * NULL row to be incorrectly emitted by the join.	Therefore, we artificially * OR the minimum-relids of such an outer join into the required_relids of * clauses appearing above it.	This forces those clauses to be delayed until * application of the outer join (or maybe even higher in the join tree). */List *deconstruct_jointree(PlannerInfo *root){	Relids		qualscope;	Relids		inner_join_rels;	/* Start recursion at top of jointree */	Assert(root->parse->jointree != NULL &&		   IsA(root->parse->jointree, FromExpr));	return deconstruct_recurse(root, (Node *) root->parse->jointree, false,							   &qualscope, &inner_join_rels);}/* * deconstruct_recurse *	  One recursion level of deconstruct_jointree processing. * * Inputs: *	jtnode is the jointree node to examine *	below_outer_join is TRUE if this node is within the nullable side of a *		higher-level outer join * Outputs: *	*qualscope gets the set of base Relids syntactically included in this *		jointree node (do not modify or free this, as it may also be pointed *		to by RestrictInfo and OuterJoinInfo nodes) *	*inner_join_rels gets the set of base Relids syntactically included in *		inner joins appearing at or below this jointree node (do not modify *		or free this, either) *	Return value is the appropriate joinlist for this jointree node * * In addition, entries will be added to root->oj_info_list for outer joins. */static List *deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,					Relids *qualscope, Relids *inner_join_rels){	List	   *joinlist;	if (jtnode == NULL)	{		*qualscope = NULL;		*inner_join_rels = NULL;		return NIL;	}	if (IsA(jtnode, RangeTblRef))	{		int			varno = ((RangeTblRef *) jtnode)->rtindex;		/* No quals to deal with, just return correct result */		*qualscope = bms_make_singleton(varno);		/* A single baserel does not create an inner join */		*inner_join_rels = NULL;		joinlist = list_make1(jtnode);	}	else if (IsA(jtnode, FromExpr))	{		FromExpr   *f = (FromExpr *) jtnode;		int			remaining;		ListCell   *l;		/*		 * First, recurse to handle child joins.  We collapse subproblems into		 * a single joinlist whenever the resulting joinlist wouldn't exceed		 * from_collapse_limit members.  Also, always collapse one-element		 * subproblems, since that won't lengthen the joinlist anyway.		 */		*qualscope = NULL;		*inner_join_rels = NULL;		joinlist = NIL;		remaining = list_length(f->fromlist);		foreach(l, f->fromlist)		{			Relids		sub_qualscope;			List	   *sub_joinlist;			int			sub_members;			sub_joinlist = deconstruct_recurse(root, lfirst(l),											   below_outer_join,											   &sub_qualscope,											   inner_join_rels);			*qualscope = bms_add_members(*qualscope, sub_qualscope);			sub_members = list_length(sub_joinlist);			remaining--;			if (sub_members <= 1 ||				list_length(joinlist) + sub_members + remaining <= from_collapse_limit)				joinlist = list_concat(joinlist, sub_joinlist);			else				joinlist = lappend(joinlist, sub_joinlist);		}		/*		 * A FROM with more than one list element is an inner join subsuming		 * all below it, so we should report inner_join_rels = qualscope. If		 * there was exactly one element, we should (and already did) report		 * whatever its inner_join_rels were.  If there were no elements (is		 * that possible?) the initialization before the loop fixed it.		 */		if (list_length(f->fromlist) > 1)			*inner_join_rels = *qualscope;		/*		 * Now process the top-level quals.

⌨️ 快捷键说明

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