optional_opclass_3.0.patch
text/x-patch
Filename: optional_opclass_3.0.patch
Type: text/x-patch
Part: 1
Message:
Re: WIP: Covering + unique indexes.
Patch
Format: unified
| File | + | − |
|---|---|---|
| src/backend/access/index/genam.c | 26 | 14 |
| src/backend/access/nbtree/nbtutils.c | 4 | 2 |
| src/backend/catalog/index.c | 42 | 39 |
| src/backend/commands/indexcmds.c | 98 | 93 |
| src/backend/optimizer/util/plancat.c | 10 | 6 |
| src/backend/utils/cache/relcache.c | 19 | 18 |
| src/backend/utils/sort/tuplesort.c | 1 | 2 |
diff --git a/src/backend/access/index/genam.c b/src/backend/access/index/genam.c
index aa5b28c..6316ca5 100644
--- a/src/backend/access/index/genam.c
+++ b/src/backend/access/index/genam.c
@@ -180,6 +180,7 @@ BuildIndexValueDescription(Relation indexRelation,
Oid indexrelid = RelationGetRelid(indexRelation);
Oid indrelid;
AclResult aclresult;
+ // elog(NOTICE, "BuildIndexValueDescription. begin");
/*
* Check permissions- if the user does not have access to view all of the
@@ -221,6 +222,7 @@ BuildIndexValueDescription(Relation indexRelation,
for (keyno = 0; keyno < idxrec->indnatts; keyno++)
{
AttrNumber attnum = idxrec->indkey.values[keyno];
+ //elog(NOTICE, "BuildIndexValueDescription. keyno %d", keyno);
/*
* Note that if attnum == InvalidAttrNumber, then this is an index
@@ -244,30 +246,40 @@ BuildIndexValueDescription(Relation indexRelation,
appendStringInfo(&buf, "(%s)=(",
pg_get_indexdef_columns(indexrelid, true));
+ int nkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation);
for (i = 0; i < natts; i++)
{
char *val;
-
if (isnull[i])
val = "null";
else
{
Oid foutoid;
bool typisvarlena;
+ TupleDesc tupdesc = RelationGetDescr(indexRelation);
+ if (i < nkeyatts)
+ {
+ /* TODO
+ * The provided data is not necessarily of the type stored in the
+ * index; rather it is of the index opclass's input type. So look
+ * at rd_opcintype not the index tupdesc.
+ *
+ * Note: this is a bit shaky for opclasses that have pseudotype
+ * input types such as ANYARRAY or RECORD. Currently, the
+ * typoutput functions associated with the pseudotypes will work
+ * okay, but we might have to try harder in future.
+ */
+ //elog(NOTICE, "BuildIndexValueDescription. tdtypeid[%d]=%u rd_opcintype[%d]=%u", i, tupdesc->attrs[i]->atttypid,i, indexRelation->rd_opcintype[i]);
+ getTypeOutputInfo(indexRelation->rd_opcintype[i], &foutoid, &typisvarlena);
+ val = OidOutputFunctionCall(foutoid, values[i]);
+ }
+ else
+ {
+ getTypeOutputInfo(tupdesc->attrs[i]->atttypid, &foutoid, &typisvarlena);
+ val = OidOutputFunctionCall(foutoid, values[i]);
+ //elog(NOTICE, "BuildIndexValueDescription. some included value [%d]", i);
- /*
- * The provided data is not necessarily of the type stored in the
- * index; rather it is of the index opclass's input type. So look
- * at rd_opcintype not the index tupdesc.
- *
- * Note: this is a bit shaky for opclasses that have pseudotype
- * input types such as ANYARRAY or RECORD. Currently, the
- * typoutput functions associated with the pseudotypes will work
- * okay, but we might have to try harder in future.
- */
- getTypeOutputInfo(indexRelation->rd_opcintype[i],
- &foutoid, &typisvarlena);
- val = OidOutputFunctionCall(foutoid, values[i]);
+ }
}
if (i > 0)
diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c
index 6932289..175714d 100644
--- a/src/backend/access/nbtree/nbtutils.c
+++ b/src/backend/access/nbtree/nbtutils.c
@@ -86,11 +86,11 @@ _bt_mkscankey(Relation rel, IndexTuple itup)
Datum arg;
bool null;
int flags;
-
/*
* We can use the cached (default) support procs since no cross-type
* comparison can be needed.
*/
+ //elog(NOTICE, "_bt_mkscankey i %d", i);
procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
arg = index_getattr(itup, i + 1, itupdesc, &null);
flags = (null ? SK_ISNULL : 0) | (indoption[i] << SK_BT_INDOPTION_SHIFT);
@@ -127,11 +127,12 @@ _bt_mkscankey_nodata(Relation rel)
int i;
natts = RelationGetNumberOfAttributes(rel);
+ int nkeyatts = rel->rd_index->indnkeyatts;
indoption = rel->rd_indoption;
skey = (ScanKey) palloc(natts * sizeof(ScanKeyData));
- for (i = 0; i < natts; i++)
+ for (i = 0; i < nkeyatts; i++)
{
FmgrInfo *procinfo;
int flags;
@@ -140,6 +141,7 @@ _bt_mkscankey_nodata(Relation rel)
* We can use the cached (default) support procs since no cross-type
* comparison can be needed.
*/
+ //elog(NOTICE, "_bt_mkscankey_nodata i %d", i);
procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
flags = SK_ISNULL | (indoption[i] << SK_BT_INDOPTION_SHIFT);
ScanKeyEntryInitializeWithInfo(&skey[i],
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 27a12a0..4ba362b 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -424,38 +424,44 @@ ConstructTupleDescriptor(Relation heapRelation,
elog(ERROR, "too few entries in colnames list");
namestrcpy(&to->attname, (const char *) lfirst(colnames_item));
colnames_item = lnext(colnames_item);
-
- /*
- * Check the opclass and index AM to see if either provides a keytype
- * (overriding the attribute type). Opclass takes precedence.
- */
- tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(classObjectId[i]));
- if (!HeapTupleIsValid(tuple))
- elog(ERROR, "cache lookup failed for opclass %u",
- classObjectId[i]);
- opclassTup = (Form_pg_opclass) GETSTRUCT(tuple);
- if (OidIsValid(opclassTup->opckeytype))
- keyType = opclassTup->opckeytype;
- else
- keyType = amform->amkeytype;
- ReleaseSysCache(tuple);
-
- if (OidIsValid(keyType) && keyType != to->atttypid)
+ if (i < indexInfo->ii_NumIndexKeyAttrs)
{
- /* index value and heap value have different types */
- tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(keyType));
+ /*
+ * Check the opclass and index AM to see if either provides a keytype
+ * (overriding the attribute type). Opclass takes precedence.
+ */
+ tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(classObjectId[i]));
if (!HeapTupleIsValid(tuple))
- elog(ERROR, "cache lookup failed for type %u", keyType);
- typeTup = (Form_pg_type) GETSTRUCT(tuple);
-
- to->atttypid = keyType;
- to->atttypmod = -1;
- to->attlen = typeTup->typlen;
- to->attbyval = typeTup->typbyval;
- to->attalign = typeTup->typalign;
- to->attstorage = typeTup->typstorage;
-
+ elog(ERROR, "cache lookup failed for opclass %u",
+ classObjectId[i]);
+ opclassTup = (Form_pg_opclass) GETSTRUCT(tuple);
+ if (OidIsValid(opclassTup->opckeytype))
+ keyType = opclassTup->opckeytype;
+ else
+ keyType = amform->amkeytype;
ReleaseSysCache(tuple);
+
+ if (OidIsValid(keyType) && keyType != to->atttypid)
+ {
+ /* index value and heap value have different types */
+ tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(keyType));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for type %u", keyType);
+ typeTup = (Form_pg_type) GETSTRUCT(tuple);
+
+ to->atttypid = keyType;
+ to->atttypmod = -1;
+ to->attlen = typeTup->typlen;
+ to->attbyval = typeTup->typbyval;
+ to->attalign = typeTup->typalign;
+ to->attstorage = typeTup->typstorage;
+
+ ReleaseSysCache(tuple);
+ }
+ }
+ else
+ {
+ //elog(NOTICE, "ConstructTupleDescriptor. Included opclass attr num %d. Don't check opclass", i);
}
}
@@ -500,7 +506,6 @@ AppendAttributeTuples(Relation indexRelation, int numatts)
pg_attribute = heap_open(AttributeRelationId, RowExclusiveLock);
indstate = CatalogOpenIndexes(pg_attribute);
-
/*
* insert data from new index's tupdesc into pg_attribute
*/
@@ -866,7 +871,6 @@ index_create(Relation heapRelation,
indexRelation->rd_rel->relowner = heapRelation->rd_rel->relowner;
indexRelation->rd_rel->relam = accessMethodObjectId;
indexRelation->rd_rel->relhasoids = false;
-
/*
* store index's pg_class entry
*/
@@ -998,7 +1002,7 @@ index_create(Relation heapRelation,
/* Store dependency on collations */
/* The default collation is pinned, so don't bother recording it */
- for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
+ for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
{
if (OidIsValid(collationObjectId[i]) &&
collationObjectId[i] != DEFAULT_COLLATION_OID)
@@ -1012,7 +1016,7 @@ index_create(Relation heapRelation,
}
/* Store dependency on operator classes */
- for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
+ for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
{
referenced.classId = OperatorClassRelationId;
referenced.objectId = classObjectId[i];
@@ -1700,7 +1704,7 @@ BuildIndexInfo(Relation index)
void
BuildSpeculativeIndexInfo(Relation index, IndexInfo *ii)
{
- int ncols = index->rd_rel->relnatts;
+ int nkeycols = IndexRelationGetNumberOfKeyAttributes(index);
int i;
/*
@@ -1711,16 +1715,16 @@ BuildSpeculativeIndexInfo(Relation index, IndexInfo *ii)
if (index->rd_rel->relam != BTREE_AM_OID)
elog(ERROR, "unexpected non-btree speculative unique index");
- ii->ii_UniqueOps = (Oid *) palloc(sizeof(Oid) * ncols);
- ii->ii_UniqueProcs = (Oid *) palloc(sizeof(Oid) * ncols);
- ii->ii_UniqueStrats = (uint16 *) palloc(sizeof(uint16) * ncols);
+ ii->ii_UniqueOps = (Oid *) palloc(sizeof(Oid) * nkeycols);
+ ii->ii_UniqueProcs = (Oid *) palloc(sizeof(Oid) * nkeycols);
+ ii->ii_UniqueStrats = (uint16 *) palloc(sizeof(uint16) * nkeycols);
/*
* We have to look up the operator's strategy number. This provides a
* cross-check that the operator does match the index.
*/
/* We need the func OIDs and strategy numbers too */
- for (i = 0; i < ncols; i++)
+ for (i = 0; i < nkeycols; i++)
{
ii->ii_UniqueStrats[i] = BTEqualStrategyNumber;
ii->ii_UniqueOps[i] =
@@ -2644,7 +2648,6 @@ IndexCheckExclusion(Relation heapRelation,
EState *estate;
ExprContext *econtext;
Snapshot snapshot;
-
/*
* If we are reindexing the target index, mark it as no longer being
* reindexed, to forestall an Assert in index_beginscan when we try to use
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 4e23dbe..aa4e430 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -983,16 +983,14 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
ListCell *nextExclOp;
ListCell *lc;
int attn;
-
+ int nkeycols = indexInfo->ii_NumIndexKeyAttrs;
/* Allocate space for exclusion operator info, if needed */
if (exclusionOpNames)
{
- int ncols = list_length(attList);
-
- Assert(list_length(exclusionOpNames) == ncols);
- indexInfo->ii_ExclusionOps = (Oid *) palloc(sizeof(Oid) * ncols);
- indexInfo->ii_ExclusionProcs = (Oid *) palloc(sizeof(Oid) * ncols);
- indexInfo->ii_ExclusionStrats = (uint16 *) palloc(sizeof(uint16) * ncols);
+ Assert(list_length(exclusionOpNames) == nkeycols);
+ indexInfo->ii_ExclusionOps = (Oid *) palloc(sizeof(Oid) * nkeycols);
+ indexInfo->ii_ExclusionProcs = (Oid *) palloc(sizeof(Oid) * nkeycols);
+ indexInfo->ii_ExclusionStrats = (uint16 *) palloc(sizeof(uint16) * nkeycols);
nextExclOp = list_head(exclusionOpNames);
}
else
@@ -1125,110 +1123,117 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
/*
* Identify the opclass to use.
*/
- classOidP[attn] = GetIndexOpClass(attribute->opclass,
- atttype,
- accessMethodName,
- accessMethodId);
-
- /*
- * Identify the exclusion operator, if any.
- */
- if (nextExclOp)
+ if (attn < nkeycols)
{
- List *opname = (List *) lfirst(nextExclOp);
- Oid opid;
- Oid opfamily;
- int strat;
+ //elog(NOTICE, "ComputeIndexAttrs attn %d, nkeycolss %d", attn, nkeycols);
+ classOidP[attn] = GetIndexOpClass(attribute->opclass,
+ atttype,
+ accessMethodName,
+ accessMethodId);
/*
- * Find the operator --- it must accept the column datatype
- * without runtime coercion (but binary compatibility is OK)
- */
- opid = compatible_oper_opid(opname, atttype, atttype, false);
+ * Identify the exclusion operator, if any.
+ */
+ if (nextExclOp)
+ {
+ List *opname = (List *) lfirst(nextExclOp);
+ Oid opid;
+ Oid opfamily;
+ int strat;
- /*
- * Only allow commutative operators to be used in exclusion
- * constraints. If X conflicts with Y, but Y does not conflict
- * with X, bad things will happen.
- */
- if (get_commutator(opid) != opid)
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("operator %s is not commutative",
- format_operator(opid)),
- errdetail("Only commutative operators can be used in exclusion constraints.")));
+ /*
+ * Find the operator --- it must accept the column datatype
+ * without runtime coercion (but binary compatibility is OK)
+ */
+ opid = compatible_oper_opid(opname, atttype, atttype, false);
- /*
- * Operator must be a member of the right opfamily, too
- */
- opfamily = get_opclass_family(classOidP[attn]);
- strat = get_op_opfamily_strategy(opid, opfamily);
- if (strat == 0)
- {
- HeapTuple opftuple;
- Form_pg_opfamily opfform;
+ /*
+ * Only allow commutative operators to be used in exclusion
+ * constraints. If X conflicts with Y, but Y does not conflict
+ * with X, bad things will happen.
+ */
+ if (get_commutator(opid) != opid)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("operator %s is not commutative",
+ format_operator(opid)),
+ errdetail("Only commutative operators can be used in exclusion constraints.")));
/*
- * attribute->opclass might not explicitly name the opfamily,
- * so fetch the name of the selected opfamily for use in the
- * error message.
- */
- opftuple = SearchSysCache1(OPFAMILYOID,
- ObjectIdGetDatum(opfamily));
- if (!HeapTupleIsValid(opftuple))
- elog(ERROR, "cache lookup failed for opfamily %u",
- opfamily);
- opfform = (Form_pg_opfamily) GETSTRUCT(opftuple);
+ * Operator must be a member of the right opfamily, too
+ */
+ opfamily = get_opclass_family(classOidP[attn]);
+ strat = get_op_opfamily_strategy(opid, opfamily);
+ if (strat == 0)
+ {
+ HeapTuple opftuple;
+ Form_pg_opfamily opfform;
+
+ /*
+ * attribute->opclass might not explicitly name the opfamily,
+ * so fetch the name of the selected opfamily for use in the
+ * error message.
+ */
+ opftuple = SearchSysCache1(OPFAMILYOID,
+ ObjectIdGetDatum(opfamily));
+ if (!HeapTupleIsValid(opftuple))
+ elog(ERROR, "cache lookup failed for opfamily %u",
+ opfamily);
+ opfform = (Form_pg_opfamily) GETSTRUCT(opftuple);
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("operator %s is not a member of operator family \"%s\"",
- format_operator(opid),
- NameStr(opfform->opfname)),
- errdetail("The exclusion operator must be related to the index operator class for the constraint.")));
- }
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("operator %s is not a member of operator family \"%s\"",
+ format_operator(opid),
+ NameStr(opfform->opfname)),
+ errdetail("The exclusion operator must be related to the index operator class for the constraint.")));
+ }
- indexInfo->ii_ExclusionOps[attn] = opid;
- indexInfo->ii_ExclusionProcs[attn] = get_opcode(opid);
- indexInfo->ii_ExclusionStrats[attn] = strat;
- nextExclOp = lnext(nextExclOp);
- }
+ indexInfo->ii_ExclusionOps[attn] = opid;
+ indexInfo->ii_ExclusionProcs[attn] = get_opcode(opid);
+ indexInfo->ii_ExclusionStrats[attn] = strat;
+ nextExclOp = lnext(nextExclOp);
+ }
- /*
- * Set up the per-column options (indoption field). For now, this is
- * zero for any un-ordered index, while ordered indexes have DESC and
- * NULLS FIRST/LAST options.
- */
- colOptionP[attn] = 0;
- if (amcanorder)
- {
- /* default ordering is ASC */
- if (attribute->ordering == SORTBY_DESC)
- colOptionP[attn] |= INDOPTION_DESC;
- /* default null ordering is LAST for ASC, FIRST for DESC */
- if (attribute->nulls_ordering == SORTBY_NULLS_DEFAULT)
+ /*
+ * Set up the per-column options (indoption field). For now, this is
+ * zero for any un-ordered index, while ordered indexes have DESC and
+ * NULLS FIRST/LAST options.
+ */
+ colOptionP[attn] = 0;
+ if (amcanorder)
{
+ /* default ordering is ASC */
if (attribute->ordering == SORTBY_DESC)
+ colOptionP[attn] |= INDOPTION_DESC;
+ /* default null ordering is LAST for ASC, FIRST for DESC */
+ if (attribute->nulls_ordering == SORTBY_NULLS_DEFAULT)
+ {
+ if (attribute->ordering == SORTBY_DESC)
+ colOptionP[attn] |= INDOPTION_NULLS_FIRST;
+ }
+ else if (attribute->nulls_ordering == SORTBY_NULLS_FIRST)
colOptionP[attn] |= INDOPTION_NULLS_FIRST;
}
- else if (attribute->nulls_ordering == SORTBY_NULLS_FIRST)
- colOptionP[attn] |= INDOPTION_NULLS_FIRST;
+ else
+ {
+ /* index AM does not support ordering */
+ if (attribute->ordering != SORTBY_DEFAULT)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("access method \"%s\" does not support ASC/DESC options",
+ accessMethodName)));
+ if (attribute->nulls_ordering != SORTBY_NULLS_DEFAULT)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("access method \"%s\" does not support NULLS FIRST/LAST options",
+ accessMethodName)));
+ }
}
else
{
- /* index AM does not support ordering */
- if (attribute->ordering != SORTBY_DEFAULT)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("access method \"%s\" does not support ASC/DESC options",
- accessMethodName)));
- if (attribute->nulls_ordering != SORTBY_NULLS_DEFAULT)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("access method \"%s\" does not support NULLS FIRST/LAST options",
- accessMethodName)));
+ //elog(NOTICE, "ComputeIndexAttrs. Included attn %d. Don't look for opclass", attn);
}
-
attn++;
}
}
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 603d11d..ffb63f2 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -225,18 +225,22 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
* each indexed column must have an opclass.
*/
info->indexkeys = (int *) palloc(sizeof(int) * ncolumns);
- info->indexcollations = (Oid *) palloc(sizeof(Oid) * ncolumns);
- info->opfamily = (Oid *) palloc(sizeof(Oid) * ncolumns);
- info->opcintype = (Oid *) palloc(sizeof(Oid) * ncolumns);
+ info->indexcollations = (Oid *) palloc(sizeof(Oid) * nkeycolumns);
+ info->opfamily = (Oid *) palloc(sizeof(Oid) * nkeycolumns);
+ info->opcintype = (Oid *) palloc(sizeof(Oid) * nkeycolumns);
info->canreturn = (bool *) palloc(sizeof(bool) * ncolumns);
for (i = 0; i < ncolumns; i++)
{
info->indexkeys[i] = index->indkey.values[i];
+ info->canreturn[i] = index_can_return(indexRelation, i + 1);
+ }
+
+ for (i = 0; i < nkeycolumns; i++)
+ {
info->indexcollations[i] = indexRelation->rd_indcollation[i];
info->opfamily[i] = indexRelation->rd_opfamily[i];
info->opcintype[i] = indexRelation->rd_opcintype[i];
- info->canreturn[i] = index_can_return(indexRelation, i + 1);
}
info->relam = indexRelation->rd_rel->relam;
@@ -263,7 +267,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
info->reverse_sort = (bool *) palloc(sizeof(bool) * ncolumns);
info->nulls_first = (bool *) palloc(sizeof(bool) * ncolumns);
- for (i = 0; i < ncolumns; i++)
+ for (i = 0; i < nkeycolumns; i++)
{
int16 opt = indexRelation->rd_indoption[i];
@@ -291,7 +295,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
info->reverse_sort = (bool *) palloc(sizeof(bool) * ncolumns);
info->nulls_first = (bool *) palloc(sizeof(bool) * ncolumns);
- for (i = 0; i < ncolumns; i++)
+ for (i = 0; i < nkeycolumns; i++)
{
int16 opt = indexRelation->rd_indoption[i];
Oid ltopr;
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 513fa57..ac828b5 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -1178,7 +1178,7 @@ RelationInitIndexAccessInfo(Relation relation)
int2vector *indoption;
MemoryContext indexcxt;
MemoryContext oldcontext;
- int natts;
+ int natts, nkeyatts;
uint16 amsupport;
/*
@@ -1214,6 +1214,7 @@ RelationInitIndexAccessInfo(Relation relation)
elog(ERROR, "relnatts disagrees with indnatts for index %u",
RelationGetRelid(relation));
amsupport = aform->amsupport;
+ nkeyatts = IndexRelationGetNumberOfKeyAttributes(relation);
/*
* Make the private context to hold index access info. The reason we need
@@ -1294,7 +1295,7 @@ RelationInitIndexAccessInfo(Relation relation)
*/
IndexSupportInitialize(indclass, relation->rd_support,
relation->rd_opfamily, relation->rd_opcintype,
- amsupport, natts);
+ amsupport, nkeyatts);
/*
* Similarly extract indoption and copy it to the cache entry
@@ -4366,7 +4367,7 @@ RelationGetExclusionInfo(Relation indexRelation,
Oid **procs,
uint16 **strategies)
{
- int ncols = indexRelation->rd_rel->relnatts;
+ int nkeycols = IndexRelationGetNumberOfKeyAttributes(indexRelation);
Oid *ops;
Oid *funcs;
uint16 *strats;
@@ -4379,16 +4380,16 @@ RelationGetExclusionInfo(Relation indexRelation,
int i;
/* Allocate result space in caller context */
- *operators = ops = (Oid *) palloc(sizeof(Oid) * ncols);
- *procs = funcs = (Oid *) palloc(sizeof(Oid) * ncols);
- *strategies = strats = (uint16 *) palloc(sizeof(uint16) * ncols);
+ *operators = ops = (Oid *) palloc(sizeof(Oid) * nkeycols);
+ *procs = funcs = (Oid *) palloc(sizeof(Oid) * nkeycols);
+ *strategies = strats = (uint16 *) palloc(sizeof(uint16) * nkeycols);
/* Quick exit if we have the data cached already */
if (indexRelation->rd_exclstrats != NULL)
{
- memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * ncols);
- memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * ncols);
- memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * ncols);
+ memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * nkeycols);
+ memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * nkeycols);
+ memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * nkeycols);
return;
}
@@ -4437,12 +4438,12 @@ RelationGetExclusionInfo(Relation indexRelation,
arr = DatumGetArrayTypeP(val); /* ensure not toasted */
nelem = ARR_DIMS(arr)[0];
if (ARR_NDIM(arr) != 1 ||
- nelem != ncols ||
+ nelem != nkeycols ||
ARR_HASNULL(arr) ||
ARR_ELEMTYPE(arr) != OIDOID)
elog(ERROR, "conexclop is not a 1-D Oid array");
- memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * ncols);
+ memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * nkeycols);
}
systable_endscan(conscan);
@@ -4453,7 +4454,7 @@ RelationGetExclusionInfo(Relation indexRelation,
RelationGetRelationName(indexRelation));
/* We need the func OIDs and strategy numbers too */
- for (i = 0; i < ncols; i++)
+ for (i = 0; i < nkeycols; i++)
{
funcs[i] = get_opcode(ops[i]);
strats[i] = get_op_opfamily_strategy(ops[i],
@@ -4466,12 +4467,12 @@ RelationGetExclusionInfo(Relation indexRelation,
/* Save a copy of the results in the relcache entry. */
oldcxt = MemoryContextSwitchTo(indexRelation->rd_indexcxt);
- indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * ncols);
- indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * ncols);
- indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * ncols);
- memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * ncols);
- memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * ncols);
- memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * ncols);
+ indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * nkeycols);
+ indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * nkeycols);
+ indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * nkeycols);
+ memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * nkeycols);
+ memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * nkeycols);
+ memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * nkeycols);
MemoryContextSwitchTo(oldcxt);
}
diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c
index d532e87..ec2a49c 100644
--- a/src/backend/utils/sort/tuplesort.c
+++ b/src/backend/utils/sort/tuplesort.c
@@ -810,9 +810,8 @@ tuplesort_begin_index_btree(Relation heapRel,
state->heapRel = heapRel;
state->indexRel = indexRel;
state->enforceUnique = enforceUnique;
-
indexScanKey = _bt_mkscankey_nodata(indexRel);
- state->nKeys = RelationGetNumberOfAttributes(indexRel);
+ state->nKeys = IndexRelationGetNumberOfKeyAttributes(indexRel);
/* Prepare SortSupport data for each column */
state->sortKeys = (SortSupport) palloc0(state->nKeys *