Skip to content

Commit 3695a55

Browse files
committed
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.
1 parent 19d2231 commit 3695a55

File tree

15 files changed

+103
-46
lines changed

15 files changed

+103
-46
lines changed

doc/src/sgml/catalogs.sgml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -481,13 +481,6 @@
481481
<entry>Does the access method support multicolumn indexes?</entry>
482482
</row>
483483

484-
<row>
485-
<entry><structfield>amcanreturn</structfield></entry>
486-
<entry><type>bool</type></entry>
487-
<entry></entry>
488-
<entry>Can the access method return the contents of index entries?</entry>
489-
</row>
490-
491484
<row>
492485
<entry><structfield>amoptionalkey</structfield></entry>
493486
<entry><type>bool</type></entry>
@@ -622,6 +615,14 @@
622615
<entry>Post-<command>VACUUM</command> cleanup function</entry>
623616
</row>
624617

618+
<row>
619+
<entry><structfield>amcanreturn</structfield></entry>
620+
<entry><type>regproc</type></entry>
621+
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
622+
<entry>Function to check whether index supports index-only scans,
623+
or zero if none</entry>
624+
</row>
625+
625626
<row>
626627
<entry><structfield>amcostestimate</structfield></entry>
627628
<entry><type>regproc</type></entry>

doc/src/sgml/indexam.sgml

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,6 @@
134134
<structfield>amsearchnulls</structfield>, indicating that it supports
135135
<literal>IS NULL</> and <literal>IS NOT NULL</> clauses as search
136136
conditions.
137-
An index method can also set <structfield>amcanreturn</structfield>,
138-
indicating that it can support <firstterm>index-only scans</> by returning
139-
the indexed column values for an index entry in the form of an IndexTuple.
140-
(An example of an index AM that cannot do this is hash, which stores only
141-
the hash values not the original data.)
142137
</para>
143138

144139
</sect1>
@@ -278,6 +273,19 @@ amvacuumcleanup (IndexVacuumInfo *info,
278273

279274
<para>
280275
<programlisting>
276+
bool
277+
amcanreturn (Relation indexRelation);
278+
</programlisting>
279+
Check whether the index can support <firstterm>index-only scans</> by
280+
returning the indexed column values for an index entry in the form of an
281+
IndexTuple. Return TRUE if so, else FALSE. If the index AM can never
282+
support index-only scans (an example is hash, which stores only
283+
the hash values not the original data), it is sufficient to set its
284+
<structfield>amcanreturn</> field to zero in <structname>pg_am</>.
285+
</para>
286+
287+
<para>
288+
<programlisting>
281289
void
282290
amcostestimate (PlannerInfo *root,
283291
IndexOptInfo *index,
@@ -391,9 +399,9 @@ amgettuple (IndexScanDesc scan,
391399
</para>
392400

393401
<para>
394-
If the access method supports index-only scans (i.e.,
395-
<structfield>amcanreturn</structfield> is TRUE in its <structname>pg_am</>
396-
row), then on success it must also check
402+
If the index supports index-only scans (i.e.,
403+
<function>amcanreturn</function> returns TRUE for it),
404+
then on success the AM must also check
397405
<literal>scan-&gt;xs_want_itup</>, and if that is true it must return
398406
the original indexed data for the index entry, in the form of an
399407
<structname>IndexTuple</> pointer stored at <literal>scan-&gt;xs_itup</>,

src/backend/access/index/indexam.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
* index_getbitmap - get all tuples from a scan
2727
* index_bulk_delete - bulk deletion of index tuples
2828
* index_vacuum_cleanup - post-deletion cleanup of an index
29+
* index_can_return - does index support index-only scans?
2930
* index_getprocid - get a support procedure OID
3031
* index_getprocinfo - get a support procedure's lookup info
3132
*
@@ -711,6 +712,27 @@ index_vacuum_cleanup(IndexVacuumInfo *info,
711712
return result;
712713
}
713714

715+
/* ----------------
716+
* index_can_return - does index support index-only scans?
717+
* ----------------
718+
*/
719+
bool
720+
index_can_return(Relation indexRelation)
721+
{
722+
FmgrInfo *procedure;
723+
724+
RELATION_CHECKS;
725+
726+
/* amcanreturn is optional; assume FALSE if not provided by AM */
727+
if (!RegProcedureIsValid(indexRelation->rd_am->amcanreturn))
728+
return false;
729+
730+
GET_REL_PROCEDURE(amcanreturn);
731+
732+
return DatumGetBool(FunctionCall1(procedure,
733+
PointerGetDatum(indexRelation)));
734+
}
735+
714736
/* ----------------
715737
* index_getprocid
716738
*

src/backend/access/nbtree/nbtree.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,3 +1091,14 @@ btvacuumpage(BTVacState *vstate, BlockNumber blkno, BlockNumber orig_blkno)
10911091
goto restart;
10921092
}
10931093
}
1094+
1095+
/*
1096+
* btcanreturn() -- Check whether btree indexes support index-only scans.
1097+
*
1098+
* btrees always do, so this is trivial.
1099+
*/
1100+
Datum
1101+
btcanreturn(PG_FUNCTION_ARGS)
1102+
{
1103+
PG_RETURN_BOOL(true);
1104+
}

src/backend/access/spgist/spgscan.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,3 +559,10 @@ spggettuple(PG_FUNCTION_ARGS)
559559

560560
PG_RETURN_BOOL(false);
561561
}
562+
563+
Datum
564+
spgcanreturn(PG_FUNCTION_ARGS)
565+
{
566+
/* Not implemented yet */
567+
PG_RETURN_BOOL(false);
568+
}

src/backend/optimizer/path/indxpath.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,10 +1075,10 @@ check_index_only(RelOptInfo *rel, IndexOptInfo *index)
10751075
ListCell *lc;
10761076
int i;
10771077

1078-
/* Index-only scans must be enabled, and AM must be capable of it */
1078+
/* Index-only scans must be enabled, and index must be capable of them */
10791079
if (!enable_indexonlyscan)
10801080
return false;
1081-
if (!index->amcanreturn)
1081+
if (!index->canreturn)
10821082
return false;
10831083

10841084
/*

src/backend/optimizer/util/plancat.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,8 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
212212

213213
info->relam = indexRelation->rd_rel->relam;
214214
info->amcostestimate = indexRelation->rd_am->amcostestimate;
215+
info->canreturn = index_can_return(indexRelation);
215216
info->amcanorderbyop = indexRelation->rd_am->amcanorderbyop;
216-
info->amcanreturn = indexRelation->rd_am->amcanreturn;
217217
info->amoptionalkey = indexRelation->rd_am->amoptionalkey;
218218
info->amsearcharray = indexRelation->rd_am->amsearcharray;
219219
info->amsearchnulls = indexRelation->rd_am->amsearchnulls;

src/include/access/genam.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ extern IndexBulkDeleteResult *index_bulk_delete(IndexVacuumInfo *info,
156156
void *callback_state);
157157
extern IndexBulkDeleteResult *index_vacuum_cleanup(IndexVacuumInfo *info,
158158
IndexBulkDeleteResult *stats);
159+
extern bool index_can_return(Relation indexRelation);
159160
extern RegProcedure index_getprocid(Relation irel, AttrNumber attnum,
160161
uint16 procnum);
161162
extern FmgrInfo *index_getprocinfo(Relation irel, AttrNumber attnum,

src/include/access/nbtree.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,7 @@ extern Datum btmarkpos(PG_FUNCTION_ARGS);
607607
extern Datum btrestrpos(PG_FUNCTION_ARGS);
608608
extern Datum btbulkdelete(PG_FUNCTION_ARGS);
609609
extern Datum btvacuumcleanup(PG_FUNCTION_ARGS);
610+
extern Datum btcanreturn(PG_FUNCTION_ARGS);
610611
extern Datum btoptions(PG_FUNCTION_ARGS);
611612

612613
/*

src/include/access/spgist.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ extern Datum spgmarkpos(PG_FUNCTION_ARGS);
182182
extern Datum spgrestrpos(PG_FUNCTION_ARGS);
183183
extern Datum spggetbitmap(PG_FUNCTION_ARGS);
184184
extern Datum spggettuple(PG_FUNCTION_ARGS);
185+
extern Datum spgcanreturn(PG_FUNCTION_ARGS);
185186

186187
/* spgutils.c */
187188
extern Datum spgoptions(PG_FUNCTION_ARGS);

src/include/catalog/catversion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 201112172
56+
#define CATALOG_VERSION_NO 201112181
5757

5858
#endif

src/include/catalog/pg_am.h

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ CATALOG(pg_am,2601)
4545
bool amcanbackward; /* does AM support backward scan? */
4646
bool amcanunique; /* does AM support UNIQUE indexes? */
4747
bool amcanmulticol; /* does AM support multi-column indexes? */
48-
bool amcanreturn; /* can AM return IndexTuples? */
4948
bool amoptionalkey; /* can query omit key for the first column? */
5049
bool amsearcharray; /* can AM handle ScalarArrayOpExpr quals? */
5150
bool amsearchnulls; /* can AM search for NULL/NOT NULL entries? */
@@ -65,6 +64,7 @@ CATALOG(pg_am,2601)
6564
regproc ambuildempty; /* "build empty index" function */
6665
regproc ambulkdelete; /* bulk-delete function */
6766
regproc amvacuumcleanup; /* post-VACUUM cleanup function */
67+
regproc amcanreturn; /* can indexscan return IndexTuples? */
6868
regproc amcostestimate; /* estimate cost of an indexscan */
6969
regproc amoptions; /* parse AM-specific parameters */
7070
} FormData_pg_am;
@@ -89,26 +89,26 @@ typedef FormData_pg_am *Form_pg_am;
8989
#define Anum_pg_am_amcanbackward 6
9090
#define Anum_pg_am_amcanunique 7
9191
#define Anum_pg_am_amcanmulticol 8
92-
#define Anum_pg_am_amcanreturn 9
93-
#define Anum_pg_am_amoptionalkey 10
94-
#define Anum_pg_am_amsearcharray 11
95-
#define Anum_pg_am_amsearchnulls 12
96-
#define Anum_pg_am_amstorage 13
97-
#define Anum_pg_am_amclusterable 14
98-
#define Anum_pg_am_ampredlocks 15
99-
#define Anum_pg_am_amkeytype 16
100-
#define Anum_pg_am_aminsert 17
101-
#define Anum_pg_am_ambeginscan 18
102-
#define Anum_pg_am_amgettuple 19
103-
#define Anum_pg_am_amgetbitmap 20
104-
#define Anum_pg_am_amrescan 21
105-
#define Anum_pg_am_amendscan 22
106-
#define Anum_pg_am_ammarkpos 23
107-
#define Anum_pg_am_amrestrpos 24
108-
#define Anum_pg_am_ambuild 25
109-
#define Anum_pg_am_ambuildempty 26
110-
#define Anum_pg_am_ambulkdelete 27
111-
#define Anum_pg_am_amvacuumcleanup 28
92+
#define Anum_pg_am_amoptionalkey 9
93+
#define Anum_pg_am_amsearcharray 10
94+
#define Anum_pg_am_amsearchnulls 11
95+
#define Anum_pg_am_amstorage 12
96+
#define Anum_pg_am_amclusterable 13
97+
#define Anum_pg_am_ampredlocks 14
98+
#define Anum_pg_am_amkeytype 15
99+
#define Anum_pg_am_aminsert 16
100+
#define Anum_pg_am_ambeginscan 17
101+
#define Anum_pg_am_amgettuple 18
102+
#define Anum_pg_am_amgetbitmap 19
103+
#define Anum_pg_am_amrescan 20
104+
#define Anum_pg_am_amendscan 21
105+
#define Anum_pg_am_ammarkpos 22
106+
#define Anum_pg_am_amrestrpos 23
107+
#define Anum_pg_am_ambuild 24
108+
#define Anum_pg_am_ambuildempty 25
109+
#define Anum_pg_am_ambulkdelete 26
110+
#define Anum_pg_am_amvacuumcleanup 27
111+
#define Anum_pg_am_amcanreturn 28
112112
#define Anum_pg_am_amcostestimate 29
113113
#define Anum_pg_am_amoptions 30
114114

@@ -117,19 +117,19 @@ typedef FormData_pg_am *Form_pg_am;
117117
* ----------------
118118
*/
119119

120-
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 ));
120+
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 ));
121121
DESCR("b-tree index access method");
122122
#define BTREE_AM_OID 403
123-
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 ));
123+
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 ));
124124
DESCR("hash index access method");
125125
#define HASH_AM_OID 405
126-
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 ));
126+
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 ));
127127
DESCR("GiST index access method");
128128
#define GIST_AM_OID 783
129-
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 ));
129+
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 ));
130130
DESCR("GIN index access method");
131131
#define GIN_AM_OID 2742
132-
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 ));
132+
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 ));
133133
DESCR("SP-GiST index access method");
134134
#define SPGIST_AM_OID 4000
135135

src/include/catalog/pg_proc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,8 @@ DATA(insert OID = 332 ( btbulkdelete PGNSP PGUID 12 1 0 0 0 f f f t f v 4 0
546546
DESCR("btree(internal)");
547547
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_ ));
548548
DESCR("btree(internal)");
549+
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_ ));
550+
DESCR("btree(internal)");
549551
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_ ));
550552
DESCR("btree(internal)");
551553
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
45064508
DESCR("spgist(internal)");
45074509
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_ ));
45084510
DESCR("spgist(internal)");
4511+
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_ ));
4512+
DESCR("spgist(internal)");
45094513
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_ ));
45104514
DESCR("spgist(internal)");
45114515
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_ ));

src/include/nodes/relation.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,8 +490,8 @@ typedef struct IndexOptInfo
490490
bool unique; /* true if a unique index */
491491
bool immediate; /* is uniqueness enforced immediately? */
492492
bool hypothetical; /* true if index doesn't really exist */
493+
bool canreturn; /* can index return IndexTuples? */
493494
bool amcanorderbyop; /* does AM support order by operator result? */
494-
bool amcanreturn; /* can AM return IndexTuples? */
495495
bool amoptionalkey; /* can query omit key for the first column? */
496496
bool amsearcharray; /* can AM handle ScalarArrayOpExpr quals? */
497497
bool amsearchnulls; /* can AM search for NULL/NOT NULL entries? */

src/include/utils/rel.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ typedef struct RelationAmInfo
6464
FmgrInfo ambuildempty;
6565
FmgrInfo ambulkdelete;
6666
FmgrInfo amvacuumcleanup;
67+
FmgrInfo amcanreturn;
6768
FmgrInfo amcostestimate;
6869
FmgrInfo amoptions;
6970
} RelationAmInfo;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy