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

📄 createplan.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 5 页
字号:
		}	}	/* Get the join qual clauses (in plain expression form) */	if (IS_OUTER_JOIN(best_path->jointype))	{		get_actual_join_clauses(joinrestrictclauses,								&joinclauses, &otherclauses);	}	else	{		/* We can treat all clauses alike for an inner join */		joinclauses = get_actual_clauses(joinrestrictclauses);		otherclauses = NIL;	}	/* Sort clauses into best execution order */	joinclauses = order_qual_clauses(root, joinclauses);	otherclauses = order_qual_clauses(root, otherclauses);	join_plan = make_nestloop(tlist,							  joinclauses,							  otherclauses,							  outer_plan,							  inner_plan,							  best_path->jointype);	copy_path_costsize(&join_plan->join.plan, &best_path->path);	return join_plan;}static MergeJoin *create_mergejoin_plan(Query *root,					  MergePath *best_path,					  Plan *outer_plan,					  Plan *inner_plan){	List	   *tlist = build_relation_tlist(best_path->jpath.path.parent);	List	   *joinclauses;	List	   *otherclauses;	List	   *mergeclauses;	MergeJoin  *join_plan;	/* Get the join qual clauses (in plain expression form) */	if (IS_OUTER_JOIN(best_path->jpath.jointype))	{		get_actual_join_clauses(best_path->jpath.joinrestrictinfo,								&joinclauses, &otherclauses);	}	else	{		/* We can treat all clauses alike for an inner join */		joinclauses = get_actual_clauses(best_path->jpath.joinrestrictinfo);		otherclauses = NIL;	}	/*	 * Remove the mergeclauses from the list of join qual clauses, leaving	 * the list of quals that must be checked as qpquals.	 */	mergeclauses = get_actual_clauses(best_path->path_mergeclauses);	joinclauses = set_difference(joinclauses, mergeclauses);	/*	 * Rearrange mergeclauses, if needed, so that the outer variable is	 * always on the left.	 */	mergeclauses = get_switched_clauses(best_path->path_mergeclauses,						 best_path->jpath.outerjoinpath->parent->relids);	/* Sort clauses into best execution order */	/* NB: do NOT reorder the mergeclauses */	joinclauses = order_qual_clauses(root, joinclauses);	otherclauses = order_qual_clauses(root, otherclauses);	/*	 * Create explicit sort nodes for the outer and inner join paths if	 * necessary.  The sort cost was already accounted for in the path.	 * Make sure there are no excess columns in the inputs if sorting.	 */	if (best_path->outersortkeys)	{		disuse_physical_tlist(outer_plan, best_path->jpath.outerjoinpath);		outer_plan = (Plan *)			make_sort_from_pathkeys(root,									outer_plan,									best_path->outersortkeys);	}	if (best_path->innersortkeys)	{		disuse_physical_tlist(inner_plan, best_path->jpath.innerjoinpath);		inner_plan = (Plan *)			make_sort_from_pathkeys(root,									inner_plan,									best_path->innersortkeys);	}	/*	 * Now we can build the mergejoin node.	 */	join_plan = make_mergejoin(tlist,							   joinclauses,							   otherclauses,							   mergeclauses,							   outer_plan,							   inner_plan,							   best_path->jpath.jointype);	copy_path_costsize(&join_plan->join.plan, &best_path->jpath.path);	return join_plan;}static HashJoin *create_hashjoin_plan(Query *root,					 HashPath *best_path,					 Plan *outer_plan,					 Plan *inner_plan){	List	   *tlist = build_relation_tlist(best_path->jpath.path.parent);	List	   *joinclauses;	List	   *otherclauses;	List	   *hashclauses;	HashJoin   *join_plan;	Hash	   *hash_plan;	List	   *innerhashkeys;	List	   *hcl;	/* Get the join qual clauses (in plain expression form) */	if (IS_OUTER_JOIN(best_path->jpath.jointype))	{		get_actual_join_clauses(best_path->jpath.joinrestrictinfo,								&joinclauses, &otherclauses);	}	else	{		/* We can treat all clauses alike for an inner join */		joinclauses = get_actual_clauses(best_path->jpath.joinrestrictinfo);		otherclauses = NIL;	}	/*	 * Remove the hashclauses from the list of join qual clauses, leaving	 * the list of quals that must be checked as qpquals.	 */	hashclauses = get_actual_clauses(best_path->path_hashclauses);	joinclauses = set_difference(joinclauses, hashclauses);	/*	 * Rearrange hashclauses, if needed, so that the outer variable is	 * always on the left.	 */	hashclauses = get_switched_clauses(best_path->path_hashclauses,						 best_path->jpath.outerjoinpath->parent->relids);	/* Sort clauses into best execution order */	joinclauses = order_qual_clauses(root, joinclauses);	otherclauses = order_qual_clauses(root, otherclauses);	hashclauses = order_qual_clauses(root, hashclauses);	/*	 * Extract the inner hash keys (right-hand operands of the hashclauses)	 * to put in the Hash node.  Must do a deep copy in case there are	 * subplans in the hash keys.	 */	innerhashkeys = NIL;	foreach(hcl, hashclauses)		innerhashkeys = lappend(innerhashkeys,								copyObject(get_rightop(lfirst(hcl))));	/* We don't want any excess columns in the hashed tuples */	disuse_physical_tlist(inner_plan, best_path->jpath.innerjoinpath);	/*	 * Build the hash node and hash join node.	 */	hash_plan = make_hash(inner_plan->targetlist,						  innerhashkeys,						  inner_plan);	join_plan = make_hashjoin(tlist,							  joinclauses,							  otherclauses,							  hashclauses,							  outer_plan,							  (Plan *) hash_plan,							  best_path->jpath.jointype);	copy_path_costsize(&join_plan->join.plan, &best_path->jpath.path);	return join_plan;}/***************************************************************************** * *	SUPPORTING ROUTINES * *****************************************************************************//* * fix_indxqual_references *	  Adjust indexqual clauses to the form the executor's indexqual *	  machinery needs, and check for recheckable (lossy) index conditions. * * We have three tasks here: *	* Index keys must be represented by Var nodes with varattno set to the *	  index's attribute number, not the attribute number in the original rel. *	* If the index key is on the right, commute the clause to put it on the *	  left.  (Someday the executor might not need this, but for now it does.) *	* If the indexable operator is marked 'amopreqcheck' in pg_amop, then *	  the index is "lossy" for this operator: it may return more tuples than *	  actually satisfy the operator condition.	For each such operator, we *	  must add (the original form of) the indexqual clause to the "qpquals" *	  of the indexscan node, where the operator will be re-evaluated to *	  ensure it passes. * * This code used to be entirely bogus for multi-index scans.  Now it keeps * track of which index applies to each subgroup of index qual clauses... * * Both the input list and the output lists have the form of lists of sublists * of qual clauses --- the top-level list has one entry for each indexscan * to be performed.  The semantics are OR-of-ANDs. * * fixed_indexquals receives a modified copy of the indexqual list --- the * original is not changed.  Note also that the copy shares no substructure * with the original; this is needed in case there is a subplan in it (we need * two separate copies of the subplan tree, or things will go awry). * * recheck_indexquals similarly receives a full copy of whichever clauses * need rechecking. */static voidfix_indxqual_references(List *indexquals, IndexPath *index_path,					  List **fixed_indexquals, List **recheck_indexquals){	FastList	fixed_quals;	FastList	recheck_quals;	Relids		baserelids = index_path->path.parent->relids;	int			baserelid = index_path->path.parent->relid;	List	   *ixinfo = index_path->indexinfo;	List	   *i;	FastListInit(&fixed_quals);	FastListInit(&recheck_quals);	foreach(i, indexquals)	{		List	   *indexqual = lfirst(i);		IndexOptInfo *index = (IndexOptInfo *) lfirst(ixinfo);		List	   *fixed_qual;		List	   *recheck_qual;		fix_indxqual_sublist(indexqual, baserelids, baserelid, index,							 &fixed_qual, &recheck_qual);		FastAppend(&fixed_quals, fixed_qual);		if (recheck_qual != NIL)			FastAppend(&recheck_quals, recheck_qual);		ixinfo = lnext(ixinfo);	}	*fixed_indexquals = FastListValue(&fixed_quals);	*recheck_indexquals = FastListValue(&recheck_quals);}/* * Fix the sublist of indexquals to be used in a particular scan. * * For each qual clause, commute if needed to put the indexkey operand on the * left, and then fix its varattno.  (We do not need to change the other side * of the clause.)	Also change the operator if necessary, and check for * lossy index behavior. * * Returns two lists: the list of fixed indexquals, and the list (usually * empty) of original clauses that must be rechecked as qpquals because * the index is lossy for this operator type. */static voidfix_indxqual_sublist(List *indexqual,					 Relids baserelids, int baserelid,					 IndexOptInfo *index,					 List **fixed_quals, List **recheck_quals){	FastList	fixed_qual;	FastList	recheck_qual;	List	   *i;	FastListInit(&fixed_qual);	FastListInit(&recheck_qual);	foreach(i, indexqual)	{		OpExpr	   *clause = (OpExpr *) lfirst(i);		OpExpr	   *newclause;		Relids		leftvarnos;		Oid			opclass;		if (!IsA(clause, OpExpr) ||length(clause->args) != 2)			elog(ERROR, "indexqual clause is not binary opclause");		/*		 * Make a copy that will become the fixed clause.		 *		 * We used to try to do a shallow copy here, but that fails if there		 * is a subplan in the arguments of the opclause.  So just do a		 * full copy.		 */		newclause = (OpExpr *) copyObject((Node *) clause);		/*		 * Check to see if the indexkey is on the right; if so, commute		 * the clause.	The indexkey should be the side that refers to		 * (only) the base relation.		 */		leftvarnos = pull_varnos((Node *) lfirst(newclause->args));		if (!bms_equal(leftvarnos, baserelids))			CommuteClause(newclause);		bms_free(leftvarnos);		/*		 * Now, determine which index attribute this is, change the		 * indexkey operand as needed, and get the index opclass.		 */		lfirst(newclause->args) = fix_indxqual_operand(lfirst(newclause->args),													   baserelid,													   index,													   &opclass);		FastAppend(&fixed_qual, newclause);		/*		 * Finally, check to see if index is lossy for this operator. If		 * so, add (a copy of) original form of clause to recheck list.		 */		if (op_requires_recheck(newclause->opno, opclass))			FastAppend(&recheck_qual, copyObject((Node *) clause));	}	*fixed_quals = FastListValue(&fixed_qual);	*recheck_quals = FastListValue(&recheck_qual);}static Node *fix_indxqual_operand(Node *node, int baserelid, IndexOptInfo *index,					 Oid *opclass){	/*	 * We represent index keys by Var nodes having the varno of the base	 * table but varattno equal to the index's attribute number (index	 * column position).  This is a bit hokey ... would be cleaner to use	 * a special-purpose node type that could not be mistaken for a	 * regular Var.  But it will do for now.	 */	Var		   *result;	int			pos;	List	   *indexprs;	/*	 * Remove any binary-compatible relabeling of the indexkey	 */	if (IsA(node, RelabelType))		node = (Node *) ((RelabelType *) node)->arg;	if (IsA(node, Var) &&		((Var *) node)->varno == baserelid)	{		/* Try to match against simple index columns */		int			varatt = ((Var *) node)->varattno;		if (varatt != 0)		{			for (pos = 0; pos < index->ncolumns; pos++)			{				if (index->indexkeys[pos] == varatt)				{					result = (Var *) copyObject(node);					result->varattno = pos + 1;					/* return the correct opclass, too */					*opclass = index->classlist[pos];					return (Node *) result;				}			}		}	}	/* Try to match against index expressions */	indexprs = index->indexprs;	for (pos = 0; pos < index->ncolumns; pos++)	{		if (index->indexkeys[pos] == 0)		{			Node	   *indexkey;			if (indexprs == NIL)				elog(ERROR, "too few entries in indexprs list");			indexkey = (Node *) lfirst(indexprs);			if (indexkey && IsA(indexkey, RelabelType))				indexkey = (Node *) ((RelabelType *) indexkey)->arg;			if (equal(node, indexkey))			{				/* Found a match */				result = makeVar(baserelid, pos + 1,								 exprType(lfirst(indexprs)), -1,								 0);				/* return the correct opclass, too */				*opclass = index->classlist[pos];				return (Node *) result;			}			indexprs = lnext(indexprs);		}	}	/* Ooops... */	elog(ERROR, "node is not an index attribute");	return NULL;				/* keep compiler quiet */}/* * get_switched_clauses *	  Given a list of merge or hash joinclauses (as RestrictInfo nodes), *	  extract the bare clauses, and rearrange the elements within the *	  clauses, if needed, so the outer join variable is on the left and *	  the inner is on the right.  The original data structure is not touched; *	  a modified list is returned. */static List *get_switched_clauses(List *clauses, Relids outerrelids){	List	   *t_list = NIL;	List	   *i;	foreach(i, clauses)	{		RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(i);		OpExpr	   *clause = (OpExpr *) restrictinfo->clause;		Assert(is_opclause(clause));		if (bms_is_subset(restrictinfo->right_relids, outerrelids))		{			/*			 * 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.			 */			OpExpr	   *temp = makeNode(OpExpr);			temp->opno = clause->opno;			temp->opfuncid = InvalidOid;			temp->opresulttype = clause->opresulttype;			temp->opretset = clause->opretset;			temp->args = listCopy(clause->args);			/* Commute it --- note this modifies the temp node in-place. */			CommuteClause(temp);			t_list = lappend(t_list, temp);		}		else			t_list = lappend(t_list, clause);	}	return t_list;}/* * order_qual_clauses *		Given a list of qual clauses that will all be evaluated at the same *		plan node, sort the list into the order we want to check the quals

⌨️ 快捷键说明

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