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

📄 pathkeys.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
	forboth(key1, keys1, key2, keys2)	{		List	   *subkey1 = (List *) lfirst(key1);		List	   *subkey2 = (List *) lfirst(key2);		/*		 * XXX would like to check that we've been given canonicalized input,		 * but PlannerInfo not accessible here...		 */#ifdef NOT_USED		Assert(list_member_ptr(root->equi_key_list, subkey1));		Assert(list_member_ptr(root->equi_key_list, subkey2));#endif		/*		 * We will never have two subkeys where one is a subset of the other,		 * because of the canonicalization process.  Either they are equal or		 * they ain't.  Furthermore, we only need pointer comparison to detect		 * equality.		 */		if (subkey1 != subkey2)			return PATHKEYS_DIFFERENT;	/* no need to keep looking */	}	/*	 * If we reached the end of only one list, the other is longer and	 * therefore not a subset.	(We assume the additional sublist(s) of the	 * other list are not NIL --- no pathkey list should ever have a NIL	 * sublist.)	 */	if (key1 == NULL && key2 == NULL)		return PATHKEYS_EQUAL;	if (key1 != NULL)		return PATHKEYS_BETTER1;	/* key1 is longer */	return PATHKEYS_BETTER2;	/* key2 is longer */}/* * pathkeys_contained_in *	  Common special case of compare_pathkeys: we just want to know *	  if keys2 are at least as well sorted as keys1. */boolpathkeys_contained_in(List *keys1, List *keys2){	switch (compare_pathkeys(keys1, keys2))	{		case PATHKEYS_EQUAL:		case PATHKEYS_BETTER2:			return true;		default:			break;	}	return false;}/* * get_cheapest_path_for_pathkeys *	  Find the cheapest path (according to the specified criterion) that *	  satisfies the given pathkeys.  Return NULL if no such path. * * 'paths' is a list of possible paths that all generate the same relation * 'pathkeys' represents a required ordering (already canonicalized!) * 'cost_criterion' is STARTUP_COST or TOTAL_COST */Path *get_cheapest_path_for_pathkeys(List *paths, List *pathkeys,							   CostSelector cost_criterion){	Path	   *matched_path = NULL;	ListCell   *l;	foreach(l, paths)	{		Path	   *path = (Path *) lfirst(l);		/*		 * Since cost comparison is a lot cheaper than pathkey comparison, do		 * that first.	(XXX is that still true?)		 */		if (matched_path != NULL &&			compare_path_costs(matched_path, path, cost_criterion) <= 0)			continue;		if (pathkeys_contained_in(pathkeys, path->pathkeys))			matched_path = path;	}	return matched_path;}/* * get_cheapest_fractional_path_for_pathkeys *	  Find the cheapest path (for retrieving a specified fraction of all *	  the tuples) that satisfies the given pathkeys. *	  Return NULL if no such path. * * See compare_fractional_path_costs() for the interpretation of the fraction * parameter. * * 'paths' is a list of possible paths that all generate the same relation * 'pathkeys' represents a required ordering (already canonicalized!) * 'fraction' is the fraction of the total tuples expected to be retrieved */Path *get_cheapest_fractional_path_for_pathkeys(List *paths,										  List *pathkeys,										  double fraction){	Path	   *matched_path = NULL;	ListCell   *l;	foreach(l, paths)	{		Path	   *path = (Path *) lfirst(l);		/*		 * Since cost comparison is a lot cheaper than pathkey comparison, do		 * that first.		 */		if (matched_path != NULL &&			compare_fractional_path_costs(matched_path, path, fraction) <= 0)			continue;		if (pathkeys_contained_in(pathkeys, path->pathkeys))			matched_path = path;	}	return matched_path;}/**************************************************************************** *		NEW PATHKEY FORMATION ****************************************************************************//* * build_index_pathkeys *	  Build a pathkeys list that describes the ordering induced by an index *	  scan using the given index.  (Note that an unordered index doesn't *	  induce any ordering; such an index will have no sortop OIDS in *	  its "ordering" field, and we will return NIL.) * * If 'scandir' is BackwardScanDirection, attempt to build pathkeys * representing a backwards scan of the index.	Return NIL if can't do it. * * If 'canonical' is TRUE, we remove duplicate pathkeys (which can occur * if two index columns are equijoined, eg WHERE x = 1 AND y = 1).  This * is required if the result is to be compared directly to a canonical query * pathkeys list.  However, some callers want a list with exactly one entry * per index column, and they must pass FALSE. * * We generate the full pathkeys list whether or not all are useful for the * current query.  Caller should do truncate_useless_pathkeys(). */List *build_index_pathkeys(PlannerInfo *root,					 IndexOptInfo *index,					 ScanDirection scandir,					 bool canonical){	List	   *retval = NIL;	int		   *indexkeys = index->indexkeys;	Oid		   *ordering = index->ordering;	ListCell   *indexprs_item = list_head(index->indexprs);	while (*ordering != InvalidOid)	{		PathKeyItem *item;		Oid			sortop;		Node	   *indexkey;		List	   *cpathkey;		sortop = *ordering;		if (ScanDirectionIsBackward(scandir))		{			sortop = get_commutator(sortop);			if (sortop == InvalidOid)				break;			/* oops, no reverse sort operator? */		}		if (*indexkeys != 0)		{			/* simple index column */			indexkey = (Node *) find_indexkey_var(root, index->rel,												  *indexkeys);		}		else		{			/* expression --- assume we need not copy it */			if (indexprs_item == NULL)				elog(ERROR, "wrong number of index expressions");			indexkey = (Node *) lfirst(indexprs_item);			indexprs_item = lnext(indexprs_item);		}		/* OK, make a sublist for this sort key */		item = makePathKeyItem(indexkey, sortop, true);		cpathkey = make_canonical_pathkey(root, item);		/* Eliminate redundant ordering info if requested */		if (canonical)			retval = list_append_unique_ptr(retval, cpathkey);		else			retval = lappend(retval, cpathkey);		indexkeys++;		ordering++;	}	return retval;}/* * Find or make a Var node for the specified attribute of the rel. * * We first look for the var in the rel's target list, because that's * easy and fast.  But the var might not be there (this should normally * only happen for vars that are used in WHERE restriction clauses, * but not in join clauses or in the SELECT target list).  In that case, * gin up a Var node the hard way. */static Var *find_indexkey_var(PlannerInfo *root, RelOptInfo *rel, AttrNumber varattno){	ListCell   *temp;	Index		relid;	Oid			reloid,				vartypeid;	int32		type_mod;	foreach(temp, rel->reltargetlist)	{		Var		   *var = (Var *) lfirst(temp);		if (IsA(var, Var) &&			var->varattno == varattno)			return var;	}	relid = rel->relid;	reloid = getrelid(relid, root->parse->rtable);	get_atttypetypmod(reloid, varattno, &vartypeid, &type_mod);	return makeVar(relid, varattno, vartypeid, type_mod, 0);}/* * convert_subquery_pathkeys *	  Build a pathkeys list that describes the ordering of a subquery's *	  result, in the terms of the outer query.	This is essentially a *	  task of conversion. * * 'rel': outer query's RelOptInfo for the subquery relation. * 'subquery_pathkeys': the subquery's output pathkeys, in its terms. * * It is not necessary for caller to do truncate_useless_pathkeys(), * because we select keys in a way that takes usefulness of the keys into * account. */List *convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,						  List *subquery_pathkeys){	List	   *retval = NIL;	int			retvallen = 0;	int			outer_query_keys = list_length(root->query_pathkeys);	List	   *sub_tlist = rel->subplan->targetlist;	ListCell   *i;	foreach(i, subquery_pathkeys)	{		List	   *sub_pathkey = (List *) lfirst(i);		ListCell   *j;		PathKeyItem *best_item = NULL;		int			best_score = 0;		List	   *cpathkey;		/*		 * The sub_pathkey could contain multiple elements (representing		 * knowledge that multiple items are effectively equal).  Each element		 * might match none, one, or more of the output columns that are		 * visible to the outer query.	This means we may have multiple		 * possible representations of the sub_pathkey in the context of the		 * outer query.  Ideally we would generate them all and put them all		 * into a pathkey list of the outer query, thereby propagating		 * equality knowledge up to the outer query. Right now we cannot do		 * so, because the outer query's canonical pathkey sets are already		 * frozen when this is called.	Instead we prefer the one that has the		 * highest "score" (number of canonical pathkey peers, plus one if it		 * matches the outer query_pathkeys). This is the most likely to be		 * useful in the outer query.		 */		foreach(j, sub_pathkey)		{			PathKeyItem *sub_item = (PathKeyItem *) lfirst(j);			Node	   *sub_key = sub_item->key;			ListCell   *k;			foreach(k, sub_tlist)			{				TargetEntry *tle = (TargetEntry *) lfirst(k);				if (!tle->resjunk &&					equal(tle->expr, sub_key))				{					/* Found a representation for this sub_key */					Var		   *outer_var;					PathKeyItem *outer_item;					int			score;					outer_var = makeVar(rel->relid,										tle->resno,										exprType((Node *) tle->expr),										exprTypmod((Node *) tle->expr),										0);					outer_item = makePathKeyItem((Node *) outer_var,												 sub_item->sortop,												 true);					/* score = # of mergejoin peers */					score = count_canonical_peers(root, outer_item);					/* +1 if it matches the proper query_pathkeys item */					if (retvallen < outer_query_keys &&						list_member(list_nth(root->query_pathkeys, retvallen), outer_item))						score++;					if (score > best_score)					{						best_item = outer_item;						best_score = score;					}				}			}		}		/*		 * If we couldn't find a representation of this sub_pathkey, we're		 * done (we can't use the ones to its right, either).		 */		if (!best_item)			break;		/* Canonicalize the chosen item (we did not before) */		cpathkey = make_canonical_pathkey(root, best_item);		/*		 * Eliminate redundant ordering info; could happen if outer query		 * equijoins subquery keys...		 */		if (!list_member_ptr(retval, cpathkey))		{			retval = lappend(retval, cpathkey);			retvallen++;		}	}	return retval;}/* * build_join_pathkeys *	  Build the path keys for a join relation constructed by mergejoin or *	  nestloop join.  These keys should include all the path key vars of the *	  outer path (since the join will retain the ordering of the outer path) *	  plus any vars of the inner path that are equijoined to the outer vars. * *	  Per the discussion in backend/optimizer/README, equijoined inner vars *	  can be considered path keys of the result, just the same as the outer *	  vars they were joined with; furthermore, it doesn't matter what kind *	  of join algorithm is actually used. * *	  EXCEPTION: in a FULL or RIGHT join, we cannot treat the result as *	  having the outer path's path keys, because null lefthand rows may be *	  inserted at random points.  It must be treated as unsorted. * * 'joinrel' is the join relation that paths are being formed for * 'jointype' is the join type (inner, left, full, etc) * 'outer_pathkeys' is the list of the current outer path's path keys * * Returns the list of new path keys. */List *build_join_pathkeys(PlannerInfo *root,					RelOptInfo *joinrel,					JoinType jointype,					List *outer_pathkeys){	if (jointype == JOIN_FULL || jointype == JOIN_RIGHT)

⌨️ 快捷键说明

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