summaryrefslogtreecommitdiff
path: root/src/backend/optimizer
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r--src/backend/optimizer/path/allpaths.c4
-rw-r--r--src/backend/optimizer/path/indxpath.c4
-rw-r--r--src/backend/optimizer/path/pathkeys.c58
-rw-r--r--src/backend/optimizer/plan/createplan.c59
-rw-r--r--src/backend/optimizer/plan/planagg.c35
-rw-r--r--src/backend/optimizer/util/clauses.c6
-rw-r--r--src/backend/optimizer/util/plancat.c56
7 files changed, 146 insertions, 76 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index c2859aba948..01178d93ddd 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.155 2007/01/05 22:19:30 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.156 2007/01/09 02:14:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -924,7 +924,7 @@ qual_is_pushdown_safe(Query *subquery, Index rti, Node *qual,
/* If subquery uses DISTINCT or DISTINCT ON, check point 4 */
if (subquery->distinctClause != NIL &&
- !targetIsInSortList(tle, subquery->distinctClause))
+ !targetIsInSortList(tle, InvalidOid, subquery->distinctClause))
{
/* non-DISTINCT column, so fail */
safe = false;
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 8906471fb7b..3fd52d48500 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.214 2007/01/05 22:19:31 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.215 2007/01/09 02:14:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -347,7 +347,7 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
* how many of them are actually useful for this query. This is not
* relevant unless we are at top level.
*/
- index_is_ordered = OidIsValid(index->ordering[0]);
+ index_is_ordered = OidIsValid(index->fwdsortop[0]);
if (index_is_ordered && istoplevel && outer_rel == NULL)
{
index_pathkeys = build_index_pathkeys(root, index,
diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c
index 2af4cf7f9e5..4fc5a5f1250 100644
--- a/src/backend/optimizer/path/pathkeys.c
+++ b/src/backend/optimizer/path/pathkeys.c
@@ -11,7 +11,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.80 2007/01/05 22:19:31 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.81 2007/01/09 02:14:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -30,7 +30,8 @@
#include "utils/memutils.h"
-static PathKeyItem *makePathKeyItem(Node *key, Oid sortop, bool checkType);
+static PathKeyItem *makePathKeyItem(Node *key, Oid sortop, bool nulls_first,
+ bool checkType);
static void generate_outer_join_implications(PlannerInfo *root,
List *equi_key_set,
Relids *relids);
@@ -53,7 +54,7 @@ static Var *find_indexkey_var(PlannerInfo *root, RelOptInfo *rel,
* create a PathKeyItem node
*/
static PathKeyItem *
-makePathKeyItem(Node *key, Oid sortop, bool checkType)
+makePathKeyItem(Node *key, Oid sortop, bool nulls_first, bool checkType)
{
PathKeyItem *item = makeNode(PathKeyItem);
@@ -78,6 +79,7 @@ makePathKeyItem(Node *key, Oid sortop, bool checkType)
item->key = key;
item->sortop = sortop;
+ item->nulls_first = nulls_first;
return item;
}
@@ -102,9 +104,11 @@ add_equijoined_keys(PlannerInfo *root, RestrictInfo *restrictinfo)
Expr *clause = restrictinfo->clause;
PathKeyItem *item1 = makePathKeyItem(get_leftop(clause),
restrictinfo->left_sortop,
+ false, /* XXX nulls_first? */
false);
PathKeyItem *item2 = makePathKeyItem(get_rightop(clause),
restrictinfo->right_sortop,
+ false, /* XXX nulls_first? */
false);
List *newset;
ListCell *cursetlink;
@@ -903,7 +907,7 @@ get_cheapest_fractional_path_for_pathkeys(List *paths,
* 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.)
+ * its sortops arrays, 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.
@@ -924,30 +928,37 @@ build_index_pathkeys(PlannerInfo *root,
bool canonical)
{
List *retval = NIL;
- int *indexkeys = index->indexkeys;
- Oid *ordering = index->ordering;
ListCell *indexprs_item = list_head(index->indexprs);
+ int i;
- while (*ordering != InvalidOid)
+ for (i = 0; i < index->ncolumns; i++)
{
- PathKeyItem *item;
Oid sortop;
+ bool nulls_first;
+ int ikey;
Node *indexkey;
+ PathKeyItem *item;
List *cpathkey;
- sortop = *ordering;
if (ScanDirectionIsBackward(scandir))
{
- sortop = get_commutator(sortop);
- if (sortop == InvalidOid)
- break; /* oops, no reverse sort operator? */
+ sortop = index->revsortop[i];
+ nulls_first = !index->nulls_first[i];
}
+ else
+ {
+ sortop = index->fwdsortop[i];
+ nulls_first = index->nulls_first[i];
+ }
+
+ if (!OidIsValid(sortop))
+ break; /* no more orderable columns */
- if (*indexkeys != 0)
+ ikey = index->indexkeys[i];
+ if (ikey != 0)
{
/* simple index column */
- indexkey = (Node *) find_indexkey_var(root, index->rel,
- *indexkeys);
+ indexkey = (Node *) find_indexkey_var(root, index->rel, ikey);
}
else
{
@@ -959,7 +970,7 @@ build_index_pathkeys(PlannerInfo *root,
}
/* OK, make a sublist for this sort key */
- item = makePathKeyItem(indexkey, sortop, true);
+ item = makePathKeyItem(indexkey, sortop, nulls_first, true);
cpathkey = make_canonical_pathkey(root, item);
/* Eliminate redundant ordering info if requested */
@@ -967,9 +978,6 @@ build_index_pathkeys(PlannerInfo *root,
retval = list_append_unique_ptr(retval, cpathkey);
else
retval = lappend(retval, cpathkey);
-
- indexkeys++;
- ordering++;
}
return retval;
@@ -1115,6 +1123,7 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
/* Found a representation for this sub_key */
outer_item = makePathKeyItem(outer_expr,
sub_item->sortop,
+ sub_item->nulls_first,
true);
/* score = # of mergejoin peers */
score = count_canonical_peers(root, outer_item);
@@ -1230,7 +1239,8 @@ make_pathkeys_for_sortclauses(List *sortclauses,
PathKeyItem *pathkey;
sortkey = get_sortgroupclause_expr(sortcl, tlist);
- pathkey = makePathKeyItem(sortkey, sortcl->sortop, true);
+ pathkey = makePathKeyItem(sortkey, sortcl->sortop, sortcl->nulls_first,
+ true);
/*
* The pathkey becomes a one-element sublist, for now;
@@ -1274,7 +1284,9 @@ cache_mergeclause_pathkeys(PlannerInfo *root, RestrictInfo *restrictinfo)
{
oldcontext = MemoryContextSwitchTo(GetMemoryChunkContext(restrictinfo));
key = get_leftop(restrictinfo->clause);
- item = makePathKeyItem(key, restrictinfo->left_sortop, false);
+ item = makePathKeyItem(key, restrictinfo->left_sortop,
+ false, /* XXX nulls_first? */
+ false);
restrictinfo->left_pathkey = make_canonical_pathkey(root, item);
MemoryContextSwitchTo(oldcontext);
}
@@ -1282,7 +1294,9 @@ cache_mergeclause_pathkeys(PlannerInfo *root, RestrictInfo *restrictinfo)
{
oldcontext = MemoryContextSwitchTo(GetMemoryChunkContext(restrictinfo));
key = get_rightop(restrictinfo->clause);
- item = makePathKeyItem(key, restrictinfo->right_sortop, false);
+ item = makePathKeyItem(key, restrictinfo->right_sortop,
+ false, /* XXX nulls_first? */
+ false);
restrictinfo->right_pathkey = make_canonical_pathkey(root, item);
MemoryContextSwitchTo(oldcontext);
}
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 7328f41a399..8f1d8e81cc4 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.219 2007/01/05 22:19:31 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.220 2007/01/09 02:14:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -117,7 +117,7 @@ static MergeJoin *make_mergejoin(List *tlist,
Plan *lefttree, Plan *righttree,
JoinType jointype);
static Sort *make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
- AttrNumber *sortColIdx, Oid *sortOperators);
+ AttrNumber *sortColIdx, Oid *sortOperators, bool *nullsFirst);
static Sort *make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree,
List *pathkeys);
@@ -734,7 +734,9 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path)
Assert(tle != NULL);
sortList = addTargetToSortList(NULL, tle,
sortList, subplan->targetlist,
- SORTBY_ASC, NIL, false);
+ SORTBY_DEFAULT,
+ SORTBY_NULLS_DEFAULT,
+ NIL, false);
}
plan = (Plan *) make_sort_from_sortclauses(root, sortList, subplan);
plan = (Plan *) make_unique(plan, sortList);
@@ -2359,11 +2361,12 @@ make_mergejoin(List *tlist,
/*
* make_sort --- basic routine to build a Sort plan node
*
- * Caller must have built the sortColIdx and sortOperators arrays already.
+ * Caller must have built the sortColIdx, sortOperators, and nullsFirst
+ * arrays already.
*/
static Sort *
make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
- AttrNumber *sortColIdx, Oid *sortOperators)
+ AttrNumber *sortColIdx, Oid *sortOperators, bool *nullsFirst)
{
Sort *node = makeNode(Sort);
Plan *plan = &node->plan;
@@ -2383,6 +2386,7 @@ make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
node->numCols = numCols;
node->sortColIdx = sortColIdx;
node->sortOperators = sortOperators;
+ node->nullsFirst = nullsFirst;
return node;
}
@@ -2397,14 +2401,23 @@ make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
* max possible number of columns. Return value is the new column count.
*/
static int
-add_sort_column(AttrNumber colIdx, Oid sortOp,
- int numCols, AttrNumber *sortColIdx, Oid *sortOperators)
+add_sort_column(AttrNumber colIdx, Oid sortOp, bool nulls_first,
+ int numCols, AttrNumber *sortColIdx,
+ Oid *sortOperators, bool *nullsFirst)
{
int i;
for (i = 0; i < numCols; i++)
{
- if (sortColIdx[i] == colIdx)
+ /*
+ * Note: we check sortOp because it's conceivable that "ORDER BY
+ * foo USING <, foo USING <<<" is not redundant, if <<< distinguishes
+ * values that < considers equal. We need not check nulls_first
+ * however because a lower-order column with the same sortop but
+ * opposite nulls direction is redundant.
+ */
+ if (sortColIdx[i] == colIdx &&
+ sortOperators[numCols] == sortOp)
{
/* Already sorting by this col, so extra sort key is useless */
return numCols;
@@ -2414,6 +2427,7 @@ add_sort_column(AttrNumber colIdx, Oid sortOp,
/* Add the column */
sortColIdx[numCols] = colIdx;
sortOperators[numCols] = sortOp;
+ nullsFirst[numCols] = nulls_first;
return numCols + 1;
}
@@ -2441,6 +2455,7 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys)
int numsortkeys;
AttrNumber *sortColIdx;
Oid *sortOperators;
+ bool *nullsFirst;
/*
* We will need at most list_length(pathkeys) sort columns; possibly less
@@ -2448,6 +2463,7 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys)
numsortkeys = list_length(pathkeys);
sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber));
sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid));
+ nullsFirst = (bool *) palloc(numsortkeys * sizeof(bool));
numsortkeys = 0;
@@ -2527,13 +2543,15 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys)
* So enter it only once in the sort arrays.
*/
numsortkeys = add_sort_column(tle->resno, pathkey->sortop,
- numsortkeys, sortColIdx, sortOperators);
+ pathkey->nulls_first,
+ numsortkeys,
+ sortColIdx, sortOperators, nullsFirst);
}
Assert(numsortkeys > 0);
return make_sort(root, lefttree, numsortkeys,
- sortColIdx, sortOperators);
+ sortColIdx, sortOperators, nullsFirst);
}
/*
@@ -2551,6 +2569,7 @@ make_sort_from_sortclauses(PlannerInfo *root, List *sortcls, Plan *lefttree)
int numsortkeys;
AttrNumber *sortColIdx;
Oid *sortOperators;
+ bool *nullsFirst;
/*
* We will need at most list_length(sortcls) sort columns; possibly less
@@ -2558,6 +2577,7 @@ make_sort_from_sortclauses(PlannerInfo *root, List *sortcls, Plan *lefttree)
numsortkeys = list_length(sortcls);
sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber));
sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid));
+ nullsFirst = (bool *) palloc(numsortkeys * sizeof(bool));
numsortkeys = 0;
@@ -2572,13 +2592,15 @@ make_sort_from_sortclauses(PlannerInfo *root, List *sortcls, Plan *lefttree)
* redundantly.
*/
numsortkeys = add_sort_column(tle->resno, sortcl->sortop,
- numsortkeys, sortColIdx, sortOperators);
+ sortcl->nulls_first,
+ numsortkeys,
+ sortColIdx, sortOperators, nullsFirst);
}
Assert(numsortkeys > 0);
return make_sort(root, lefttree, numsortkeys,
- sortColIdx, sortOperators);
+ sortColIdx, sortOperators, nullsFirst);
}
/*
@@ -2591,8 +2613,8 @@ make_sort_from_sortclauses(PlannerInfo *root, List *sortcls, Plan *lefttree)
* This might look like it could be merged with make_sort_from_sortclauses,
* but presently we *must* use the grpColIdx[] array to locate sort columns,
* because the child plan's tlist is not marked with ressortgroupref info
- * appropriate to the grouping node. So, only the sortop is used from the
- * GroupClause entries.
+ * appropriate to the grouping node. So, only the sort direction info
+ * is used from the GroupClause entries.
*/
Sort *
make_sort_from_groupcols(PlannerInfo *root,
@@ -2606,6 +2628,7 @@ make_sort_from_groupcols(PlannerInfo *root,
int numsortkeys;
AttrNumber *sortColIdx;
Oid *sortOperators;
+ bool *nullsFirst;
/*
* We will need at most list_length(groupcls) sort columns; possibly less
@@ -2613,6 +2636,7 @@ make_sort_from_groupcols(PlannerInfo *root,
numsortkeys = list_length(groupcls);
sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber));
sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid));
+ nullsFirst = (bool *) palloc(numsortkeys * sizeof(bool));
numsortkeys = 0;
@@ -2627,14 +2651,16 @@ make_sort_from_groupcols(PlannerInfo *root,
* redundantly.
*/
numsortkeys = add_sort_column(tle->resno, grpcl->sortop,
- numsortkeys, sortColIdx, sortOperators);
+ grpcl->nulls_first,
+ numsortkeys,
+ sortColIdx, sortOperators, nullsFirst);
grpno++;
}
Assert(numsortkeys > 0);
return make_sort(root, lefttree, numsortkeys,
- sortColIdx, sortOperators);
+ sortColIdx, sortOperators, nullsFirst);
}
Material *
@@ -2871,7 +2897,6 @@ make_unique(Plan *lefttree, List *distinctList)
* distinctList is a list of SortClauses, identifying the targetlist items
* that should be considered by the SetOp filter.
*/
-
SetOp *
make_setop(SetOpCmd cmd, Plan *lefttree,
List *distinctList, AttrNumber flagColIdx)
diff --git a/src/backend/optimizer/plan/planagg.c b/src/backend/optimizer/plan/planagg.c
index fa980bb9150..bce3b1ac442 100644
--- a/src/backend/optimizer/plan/planagg.c
+++ b/src/backend/optimizer/plan/planagg.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.24 2007/01/05 22:19:32 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.25 2007/01/09 02:14:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -37,6 +37,7 @@ typedef struct
Expr *target; /* expression we are aggregating on */
IndexPath *path; /* access path for index scan */
Cost pathcost; /* estimated cost to fetch first row */
+ bool nulls_first; /* null ordering direction matching index */
Param *param; /* param for subplan's output */
} MinMaxAggInfo;
@@ -277,6 +278,7 @@ build_minmax_path(PlannerInfo *root, RelOptInfo *rel, MinMaxAggInfo *info)
{
IndexPath *best_path = NULL;
Cost best_cost = 0;
+ bool best_nulls_first = false;
ListCell *l;
foreach(l, rel->indexlist)
@@ -377,11 +379,16 @@ build_minmax_path(PlannerInfo *root, RelOptInfo *rel, MinMaxAggInfo *info)
{
best_path = new_path;
best_cost = new_cost;
+ if (ScanDirectionIsForward(indexscandir))
+ best_nulls_first = index->nulls_first[indexcol];
+ else
+ best_nulls_first = !index->nulls_first[indexcol];
}
}
info->path = best_path;
info->pathcost = best_cost;
+ info->nulls_first = best_nulls_first;
return (best_path != NULL);
}
@@ -390,29 +397,30 @@ build_minmax_path(PlannerInfo *root, RelOptInfo *rel, MinMaxAggInfo *info)
* Does an aggregate match an index column?
*
* It matches if its argument is equal to the index column's data and its
- * sortop is either a LessThan or GreaterThan member of the column's opfamily.
+ * sortop is either the forward or reverse sort operator for the column.
*
- * We return ForwardScanDirection if match a LessThan member,
- * BackwardScanDirection if match a GreaterThan member,
+ * We return ForwardScanDirection if match the forward sort operator,
+ * BackwardScanDirection if match the reverse sort operator,
* and NoMovementScanDirection if there's no match.
*/
static ScanDirection
match_agg_to_index_col(MinMaxAggInfo *info, IndexOptInfo *index, int indexcol)
{
- int strategy;
+ ScanDirection result;
+
+ /* Check for operator match first (cheaper) */
+ if (info->aggsortop == index->fwdsortop[indexcol])
+ result = ForwardScanDirection;
+ else if (info->aggsortop == index->revsortop[indexcol])
+ result = BackwardScanDirection;
+ else
+ return NoMovementScanDirection;
/* Check for data match */
if (!match_index_to_operand((Node *) info->target, indexcol, index))
return NoMovementScanDirection;
- /* Look up the operator in the opfamily */
- strategy = get_op_opfamily_strategy(info->aggsortop,
- index->opfamily[indexcol]);
- if (strategy == BTLessStrategyNumber)
- return ForwardScanDirection;
- if (strategy == BTGreaterStrategyNumber)
- return BackwardScanDirection;
- return NoMovementScanDirection;
+ return result;
}
/*
@@ -458,6 +466,7 @@ make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info)
sortcl = makeNode(SortClause);
sortcl->tleSortGroupRef = assignSortGroupRef(tle, subparse->targetList);
sortcl->sortop = info->aggsortop;
+ sortcl->nulls_first = info->nulls_first;
subparse->sortClause = list_make1(sortcl);
/* set up LIMIT 1 */
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index d1ac0740c64..3250beafb67 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.227 2007/01/05 22:19:32 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.228 2007/01/09 02:14:13 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -1147,7 +1147,7 @@ has_distinct_on_clause(Query *query)
continue; /* we can ignore unsorted junk cols */
return true; /* definitely not in DISTINCT list */
}
- if (targetIsInSortList(tle, query->distinctClause))
+ if (targetIsInSortList(tle, InvalidOid, query->distinctClause))
{
if (tle->resjunk)
return true; /* junk TLE in DISTINCT means DISTINCT ON */
@@ -1158,7 +1158,7 @@ has_distinct_on_clause(Query *query)
/* This TLE is not in DISTINCT list */
if (!tle->resjunk)
return true; /* non-junk, non-DISTINCT, so DISTINCT ON */
- if (targetIsInSortList(tle, query->sortClause))
+ if (targetIsInSortList(tle, InvalidOid, query->sortClause))
return true; /* sorted, non-distinct junk */
/* unsorted junk is okay, keep looking */
}
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 353f2debe4c..9150f1d936f 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.130 2007/01/05 22:19:33 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.131 2007/01/09 02:14:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -142,7 +142,6 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
IndexOptInfo *info;
int ncolumns;
int i;
- int16 amorderstrategy;
/*
* Extract info from the relation descriptor for the index.
@@ -169,12 +168,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
info->ncolumns = ncolumns = index->indnatts;
/*
- * Need to make opfamily and ordering arrays large enough to put
- * a terminating 0 at the end of each one.
+ * Need to make opfamily array large enough to put a terminating
+ * zero at the end.
*/
info->indexkeys = (int *) palloc(sizeof(int) * ncolumns);
info->opfamily = (Oid *) palloc0(sizeof(Oid) * (ncolumns + 1));
- info->ordering = (Oid *) palloc0(sizeof(Oid) * (ncolumns + 1));
+ /* initialize these to zeroes in case index is unordered */
+ info->fwdsortop = (Oid *) palloc0(sizeof(Oid) * ncolumns);
+ info->revsortop = (Oid *) palloc0(sizeof(Oid) * ncolumns);
+ info->nulls_first = (bool *) palloc0(sizeof(bool) * ncolumns);
for (i = 0; i < ncolumns; i++)
{
@@ -189,22 +191,42 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
/*
* Fetch the ordering operators associated with the index, if any.
*/
- amorderstrategy = indexRelation->rd_am->amorderstrategy;
- if (amorderstrategy > 0)
+ if (indexRelation->rd_am->amorderstrategy > 0)
{
- int oprindex = amorderstrategy - 1;
-
- /*
- * Index AM must have a fixed set of strategies for it to
- * make sense to specify amorderstrategy, so we need not
- * allow the case amstrategies == 0.
- */
- Assert(oprindex < indexRelation->rd_am->amstrategies);
+ int nstrat = indexRelation->rd_am->amstrategies;
for (i = 0; i < ncolumns; i++)
{
- info->ordering[i] = indexRelation->rd_operator[oprindex];
- oprindex += indexRelation->rd_am->amstrategies;
+ int16 opt = indexRelation->rd_indoption[i];
+ int fwdstrat;
+ int revstrat;
+
+ if (opt & INDOPTION_DESC)
+ {
+ fwdstrat = indexRelation->rd_am->amdescorder;
+ revstrat = indexRelation->rd_am->amorderstrategy;
+ }
+ else
+ {
+ fwdstrat = indexRelation->rd_am->amorderstrategy;
+ revstrat = indexRelation->rd_am->amdescorder;
+ }
+ /*
+ * Index AM must have a fixed set of strategies for it
+ * to make sense to specify amorderstrategy, so we
+ * need not allow the case amstrategies == 0.
+ */
+ if (fwdstrat > 0)
+ {
+ Assert(fwdstrat <= nstrat);
+ info->fwdsortop[i] = indexRelation->rd_operator[i * nstrat + fwdstrat - 1];
+ }
+ if (revstrat > 0)
+ {
+ Assert(revstrat <= nstrat);
+ info->revsortop[i] = indexRelation->rd_operator[i * nstrat + revstrat - 1];
+ }
+ info->nulls_first[i] = (opt & INDOPTION_NULLS_FIRST) != 0;
}
}