1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-27 07:42:10 +03:00

Support ORDER BY ... NULLS FIRST/LAST, and add ASC/DESC/NULLS FIRST/NULLS LAST

per-column options for btree indexes.  The planner's support for this is still
pretty rudimentary; it does not yet know how to plan mergejoins with
nondefault ordering options.  The documentation is pretty rudimentary, too.
I'll work on improving that stuff later.

Note incompatible change from prior behavior: ORDER BY ... USING will now be
rejected if the operator is not a less-than or greater-than member of some
btree opclass.  This prevents less-than-sane behavior if an operator that
doesn't actually define a proper sort ordering is selected.
This commit is contained in:
Tom Lane
2007-01-09 02:14:16 +00:00
parent 3a32ba2f3f
commit 4431758229
65 changed files with 1476 additions and 593 deletions

View File

@@ -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;

View File

@@ -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,

View File

@@ -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 (*indexkeys != 0)
if (!OidIsValid(sortop))
break; /* no more orderable columns */
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);
}

View File

@@ -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)

View File

@@ -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 */

View File

@@ -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 */
}

View File

@@ -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;
}
}