Fix fuzzy thinking about amcanmulticol versus amcaninclude.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 15 Nov 2020 21:10:48 +0000 (16:10 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 15 Nov 2020 21:10:58 +0000 (16:10 -0500)
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.

doc/src/sgml/indexam.sgml
src/backend/commands/indexcmds.c

index 80473e0f1a2b0702ae00a9e01f82608b27cc6ea5..f00268d5b51f2c6818d333ada386cd47068a7240 100644 (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>,
index 3522f4b6a69c043f51f6216df6a872232a42973b..35696f9f757546be16489fd37d6ca8973fbaa27b 100644 (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",