Skip to content

Commit 52ccd00

Browse files
alubennikovavbwagner
authored andcommitted
including_columns_2.0. Clear patch.
1 parent 747aa24 commit 52ccd00

File tree

17 files changed

+135
-110
lines changed

17 files changed

+135
-110
lines changed

doc/src/sgml/catalogs.sgml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,7 @@
645645
</row>
646646

647647
<row>
648-
<entry><structfield>amcanincluding</structfield></entry>
648+
<entry><structfield>amcaninclude</structfield></entry>
649649
<entry><type>bool</type></entry>
650650
<entry></entry>
651651
<entry>Does the access method support included columns?</entry>

doc/src/sgml/indexam.sgml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -765,10 +765,10 @@ amrestrpos (IndexScanDesc scan);
765765
<para>
766766
<productname>&productname;</productname> enforces SQL uniqueness constraints
767767
using <firstterm>unique indexes</>, which are indexes that disallow
768-
multiple entries with identical keys. An access method that supports this
768+
multiple entries with identical keys. An access method that supports this
769769
feature sets <structname>pg_am</>.<structfield>amcanunique</> true.
770-
Columns included with clause INCLUDING aren't used to enforce uniqueness.
771-
(At present, only b-tree supports them.)
770+
(At present, only b-tree supports it.) Columns which are present in the
771+
<literal>INCLUDING</> clause are not used to enforce uniqueness.
772772
</para>
773773

774774
<para>

doc/src/sgml/indices.sgml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,8 @@ CREATE UNIQUE INDEX <replaceable>name</replaceable> ON <replaceable>table</repla
644644
indexed values are not allowed. Null values are not considered
645645
equal. A multicolumn unique index will only reject cases where all
646646
indexed columns are equal in multiple rows. Columns included with clause
647-
<literal>INCLUDING</literal> aren't used to enforce constraints (UNIQUE, PRIMARY KEY, etc).
647+
<literal>INCLUDING</literal> aren't used to enforce constraints (UNIQUE,
648+
PRIMARY KEY, etc).
648649
</para>
649650

650651
<para>

doc/src/sgml/ref/create_index.sgml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] <replaceable class=
157157
<literal>INCLUDING</> clause, on which the uniqueness is not enforced upon.
158158
It's the same with other constraints (PRIMARY KEY and EXCLUDE). This can
159159
also can be used for non-unique indexes as any columns which are not required
160-
for the searching or ordering of records can defined in the
160+
for the searching or ordering of records can be included in the
161161
<literal>INCLUDING</> clause, which can slightly reduce the size of the index,
162162
due to storing included attributes only in leaf index pages.
163163
Currently, only the B-tree access method supports this feature.

src/backend/access/index/genam.c

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ BuildIndexValueDescription(Relation indexRelation,
175175
Form_pg_index idxrec;
176176
HeapTuple ht_idx;
177177
int natts = indexRelation->rd_rel->relnatts;
178+
int nkeyatts;
178179
int i;
179180
int keyno;
180181
Oid indexrelid = RelationGetRelid(indexRelation);
@@ -244,6 +245,7 @@ BuildIndexValueDescription(Relation indexRelation,
244245
appendStringInfo(&buf, "(%s)=(",
245246
pg_get_indexdef_columns(indexrelid, true));
246247

248+
nkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation);
247249
for (i = 0; i < natts; i++)
248250
{
249251
char *val;
@@ -254,20 +256,31 @@ BuildIndexValueDescription(Relation indexRelation,
254256
{
255257
Oid foutoid;
256258
bool typisvarlena;
257-
259+
TupleDesc tupdesc = RelationGetDescr(indexRelation);
258260
/*
259-
* The provided data is not necessarily of the type stored in the
260-
* index; rather it is of the index opclass's input type. So look
261-
* at rd_opcintype not the index tupdesc.
261+
* For key attributes the provided data is not necessarily of the
262+
* type stored in the index; rather it is of the index opclass's
263+
* input type. So look at rd_opcintype not the index tupdesc.
262264
*
263265
* Note: this is a bit shaky for opclasses that have pseudotype
264266
* input types such as ANYARRAY or RECORD. Currently, the
265267
* typoutput functions associated with the pseudotypes will work
266268
* okay, but we might have to try harder in future.
269+
*
270+
* For included attributes just use info stored in the index
271+
* tupdesc.
267272
*/
268-
getTypeOutputInfo(indexRelation->rd_opcintype[i],
269-
&foutoid, &typisvarlena);
270-
val = OidOutputFunctionCall(foutoid, values[i]);
273+
if (i < nkeyatts)
274+
{
275+
getTypeOutputInfo(indexRelation->rd_opcintype[i],
276+
&foutoid, &typisvarlena);
277+
val = OidOutputFunctionCall(foutoid, values[i]);
278+
}
279+
else
280+
{
281+
getTypeOutputInfo(tupdesc->attrs[i]->atttypid, &foutoid, &typisvarlena);
282+
val = OidOutputFunctionCall(foutoid, values[i]);
283+
}
271284
}
272285

273286
if (i > 0)

src/backend/access/nbtree/nbtinsert.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ bool
107107
_bt_doinsert(Relation rel, IndexTuple itup,
108108
IndexUniqueCheck checkUnique, Relation heapRel)
109109
{
110-
bool is_unique;
110+
bool is_unique = false;
111111
int nkeyatts;
112112
ScanKey itup_scankey;
113113
BTStack stack;
@@ -117,7 +117,6 @@ _bt_doinsert(Relation rel, IndexTuple itup,
117117
Assert(rel->rd_index->indnatts != 0);
118118
Assert(rel->rd_index->indnkeyatts != 0);
119119
nkeyatts = IndexRelationGetNumberOfKeyAttributes(rel);
120-
is_unique = false;
121120

122121
/* we need an insertion scan key to do our search, so build one */
123122
itup_scankey = _bt_mkscankey(rel, itup);
@@ -255,9 +254,6 @@ _bt_check_unique(Relation rel, IndexTuple itup, Relation heapRel,
255254
Buffer nbuf = InvalidBuffer;
256255
bool found = false;
257256

258-
Assert(rel->rd_index->indnatts != 0);
259-
Assert(rel->rd_index->indnkeyatts != 0);
260-
261257
/* Assume unique until we find a duplicate */
262258
*is_unique = true;
263259

@@ -1977,8 +1973,11 @@ _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf)
19771973
itemid = PageGetItemId(lpage, P_HIKEY);
19781974
right_item_sz = ItemIdGetLength(itemid);
19791975
item = (IndexTuple) PageGetItem(lpage, itemid);
1980-
right_item = CopyIndexTuple(item);
1981-
right_item = index_reform_tuple(rel, right_item, rel->rd_index->indnatts, rel->rd_index->indnkeyatts);
1976+
1977+
if (rel->rd_index->indnatts != rel->rd_index->indnkeyatts)
1978+
right_item = index_reform_tuple(rel, item, rel->rd_index->indnatts, rel->rd_index->indnkeyatts);
1979+
else
1980+
right_item = CopyIndexTuple(item);
19821981
ItemPointerSet(&(right_item->t_tid), rbkno, P_HIKEY);
19831982

19841983
/* NO EREPORT(ERROR) from here till newroot op is logged */

src/backend/access/nbtree/nbtutils.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,16 @@ _bt_mkscankey(Relation rel, IndexTuple itup)
6464
ScanKey skey;
6565
TupleDesc itupdesc;
6666
int nkeyatts;
67-
int16 *indoption = rel->rd_indoption;
67+
int16 *indoption;
6868
int i;
69+
6970
itupdesc = RelationGetDescr(rel);
71+
nkeyatts = rel->rd_index->indnkeyatts;
72+
indoption = rel->rd_indoption;
7073

7174
Assert(rel->rd_index->indnkeyatts != 0);
7275
Assert(rel->rd_index->indnkeyatts <= rel->rd_index->indnatts);
7376

74-
nkeyatts = rel->rd_index->indnkeyatts;
75-
7677
/*
7778
* We'll execute search using ScanKey constructed on key columns.
7879
* Non key (included) columns must be omitted.
@@ -121,16 +122,16 @@ ScanKey
121122
_bt_mkscankey_nodata(Relation rel)
122123
{
123124
ScanKey skey;
124-
int natts;
125+
int nkeyatts;
125126
int16 *indoption;
126127
int i;
127128

128-
natts = RelationGetNumberOfAttributes(rel);
129+
nkeyatts = IndexRelationGetNumberOfKeyAttributes(rel);
129130
indoption = rel->rd_indoption;
130131

131-
skey = (ScanKey) palloc(natts * sizeof(ScanKeyData));
132+
skey = (ScanKey) palloc(nkeyatts * sizeof(ScanKeyData));
132133

133-
for (i = 0; i < natts; i++)
134+
for (i = 0; i < nkeyatts; i++)
134135
{
135136
FmgrInfo *procinfo;
136137
int flags;

src/backend/catalog/index.c

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,9 @@ ConstructTupleDescriptor(Relation heapRelation,
425425
namestrcpy(&to->attname, (const char *) lfirst(colnames_item));
426426
colnames_item = lnext(colnames_item);
427427

428+
if (i >= indexInfo->ii_NumIndexKeyAttrs)
429+
continue;
430+
428431
/*
429432
* Check the opclass and index AM to see if either provides a keytype
430433
* (overriding the attribute type). Opclass takes precedence.
@@ -1012,7 +1015,7 @@ index_create(Relation heapRelation,
10121015
}
10131016

10141017
/* Store dependency on operator classes */
1015-
for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
1018+
for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
10161019
{
10171020
referenced.classId = OperatorClassRelationId;
10181021
referenced.objectId = classObjectId[i];
@@ -1632,19 +1635,19 @@ BuildIndexInfo(Relation index)
16321635
IndexInfo *ii = makeNode(IndexInfo);
16331636
Form_pg_index indexStruct = index->rd_index;
16341637
int i;
1635-
int numKeys;
1638+
int numAtts;
16361639

16371640
/* check the number of keys, and copy attr numbers into the IndexInfo */
1638-
numKeys = indexStruct->indnatts;
1639-
if (numKeys < 1 || numKeys > INDEX_MAX_KEYS)
1641+
numAtts = indexStruct->indnatts;
1642+
if (numAtts < 1 || numAtts > INDEX_MAX_KEYS)
16401643
elog(ERROR, "invalid indnatts %d for index %u",
1641-
numKeys, RelationGetRelid(index));
1642-
ii->ii_NumIndexAttrs = numKeys;
1644+
numAtts, RelationGetRelid(index));
1645+
ii->ii_NumIndexAttrs = numAtts;
16431646
ii->ii_NumIndexKeyAttrs = indexStruct->indnkeyatts;
16441647
Assert(ii->ii_NumIndexKeyAttrs != 0);
16451648
Assert(ii->ii_NumIndexKeyAttrs <= ii->ii_NumIndexAttrs);
16461649

1647-
for (i = 0; i < numKeys; i++)
1650+
for (i = 0; i < numAtts; i++)
16481651
ii->ii_KeyAttrNumbers[i] = indexStruct->indkey.values[i];
16491652

16501653
/* fetch any expressions needed for expressional indexes */
@@ -1700,9 +1703,11 @@ BuildIndexInfo(Relation index)
17001703
void
17011704
BuildSpeculativeIndexInfo(Relation index, IndexInfo *ii)
17021705
{
1703-
int ncols = index->rd_rel->relnatts;
1706+
int nkeycols;
17041707
int i;
17051708

1709+
nkeycols = IndexRelationGetNumberOfKeyAttributes(index);
1710+
17061711
/*
17071712
* fetch info for checking unique indexes
17081713
*/
@@ -1711,16 +1716,16 @@ BuildSpeculativeIndexInfo(Relation index, IndexInfo *ii)
17111716
if (index->rd_rel->relam != BTREE_AM_OID)
17121717
elog(ERROR, "unexpected non-btree speculative unique index");
17131718

1714-
ii->ii_UniqueOps = (Oid *) palloc(sizeof(Oid) * ncols);
1715-
ii->ii_UniqueProcs = (Oid *) palloc(sizeof(Oid) * ncols);
1716-
ii->ii_UniqueStrats = (uint16 *) palloc(sizeof(uint16) * ncols);
1719+
ii->ii_UniqueOps = (Oid *) palloc(sizeof(Oid) * nkeycols);
1720+
ii->ii_UniqueProcs = (Oid *) palloc(sizeof(Oid) * nkeycols);
1721+
ii->ii_UniqueStrats = (uint16 *) palloc(sizeof(uint16) * nkeycols);
17171722

17181723
/*
17191724
* We have to look up the operator's strategy number. This provides a
17201725
* cross-check that the operator does match the index.
17211726
*/
17221727
/* We need the func OIDs and strategy numbers too */
1723-
for (i = 0; i < ncols; i++)
1728+
for (i = 0; i < nkeycols; i++)
17241729
{
17251730
ii->ii_UniqueStrats[i] = BTEqualStrategyNumber;
17261731
ii->ii_UniqueOps[i] =

src/backend/commands/indexcmds.c

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -320,8 +320,8 @@ DefineIndex(Oid relationId,
320320
Datum reloptions;
321321
int16 *coloptions;
322322
IndexInfo *indexInfo;
323-
int numberOfAttributes,
324-
numberOfKeyAttributes;
323+
int numberOfAttributes;
324+
int numberOfKeyAttributes;
325325
TransactionId limitXmin;
326326
VirtualTransactionId *old_snapshots;
327327
ObjectAddress address;
@@ -336,7 +336,6 @@ DefineIndex(Oid relationId,
336336
ereport(ERROR,
337337
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
338338
errmsg("included columns must not intersect with key columns")));
339-
340339
/*
341340
* count attributes in index
342341
*/
@@ -351,7 +350,7 @@ DefineIndex(Oid relationId,
351350
* we have one list with all columns. Later we can determine which of these
352351
* are key columns, and which are just part of the INCLUDING list by check the list
353352
* position. A list item in a position less than ii_NumIndexKeyAttrs is part of
354-
* the indexed columns, and anything equal to and over is part of the
353+
* the key columns, and anything equal to and over is part of the
355354
* INCLUDING columns.
356355
*/
357356
stmt->indexParams = list_concat(stmt->indexParams, stmt->indexIncludingParams);
@@ -488,7 +487,6 @@ DefineIndex(Oid relationId,
488487
* look up the access method, verify it can handle the requested features
489488
*/
490489
accessMethodName = stmt->accessMethod;
491-
492490
tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName));
493491
if (!HeapTupleIsValid(tuple))
494492
{
@@ -523,6 +521,11 @@ DefineIndex(Oid relationId,
523521
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
524522
errmsg("access method \"%s\" does not support unique indexes",
525523
accessMethodName)));
524+
if (list_length(stmt->indexIncludingParams) > 0 && !accessMethodForm->amcaninclude)
525+
ereport(ERROR,
526+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
527+
errmsg("access method \"%s\" does not support included columns",
528+
accessMethodName)));
526529
if (numberOfAttributes > 1 && !accessMethodForm->amcanmulticol)
527530
ereport(ERROR,
528531
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -534,12 +537,6 @@ DefineIndex(Oid relationId,
534537
errmsg("access method \"%s\" does not support exclusion constraints",
535538
accessMethodName)));
536539

537-
if (list_length(stmt->indexIncludingParams) > 0 && !accessMethodForm->amcanincluding)
538-
ereport(ERROR,
539-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
540-
errmsg("access method \"%s\" does not support included columns",
541-
accessMethodName)));
542-
543540
amcanorder = accessMethodForm->amcanorder;
544541
amoptions = accessMethodForm->amoptions;
545542

@@ -988,16 +985,15 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
988985
ListCell *nextExclOp;
989986
ListCell *lc;
990987
int attn;
988+
int nkeycols = indexInfo->ii_NumIndexKeyAttrs;
991989

992990
/* Allocate space for exclusion operator info, if needed */
993991
if (exclusionOpNames)
994992
{
995-
int ncols = list_length(attList);
996-
997-
Assert(list_length(exclusionOpNames) == ncols);
998-
indexInfo->ii_ExclusionOps = (Oid *) palloc(sizeof(Oid) * ncols);
999-
indexInfo->ii_ExclusionProcs = (Oid *) palloc(sizeof(Oid) * ncols);
1000-
indexInfo->ii_ExclusionStrats = (uint16 *) palloc(sizeof(uint16) * ncols);
993+
Assert(list_length(exclusionOpNames) == nkeycols);
994+
indexInfo->ii_ExclusionOps = (Oid *) palloc(sizeof(Oid) * nkeycols);
995+
indexInfo->ii_ExclusionProcs = (Oid *) palloc(sizeof(Oid) * nkeycols);
996+
indexInfo->ii_ExclusionStrats = (uint16 *) palloc(sizeof(uint16) * nkeycols);
1001997
nextExclOp = list_head(exclusionOpNames);
1002998
}
1003999
else
@@ -1050,6 +1046,11 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
10501046
Node *expr = attribute->expr;
10511047

10521048
Assert(expr != NULL);
1049+
1050+
if (attn >= nkeycols)
1051+
ereport(ERROR,
1052+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1053+
errmsg("Expressions in INCLUDING clause are not supported")));
10531054
atttype = exprType(expr);
10541055
attcollation = exprCollation(expr);
10551056

@@ -1130,6 +1131,11 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
11301131
/*
11311132
* Identify the opclass to use.
11321133
*/
1134+
if (attn >= nkeycols)
1135+
{
1136+
attn++;
1137+
continue;
1138+
}
11331139
classOidP[attn] = GetIndexOpClass(attribute->opclass,
11341140
atttype,
11351141
accessMethodName,

0 commit comments

Comments
 (0)