* 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)
{
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);
/*
* 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.
*/
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
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
* 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.
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;
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)
{
/* 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,
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)
* 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);
}
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++)
{
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
* 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
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))
Assert(nnumbers == 1);
varCorrelation = numbers[0];
+ if (index->reverse_sort[0])
+ varCorrelation = -varCorrelation;
+
if (index->ncolumns > 1)
*indexCorrelation = varCorrelation * 0.75;
else
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);
#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"
#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};
/*
* 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;
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);
MemoryContext indexcxt;
MemoryContext oldcontext;
int natts;
- uint16 amstrategies;
uint16 amsupport;
/*
if (natts != relation->rd_index->indnatts)
elog(ERROR, "relnatts disagrees with indnatts for index %u",
RelationGetRelid(relation));
- amstrategies = aform->amstrategies;
amsupport = aform->amsupport;
/*
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;
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
* 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)
{
/* 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,
* 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.
*
*/
static OpClassCacheEnt *
LookupOpclassInfo(Oid operatorClassOid,
- StrategyNumber numStrats,
StrategyNumber numSupport)
{
OpClassCacheEnt *opcentry;
{
/* 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,
}
else
{
- Assert(numStrats == opcentry->numStrats);
Assert(numSupport == opcentry->numSupport);
}
/*
* 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.
*/
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).
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;
}
MemoryContext indexcxt;
Oid *opfamily;
Oid *opcintype;
- Oid *operator;
RegProcedure *support;
int nsupport;
int16 *indoption;
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);
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);
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);
* 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
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 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
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 */