Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

+8-7
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

+16-8
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

+22
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

+11
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

+7
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

+2-2
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

+1-1
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

+1
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

+1
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

+1
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

+1-1
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

+26-26
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

+4
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

+1-1
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

+1
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)