Replace simple constant pg_am.amcanreturn with an AM support function.

The need for this was debated when we put in the index-only-scan feature,
but at the time we had no near-term expectation of having AMs that could
support such scans for only some indexes; so we kept it simple.  However,
the SP-GiST AM forces the issue, so let's fix it.

This patch only installs the new API; no behavior actually changes.
This commit is contained in:
Tom Lane 2011-12-18 15:49:00 -05:00
parent 19d2231718
commit 3695a55513
15 changed files with 103 additions and 46 deletions

View File

@ -481,13 +481,6 @@
<entry>Does the access method support multicolumn indexes?</entry>
</row>
<row>
<entry><structfield>amcanreturn</structfield></entry>
<entry><type>bool</type></entry>
<entry></entry>
<entry>Can the access method return the contents of index entries?</entry>
</row>
<row>
<entry><structfield>amoptionalkey</structfield></entry>
<entry><type>bool</type></entry>
@ -622,6 +615,14 @@
<entry>Post-<command>VACUUM</command> cleanup function</entry>
</row>
<row>
<entry><structfield>amcanreturn</structfield></entry>
<entry><type>regproc</type></entry>
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
<entry>Function to check whether index supports index-only scans,
or zero if none</entry>
</row>
<row>
<entry><structfield>amcostestimate</structfield></entry>
<entry><type>regproc</type></entry>

View File

@ -134,11 +134,6 @@
<structfield>amsearchnulls</structfield>, indicating that it supports
<literal>IS NULL</> and <literal>IS NOT NULL</> clauses as search
conditions.
An index method can also set <structfield>amcanreturn</structfield>,
indicating that it can support <firstterm>index-only scans</> by returning
the indexed column values for an index entry in the form of an IndexTuple.
(An example of an index AM that cannot do this is hash, which stores only
the hash values not the original data.)
</para>
</sect1>
@ -278,6 +273,19 @@ amvacuumcleanup (IndexVacuumInfo *info,
<para>
<programlisting>
bool
amcanreturn (Relation indexRelation);
</programlisting>
Check whether the index can support <firstterm>index-only scans</> by
returning the indexed column values for an index entry in the form of an
IndexTuple. Return TRUE if so, else FALSE. If the index AM can never
support index-only scans (an example is hash, which stores only
the hash values not the original data), it is sufficient to set its
<structfield>amcanreturn</> field to zero in <structname>pg_am</>.
</para>
<para>
<programlisting>
void
amcostestimate (PlannerInfo *root,
IndexOptInfo *index,
@ -391,9 +399,9 @@ amgettuple (IndexScanDesc scan,
</para>
<para>
If the access method supports index-only scans (i.e.,
<structfield>amcanreturn</structfield> is TRUE in its <structname>pg_am</>
row), then on success it must also check
If the index supports index-only scans (i.e.,
<function>amcanreturn</function> returns TRUE for it),
then on success the AM must also check
<literal>scan-&gt;xs_want_itup</>, and if that is true it must return
the original indexed data for the index entry, in the form of an
<structname>IndexTuple</> pointer stored at <literal>scan-&gt;xs_itup</>,

View File

@ -26,6 +26,7 @@
* index_getbitmap - get all tuples from a scan
* index_bulk_delete - bulk deletion of index tuples
* index_vacuum_cleanup - post-deletion cleanup of an index
* index_can_return - does index support index-only scans?
* index_getprocid - get a support procedure OID
* index_getprocinfo - get a support procedure's lookup info
*
@ -711,6 +712,27 @@ index_vacuum_cleanup(IndexVacuumInfo *info,
return result;
}
/* ----------------
* index_can_return - does index support index-only scans?
* ----------------
*/
bool
index_can_return(Relation indexRelation)
{
FmgrInfo *procedure;
RELATION_CHECKS;
/* amcanreturn is optional; assume FALSE if not provided by AM */
if (!RegProcedureIsValid(indexRelation->rd_am->amcanreturn))
return false;
GET_REL_PROCEDURE(amcanreturn);
return DatumGetBool(FunctionCall1(procedure,
PointerGetDatum(indexRelation)));
}
/* ----------------
* index_getprocid
*

View File

@ -1091,3 +1091,14 @@ restart:
goto restart;
}
}
/*
* btcanreturn() -- Check whether btree indexes support index-only scans.
*
* btrees always do, so this is trivial.
*/
Datum
btcanreturn(PG_FUNCTION_ARGS)
{
PG_RETURN_BOOL(true);
}

View File

@ -559,3 +559,10 @@ spggettuple(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(false);
}
Datum
spgcanreturn(PG_FUNCTION_ARGS)
{
/* Not implemented yet */
PG_RETURN_BOOL(false);
}

View File

@ -1075,10 +1075,10 @@ check_index_only(RelOptInfo *rel, IndexOptInfo *index)
ListCell *lc;
int i;
/* Index-only scans must be enabled, and AM must be capable of it */
/* Index-only scans must be enabled, and index must be capable of them */
if (!enable_indexonlyscan)
return false;
if (!index->amcanreturn)
if (!index->canreturn)
return false;
/*

View File

@ -212,8 +212,8 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
info->relam = indexRelation->rd_rel->relam;
info->amcostestimate = indexRelation->rd_am->amcostestimate;
info->canreturn = index_can_return(indexRelation);
info->amcanorderbyop = indexRelation->rd_am->amcanorderbyop;
info->amcanreturn = indexRelation->rd_am->amcanreturn;
info->amoptionalkey = indexRelation->rd_am->amoptionalkey;
info->amsearcharray = indexRelation->rd_am->amsearcharray;
info->amsearchnulls = indexRelation->rd_am->amsearchnulls;

View File

@ -156,6 +156,7 @@ extern IndexBulkDeleteResult *index_bulk_delete(IndexVacuumInfo *info,
void *callback_state);
extern IndexBulkDeleteResult *index_vacuum_cleanup(IndexVacuumInfo *info,
IndexBulkDeleteResult *stats);
extern bool index_can_return(Relation indexRelation);
extern RegProcedure index_getprocid(Relation irel, AttrNumber attnum,
uint16 procnum);
extern FmgrInfo *index_getprocinfo(Relation irel, AttrNumber attnum,

View File

@ -607,6 +607,7 @@ extern Datum btmarkpos(PG_FUNCTION_ARGS);
extern Datum btrestrpos(PG_FUNCTION_ARGS);
extern Datum btbulkdelete(PG_FUNCTION_ARGS);
extern Datum btvacuumcleanup(PG_FUNCTION_ARGS);
extern Datum btcanreturn(PG_FUNCTION_ARGS);
extern Datum btoptions(PG_FUNCTION_ARGS);
/*

View File

@ -182,6 +182,7 @@ extern Datum spgmarkpos(PG_FUNCTION_ARGS);
extern Datum spgrestrpos(PG_FUNCTION_ARGS);
extern Datum spggetbitmap(PG_FUNCTION_ARGS);
extern Datum spggettuple(PG_FUNCTION_ARGS);
extern Datum spgcanreturn(PG_FUNCTION_ARGS);
/* spgutils.c */
extern Datum spgoptions(PG_FUNCTION_ARGS);

View File

@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201112172
#define CATALOG_VERSION_NO 201112181
#endif

View File

@ -45,7 +45,6 @@ CATALOG(pg_am,2601)
bool amcanbackward; /* does AM support backward scan? */
bool amcanunique; /* does AM support UNIQUE indexes? */
bool amcanmulticol; /* does AM support multi-column indexes? */
bool amcanreturn; /* can AM return IndexTuples? */
bool amoptionalkey; /* can query omit key for the first column? */
bool amsearcharray; /* can AM handle ScalarArrayOpExpr quals? */
bool amsearchnulls; /* can AM search for NULL/NOT NULL entries? */
@ -65,6 +64,7 @@ CATALOG(pg_am,2601)
regproc ambuildempty; /* "build empty index" function */
regproc ambulkdelete; /* bulk-delete function */
regproc amvacuumcleanup; /* post-VACUUM cleanup function */
regproc amcanreturn; /* can indexscan return IndexTuples? */
regproc amcostestimate; /* estimate cost of an indexscan */
regproc amoptions; /* parse AM-specific parameters */
} FormData_pg_am;
@ -89,26 +89,26 @@ typedef FormData_pg_am *Form_pg_am;
#define Anum_pg_am_amcanbackward 6
#define Anum_pg_am_amcanunique 7
#define Anum_pg_am_amcanmulticol 8
#define Anum_pg_am_amcanreturn 9
#define Anum_pg_am_amoptionalkey 10
#define Anum_pg_am_amsearcharray 11
#define Anum_pg_am_amsearchnulls 12
#define Anum_pg_am_amstorage 13
#define Anum_pg_am_amclusterable 14
#define Anum_pg_am_ampredlocks 15
#define Anum_pg_am_amkeytype 16
#define Anum_pg_am_aminsert 17
#define Anum_pg_am_ambeginscan 18
#define Anum_pg_am_amgettuple 19
#define Anum_pg_am_amgetbitmap 20
#define Anum_pg_am_amrescan 21
#define Anum_pg_am_amendscan 22
#define Anum_pg_am_ammarkpos 23
#define Anum_pg_am_amrestrpos 24
#define Anum_pg_am_ambuild 25
#define Anum_pg_am_ambuildempty 26
#define Anum_pg_am_ambulkdelete 27
#define Anum_pg_am_amvacuumcleanup 28
#define Anum_pg_am_amoptionalkey 9
#define Anum_pg_am_amsearcharray 10
#define Anum_pg_am_amsearchnulls 11
#define Anum_pg_am_amstorage 12
#define Anum_pg_am_amclusterable 13
#define Anum_pg_am_ampredlocks 14
#define Anum_pg_am_amkeytype 15
#define Anum_pg_am_aminsert 16
#define Anum_pg_am_ambeginscan 17
#define Anum_pg_am_amgettuple 18
#define Anum_pg_am_amgetbitmap 19
#define Anum_pg_am_amrescan 20
#define Anum_pg_am_amendscan 21
#define Anum_pg_am_ammarkpos 22
#define Anum_pg_am_amrestrpos 23
#define Anum_pg_am_ambuild 24
#define Anum_pg_am_ambuildempty 25
#define Anum_pg_am_ambulkdelete 26
#define Anum_pg_am_amvacuumcleanup 27
#define Anum_pg_am_amcanreturn 28
#define Anum_pg_am_amcostestimate 29
#define Anum_pg_am_amoptions 30
@ -117,19 +117,19 @@ typedef FormData_pg_am *Form_pg_am;
* ----------------
*/
DATA(insert OID = 403 ( btree 5 2 t f t t t t t t t f t t 0 btinsert btbeginscan btgettuple btgetbitmap btrescan btendscan btmarkpos btrestrpos btbuild btbuildempty btbulkdelete btvacuumcleanup btcostestimate btoptions ));
DATA(insert OID = 403 ( btree 5 2 t f t t t t t t f t t 0 btinsert btbeginscan btgettuple btgetbitmap btrescan btendscan btmarkpos btrestrpos btbuild btbuildempty btbulkdelete btvacuumcleanup btcanreturn btcostestimate btoptions ));
DESCR("b-tree index access method");
#define BTREE_AM_OID 403
DATA(insert OID = 405 ( hash 1 1 f f t f f f f f f f f f 23 hashinsert hashbeginscan hashgettuple hashgetbitmap hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbuildempty hashbulkdelete hashvacuumcleanup hashcostestimate hashoptions ));
DATA(insert OID = 405 ( hash 1 1 f f t f f f f f f f f 23 hashinsert hashbeginscan hashgettuple hashgetbitmap hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbuildempty hashbulkdelete hashvacuumcleanup - hashcostestimate hashoptions ));
DESCR("hash index access method");
#define HASH_AM_OID 405
DATA(insert OID = 783 ( gist 0 8 f t f f t f t f t t t f 0 gistinsert gistbeginscan gistgettuple gistgetbitmap gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbuildempty gistbulkdelete gistvacuumcleanup gistcostestimate gistoptions ));
DATA(insert OID = 783 ( gist 0 8 f t f f t t f t t t f 0 gistinsert gistbeginscan gistgettuple gistgetbitmap gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbuildempty gistbulkdelete gistvacuumcleanup - gistcostestimate gistoptions ));
DESCR("GiST index access method");
#define GIST_AM_OID 783
DATA(insert OID = 2742 ( gin 0 5 f f f f t f t f f t f f 0 gininsert ginbeginscan - gingetbitmap ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbuildempty ginbulkdelete ginvacuumcleanup gincostestimate ginoptions ));
DATA(insert OID = 2742 ( gin 0 5 f f f f t t f f t f f 0 gininsert ginbeginscan - gingetbitmap ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbuildempty ginbulkdelete ginvacuumcleanup - gincostestimate ginoptions ));
DESCR("GIN index access method");
#define GIN_AM_OID 2742
DATA(insert OID = 4000 ( spgist 0 5 f f f f f f f f f f f f 0 spginsert spgbeginscan spggettuple spggetbitmap spgrescan spgendscan spgmarkpos spgrestrpos spgbuild spgbuildempty spgbulkdelete spgvacuumcleanup spgcostestimate spgoptions ));
DATA(insert OID = 4000 ( spgist 0 5 f f f f f f f f f f f 0 spginsert spgbeginscan spggettuple spggetbitmap spgrescan spgendscan spgmarkpos spgrestrpos spgbuild spgbuildempty spgbulkdelete spgvacuumcleanup spgcanreturn spgcostestimate spgoptions ));
DESCR("SP-GiST index access method");
#define SPGIST_AM_OID 4000

View File

@ -546,6 +546,8 @@ DATA(insert OID = 332 ( btbulkdelete PGNSP PGUID 12 1 0 0 0 f f f t f v 4 0
DESCR("btree(internal)");
DATA(insert OID = 972 ( btvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f t f v 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ btvacuumcleanup _null_ _null_ _null_ ));
DESCR("btree(internal)");
DATA(insert OID = 276 ( btcanreturn PGNSP PGUID 12 1 0 0 0 f f f t f s 1 0 16 "2281" _null_ _null_ _null_ _null_ btcanreturn _null_ _null_ _null_ ));
DESCR("btree(internal)");
DATA(insert OID = 1268 ( btcostestimate PGNSP PGUID 12 1 0 0 0 f f f t f v 9 0 2278 "2281 2281 2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ btcostestimate _null_ _null_ _null_ ));
DESCR("btree(internal)");
DATA(insert OID = 2785 ( btoptions PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ btoptions _null_ _null_ _null_ ));
@ -4506,6 +4508,8 @@ DATA(insert OID = 4011 ( spgbulkdelete PGNSP PGUID 12 1 0 0 0 f f f t f v 4
DESCR("spgist(internal)");
DATA(insert OID = 4012 ( spgvacuumcleanup PGNSP PGUID 12 1 0 0 0 f f f t f v 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ spgvacuumcleanup _null_ _null_ _null_ ));
DESCR("spgist(internal)");
DATA(insert OID = 4032 ( spgcanreturn PGNSP PGUID 12 1 0 0 0 f f f t f s 1 0 16 "2281" _null_ _null_ _null_ _null_ spgcanreturn _null_ _null_ _null_ ));
DESCR("spgist(internal)");
DATA(insert OID = 4013 ( spgcostestimate PGNSP PGUID 12 1 0 0 0 f f f t f v 9 0 2278 "2281 2281 2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ spgcostestimate _null_ _null_ _null_ ));
DESCR("spgist(internal)");
DATA(insert OID = 4014 ( spgoptions PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 17 "1009 16" _null_ _null_ _null_ _null_ spgoptions _null_ _null_ _null_ ));

View File

@ -490,8 +490,8 @@ typedef struct IndexOptInfo
bool unique; /* true if a unique index */
bool immediate; /* is uniqueness enforced immediately? */
bool hypothetical; /* true if index doesn't really exist */
bool canreturn; /* can index return IndexTuples? */
bool amcanorderbyop; /* does AM support order by operator result? */
bool amcanreturn; /* can AM return IndexTuples? */
bool amoptionalkey; /* can query omit key for the first column? */
bool amsearcharray; /* can AM handle ScalarArrayOpExpr quals? */
bool amsearchnulls; /* can AM search for NULL/NOT NULL entries? */

View File

@ -64,6 +64,7 @@ typedef struct RelationAmInfo
FmgrInfo ambuildempty;
FmgrInfo ambulkdelete;
FmgrInfo amvacuumcleanup;
FmgrInfo amcanreturn;
FmgrInfo amcostestimate;
FmgrInfo amoptions;
} RelationAmInfo;