]> granicus.if.org Git - postgresql/commitdiff
Simplify and speed up mapping of index opfamilies to pathkeys.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 29 Nov 2010 17:29:42 +0000 (12:29 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 29 Nov 2010 17:30:43 +0000 (12:30 -0500)
Formerly we looked up the operators associated with each index (caching
them in relcache) and then the planner looked up the btree opfamily
containing such operators in order to build the btree-centric pathkey
representation that describes the index's sort order.  This is quite
pointless for btree indexes: we might as well just use the index's opfamily
information directly.  That saves syscache lookup cycles during planning,
and furthermore allows us to eliminate the relcache's caching of operators
altogether, which may help in reducing backend startup time.

I added code to plancat.c to perform the same type of double lookup
on-the-fly if it's ever faced with a non-btree amcanorder index AM.
If such a thing actually becomes interesting for production, we should
replace that logic with some more-direct method for identifying the
corresponding btree opfamily; but it's not worth spending effort on now.

There is considerably more to do pursuant to my recent proposal to get rid
of sort-operator-based representations of sort orderings, but this patch
grabs some of the low-hanging fruit.  I'll look at the remainder of that
work after the current commitfest.

src/backend/optimizer/path/indxpath.c
src/backend/optimizer/path/pathkeys.c
src/backend/optimizer/util/plancat.c
src/backend/utils/adt/selfuncs.c
src/backend/utils/cache/relcache.c
src/include/nodes/relation.h
src/include/utils/rel.h

index d8fc12068fb6113c0baf8aa4e5941e0150ce3521..f73e0e6dc6007ce768828480f74621752aaf57d2 100644 (file)
@@ -380,7 +380,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->fwdsortop[0]);
+               index_is_ordered = (index->sortopfamily != NULL);
                if (index_is_ordered && possibly_useful_pathkeys &&
                        istoplevel && outer_rel == NULL)
                {
index 8af0c6dc482372244b15a8a5f5a4a562e34ac91b..6325655eed84759168a51aed3f712582ec9c1f00 100644 (file)
@@ -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);
 }
 
index 908b4f7205d86f0888007d3a05e65b13132520b9..2ab272552be03ec16bfdde5a484a2e700e46d129 100644 (file)
@@ -189,19 +189,9 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
                                RelationGetForm(indexRelation)->reltablespace;
                        info->rel = rel;
                        info->ncolumns = ncolumns = index->indnatts;
-
-                       /*
-                        * Allocate per-column info arrays.  To save a few palloc cycles
-                        * we allocate all the Oid-type arrays in one request.  We must
-                        * pre-zero the sortop and nulls_first arrays in case the index is
-                        * unordered.
-                        */
                        info->indexkeys = (int *) palloc(sizeof(int) * ncolumns);
-                       info->opfamily = (Oid *) palloc0(sizeof(Oid) * (4 * ncolumns));
-                       info->opcintype = info->opfamily + ncolumns;
-                       info->fwdsortop = info->opcintype + ncolumns;
-                       info->revsortop = info->fwdsortop + ncolumns;
-                       info->nulls_first = (bool *) palloc0(sizeof(bool) * ncolumns);
+                       info->opfamily = (Oid *) palloc(sizeof(Oid) * ncolumns);
+                       info->opcintype = (Oid *) palloc(sizeof(Oid) * ncolumns);
 
                        for (i = 0; i < ncolumns; i++)
                        {
@@ -219,49 +209,90 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
                        info->amhasgetbitmap = OidIsValid(indexRelation->rd_am->amgetbitmap);
 
                        /*
-                        * Fetch the ordering operators associated with the index, if any.
-                        * We expect that all ordering-capable indexes use btree's
-                        * strategy numbers for the ordering operators.
+                        * Fetch the ordering information for the index, if any.
                         */
-                       if (indexRelation->rd_am->amcanorder)
+                       if (info->relam == BTREE_AM_OID)
                        {
-                               int                     nstrat = indexRelation->rd_am->amstrategies;
+                               /*
+                                * If it's a btree index, we can use its opfamily OIDs
+                                * directly as the sort ordering opfamily OIDs.
+                                */
+                               Assert(indexRelation->rd_am->amcanorder);
+
+                               info->sortopfamily = info->opfamily;
+                               info->reverse_sort = (bool *) palloc(sizeof(bool) * ncolumns);
+                               info->nulls_first = (bool *) palloc(sizeof(bool) * ncolumns);
 
                                for (i = 0; i < ncolumns; i++)
                                {
                                        int16           opt = indexRelation->rd_indoption[i];
-                                       int                     fwdstrat;
-                                       int                     revstrat;
 
-                                       if (opt & INDOPTION_DESC)
-                                       {
-                                               fwdstrat = BTGreaterStrategyNumber;
-                                               revstrat = BTLessStrategyNumber;
-                                       }
-                                       else
-                                       {
-                                               fwdstrat = BTLessStrategyNumber;
-                                               revstrat = BTGreaterStrategyNumber;
-                                       }
+                                       info->reverse_sort[i] = (opt & INDOPTION_DESC) != 0;
+                                       info->nulls_first[i] = (opt & INDOPTION_NULLS_FIRST) != 0;
+                               }
+                       }
+                       else if (indexRelation->rd_am->amcanorder)
+                       {
+                               /*
+                                * Otherwise, identify the corresponding btree opfamilies by
+                                * trying to map this index's "<" operators into btree.  Since
+                                * "<" uniquely defines the behavior of a sort order, this is
+                                * a sufficient test.
+                                *
+                                * XXX This method is rather slow and also requires the
+                                * undesirable assumption that the other index AM numbers its
+                                * strategies the same as btree.  It'd be better to have a way
+                                * to explicitly declare the corresponding btree opfamily for
+                                * each opfamily of the other index type.  But given the lack
+                                * of current or foreseeable amcanorder index types, it's not
+                                * worth expending more effort on now.
+                                */
+                               info->sortopfamily = (Oid *) palloc(sizeof(Oid) * ncolumns);
+                               info->reverse_sort = (bool *) palloc(sizeof(bool) * ncolumns);
+                               info->nulls_first = (bool *) palloc(sizeof(bool) * ncolumns);
+
+                               for (i = 0; i < ncolumns; i++)
+                               {
+                                       int16           opt = indexRelation->rd_indoption[i];
+                                       Oid                     ltopr;
+                                       Oid                     btopfamily;
+                                       Oid                     btopcintype;
+                                       int16           btstrategy;
 
-                                       /*
-                                        * Index AM must have a fixed set of strategies for it to
-                                        * make sense to specify amcanorder, so we need not allow
-                                        * the case amstrategies == 0.
-                                        */
-                                       if (fwdstrat > 0)
+                                       info->reverse_sort[i] = (opt & INDOPTION_DESC) != 0;
+                                       info->nulls_first[i] = (opt & INDOPTION_NULLS_FIRST) != 0;
+
+                                       ltopr = get_opfamily_member(info->opfamily[i],
+                                                                                               info->opcintype[i],
+                                                                                               info->opcintype[i],
+                                                                                               BTLessStrategyNumber);
+                                       if (OidIsValid(ltopr) &&
+                                               get_ordering_op_properties(ltopr,
+                                                                                                  &btopfamily,
+                                                                                                  &btopcintype,
+                                                                                                  &btstrategy) &&
+                                               btopcintype == info->opcintype[i] &&
+                                               btstrategy == BTLessStrategyNumber)
                                        {
-                                               Assert(fwdstrat <= nstrat);
-                                               info->fwdsortop[i] = indexRelation->rd_operator[i * nstrat + fwdstrat - 1];
+                                               /* Successful mapping */
+                                               info->sortopfamily[i] = btopfamily;
                                        }
-                                       if (revstrat > 0)
+                                       else
                                        {
-                                               Assert(revstrat <= nstrat);
-                                               info->revsortop[i] = indexRelation->rd_operator[i * nstrat + revstrat - 1];
+                                               /* Fail ... quietly treat index as unordered */
+                                               info->sortopfamily = NULL;
+                                               info->reverse_sort = NULL;
+                                               info->nulls_first = NULL;
+                                               break;
                                        }
-                                       info->nulls_first[i] = (opt & INDOPTION_NULLS_FIRST) != 0;
                                }
                        }
+                       else
+                       {
+                               info->sortopfamily = NULL;
+                               info->reverse_sort = NULL;
+                               info->nulls_first = NULL;
+                       }
 
                        /*
                         * Fetch the index expressions and predicate, if any.  We must
index c7442218a84a12972658ef320c20c7aa783b80a7..95397aa7cee3132db72138443bd7181ff5c32889 100644 (file)
@@ -4567,14 +4567,26 @@ get_actual_variable_range(PlannerInfo *root, VariableStatData *vardata,
                 * The first index column must match the desired variable and sort
                 * operator --- but we can use a descending-order index.
                 */
-               if (sortop == index->fwdsortop[0])
-                       indexscandir = ForwardScanDirection;
-               else if (sortop == index->revsortop[0])
-                       indexscandir = BackwardScanDirection;
-               else
-                       continue;
                if (!match_index_to_operand(vardata->var, 0, index))
                        continue;
+               switch (get_op_opfamily_strategy(sortop, index->sortopfamily[0]))
+               {
+                       case BTLessStrategyNumber:
+                               if (index->reverse_sort[0])
+                                       indexscandir = BackwardScanDirection;
+                               else
+                                       indexscandir = ForwardScanDirection;
+                               break;
+                       case BTGreaterStrategyNumber:
+                               if (index->reverse_sort[0])
+                                       indexscandir = ForwardScanDirection;
+                               else
+                                       indexscandir = BackwardScanDirection;
+                               break;
+                       default:
+                               /* index doesn't match the sortop */
+                               continue;
+               }
 
                /*
                 * Found a suitable index to extract data from.  We'll need an EState
@@ -6150,12 +6162,18 @@ btcostestimate(PG_FUNCTION_ARGS)
 
        if (HeapTupleIsValid(vardata.statsTuple))
        {
+               Oid                     sortop;
                float4     *numbers;
                int                     nnumbers;
 
-               if (get_attstatsslot(vardata.statsTuple, InvalidOid, 0,
+               sortop = get_opfamily_member(index->opfamily[0],
+                                                                        index->opcintype[0],
+                                                                        index->opcintype[0],
+                                                                        BTLessStrategyNumber);
+               if (OidIsValid(sortop) &&
+                       get_attstatsslot(vardata.statsTuple, InvalidOid, 0,
                                                         STATISTIC_KIND_CORRELATION,
-                                                        index->fwdsortop[0],
+                                                        sortop,
                                                         NULL,
                                                         NULL, NULL,
                                                         &numbers, &nnumbers))
@@ -6165,6 +6183,9 @@ btcostestimate(PG_FUNCTION_ARGS)
                        Assert(nnumbers == 1);
                        varCorrelation = numbers[0];
 
+                       if (index->reverse_sort[0])
+                               varCorrelation = -varCorrelation;
+
                        if (index->ncolumns > 1)
                                *indexCorrelation = varCorrelation * 0.75;
                        else
@@ -6172,25 +6193,6 @@ btcostestimate(PG_FUNCTION_ARGS)
 
                        free_attstatsslot(InvalidOid, NULL, 0, numbers, nnumbers);
                }
-               else if (get_attstatsslot(vardata.statsTuple, InvalidOid, 0,
-                                                                 STATISTIC_KIND_CORRELATION,
-                                                                 index->revsortop[0],
-                                                                 NULL,
-                                                                 NULL, NULL,
-                                                                 &numbers, &nnumbers))
-               {
-                       double          varCorrelation;
-
-                       Assert(nnumbers == 1);
-                       varCorrelation = numbers[0];
-
-                       if (index->ncolumns > 1)
-                               *indexCorrelation = -varCorrelation * 0.75;
-                       else
-                               *indexCorrelation = -varCorrelation;
-
-                       free_attstatsslot(InvalidOid, NULL, 0, numbers, nnumbers);
-               }
        }
 
        ReleaseVariableStats(vardata);
index 9353a347bcb3692a4c82bc4ea3c275610e42fd82..8df12a1424322501c2a55a59723a4b21880dfb35 100644 (file)
@@ -39,7 +39,6 @@
 #include "catalog/index.h"
 #include "catalog/indexing.h"
 #include "catalog/namespace.h"
-#include "catalog/pg_amop.h"
 #include "catalog/pg_amproc.h"
 #include "catalog/pg_attrdef.h"
 #include "catalog/pg_authid.h"
@@ -48,7 +47,6 @@
 #include "catalog/pg_database.h"
 #include "catalog/pg_namespace.h"
 #include "catalog/pg_opclass.h"
-#include "catalog/pg_operator.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_rewrite.h"
 #include "catalog/pg_tablespace.h"
  */
 #define RELCACHE_INIT_FILENAME "pg_internal.init"
 
-#define RELCACHE_INIT_FILEMAGIC                0x573265        /* version ID value */
+#define RELCACHE_INIT_FILEMAGIC                0x573266        /* version ID value */
 
 /*
- *             hardcoded tuple descriptors, generated by genbki.pl
+ *             hardcoded tuple descriptors, contents generated by genbki.pl
  */
 static const FormData_pg_attribute Desc_pg_class[Natts_pg_class] = {Schema_pg_class};
 static const FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute] = {Schema_pg_attribute};
@@ -185,19 +183,17 @@ do { \
 /*
  * Special cache for opclass-related information
  *
- * Note: only default operators and support procs get cached, ie, those with
+ * Note: only default support procs get cached, ie, those with
  * lefttype = righttype = opcintype.
  */
 typedef struct opclasscacheent
 {
        Oid                     opclassoid;             /* lookup key: OID of opclass */
        bool            valid;                  /* set TRUE after successful fill-in */
-       StrategyNumber numStrats;       /* max # of strategies (from pg_am) */
        StrategyNumber numSupport;      /* max # of support procs (from pg_am) */
        Oid                     opcfamily;              /* OID of opclass's family */
        Oid                     opcintype;              /* OID of opclass's declared input type */
-       Oid                *operatorOids;       /* strategy operators' OIDs */
-       RegProcedure *supportProcs; /* support procs */
+       RegProcedure *supportProcs; /* OIDs of support procedures */
 } OpClassCacheEnt;
 
 static HTAB *OpClassCache = NULL;
@@ -231,15 +227,12 @@ static void AttrDefaultFetch(Relation relation);
 static void CheckConstraintFetch(Relation relation);
 static List *insert_ordered_oid(List *list, Oid datum);
 static void IndexSupportInitialize(oidvector *indclass,
-                                          Oid *indexOperator,
                                           RegProcedure *indexSupport,
                                           Oid *opFamily,
                                           Oid *opcInType,
-                                          StrategyNumber maxStrategyNumber,
                                           StrategyNumber maxSupportNumber,
                                           AttrNumber maxAttributeNumber);
 static OpClassCacheEnt *LookupOpclassInfo(Oid operatorClassOid,
-                                 StrategyNumber numStrats,
                                  StrategyNumber numSupport);
 static void RelationCacheInitFileRemoveInDir(const char *tblspcpath);
 static void unlink_initfile(const char *initfilename);
@@ -980,7 +973,6 @@ RelationInitIndexAccessInfo(Relation relation)
        MemoryContext indexcxt;
        MemoryContext oldcontext;
        int                     natts;
-       uint16          amstrategies;
        uint16          amsupport;
 
        /*
@@ -1015,7 +1007,6 @@ RelationInitIndexAccessInfo(Relation relation)
        if (natts != relation->rd_index->indnatts)
                elog(ERROR, "relnatts disagrees with indnatts for index %u",
                         RelationGetRelid(relation));
-       amstrategies = aform->amstrategies;
        amsupport = aform->amsupport;
 
        /*
@@ -1044,13 +1035,6 @@ RelationInitIndexAccessInfo(Relation relation)
        relation->rd_opcintype = (Oid *)
                MemoryContextAllocZero(indexcxt, natts * sizeof(Oid));
 
-       if (amstrategies > 0)
-               relation->rd_operator = (Oid *)
-                       MemoryContextAllocZero(indexcxt,
-                                                                  natts * amstrategies * sizeof(Oid));
-       else
-               relation->rd_operator = NULL;
-
        if (amsupport > 0)
        {
                int                     nsupport = natts * amsupport;
@@ -1082,14 +1066,13 @@ RelationInitIndexAccessInfo(Relation relation)
        indclass = (oidvector *) DatumGetPointer(indclassDatum);
 
        /*
-        * Fill the operator and support procedure OID arrays, as well as the info
-        * about opfamilies and opclass input types.  (aminfo and supportinfo are
-        * left as zeroes, and are filled on-the-fly when used)
+        * Fill the support procedure OID array, as well as the info about
+        * opfamilies and opclass input types.  (aminfo and supportinfo are left
+        * as zeroes, and are filled on-the-fly when used)
         */
-       IndexSupportInitialize(indclass,
-                                                  relation->rd_operator, relation->rd_support,
+       IndexSupportInitialize(indclass, relation->rd_support,
                                                   relation->rd_opfamily, relation->rd_opcintype,
-                                                  amstrategies, amsupport, natts);
+                                                  amsupport, natts);
 
        /*
         * Similarly extract indoption and copy it to the cache entry
@@ -1118,22 +1101,19 @@ RelationInitIndexAccessInfo(Relation relation)
  *             Initializes an index's cached opclass information,
  *             given the index's pg_index.indclass entry.
  *
- * Data is returned into *indexOperator, *indexSupport, *opFamily, and
- * *opcInType, which are arrays allocated by the caller.
+ * Data is returned into *indexSupport, *opFamily, and *opcInType,
+ * which are arrays allocated by the caller.
  *
- * The caller also passes maxStrategyNumber, maxSupportNumber, and
- * maxAttributeNumber, since these indicate the size of the arrays
- * it has allocated --- but in practice these numbers must always match
- * those obtainable from the system catalog entries for the index and
- * access method.
+ * The caller also passes maxSupportNumber and maxAttributeNumber, since these
+ * indicate the size of the arrays it has allocated --- but in practice these
+ * numbers must always match those obtainable from the system catalog entries
+ * for the index and access method.
  */
 static void
 IndexSupportInitialize(oidvector *indclass,
-                                          Oid *indexOperator,
                                           RegProcedure *indexSupport,
                                           Oid *opFamily,
                                           Oid *opcInType,
-                                          StrategyNumber maxStrategyNumber,
                                           StrategyNumber maxSupportNumber,
                                           AttrNumber maxAttributeNumber)
 {
@@ -1148,16 +1128,11 @@ IndexSupportInitialize(oidvector *indclass,
 
                /* look up the info for this opclass, using a cache */
                opcentry = LookupOpclassInfo(indclass->values[attIndex],
-                                                                        maxStrategyNumber,
                                                                         maxSupportNumber);
 
                /* copy cached data into relcache entry */
                opFamily[attIndex] = opcentry->opcfamily;
                opcInType[attIndex] = opcentry->opcintype;
-               if (maxStrategyNumber > 0)
-                       memcpy(&indexOperator[attIndex * maxStrategyNumber],
-                                  opcentry->operatorOids,
-                                  maxStrategyNumber * sizeof(Oid));
                if (maxSupportNumber > 0)
                        memcpy(&indexSupport[attIndex * maxSupportNumber],
                                   opcentry->supportProcs,
@@ -1171,9 +1146,9 @@ IndexSupportInitialize(oidvector *indclass,
  * This routine maintains a per-opclass cache of the information needed
  * by IndexSupportInitialize().  This is more efficient than relying on
  * the catalog cache, because we can load all the info about a particular
- * opclass in a single indexscan of pg_amproc or pg_amop.
+ * opclass in a single indexscan of pg_amproc.
  *
- * The information from pg_am about expected range of strategy and support
+ * The information from pg_am about expected range of support function
  * numbers is passed in, rather than being looked up, mainly because the
  * caller will have it already.
  *
@@ -1187,7 +1162,6 @@ IndexSupportInitialize(oidvector *indclass,
  */
 static OpClassCacheEnt *
 LookupOpclassInfo(Oid operatorClassOid,
-                                 StrategyNumber numStrats,
                                  StrategyNumber numSupport)
 {
        OpClassCacheEnt *opcentry;
@@ -1223,16 +1197,8 @@ LookupOpclassInfo(Oid operatorClassOid,
        {
                /* Need to allocate memory for new entry */
                opcentry->valid = false;        /* until known OK */
-               opcentry->numStrats = numStrats;
                opcentry->numSupport = numSupport;
 
-               if (numStrats > 0)
-                       opcentry->operatorOids = (Oid *)
-                               MemoryContextAllocZero(CacheMemoryContext,
-                                                                          numStrats * sizeof(Oid));
-               else
-                       opcentry->operatorOids = NULL;
-
                if (numSupport > 0)
                        opcentry->supportProcs = (RegProcedure *)
                                MemoryContextAllocZero(CacheMemoryContext,
@@ -1242,7 +1208,6 @@ LookupOpclassInfo(Oid operatorClassOid,
        }
        else
        {
-               Assert(numStrats == opcentry->numStrats);
                Assert(numSupport == opcentry->numSupport);
        }
 
@@ -1273,7 +1238,7 @@ LookupOpclassInfo(Oid operatorClassOid,
 
        /*
         * We have to fetch the pg_opclass row to determine its opfamily and
-        * opcintype, which are needed to look up the operators and functions.
+        * opcintype, which are needed to look up related operators and functions.
         * It'd be convenient to use the syscache here, but that probably doesn't
         * work while bootstrapping.
         */
@@ -1298,45 +1263,6 @@ LookupOpclassInfo(Oid operatorClassOid,
        systable_endscan(scan);
        heap_close(rel, AccessShareLock);
 
-
-       /*
-        * Scan pg_amop to obtain operators for the opclass.  We only fetch the
-        * default ones (those with lefttype = righttype = opcintype).
-        */
-       if (numStrats > 0)
-       {
-               ScanKeyInit(&skey[0],
-                                       Anum_pg_amop_amopfamily,
-                                       BTEqualStrategyNumber, F_OIDEQ,
-                                       ObjectIdGetDatum(opcentry->opcfamily));
-               ScanKeyInit(&skey[1],
-                                       Anum_pg_amop_amoplefttype,
-                                       BTEqualStrategyNumber, F_OIDEQ,
-                                       ObjectIdGetDatum(opcentry->opcintype));
-               ScanKeyInit(&skey[2],
-                                       Anum_pg_amop_amoprighttype,
-                                       BTEqualStrategyNumber, F_OIDEQ,
-                                       ObjectIdGetDatum(opcentry->opcintype));
-               rel = heap_open(AccessMethodOperatorRelationId, AccessShareLock);
-               scan = systable_beginscan(rel, AccessMethodStrategyIndexId, indexOK,
-                                                                 SnapshotNow, 3, skey);
-
-               while (HeapTupleIsValid(htup = systable_getnext(scan)))
-               {
-                       Form_pg_amop amopform = (Form_pg_amop) GETSTRUCT(htup);
-
-                       if (amopform->amopstrategy <= 0 ||
-                               (StrategyNumber) amopform->amopstrategy > numStrats)
-                               elog(ERROR, "invalid amopstrategy number %d for opclass %u",
-                                        amopform->amopstrategy, operatorClassOid);
-                       opcentry->operatorOids[amopform->amopstrategy - 1] =
-                               amopform->amopopr;
-               }
-
-               systable_endscan(scan);
-               heap_close(rel, AccessShareLock);
-       }
-
        /*
         * Scan pg_amproc to obtain support procs for the opclass.      We only fetch
         * the default ones (those with lefttype = righttype = opcintype).
@@ -2907,18 +2833,14 @@ RelationCacheInitializePhase3(void)
                                                        IndexRelationId);
                load_critical_index(OpclassOidIndexId,
                                                        OperatorClassRelationId);
-               load_critical_index(AccessMethodStrategyIndexId,
-                                                       AccessMethodOperatorRelationId);
                load_critical_index(AccessMethodProcedureIndexId,
                                                        AccessMethodProcedureRelationId);
-               load_critical_index(OperatorOidIndexId,
-                                                       OperatorRelationId);
                load_critical_index(RewriteRelRulenameIndexId,
                                                        RewriteRelationId);
                load_critical_index(TriggerRelidNameIndexId,
                                                        TriggerRelationId);
 
-#define NUM_CRITICAL_LOCAL_INDEXES     9       /* fix if you change list above */
+#define NUM_CRITICAL_LOCAL_INDEXES     7       /* fix if you change list above */
 
                criticalRelcachesBuilt = true;
        }
@@ -4044,7 +3966,6 @@ load_relcache_init_file(bool shared)
                        MemoryContext indexcxt;
                        Oid                *opfamily;
                        Oid                *opcintype;
-                       Oid                *operator;
                        RegProcedure *support;
                        int                     nsupport;
                        int16      *indoption;
@@ -4105,17 +4026,7 @@ load_relcache_init_file(bool shared)
 
                        rel->rd_opcintype = opcintype;
 
-                       /* next, read the vector of operator OIDs */
-                       if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
-                               goto read_failed;
-
-                       operator = (Oid *) MemoryContextAlloc(indexcxt, len);
-                       if (fread(operator, 1, len, fp) != len)
-                               goto read_failed;
-
-                       rel->rd_operator = operator;
-
-                       /* next, read the vector of support procedures */
+                       /* next, read the vector of support procedure OIDs */
                        if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
                                goto read_failed;
                        support = (RegProcedure *) MemoryContextAlloc(indexcxt, len);
@@ -4154,7 +4065,6 @@ load_relcache_init_file(bool shared)
                        Assert(rel->rd_aminfo == NULL);
                        Assert(rel->rd_opfamily == NULL);
                        Assert(rel->rd_opcintype == NULL);
-                       Assert(rel->rd_operator == NULL);
                        Assert(rel->rd_support == NULL);
                        Assert(rel->rd_supportinfo == NULL);
                        Assert(rel->rd_indoption == NULL);
@@ -4371,12 +4281,7 @@ write_relcache_init_file(bool shared)
                                           relform->relnatts * sizeof(Oid),
                                           fp);
 
-                       /* next, write the vector of operator OIDs */
-                       write_item(rel->rd_operator,
-                                          relform->relnatts * (am->amstrategies * sizeof(Oid)),
-                                          fp);
-
-                       /* next, write the vector of support procedures */
+                       /* next, write the vector of support procedure OIDs */
                        write_item(rel->rd_support,
                                  relform->relnatts * (am->amsupport * sizeof(RegProcedure)),
                                           fp);
index 785acc955ad652254c547d015715ec6ac1841925..d084338f356206c354a0a85179ea358862eab5bb 100644 (file)
@@ -421,20 +421,17 @@ typedef struct RelOptInfo
  * IndexOptInfo
  *             Per-index information for planning/optimization
  *
- *             Prior to Postgres 7.0, RelOptInfo was used to describe both relations
- *             and indexes, but that created confusion without actually doing anything
- *             useful.  So now we have a separate IndexOptInfo struct for indexes.
- *
- *             opfamily[], indexkeys[], opcintype[], fwdsortop[], revsortop[],
- *             and nulls_first[] each have ncolumns entries.
+ *             opfamily[], indexkeys[], and opcintype[] each have ncolumns entries.
+ *             sortopfamily[], reverse_sort[], and nulls_first[] likewise have
+ *             ncolumns entries, if the index is ordered; but if it is unordered,
+ *             those pointers are NULL.
  *
  *             Zeroes in the indexkeys[] array indicate index columns that are
  *             expressions; there is one element in indexprs for each such column.
  *
- *             For an unordered index, the sortop arrays contains zeroes.      Note that
- *             fwdsortop[] and nulls_first[] describe the sort ordering of a forward
- *             indexscan; we can also consider a backward indexscan, which will
- *             generate sort order described by revsortop/!nulls_first.
+ *             For an ordered index, reverse_sort[] and nulls_first[] describe the
+ *             sort ordering of a forward indexscan; we can also consider a backward
+ *             indexscan, which will generate the reverse ordering.
  *
  *             The indexprs and indpred expressions have been run through
  *             prepqual.c and eval_const_expressions() for ease of matching to
@@ -457,8 +454,8 @@ typedef struct IndexOptInfo
        Oid                *opfamily;           /* OIDs of operator families for columns */
        int                *indexkeys;          /* column numbers of index's keys, or 0 */
        Oid                *opcintype;          /* OIDs of opclass declared input data types */
-       Oid                *fwdsortop;          /* OIDs of sort operators for each column */
-       Oid                *revsortop;          /* OIDs of sort operators for backward scan */
+       Oid                *sortopfamily;       /* OIDs of btree opfamilies, if orderable */
+       bool       *reverse_sort;       /* is sort order descending? */
        bool       *nulls_first;        /* do NULLs come first in the sort order? */
        Oid                     relam;                  /* OID of the access method (in pg_am) */
 
index 9ad92c299e8355ce9874478c76d71330b940e382..39e0365c0b124022f2ec487d8be6a4fa2668760d 100644 (file)
@@ -178,10 +178,10 @@ typedef struct RelationData
        /*
         * index access support info (used only for an index relation)
         *
-        * Note: only default operators and support procs for each opclass are
-        * cached, namely those with lefttype and righttype equal to the opclass's
-        * opcintype.  The arrays are indexed by strategy or support number, which
-        * is a sufficient identifier given that restriction.
+        * Note: only default support procs for each opclass are cached, namely
+        * those with lefttype and righttype equal to the opclass's opcintype.
+        * The arrays are indexed by support function number, which is a
+        * sufficient identifier given that restriction.
         *
         * Note: rd_amcache is available for index AMs to cache private data about
         * an index.  This must be just a cache since it may get reset at any time
@@ -194,7 +194,6 @@ typedef struct RelationData
        RelationAmInfo *rd_aminfo;      /* lookup info for funcs found in pg_am */
        Oid                *rd_opfamily;        /* OIDs of op families for each index col */
        Oid                *rd_opcintype;       /* OIDs of opclass declared input data types */
-       Oid                *rd_operator;        /* OIDs of index operators */
        RegProcedure *rd_support;       /* OIDs of support procedures */
        FmgrInfo   *rd_supportinfo; /* lookup info for support procedures */
        int16      *rd_indoption;       /* per-column AM-specific flags */