-<!-- $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
-->
</row>
<row>
- <entry><structfield>amgetmulti</structfield></entry>
+ <entry><structfield>amgetbitmap</structfield></entry>
<entry><type>regproc</type></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>
-<!-- $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">
<title>Index Access Method Interface Definition</title>
<para>
<programlisting>
-boolean
-amgetmulti (IndexScanDesc scan,
- ItemPointer tids,
- int32 max_tids,
- int32 *returned_tids);
+int64
+amgetbitmap (IndexScanDesc scan,
+ TIDBitmap *tbm);
</programlisting>
- Fetch multiple tuples in the given scan. Returns TRUE if the scan should
- continue, FALSE if no matching tuples remain. <literal>tids</> points to
- a caller-supplied array of <literal>max_tids</>
- <structname>ItemPointerData</> records, which the call fills with TIDs of
- 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
+ Fetch all tuples in the given scan and add them to the caller-supplied
+ TIDBitmap (that is, OR the set of tuple IDs into whatever set is already
+ in the bitmap). The number of tuples fetched is returned.
+ <function>amgetbitmap</> and
<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">.
</para>
<para>
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
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
- simplify matters. In the first place, <function>amgetmulti</> does not
- take a <literal>direction</> argument, and therefore it does not support
- backwards scan nor intrascan reversal of direction. The access method
- need not support marking or restoring scan positions during an
- <function>amgetmulti</> scan, either. (These restrictions cost little
- since it would be difficult to use these features in an
- <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
+ simplify matters. First of all, <function>amgetbitmap</> returns all
+ tuples at once and marking or restoring scan positions isn't
+ supported. Secondly, the tuples are returned in a bitmap which doesn't
+ have any specific ordering, which is why <function>amgetbitmap</> doesn't
+ take a <literal>direction</> argument. Finally, <function>amgetbitmap</>
+ does not guarantee any locking of the returned tuples, with implications
spelled out in <xref linkend="index-locking">.
</para>
</para>
<para>
- In an <function>amgetmulti</> index scan, the access method need not
- guarantee to keep an index pin on any of the returned tuples. (It would be
- impractical to pin more than the last one anyway.) Therefore
+ In an <function>amgetbitmap</> index scan, the access method does not
+ keep an index pin on any of the returned tuples. Therefore
it is only safe to use such scans with MVCC-compliant snapshots.
</para>
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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 "access/gin.h"
#include "catalog/index.h"
+#include "miscadmin.h"
#include "utils/memutils.h"
static bool
#define GinIsVoidRes(s) ( ((GinScanOpaque) scan->opaque)->isVoidRes == true )
Datum
-gingetmulti(PG_FUNCTION_ARGS)
+gingetbitmap(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
- ItemPointer tids = (ItemPointer) PG_GETARG_POINTER(1);
- int32 max_tids = PG_GETARG_INT32(2);
- int32 *returned_tids = (int32 *) PG_GETARG_POINTER(3);
+ TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1);
+ int64 ntids;
if (GinIsNewKey(scan))
newScanKey(scan);
- *returned_tids = 0;
-
if (GinIsVoidRes(scan))
- PG_RETURN_BOOL(false);
+ PG_RETURN_INT64(0);
startScan(scan);
- do
+ ntids = 0;
+ for (;;)
{
- if (scanGetItem(scan, tids + *returned_tids))
- (*returned_tids)++;
- else
+ ItemPointerData iptr;
+
+ CHECK_FOR_INTERRUPTS();
+
+ if (!scanGetItem(scan, &iptr))
break;
- } while (*returned_tids < max_tids);
+
+ tbm_add_tuples(tbm, &iptr, 1, false);
+ ntids++;
+ }
stopScan(scan);
- PG_RETURN_BOOL(*returned_tids == max_tids);
+ PG_RETURN_INT64(ntids);
}
Datum
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "access/gist_private.h"
#include "executor/execdebug.h"
+#include "miscadmin.h"
#include "pgstat.h"
#include "utils/memutils.h"
static OffsetNumber gistfindnext(IndexScanDesc scan, OffsetNumber n,
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,
OffsetNumber offset);
* tuples, continue looping until we find a non-killed tuple that matches
* 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);
}
Datum
-gistgetmulti(PG_FUNCTION_ARGS)
+gistgetbitmap(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
- ItemPointer tids = (ItemPointer) PG_GETARG_POINTER(1);
- int32 max_tids = PG_GETARG_INT32(2);
- int32 *returned_tids = (int32 *) PG_GETARG_POINTER(3);
+ TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1);
+ int64 ntids;
- *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
- * either to fetch the first such tuple or subsequent matching
- * tuples. Returns true iff a matching tuple was found.
+ * Fetch tuple(s) that match the search key; this can be invoked
+ * either to fetch the first such tuple or subsequent matching tuples.
+ *
+ * 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
-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)
{
Page p;
OffsetNumber n;
IndexTuple it;
GISTPageOpaque opaque;
bool resetoffset = false;
- int ntids = 0;
+ int64 ntids = 0;
so = (GISTScanOpaque) scan->opaque;
for (;;)
{
+ CHECK_FOR_INTERRUPTS();
+
/* First of all, we need lock buffer */
Assert(so->curbuf != InvalidBuffer);
LockBuffer(so->curbuf, GIST_SHARE);
* return success. Note that we keep "curbuf" pinned so that
* we can efficiently resume the index scan later.
*/
-
ItemPointerSet(&(so->curpos),
BufferGetBlockNumber(so->curbuf), n);
if (!(ignore_killed_tuples && ItemIdIsDead(PageGetItemId(p, n))))
{
it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
- tids[ntids] = scan->xs_ctup.t_self = it->t_tid;
ntids++;
-
- if (ntids == maxtids)
+ if (tbm != NULL)
+ tbm_add_tuples(tbm, &it->t_tid, 1, false);
+ else
{
+ *tid = scan->xs_ctup.t_self = it->t_tid;
+
LockBuffer(so->curbuf, GIST_UNLOCK);
- return ntids;
+ return ntids; /* always 1 */
}
}
}
* We've found an entry in an internal node whose key is
* consistent with the search key, so push it to stack
*/
-
stk = (GISTSearchStack *) palloc(sizeof(GISTSearchStack));
it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
stk->next = so->stack->next;
so->stack->next = stk;
-
}
if (ScanDirectionIsBackward(dir))
*
*
* 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
* This file contains only the public interface routines.
#include "access/hash.h"
#include "catalog/index.h"
#include "commands/vacuum.h"
+#include "miscadmin.h"
#include "optimizer/cost.h"
#include "optimizer/plancat.h"
/*
- * hashgetmulti() -- get multiple 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.
+ * hashgetbitmap() -- get all tuples at once
*/
Datum
-hashgetmulti(PG_FUNCTION_ARGS)
+hashgetbitmap(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
- ItemPointer tids = (ItemPointer) PG_GETARG_POINTER(1);
- int32 max_tids = PG_GETARG_INT32(2);
- int32 *returned_tids = (int32 *) PG_GETARG_POINTER(3);
+ TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1);
HashScanOpaque so = (HashScanOpaque) scan->opaque;
- Relation rel = scan->indexRelation;
- bool res = true;
- int32 ntids = 0;
+ bool res;
+ int64 ntids = 0;
- /*
- * 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);
+ res = _hash_first(scan, ForwardScanDirection);
- while (ntids < max_tids)
+ while (res)
{
- /*
- * Start scan, or advance to next tuple.
- */
- if (ItemPointerIsValid(&(so->hashso_curpos)))
- res = _hash_next(scan, ForwardScanDirection);
- else
- res = _hash_first(scan, ForwardScanDirection);
+ bool add_tuple;
+
+ CHECK_FOR_INTERRUPTS();
/*
* Skip killed tuples if asked to.
*/
if (scan->ignore_killed_tuples)
{
- while (res)
- {
- Page page;
- OffsetNumber offnum;
-
- offnum = ItemPointerGetOffsetNumber(&(so->hashso_curpos));
- page = BufferGetPage(so->hashso_curbuf);
- if (!ItemIdIsDead(PageGetItemId(page, offnum)))
- break;
- res = _hash_next(scan, ForwardScanDirection);
- }
+ Page page;
+ OffsetNumber offnum;
+
+ offnum = ItemPointerGetOffsetNumber(&(so->hashso_curpos));
+ page = BufferGetPage(so->hashso_curbuf);
+ add_tuple = !ItemIdIsDead(PageGetItemId(page, offnum));
}
+ else
+ add_tuple = true;
- if (!res)
- break;
/* Save tuple ID, and continue scanning */
- tids[ntids] = scan->xs_ctup.t_self;
- ntids++;
- }
+ if (add_tuple)
+ {
+ tbm_add_tuples(tbm, &scan->xs_ctup.t_self, 1, false);
+ ntids++;
+ }
- /* Release read lock on current buffer, but keep it pinned */
- if (BufferIsValid(so->hashso_curbuf))
- _hash_chgbufaccess(rel, so->hashso_curbuf, HASH_READ, HASH_NOLOCK);
+ res = _hash_next(scan, ForwardScanDirection);
+ }
- *returned_tids = ntids;
- PG_RETURN_BOOL(res);
+ PG_RETURN_INT64(ntids);
}
*
*
* 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
* many of the old access method routines have been turned into
else
scan->keyData = NULL;
- scan->is_multiscan = false; /* caller may change this */
scan->kill_prior_tuple = false;
scan->ignore_killed_tuples = true; /* default setting */
*
*
* 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
* index_open - open an index relation by relation OID
* index_close - close an index relation
* 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_endscan - end a scan
* index_insert - insert an index tuple into a relation
* index_markpos - mark a scan position
* index_restrpos - restore a scan position
* 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_vacuum_cleanup - post-deletion cleanup of an index
* index_getprocid - get a support procedure OID
* Save additional parameters into the scandesc. Everything else was set
* up by RelationGetIndexScan.
*/
- scan->is_multiscan = false;
scan->heapRelation = heapRelation;
scan->xs_snapshot = snapshot;
}
/*
- * 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
* relation, even though it's not explicitly mentioned here.
*/
IndexScanDesc
-index_beginscan_multi(Relation indexRelation,
- Snapshot snapshot,
- int nkeys, ScanKey key)
+index_beginscan_bitmap(Relation indexRelation,
+ Snapshot snapshot,
+ int nkeys, ScanKey key)
{
IndexScanDesc scan;
* Save additional parameters into the scandesc. Everything else was set
* up by RelationGetIndexScan.
*/
- scan->is_multiscan = true;
scan->xs_snapshot = snapshot;
return 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
* 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
* to it.
*
- * A TRUE result indicates more calls should occur; a FALSE result says the
- * scan is done. *returned_tids could be zero or nonzero in either case.
+ * Returns the number of matching tuples found.
* ----------------
*/
-bool
-index_getmulti(IndexScanDesc scan,
- ItemPointer tids, int32 max_tids,
- int32 *returned_tids)
+int64
+index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap)
{
FmgrInfo *procedure;
- bool found;
+ int64 ntids;
SCAN_CHECKS;
- GET_SCAN_PROCEDURE(amgetmulti);
+ GET_SCAN_PROCEDURE(amgetbitmap);
/* just make sure this is 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,
- PointerGetDatum(scan),
- PointerGetDatum(tids),
- Int32GetDatum(max_tids),
- PointerGetDatum(returned_tids)));
+ ntids = DatumGetInt64(FunctionCall2(procedure,
+ PointerGetDatum(scan),
+ PointerGetDatum(bitmap)));
- pgstat_count_index_tuples(scan->indexRelation, *returned_tids);
+ pgstat_count_index_tuples(scan->indexRelation, ntids);
- return found;
+ return ntids;
}
/* ----------------
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "access/nbtree.h"
#include "catalog/index.h"
#include "commands/vacuum.h"
+#include "miscadmin.h"
#include "storage/freespace.h"
#include "storage/lmgr.h"
#include "utils/memutils.h"
}
/*
- * btgetmulti() -- get multiple tuples at once
- *
- * 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.
+ * btgetbitmap() -- gets all matching tuples, and adds them to a bitmap
*/
Datum
-btgetmulti(PG_FUNCTION_ARGS)
+btgetbitmap(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
- ItemPointer tids = (ItemPointer) PG_GETARG_POINTER(1);
- int32 max_tids = PG_GETARG_INT32(2);
- int32 *returned_tids = (int32 *) PG_GETARG_POINTER(3);
+ TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1);
BTScanOpaque so = (BTScanOpaque) scan->opaque;
- bool res = true;
- int32 ntids = 0;
-
- if (max_tids <= 0) /* behave correctly in boundary case */
- PG_RETURN_BOOL(true);
+ int64 ntids = 0;
+ ItemPointer heapTid;
- /* If we haven't started the scan yet, fetch the first page & tuple. */
- if (!BTScanPosIsValid(so->currPos))
+ /* Fetch the first page & tuple. */
+ if (!_bt_first(scan, ForwardScanDirection))
{
- res = _bt_first(scan, ForwardScanDirection);
- if (!res)
- {
- /* empty scan */
- *returned_tids = ntids;
- PG_RETURN_BOOL(res);
- }
- /* Save tuple ID, and continue scanning */
- tids[ntids] = scan->xs_ctup.t_self;
- ntids++;
+ /* empty scan */
+ PG_RETURN_INT64(0);
}
+ /* Save tuple ID, and continue scanning */
+ heapTid = &scan->xs_ctup.t_self;
+ tbm_add_tuples(tbm, heapTid, 1, false);
+ ntids++;
- while (ntids < max_tids)
+ for (;;)
{
/*
* Advance to next tuple within page. This is the same as the easy
*/
if (++so->currPos.itemIndex > so->currPos.lastItem)
{
+ CHECK_FOR_INTERRUPTS();
+
/* let _bt_next do the heavy lifting */
- res = _bt_next(scan, ForwardScanDirection);
- if (!res)
+ if (!_bt_next(scan, ForwardScanDirection))
break;
}
/* 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++;
}
- *returned_tids = ntids;
- PG_RETURN_BOOL(res);
+ PG_RETURN_INT64(ntids);
}
/*
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* If we are using lossy info, we have to recheck the qual conditions
* at every tuple.
*/
- if (tbmres->ntuples < 0)
+ if (tbmres->recheck)
{
econtext->ecxt_scantuple = slot;
ResetExprContext(econtext);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
Node *
MultiExecBitmapIndexScan(BitmapIndexScanState *node)
{
-#define MAX_TIDS 1024
TIDBitmap *tbm;
IndexScanDesc scandesc;
- ItemPointerData tids[MAX_TIDS];
- int32 ntids;
double nTuples = 0;
bool doscan;
*/
while (doscan)
{
- bool more = index_getmulti(scandesc, tids, MAX_TIDS, &ntids);
-
- if (ntids > 0)
- {
- tbm_add_tuples(tbm, tids, ntids);
- nTuples += ntids;
- }
+ nTuples += (double) index_getbitmap(scandesc, tbm);
CHECK_FOR_INTERRUPTS();
- if (!more)
- {
- doscan = ExecIndexAdvanceArrayKeys(node->biss_ArrayKeys,
- node->biss_NumArrayKeys);
- if (doscan) /* reset index scan */
- index_rescan(node->biss_ScanDesc, node->biss_ScanKeys);
- }
+ doscan = ExecIndexAdvanceArrayKeys(node->biss_ArrayKeys,
+ node->biss_NumArrayKeys);
+ if (doscan) /* reset index scan */
+ index_rescan(node->biss_ScanDesc, node->biss_ScanKeys);
}
/* must provide our own instrumentation support */
* Initialize scan descriptor.
*/
indexstate->biss_ScanDesc =
- index_beginscan_multi(indexstate->biss_RelationDesc,
- estate->es_snapshot,
- indexstate->biss_NumScanKeys,
- indexstate->biss_ScanKeys);
+ index_beginscan_bitmap(indexstate->biss_RelationDesc,
+ estate->es_snapshot,
+ indexstate->biss_NumScanKeys,
+ indexstate->biss_ScanKeys);
/*
* all done.
* of lossiness. In theory we could fall back to page ranges at some
* 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
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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
* 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
{
BlockNumber blockno; /* page number (hashtable key) */
bool ischunk; /* T = lossy storage, F = exact */
+ bool recheck; /* should the tuples be rechecked? */
bitmapword words[Max(WORDS_PER_PAGE, WORDS_PER_CHUNK)];
} PagetableEntry;
/*
* 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
-tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids)
+tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids,
+ bool recheck)
{
int i;
bitnum = BITNUM(off - 1);
}
page->words[wordnum] |= ((bitmapword) 1 << bitnum);
+ page->recheck |= recheck;
if (tbm->nentries > tbm->maxentries)
tbm_lossify(tbm);
/* Both pages are exact, merge at the bit level */
for (wordnum = 0; wordnum < WORDS_PER_PAGE; wordnum++)
apage->words[wordnum] |= bpage->words[wordnum];
+ apage->recheck |= bpage->recheck;
}
}
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
- * know that no bits need be set in bitmap a, but we do not know which
- * ones should be cleared, and we have no API for "at most these
- * tuples need be checked". (Perhaps it's worth adding that?)
- */
- 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.
+ * Some of the tuples in 'a' might not satisfy the quals for 'b',
+ * but because the page 'b' is lossy, we don't know which ones.
+ * Therefore we mark 'a' as requiring rechecks, to indicate that
+ * at most those tuples set in 'a' are matches.
*/
+ apage->recheck = true;
return false;
}
else
if (apage->words[wordnum] != 0)
candelete = false;
}
+ apage->recheck |= bpage->recheck;
}
+ /* If there is no matching b page, we can just delete the a page */
return candelete;
}
}
* 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
* 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 *
tbm_iterate(TIDBitmap *tbm)
/* Return a lossy page indicator from the chunk */
output->blockno = chunk_blockno;
output->ntuples = -1;
+ output->recheck = true;
tbm->schunkbit++;
return output;
}
}
output->blockno = page->blockno;
output->ntuples = ntuples;
+ output->recheck = page->recheck;
tbm->spageptr++;
return output;
}
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "access/relscan.h"
#include "access/sdir.h"
#include "nodes/primnodes.h"
+#include "nodes/tidbitmap.h"
#include "storage/lock.h"
/*
Relation indexRelation,
Snapshot snapshot,
int nkeys, ScanKey key);
-extern IndexScanDesc index_beginscan_multi(Relation indexRelation,
+extern IndexScanDesc index_beginscan_bitmap(Relation indexRelation,
Snapshot snapshot,
int nkeys, ScanKey key);
extern void index_rescan(IndexScanDesc scan, ScanKey key);
extern HeapTuple index_getnext(IndexScanDesc scan, ScanDirection direction);
extern bool index_getnext_indexitem(IndexScanDesc scan,
ScanDirection direction);
-extern bool index_getmulti(IndexScanDesc scan,
- ItemPointer tids, int32 max_tids,
- int32 *returned_tids);
+extern int64 index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap);
extern IndexBulkDeleteResult *index_bulk_delete(IndexVacuumInfo *info,
IndexBulkDeleteResult *stats,
*
* 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 $
*--------------------------------------------------------------------------
*/
#define ItemPointerSetMin(p) ItemPointerSet( (p), (BlockNumber)0, (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);
/* ginvacuum.c */
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
/* gistget.c */
extern Datum gistgettuple(PG_FUNCTION_ARGS);
-extern Datum gistgetmulti(PG_FUNCTION_ARGS);
+extern Datum gistgetbitmap(PG_FUNCTION_ARGS);
/* gistutil.c */
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* 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
* modeled after Margo Seltzer's hash implementation for unix.
extern Datum hashinsert(PG_FUNCTION_ARGS);
extern Datum hashbeginscan(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 hashendscan(PG_FUNCTION_ARGS);
extern Datum hashmarkpos(PG_FUNCTION_ARGS);
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
extern Datum btinsert(PG_FUNCTION_ARGS);
extern Datum btbeginscan(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 btendscan(PG_FUNCTION_ARGS);
extern Datum btmarkpos(PG_FUNCTION_ARGS);
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
/*
* 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.
*/
typedef struct IndexScanDescData
Snapshot xs_snapshot; /* snapshot to see */
int numberOfKeys; /* number of scan keys */
ScanKey keyData; /* array of scan key descriptors */
- bool is_multiscan; /* TRUE = using amgetmulti */
/* signaling to index AM about killing index tuples */
bool kill_prior_tuple; /* last-returned tuple is dead */
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200804051
+#define CATALOG_VERSION_NO 200804101
#endif
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* 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
* the genbki.sh script reads this file and generates .bki
regproc aminsert; /* "insert this tuple" function */
regproc ambeginscan; /* "start new scan" 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 amendscan; /* "end this scan" function */
regproc ammarkpos; /* "mark current scan position" function */
#define Anum_pg_am_aminsert 12
#define Anum_pg_am_ambeginscan 13
#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_amendscan 17
#define Anum_pg_am_ammarkpos 18
* ----------------
*/
-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");
#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");
#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");
#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");
#define GIN_AM_OID 2742
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* 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
* The script catalog/genbki.sh reads this file and generates .bki
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)");
-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)");
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)");
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)");
-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)");
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)");
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)");
-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)");
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)");
/* 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_ ));
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)");
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)");
*
* 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 $
*
*-------------------------------------------------------------------------
*/
{
BlockNumber blockno; /* page number containing tuples */
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 */
} TBMIterateResult; /* VARIABLE LENGTH STRUCT */
extern TIDBitmap *tbm_create(long maxbytes);
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_intersect(TIDBitmap *a, const TIDBitmap *b);
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
FmgrInfo aminsert;
FmgrInfo ambeginscan;
FmgrInfo amgettuple;
- FmgrInfo amgetmulti;
+ FmgrInfo amgetbitmap;
FmgrInfo amrescan;
FmgrInfo amendscan;
FmgrInfo ammarkpos;
--- /dev/null
+-- 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;
--
SET enable_seqscan = OFF;
SET enable_indexscan = ON;
-SET enable_bitmapscan = ON;
+SET enable_bitmapscan = OFF;
CREATE INDEX intarrayidx ON array_index_op_test USING gin (i);
SELECT * FROM array_index_op_test WHERE i @> '{32}' ORDER BY seqno;
seqno | i | t
96 | {23,97,43} | {AAAAAAAAAA646,A87088}
(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_indexscan;
RESET enable_bitmapscan;
------+------------
(0 rows)
-SELECT ctid, amgetmulti
+SELECT ctid, amgetbitmap
FROM pg_catalog.pg_am fk
-WHERE amgetmulti != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetmulti);
- ctid | amgetmulti
-------+------------
+WHERE amgetbitmap != 0 AND
+ NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
+ ctid | amgetbitmap
+------+-------------
(0 rows)
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;
# this limits the number of connections needed to run the 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
-# $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.
test: boolean
test: char
test: cluster
test: dependency
test: guc
+test: bitmapops
test: combocid
test: tsearch
test: plancache
--- /dev/null
+-- 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;
SET enable_seqscan = OFF;
SET enable_indexscan = ON;
-SET enable_bitmapscan = ON;
+SET enable_bitmapscan = OFF;
CREATE INDEX intarrayidx ON array_index_op_test USING gin (i);
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;
+-- 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_indexscan;
FROM pg_catalog.pg_am fk
WHERE amgettuple != 0 AND
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
-WHERE amgetmulti != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetmulti);
+WHERE amgetbitmap != 0 AND
+ NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
SELECT ctid, amrescan
FROM pg_catalog.pg_am fk
WHERE amrescan != 0 AND