prepunion.c

来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 1,246 行 · 第 1/3 页

C
1,246
字号
/*------------------------------------------------------------------------- * * prepunion.c *	  Routines to plan set-operation queries.  The filename is a leftover *	  from a time when only UNIONs were implemented. * * There is also some code here to support planning of queries that use * inheritance (SELECT FROM foo*).	This no longer has much connection * to the processing of UNION queries, but it's still here. * * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.127.2.1 2005/11/22 18:23:11 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "catalog/namespace.h"#include "catalog/pg_type.h"#include "nodes/makefuncs.h"#include "optimizer/clauses.h"#include "optimizer/plancat.h"#include "optimizer/planmain.h"#include "optimizer/planner.h"#include "optimizer/prep.h"#include "optimizer/tlist.h"#include "parser/parse_clause.h"#include "parser/parse_coerce.h"#include "parser/parse_expr.h"#include "parser/parsetree.h"#include "utils/lsyscache.h"typedef struct{	Index		old_rt_index;	Index		new_rt_index;	Oid			old_rel_type;	Oid			new_rel_type;	TupleDesc	old_tupdesc;	TupleDesc	new_tupdesc;	char	   *old_rel_name;	char	   *new_rel_name;} adjust_inherited_attrs_context;static Plan *recurse_set_operations(Node *setOp, PlannerInfo *root,					   double tuple_fraction,					   List *colTypes, bool junkOK,					   int flag, List *refnames_tlist,					   List **sortClauses);static Plan *generate_union_plan(SetOperationStmt *op, PlannerInfo *root,					double tuple_fraction,					List *refnames_tlist, List **sortClauses);static Plan *generate_nonunion_plan(SetOperationStmt *op, PlannerInfo *root,					   List *refnames_tlist, List **sortClauses);static List *recurse_union_children(Node *setOp, PlannerInfo *root,					   double tuple_fraction,					   SetOperationStmt *top_union,					   List *refnames_tlist);static List *generate_setop_tlist(List *colTypes, int flag,					 Index varno,					 bool hack_constants,					 List *input_tlist,					 List *refnames_tlist);static List *generate_append_tlist(List *colTypes, bool flag,					  List *input_plans,					  List *refnames_tlist);static bool tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK);static Node *adjust_inherited_attrs_mutator(Node *node,							   adjust_inherited_attrs_context *context);static Relids adjust_relid_set(Relids relids, Index oldrelid, Index newrelid);static List *adjust_inherited_tlist(List *tlist,					   adjust_inherited_attrs_context *context);/* * plan_set_operations * *	  Plans the queries for a tree of set operations (UNION/INTERSECT/EXCEPT) * * This routine only deals with the setOperations tree of the given query. * Any top-level ORDER BY requested in root->parse->sortClause will be added * when we return to grouping_planner. * * tuple_fraction is the fraction of tuples we expect will be retrieved. * tuple_fraction is interpreted as for grouping_planner(); in particular, * zero means "all the tuples will be fetched".  Any LIMIT present at the * top level has already been factored into tuple_fraction. * * *sortClauses is an output argument: it is set to a list of SortClauses * representing the result ordering of the topmost set operation. */Plan *plan_set_operations(PlannerInfo *root, double tuple_fraction,					List **sortClauses){	Query	   *parse = root->parse;	SetOperationStmt *topop = (SetOperationStmt *) parse->setOperations;	Node	   *node;	Query	   *leftmostQuery;	Assert(topop && IsA(topop, SetOperationStmt));	/* check for unsupported stuff */	Assert(parse->utilityStmt == NULL);	Assert(parse->jointree->fromlist == NIL);	Assert(parse->jointree->quals == NULL);	Assert(parse->groupClause == NIL);	Assert(parse->havingQual == NULL);	Assert(parse->distinctClause == NIL);	/*	 * Find the leftmost component Query.  We need to use its column names for	 * all generated tlists (else SELECT INTO won't work right).	 */	node = topop->larg;	while (node && IsA(node, SetOperationStmt))		node = ((SetOperationStmt *) node)->larg;	Assert(node && IsA(node, RangeTblRef));	leftmostQuery = rt_fetch(((RangeTblRef *) node)->rtindex,							 parse->rtable)->subquery;	Assert(leftmostQuery != NULL);	/*	 * Recurse on setOperations tree to generate plans for set ops. The final	 * output plan should have just the column types shown as the output from	 * the top-level node, plus possibly resjunk working columns (we can rely	 * on upper-level nodes to deal with that).	 */	return recurse_set_operations((Node *) topop, root, tuple_fraction,								  topop->colTypes, true, -1,								  leftmostQuery->targetList,								  sortClauses);}/* * recurse_set_operations *	  Recursively handle one step in a tree of set operations * * tuple_fraction: fraction of tuples we expect to retrieve from node * colTypes: list of type OIDs of expected output columns * junkOK: if true, child resjunk columns may be left in the result * flag: if >= 0, add a resjunk output column indicating value of flag * refnames_tlist: targetlist to take column names from * *sortClauses: receives list of SortClauses for result plan, if any */static Plan *recurse_set_operations(Node *setOp, PlannerInfo *root,					   double tuple_fraction,					   List *colTypes, bool junkOK,					   int flag, List *refnames_tlist,					   List **sortClauses){	if (IsA(setOp, RangeTblRef))	{		RangeTblRef *rtr = (RangeTblRef *) setOp;		RangeTblEntry *rte = rt_fetch(rtr->rtindex, root->parse->rtable);		Query	   *subquery = rte->subquery;		Plan	   *subplan,				   *plan;		Assert(subquery != NULL);		/*		 * Generate plan for primitive subquery		 */		subplan = subquery_planner(subquery, tuple_fraction, NULL);		/*		 * Add a SubqueryScan with the caller-requested targetlist		 */		plan = (Plan *)			make_subqueryscan(generate_setop_tlist(colTypes, flag,												   rtr->rtindex,												   true,												   subplan->targetlist,												   refnames_tlist),							  NIL,							  rtr->rtindex,							  subplan);		/*		 * We don't bother to determine the subquery's output ordering since		 * it won't be reflected in the set-op result anyhow.		 */		*sortClauses = NIL;		return plan;	}	else if (IsA(setOp, SetOperationStmt))	{		SetOperationStmt *op = (SetOperationStmt *) setOp;		Plan	   *plan;		/* UNIONs are much different from INTERSECT/EXCEPT */		if (op->op == SETOP_UNION)			plan = generate_union_plan(op, root, tuple_fraction,									   refnames_tlist,									   sortClauses);		else			plan = generate_nonunion_plan(op, root,										  refnames_tlist,										  sortClauses);		/*		 * If necessary, add a Result node to project the caller-requested		 * output columns.		 *		 * XXX you don't really want to know about this: setrefs.c will apply		 * replace_vars_with_subplan_refs() to the Result node's tlist. This		 * would fail if the Vars generated by generate_setop_tlist() were not		 * exactly equal() to the corresponding tlist entries of the subplan.		 * However, since the subplan was generated by generate_union_plan()		 * or generate_nonunion_plan(), and hence its tlist was generated by		 * generate_append_tlist(), this will work.  We just tell		 * generate_setop_tlist() to use varno 0.		 */		if (flag >= 0 ||			!tlist_same_datatypes(plan->targetlist, colTypes, junkOK))		{			plan = (Plan *)				make_result(generate_setop_tlist(colTypes, flag,												 0,												 false,												 plan->targetlist,												 refnames_tlist),							NULL,							plan);		}		return plan;	}	else	{		elog(ERROR, "unrecognized node type: %d",			 (int) nodeTag(setOp));		return NULL;			/* keep compiler quiet */	}}/* * Generate plan for a UNION or UNION ALL node */static Plan *generate_union_plan(SetOperationStmt *op, PlannerInfo *root,					double tuple_fraction,					List *refnames_tlist,					List **sortClauses){	List	   *planlist;	List	   *tlist;	Plan	   *plan;	/*	 * If plain UNION, tell children to fetch all tuples.	 *	 * Note: in UNION ALL, we pass the top-level tuple_fraction unmodified to	 * each arm of the UNION ALL.  One could make a case for reducing the	 * tuple fraction for later arms (discounting by the expected size of the	 * earlier arms' results) but it seems not worth the trouble. The normal	 * case where tuple_fraction isn't already zero is a LIMIT at top level,	 * and passing it down as-is is usually enough to get the desired result	 * of preferring fast-start plans.	 */	if (!op->all)		tuple_fraction = 0.0;	/*	 * If any of my children are identical UNION nodes (same op, all-flag, and	 * colTypes) then they can be merged into this node so that we generate	 * only one Append and Sort for the lot.  Recurse to find such nodes and	 * compute their children's plans.	 */	planlist = list_concat(recurse_union_children(op->larg, root,												  tuple_fraction,												  op, refnames_tlist),						   recurse_union_children(op->rarg, root,												  tuple_fraction,												  op, refnames_tlist));	/*	 * Generate tlist for Append plan node.	 *	 * The tlist for an Append plan isn't important as far as the Append is	 * concerned, but we must make it look real anyway for the benefit of the	 * next plan level up.	 */	tlist = generate_append_tlist(op->colTypes, false,								  planlist, refnames_tlist);	/*	 * Append the child results together.	 */	plan = (Plan *) make_append(planlist, false, tlist);	/*	 * For UNION ALL, we just need the Append plan.  For UNION, need to add	 * Sort and Unique nodes to produce unique output.	 */	if (!op->all)	{		List	   *sortList;		sortList = addAllTargetsToSortList(NULL, NIL, tlist, false);		if (sortList)		{			plan = (Plan *) make_sort_from_sortclauses(root, sortList, plan);			plan = (Plan *) make_unique(plan, sortList);		}		*sortClauses = sortList;	}	else		*sortClauses = NIL;	return plan;}/* * Generate plan for an INTERSECT, INTERSECT ALL, EXCEPT, or EXCEPT ALL node */static Plan *generate_nonunion_plan(SetOperationStmt *op, PlannerInfo *root,					   List *refnames_tlist,					   List **sortClauses){	Plan	   *lplan,			   *rplan,			   *plan;	List	   *tlist,			   *sortList,			   *planlist,			   *child_sortclauses;	SetOpCmd	cmd;	/* Recurse on children, ensuring their outputs are marked */	lplan = recurse_set_operations(op->larg, root,								   0.0 /* all tuples needed */ ,								   op->colTypes, false, 0,								   refnames_tlist,								   &child_sortclauses);	rplan = recurse_set_operations(op->rarg, root,								   0.0 /* all tuples needed */ ,								   op->colTypes, false, 1,								   refnames_tlist,								   &child_sortclauses);	planlist = list_make2(lplan, rplan);	/*	 * Generate tlist for Append plan node.	 *	 * The tlist for an Append plan isn't important as far as the Append is	 * concerned, but we must make it look real anyway for the benefit of the	 * next plan level up.	In fact, it has to be real enough that the flag	 * column is shown as a variable not a constant, else setrefs.c will get	 * confused.	 */	tlist = generate_append_tlist(op->colTypes, true,								  planlist, refnames_tlist);	/*	 * Append the child results together.	 */	plan = (Plan *) make_append(planlist, false, tlist);	/*	 * Sort the child results, then add a SetOp plan node to generate the	 * correct output.	 */	sortList = addAllTargetsToSortList(NULL, NIL, tlist, false);	if (sortList == NIL)		/* nothing to sort on? */	{		*sortClauses = NIL;		return plan;	}	plan = (Plan *) make_sort_from_sortclauses(root, sortList, plan);	switch (op->op)	{		case SETOP_INTERSECT:			cmd = op->all ? SETOPCMD_INTERSECT_ALL : SETOPCMD_INTERSECT;			break;		case SETOP_EXCEPT:			cmd = op->all ? SETOPCMD_EXCEPT_ALL : SETOPCMD_EXCEPT;			break;		default:			elog(ERROR, "unrecognized set op: %d",				 (int) op->op);			cmd = SETOPCMD_INTERSECT;	/* keep compiler quiet */			break;	}	plan = (Plan *) make_setop(cmd, plan, sortList, list_length(op->colTypes) + 1);	*sortClauses = sortList;	return plan;}/* * Pull up children of a UNION node that are identically-propertied UNIONs. * * NOTE: we can also pull a UNION ALL up into a UNION, since the distinct * output rows will be lost anyway. */static List *recurse_union_children(Node *setOp, PlannerInfo *root,					   double tuple_fraction,					   SetOperationStmt *top_union,					   List *refnames_tlist){

⌨️ 快捷键说明

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