Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 00ce737

Browse files
committed
Teach the planner to support index access methods that only implement
amgettuple or only implement amgetbitmap, instead of the former assumption that every AM supports both APIs. Extracted with minor editorialization from Teodor's fast-GIN-insert patch; whatever becomes of that, this seems like a simple and reasonable generalization of the index AM interface spec.
1 parent df8684c commit 00ce737

File tree

6 files changed

+114
-38
lines changed

6 files changed

+114
-38
lines changed

doc/src/sgml/catalogs.sgml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.198 2009/02/24 10:06:31 petere Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.199 2009/03/05 23:06:45 tgl Exp $ -->
22
<!--
33
Documentation of the system catalogs, directed toward PostgreSQL developers
44
-->
@@ -493,14 +493,14 @@
493493
<entry><structfield>amgettuple</structfield></entry>
494494
<entry><type>regproc</type></entry>
495495
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
496-
<entry><quote>Next valid tuple</quote> function</entry>
496+
<entry><quote>Next valid tuple</quote> function, or zero if none</entry>
497497
</row>
498498

499499
<row>
500500
<entry><structfield>amgetbitmap</structfield></entry>
501501
<entry><type>regproc</type></entry>
502502
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
503-
<entry><quote>Fetch all valid tuples</quote> function</entry>
503+
<entry><quote>Fetch all valid tuples</quote> function, or zero if none</entry>
504504
</row>
505505

506506
<row>

doc/src/sgml/indexam.sgml

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.28 2008/10/17 22:10:29 tgl Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.29 2009/03/05 23:06:45 tgl Exp $ -->
22

33
<chapter id="indexam">
44
<title>Index Access Method Interface Definition</title>
@@ -37,8 +37,10 @@
3737
extant versions of the same logical row; to an index, each tuple is
3838
an independent object that needs its own index entry. Thus, an
3939
update of a row always creates all-new index entries for the row, even if
40-
the key values did not change. Index entries for dead tuples are
41-
reclaimed (by vacuuming) when the dead tuples themselves are reclaimed.
40+
the key values did not change. (HOT tuples are an exception to this
41+
statement; but indexes do not deal with those, either.) Index entries for
42+
dead tuples are reclaimed (by vacuuming) when the dead tuples themselves
43+
are reclaimed.
4244
</para>
4345

4446
<sect1 id="index-catalog">
@@ -266,7 +268,7 @@ amoptions (ArrayType *reloptions,
266268
The function should construct a <type>bytea</> value, which will be copied
267269
into the <structfield>rd_options</> field of the index's relcache entry.
268270
The data contents of the <type>bytea</> value are open for the access
269-
method to define, but the standard access methods currently all use struct
271+
method to define; most of the standard access methods use struct
270272
<structname>StdRdOptions</>.
271273
When <parameter>validate</> is true, the function should report a suitable
272274
error message if any of the options are unrecognized or have invalid
@@ -283,8 +285,9 @@ amoptions (ArrayType *reloptions,
283285
an indexable <literal>WHERE</> condition, often called a
284286
<firstterm>qualifier</> or <firstterm>scan key</>. The semantics of
285287
index scanning are described more fully in <xref linkend="index-scanning">,
286-
below. The scan-related functions that an index access method must provide
287-
are:
288+
below. An index access method can support <quote>plain</> index scans,
289+
<quote>bitmap</> index scans, or both. The scan-related functions that an
290+
index access method must or may provide are:
288291
</para>
289292

290293
<para>
@@ -326,6 +329,13 @@ amgettuple (IndexScanDesc scan,
326329
callers.
327330
</para>
328331

332+
<para>
333+
The <function>amgettuple</> function need only be provided if the access
334+
method supports <quote>plain</> index scans. If it doesn't, the
335+
<structfield>amgettuple</> field in its <structname>pg_am</> row must
336+
be set to zero.
337+
</para>
338+
329339
<para>
330340
<programlisting>
331341
int64
@@ -349,6 +359,13 @@ amgetbitmap (IndexScanDesc scan,
349359
in <xref linkend="index-scanning">.
350360
</para>
351361

362+
<para>
363+
The <function>amgetbitmap</> function need only be provided if the access
364+
method supports <quote>bitmap</> index scans. If it doesn't, the
365+
<structfield>amgetbitmap</> field in its <structname>pg_am</> row must
366+
be set to zero.
367+
</para>
368+
352369
<para>
353370
<programlisting>
354371
void
@@ -519,6 +536,12 @@ amrestrpos (IndexScanDesc scan);
519536
spelled out in <xref linkend="index-locking">.
520537
</para>
521538

539+
<para>
540+
Note that it is permitted for an access method to implement only
541+
<function>amgetbitmap</> and not <function>amgettuple</>, or vice versa,
542+
if its internal implementation is unsuited to one API or the other.
543+
</para>
544+
522545
</sect1>
523546

524547
<sect1 id="index-locking">

src/backend/optimizer/path/indxpath.c

Lines changed: 73 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.236 2009/02/15 20:16:21 tgl Exp $
12+
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.237 2009/03/05 23:06:45 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -45,6 +45,14 @@
4545
((opfamily) == BOOL_BTREE_FAM_OID || (opfamily) == BOOL_HASH_FAM_OID)
4646

4747

48+
/* Whether we are looking for plain indexscan, bitmap scan, or either */
49+
typedef enum
50+
{
51+
ST_INDEXSCAN, /* must support amgettuple */
52+
ST_BITMAPSCAN, /* must support amgetbitmap */
53+
ST_ANYSCAN /* either is okay */
54+
} ScanTypeControl;
55+
4856
/* Per-path data used within choose_bitmap_and() */
4957
typedef struct
5058
{
@@ -58,7 +66,7 @@ typedef struct
5866
static List *find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
5967
List *clauses, List *outer_clauses,
6068
bool istoplevel, RelOptInfo *outer_rel,
61-
SaOpControl saop_control);
69+
SaOpControl saop_control, ScanTypeControl scantype);
6270
static List *find_saop_paths(PlannerInfo *root, RelOptInfo *rel,
6371
List *clauses, List *outer_clauses,
6472
bool istoplevel, RelOptInfo *outer_rel);
@@ -168,22 +176,28 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel)
168176
*/
169177
indexpaths = find_usable_indexes(root, rel,
170178
rel->baserestrictinfo, NIL,
171-
true, NULL, SAOP_FORBID);
179+
true, NULL, SAOP_FORBID, ST_ANYSCAN);
172180

173181
/*
174-
* We can submit them all to add_path. (This generates access paths for
175-
* plain IndexScan plans.) However, for the next step we will only want
176-
* the ones that have some selectivity; we must discard anything that was
182+
* Submit all the ones that can form plain IndexScan plans to add_path.
183+
* (A plain IndexPath always represents a plain IndexScan plan; however
184+
* some of the indexes might support only bitmap scans, and those we
185+
* mustn't submit to add_path here.) Also, pick out the ones that might
186+
* be useful as bitmap scans. For that, we must discard indexes that
187+
* don't support bitmap scans, and we also are only interested in paths
188+
* that have some selectivity; we should discard anything that was
177189
* generated solely for ordering purposes.
178190
*/
179191
bitindexpaths = NIL;
180192
foreach(l, indexpaths)
181193
{
182194
IndexPath *ipath = (IndexPath *) lfirst(l);
183195

184-
add_path(rel, (Path *) ipath);
196+
if (ipath->indexinfo->amhasgettuple)
197+
add_path(rel, (Path *) ipath);
185198

186-
if (ipath->indexselectivity < 1.0 &&
199+
if (ipath->indexinfo->amhasgetbitmap &&
200+
ipath->indexselectivity < 1.0 &&
187201
!ScanDirectionIsBackward(ipath->indexscandir))
188202
bitindexpaths = lappend(bitindexpaths, ipath);
189203
}
@@ -254,6 +268,7 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel)
254268
* 'outer_rel' is the outer side of the join if forming an inner indexscan
255269
* (so some of the given clauses are join clauses); NULL if not
256270
* 'saop_control' indicates whether ScalarArrayOpExpr clauses can be used
271+
* 'scantype' indicates whether we need plain or bitmap scan support
257272
*
258273
* Note: check_partial_indexes() must have been run previously.
259274
*----------
@@ -262,7 +277,7 @@ static List *
262277
find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
263278
List *clauses, List *outer_clauses,
264279
bool istoplevel, RelOptInfo *outer_rel,
265-
SaOpControl saop_control)
280+
SaOpControl saop_control, ScanTypeControl scantype)
266281
{
267282
Relids outer_relids = outer_rel ? outer_rel->relids : NULL;
268283
bool possibly_useful_pathkeys = has_useful_pathkeys(root, rel);
@@ -281,6 +296,24 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
281296
bool found_clause;
282297
bool index_is_ordered;
283298

299+
/*
300+
* Check that index supports the desired scan type(s)
301+
*/
302+
switch (scantype)
303+
{
304+
case ST_INDEXSCAN:
305+
if (!index->amhasgettuple)
306+
continue;
307+
break;
308+
case ST_BITMAPSCAN:
309+
if (!index->amhasgetbitmap)
310+
continue;
311+
break;
312+
case ST_ANYSCAN:
313+
/* either or both are OK */
314+
break;
315+
}
316+
284317
/*
285318
* Ignore partial indexes that do not match the query. If a partial
286319
* index is marked predOK then we know it's OK; otherwise, if we are
@@ -445,7 +478,7 @@ find_saop_paths(PlannerInfo *root, RelOptInfo *rel,
445478
return find_usable_indexes(root, rel,
446479
clauses, outer_clauses,
447480
istoplevel, outer_rel,
448-
SAOP_REQUIRE);
481+
SAOP_REQUIRE, ST_BITMAPSCAN);
449482
}
450483

451484

@@ -507,7 +540,8 @@ generate_bitmap_or_paths(PlannerInfo *root, RelOptInfo *rel,
507540
all_clauses,
508541
false,
509542
outer_rel,
510-
SAOP_ALLOW);
543+
SAOP_ALLOW,
544+
ST_BITMAPSCAN);
511545
/* Recurse in case there are sub-ORs */
512546
indlist = list_concat(indlist,
513547
generate_bitmap_or_paths(root, rel,
@@ -524,7 +558,8 @@ generate_bitmap_or_paths(PlannerInfo *root, RelOptInfo *rel,
524558
all_clauses,
525559
false,
526560
outer_rel,
527-
SAOP_ALLOW);
561+
SAOP_ALLOW,
562+
ST_BITMAPSCAN);
528563
}
529564

530565
/*
@@ -1641,6 +1676,7 @@ best_inner_indexscan(PlannerInfo *root, RelOptInfo *rel,
16411676
List *clause_list;
16421677
List *indexpaths;
16431678
List *bitindexpaths;
1679+
List *allindexpaths;
16441680
ListCell *l;
16451681
InnerIndexscanInfo *info;
16461682
MemoryContext oldcontext;
@@ -1736,18 +1772,36 @@ best_inner_indexscan(PlannerInfo *root, RelOptInfo *rel,
17361772
* Find all the index paths that are usable for this join, except for
17371773
* stuff involving OR and ScalarArrayOpExpr clauses.
17381774
*/
1739-
indexpaths = find_usable_indexes(root, rel,
1740-
clause_list, NIL,
1741-
false, outer_rel,
1742-
SAOP_FORBID);
1775+
allindexpaths = find_usable_indexes(root, rel,
1776+
clause_list, NIL,
1777+
false, outer_rel,
1778+
SAOP_FORBID,
1779+
ST_ANYSCAN);
1780+
1781+
/*
1782+
* Include the ones that are usable as plain indexscans in indexpaths, and
1783+
* include the ones that are usable as bitmap scans in bitindexpaths.
1784+
*/
1785+
indexpaths = bitindexpaths = NIL;
1786+
foreach(l, allindexpaths)
1787+
{
1788+
IndexPath *ipath = (IndexPath *) lfirst(l);
1789+
1790+
if (ipath->indexinfo->amhasgettuple)
1791+
indexpaths = lappend(indexpaths, ipath);
1792+
1793+
if (ipath->indexinfo->amhasgetbitmap)
1794+
bitindexpaths = lappend(bitindexpaths, ipath);
1795+
}
17431796

17441797
/*
17451798
* Generate BitmapOrPaths for any suitable OR-clauses present in the
17461799
* clause list.
17471800
*/
1748-
bitindexpaths = generate_bitmap_or_paths(root, rel,
1749-
clause_list, NIL,
1750-
outer_rel);
1801+
bitindexpaths = list_concat(bitindexpaths,
1802+
generate_bitmap_or_paths(root, rel,
1803+
clause_list, NIL,
1804+
outer_rel));
17511805

17521806
/*
17531807
* Likewise, generate paths using ScalarArrayOpExpr clauses; these can't
@@ -1758,11 +1812,6 @@ best_inner_indexscan(PlannerInfo *root, RelOptInfo *rel,
17581812
clause_list, NIL,
17591813
false, outer_rel));
17601814

1761-
/*
1762-
* Include the regular index paths in bitindexpaths.
1763-
*/
1764-
bitindexpaths = list_concat(bitindexpaths, list_copy(indexpaths));
1765-
17661815
/*
17671816
* If we found anything usable, generate a BitmapHeapPath for the most
17681817
* promising combination of bitmap index paths.

src/backend/optimizer/util/plancat.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.155 2009/02/15 20:16:21 tgl Exp $
12+
* $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.156 2009/03/05 23:06:45 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -214,6 +214,8 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
214214
info->amcostestimate = indexRelation->rd_am->amcostestimate;
215215
info->amoptionalkey = indexRelation->rd_am->amoptionalkey;
216216
info->amsearchnulls = indexRelation->rd_am->amsearchnulls;
217+
info->amhasgettuple = OidIsValid(indexRelation->rd_am->amgettuple);
218+
info->amhasgetbitmap = OidIsValid(indexRelation->rd_am->amgetbitmap);
217219

218220
/*
219221
* Fetch the ordering operators associated with the index, if any.

src/include/catalog/pg_am.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
99
* Portions Copyright (c) 1994, Regents of the University of California
1010
*
11-
* $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.60 2009/01/01 17:23:56 momjian Exp $
11+
* $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.61 2009/03/05 23:06:45 tgl Exp $
1212
*
1313
* NOTES
1414
* the genbki.sh script reads this file and generates .bki
@@ -52,8 +52,8 @@ CATALOG(pg_am,2601)
5252
Oid amkeytype; /* type of data in index, or InvalidOid */
5353
regproc aminsert; /* "insert this tuple" function */
5454
regproc ambeginscan; /* "start new scan" function */
55-
regproc amgettuple; /* "next valid tuple" function */
56-
regproc amgetbitmap; /* "fetch all valid tuples" function */
55+
regproc amgettuple; /* "next valid tuple" function, or 0 */
56+
regproc amgetbitmap; /* "fetch all valid tuples" function, or 0 */
5757
regproc amrescan; /* "restart this scan" function */
5858
regproc amendscan; /* "end this scan" function */
5959
regproc ammarkpos; /* "mark current scan position" function */

src/include/nodes/relation.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.169 2009/02/25 03:30:37 tgl Exp $
10+
* $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.170 2009/03/05 23:06:45 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -441,6 +441,8 @@ typedef struct IndexOptInfo
441441
bool unique; /* true if a unique index */
442442
bool amoptionalkey; /* can query omit key for the first column? */
443443
bool amsearchnulls; /* can AM search for NULL index entries? */
444+
bool amhasgettuple; /* does AM have amgettuple interface? */
445+
bool amhasgetbitmap; /* does AM have amgetbitmap interface? */
444446
} IndexOptInfo;
445447

446448

0 commit comments

Comments
 (0)