-<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.28 2008/10/17 22:10:29 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.29 2009/03/05 23:06:45 tgl Exp $ -->
<chapter id="indexam">
<title>Index Access Method Interface Definition</title>
extant versions of the same logical row; to an index, each tuple is
an independent object that needs its own index entry. Thus, an
update of a row always creates all-new index entries for the row, even if
- the key values did not change. Index entries for dead tuples are
- reclaimed (by vacuuming) when the dead tuples themselves are reclaimed.
+ the key values did not change. (HOT tuples are an exception to this
+ statement; but indexes do not deal with those, either.) Index entries for
+ dead tuples are reclaimed (by vacuuming) when the dead tuples themselves
+ are reclaimed.
</para>
<sect1 id="index-catalog">
The function should construct a <type>bytea</> value, which will be copied
into the <structfield>rd_options</> field of the index's relcache entry.
The data contents of the <type>bytea</> value are open for the access
- method to define, but the standard access methods currently all use struct
+ method to define; most of the standard access methods use struct
<structname>StdRdOptions</>.
When <parameter>validate</> is true, the function should report a suitable
error message if any of the options are unrecognized or have invalid
an indexable <literal>WHERE</> condition, often called a
<firstterm>qualifier</> or <firstterm>scan key</>. The semantics of
index scanning are described more fully in <xref linkend="index-scanning">,
- below. The scan-related functions that an index access method must provide
- are:
+ below. An index access method can support <quote>plain</> index scans,
+ <quote>bitmap</> index scans, or both. The scan-related functions that an
+ index access method must or may provide are:
</para>
<para>
callers.
</para>
+ <para>
+ The <function>amgettuple</> function need only be provided if the access
+ method supports <quote>plain</> index scans. If it doesn't, the
+ <structfield>amgettuple</> field in its <structname>pg_am</> row must
+ be set to zero.
+ </para>
+
<para>
<programlisting>
int64
in <xref linkend="index-scanning">.
</para>
+ <para>
+ The <function>amgetbitmap</> function need only be provided if the access
+ method supports <quote>bitmap</> index scans. If it doesn't, the
+ <structfield>amgetbitmap</> field in its <structname>pg_am</> row must
+ be set to zero.
+ </para>
+
<para>
<programlisting>
void
spelled out in <xref linkend="index-locking">.
</para>
+ <para>
+ Note that it is permitted for an access method to implement only
+ <function>amgetbitmap</> and not <function>amgettuple</>, or vice versa,
+ if its internal implementation is unsuited to one API or the other.
+ </para>
+
</sect1>
<sect1 id="index-locking">
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.236 2009/02/15 20:16:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.237 2009/03/05 23:06:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
((opfamily) == BOOL_BTREE_FAM_OID || (opfamily) == BOOL_HASH_FAM_OID)
+/* Whether we are looking for plain indexscan, bitmap scan, or either */
+typedef enum
+{
+ ST_INDEXSCAN, /* must support amgettuple */
+ ST_BITMAPSCAN, /* must support amgetbitmap */
+ ST_ANYSCAN /* either is okay */
+} ScanTypeControl;
+
/* Per-path data used within choose_bitmap_and() */
typedef struct
{
static List *find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
List *clauses, List *outer_clauses,
bool istoplevel, RelOptInfo *outer_rel,
- SaOpControl saop_control);
+ SaOpControl saop_control, ScanTypeControl scantype);
static List *find_saop_paths(PlannerInfo *root, RelOptInfo *rel,
List *clauses, List *outer_clauses,
bool istoplevel, RelOptInfo *outer_rel);
*/
indexpaths = find_usable_indexes(root, rel,
rel->baserestrictinfo, NIL,
- true, NULL, SAOP_FORBID);
+ true, NULL, SAOP_FORBID, ST_ANYSCAN);
/*
- * We can submit them all to add_path. (This generates access paths for
- * plain IndexScan plans.) However, for the next step we will only want
- * the ones that have some selectivity; we must discard anything that was
+ * Submit all the ones that can form plain IndexScan plans to add_path.
+ * (A plain IndexPath always represents a plain IndexScan plan; however
+ * some of the indexes might support only bitmap scans, and those we
+ * mustn't submit to add_path here.) Also, pick out the ones that might
+ * be useful as bitmap scans. For that, we must discard indexes that
+ * don't support bitmap scans, and we also are only interested in paths
+ * that have some selectivity; we should discard anything that was
* generated solely for ordering purposes.
*/
bitindexpaths = NIL;
{
IndexPath *ipath = (IndexPath *) lfirst(l);
- add_path(rel, (Path *) ipath);
+ if (ipath->indexinfo->amhasgettuple)
+ add_path(rel, (Path *) ipath);
- if (ipath->indexselectivity < 1.0 &&
+ if (ipath->indexinfo->amhasgetbitmap &&
+ ipath->indexselectivity < 1.0 &&
!ScanDirectionIsBackward(ipath->indexscandir))
bitindexpaths = lappend(bitindexpaths, ipath);
}
* 'outer_rel' is the outer side of the join if forming an inner indexscan
* (so some of the given clauses are join clauses); NULL if not
* 'saop_control' indicates whether ScalarArrayOpExpr clauses can be used
+ * 'scantype' indicates whether we need plain or bitmap scan support
*
* Note: check_partial_indexes() must have been run previously.
*----------
find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
List *clauses, List *outer_clauses,
bool istoplevel, RelOptInfo *outer_rel,
- SaOpControl saop_control)
+ SaOpControl saop_control, ScanTypeControl scantype)
{
Relids outer_relids = outer_rel ? outer_rel->relids : NULL;
bool possibly_useful_pathkeys = has_useful_pathkeys(root, rel);
bool found_clause;
bool index_is_ordered;
+ /*
+ * Check that index supports the desired scan type(s)
+ */
+ switch (scantype)
+ {
+ case ST_INDEXSCAN:
+ if (!index->amhasgettuple)
+ continue;
+ break;
+ case ST_BITMAPSCAN:
+ if (!index->amhasgetbitmap)
+ continue;
+ break;
+ case ST_ANYSCAN:
+ /* either or both are OK */
+ break;
+ }
+
/*
* Ignore partial indexes that do not match the query. If a partial
* index is marked predOK then we know it's OK; otherwise, if we are
return find_usable_indexes(root, rel,
clauses, outer_clauses,
istoplevel, outer_rel,
- SAOP_REQUIRE);
+ SAOP_REQUIRE, ST_BITMAPSCAN);
}
all_clauses,
false,
outer_rel,
- SAOP_ALLOW);
+ SAOP_ALLOW,
+ ST_BITMAPSCAN);
/* Recurse in case there are sub-ORs */
indlist = list_concat(indlist,
generate_bitmap_or_paths(root, rel,
all_clauses,
false,
outer_rel,
- SAOP_ALLOW);
+ SAOP_ALLOW,
+ ST_BITMAPSCAN);
}
/*
List *clause_list;
List *indexpaths;
List *bitindexpaths;
+ List *allindexpaths;
ListCell *l;
InnerIndexscanInfo *info;
MemoryContext oldcontext;
* Find all the index paths that are usable for this join, except for
* stuff involving OR and ScalarArrayOpExpr clauses.
*/
- indexpaths = find_usable_indexes(root, rel,
- clause_list, NIL,
- false, outer_rel,
- SAOP_FORBID);
+ allindexpaths = find_usable_indexes(root, rel,
+ clause_list, NIL,
+ false, outer_rel,
+ SAOP_FORBID,
+ ST_ANYSCAN);
+
+ /*
+ * Include the ones that are usable as plain indexscans in indexpaths, and
+ * include the ones that are usable as bitmap scans in bitindexpaths.
+ */
+ indexpaths = bitindexpaths = NIL;
+ foreach(l, allindexpaths)
+ {
+ IndexPath *ipath = (IndexPath *) lfirst(l);
+
+ if (ipath->indexinfo->amhasgettuple)
+ indexpaths = lappend(indexpaths, ipath);
+
+ if (ipath->indexinfo->amhasgetbitmap)
+ bitindexpaths = lappend(bitindexpaths, ipath);
+ }
/*
* Generate BitmapOrPaths for any suitable OR-clauses present in the
* clause list.
*/
- bitindexpaths = generate_bitmap_or_paths(root, rel,
- clause_list, NIL,
- outer_rel);
+ bitindexpaths = list_concat(bitindexpaths,
+ generate_bitmap_or_paths(root, rel,
+ clause_list, NIL,
+ outer_rel));
/*
* Likewise, generate paths using ScalarArrayOpExpr clauses; these can't
clause_list, NIL,
false, outer_rel));
- /*
- * Include the regular index paths in bitindexpaths.
- */
- bitindexpaths = list_concat(bitindexpaths, list_copy(indexpaths));
-
/*
* If we found anything usable, generate a BitmapHeapPath for the most
* promising combination of bitmap index paths.