diff options
Diffstat (limited to 'src/backend/optimizer')
| -rw-r--r-- | src/backend/optimizer/path/allpaths.c | 4 | ||||
| -rw-r--r-- | src/backend/optimizer/path/indxpath.c | 4 | ||||
| -rw-r--r-- | src/backend/optimizer/path/pathkeys.c | 58 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/createplan.c | 59 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/planagg.c | 35 | ||||
| -rw-r--r-- | src/backend/optimizer/util/clauses.c | 6 | ||||
| -rw-r--r-- | src/backend/optimizer/util/plancat.c | 56 |
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; } } |
