Commit 4e82a954 authored by Tom Lane's avatar Tom Lane

Replace "amgetmulti" AM functions with "amgetbitmap", in which the whole

indexscan always occurs in one call, and the results are returned in a
TIDBitmap instead of a limited-size array of TIDs.  This should improve
speed a little by reducing AM entry/exit overhead, and it is necessary
infrastructure if we are ever to support bitmap indexes.

In an only slightly related change, add support for TIDBitmaps to preserve
(somewhat lossily) the knowledge that particular TIDs reported by an index
need to have their quals rechecked when the heap is visited.  This facility
is not really used yet; we'll need to extend the forced-recheck feature to
plain indexscans before it's useful, and that hasn't been coded yet.
The intent is to use it to clean up 8.3's horrid @@@ kluge for text search
with weighted queries.  There might be other uses in future, but that one
alone is sufficient reason.

Heikki Linnakangas, with some adjustments by me.
parent f260edb1
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.163 2008/03/10 12:55:13 mha Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.164 2008/04/10 22:25:25 tgl Exp $ -->
<!-- <!--
Documentation of the system catalogs, directed toward PostgreSQL developers Documentation of the system catalogs, directed toward PostgreSQL developers
--> -->
...@@ -473,10 +473,10 @@ ...@@ -473,10 +473,10 @@
</row> </row>
<row> <row>
<entry><structfield>amgetmulti</structfield></entry> <entry><structfield>amgetbitmap</structfield></entry>
<entry><type>regproc</type></entry> <entry><type>regproc</type></entry>
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry> <entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
<entry><quote>Fetch multiple tuples</quote> function</entry> <entry><quote>Fetch all valid tuples</quote> function</entry>
</row> </row>
<row> <row>
......
<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.23 2007/04/06 22:33:41 tgl Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.24 2008/04/10 22:25:25 tgl Exp $ -->
<chapter id="indexam"> <chapter id="indexam">
<title>Index Access Method Interface Definition</title> <title>Index Access Method Interface Definition</title>
...@@ -320,23 +320,16 @@ amgettuple (IndexScanDesc scan, ...@@ -320,23 +320,16 @@ amgettuple (IndexScanDesc scan,
<para> <para>
<programlisting> <programlisting>
boolean int64
amgetmulti (IndexScanDesc scan, amgetbitmap (IndexScanDesc scan,
ItemPointer tids, TIDBitmap *tbm);
int32 max_tids,
int32 *returned_tids);
</programlisting> </programlisting>
Fetch multiple tuples in the given scan. Returns TRUE if the scan should Fetch all tuples in the given scan and add them to the caller-supplied
continue, FALSE if no matching tuples remain. <literal>tids</> points to TIDBitmap (that is, OR the set of tuple IDs into whatever set is already
a caller-supplied array of <literal>max_tids</> in the bitmap). The number of tuples fetched is returned.
<structname>ItemPointerData</> records, which the call fills with TIDs of <function>amgetbitmap</> and
matching tuples. <literal>*returned_tids</> is set to the number of TIDs
actually returned. This can be less than <literal>max_tids</>, or even
zero, even when the return value is TRUE. (This provision allows the
access method to choose the most efficient stopping points in its scan,
for example index page boundaries.) <function>amgetmulti</> and
<function>amgettuple</> cannot be used in the same index scan; there <function>amgettuple</> cannot be used in the same index scan; there
are other restrictions too when using <function>amgetmulti</>, as explained are other restrictions too when using <function>amgetbitmap</>, as explained
in <xref linkend="index-scanning">. in <xref linkend="index-scanning">.
</para> </para>
...@@ -491,20 +484,17 @@ amrestrpos (IndexScanDesc scan); ...@@ -491,20 +484,17 @@ amrestrpos (IndexScanDesc scan);
<para> <para>
Instead of using <function>amgettuple</>, an index scan can be done with Instead of using <function>amgettuple</>, an index scan can be done with
<function>amgetmulti</> to fetch multiple tuples per call. This can be <function>amgetbitmap</> to fetch all tuples in one call. This can be
noticeably more efficient than <function>amgettuple</> because it allows noticeably more efficient than <function>amgettuple</> because it allows
avoiding lock/unlock cycles within the access method. In principle avoiding lock/unlock cycles within the access method. In principle
<function>amgetmulti</> should have the same effects as repeated <function>amgetbitmap</> should have the same effects as repeated
<function>amgettuple</> calls, but we impose several restrictions to <function>amgettuple</> calls, but we impose several restrictions to
simplify matters. In the first place, <function>amgetmulti</> does not simplify matters. First of all, <function>amgetbitmap</> returns all
take a <literal>direction</> argument, and therefore it does not support tuples at once and marking or restoring scan positions isn't
backwards scan nor intrascan reversal of direction. The access method supported. Secondly, the tuples are returned in a bitmap which doesn't
need not support marking or restoring scan positions during an have any specific ordering, which is why <function>amgetbitmap</> doesn't
<function>amgetmulti</> scan, either. (These restrictions cost little take a <literal>direction</> argument. Finally, <function>amgetbitmap</>
since it would be difficult to use these features in an does not guarantee any locking of the returned tuples, with implications
<function>amgetmulti</> scan anyway: adjusting the caller's buffered
list of TIDs would be complex.) Finally, <function>amgetmulti</> does
not guarantee any locking of the returned tuples, with implications
spelled out in <xref linkend="index-locking">. spelled out in <xref linkend="index-locking">.
</para> </para>
...@@ -605,9 +595,8 @@ amrestrpos (IndexScanDesc scan); ...@@ -605,9 +595,8 @@ amrestrpos (IndexScanDesc scan);
</para> </para>
<para> <para>
In an <function>amgetmulti</> index scan, the access method need not In an <function>amgetbitmap</> index scan, the access method does not
guarantee to keep an index pin on any of the returned tuples. (It would be keep an index pin on any of the returned tuples. Therefore
impractical to pin more than the last one anyway.) Therefore
it is only safe to use such scans with MVCC-compliant snapshots. it is only safe to use such scans with MVCC-compliant snapshots.
</para> </para>
......
...@@ -8,13 +8,15 @@ ...@@ -8,13 +8,15 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginget.c,v 1.10 2008/01/01 19:45:46 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/gin/ginget.c,v 1.11 2008/04/10 22:25:25 tgl Exp $
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
#include "access/gin.h" #include "access/gin.h"
#include "catalog/index.h" #include "catalog/index.h"
#include "miscadmin.h"
#include "utils/memutils.h" #include "utils/memutils.h"
static bool static bool
...@@ -476,34 +478,37 @@ scanGetItem(IndexScanDesc scan, ItemPointerData *item) ...@@ -476,34 +478,37 @@ scanGetItem(IndexScanDesc scan, ItemPointerData *item)
#define GinIsVoidRes(s) ( ((GinScanOpaque) scan->opaque)->isVoidRes == true ) #define GinIsVoidRes(s) ( ((GinScanOpaque) scan->opaque)->isVoidRes == true )
Datum Datum
gingetmulti(PG_FUNCTION_ARGS) gingetbitmap(PG_FUNCTION_ARGS)
{ {
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
ItemPointer tids = (ItemPointer) PG_GETARG_POINTER(1); TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1);
int32 max_tids = PG_GETARG_INT32(2); int64 ntids;
int32 *returned_tids = (int32 *) PG_GETARG_POINTER(3);
if (GinIsNewKey(scan)) if (GinIsNewKey(scan))
newScanKey(scan); newScanKey(scan);
*returned_tids = 0;
if (GinIsVoidRes(scan)) if (GinIsVoidRes(scan))
PG_RETURN_BOOL(false); PG_RETURN_INT64(0);
startScan(scan); startScan(scan);
do ntids = 0;
for (;;)
{ {
if (scanGetItem(scan, tids + *returned_tids)) ItemPointerData iptr;
(*returned_tids)++;
else CHECK_FOR_INTERRUPTS();
if (!scanGetItem(scan, &iptr))
break; break;
} while (*returned_tids < max_tids);
tbm_add_tuples(tbm, &iptr, 1, false);
ntids++;
}
stopScan(scan); stopScan(scan);
PG_RETURN_BOOL(*returned_tids == max_tids); PG_RETURN_INT64(ntids);
} }
Datum Datum
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gistget.c,v 1.69 2008/01/01 19:45:46 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/gist/gistget.c,v 1.70 2008/04/10 22:25:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -16,13 +16,16 @@ ...@@ -16,13 +16,16 @@
#include "access/gist_private.h" #include "access/gist_private.h"
#include "executor/execdebug.h" #include "executor/execdebug.h"
#include "miscadmin.h"
#include "pgstat.h" #include "pgstat.h"
#include "utils/memutils.h" #include "utils/memutils.h"
static OffsetNumber gistfindnext(IndexScanDesc scan, OffsetNumber n, static OffsetNumber gistfindnext(IndexScanDesc scan, OffsetNumber n,
ScanDirection dir); ScanDirection dir);
static int gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids, int maxtids, bool ignore_killed_tuples); static int64 gistnext(IndexScanDesc scan, ScanDirection dir,
ItemPointer tid, TIDBitmap *tbm,
bool ignore_killed_tuples);
static bool gistindex_keytest(IndexTuple tuple, IndexScanDesc scan, static bool gistindex_keytest(IndexTuple tuple, IndexScanDesc scan,
OffsetNumber offset); OffsetNumber offset);
...@@ -114,32 +117,37 @@ gistgettuple(PG_FUNCTION_ARGS) ...@@ -114,32 +117,37 @@ gistgettuple(PG_FUNCTION_ARGS)
* tuples, continue looping until we find a non-killed tuple that matches * tuples, continue looping until we find a non-killed tuple that matches
* the search key. * the search key.
*/ */
res = (gistnext(scan, dir, &tid, 1, scan->ignore_killed_tuples)) ? true : false; res = (gistnext(scan, dir, &tid, NULL, scan->ignore_killed_tuples) > 0) ? true : false;
PG_RETURN_BOOL(res); PG_RETURN_BOOL(res);
} }
Datum Datum
gistgetmulti(PG_FUNCTION_ARGS) gistgetbitmap(PG_FUNCTION_ARGS)
{ {
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
ItemPointer tids = (ItemPointer) PG_GETARG_POINTER(1); TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1);
int32 max_tids = PG_GETARG_INT32(2); int64 ntids;
int32 *returned_tids = (int32 *) PG_GETARG_POINTER(3);
*returned_tids = gistnext(scan, ForwardScanDirection, tids, max_tids, false); ntids = gistnext(scan, ForwardScanDirection, NULL, tbm, false);
PG_RETURN_BOOL(*returned_tids == max_tids); PG_RETURN_INT64(ntids);
} }
/* /*
* Fetch a tuples that matchs the search key; this can be invoked * Fetch tuple(s) that match the search key; this can be invoked
* either to fetch the first such tuple or subsequent matching * either to fetch the first such tuple or subsequent matching tuples.
* tuples. Returns true iff a matching tuple was found. *
* This function is used by both gistgettuple and gistgetbitmap. When
* invoked from gistgettuple, tbm is null and the next matching tuple
* is returned in *tid. When invoked from getbitmap, tid is null and
* all matching tuples are added to tbm. In both cases, the function
* result is the number of returned tuples.
*/ */
static int static int64
gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids, gistnext(IndexScanDesc scan, ScanDirection dir,
int maxtids, bool ignore_killed_tuples) ItemPointer tid, TIDBitmap *tbm,
bool ignore_killed_tuples)
{ {
Page p; Page p;
OffsetNumber n; OffsetNumber n;
...@@ -148,7 +156,7 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids, ...@@ -148,7 +156,7 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids,
IndexTuple it; IndexTuple it;
GISTPageOpaque opaque; GISTPageOpaque opaque;
bool resetoffset = false; bool resetoffset = false;
int ntids = 0; int64 ntids = 0;
so = (GISTScanOpaque) scan->opaque; so = (GISTScanOpaque) scan->opaque;
...@@ -174,6 +182,8 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids, ...@@ -174,6 +182,8 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids,
for (;;) for (;;)
{ {
CHECK_FOR_INTERRUPTS();
/* First of all, we need lock buffer */ /* First of all, we need lock buffer */
Assert(so->curbuf != InvalidBuffer); Assert(so->curbuf != InvalidBuffer);
LockBuffer(so->curbuf, GIST_SHARE); LockBuffer(so->curbuf, GIST_SHARE);
...@@ -285,20 +295,21 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids, ...@@ -285,20 +295,21 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids,
* return success. Note that we keep "curbuf" pinned so that * return success. Note that we keep "curbuf" pinned so that
* we can efficiently resume the index scan later. * we can efficiently resume the index scan later.
*/ */
ItemPointerSet(&(so->curpos), ItemPointerSet(&(so->curpos),
BufferGetBlockNumber(so->curbuf), n); BufferGetBlockNumber(so->curbuf), n);
if (!(ignore_killed_tuples && ItemIdIsDead(PageGetItemId(p, n)))) if (!(ignore_killed_tuples && ItemIdIsDead(PageGetItemId(p, n))))
{ {
it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n)); it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
tids[ntids] = scan->xs_ctup.t_self = it->t_tid;
ntids++; ntids++;
if (tbm != NULL)
if (ntids == maxtids) tbm_add_tuples(tbm, &it->t_tid, 1, false);
else
{ {
*tid = scan->xs_ctup.t_self = it->t_tid;
LockBuffer(so->curbuf, GIST_UNLOCK); LockBuffer(so->curbuf, GIST_UNLOCK);
return ntids; return ntids; /* always 1 */
} }
} }
} }
...@@ -308,7 +319,6 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids, ...@@ -308,7 +319,6 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids,
* We've found an entry in an internal node whose key is * We've found an entry in an internal node whose key is
* consistent with the search key, so push it to stack * consistent with the search key, so push it to stack
*/ */
stk = (GISTSearchStack *) palloc(sizeof(GISTSearchStack)); stk = (GISTSearchStack *) palloc(sizeof(GISTSearchStack));
it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n)); it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
...@@ -318,7 +328,6 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids, ...@@ -318,7 +328,6 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids,
stk->next = so->stack->next; stk->next = so->stack->next;
so->stack->next = stk; so->stack->next = stk;
} }
if (ScanDirectionIsBackward(dir)) if (ScanDirectionIsBackward(dir))
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/hash/hash.c,v 1.100 2008/03/16 23:15:08 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/hash/hash.c,v 1.101 2008/04/10 22:25:25 tgl Exp $
* *
* NOTES * NOTES
* This file contains only the public interface routines. * This file contains only the public interface routines.
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "access/hash.h" #include "access/hash.h"
#include "catalog/index.h" #include "catalog/index.h"
#include "commands/vacuum.h" #include "commands/vacuum.h"
#include "miscadmin.h"
#include "optimizer/cost.h" #include "optimizer/cost.h"
#include "optimizer/plancat.h" #include "optimizer/plancat.h"
...@@ -275,72 +276,51 @@ hashgettuple(PG_FUNCTION_ARGS) ...@@ -275,72 +276,51 @@ hashgettuple(PG_FUNCTION_ARGS)
/* /*
* hashgetmulti() -- get multiple tuples at once * hashgetbitmap() -- get all tuples at once
*
* This is a somewhat generic implementation: it avoids lock reacquisition
* overhead, but there's no smarts about picking especially good stopping
* points such as index page boundaries.
*/ */
Datum Datum
hashgetmulti(PG_FUNCTION_ARGS) hashgetbitmap(PG_FUNCTION_ARGS)
{ {
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
ItemPointer tids = (ItemPointer) PG_GETARG_POINTER(1); TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1);
int32 max_tids = PG_GETARG_INT32(2);
int32 *returned_tids = (int32 *) PG_GETARG_POINTER(3);
HashScanOpaque so = (HashScanOpaque) scan->opaque; HashScanOpaque so = (HashScanOpaque) scan->opaque;
Relation rel = scan->indexRelation; bool res;
bool res = true; int64 ntids = 0;
int32 ntids = 0;
/* res = _hash_first(scan, ForwardScanDirection);
* We hold pin but not lock on current buffer while outside the hash AM.
* Reacquire the read lock here.
*/
if (BufferIsValid(so->hashso_curbuf))
_hash_chgbufaccess(rel, so->hashso_curbuf, HASH_NOLOCK, HASH_READ);
while (ntids < max_tids) while (res)
{ {
/* bool add_tuple;
* Start scan, or advance to next tuple.
*/ CHECK_FOR_INTERRUPTS();
if (ItemPointerIsValid(&(so->hashso_curpos)))
res = _hash_next(scan, ForwardScanDirection);
else
res = _hash_first(scan, ForwardScanDirection);
/* /*
* Skip killed tuples if asked to. * Skip killed tuples if asked to.
*/ */
if (scan->ignore_killed_tuples) if (scan->ignore_killed_tuples)
{
while (res)
{ {
Page page; Page page;
OffsetNumber offnum; OffsetNumber offnum;
offnum = ItemPointerGetOffsetNumber(&(so->hashso_curpos)); offnum = ItemPointerGetOffsetNumber(&(so->hashso_curpos));
page = BufferGetPage(so->hashso_curbuf); page = BufferGetPage(so->hashso_curbuf);
if (!ItemIdIsDead(PageGetItemId(page, offnum))) add_tuple = !ItemIdIsDead(PageGetItemId(page, offnum));
break;
res = _hash_next(scan, ForwardScanDirection);
}
} }
else
add_tuple = true;
if (!res)
break;
/* Save tuple ID, and continue scanning */ /* Save tuple ID, and continue scanning */
tids[ntids] = scan->xs_ctup.t_self; if (add_tuple)
{
tbm_add_tuples(tbm, &scan->xs_ctup.t_self, 1, false);
ntids++; ntids++;
} }
/* Release read lock on current buffer, but keep it pinned */ res = _hash_next(scan, ForwardScanDirection);
if (BufferIsValid(so->hashso_curbuf)) }
_hash_chgbufaccess(rel, so->hashso_curbuf, HASH_READ, HASH_NOLOCK);
*returned_tids = ntids; PG_RETURN_INT64(ntids);
PG_RETURN_BOOL(res);
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.65 2008/03/26 21:10:37 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.66 2008/04/10 22:25:25 tgl Exp $
* *
* NOTES * NOTES
* many of the old access method routines have been turned into * many of the old access method routines have been turned into
...@@ -88,7 +88,6 @@ RelationGetIndexScan(Relation indexRelation, ...@@ -88,7 +88,6 @@ RelationGetIndexScan(Relation indexRelation,
else else
scan->keyData = NULL; scan->keyData = NULL;
scan->is_multiscan = false; /* caller may change this */
scan->kill_prior_tuple = false; scan->kill_prior_tuple = false;
scan->ignore_killed_tuples = true; /* default setting */ scan->ignore_killed_tuples = true; /* default setting */
......
...@@ -8,20 +8,20 @@ ...@@ -8,20 +8,20 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.104 2008/03/26 21:10:37 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.105 2008/04/10 22:25:25 tgl Exp $
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
* index_open - open an index relation by relation OID * index_open - open an index relation by relation OID
* index_close - close an index relation * index_close - close an index relation
* index_beginscan - start a scan of an index with amgettuple * index_beginscan - start a scan of an index with amgettuple
* index_beginscan_multi - start a scan of an index with amgetmulti * index_beginscan_bitmap - start a scan of an index with amgetbitmap
* index_rescan - restart a scan of an index * index_rescan - restart a scan of an index
* index_endscan - end a scan * index_endscan - end a scan
* index_insert - insert an index tuple into a relation * index_insert - insert an index tuple into a relation
* index_markpos - mark a scan position * index_markpos - mark a scan position
* index_restrpos - restore a scan position * index_restrpos - restore a scan position
* index_getnext - get the next tuple from a scan * index_getnext - get the next tuple from a scan
* index_getmulti - get multiple tuples from a scan * index_getbitmap - get all tuples from a scan
* index_bulk_delete - bulk deletion of index tuples * index_bulk_delete - bulk deletion of index tuples
* index_vacuum_cleanup - post-deletion cleanup of an index * index_vacuum_cleanup - post-deletion cleanup of an index
* index_getprocid - get a support procedure OID * index_getprocid - get a support procedure OID
...@@ -227,7 +227,6 @@ index_beginscan(Relation heapRelation, ...@@ -227,7 +227,6 @@ index_beginscan(Relation heapRelation,
* Save additional parameters into the scandesc. Everything else was set * Save additional parameters into the scandesc. Everything else was set
* up by RelationGetIndexScan. * up by RelationGetIndexScan.
*/ */
scan->is_multiscan = false;
scan->heapRelation = heapRelation; scan->heapRelation = heapRelation;
scan->xs_snapshot = snapshot; scan->xs_snapshot = snapshot;
...@@ -235,13 +234,13 @@ index_beginscan(Relation heapRelation, ...@@ -235,13 +234,13 @@ index_beginscan(Relation heapRelation,
} }
/* /*
* index_beginscan_multi - start a scan of an index with amgetmulti * index_beginscan_bitmap - start a scan of an index with amgetbitmap
* *
* As above, caller had better be holding some lock on the parent heap * As above, caller had better be holding some lock on the parent heap
* relation, even though it's not explicitly mentioned here. * relation, even though it's not explicitly mentioned here.
*/ */
IndexScanDesc IndexScanDesc
index_beginscan_multi(Relation indexRelation, index_beginscan_bitmap(Relation indexRelation,
Snapshot snapshot, Snapshot snapshot,
int nkeys, ScanKey key) int nkeys, ScanKey key)
{ {
...@@ -253,7 +252,6 @@ index_beginscan_multi(Relation indexRelation, ...@@ -253,7 +252,6 @@ index_beginscan_multi(Relation indexRelation,
* Save additional parameters into the scandesc. Everything else was set * Save additional parameters into the scandesc. Everything else was set
* up by RelationGetIndexScan. * up by RelationGetIndexScan.
*/ */
scan->is_multiscan = true;
scan->xs_snapshot = snapshot; scan->xs_snapshot = snapshot;
return scan; return scan;
...@@ -676,44 +674,39 @@ index_getnext_indexitem(IndexScanDesc scan, ...@@ -676,44 +674,39 @@ index_getnext_indexitem(IndexScanDesc scan,
} }
/* ---------------- /* ----------------
* index_getmulti - get multiple tuples from an index scan * index_getbitmap - get all tuples at once from an index scan
* *
* Collects the TIDs of multiple heap tuples satisfying the scan keys. * Adds the TIDs of all heap tuples satisfying the scan keys to a bitmap.
* Since there's no interlock between the index scan and the eventual heap * Since there's no interlock between the index scan and the eventual heap
* access, this is only safe to use with MVCC-based snapshots: the heap * access, this is only safe to use with MVCC-based snapshots: the heap
* item slot could have been replaced by a newer tuple by the time we get * item slot could have been replaced by a newer tuple by the time we get
* to it. * to it.
* *
* A TRUE result indicates more calls should occur; a FALSE result says the * Returns the number of matching tuples found.
* scan is done. *returned_tids could be zero or nonzero in either case.
* ---------------- * ----------------
*/ */
bool int64
index_getmulti(IndexScanDesc scan, index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap)
ItemPointer tids, int32 max_tids,
int32 *returned_tids)
{ {
FmgrInfo *procedure; FmgrInfo *procedure;
bool found; int64 ntids;
SCAN_CHECKS; SCAN_CHECKS;
GET_SCAN_PROCEDURE(amgetmulti); GET_SCAN_PROCEDURE(amgetbitmap);
/* just make sure this is false... */ /* just make sure this is false... */
scan->kill_prior_tuple = false; scan->kill_prior_tuple = false;
/* /*
* have the am's getmulti proc do all the work. * have the am's getbitmap proc do all the work.
*/ */
found = DatumGetBool(FunctionCall4(procedure, ntids = DatumGetInt64(FunctionCall2(procedure,
PointerGetDatum(scan), PointerGetDatum(scan),
PointerGetDatum(tids), PointerGetDatum(bitmap)));
Int32GetDatum(max_tids),
PointerGetDatum(returned_tids)));
pgstat_count_index_tuples(scan->indexRelation, *returned_tids); pgstat_count_index_tuples(scan->indexRelation, ntids);
return found; return ntids;
} }
/* ---------------- /* ----------------
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.156 2008/01/01 19:45:46 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.157 2008/04/10 22:25:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "access/nbtree.h" #include "access/nbtree.h"
#include "catalog/index.h" #include "catalog/index.h"
#include "commands/vacuum.h" #include "commands/vacuum.h"
#include "miscadmin.h"
#include "storage/freespace.h" #include "storage/freespace.h"
#include "storage/lmgr.h" #include "storage/lmgr.h"
#include "utils/memutils.h" #include "utils/memutils.h"
...@@ -278,42 +279,29 @@ btgettuple(PG_FUNCTION_ARGS) ...@@ -278,42 +279,29 @@ btgettuple(PG_FUNCTION_ARGS)
} }
/* /*
* btgetmulti() -- get multiple tuples at once * btgetbitmap() -- gets all matching tuples, and adds them to a bitmap
*
* In the current implementation there seems no strong reason to stop at
* index page boundaries; we just press on until we fill the caller's buffer
* or run out of matches.
*/ */
Datum Datum
btgetmulti(PG_FUNCTION_ARGS) btgetbitmap(PG_FUNCTION_ARGS)
{ {
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
ItemPointer tids = (ItemPointer) PG_GETARG_POINTER(1); TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1);
int32 max_tids = PG_GETARG_INT32(2);
int32 *returned_tids = (int32 *) PG_GETARG_POINTER(3);
BTScanOpaque so = (BTScanOpaque) scan->opaque; BTScanOpaque so = (BTScanOpaque) scan->opaque;
bool res = true; int64 ntids = 0;
int32 ntids = 0; ItemPointer heapTid;
if (max_tids <= 0) /* behave correctly in boundary case */
PG_RETURN_BOOL(true);
/* If we haven't started the scan yet, fetch the first page & tuple. */ /* Fetch the first page & tuple. */
if (!BTScanPosIsValid(so->currPos)) if (!_bt_first(scan, ForwardScanDirection))
{
res = _bt_first(scan, ForwardScanDirection);
if (!res)
{ {
/* empty scan */ /* empty scan */
*returned_tids = ntids; PG_RETURN_INT64(0);
PG_RETURN_BOOL(res);
} }
/* Save tuple ID, and continue scanning */ /* Save tuple ID, and continue scanning */
tids[ntids] = scan->xs_ctup.t_self; heapTid = &scan->xs_ctup.t_self;
tbm_add_tuples(tbm, heapTid, 1, false);
ntids++; ntids++;
}
while (ntids < max_tids) for (;;)
{ {
/* /*
* Advance to next tuple within page. This is the same as the easy * Advance to next tuple within page. This is the same as the easy
...@@ -321,19 +309,20 @@ btgetmulti(PG_FUNCTION_ARGS) ...@@ -321,19 +309,20 @@ btgetmulti(PG_FUNCTION_ARGS)
*/ */
if (++so->currPos.itemIndex > so->currPos.lastItem) if (++so->currPos.itemIndex > so->currPos.lastItem)
{ {
CHECK_FOR_INTERRUPTS();
/* let _bt_next do the heavy lifting */ /* let _bt_next do the heavy lifting */
res = _bt_next(scan, ForwardScanDirection); if (!_bt_next(scan, ForwardScanDirection))
if (!res)
break; break;
} }
/* Save tuple ID, and continue scanning */ /* Save tuple ID, and continue scanning */
tids[ntids] = so->currPos.items[so->currPos.itemIndex].heapTid; heapTid = &so->currPos.items[so->currPos.itemIndex].heapTid;
tbm_add_tuples(tbm, heapTid, 1, false);
ntids++; ntids++;
} }
*returned_tids = ntids; PG_RETURN_INT64(ntids);
PG_RETURN_BOOL(res);
} }
/* /*
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeBitmapHeapscan.c,v 1.25 2008/03/26 21:10:38 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/executor/nodeBitmapHeapscan.c,v 1.26 2008/04/10 22:25:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -206,7 +206,7 @@ BitmapHeapNext(BitmapHeapScanState *node) ...@@ -206,7 +206,7 @@ BitmapHeapNext(BitmapHeapScanState *node)
* If we are using lossy info, we have to recheck the qual conditions * If we are using lossy info, we have to recheck the qual conditions
* at every tuple. * at every tuple.
*/ */
if (tbmres->ntuples < 0) if (tbmres->recheck)
{ {
econtext->ecxt_scantuple = slot; econtext->ecxt_scantuple = slot;
ResetExprContext(econtext); ResetExprContext(econtext);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeBitmapIndexscan.c,v 1.25 2008/01/01 19:45:49 momjian Exp $ * $PostgreSQL: pgsql/src/backend/executor/nodeBitmapIndexscan.c,v 1.26 2008/04/10 22:25:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -37,11 +37,8 @@ ...@@ -37,11 +37,8 @@
Node * Node *
MultiExecBitmapIndexScan(BitmapIndexScanState *node) MultiExecBitmapIndexScan(BitmapIndexScanState *node)
{ {
#define MAX_TIDS 1024
TIDBitmap *tbm; TIDBitmap *tbm;
IndexScanDesc scandesc; IndexScanDesc scandesc;
ItemPointerData tids[MAX_TIDS];
int32 ntids;
double nTuples = 0; double nTuples = 0;
bool doscan; bool doscan;
...@@ -91,24 +88,15 @@ MultiExecBitmapIndexScan(BitmapIndexScanState *node) ...@@ -91,24 +88,15 @@ MultiExecBitmapIndexScan(BitmapIndexScanState *node)
*/ */
while (doscan) while (doscan)
{ {
bool more = index_getmulti(scandesc, tids, MAX_TIDS, &ntids); nTuples += (double) index_getbitmap(scandesc, tbm);
if (ntids > 0)
{
tbm_add_tuples(tbm, tids, ntids);
nTuples += ntids;
}
CHECK_FOR_INTERRUPTS(); CHECK_FOR_INTERRUPTS();
if (!more)
{
doscan = ExecIndexAdvanceArrayKeys(node->biss_ArrayKeys, doscan = ExecIndexAdvanceArrayKeys(node->biss_ArrayKeys,
node->biss_NumArrayKeys); node->biss_NumArrayKeys);
if (doscan) /* reset index scan */ if (doscan) /* reset index scan */
index_rescan(node->biss_ScanDesc, node->biss_ScanKeys); index_rescan(node->biss_ScanDesc, node->biss_ScanKeys);
} }
}
/* must provide our own instrumentation support */ /* must provide our own instrumentation support */
if (node->ss.ps.instrument) if (node->ss.ps.instrument)
...@@ -321,7 +309,7 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags) ...@@ -321,7 +309,7 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags)
* Initialize scan descriptor. * Initialize scan descriptor.
*/ */
indexstate->biss_ScanDesc = indexstate->biss_ScanDesc =
index_beginscan_multi(indexstate->biss_RelationDesc, index_beginscan_bitmap(indexstate->biss_RelationDesc,
estate->es_snapshot, estate->es_snapshot,
indexstate->biss_NumScanKeys, indexstate->biss_NumScanKeys,
indexstate->biss_ScanKeys); indexstate->biss_ScanKeys);
......
...@@ -19,11 +19,20 @@ ...@@ -19,11 +19,20 @@
* of lossiness. In theory we could fall back to page ranges at some * of lossiness. In theory we could fall back to page ranges at some
* point, but for now that seems useless complexity. * point, but for now that seems useless complexity.
* *
* We also support the notion of candidate matches, or rechecking. This
* means we know that a search need visit only some tuples on a page,
* but we are not certain that all of those tuples are real matches.
* So the eventual heap scan must recheck the quals for these tuples only,
* rather than rechecking the quals for all tuples on the page as in the
* lossy-bitmap case. Rechecking can be specified when TIDs are inserted
* into a bitmap, and it can also happen internally when we AND a lossy
* and a non-lossy page.
*
* *
* Copyright (c) 2003-2008, PostgreSQL Global Development Group * Copyright (c) 2003-2008, PostgreSQL Global Development Group
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/tidbitmap.c,v 1.14 2008/01/01 19:45:50 momjian Exp $ * $PostgreSQL: pgsql/src/backend/nodes/tidbitmap.c,v 1.15 2008/04/10 22:25:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -81,11 +90,16 @@ ...@@ -81,11 +90,16 @@
* have exact storage for the first page of a chunk if we are using * have exact storage for the first page of a chunk if we are using
* lossy storage for any page in the chunk's range, since the same * lossy storage for any page in the chunk's range, since the same
* hashtable entry has to serve both purposes. * hashtable entry has to serve both purposes.
*
* recheck is used only on exact pages --- it indicates that although
* only the stated tuples need be checked, the full index qual condition
* must be checked for each (ie, these are candidate matches).
*/ */
typedef struct PagetableEntry typedef struct PagetableEntry
{ {
BlockNumber blockno; /* page number (hashtable key) */ BlockNumber blockno; /* page number (hashtable key) */
bool ischunk; /* T = lossy storage, F = exact */ bool ischunk; /* T = lossy storage, F = exact */
bool recheck; /* should the tuples be rechecked? */
bitmapword words[Max(WORDS_PER_PAGE, WORDS_PER_CHUNK)]; bitmapword words[Max(WORDS_PER_PAGE, WORDS_PER_CHUNK)];
} PagetableEntry; } PagetableEntry;
...@@ -244,9 +258,13 @@ tbm_free(TIDBitmap *tbm) ...@@ -244,9 +258,13 @@ tbm_free(TIDBitmap *tbm)
/* /*
* tbm_add_tuples - add some tuple IDs to a TIDBitmap * tbm_add_tuples - add some tuple IDs to a TIDBitmap
*
* If recheck is true, then the recheck flag will be set in the
* TBMIterateResult when any of these tuples are reported out.
*/ */
void void
tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids) tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids,
bool recheck)
{ {
int i; int i;
...@@ -280,6 +298,7 @@ tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids) ...@@ -280,6 +298,7 @@ tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids)
bitnum = BITNUM(off - 1); bitnum = BITNUM(off - 1);
} }
page->words[wordnum] |= ((bitmapword) 1 << bitnum); page->words[wordnum] |= ((bitmapword) 1 << bitnum);
page->recheck |= recheck;
if (tbm->nentries > tbm->maxentries) if (tbm->nentries > tbm->maxentries)
tbm_lossify(tbm); tbm_lossify(tbm);
...@@ -360,6 +379,7 @@ tbm_union_page(TIDBitmap *a, const PagetableEntry *bpage) ...@@ -360,6 +379,7 @@ tbm_union_page(TIDBitmap *a, const PagetableEntry *bpage)
/* Both pages are exact, merge at the bit level */ /* Both pages are exact, merge at the bit level */
for (wordnum = 0; wordnum < WORDS_PER_PAGE; wordnum++) for (wordnum = 0; wordnum < WORDS_PER_PAGE; wordnum++)
apage->words[wordnum] |= bpage->words[wordnum]; apage->words[wordnum] |= bpage->words[wordnum];
apage->recheck |= bpage->recheck;
} }
} }
...@@ -471,22 +491,12 @@ tbm_intersect_page(TIDBitmap *a, PagetableEntry *apage, const TIDBitmap *b) ...@@ -471,22 +491,12 @@ tbm_intersect_page(TIDBitmap *a, PagetableEntry *apage, const TIDBitmap *b)
else if (tbm_page_is_lossy(b, apage->blockno)) else if (tbm_page_is_lossy(b, apage->blockno))
{ {
/* /*
* When the page is lossy in b, we have to mark it lossy in a too. We * Some of the tuples in 'a' might not satisfy the quals for 'b',
* know that no bits need be set in bitmap a, but we do not know which * but because the page 'b' is lossy, we don't know which ones.
* ones should be cleared, and we have no API for "at most these * Therefore we mark 'a' as requiring rechecks, to indicate that
* tuples need be checked". (Perhaps it's worth adding that?) * at most those tuples set in 'a' are matches.
*/
tbm_mark_page_lossy(a, apage->blockno);
/*
* Note: tbm_mark_page_lossy will have removed apage from a, and may
* have inserted a new lossy chunk instead. We can continue the same
* seq_search scan at the caller level, because it does not matter
* whether we visit such a new chunk or not: it will have only the bit
* for apage->blockno set, which is correct.
*
* We must return false here since apage was already deleted.
*/ */
apage->recheck = true;
return false; return false;
} }
else else
...@@ -504,7 +514,9 @@ tbm_intersect_page(TIDBitmap *a, PagetableEntry *apage, const TIDBitmap *b) ...@@ -504,7 +514,9 @@ tbm_intersect_page(TIDBitmap *a, PagetableEntry *apage, const TIDBitmap *b)
if (apage->words[wordnum] != 0) if (apage->words[wordnum] != 0)
candelete = false; candelete = false;
} }
apage->recheck |= bpage->recheck;
} }
/* If there is no matching b page, we can just delete the a page */
return candelete; return candelete;
} }
} }
...@@ -585,7 +597,9 @@ tbm_begin_iterate(TIDBitmap *tbm) ...@@ -585,7 +597,9 @@ tbm_begin_iterate(TIDBitmap *tbm)
* order. If result->ntuples < 0, then the bitmap is "lossy" and failed to * order. If result->ntuples < 0, then the bitmap is "lossy" and failed to
* remember the exact tuples to look at on this page --- the caller must * remember the exact tuples to look at on this page --- the caller must
* examine all tuples on the page and check if they meet the intended * examine all tuples on the page and check if they meet the intended
* condition. * condition. If result->recheck is true, only the indicated tuples need
* be examined, but the condition must be rechecked anyway. (For ease of
* testing, recheck is always set true when ntuples < 0.)
*/ */
TBMIterateResult * TBMIterateResult *
tbm_iterate(TIDBitmap *tbm) tbm_iterate(TIDBitmap *tbm)
...@@ -638,6 +652,7 @@ tbm_iterate(TIDBitmap *tbm) ...@@ -638,6 +652,7 @@ tbm_iterate(TIDBitmap *tbm)
/* Return a lossy page indicator from the chunk */ /* Return a lossy page indicator from the chunk */
output->blockno = chunk_blockno; output->blockno = chunk_blockno;
output->ntuples = -1; output->ntuples = -1;
output->recheck = true;
tbm->schunkbit++; tbm->schunkbit++;
return output; return output;
} }
...@@ -676,6 +691,7 @@ tbm_iterate(TIDBitmap *tbm) ...@@ -676,6 +691,7 @@ tbm_iterate(TIDBitmap *tbm)
} }
output->blockno = page->blockno; output->blockno = page->blockno;
output->ntuples = ntuples; output->ntuples = ntuples;
output->recheck = page->recheck;
tbm->spageptr++; tbm->spageptr++;
return output; return output;
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/genam.h,v 1.69 2008/01/01 19:45:56 momjian Exp $ * $PostgreSQL: pgsql/src/include/access/genam.h,v 1.70 2008/04/10 22:25:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "access/relscan.h" #include "access/relscan.h"
#include "access/sdir.h" #include "access/sdir.h"
#include "nodes/primnodes.h" #include "nodes/primnodes.h"
#include "nodes/tidbitmap.h"
#include "storage/lock.h" #include "storage/lock.h"
/* /*
...@@ -99,7 +100,7 @@ extern IndexScanDesc index_beginscan(Relation heapRelation, ...@@ -99,7 +100,7 @@ extern IndexScanDesc index_beginscan(Relation heapRelation,
Relation indexRelation, Relation indexRelation,
Snapshot snapshot, Snapshot snapshot,
int nkeys, ScanKey key); int nkeys, ScanKey key);
extern IndexScanDesc index_beginscan_multi(Relation indexRelation, extern IndexScanDesc index_beginscan_bitmap(Relation indexRelation,
Snapshot snapshot, Snapshot snapshot,
int nkeys, ScanKey key); int nkeys, ScanKey key);
extern void index_rescan(IndexScanDesc scan, ScanKey key); extern void index_rescan(IndexScanDesc scan, ScanKey key);
...@@ -109,9 +110,7 @@ extern void index_restrpos(IndexScanDesc scan); ...@@ -109,9 +110,7 @@ extern void index_restrpos(IndexScanDesc scan);
extern HeapTuple index_getnext(IndexScanDesc scan, ScanDirection direction); extern HeapTuple index_getnext(IndexScanDesc scan, ScanDirection direction);
extern bool index_getnext_indexitem(IndexScanDesc scan, extern bool index_getnext_indexitem(IndexScanDesc scan,
ScanDirection direction); ScanDirection direction);
extern bool index_getmulti(IndexScanDesc scan, extern int64 index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap);
ItemPointer tids, int32 max_tids,
int32 *returned_tids);
extern IndexBulkDeleteResult *index_bulk_delete(IndexVacuumInfo *info, extern IndexBulkDeleteResult *index_bulk_delete(IndexVacuumInfo *info,
IndexBulkDeleteResult *stats, IndexBulkDeleteResult *stats,
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* *
* Copyright (c) 2006-2008, PostgreSQL Global Development Group * Copyright (c) 2006-2008, PostgreSQL Global Development Group
* *
* $PostgreSQL: pgsql/src/include/access/gin.h,v 1.16 2008/01/01 19:45:56 momjian Exp $ * $PostgreSQL: pgsql/src/include/access/gin.h,v 1.17 2008/04/10 22:25:25 tgl Exp $
*-------------------------------------------------------------------------- *--------------------------------------------------------------------------
*/ */
...@@ -422,7 +422,7 @@ extern PGDLLIMPORT int GinFuzzySearchLimit; ...@@ -422,7 +422,7 @@ extern PGDLLIMPORT int GinFuzzySearchLimit;
#define ItemPointerSetMin(p) ItemPointerSet( (p), (BlockNumber)0, (OffsetNumber)0) #define ItemPointerSetMin(p) ItemPointerSet( (p), (BlockNumber)0, (OffsetNumber)0)
#define ItemPointerIsMin(p) ( ItemPointerGetBlockNumber(p) == (BlockNumber)0 && ItemPointerGetOffsetNumber(p) == (OffsetNumber)0 ) #define ItemPointerIsMin(p) ( ItemPointerGetBlockNumber(p) == (BlockNumber)0 && ItemPointerGetOffsetNumber(p) == (OffsetNumber)0 )
extern Datum gingetmulti(PG_FUNCTION_ARGS); extern Datum gingetbitmap(PG_FUNCTION_ARGS);
extern Datum gingettuple(PG_FUNCTION_ARGS); extern Datum gingettuple(PG_FUNCTION_ARGS);
/* ginvacuum.c */ /* ginvacuum.c */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/gist_private.h,v 1.28 2008/01/01 19:45:56 momjian Exp $ * $PostgreSQL: pgsql/src/include/access/gist_private.h,v 1.29 2008/04/10 22:25:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -269,7 +269,7 @@ extern XLogRecPtr gistxlogInsertCompletion(RelFileNode node, ItemPointerData *ke ...@@ -269,7 +269,7 @@ extern XLogRecPtr gistxlogInsertCompletion(RelFileNode node, ItemPointerData *ke
/* gistget.c */ /* gistget.c */
extern Datum gistgettuple(PG_FUNCTION_ARGS); extern Datum gistgettuple(PG_FUNCTION_ARGS);
extern Datum gistgetmulti(PG_FUNCTION_ARGS); extern Datum gistgetbitmap(PG_FUNCTION_ARGS);
/* gistutil.c */ /* gistutil.c */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/hash.h,v 1.86 2008/03/16 23:15:08 tgl Exp $ * $PostgreSQL: pgsql/src/include/access/hash.h,v 1.87 2008/04/10 22:25:25 tgl Exp $
* *
* NOTES * NOTES
* modeled after Margo Seltzer's hash implementation for unix. * modeled after Margo Seltzer's hash implementation for unix.
...@@ -233,7 +233,7 @@ extern Datum hashbuild(PG_FUNCTION_ARGS); ...@@ -233,7 +233,7 @@ extern Datum hashbuild(PG_FUNCTION_ARGS);
extern Datum hashinsert(PG_FUNCTION_ARGS); extern Datum hashinsert(PG_FUNCTION_ARGS);
extern Datum hashbeginscan(PG_FUNCTION_ARGS); extern Datum hashbeginscan(PG_FUNCTION_ARGS);
extern Datum hashgettuple(PG_FUNCTION_ARGS); extern Datum hashgettuple(PG_FUNCTION_ARGS);
extern Datum hashgetmulti(PG_FUNCTION_ARGS); extern Datum hashgetbitmap(PG_FUNCTION_ARGS);
extern Datum hashrescan(PG_FUNCTION_ARGS); extern Datum hashrescan(PG_FUNCTION_ARGS);
extern Datum hashendscan(PG_FUNCTION_ARGS); extern Datum hashendscan(PG_FUNCTION_ARGS);
extern Datum hashmarkpos(PG_FUNCTION_ARGS); extern Datum hashmarkpos(PG_FUNCTION_ARGS);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/nbtree.h,v 1.116 2008/01/01 19:45:56 momjian Exp $ * $PostgreSQL: pgsql/src/include/access/nbtree.h,v 1.117 2008/04/10 22:25:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -507,7 +507,7 @@ extern Datum btbuild(PG_FUNCTION_ARGS); ...@@ -507,7 +507,7 @@ extern Datum btbuild(PG_FUNCTION_ARGS);
extern Datum btinsert(PG_FUNCTION_ARGS); extern Datum btinsert(PG_FUNCTION_ARGS);
extern Datum btbeginscan(PG_FUNCTION_ARGS); extern Datum btbeginscan(PG_FUNCTION_ARGS);
extern Datum btgettuple(PG_FUNCTION_ARGS); extern Datum btgettuple(PG_FUNCTION_ARGS);
extern Datum btgetmulti(PG_FUNCTION_ARGS); extern Datum btgetbitmap(PG_FUNCTION_ARGS);
extern Datum btrescan(PG_FUNCTION_ARGS); extern Datum btrescan(PG_FUNCTION_ARGS);
extern Datum btendscan(PG_FUNCTION_ARGS); extern Datum btendscan(PG_FUNCTION_ARGS);
extern Datum btmarkpos(PG_FUNCTION_ARGS); extern Datum btmarkpos(PG_FUNCTION_ARGS);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/relscan.h,v 1.61 2008/03/26 16:20:48 alvherre Exp $ * $PostgreSQL: pgsql/src/include/access/relscan.h,v 1.62 2008/04/10 22:25:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -57,7 +57,7 @@ typedef HeapScanDescData *HeapScanDesc; ...@@ -57,7 +57,7 @@ typedef HeapScanDescData *HeapScanDesc;
/* /*
* We use the same IndexScanDescData structure for both amgettuple-based * We use the same IndexScanDescData structure for both amgettuple-based
* and amgetmulti-based index scans. Some fields are only relevant in * and amgetbitmap-based index scans. Some fields are only relevant in
* amgettuple-based scans. * amgettuple-based scans.
*/ */
typedef struct IndexScanDescData typedef struct IndexScanDescData
...@@ -68,7 +68,6 @@ typedef struct IndexScanDescData ...@@ -68,7 +68,6 @@ typedef struct IndexScanDescData
Snapshot xs_snapshot; /* snapshot to see */ Snapshot xs_snapshot; /* snapshot to see */
int numberOfKeys; /* number of scan keys */ int numberOfKeys; /* number of scan keys */
ScanKey keyData; /* array of scan key descriptors */ ScanKey keyData; /* array of scan key descriptors */
bool is_multiscan; /* TRUE = using amgetmulti */
/* signaling to index AM about killing index tuples */ /* signaling to index AM about killing index tuples */
bool kill_prior_tuple; /* last-returned tuple is dead */ bool kill_prior_tuple; /* last-returned tuple is dead */
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.446 2008/04/06 16:54:48 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.447 2008/04/10 22:25:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200804051 #define CATALOG_VERSION_NO 200804101
#endif #endif
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.54 2008/03/27 03:57:34 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.55 2008/04/10 22:25:25 tgl Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
...@@ -51,7 +51,7 @@ CATALOG(pg_am,2601) ...@@ -51,7 +51,7 @@ CATALOG(pg_am,2601)
regproc aminsert; /* "insert this tuple" function */ regproc aminsert; /* "insert this tuple" function */
regproc ambeginscan; /* "start new scan" function */ regproc ambeginscan; /* "start new scan" function */
regproc amgettuple; /* "next valid tuple" function */ regproc amgettuple; /* "next valid tuple" function */
regproc amgetmulti; /* "fetch multiple tuples" function */ regproc amgetbitmap; /* "fetch all valid tuples" function */
regproc amrescan; /* "restart this scan" function */ regproc amrescan; /* "restart this scan" function */
regproc amendscan; /* "end this scan" function */ regproc amendscan; /* "end this scan" function */
regproc ammarkpos; /* "mark current scan position" function */ regproc ammarkpos; /* "mark current scan position" function */
...@@ -89,7 +89,7 @@ typedef FormData_pg_am *Form_pg_am; ...@@ -89,7 +89,7 @@ typedef FormData_pg_am *Form_pg_am;
#define Anum_pg_am_aminsert 12 #define Anum_pg_am_aminsert 12
#define Anum_pg_am_ambeginscan 13 #define Anum_pg_am_ambeginscan 13
#define Anum_pg_am_amgettuple 14 #define Anum_pg_am_amgettuple 14
#define Anum_pg_am_amgetmulti 15 #define Anum_pg_am_amgetbitmap 15
#define Anum_pg_am_amrescan 16 #define Anum_pg_am_amrescan 16
#define Anum_pg_am_amendscan 17 #define Anum_pg_am_amendscan 17
#define Anum_pg_am_ammarkpos 18 #define Anum_pg_am_ammarkpos 18
...@@ -105,16 +105,16 @@ typedef FormData_pg_am *Form_pg_am; ...@@ -105,16 +105,16 @@ typedef FormData_pg_am *Form_pg_am;
* ---------------- * ----------------
*/ */
DATA(insert OID = 403 ( btree 5 1 t t t t t t f t btinsert btbeginscan btgettuple btgetmulti btrescan btendscan btmarkpos btrestrpos btbuild btbulkdelete btvacuumcleanup btcostestimate btoptions )); DATA(insert OID = 403 ( btree 5 1 t t t t t t f t btinsert btbeginscan btgettuple btgetbitmap btrescan btendscan btmarkpos btrestrpos btbuild btbulkdelete btvacuumcleanup btcostestimate btoptions ));
DESCR("b-tree index access method"); DESCR("b-tree index access method");
#define BTREE_AM_OID 403 #define BTREE_AM_OID 403
DATA(insert OID = 405 ( hash 1 1 f f f f f f f f hashinsert hashbeginscan hashgettuple hashgetmulti hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbulkdelete hashvacuumcleanup hashcostestimate hashoptions )); DATA(insert OID = 405 ( hash 1 1 f f f f f f f f hashinsert hashbeginscan hashgettuple hashgetbitmap hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbulkdelete hashvacuumcleanup hashcostestimate hashoptions ));
DESCR("hash index access method"); DESCR("hash index access method");
#define HASH_AM_OID 405 #define HASH_AM_OID 405
DATA(insert OID = 783 ( gist 0 7 f f t t t t t t gistinsert gistbeginscan gistgettuple gistgetmulti gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete gistvacuumcleanup gistcostestimate gistoptions )); DATA(insert OID = 783 ( gist 0 7 f f t t t t t t gistinsert gistbeginscan gistgettuple gistgetbitmap gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete gistvacuumcleanup gistcostestimate gistoptions ));
DESCR("GiST index access method"); DESCR("GiST index access method");
#define GIST_AM_OID 783 #define GIST_AM_OID 783
DATA(insert OID = 2742 ( gin 0 4 f f f f f f t f gininsert ginbeginscan gingettuple gingetmulti ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbulkdelete ginvacuumcleanup gincostestimate ginoptions )); DATA(insert OID = 2742 ( gin 0 4 f f f f f f t f gininsert ginbeginscan gingettuple gingetbitmap ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbulkdelete ginvacuumcleanup gincostestimate ginoptions ));
DESCR("GIN index access method"); DESCR("GIN index access method");
#define GIN_AM_OID 2742 #define GIN_AM_OID 2742
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.487 2008/04/04 18:45:36 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.488 2008/04/10 22:25:25 tgl Exp $
* *
* NOTES * NOTES
* The script catalog/genbki.sh reads this file and generates .bki * The script catalog/genbki.sh reads this file and generates .bki
...@@ -655,7 +655,7 @@ DESCR("convert float4 to int4"); ...@@ -655,7 +655,7 @@ DESCR("convert float4 to int4");
DATA(insert OID = 330 ( btgettuple PGNSP PGUID 12 1 0 f f t f v 2 16 "2281 2281" _null_ _null_ _null_ btgettuple - _null_ _null_ )); DATA(insert OID = 330 ( btgettuple PGNSP PGUID 12 1 0 f f t f v 2 16 "2281 2281" _null_ _null_ _null_ btgettuple - _null_ _null_ ));
DESCR("btree(internal)"); DESCR("btree(internal)");
DATA(insert OID = 636 ( btgetmulti PGNSP PGUID 12 1 0 f f t f v 4 16 "2281 2281 2281 2281" _null_ _null_ _null_ btgetmulti - _null_ _null_ )); DATA(insert OID = 636 ( btgetbitmap PGNSP PGUID 12 1 0 f f t f v 2 20 "2281 2281" _null_ _null_ _null_ btgetbitmap - _null_ _null_ ));
DESCR("btree(internal)"); DESCR("btree(internal)");
DATA(insert OID = 331 ( btinsert PGNSP PGUID 12 1 0 f f t f v 6 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ btinsert - _null_ _null_ )); DATA(insert OID = 331 ( btinsert PGNSP PGUID 12 1 0 f f t f v 6 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ btinsert - _null_ _null_ ));
DESCR("btree(internal)"); DESCR("btree(internal)");
...@@ -774,7 +774,7 @@ DESCR("convert char(n) to name"); ...@@ -774,7 +774,7 @@ DESCR("convert char(n) to name");
DATA(insert OID = 440 ( hashgettuple PGNSP PGUID 12 1 0 f f t f v 2 16 "2281 2281" _null_ _null_ _null_ hashgettuple - _null_ _null_ )); DATA(insert OID = 440 ( hashgettuple PGNSP PGUID 12 1 0 f f t f v 2 16 "2281 2281" _null_ _null_ _null_ hashgettuple - _null_ _null_ ));
DESCR("hash(internal)"); DESCR("hash(internal)");
DATA(insert OID = 637 ( hashgetmulti PGNSP PGUID 12 1 0 f f t f v 4 16 "2281 2281 2281 2281" _null_ _null_ _null_ hashgetmulti - _null_ _null_ )); DATA(insert OID = 637 ( hashgetbitmap PGNSP PGUID 12 1 0 f f t f v 2 20 "2281 2281" _null_ _null_ _null_ hashgetbitmap - _null_ _null_ ));
DESCR("hash(internal)"); DESCR("hash(internal)");
DATA(insert OID = 441 ( hashinsert PGNSP PGUID 12 1 0 f f t f v 6 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ hashinsert - _null_ _null_ )); DATA(insert OID = 441 ( hashinsert PGNSP PGUID 12 1 0 f f t f v 6 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ hashinsert - _null_ _null_ ));
DESCR("hash(internal)"); DESCR("hash(internal)");
...@@ -1040,7 +1040,7 @@ DESCR("smaller of two"); ...@@ -1040,7 +1040,7 @@ DESCR("smaller of two");
DATA(insert OID = 774 ( gistgettuple PGNSP PGUID 12 1 0 f f t f v 2 16 "2281 2281" _null_ _null_ _null_ gistgettuple - _null_ _null_ )); DATA(insert OID = 774 ( gistgettuple PGNSP PGUID 12 1 0 f f t f v 2 16 "2281 2281" _null_ _null_ _null_ gistgettuple - _null_ _null_ ));
DESCR("gist(internal)"); DESCR("gist(internal)");
DATA(insert OID = 638 ( gistgetmulti PGNSP PGUID 12 1 0 f f t f v 4 16 "2281 2281 2281 2281" _null_ _null_ _null_ gistgetmulti - _null_ _null_ )); DATA(insert OID = 638 ( gistgetbitmap PGNSP PGUID 12 1 0 f f t f v 2 20 "2281 2281" _null_ _null_ _null_ gistgetbitmap - _null_ _null_ ));
DESCR("gist(internal)"); DESCR("gist(internal)");
DATA(insert OID = 775 ( gistinsert PGNSP PGUID 12 1 0 f f t f v 6 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ gistinsert - _null_ _null_ )); DATA(insert OID = 775 ( gistinsert PGNSP PGUID 12 1 0 f f t f v 6 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ gistinsert - _null_ _null_ ));
DESCR("gist(internal)"); DESCR("gist(internal)");
...@@ -3967,7 +3967,7 @@ DESCR("GiST support"); ...@@ -3967,7 +3967,7 @@ DESCR("GiST support");
/* GIN */ /* GIN */
DATA(insert OID = 2730 ( gingettuple PGNSP PGUID 12 1 0 f f t f v 2 16 "2281 2281" _null_ _null_ _null_ gingettuple - _null_ _null_ )); DATA(insert OID = 2730 ( gingettuple PGNSP PGUID 12 1 0 f f t f v 2 16 "2281 2281" _null_ _null_ _null_ gingettuple - _null_ _null_ ));
DESCR("gin(internal)"); DESCR("gin(internal)");
DATA(insert OID = 2731 ( gingetmulti PGNSP PGUID 12 1 0 f f t f v 4 16 "2281 2281 2281 2281" _null_ _null_ _null_ gingetmulti - _null_ _null_ )); DATA(insert OID = 2731 ( gingetbitmap PGNSP PGUID 12 1 0 f f t f v 2 20 "2281 2281" _null_ _null_ _null_ gingetbitmap - _null_ _null_ ));
DESCR("gin(internal)"); DESCR("gin(internal)");
DATA(insert OID = 2732 ( gininsert PGNSP PGUID 12 1 0 f f t f v 6 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ gininsert - _null_ _null_ )); DATA(insert OID = 2732 ( gininsert PGNSP PGUID 12 1 0 f f t f v 6 16 "2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ gininsert - _null_ _null_ ));
DESCR("gin(internal)"); DESCR("gin(internal)");
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* Copyright (c) 2003-2008, PostgreSQL Global Development Group * Copyright (c) 2003-2008, PostgreSQL Global Development Group
* *
* $PostgreSQL: pgsql/src/include/nodes/tidbitmap.h,v 1.6 2008/01/01 19:45:58 momjian Exp $ * $PostgreSQL: pgsql/src/include/nodes/tidbitmap.h,v 1.7 2008/04/10 22:25:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -36,6 +36,8 @@ typedef struct ...@@ -36,6 +36,8 @@ typedef struct
{ {
BlockNumber blockno; /* page number containing tuples */ BlockNumber blockno; /* page number containing tuples */
int ntuples; /* -1 indicates lossy result */ int ntuples; /* -1 indicates lossy result */
bool recheck; /* should the tuples be rechecked? */
/* Note: recheck is always true if ntuples < 0 */
OffsetNumber offsets[1]; /* VARIABLE LENGTH ARRAY */ OffsetNumber offsets[1]; /* VARIABLE LENGTH ARRAY */
} TBMIterateResult; /* VARIABLE LENGTH STRUCT */ } TBMIterateResult; /* VARIABLE LENGTH STRUCT */
...@@ -44,7 +46,9 @@ typedef struct ...@@ -44,7 +46,9 @@ typedef struct
extern TIDBitmap *tbm_create(long maxbytes); extern TIDBitmap *tbm_create(long maxbytes);
extern void tbm_free(TIDBitmap *tbm); extern void tbm_free(TIDBitmap *tbm);
extern void tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids); extern void tbm_add_tuples(TIDBitmap *tbm,
const ItemPointer tids, int ntids,
bool recheck);
extern void tbm_union(TIDBitmap *a, const TIDBitmap *b); extern void tbm_union(TIDBitmap *a, const TIDBitmap *b);
extern void tbm_intersect(TIDBitmap *a, const TIDBitmap *b); extern void tbm_intersect(TIDBitmap *a, const TIDBitmap *b);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.105 2008/03/28 00:21:56 tgl Exp $ * $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.106 2008/04/10 22:25:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -100,7 +100,7 @@ typedef struct RelationAmInfo ...@@ -100,7 +100,7 @@ typedef struct RelationAmInfo
FmgrInfo aminsert; FmgrInfo aminsert;
FmgrInfo ambeginscan; FmgrInfo ambeginscan;
FmgrInfo amgettuple; FmgrInfo amgettuple;
FmgrInfo amgetmulti; FmgrInfo amgetbitmap;
FmgrInfo amrescan; FmgrInfo amrescan;
FmgrInfo amendscan; FmgrInfo amendscan;
FmgrInfo ammarkpos; FmgrInfo ammarkpos;
......
-- Test bitmap AND and OR
-- Generate enough data that we can test the lossy bitmaps.
-- There's 55 tuples per page in the table. 53 is just
-- below 55, so that an index scan with qual a = constant
-- will return at least one hit per page. 59 is just above
-- 55, so that an index scan with qual b = constant will return
-- hits on most but not all pages. 53 and 59 are prime, so that
-- there's a maximum number of a,b combinations in the table.
-- That allows us to test all the different combinations of
-- lossy and non-lossy pages with the minimum amount of data
CREATE TABLE bmscantest (a int, b int, t text);
INSERT INTO bmscantest
SELECT (r%53), (r%59), 'foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo'
FROM generate_series(1,70000) r;
CREATE INDEX i_bmtest_a ON bmscantest(a);
CREATE INDEX i_bmtest_b ON bmscantest(b);
-- We want to use bitmapscans. With default settings, the planner currently
-- chooses a bitmap scan for the queries below anyway, but let's make sure.
set enable_indexscan=false;
set enable_seqscan=false;
-- Lower work_mem to trigger use of lossy bitmaps
set work_mem = 64;
-- Test bitmap-and.
SELECT count(*) FROM bmscantest WHERE a = 1 AND b = 1;
count
-------
23
(1 row)
-- Test bitmap-or.
SELECT count(*) FROM bmscantest WHERE a = 1 OR b = 1;
count
-------
2485
(1 row)
-- clean up
DROP TABLE bmscantest;
...@@ -174,7 +174,7 @@ RESET enable_bitmapscan; ...@@ -174,7 +174,7 @@ RESET enable_bitmapscan;
-- --
SET enable_seqscan = OFF; SET enable_seqscan = OFF;
SET enable_indexscan = ON; SET enable_indexscan = ON;
SET enable_bitmapscan = ON; SET enable_bitmapscan = OFF;
CREATE INDEX intarrayidx ON array_index_op_test USING gin (i); CREATE INDEX intarrayidx ON array_index_op_test USING gin (i);
SELECT * FROM array_index_op_test WHERE i @> '{32}' ORDER BY seqno; SELECT * FROM array_index_op_test WHERE i @> '{32}' ORDER BY seqno;
seqno | i | t seqno | i | t
...@@ -327,6 +327,95 @@ SELECT * FROM array_index_op_test WHERE t = '{AAAAAAAAAA646,A87088}' ORDER BY se ...@@ -327,6 +327,95 @@ SELECT * FROM array_index_op_test WHERE t = '{AAAAAAAAAA646,A87088}' ORDER BY se
96 | {23,97,43} | {AAAAAAAAAA646,A87088} 96 | {23,97,43} | {AAAAAAAAAA646,A87088}
(1 row) (1 row)
-- Repeat some of the above tests but exercising bitmapscans instead
SET enable_indexscan = OFF;
SET enable_bitmapscan = ON;
SELECT * FROM array_index_op_test WHERE i @> '{32}' ORDER BY seqno;
seqno | i | t
-------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------
6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657}
74 | {32} | {AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAA22860,AAAAAA99807,AAAAA17383,AAAAAAAAAAAAAAA67062,AAAAAAAAAAA15165,AAAAAAAAAAA50956}
77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066}
89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673}
98 | {38,34,32,89} | {AAAAAAAAAAAAAAAAAA71621,AAAA8857,AAAAAAAAAAAAAAAAAAA65037,AAAAAAAAAAAAAAAA31334,AAAAAAAAAA48845}
100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523}
(6 rows)
SELECT * FROM array_index_op_test WHERE i && '{32}' ORDER BY seqno;
seqno | i | t
-------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------
6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657}
74 | {32} | {AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAA22860,AAAAAA99807,AAAAA17383,AAAAAAAAAAAAAAA67062,AAAAAAAAAAA15165,AAAAAAAAAAA50956}
77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066}
89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673}
98 | {38,34,32,89} | {AAAAAAAAAAAAAAAAAA71621,AAAA8857,AAAAAAAAAAAAAAAAAAA65037,AAAAAAAAAAAAAAAA31334,AAAAAAAAAA48845}
100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523}
(6 rows)
SELECT * FROM array_index_op_test WHERE i @> '{17}' ORDER BY seqno;
seqno | i | t
-------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------
6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657}
12 | {17,99,18,52,91,72,0,43,96,23} | {AAAAA33250,AAAAAAAAAAAAAAAAAAA85420,AAAAAAAAAAA33576}
15 | {17,14,16,63,67} | {AA6416,AAAAAAAAAA646,AAAAA95309}
19 | {52,82,17,74,23,46,69,51,75} | {AAAAAAAAAAAAA73084,AAAAA75968,AAAAAAAAAAAAAAAA14047,AAAAAAA80240,AAAAAAAAAAAAAAAAAAA1205,A68938}
53 | {38,17} | {AAAAAAAAAAA21658}
65 | {61,5,76,59,17} | {AAAAAA99807,AAAAA64741,AAAAAAAAAAA53908,AA21643,AAAAAAAAA10012}
77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066}
89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673}
(8 rows)
SELECT * FROM array_index_op_test WHERE i && '{17}' ORDER BY seqno;
seqno | i | t
-------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------
6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657}
12 | {17,99,18,52,91,72,0,43,96,23} | {AAAAA33250,AAAAAAAAAAAAAAAAAAA85420,AAAAAAAAAAA33576}
15 | {17,14,16,63,67} | {AA6416,AAAAAAAAAA646,AAAAA95309}
19 | {52,82,17,74,23,46,69,51,75} | {AAAAAAAAAAAAA73084,AAAAA75968,AAAAAAAAAAAAAAAA14047,AAAAAAA80240,AAAAAAAAAAAAAAAAAAA1205,A68938}
53 | {38,17} | {AAAAAAAAAAA21658}
65 | {61,5,76,59,17} | {AAAAAA99807,AAAAA64741,AAAAAAAAAAA53908,AA21643,AAAAAAAAA10012}
77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066}
89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673}
(8 rows)
SELECT * FROM array_index_op_test WHERE i @> '{32,17}' ORDER BY seqno;
seqno | i | t
-------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------
6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657}
77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066}
89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673}
(3 rows)
SELECT * FROM array_index_op_test WHERE i && '{32,17}' ORDER BY seqno;
seqno | i | t
-------+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------
6 | {39,35,5,94,17,92,60,32} | {AAAAAAAAAAAAAAA35875,AAAAAAAAAAAAAAAA23657}
12 | {17,99,18,52,91,72,0,43,96,23} | {AAAAA33250,AAAAAAAAAAAAAAAAAAA85420,AAAAAAAAAAA33576}
15 | {17,14,16,63,67} | {AA6416,AAAAAAAAAA646,AAAAA95309}
19 | {52,82,17,74,23,46,69,51,75} | {AAAAAAAAAAAAA73084,AAAAA75968,AAAAAAAAAAAAAAAA14047,AAAAAAA80240,AAAAAAAAAAAAAAAAAAA1205,A68938}
53 | {38,17} | {AAAAAAAAAAA21658}
65 | {61,5,76,59,17} | {AAAAAA99807,AAAAA64741,AAAAAAAAAAA53908,AA21643,AAAAAAAAA10012}
74 | {32} | {AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAA22860,AAAAAA99807,AAAAA17383,AAAAAAAAAAAAAAA67062,AAAAAAAAAAA15165,AAAAAAAAAAA50956}
77 | {97,15,32,17,55,59,18,37,50,39} | {AAAAAAAAAAAA67946,AAAAAA54032,AAAAAAAA81587,55847,AAAAAAAAAAAAAA28620,AAAAAAAAAAAAAAAAA43052,AAAAAA75463,AAAA49534,AAAAAAAA44066}
89 | {40,32,17,6,30,88} | {AA44673,AAAAAAAAAAA6119,AAAAAAAAAAAAAAAA23657,AAAAAAAAAAAAAAAAAA47955,AAAAAAAAAAAAAAAA33598,AAAAAAAAAAA33576,AA44673}
98 | {38,34,32,89} | {AAAAAAAAAAAAAAAAAA71621,AAAA8857,AAAAAAAAAAAAAAAAAAA65037,AAAAAAAAAAAAAAAA31334,AAAAAAAAAA48845}
100 | {85,32,57,39,49,84,32,3,30} | {AAAAAAA80240,AAAAAAAAAAAAAAAA1729,AAAAA60038,AAAAAAAAAAA92631,AAAAAAAA9523}
(11 rows)
SELECT * FROM array_index_op_test WHERE i <@ '{38,34,32,89}' ORDER BY seqno;
seqno | i | t
-------+---------------+----------------------------------------------------------------------------------------------------------------------------
40 | {34} | {AAAAAAAAAAAAAA10611,AAAAAAAAAAAAAAAAAAA1205,AAAAAAAAAAA50956,AAAAAAAAAAAAAAAA31334,AAAAA70466,AAAAAAAA81587,AAAAAAA74623}
74 | {32} | {AAAAAAAAAAAAAAAA1729,AAAAAAAAAAAAA22860,AAAAAA99807,AAAAA17383,AAAAAAAAAAAAAAA67062,AAAAAAAAAAA15165,AAAAAAAAAAA50956}
98 | {38,34,32,89} | {AAAAAAAAAAAAAAAAAA71621,AAAA8857,AAAAAAAAAAAAAAAAAAA65037,AAAAAAAAAAAAAAAA31334,AAAAAAAAAA48845}
(3 rows)
SELECT * FROM array_index_op_test WHERE i = '{47,77}' ORDER BY seqno;
seqno | i | t
-------+---------+-----------------------------------------------------------------------------------------------------------------
95 | {47,77} | {AAAAAAAAAAAAAAAAA764,AAAAAAAAAAA74076,AAAAAAAAAA18107,AAAAA40681,AAAAAAAAAAAAAAA35875,AAAAA60038,AAAAAAA56483}
(1 row)
RESET enable_seqscan; RESET enable_seqscan;
RESET enable_indexscan; RESET enable_indexscan;
RESET enable_bitmapscan; RESET enable_bitmapscan;
......
...@@ -65,12 +65,12 @@ WHERE amgettuple != 0 AND ...@@ -65,12 +65,12 @@ WHERE amgettuple != 0 AND
------+------------ ------+------------
(0 rows) (0 rows)
SELECT ctid, amgetmulti SELECT ctid, amgetbitmap
FROM pg_catalog.pg_am fk FROM pg_catalog.pg_am fk
WHERE amgetmulti != 0 AND WHERE amgetbitmap != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetmulti); NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
ctid | amgetmulti ctid | amgetbitmap
------+------------ ------+-------------
(0 rows) (0 rows)
SELECT ctid, amrescan SELECT ctid, amrescan
......
# ---------- # ----------
# $PostgreSQL: pgsql/src/test/regress/parallel_schedule,v 1.46 2007/11/24 19:49:23 darcy Exp $ # $PostgreSQL: pgsql/src/test/regress/parallel_schedule,v 1.47 2008/04/10 22:25:26 tgl Exp $
# #
# By convention, we put no more than twenty tests in any one parallel group; # By convention, we put no more than twenty tests in any one parallel group;
# this limits the number of connections needed to run the tests. # this limits the number of connections needed to run the tests.
...@@ -77,7 +77,7 @@ test: misc ...@@ -77,7 +77,7 @@ test: misc
# ---------- # ----------
# Another group of parallel tests # Another group of parallel tests
# ---------- # ----------
test: select_views portals_p2 rules foreign_key cluster dependency guc combocid tsearch tsdicts test: select_views portals_p2 rules foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts
# ---------- # ----------
# Another group of parallel tests # Another group of parallel tests
......
# $PostgreSQL: pgsql/src/test/regress/serial_schedule,v 1.43 2007/11/24 20:41:35 tgl Exp $ # $PostgreSQL: pgsql/src/test/regress/serial_schedule,v 1.44 2008/04/10 22:25:26 tgl Exp $
# This should probably be in an order similar to parallel_schedule. # This should probably be in an order similar to parallel_schedule.
test: boolean test: boolean
test: char test: char
...@@ -92,6 +92,7 @@ test: foreign_key ...@@ -92,6 +92,7 @@ test: foreign_key
test: cluster test: cluster
test: dependency test: dependency
test: guc test: guc
test: bitmapops
test: combocid test: combocid
test: tsearch test: tsearch
test: plancache test: plancache
......
-- Test bitmap AND and OR
-- Generate enough data that we can test the lossy bitmaps.
-- There's 55 tuples per page in the table. 53 is just
-- below 55, so that an index scan with qual a = constant
-- will return at least one hit per page. 59 is just above
-- 55, so that an index scan with qual b = constant will return
-- hits on most but not all pages. 53 and 59 are prime, so that
-- there's a maximum number of a,b combinations in the table.
-- That allows us to test all the different combinations of
-- lossy and non-lossy pages with the minimum amount of data
CREATE TABLE bmscantest (a int, b int, t text);
INSERT INTO bmscantest
SELECT (r%53), (r%59), 'foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo'
FROM generate_series(1,70000) r;
CREATE INDEX i_bmtest_a ON bmscantest(a);
CREATE INDEX i_bmtest_b ON bmscantest(b);
-- We want to use bitmapscans. With default settings, the planner currently
-- chooses a bitmap scan for the queries below anyway, but let's make sure.
set enable_indexscan=false;
set enable_seqscan=false;
-- Lower work_mem to trigger use of lossy bitmaps
set work_mem = 64;
-- Test bitmap-and.
SELECT count(*) FROM bmscantest WHERE a = 1 AND b = 1;
-- Test bitmap-or.
SELECT count(*) FROM bmscantest WHERE a = 1 OR b = 1;
-- clean up
DROP TABLE bmscantest;
...@@ -143,7 +143,7 @@ RESET enable_bitmapscan; ...@@ -143,7 +143,7 @@ RESET enable_bitmapscan;
SET enable_seqscan = OFF; SET enable_seqscan = OFF;
SET enable_indexscan = ON; SET enable_indexscan = ON;
SET enable_bitmapscan = ON; SET enable_bitmapscan = OFF;
CREATE INDEX intarrayidx ON array_index_op_test USING gin (i); CREATE INDEX intarrayidx ON array_index_op_test USING gin (i);
...@@ -167,6 +167,18 @@ SELECT * FROM array_index_op_test WHERE t && '{AAAAAAAA72908,AAAAAAAAAA646}' ORD ...@@ -167,6 +167,18 @@ SELECT * FROM array_index_op_test WHERE t && '{AAAAAAAA72908,AAAAAAAAAA646}' ORD
SELECT * FROM array_index_op_test WHERE t <@ '{AAAAAAAA72908,AAAAAAAAAAAAAAAAAAA17075,AA88409,AAAAAAAAAAAAAAAAAA36842,AAAAAAA48038,AAAAAAAAAAAAAA10611}' ORDER BY seqno; SELECT * FROM array_index_op_test WHERE t <@ '{AAAAAAAA72908,AAAAAAAAAAAAAAAAAAA17075,AA88409,AAAAAAAAAAAAAAAAAA36842,AAAAAAA48038,AAAAAAAAAAAAAA10611}' ORDER BY seqno;
SELECT * FROM array_index_op_test WHERE t = '{AAAAAAAAAA646,A87088}' ORDER BY seqno; SELECT * FROM array_index_op_test WHERE t = '{AAAAAAAAAA646,A87088}' ORDER BY seqno;
-- Repeat some of the above tests but exercising bitmapscans instead
SET enable_indexscan = OFF;
SET enable_bitmapscan = ON;
SELECT * FROM array_index_op_test WHERE i @> '{32}' ORDER BY seqno;
SELECT * FROM array_index_op_test WHERE i && '{32}' ORDER BY seqno;
SELECT * FROM array_index_op_test WHERE i @> '{17}' ORDER BY seqno;
SELECT * FROM array_index_op_test WHERE i && '{17}' ORDER BY seqno;
SELECT * FROM array_index_op_test WHERE i @> '{32,17}' ORDER BY seqno;
SELECT * FROM array_index_op_test WHERE i && '{32,17}' ORDER BY seqno;
SELECT * FROM array_index_op_test WHERE i <@ '{38,34,32,89}' ORDER BY seqno;
SELECT * FROM array_index_op_test WHERE i = '{47,77}' ORDER BY seqno;
RESET enable_seqscan; RESET enable_seqscan;
RESET enable_indexscan; RESET enable_indexscan;
......
...@@ -33,10 +33,10 @@ SELECT ctid, amgettuple ...@@ -33,10 +33,10 @@ SELECT ctid, amgettuple
FROM pg_catalog.pg_am fk FROM pg_catalog.pg_am fk
WHERE amgettuple != 0 AND WHERE amgettuple != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple); NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
SELECT ctid, amgetmulti SELECT ctid, amgetbitmap
FROM pg_catalog.pg_am fk FROM pg_catalog.pg_am fk
WHERE amgetmulti != 0 AND WHERE amgetbitmap != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetmulti); NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
SELECT ctid, amrescan SELECT ctid, amrescan
FROM pg_catalog.pg_am fk FROM pg_catalog.pg_am fk
WHERE amrescan != 0 AND WHERE amrescan != 0 AND
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment