aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/path/pathkeys.c
diff options
context:
space:
mode:
authorBruce Momjian <bruce@momjian.us>2000-04-12 17:17:23 +0000
committerBruce Momjian <bruce@momjian.us>2000-04-12 17:17:23 +0000
commit52f77df613cea1803ce86321c37229626d9f213c (patch)
treebd9ac9f667f295cb65f4c448a5bb5a062d656b27 /src/backend/optimizer/path/pathkeys.c
parentdb4518729d85da83eafdacbcebaeb12618517595 (diff)
downloadpostgresql-52f77df613cea1803ce86321c37229626d9f213c.tar.gz
postgresql-52f77df613cea1803ce86321c37229626d9f213c.zip
Ye-old pgindent run. Same 4-space tabs.
Diffstat (limited to 'src/backend/optimizer/path/pathkeys.c')
-rw-r--r--src/backend/optimizer/path/pathkeys.c168
1 files changed, 90 insertions, 78 deletions
diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c
index d5fbf82eb50..580675a85b7 100644
--- a/src/backend/optimizer/path/pathkeys.c
+++ b/src/backend/optimizer/path/pathkeys.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.20 2000/02/18 23:47:19 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.21 2000/04/12 17:15:20 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,7 +28,7 @@
static PathKeyItem *makePathKeyItem(Node *key, Oid sortop);
static List *make_canonical_pathkey(Query *root, PathKeyItem *item);
static Var *find_indexkey_var(Query *root, RelOptInfo *rel,
- AttrNumber varattno);
+ AttrNumber varattno);
/*--------------------
@@ -42,8 +42,8 @@ static Var *find_indexkey_var(Query *root, RelOptInfo *rel,
* of scanning the relation and the resulting ordering of the tuples.
* Sequential scan Paths have NIL pathkeys, indicating no known ordering.
* Index scans have Path.pathkeys that represent the chosen index's ordering,
- * if any. A single-key index would create a pathkey with a single sublist,
- * e.g. ( (tab1.indexkey1/sortop1) ). A multi-key index generates a sublist
+ * if any. A single-key index would create a pathkey with a single sublist,
+ * e.g. ( (tab1.indexkey1/sortop1) ). A multi-key index generates a sublist
* per key, e.g. ( (tab1.indexkey1/sortop1) (tab1.indexkey2/sortop2) ) which
* shows major sort by indexkey1 (ordering by sortop1) and minor sort by
* indexkey2 with sortop2.
@@ -56,10 +56,10 @@ static Var *find_indexkey_var(Query *root, RelOptInfo *rel,
* ordering operators used.
*
* Things get more interesting when we consider joins. Suppose we do a
- * mergejoin between A and B using the mergeclause A.X = B.Y. The output
+ * mergejoin between A and B using the mergeclause A.X = B.Y. The output
* of the mergejoin is sorted by X --- but it is also sorted by Y. We
* represent this fact by listing both keys in a single pathkey sublist:
- * ( (A.X/xsortop B.Y/ysortop) ). This pathkey asserts that the major
+ * ( (A.X/xsortop B.Y/ysortop) ). This pathkey asserts that the major
* sort order of the Path can be taken to be *either* A.X or B.Y.
* They are equal, so they are both primary sort keys. By doing this,
* we allow future joins to use either var as a pre-sorted key, so upper
@@ -120,12 +120,12 @@ static Var *find_indexkey_var(Query *root, RelOptInfo *rel,
* We did implement pathkeys just as described above, and found that the
* planner spent a huge amount of time comparing pathkeys, because the
* representation of pathkeys as unordered lists made it expensive to decide
- * whether two were equal or not. So, we've modified the representation
+ * whether two were equal or not. So, we've modified the representation
* as described next.
*
* If we scan the WHERE clause for equijoin clauses (mergejoinable clauses)
* during planner startup, we can construct lists of equivalent pathkey items
- * for the query. There could be more than two items per equivalence set;
+ * for the query. There could be more than two items per equivalence set;
* for example, WHERE A.X = B.Y AND B.Y = C.Z AND D.R = E.S creates the
* equivalence sets { A.X B.Y C.Z } and { D.R E.S } (plus associated sortops).
* Any pathkey item that belongs to an equivalence set implies that all the
@@ -147,20 +147,20 @@ static Var *find_indexkey_var(Query *root, RelOptInfo *rel,
* equivalence set, we instantly add all the other vars equivalenced to it,
* whether they appear yet in the pathkey's relation or not. And we also
* mandate that the pathkey sublist appear in the same order as the
- * equivalence set it comes from. (In practice, we simply return a pointer
+ * equivalence set it comes from. (In practice, we simply return a pointer
* to the relevant equivalence set without building any new sublist at all.)
* This makes comparing pathkeys very simple and fast, and saves a lot of
* work and memory space for pathkey construction as well.
*
* Note that pathkey sublists having just one item still exist, and are
- * not expected to be equal() to any equivalence set. This occurs when
+ * not expected to be equal() to any equivalence set. This occurs when
* we describe a sort order that involves a var that's not mentioned in
* any equijoin clause of the WHERE. We could add singleton sets containing
* such vars to the query's list of equivalence sets, but there's little
* point in doing so.
*
* By the way, it's OK and even useful for us to build equivalence sets
- * that mention multiple vars from the same relation. For example, if
+ * that mention multiple vars from the same relation. For example, if
* we have WHERE A.X = A.Y and we are scanning A using an index on X,
* we can legitimately conclude that the path is sorted by Y as well;
* and this could be handy if Y is the variable used in other join clauses
@@ -179,7 +179,7 @@ static Var *find_indexkey_var(Query *root, RelOptInfo *rel,
static PathKeyItem *
makePathKeyItem(Node *key, Oid sortop)
{
- PathKeyItem *item = makeNode(PathKeyItem);
+ PathKeyItem *item = makeNode(PathKeyItem);
item->key = key;
item->sortop = sortop;
@@ -219,11 +219,13 @@ add_equijoined_keys(Query *root, RestrictInfo *restrictinfo)
/* We might see a clause X=X; don't make a single-element list from it */
if (equal(item1, item2))
return;
+
/*
- * Our plan is to make a two-element set, then sweep through the existing
- * equijoin sets looking for matches to item1 or item2. When we find one,
- * we remove that set from equi_key_list and union it into our new set.
- * When done, we add the new set to the front of equi_key_list.
+ * Our plan is to make a two-element set, then sweep through the
+ * existing equijoin sets looking for matches to item1 or item2. When
+ * we find one, we remove that set from equi_key_list and union it
+ * into our new set. When done, we add the new set to the front of
+ * equi_key_list.
*
* This is a standard UNION-FIND problem, for which there exist better
* data structures than simple lists. If this code ever proves to be
@@ -240,8 +242,11 @@ add_equijoined_keys(Query *root, RestrictInfo *restrictinfo)
{
/* Found a set to merge into our new set */
newset = LispUnion(newset, curset);
- /* Remove old set from equi_key_list. NOTE this does not change
- * lnext(cursetlink), so the outer foreach doesn't break.
+
+ /*
+ * Remove old set from equi_key_list. NOTE this does not
+ * change lnext(cursetlink), so the outer foreach doesn't
+ * break.
*/
root->equi_key_list = lremove(curset, root->equi_key_list);
freeList(curset); /* might as well recycle old cons cells */
@@ -256,7 +261,7 @@ add_equijoined_keys(Query *root, RestrictInfo *restrictinfo)
* Given a PathKeyItem, find the equi_key_list subset it is a member of,
* if any. If so, return a pointer to that sublist, which is the
* canonical representation (for this query) of that PathKeyItem's
- * equivalence set. If it is not found, return a single-element list
+ * equivalence set. If it is not found, return a single-element list
* containing the PathKeyItem (when the item has no equivalence peers,
* we just allow it to be a standalone list).
*
@@ -293,13 +298,13 @@ canonicalize_pathkeys(Query *root, List *pathkeys)
foreach(i, pathkeys)
{
- List *pathkey = (List *) lfirst(i);
- PathKeyItem *item;
+ List *pathkey = (List *) lfirst(i);
+ PathKeyItem *item;
/*
- * It's sufficient to look at the first entry in the sublist;
- * if there are more entries, they're already part of an
- * equivalence set by definition.
+ * It's sufficient to look at the first entry in the sublist; if
+ * there are more entries, they're already part of an equivalence
+ * set by definition.
*/
Assert(pathkey != NIL);
item = (PathKeyItem *) lfirst(pathkey);
@@ -319,12 +324,12 @@ canonicalize_pathkeys(Query *root, List *pathkeys)
* one is "better" than the other.
*
* A pathkey can be considered better than another if it is a superset:
- * it contains all the keys of the other plus more. For example, either
+ * it contains all the keys of the other plus more. For example, either
* ((A) (B)) or ((A B)) is better than ((A)).
*
* Because we actually only expect to see canonicalized pathkey sublists,
* we don't have to do the full two-way-subset-inclusion test on each
- * pair of sublists that is implied by the above statement. Instead we
+ * pair of sublists that is implied by the above statement. Instead we
* just do an equal(). In the normal case where multi-element sublists
* are pointers into the root's equi_key_list, equal() will be very fast:
* it will recognize pointer equality when the sublists are the same,
@@ -345,23 +350,25 @@ compare_pathkeys(List *keys1, List *keys2)
List *subkey1 = lfirst(key1);
List *subkey2 = lfirst(key2);
- /* We will never have two subkeys where one is a subset of the other,
- * because of the canonicalization explained above. Either they are
- * equal or they ain't.
+ /*
+ * We will never have two subkeys where one is a subset of the
+ * other, because of the canonicalization explained above. Either
+ * they are equal or they ain't.
*/
- if (! equal(subkey1, subkey2))
- return PATHKEYS_DIFFERENT; /* no need to keep looking */
+ if (!equal(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 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 == NIL && key2 == NIL)
return PATHKEYS_EQUAL;
if (key1 != NIL)
- return PATHKEYS_BETTER1; /* key1 is longer */
+ return PATHKEYS_BETTER1;/* key1 is longer */
return PATHKEYS_BETTER2; /* key2 is longer */
}
@@ -375,8 +382,8 @@ pathkeys_contained_in(List *keys1, List *keys2)
{
switch (compare_pathkeys(keys1, keys2))
{
- case PATHKEYS_EQUAL:
- case PATHKEYS_BETTER2:
+ case PATHKEYS_EQUAL:
+ case PATHKEYS_BETTER2:
return true;
default:
break;
@@ -448,7 +455,7 @@ get_cheapest_fractional_path_for_pathkeys(List *paths,
* do that first.
*/
if (matched_path != NULL &&
- compare_fractional_path_costs(matched_path, path, fraction) <= 0)
+ compare_fractional_path_costs(matched_path, path, fraction) <= 0)
continue;
if (pathkeys_contained_in(pathkeys, path->pathkeys))
@@ -469,7 +476,7 @@ get_cheapest_fractional_path_for_pathkeys(List *paths,
* 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.
+ * representing a backwards scan of the index. Return NIL if can't do it.
*/
List *
build_index_pathkeys(Query *root,
@@ -527,7 +534,7 @@ build_index_pathkeys(Query *root,
/* Normal non-functional index */
while (*indexkeys != 0 && *ordering != InvalidOid)
{
- Var *relvar = find_indexkey_var(root, rel, *indexkeys);
+ Var *relvar = find_indexkey_var(root, rel, *indexkeys);
sortop = *ordering;
if (ScanDirectionIsBackward(scandir))
@@ -569,9 +576,9 @@ find_indexkey_var(Query *root, RelOptInfo *rel, AttrNumber varattno)
foreach(temp, rel->targetlist)
{
- Var *tle_var = get_expr(lfirst(temp));
+ Var *tle_var = get_expr(lfirst(temp));
- if (IsA(tle_var, Var) && tle_var->varattno == varattno)
+ if (IsA(tle_var, Var) &&tle_var->varattno == varattno)
return tle_var;
}
@@ -606,11 +613,12 @@ build_join_pathkeys(List *outer_pathkeys,
List *join_rel_tlist,
List *equi_key_list)
{
+
/*
* This used to be quite a complex bit of code, but now that all
- * pathkey sublists start out life canonicalized, we don't have to
- * do a darn thing here! The inner-rel vars we used to need to add
- * are *already* part of the outer pathkey!
+ * pathkey sublists start out life canonicalized, we don't have to do
+ * a darn thing here! The inner-rel vars we used to need to add are
+ * *already* part of the outer pathkey!
*
* I'd remove the routine entirely, but maybe someday we'll need it...
*/
@@ -644,16 +652,17 @@ make_pathkeys_for_sortclauses(List *sortclauses,
foreach(i, sortclauses)
{
- SortClause *sortcl = (SortClause *) lfirst(i);
- Node *sortkey;
- PathKeyItem *pathkey;
+ SortClause *sortcl = (SortClause *) lfirst(i);
+ Node *sortkey;
+ PathKeyItem *pathkey;
sortkey = get_sortgroupclause_expr(sortcl, tlist);
pathkey = makePathKeyItem(sortkey, sortcl->sortop);
+
/*
* The pathkey becomes a one-element sublist, for now;
- * canonicalize_pathkeys() might replace it with a longer
- * sublist later.
+ * canonicalize_pathkeys() might replace it with a longer sublist
+ * later.
*/
pathkeys = lappend(pathkeys, lcons(pathkey, NIL));
}
@@ -691,28 +700,28 @@ find_mergeclauses_for_pathkeys(List *pathkeys, List *restrictinfos)
foreach(i, pathkeys)
{
- List *pathkey = lfirst(i);
- RestrictInfo *matched_restrictinfo = NULL;
- List *j;
+ List *pathkey = lfirst(i);
+ RestrictInfo *matched_restrictinfo = NULL;
+ List *j;
/*
- * We can match any of the keys in this pathkey sublist,
- * since they're all equivalent. And we can match against
- * either left or right side of any mergejoin clause we haven't
- * used yet. For the moment we use a dumb "greedy" algorithm
- * with no backtracking. Is it worth being any smarter to
- * make a longer list of usable mergeclauses? Probably not.
+ * We can match any of the keys in this pathkey sublist, since
+ * they're all equivalent. And we can match against either left
+ * or right side of any mergejoin clause we haven't used yet. For
+ * the moment we use a dumb "greedy" algorithm with no
+ * backtracking. Is it worth being any smarter to make a longer
+ * list of usable mergeclauses? Probably not.
*/
foreach(j, pathkey)
{
- PathKeyItem *keyitem = lfirst(j);
- Node *key = keyitem->key;
- Oid keyop = keyitem->sortop;
- List *k;
+ PathKeyItem *keyitem = lfirst(j);
+ Node *key = keyitem->key;
+ Oid keyop = keyitem->sortop;
+ List *k;
foreach(k, restrictinfos)
{
- RestrictInfo *restrictinfo = lfirst(k);
+ RestrictInfo *restrictinfo = lfirst(k);
Assert(restrictinfo->mergejoinoperator != InvalidOid);
@@ -720,7 +729,7 @@ find_mergeclauses_for_pathkeys(List *pathkeys, List *restrictinfos)
equal(key, get_leftop(restrictinfo->clause))) ||
(keyop == restrictinfo->right_sortop &&
equal(key, get_rightop(restrictinfo->clause)))) &&
- ! member(restrictinfo, mergeclauses))
+ !member(restrictinfo, mergeclauses))
{
matched_restrictinfo = restrictinfo;
break;
@@ -732,11 +741,12 @@ find_mergeclauses_for_pathkeys(List *pathkeys, List *restrictinfos)
/*
* If we didn't find a mergeclause, we're done --- any additional
- * sort-key positions in the pathkeys are useless. (But we can
+ * sort-key positions in the pathkeys are useless. (But we can
* still mergejoin if we found at least one mergeclause.)
*/
- if (! matched_restrictinfo)
+ if (!matched_restrictinfo)
break;
+
/*
* If we did find a usable mergeclause for this sort-key position,
* add it to result list.
@@ -756,7 +766,7 @@ find_mergeclauses_for_pathkeys(List *pathkeys, List *restrictinfos)
* 'mergeclauses' is a list of RestrictInfos for mergejoin clauses
* that will be used in a merge join.
* 'tlist' is a relation target list for either the inner or outer
- * side of the proposed join rel. (Not actually needed anymore)
+ * side of the proposed join rel. (Not actually needed anymore)
*
* Returns a pathkeys list that can be applied to the indicated relation.
*
@@ -785,24 +795,26 @@ make_pathkeys_for_mergeclauses(Query *root,
/*
* Find the key and sortop needed for this mergeclause.
*
- * Both sides of the mergeclause should appear in one of the
- * query's pathkey equivalence classes, so it doesn't matter
- * which one we use here.
+ * Both sides of the mergeclause should appear in one of the query's
+ * pathkey equivalence classes, so it doesn't matter which one we
+ * use here.
*/
key = (Node *) get_leftop(restrictinfo->clause);
sortop = restrictinfo->left_sortop;
+
/*
- * Find pathkey sublist for this sort item. We expect to find
- * the canonical set including the mergeclause's left and right
- * sides; if we get back just the one item, something is rotten.
+ * Find pathkey sublist for this sort item. We expect to find the
+ * canonical set including the mergeclause's left and right sides;
+ * if we get back just the one item, something is rotten.
*/
item = makePathKeyItem(key, sortop);
pathkey = make_canonical_pathkey(root, item);
Assert(length(pathkey) > 1);
+
/*
- * Since the item we just made is not in the returned canonical set,
- * we can free it --- this saves a useful amount of storage in a
- * big join tree.
+ * Since the item we just made is not in the returned canonical
+ * set, we can free it --- this saves a useful amount of storage
+ * in a big join tree.
*/
pfree(item);