aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/path/pathkeys.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/path/pathkeys.c')
-rw-r--r--src/backend/optimizer/path/pathkeys.c137
1 files changed, 81 insertions, 56 deletions
diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c
index 8af0c6dc482..6325655eed8 100644
--- a/src/backend/optimizer/path/pathkeys.c
+++ b/src/backend/optimizer/path/pathkeys.c
@@ -36,12 +36,6 @@ static PathKey *make_canonical_pathkey(PlannerInfo *root,
EquivalenceClass *eclass, Oid opfamily,
int strategy, bool nulls_first);
static bool pathkey_is_redundant(PathKey *new_pathkey, List *pathkeys);
-static PathKey *make_pathkey_from_sortinfo(PlannerInfo *root,
- Expr *expr, Oid ordering_op,
- bool nulls_first,
- Index sortref,
- bool create_it,
- bool canonicalize);
static Var *find_indexkey_var(PlannerInfo *root, RelOptInfo *rel,
AttrNumber varattno);
static bool right_merge_direction(PlannerInfo *root, PathKey *pathkey);
@@ -224,9 +218,9 @@ canonicalize_pathkeys(PlannerInfo *root, List *pathkeys)
/*
* make_pathkey_from_sortinfo
- * Given an expression, a sortop, and a nulls-first flag, create
- * a PathKey. If canonicalize = true, the result is a "canonical"
- * PathKey, otherwise not. (But note it might be redundant anyway.)
+ * Given an expression and sort-order information, create a PathKey.
+ * If canonicalize = true, the result is a "canonical" PathKey,
+ * otherwise not. (But note it might be redundant anyway.)
*
* If the PathKey is being generated from a SortGroupClause, sortref should be
* the SortGroupClause's SortGroupRef; otherwise zero.
@@ -240,46 +234,39 @@ canonicalize_pathkeys(PlannerInfo *root, List *pathkeys)
*/
static PathKey *
make_pathkey_from_sortinfo(PlannerInfo *root,
- Expr *expr, Oid ordering_op,
+ Expr *expr,
+ Oid opfamily,
+ Oid opcintype,
+ bool reverse_sort,
bool nulls_first,
Index sortref,
bool create_it,
bool canonicalize)
{
- Oid opfamily,
- opcintype;
int16 strategy;
Oid equality_op;
List *opfamilies;
EquivalenceClass *eclass;
+ strategy = reverse_sort ? BTGreaterStrategyNumber : BTLessStrategyNumber;
+
/*
- * An ordering operator fully determines the behavior of its opfamily, so
- * could only meaningfully appear in one family --- or perhaps two if one
- * builds a reverse-sort opfamily, but there's not much point in that
- * anymore. But EquivalenceClasses need to contain opfamily lists based
- * on the family membership of equality operators, which could easily be
- * bigger. So, look up the equality operator that goes with the ordering
- * operator (this should be unique) and get its membership.
+ * EquivalenceClasses need to contain opfamily lists based on the family
+ * membership of mergejoinable equality operators, which could belong to
+ * more than one opfamily. So we have to look up the opfamily's equality
+ * operator and get its membership.
*/
-
- /* Find the operator in pg_amop --- failure shouldn't happen */
- if (!get_ordering_op_properties(ordering_op,
- &opfamily, &opcintype, &strategy))
- elog(ERROR, "operator %u is not a valid ordering operator",
- ordering_op);
- /* Get matching equality operator */
equality_op = get_opfamily_member(opfamily,
opcintype,
opcintype,
BTEqualStrategyNumber);
if (!OidIsValid(equality_op)) /* shouldn't happen */
- elog(ERROR, "could not find equality operator for ordering operator %u",
- ordering_op);
+ elog(ERROR, "could not find equality operator for opfamily %u",
+ opfamily);
opfamilies = get_mergejoin_opfamilies(equality_op);
if (!opfamilies) /* certainly should find some */
- elog(ERROR, "could not find opfamilies for ordering operator %u",
- ordering_op);
+ elog(ERROR, "could not find opfamilies for equality operator %u",
+ equality_op);
/*
* When dealing with binary-compatible opclasses, we have to ensure that
@@ -322,6 +309,42 @@ make_pathkey_from_sortinfo(PlannerInfo *root,
return makePathKey(eclass, opfamily, strategy, nulls_first);
}
+/*
+ * make_pathkey_from_sortop
+ * Like make_pathkey_from_sortinfo, but work from a sort operator.
+ *
+ * This should eventually go away, but we need to restructure SortGroupClause
+ * first.
+ */
+static PathKey *
+make_pathkey_from_sortop(PlannerInfo *root,
+ Expr *expr,
+ Oid ordering_op,
+ bool nulls_first,
+ Index sortref,
+ bool create_it,
+ bool canonicalize)
+{
+ Oid opfamily,
+ opcintype;
+ int16 strategy;
+
+ /* Find the operator in pg_amop --- failure shouldn't happen */
+ if (!get_ordering_op_properties(ordering_op,
+ &opfamily, &opcintype, &strategy))
+ elog(ERROR, "operator %u is not a valid ordering operator",
+ ordering_op);
+ return make_pathkey_from_sortinfo(root,
+ expr,
+ opfamily,
+ opcintype,
+ (strategy == BTGreaterStrategyNumber),
+ nulls_first,
+ sortref,
+ create_it,
+ canonicalize);
+}
+
/****************************************************************************
* PATHKEY COMPARISONS
@@ -479,11 +502,10 @@ get_cheapest_fractional_path_for_pathkeys(List *paths,
* 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 sortops arrays, and we will return NIL.)
+ * induce any ordering, so we 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 'scandir' is BackwardScanDirection, build pathkeys representing a
+ * backwards scan of the index.
*
* The result is canonical, meaning that redundant pathkeys are removed;
* it may therefore have fewer entries than there are index columns.
@@ -500,12 +522,16 @@ build_index_pathkeys(PlannerInfo *root,
ScanDirection scandir)
{
List *retval = NIL;
- ListCell *indexprs_item = list_head(index->indexprs);
+ ListCell *indexprs_item;
int i;
+ if (index->sortopfamily == NULL)
+ return NIL; /* non-orderable index */
+
+ indexprs_item = list_head(index->indexprs);
for (i = 0; i < index->ncolumns; i++)
{
- Oid sortop;
+ bool reverse_sort;
bool nulls_first;
int ikey;
Expr *indexkey;
@@ -513,18 +539,15 @@ build_index_pathkeys(PlannerInfo *root,
if (ScanDirectionIsBackward(scandir))
{
- sortop = index->revsortop[i];
+ reverse_sort = !index->reverse_sort[i];
nulls_first = !index->nulls_first[i];
}
else
{
- sortop = index->fwdsortop[i];
+ reverse_sort = index->reverse_sort[i];
nulls_first = index->nulls_first[i];
}
- if (!OidIsValid(sortop))
- break; /* no more orderable columns */
-
ikey = index->indexkeys[i];
if (ikey != 0)
{
@@ -543,7 +566,9 @@ build_index_pathkeys(PlannerInfo *root,
/* OK, try to make a canonical pathkey for this sort key */
cpathkey = make_pathkey_from_sortinfo(root,
indexkey,
- sortop,
+ index->sortopfamily[i],
+ index->opcintype[i],
+ reverse_sort,
nulls_first,
0,
false,
@@ -892,13 +917,13 @@ make_pathkeys_for_sortclauses(PlannerInfo *root,
sortkey = (Expr *) get_sortgroupclause_expr(sortcl, tlist);
Assert(OidIsValid(sortcl->sortop));
- pathkey = make_pathkey_from_sortinfo(root,
- sortkey,
- sortcl->sortop,
- sortcl->nulls_first,
- sortcl->tleSortGroupRef,
- true,
- canonicalize);
+ pathkey = make_pathkey_from_sortop(root,
+ sortkey,
+ sortcl->sortop,
+ sortcl->nulls_first,
+ sortcl->tleSortGroupRef,
+ true,
+ canonicalize);
/* Canonical form eliminates redundant ordering keys */
if (canonicalize)
@@ -935,13 +960,13 @@ make_pathkeys_for_aggregate(PlannerInfo *root,
* We arbitrarily set nulls_first to false. Actually, a MIN/MAX agg can
* use either nulls ordering option, but that is dealt with elsewhere.
*/
- pathkey = make_pathkey_from_sortinfo(root,
- aggtarget,
- aggsortop,
- false, /* nulls_first */
- 0,
- true,
- false);
+ pathkey = make_pathkey_from_sortop(root,
+ aggtarget,
+ aggsortop,
+ false, /* nulls_first */
+ 0,
+ true,
+ false);
return list_make1(pathkey);
}