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

📄 createplan.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 3 页
字号:
		 * in the inner relation. There will never be more than one index		 * used in the inner scan path, so we need only consider the first		 * set of qualifications in indxqual.		 *		 * But there may be more than one clause in this "first set" in the		 * case of multi-column indices. - vadim 03/18/97		 */		List	   *inner_indxqual = lfirst(((IndexScan *) inner_node)->indxqual);		List	   *inner_qual;		bool		found = false;		foreach(inner_qual, inner_indxqual)		{			if (!qual_clause_p((Node *) lfirst(inner_qual)))			{				found = true;				break;			}		}		/*		 * If we have in fact found a join index qualification, remove		 * these index clauses from the nestloop's join clauses and reset		 * the inner(index) scan's qualification so that the var nodes		 * refer to the proper outer join relation attributes.		 *		 * XXX Re-moving index clauses doesn't work properly: 1.		 * fix_indxqual_references may change varattno-s in		 * inner_indxqual; 2. clauses may be commuted I havn't time to fix		 * it at the moment.   - vadim 04/24/97		 */		if (found)		{			List	   *new_inner_qual = NIL;			clauses = set_difference(clauses, inner_indxqual);	/* XXX */			new_inner_qual = index_outerjoin_references(inner_indxqual,												  outer_node->targetlist,									   ((Scan *) inner_node)->scanrelid);			((IndexScan *) inner_node)->indxqual = lcons(new_inner_qual, NIL);		}	}	else if (IsA_Join(inner_node))	{		inner_node = (Plan *) make_noname(inner_tlist,										  NIL,										  NULL,										  inner_node,										  NONAME_MATERIAL);	}	join_node = make_nestloop(tlist,							  join_references(clauses,											  outer_tlist,											  inner_tlist),							  outer_node,							  inner_node);	join_node->join.cost = best_path->path.path_cost;	return join_node;}static MergeJoin *create_mergejoin_node(MergePath *best_path,					  List *tlist,					  List *clauses,					  Plan *outer_node,					  List *outer_tlist,					  Plan *inner_node,					  List *inner_tlist){	List	   *qpqual,			   *mergeclauses;	MergeJoin  *join_node;	/*	 * Separate the mergeclauses from the other join qualification clauses	 * and set those clauses to contain references to lower attributes.	 */	qpqual = join_references(set_difference(clauses,											best_path->path_mergeclauses),							 outer_tlist,							 inner_tlist);	/*	 * Now set the references in the mergeclauses and rearrange them so	 * that the outer variable is always on the left.	 */	mergeclauses = switch_outer(join_references(best_path->path_mergeclauses,												outer_tlist,												inner_tlist));	/*	 * Create explicit sort paths for the outer and inner join paths if	 * necessary.  The sort cost was already accounted for in the path.	 */	if (best_path->outersortkeys)	{		Oid		   *outer_order = generate_merge_input_sortorder(												best_path->outersortkeys,							 best_path->jpath.path.pathorder->ord.merge);		outer_node = (Plan *) make_noname(outer_tlist,										  best_path->outersortkeys,										  outer_order,										  outer_node,										  NONAME_SORT);	}	if (best_path->innersortkeys)	{		Oid		   *inner_order = generate_merge_input_sortorder(												best_path->innersortkeys,							 best_path->jpath.path.pathorder->ord.merge);		inner_node = (Plan *) make_noname(inner_tlist,										  best_path->innersortkeys,										  inner_order,										  inner_node,										  NONAME_SORT);	}	join_node = make_mergejoin(tlist,							   qpqual,							   mergeclauses,							   inner_node,							   outer_node);	join_node->join.cost = best_path->jpath.path.path_cost;	return join_node;}/* * create_hashjoin_node--						XXX HASH * *	  Returns a new hashjoin node. * *	  XXX hash join ops are totally bogus -- how the hell do we choose *		these??  at runtime?  what about a hash index? */static HashJoin *create_hashjoin_node(HashPath *best_path,					 List *tlist,					 List *clauses,					 Plan *outer_node,					 List *outer_tlist,					 Plan *inner_node,					 List *inner_tlist){	List	   *qpqual;	List	   *hashclauses;	HashJoin   *join_node;	Hash	   *hash_node;	Var		   *innerhashkey;	/*	 * Separate the hashclauses from the other join qualification clauses	 * and set those clauses to contain references to lower attributes.	 */	qpqual = join_references(set_difference(clauses,											best_path->path_hashclauses),							 outer_tlist,							 inner_tlist);	/*	 * Now set the references in the hashclauses and rearrange them so	 * that the outer variable is always on the left.	 */	hashclauses = switch_outer(join_references(best_path->path_hashclauses,											   outer_tlist,											   inner_tlist));	innerhashkey = get_rightop(lfirst(hashclauses));	hash_node = make_hash(inner_tlist, innerhashkey, inner_node);	join_node = make_hashjoin(tlist,							  qpqual,							  hashclauses,							  outer_node,							  (Plan *) hash_node);	join_node->join.cost = best_path->jpath.path.path_cost;	return join_node;}/***************************************************************************** * *	SUPPORTING ROUTINES * *****************************************************************************//* * fix_indxqual_references *	Adjust a qual clause to refer to an index instead of the original relation. * * Returns a modified copy of the given clause --- the original is not changed. */static Node *fix_indxqual_references(Node *clause, Path *index_path){	if (clause == NULL)		return NULL;	else if (IsA(clause, Var))	{		if (lfirsti(index_path->parent->relids) == ((Var *) clause)->varno)		{			Node	   *newclause;			int			pos = 0;			int			varatt = ((Var *) clause)->varattno;			int		   *indexkeys = ((IndexPath *) index_path)->indexkeys;			if (indexkeys)			{				while (indexkeys[pos] != 0)				{					if (varatt == indexkeys[pos])						break;					pos++;				}			}			newclause = copyObject(clause);			((Var *) newclause)->varattno = pos + 1;			return newclause;		}		/* The Var is not part of the indexed relation, leave it alone */		return copyObject(clause);	}	else if (single_node(clause))		return copyObject(clause);	else if (is_opclause(clause) &&			 is_funcclause((Node *) get_leftop((Expr *) clause)) &&	((Func *) ((Expr *) get_leftop((Expr *) clause))->oper)->funcisindex)	{		/*		 * This looks pretty seriously wrong to me, but I'm not sure what		 * it's supposed to be doing ... tgl 5/99		 */		Var		   *newvar = makeVar((Index) lfirsti(index_path->parent->relids),									 1, /* func indices have one key */							((Func *) ((Expr *) clause)->oper)->functype,									 -1,									 0,							 (Index) lfirsti(index_path->parent->relids),									 0);		return ((Node *) make_opclause((Oper *) ((Expr *) clause)->oper,									   newvar,									   get_rightop((Expr *) clause)));	}	else if (IsA(clause, Expr))	{		Expr	   *expr = (Expr *) clause;		List	   *new_subclauses = NIL;		List	   *i;		foreach(i, expr->args)		{			Node	   *subclause = lfirst(i);			new_subclauses = lappend(new_subclauses,									 fix_indxqual_references(subclause,															 index_path));		}		return (Node *) make_clause(expr->opType, expr->oper, new_subclauses);	}	else if (IsA(clause, List))	{		List	   *new_subclauses = NIL;		List	   *i;		foreach(i, (List *) clause)		{			Node	   *subclause = lfirst(i);			new_subclauses = lappend(new_subclauses,									 fix_indxqual_references(subclause,															 index_path));		}		return (Node *) new_subclauses;	}	else if (IsA(clause, ArrayRef))	{		ArrayRef   *oldnode = (ArrayRef *) clause;		ArrayRef   *newnode = makeNode(ArrayRef);		newnode->refattrlength = oldnode->refattrlength;		newnode->refelemlength = oldnode->refelemlength;		newnode->refelemtype = oldnode->refelemtype;		newnode->refelembyval = oldnode->refelembyval;		newnode->refupperindexpr = (List *)			fix_indxqual_references((Node *) oldnode->refupperindexpr,									index_path);		newnode->reflowerindexpr = (List *)			fix_indxqual_references((Node *) oldnode->reflowerindexpr,									index_path);		newnode->refexpr =			fix_indxqual_references(oldnode->refexpr, index_path);		newnode->refassgnexpr =			fix_indxqual_references(oldnode->refassgnexpr, index_path);		return (Node *) newnode;	}	else if (IsA(clause, CaseExpr))	{		CaseExpr   *oldnode = (CaseExpr *) clause;		CaseExpr   *newnode = makeNode(CaseExpr);		newnode->casetype = oldnode->casetype;		newnode->arg = oldnode->arg;	/* XXX should always be null										 * anyway ... */		newnode->args = (List *)			fix_indxqual_references((Node *) oldnode->args,									index_path);		newnode->defresult =			fix_indxqual_references(oldnode->defresult,									index_path);		return (Node *) newnode;	}	else if (IsA(clause, CaseWhen))	{		CaseWhen   *oldnode = (CaseWhen *) clause;		CaseWhen   *newnode = makeNode(CaseWhen);		newnode->expr =			fix_indxqual_references(oldnode->expr,									index_path);		newnode->result =			fix_indxqual_references(oldnode->result,									index_path);		return (Node *) newnode;	}	else	{		elog(ERROR, "fix_indxqual_references: Cannot handle node type %d",			 nodeTag(clause));		return NULL;	}}/* * switch_outer *	  Given a list of merge clauses, rearranges the elements within the *	  clauses so the outer join variable is on the left and the inner is on *	  the right.  The original list is not touched; a modified list *	  is returned. */static List *switch_outer(List *clauses){	List	   *t_list = NIL;	Expr	   *temp;	List	   *i;	Expr	   *clause;	Node	   *op;	foreach(i, clauses)	{		clause = lfirst(i);		Assert(is_opclause((Node *) clause));		op = (Node *) get_rightop(clause);		Assert(op != (Node *) NULL);		if (IsA(op, ArrayRef))			op = ((ArrayRef *) op)->refexpr;		Assert(IsA(op, Var));		if (var_is_outer((Var *) op))		{			/*			 * Duplicate just enough of the structure to allow commuting			 * the clause without changing the original list.  Could use			 * copyObject, but a complete deep copy is overkill.			 */			temp = make_clause(clause->opType, clause->oper,							   lcons(get_leftop(clause),									 lcons(get_rightop(clause),										   NIL)));			/* Commute it --- note this modifies the temp node in-place. */			CommuteClause((Node *) temp);			t_list = lappend(t_list, temp);		}		else			t_list = lappend(t_list, clause);	}	return t_list;}/* * generate_merge_input_sortorder * * Generate the list of sort ops needed to sort one of the input paths for * a merge.  We may have to use either left or right sortop for each item, * since the original mergejoin clause may or may not have been commuted * (compare switch_outer above). * * XXX This is largely a crock.  It works only because group_clauses_by_order * only groups together mergejoin clauses that have identical MergeOrder info, * which means we can safely use a single MergeOrder input to deal with all * the data.  There should be a more general data structure that allows coping * with groups of mergejoin clauses that have different join operators. */static Oid *generate_merge_input_sortorder(List *pathkeys, MergeOrder *mergeorder){	int			listlength = length(pathkeys);	Oid		   *result = (Oid *) palloc(sizeof(Oid) * (listlength + 1));	Oid		   *nextsortop = result;	List	   *p;	foreach(p, pathkeys)	{		Var		   *pkey = (Var *) lfirst((List *) lfirst(p));		Assert(IsA(pkey, Var));		if (pkey->vartype == mergeorder->left_type)			*nextsortop++ = mergeorder->left_operator;		else if (pkey->vartype == mergeorder->right_type)			*nextsortop++ = mergeorder->right_operator;		else			elog(ERROR,			 "generate_merge_input_sortorder: can't handle data type %d",				 pkey->vartype);

⌨️ 快捷键说明

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