]> granicus.if.org Git - postgresql/commitdiff
Replace "amgetmulti" AM functions with "amgetbitmap", in which the whole
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 10 Apr 2008 22:25:26 +0000 (22:25 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 10 Apr 2008 22:25:26 +0000 (22:25 +0000)
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.

30 files changed:
doc/src/sgml/catalogs.sgml
doc/src/sgml/indexam.sgml
src/backend/access/gin/ginget.c
src/backend/access/gist/gistget.c
src/backend/access/hash/hash.c
src/backend/access/index/genam.c
src/backend/access/index/indexam.c
src/backend/access/nbtree/nbtree.c
src/backend/executor/nodeBitmapHeapscan.c
src/backend/executor/nodeBitmapIndexscan.c
src/backend/nodes/tidbitmap.c
src/include/access/genam.h
src/include/access/gin.h
src/include/access/gist_private.h
src/include/access/hash.h
src/include/access/nbtree.h
src/include/access/relscan.h
src/include/catalog/catversion.h
src/include/catalog/pg_am.h
src/include/catalog/pg_proc.h
src/include/nodes/tidbitmap.h
src/include/utils/rel.h
src/test/regress/expected/bitmapops.out [new file with mode: 0644]
src/test/regress/expected/create_index.out
src/test/regress/expected/oidjoins.out
src/test/regress/parallel_schedule
src/test/regress/serial_schedule
src/test/regress/sql/bitmapops.sql [new file with mode: 0644]
src/test/regress/sql/create_index.sql
src/test/regress/sql/oidjoins.sql

index 4c92c2c77a5d90bdf4b73ee04868268af1946bcb..a6aaa4fd5a8519c01c069259de1d70b3ef0d5e08 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $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>
index 8b246719ccfcc08687e2028772706ba45c393a25..65da721de47d3a7998e1e15db7635abe263c4265 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $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>
@@ -320,23 +320,16 @@ amgettuple (IndexScanDesc scan,
 
   <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>
 
@@ -491,20 +484,17 @@ amrestrpos (IndexScanDesc scan);
 
   <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>
 
@@ -605,9 +595,8 @@ amrestrpos (IndexScanDesc scan);
   </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>
 
index 31464ab2bc3010a99fce07fdae306bec722d6fac..4fb5ee556c5dc45fa956d1787bf2219cbe558d25 100644 (file)
@@ -8,13 +8,15 @@
  * 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
@@ -476,34 +478,37 @@ scanGetItem(IndexScanDesc scan, ItemPointerData *item)
 #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
index 22a7d0ceae6700b71bb65d8f533dedb4ebac1726..4533ff8c85f9997232afac5369aad109b6825589 100644 (file)
@@ -8,7 +8,7 @@
  * 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);
 
@@ -114,32 +117,37 @@ gistgettuple(PG_FUNCTION_ARGS)
         * 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;
@@ -148,7 +156,7 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids,
        IndexTuple      it;
        GISTPageOpaque opaque;
        bool            resetoffset = false;
-       int                     ntids = 0;
+       int64           ntids = 0;
 
        so = (GISTScanOpaque) scan->opaque;
 
@@ -174,6 +182,8 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids,
 
        for (;;)
        {
+               CHECK_FOR_INTERRUPTS();
+
                /* First of all, we need lock buffer */
                Assert(so->curbuf != InvalidBuffer);
                LockBuffer(so->curbuf, GIST_SHARE);
@@ -285,20 +295,21 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids,
                                 * 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 */
                                        }
                                }
                        }
@@ -308,7 +319,6 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids,
                                 * 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));
@@ -318,7 +328,6 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids,
 
                                stk->next = so->stack->next;
                                so->stack->next = stk;
-
                        }
 
                        if (ScanDirectionIsBackward(dir))
index 01da35ec9f20605192170efbb6e628c8a69e9636..c090cfef8bb2042c7e7f278ae539508fe24cf4f1 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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.
@@ -22,6 +22,7 @@
 #include "access/hash.h"
 #include "catalog/index.h"
 #include "commands/vacuum.h"
+#include "miscadmin.h"
 #include "optimizer/cost.h"
 #include "optimizer/plancat.h"
 
@@ -275,72 +276,51 @@ hashgettuple(PG_FUNCTION_ARGS)
 
 
 /*
- *     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);
 }
 
 
index a4395cb240eb8676823d401eb5de99e4e2a8975b..8877938322d5c83b8be4a4b4c38f7a02a5b04026 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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
@@ -88,7 +88,6 @@ RelationGetIndexScan(Relation indexRelation,
        else
                scan->keyData = NULL;
 
-       scan->is_multiscan = false; /* caller may change this */
        scan->kill_prior_tuple = false;
        scan->ignore_killed_tuples = true;      /* default setting */
 
index c4739aa1cd15ab67a751f02337d7c2f27a2abc62..d59f1529db1c7033a5ccc6a7f8f99da6a9140f35 100644 (file)
@@ -8,20 +8,20 @@
  *
  *
  * 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
@@ -227,7 +227,6 @@ index_beginscan(Relation heapRelation,
         * Save additional parameters into the scandesc.  Everything else was set
         * up by RelationGetIndexScan.
         */
-       scan->is_multiscan = false;
        scan->heapRelation = heapRelation;
        scan->xs_snapshot = snapshot;
 
@@ -235,15 +234,15 @@ 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
  * 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;
 
@@ -253,7 +252,6 @@ index_beginscan_multi(Relation indexRelation,
         * Save additional parameters into the scandesc.  Everything else was set
         * up by RelationGetIndexScan.
         */
-       scan->is_multiscan = true;
        scan->xs_snapshot = snapshot;
 
        return 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
  * 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;
 }
 
 /* ----------------
index 5cfa8f315d79ee09a153c4ab72750113f62deb4d..d96348ace46eec87ebf1226d0bdccc14baa98809 100644 (file)
@@ -12,7 +12,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,6 +22,7 @@
 #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"
@@ -278,42 +279,29 @@ btgettuple(PG_FUNCTION_ARGS)
 }
 
 /*
- * 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
@@ -321,19 +309,20 @@ btgetmulti(PG_FUNCTION_ARGS)
                 */
                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);
 }
 
 /*
index 998ef91097dadd096b222f2f744cc7abb050e979..3908892bc2af72e5b64f02bc515436406a34897f 100644 (file)
@@ -21,7 +21,7 @@
  *
  *
  * 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)
                 * 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);
index fd56e862df6461f6e3a2666f05ce2492e5098085..a2b2700723ccbe74cfa72739f13e417a23d2fec1 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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;
 
@@ -91,23 +88,14 @@ MultiExecBitmapIndexScan(BitmapIndexScanState *node)
         */
        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 */
@@ -321,10 +309,10 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags)
         * 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.
index 18a260675a4602debda1ff0e5a26f9fc8f5969f9..37a2b4bfae7de53cf3d965d81b45f5909374e951 100644 (file)
  * 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;
 
@@ -244,9 +258,13 @@ tbm_free(TIDBitmap *tbm)
 
 /*
  * 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;
 
@@ -280,6 +298,7 @@ tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids)
                        bitnum = BITNUM(off - 1);
                }
                page->words[wordnum] |= ((bitmapword) 1 << bitnum);
+               page->recheck |= recheck;
 
                if (tbm->nentries > tbm->maxentries)
                        tbm_lossify(tbm);
@@ -360,6 +379,7 @@ tbm_union_page(TIDBitmap *a, const PagetableEntry *bpage)
                        /* 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;
                }
        }
 
@@ -471,22 +491,12 @@ tbm_intersect_page(TIDBitmap *a, PagetableEntry *apage, const TIDBitmap *b)
        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
@@ -504,7 +514,9 @@ tbm_intersect_page(TIDBitmap *a, PagetableEntry *apage, const TIDBitmap *b)
                                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;
        }
 }
@@ -585,7 +597,9 @@ tbm_begin_iterate(TIDBitmap *tbm)
  * 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)
@@ -638,6 +652,7 @@ 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;
                }
@@ -676,6 +691,7 @@ tbm_iterate(TIDBitmap *tbm)
                }
                output->blockno = page->blockno;
                output->ntuples = ntuples;
+               output->recheck = page->recheck;
                tbm->spageptr++;
                return output;
        }
index df3c7f0ed955e8061e36fe30397b6480c771415a..57785913394b07398119ca5a2cbda69e77454a38 100644 (file)
@@ -7,7 +7,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,6 +17,7 @@
 #include "access/relscan.h"
 #include "access/sdir.h"
 #include "nodes/primnodes.h"
+#include "nodes/tidbitmap.h"
 #include "storage/lock.h"
 
 /*
@@ -99,7 +100,7 @@ extern IndexScanDesc index_beginscan(Relation heapRelation,
                                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);
@@ -109,9 +110,7 @@ extern void index_restrpos(IndexScanDesc scan);
 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,
index d27ba66a5970ff59b831a5d97856ccf371682a6c..7a343c62c491a9d6230d882a0131838a41845990 100644 (file)
@@ -4,7 +4,7 @@
  *
  *     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;
 #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 */
index e6ca50a702f26028f9fc2ae87998433a8cbbad38..b34388b4ed149b4f8151b108b7574fa1d4dc53c8 100644 (file)
@@ -7,7 +7,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -269,7 +269,7 @@ extern XLogRecPtr gistxlogInsertCompletion(RelFileNode node, ItemPointerData *ke
 
 /* gistget.c */
 extern Datum gistgettuple(PG_FUNCTION_ARGS);
-extern Datum gistgetmulti(PG_FUNCTION_ARGS);
+extern Datum gistgetbitmap(PG_FUNCTION_ARGS);
 
 /* gistutil.c */
 
index 34275ad9d60b68fc9933d5fe4d565aac83287284..a786117ee55212db018916c4b11894ae6f1a7112 100644 (file)
@@ -7,7 +7,7 @@
  * 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.
@@ -233,7 +233,7 @@ extern Datum hashbuild(PG_FUNCTION_ARGS);
 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);
index 2bcf8ab38f417351f6c2dcabd87ff18819b27e1c..1422994506d539c685ab2f907cd6944cecf8fe08 100644 (file)
@@ -7,7 +7,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -507,7 +507,7 @@ extern Datum btbuild(PG_FUNCTION_ARGS);
 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);
index eebcc86bb30412f0649178d4b1fc760ccbb8ec46..677fd04e2c2d94c300d11dd46e0f0186350c5031 100644 (file)
@@ -7,7 +7,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -57,7 +57,7 @@ typedef HeapScanDescData *HeapScanDesc;
 
 /*
  * 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
@@ -68,7 +68,6 @@ 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 */
index c8ce4727400d75a63ec8a9213dac24df2d7c6524..a0b1a34f29cfeeb30c97235a16b0375ba67d558a 100644 (file)
@@ -37,7 +37,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200804051
+#define CATALOG_VERSION_NO     200804101
 
 #endif
index 06287979d19bd6beee895df1707a436815e79770..9837a8c200382bb1e5ad8abd13be7c6b6df92ed8 100644 (file)
@@ -8,7 +8,7 @@
  * 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
@@ -51,7 +51,7 @@ CATALOG(pg_am,2601)
        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 */
@@ -89,7 +89,7 @@ typedef FormData_pg_am *Form_pg_am;
 #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
@@ -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");
 #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
 
index 2abaeea211efcca1fd6a50cfcac2caa65e896977..7ef852666be8cd5039135d45acfbf33c5144d33c 100644 (file)
@@ -7,7 +7,7 @@
  * 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
@@ -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_ ));
 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)");
@@ -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_ ));
 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)");
@@ -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_ ));
 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)");
@@ -3967,7 +3967,7 @@ DESCR("GiST support");
 /* 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)");
index d40502b940d3f2d13b902cc24a3b7249648fc050..08eaeb0aeefabf6ba9e6631856fbacce886f4885 100644 (file)
@@ -15,7 +15,7 @@
  *
  * 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
 {
        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 */
 
@@ -44,7 +46,9 @@ typedef 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);
index f7d46193de5d396891d2f3bec099e99ab6759ce2..25b9d43845a4cd91cf4219f04947dc0f1cad7952 100644 (file)
@@ -7,7 +7,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -100,7 +100,7 @@ typedef struct RelationAmInfo
        FmgrInfo        aminsert;
        FmgrInfo        ambeginscan;
        FmgrInfo        amgettuple;
-       FmgrInfo        amgetmulti;
+       FmgrInfo        amgetbitmap;
        FmgrInfo        amrescan;
        FmgrInfo        amendscan;
        FmgrInfo        ammarkpos;
diff --git a/src/test/regress/expected/bitmapops.out b/src/test/regress/expected/bitmapops.out
new file mode 100644 (file)
index 0000000..d88a76f
--- /dev/null
@@ -0,0 +1,38 @@
+-- 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;
index b56078edf235cbbb01f009663430afcb00cefd1d..52ba630a560d9050574694d129890c4146231088 100644 (file)
@@ -174,7 +174,7 @@ RESET enable_bitmapscan;
 --
 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                                                                  
@@ -327,6 +327,95 @@ SELECT * FROM array_index_op_test WHERE t = '{AAAAAAAAAA646,A87088}' ORDER BY se
     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;
index bd55dc24ae3fcaca207913c80259e19d4ed0f00f..c57721958ff58425c03d53aaec7c93d73fcc75f7 100644 (file)
@@ -65,12 +65,12 @@ WHERE       amgettuple != 0 AND
 ------+------------
 (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 
index 8d72885bc773b9842b6af0abe159363c70341be1..f03d4179e1eb90adfac66db429965b21c856e213 100644 (file)
@@ -1,5 +1,5 @@
 # ----------
-# $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.
@@ -77,7 +77,7 @@ test: misc
 # ----------
 # 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
index 49911961f5330888748c29402cf75a60e74dae98..34c75f6c5cde9513ec696ecf2cfbcc7730728492 100644 (file)
@@ -1,4 +1,4 @@
-# $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
@@ -92,6 +92,7 @@ test: foreign_key
 test: cluster
 test: dependency
 test: guc
+test: bitmapops
 test: combocid
 test: tsearch
 test: plancache
diff --git a/src/test/regress/sql/bitmapops.sql b/src/test/regress/sql/bitmapops.sql
new file mode 100644 (file)
index 0000000..0b5477e
--- /dev/null
@@ -0,0 +1,41 @@
+-- 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;
index 14f2f281ff8456aa84d4e1e1232f379e101f2e1f..447c5df37acfaa5ec8a747933df70c98f6de24a9 100644 (file)
@@ -143,7 +143,7 @@ RESET enable_bitmapscan;
 
 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);
 
@@ -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 = '{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;
index 773c2afe7faf69992ba27c36934237ec46653864..7a072d4fd3dcd13efc22e09b1b8cea39af69fd0a 100644 (file)
@@ -33,10 +33,10 @@ SELECT      ctid, amgettuple
 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