Fix fuzzy thinking about amcanmulticol versus amcaninclude.

These flags should be independent: in particular an index AM should
be able to say that it supports include columns without necessarily
supporting multiple key columns.  The included-columns patch got
this wrong, possibly aided by the fact that it didn't bother to
update the documentation.

While here, clarify some text about amcanreturn, which was a little
vague about what should happen when amcanreturn reports that only
some of the index columns are returnable.

Noted while reviewing the SP-GiST included-columns patch, which
quite incorrectly (and unsafely) changed SP-GiST to claim
amcanmulticol = true as a workaround for this bug.

Backpatch to v11 where included columns were introduced.
This commit is contained in:
Tom Lane 2020-11-15 16:10:48 -05:00
parent 46cf3c72c3
commit 29d29d652f
2 changed files with 29 additions and 10 deletions

View File

@ -197,7 +197,7 @@ typedef struct IndexAmRoutine
implications. The requirements of <structfield>amcanunique</structfield>
are discussed in <xref linkend="index-unique-checks"/>.
The <structfield>amcanmulticol</structfield> flag asserts that the
access method supports multicolumn indexes, while
access method supports multi-key-column indexes, while
<structfield>amoptionalkey</structfield> asserts that it allows scans
where no indexable restriction clause is given for the first index column.
When <structfield>amcanmulticol</structfield> is false,
@ -233,6 +233,19 @@ typedef struct IndexAmRoutine
conditions.
</para>
<para>
The <structfield>amcaninclude</structfield> flag indicates whether the
access method supports <quote>included</quote> columns, that is it can
store (without processing) additional columns beyond the key column(s).
The requirements of the preceding paragraph apply only to the key
columns. In particular, the combination
of <structfield>amcanmulticol</structfield>=<literal>false</literal>
and <structfield>amcaninclude</structfield>=<literal>true</literal> is
sensible: it means that there can only be one key column, but there can
also be included column(s). Also, included columns must be allowed to be
null, independently of <structfield>amoptionalkey</structfield>.
</para>
</sect1>
<sect1 id="index-functions">
@ -383,10 +396,13 @@ amcanreturn (Relation indexRelation, int attno);
</programlisting>
Check whether the index can support <link
linkend="indexes-index-only-scans"><firstterm>index-only scans</firstterm></link> on
the given column, by returning the indexed column values for an index entry
in the form of an <structname>IndexTuple</structname>. The attribute number
is 1-based, i.e., the first column's attno is 1. Returns true if supported,
else false. If the access method does not support index-only scans at all,
the given column, by returning the column's original indexed value.
The attribute number is 1-based, i.e., the first column's attno is 1.
Returns true if supported, else false.
This function should always return true for included columns
(if those are supported), since there's little point in an included
column that can't be retrieved.
If the access method does not support index-only scans at all,
the <structfield>amcanreturn</structfield> field in its <structname>IndexAmRoutine</structname>
struct can be set to NULL.
</para>
@ -476,7 +492,7 @@ amproperty (Oid index_oid, int attno,
core code does not know how to do that and will return NULL. It may
also be advantageous to implement <literal>AMPROP_RETURNABLE</literal> testing,
if that can be done more cheaply than by opening the index and calling
<structfield>amcanreturn</structfield>, which is the core code's default behavior.
<function>amcanreturn</function>, which is the core code's default behavior.
The default behavior should be satisfactory for all other standard
properties.
</para>
@ -621,10 +637,13 @@ amgettuple (IndexScanDesc scan,
<para>
If the index supports <link linkend="indexes-index-only-scans">index-only
scans</link> (i.e., <function>amcanreturn</function> returns true for it),
scans</link> (i.e., <function>amcanreturn</function> returns true for any
of its columns),
then on success the AM must also check <literal>scan-&gt;xs_want_itup</literal>,
and if that is true it must return the originally indexed data for the
index entry. The data can be returned in the form of an
index entry. Columns for which <function>amcanreturn</function> returns
false can be returned as nulls.
The data can be returned in the form of an
<structname>IndexTuple</structname> pointer stored at <literal>scan-&gt;xs_itup</literal>,
with tuple descriptor <literal>scan-&gt;xs_itupdesc</literal>; or in the form of
a <structname>HeapTuple</structname> pointer stored at <literal>scan-&gt;xs_hitup</literal>,

View File

@ -597,7 +597,7 @@ DefineIndex(Oid relationId,
stmt->indexIncludingParams);
numberOfAttributes = list_length(allIndexParams);
if (numberOfAttributes <= 0)
if (numberOfKeyAttributes <= 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("must specify at least one column")));
@ -820,7 +820,7 @@ DefineIndex(Oid relationId,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("access method \"%s\" does not support included columns",
accessMethodName)));
if (numberOfAttributes > 1 && !amRoutine->amcanmulticol)
if (numberOfKeyAttributes > 1 && !amRoutine->amcanmulticol)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("access method \"%s\" does not support multicolumn indexes",