diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 2a8f978f85c..0ab11dda6d2 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -1,4 +1,4 @@
-
+
@@ -493,14 +493,14 @@
amgettupleregprocpg_proc.oid
- Next valid tuple function
+ Next valid tuple function, or zero if noneamgetbitmapregprocpg_proc.oid
- Fetch all valid tuples function
+ Fetch all valid tuples function, or zero if none
diff --git a/doc/src/sgml/indexam.sgml b/doc/src/sgml/indexam.sgml
index db16c1d4ee5..3643d706735 100644
--- a/doc/src/sgml/indexam.sgml
+++ b/doc/src/sgml/indexam.sgml
@@ -1,4 +1,4 @@
-
+
Index Access Method Interface Definition
@@ -37,8 +37,10 @@
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.
@@ -266,7 +268,7 @@ amoptions (ArrayType *reloptions,
The function should construct a bytea> value, which will be copied
into the rd_options> field of the index's relcache entry.
The data contents of the 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
StdRdOptions>.
When validate> is true, the function should report a suitable
error message if any of the options are unrecognized or have invalid
@@ -283,8 +285,9 @@ amoptions (ArrayType *reloptions,
an indexable WHERE> condition, often called a
qualifier> or scan key>. The semantics of
index scanning are described more fully in ,
- below. The scan-related functions that an index access method must provide
- are:
+ below. An index access method can support plain> index scans,
+ bitmap> index scans, or both. The scan-related functions that an
+ index access method must or may provide are:
@@ -326,6 +329,13 @@ amgettuple (IndexScanDesc scan,
callers.
+
+ The amgettuple> function need only be provided if the access
+ method supports plain> index scans. If it doesn't, the
+ amgettuple> field in its pg_am> row must
+ be set to zero.
+
+
int64
@@ -349,6 +359,13 @@ amgetbitmap (IndexScanDesc scan,
in .
+
+ The amgetbitmap> function need only be provided if the access
+ method supports bitmap> index scans. If it doesn't, the
+ amgetbitmap> field in its pg_am> row must
+ be set to zero.
+
+
void
@@ -519,6 +536,12 @@ amrestrpos (IndexScanDesc scan);
spelled out in .
+
+ Note that it is permitted for an access method to implement only
+ amgetbitmap> and not amgettuple>, or vice versa,
+ if its internal implementation is unsuited to one API or the other.
+
+
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 6f27a191828..e99583ab99c 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -9,7 +9,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@@ -45,6 +45,14 @@
((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
{
@@ -58,7 +66,7 @@ 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);
@@ -168,12 +176,16 @@ create_index_paths(PlannerInfo *root, RelOptInfo *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;
@@ -181,9 +193,11 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel)
{
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);
}
@@ -254,6 +268,7 @@ create_index_paths(PlannerInfo *root, RelOptInfo *rel)
* '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.
*----------
@@ -262,7 +277,7 @@ 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)
{
Relids outer_relids = outer_rel ? outer_rel->relids : NULL;
bool possibly_useful_pathkeys = has_useful_pathkeys(root, rel);
@@ -281,6 +296,24 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *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
@@ -445,7 +478,7 @@ find_saop_paths(PlannerInfo *root, RelOptInfo *rel,
return find_usable_indexes(root, rel,
clauses, outer_clauses,
istoplevel, outer_rel,
- SAOP_REQUIRE);
+ SAOP_REQUIRE, ST_BITMAPSCAN);
}
@@ -507,7 +540,8 @@ generate_bitmap_or_paths(PlannerInfo *root, RelOptInfo *rel,
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,
@@ -524,7 +558,8 @@ generate_bitmap_or_paths(PlannerInfo *root, RelOptInfo *rel,
all_clauses,
false,
outer_rel,
- SAOP_ALLOW);
+ SAOP_ALLOW,
+ ST_BITMAPSCAN);
}
/*
@@ -1641,6 +1676,7 @@ best_inner_indexscan(PlannerInfo *root, RelOptInfo *rel,
List *clause_list;
List *indexpaths;
List *bitindexpaths;
+ List *allindexpaths;
ListCell *l;
InnerIndexscanInfo *info;
MemoryContext oldcontext;
@@ -1736,18 +1772,36 @@ best_inner_indexscan(PlannerInfo *root, RelOptInfo *rel,
* 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
@@ -1758,11 +1812,6 @@ best_inner_indexscan(PlannerInfo *root, RelOptInfo *rel,
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.
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index e880e668cba..6225bc14fff 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.155 2009/02/15 20:16:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.156 2009/03/05 23:06:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -214,6 +214,8 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
info->amcostestimate = indexRelation->rd_am->amcostestimate;
info->amoptionalkey = indexRelation->rd_am->amoptionalkey;
info->amsearchnulls = indexRelation->rd_am->amsearchnulls;
+ info->amhasgettuple = OidIsValid(indexRelation->rd_am->amgettuple);
+ info->amhasgetbitmap = OidIsValid(indexRelation->rd_am->amgetbitmap);
/*
* Fetch the ordering operators associated with the index, if any.
diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h
index e25eccbdcff..7736cb6e58a 100644
--- a/src/include/catalog/pg_am.h
+++ b/src/include/catalog/pg_am.h
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.60 2009/01/01 17:23:56 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.61 2009/03/05 23:06:45 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@@ -52,8 +52,8 @@ CATALOG(pg_am,2601)
Oid amkeytype; /* type of data in index, or InvalidOid */
regproc aminsert; /* "insert this tuple" function */
regproc ambeginscan; /* "start new scan" function */
- regproc amgettuple; /* "next valid tuple" function */
- regproc amgetbitmap; /* "fetch all valid tuples" function */
+ regproc amgettuple; /* "next valid tuple" function, or 0 */
+ regproc amgetbitmap; /* "fetch all valid tuples" function, or 0 */
regproc amrescan; /* "restart this scan" function */
regproc amendscan; /* "end this scan" function */
regproc ammarkpos; /* "mark current scan position" function */
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index e8e20d202b1..4f1bc4067d2 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.169 2009/02/25 03:30:37 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.170 2009/03/05 23:06:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -441,6 +441,8 @@ typedef struct IndexOptInfo
bool unique; /* true if a unique index */
bool amoptionalkey; /* can query omit key for the first column? */
bool amsearchnulls; /* can AM search for NULL index entries? */
+ bool amhasgettuple; /* does AM have amgettuple interface? */
+ bool amhasgetbitmap; /* does AM have amgetbitmap interface? */
} IndexOptInfo;