]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Replace inefficient _bt_invokestrat calls with direct calls to the
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 18 Feb 2000 06:32:39 +0000 (06:32 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 18 Feb 2000 06:32:39 +0000 (06:32 +0000)
appropriate btree three-way comparison routine.  Not clear why the
three-way comparison routines were being used in some paths and not
others in btree --- incomplete changes by someone long ago, maybe?
Anyway, this makes for a nice speedup in CREATE INDEX.

src/backend/access/nbtree/nbtinsert.c
src/backend/access/nbtree/nbtsearch.c
src/backend/access/nbtree/nbtsort.c
src/backend/access/nbtree/nbtstrat.c
src/backend/access/nbtree/nbtutils.c
src/backend/utils/sort/tuplesort.c
src/include/access/nbtree.h

index a4153288dd7b5eb79c688b0bc96b74ecd6a02364..463a0f00fe30cefbe22d779e7fe36351246b6744 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.54 2000/01/26 05:55:58 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.55 2000/02/18 06:32:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 
 static InsertIndexResult _bt_insertonpg(Relation rel, Buffer buf, BTStack stack, int keysz, ScanKey scankey, BTItem btitem, BTItem afteritem);
-static Buffer _bt_split(Relation rel, Buffer buf, OffsetNumber firstright);
-static OffsetNumber _bt_findsplitloc(Relation rel, Page page, OffsetNumber start, OffsetNumber maxoff, Size llimit);
+static Buffer _bt_split(Relation rel, Size keysz, ScanKey scankey,
+                                               Buffer buf, OffsetNumber firstright);
+static OffsetNumber _bt_findsplitloc(Relation rel, Size keysz, ScanKey scankey,
+                                                                        Page page, OffsetNumber start,
+                                                                        OffsetNumber maxoff, Size llimit);
 static void _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf);
 static OffsetNumber _bt_pgaddtup(Relation rel, Buffer buf, int keysz, ScanKey itup_scankey, Size itemsize, BTItem btitem, BTItem afteritem);
 static bool _bt_goesonpg(Relation rel, Buffer buf, Size keysz, ScanKey scankey, BTItem afteritem);
@@ -297,7 +300,7 @@ _bt_insertonpg(Relation rel,
                hitemid = PageGetItemId(page, P_HIKEY);
                hitem = (BTItem) PageGetItem(page, hitemid);
                if (maxoff > P_HIKEY &&
-                       !_bt_itemcmp(rel, keysz, hitem,
+                       !_bt_itemcmp(rel, keysz, scankey, hitem,
                         (BTItem) PageGetItem(page, PageGetItemId(page, P_FIRSTKEY)),
                                                 BTEqualStrategyNumber))
                        elog(FATAL, "btree: bad key on the page in the chain of duplicates");
@@ -373,7 +376,8 @@ _bt_insertonpg(Relation rel,
                        {
                                itid = PageGetItemId(page, offnum);
                                chkitem = (BTItem) PageGetItem(page, itid);
-                               if (!_bt_itemcmp(rel, keysz, previtem, chkitem,
+                               if (!_bt_itemcmp(rel, keysz, scankey,
+                                                                previtem, chkitem,
                                                                 BTEqualStrategyNumber))
                                {
                                        if (currsize > maxsize)
@@ -471,9 +475,10 @@ _bt_insertonpg(Relation rel,
                                MAXALIGN(sizeof(BTPageOpaqueData))
                                +sizeof(ItemIdData);
                        llimit /= 2;
-                       firstright = _bt_findsplitloc(rel, page, start, maxoff, llimit);
+                       firstright = _bt_findsplitloc(rel, keysz, scankey,
+                                                                                 page, start, maxoff, llimit);
 
-                       if (_bt_itemcmp(rel, keysz,
+                       if (_bt_itemcmp(rel, keysz, scankey,
                                  (BTItem) PageGetItem(page, PageGetItemId(page, start)),
                         (BTItem) PageGetItem(page, PageGetItemId(page, firstright)),
                                                        BTEqualStrategyNumber))
@@ -503,7 +508,8 @@ _bt_insertonpg(Relation rel,
                                                ItemPointerSet(&(stack->bts_btitem->bti_itup.t_tid),
                                                                           bknum, P_HIKEY);
                                                pbuf = _bt_getstackbuf(rel, stack, BT_WRITE);
-                                               if (_bt_itemcmp(rel, keysz, stack->bts_btitem,
+                                               if (_bt_itemcmp(rel, keysz, scankey,
+                                                                               stack->bts_btitem,
                                                                                (BTItem) PageGetItem(page,
                                                                                         PageGetItemId(page, start)),
                                                                                BTLessStrategyNumber))
@@ -519,7 +525,7 @@ _bt_insertonpg(Relation rel,
                }
 
                /* split the buffer into left and right halves */
-               rbuf = _bt_split(rel, buf, firstright);
+               rbuf = _bt_split(rel, keysz, scankey, buf, firstright);
 
                /* which new page (left half or right half) gets the tuple? */
                if (_bt_goesonpg(rel, buf, keysz, scankey, afteritem))
@@ -550,7 +556,7 @@ _bt_insertonpg(Relation rel,
                                elog(FATAL, "btree: un-shifted page is empty");
                        lowLeftItem = (BTItem) PageGetItem(page,
                                                                                PageGetItemId(page, P_FIRSTKEY));
-                       if (_bt_itemcmp(rel, keysz, lowLeftItem,
+                       if (_bt_itemcmp(rel, keysz, scankey, lowLeftItem,
                                (BTItem) PageGetItem(page, PageGetItemId(page, P_HIKEY)),
                                                        BTEqualStrategyNumber))
                                lpageop->btpo_flags |= BTP_CHAIN;
@@ -613,7 +619,8 @@ l_spl:      ;
                        {
                                ritem = (BTItem) PageGetItem(rpage,
                                                                           PageGetItemId(rpage, P_FIRSTKEY));
-                               if (_bt_itemcmp(rel, keysz, ritem,
+                               if (_bt_itemcmp(rel, keysz, scankey,
+                                                               ritem,
                                                                (BTItem) PageGetItem(rpage,
                                                                                  PageGetItemId(rpage, P_HIKEY)),
                                                                BTEqualStrategyNumber))
@@ -663,13 +670,16 @@ l_spl:    ;
                         * possible in splitting leftmost page) and current parent
                         * item == new_item.            - vadim 05/27/97
                         */
-                       if (_bt_itemcmp(rel, keysz, stack->bts_btitem, new_item,
+                       if (_bt_itemcmp(rel, keysz, scankey,
+                                                       stack->bts_btitem, new_item,
                                                        BTGreaterStrategyNumber) ||
                                (!shifted &&
-                                _bt_itemcmp(rel, keysz, stack->bts_btitem,
-                                                        new_item, BTEqualStrategyNumber) &&
-                                _bt_itemcmp(rel, keysz, lowLeftItem,
-                                                        new_item, BTLessStrategyNumber)))
+                                _bt_itemcmp(rel, keysz, scankey,
+                                                        stack->bts_btitem, new_item,
+                                                        BTEqualStrategyNumber) &&
+                                _bt_itemcmp(rel, keysz, scankey,
+                                                        lowLeftItem, new_item,
+                                                        BTLessStrategyNumber)))
                        {
                                do_update = true;
 
@@ -831,7 +841,8 @@ l_spl:      ;
  *             pin and lock on buf are maintained.
  */
 static Buffer
-_bt_split(Relation rel, Buffer buf, OffsetNumber firstright)
+_bt_split(Relation rel, Size keysz, ScanKey scankey,
+                 Buffer buf, OffsetNumber firstright)
 {
        Buffer          rbuf;
        Page            origpage;
@@ -915,7 +926,8 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright)
        {
                Size            llimit = PageGetFreeSpace(leftpage) / 2;
 
-               firstright = _bt_findsplitloc(rel, origpage, start, maxoff, llimit);
+               firstright = _bt_findsplitloc(rel, keysz, scankey,
+                                                                         origpage, start, maxoff, llimit);
        }
 
        for (i = start; i <= maxoff; i = OffsetNumberNext(i))
@@ -1027,6 +1039,8 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright)
  */
 static OffsetNumber
 _bt_findsplitloc(Relation rel,
+                                Size keysz,
+                                ScanKey scankey,
                                 Page page,
                                 OffsetNumber start,
                                 OffsetNumber maxoff,
@@ -1039,12 +1053,10 @@ _bt_findsplitloc(Relation rel,
        BTItem          safeitem,
                                nxtitem;
        Size            nbytes;
-       int                     natts;
 
        if (start >= maxoff)
                elog(FATAL, "btree: cannot split if start (%d) >= maxoff (%d)",
                         start, maxoff);
-       natts = rel->rd_rel->relnatts;
        saferight = start;
        safeitemid = PageGetItemId(page, saferight);
        nbytes = ItemIdGetLength(safeitemid) + sizeof(ItemIdData);
@@ -1064,7 +1076,7 @@ _bt_findsplitloc(Relation rel,
                 * at isn't equal to the last safe one we saw, then it's our new
                 * safe tuple.
                 */
-               if (!_bt_itemcmp(rel, natts,
+               if (!_bt_itemcmp(rel, keysz, scankey,
                                                 safeitem, nxtitem, BTEqualStrategyNumber))
                {
                        safeitem = nxtitem;
@@ -1345,92 +1357,94 @@ _bt_goesonpg(Relation rel,
 }
 
 /*
- *             _bt_itemcmp() -- compare item1 to item2 using a requested
- *                                              strategy (<, <=, =, >=, >)
+ *             _bt_tuplecompare() -- compare two IndexTuples,
+ *                                                       return -1, 0, or +1
  *
  */
-bool
-_bt_itemcmp(Relation rel,
-                       Size keysz,
-                       BTItem item1,
-                       BTItem item2,
-                       StrategyNumber strat)
+int32
+_bt_tuplecompare(Relation rel,
+                                Size keysz,
+                                ScanKey scankey,
+                                IndexTuple tuple1,
+                                IndexTuple tuple2)
 {
        TupleDesc       tupDes;
-       IndexTuple      indexTuple1,
-                               indexTuple2;
-       Datum           attrDatum1,
-                               attrDatum2;
        int                     i;
-       bool            isFirstNull,
-                               isSecondNull;
-       bool            compare;
-       bool            useEqual = false;
-
-       if (strat == BTLessEqualStrategyNumber)
-       {
-               useEqual = true;
-               strat = BTLessStrategyNumber;
-       }
-       else if (strat == BTGreaterEqualStrategyNumber)
-       {
-               useEqual = true;
-               strat = BTGreaterStrategyNumber;
-       }
+       int32           compare = 0;
 
        tupDes = RelationGetDescr(rel);
-       indexTuple1 = &(item1->bti_itup);
-       indexTuple2 = &(item2->bti_itup);
 
        for (i = 1; i <= keysz; i++)
        {
-               attrDatum1 = index_getattr(indexTuple1, i, tupDes, &isFirstNull);
-               attrDatum2 = index_getattr(indexTuple2, i, tupDes, &isSecondNull);
+               ScanKey         entry = &scankey[i - 1];
+               Datum           attrDatum1,
+                                       attrDatum2;
+               bool            isFirstNull,
+                                       isSecondNull;
+
+               attrDatum1 = index_getattr(tuple1, i, tupDes, &isFirstNull);
+               attrDatum2 = index_getattr(tuple2, i, tupDes, &isSecondNull);
 
                /* see comments about NULLs handling in btbuild */
-               if (isFirstNull)                /* attr in item1 is NULL */
+               if (isFirstNull)                /* attr in tuple1 is NULL */
                {
-                       if (isSecondNull)       /* attr in item2 is NULL too */
-                               compare = (strat == BTEqualStrategyNumber) ? true : false;
+                       if (isSecondNull)       /* attr in tuple2 is NULL too */
+                               compare = 0;
                        else
-                               compare = (strat == BTGreaterStrategyNumber) ? true : false;
+                               compare = 1;    /* NULL ">" not-NULL */
                }
-               else if (isSecondNull)  /* attr in item1 is NOT_NULL and */
-               {                                               /* and attr in item2 is NULL */
-                       compare = (strat == BTLessStrategyNumber) ? true : false;
+               else if (isSecondNull)  /* attr in tuple1 is NOT_NULL and */
+               {                                               /* attr in tuple2 is NULL */
+                       compare = -1;           /* not-NULL "<" NULL */
                }
                else
-                       compare = _bt_invokestrat(rel, i, strat, attrDatum1, attrDatum2);
-
-               if (compare)                    /* true for one of ">, <, =" */
                {
-                       if (strat != BTEqualStrategyNumber)
-                               return true;
+                       compare = (int32) FMGR_PTR2(&entry->sk_func,
+                                                                               attrDatum1, attrDatum2);
                }
-               else
-/* false for one of ">, <, =" */
-               {
-                       if (strat == BTEqualStrategyNumber)
-                               return false;
 
-                       /*
-                        * if original strat was "<=, >=" OR "<, >" but some
-                        * attribute(s) left - need to test for Equality
-                        */
-                       if (useEqual || i < keysz)
-                       {
-                               if (isFirstNull || isSecondNull)
-                                       compare = (isFirstNull && isSecondNull) ? true : false;
-                               else
-                                       compare = _bt_invokestrat(rel, i, BTEqualStrategyNumber,
-                                                                                         attrDatum1, attrDatum2);
-                               if (compare)    /* item1' and item2' attributes are equal */
-                                       continue;       /* - try to compare next attributes */
-                       }
-                       return false;
-               }
+               if (compare != 0)
+                       break;                          /* done when we find unequal attributes */
        }
-       return true;
+
+       return compare;
+}
+
+/*
+ *             _bt_itemcmp() -- compare two BTItems using a requested
+ *                                              strategy (<, <=, =, >=, >)
+ *
+ */
+bool
+_bt_itemcmp(Relation rel,
+                       Size keysz,
+                       ScanKey scankey,
+                       BTItem item1,
+                       BTItem item2,
+                       StrategyNumber strat)
+{
+       int32           compare;
+
+       compare = _bt_tuplecompare(rel, keysz, scankey,
+                                                          &(item1->bti_itup),
+                                                          &(item2->bti_itup));
+
+       switch (strat)
+       {
+               case BTLessStrategyNumber:
+                       return (bool) (compare < 0);
+               case BTLessEqualStrategyNumber:
+                       return (bool) (compare <= 0);
+               case BTEqualStrategyNumber:
+                       return (bool) (compare == 0);
+               case BTGreaterEqualStrategyNumber:
+                       return (bool) (compare >= 0);
+               case BTGreaterStrategyNumber:
+                       return (bool) (compare > 0);
+       }
+
+       elog(ERROR, "_bt_itemcmp: bogus strategy %d", (int) strat);
+       return false;
 }
 
 /*
@@ -1585,7 +1599,7 @@ _bt_shift(Relation rel, Buffer buf, BTStack stack, int keysz,
        /* init old page opaque */
        pageop->btpo_flags = npageop->btpo_flags;       /* restore flags */
        pageop->btpo_flags &= ~BTP_CHAIN;
-       if (_bt_itemcmp(rel, keysz, hikey, btitem, BTEqualStrategyNumber))
+       if (_bt_itemcmp(rel, keysz, scankey, hikey, btitem, BTEqualStrategyNumber))
                pageop->btpo_flags |= BTP_CHAIN;
        pageop->btpo_prev = npageop->btpo_prev;         /* restore prev */
        pageop->btpo_next = nbknum; /* next points to the new page */
index a22e042c1cf51fafeb36510a8dd9fa392ec11653..99a172e46d838f24eb75e9729de66be676a2f2a6 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.56 2000/01/26 05:55:58 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.57 2000/02/18 06:32:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -264,36 +264,21 @@ _bt_skeycmp(Relation rel,
        BTItem          item;
        IndexTuple      indexTuple;
        TupleDesc       tupDes;
-       ScanKey         entry;
        int                     i;
-       Datum           attrDatum;
-       Datum           keyDatum;
-       bool            compare;
-       bool            isNull;
-       bool            useEqual = false;
-       bool            keyNull;
-
-       if (strat == BTLessEqualStrategyNumber)
-       {
-               useEqual = true;
-               strat = BTLessStrategyNumber;
-       }
-       else if (strat == BTGreaterEqualStrategyNumber)
-       {
-               useEqual = true;
-               strat = BTGreaterStrategyNumber;
-       }
+       int32           compare = 0;
 
        item = (BTItem) PageGetItem(page, itemid);
        indexTuple = &(item->bti_itup);
 
        tupDes = RelationGetDescr(rel);
 
-       /* see if the comparison is true for all of the key attributes */
        for (i = 1; i <= keysz; i++)
        {
+               ScanKey         entry = &scankey[i - 1];
+               Datum           attrDatum;
+               bool            isNull;
+               Datum           keyDatum;
 
-               entry = &scankey[i - 1];
                Assert(entry->sk_attno == i);
                attrDatum = index_getattr(indexTuple,
                                                                  entry->sk_attno,
@@ -304,54 +289,40 @@ _bt_skeycmp(Relation rel,
                /* see comments about NULLs handling in btbuild */
                if (entry->sk_flags & SK_ISNULL)                /* key is NULL */
                {
-                       Assert(entry->sk_procedure == F_NULLVALUE);
-                       keyNull = true;
                        if (isNull)
-                               compare = (strat == BTEqualStrategyNumber) ? true : false;
+                               compare = 0;    /* NULL key "=" NULL datum */
                        else
-                               compare = (strat == BTGreaterStrategyNumber) ? true : false;
+                               compare = 1;    /* NULL key ">" not-NULL datum */
                }
                else if (isNull)                /* key is NOT_NULL and item is NULL */
                {
-                       keyNull = false;
-                       compare = (strat == BTLessStrategyNumber) ? true : false;
+                       compare = -1;           /* not-NULL key "<" NULL datum */
                }
                else
                {
-                       keyNull = false;
-                       compare = _bt_invokestrat(rel, i, strat, keyDatum, attrDatum);
+                       compare = (int32) FMGR_PTR2(&entry->sk_func, keyDatum, attrDatum);
                }
 
-               if (compare)                    /* true for one of ">, <, =" */
-               {
-                       if (strat != BTEqualStrategyNumber)
-                               return true;
-               }
-               else
-/* false for one of ">, <, =" */
-               {
-                       if (strat == BTEqualStrategyNumber)
-                               return false;
+               if (compare != 0)
+                       break;                          /* done when we find unequal attributes */
+       }
 
-                       /*
-                        * if original strat was "<=, >=" OR "<, >" but some
-                        * attribute(s) left - need to test for Equality
-                        */
-                       if (useEqual || i < keysz)
-                       {
-                               if (keyNull || isNull)
-                                       compare = (keyNull && isNull) ? true : false;
-                               else
-                                       compare = _bt_invokestrat(rel, i, BTEqualStrategyNumber,
-                                                                                         keyDatum, attrDatum);
-                               if (compare)    /* key' and item' attributes are equal */
-                                       continue;       /* - try to compare next attributes */
-                       }
-                       return false;
-               }
+       switch (strat)
+       {
+               case BTLessStrategyNumber:
+                       return (bool) (compare < 0);
+               case BTLessEqualStrategyNumber:
+                       return (bool) (compare <= 0);
+               case BTEqualStrategyNumber:
+                       return (bool) (compare == 0);
+               case BTGreaterEqualStrategyNumber:
+                       return (bool) (compare >= 0);
+               case BTGreaterStrategyNumber:
+                       return (bool) (compare > 0);
        }
 
-       return true;
+       elog(ERROR, "_bt_skeycmp: bogus strategy %d", (int) strat);
+       return false;
 }
 
 /*
@@ -610,7 +581,6 @@ _bt_compare(Relation rel,
                /* see comments about NULLs handling in btbuild */
                if (entry->sk_flags & SK_ISNULL)                /* key is NULL */
                {
-                       Assert(entry->sk_procedure == F_NULLVALUE);
                        if (null)
                                tmpres = (long) 0;              /* NULL "=" NULL */
                        else
index f92a626e1784d86059d486564aff8f535128412a..f9cbf7121ff4fb078723e226e6e81255dbbc3d48 100644 (file)
@@ -28,7 +28,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsort.c,v 1.50 2000/01/26 05:55:59 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsort.c,v 1.51 2000/02/18 06:32:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -69,12 +69,13 @@ struct BTSpool
 
 
 static void _bt_load(Relation index, BTSpool *btspool);
-static BTItem _bt_buildadd(Relation index, BTPageState *state, BTItem bti,
-                                                  int flags);
+static BTItem _bt_buildadd(Relation index, Size keysz, ScanKey scankey,
+                                                  BTPageState *state, BTItem bti, int flags);
 static BTItem _bt_minitem(Page opage, BlockNumber oblkno, int atend);
 static BTPageState *_bt_pagestate(Relation index, int flags,
                                                                  int level, bool doupper);
-static void _bt_uppershutdown(Relation index, BTPageState *state);
+static void _bt_uppershutdown(Relation index, Size keysz, ScanKey scankey,
+                                                         BTPageState *state);
 
 
 /*
@@ -282,7 +283,8 @@ _bt_minitem(Page opage, BlockNumber oblkno, int atend)
  * if all keys are unique, 'first' will always be the same as 'last'.
  */
 static BTItem
-_bt_buildadd(Relation index, BTPageState *state, BTItem bti, int flags)
+_bt_buildadd(Relation index, Size keysz, ScanKey scankey,
+                        BTPageState *state, BTItem bti, int flags)
 {
        Buffer          nbuf;
        Page            npage;
@@ -402,7 +404,7 @@ _bt_buildadd(Relation index, BTPageState *state, BTItem bti, int flags)
                        nopaque->btpo_prev = BufferGetBlockNumber(obuf);
                        nopaque->btpo_next = P_NONE;
 
-                       if (_bt_itemcmp(index, index->rd_att->natts,
+                       if (_bt_itemcmp(index, keysz, scankey,
                          (BTItem) PageGetItem(opage, PageGetItemId(opage, P_HIKEY)),
                        (BTItem) PageGetItem(opage, PageGetItemId(opage, P_FIRSTKEY)),
                                                        BTEqualStrategyNumber))
@@ -424,7 +426,7 @@ _bt_buildadd(Relation index, BTPageState *state, BTItem bti, int flags)
                                        _bt_pagestate(index, 0, state->btps_level + 1, true);
                        }
                        nbti = _bt_minitem(opage, BufferGetBlockNumber(obuf), 0);
-                       _bt_buildadd(index, state->btps_next, nbti, 0);
+                       _bt_buildadd(index, keysz, scankey, state->btps_next, nbti, 0);
                        pfree((void *) nbti);
                }
 
@@ -454,7 +456,7 @@ _bt_buildadd(Relation index, BTPageState *state, BTItem bti, int flags)
 #endif
        if (last_bti == (BTItem) NULL)
                first_off = P_FIRSTKEY;
-       else if (!_bt_itemcmp(index, index->rd_att->natts,
+       else if (!_bt_itemcmp(index, keysz, scankey,
                                                  bti, last_bti, BTEqualStrategyNumber))
                first_off = off;
        last_off = off;
@@ -470,7 +472,8 @@ _bt_buildadd(Relation index, BTPageState *state, BTItem bti, int flags)
 }
 
 static void
-_bt_uppershutdown(Relation index, BTPageState *state)
+_bt_uppershutdown(Relation index, Size keysz, ScanKey scankey,
+                                 BTPageState *state)
 {
        BTPageState *s;
        BlockNumber blkno;
@@ -499,7 +502,7 @@ _bt_uppershutdown(Relation index, BTPageState *state)
                        else
                        {
                                bti = _bt_minitem(s->btps_page, blkno, 0);
-                               _bt_buildadd(index, s->btps_next, bti, 0);
+                               _bt_buildadd(index, keysz, scankey, s->btps_next, bti, 0);
                                pfree((void *) bti);
                        }
                }
@@ -521,6 +524,8 @@ static void
 _bt_load(Relation index, BTSpool *btspool)
 {
        BTPageState *state;
+       ScanKey         skey;
+       int                     natts;
        BTItem          bti;
        bool            should_free;
 
@@ -529,93 +534,21 @@ _bt_load(Relation index, BTSpool *btspool)
         */
        state = _bt_pagestate(index, BTP_LEAF, 0, true);
 
+       skey = _bt_mkscankey_nodata(index);
+       natts = RelationGetNumberOfAttributes(index);
+
        for (;;)
        {
                bti = (BTItem) tuplesort_getindextuple(btspool->sortstate, true,
                                                                                           &should_free);
                if (bti == (BTItem) NULL)
                        break;
-               _bt_buildadd(index, state, bti, BTP_LEAF);
+               _bt_buildadd(index, natts, skey, state, bti, BTP_LEAF);
                if (should_free)
                        pfree((void *) bti);
        }
 
-       _bt_uppershutdown(index, state);
-}
-
+       _bt_uppershutdown(index, natts, skey, state);
 
-/*
- * given the (appropriately side-linked) leaf pages of a btree,
- * construct the corresponding upper levels.  we do this by inserting
- * minimum keys from each page into parent pages as needed.  the
- * format of the internal pages is otherwise the same as for leaf
- * pages.
- *
- * this routine is not called during conventional bulk-loading (in
- * which case we can just build the upper levels as we create the
- * sorted bottom level).  it is only used for index recycling.
- */
-#ifdef NOT_USED
-void
-_bt_upperbuild(Relation index)
-{
-       Buffer          rbuf;
-       BlockNumber blk;
-       Page            rpage;
-       BTPageOpaque ropaque;
-       BTPageState *state;
-       BTItem          nbti;
-
-       /*
-        * find the first leaf block.  while we're at it, clear the BTP_ROOT
-        * flag that we set while building it (so we could find it later).
-        */
-       rbuf = _bt_getroot(index, BT_WRITE);
-       blk = BufferGetBlockNumber(rbuf);
-       rpage = BufferGetPage(rbuf);
-       ropaque = (BTPageOpaque) PageGetSpecialPointer(rpage);
-       ropaque->btpo_flags &= ~BTP_ROOT;
-       _bt_wrtbuf(index, rbuf);
-
-       state = _bt_pagestate(index, 0, 0, true);
-
-       /* for each page... */
-       do
-       {
-#ifdef NOT_USED
-               printf("\t\tblk=%d\n", blk);
-#endif
-               rbuf = _bt_getbuf(index, blk, BT_READ);
-               rpage = BufferGetPage(rbuf);
-               ropaque = (BTPageOpaque) PageGetSpecialPointer(rpage);
-
-               /* for each item... */
-               if (!PageIsEmpty(rpage))
-               {
-
-                       /*
-                        * form a new index tuple corresponding to the minimum key of
-                        * the lower page and insert it into a page at this level.
-                        */
-                       nbti = _bt_minitem(rpage, blk, P_RIGHTMOST(ropaque));
-#ifdef FASTBUILD_DEBUG
-                       {
-                               bool            isnull;
-                               Datum           d = index_getattr(&(nbti->bti_itup), 1, index->rd_att,
-                                                                                         &isnull);
-
-                               printf("_bt_upperbuild: inserting <%x> at %d\n",
-                                          d, state->btps_level);
-                       }
-#endif
-                       _bt_buildadd(index, state, nbti, 0);
-                       pfree((void *) nbti);
-               }
-               blk = ropaque->btpo_next;
-               _bt_relbuf(index, rbuf, BT_READ);
-       } while (blk != P_NONE);
-
-       _bt_uppershutdown(index, state);
+       _bt_freeskey(skey);
 }
-
-#endif
index 7fbf80dd4451ec61fa4d470d50a9b55ac27939c0..57f33205fdb0a50e6fb016f96519fc335c80faae 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/nbtree/Attic/nbtstrat.c,v 1.11 2000/01/26 05:55:59 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/nbtree/Attic/nbtstrat.c,v 1.12 2000/02/18 06:32:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -118,6 +118,8 @@ _bt_getstrat(Relation rel,
        return strat;
 }
 
+#ifdef NOT_USED
+
 bool
 _bt_invokestrat(Relation rel,
                                AttrNumber attno,
@@ -128,3 +130,5 @@ _bt_invokestrat(Relation rel,
        return (RelationInvokeStrategy(rel, &BTEvaluationData, attno, strat,
                                                                   left, right));
 }
+
+#endif
index 3d79384abdc2e3d95680bea8ab33e62e571f6d43..9d1cc7b10d0531f07d566b8847f56bc2f28e4a7d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtutils.c,v 1.34 2000/01/26 05:55:59 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtutils.c,v 1.35 2000/02/18 06:32:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 extern int     NIndexTupleProcessed;
 
 
-
+/*
+ * _bt_mkscankey
+ *             Build a scan key that contains comparison data from itup
+ *             as well as comparator routines appropriate to the key datatypes.
+ *
+ *             The result is intended for use with _bt_skeycmp() or _bt_compare(),
+ *             although it could be used with _bt_itemcmp() or _bt_tuplecompare().
+ */
 ScanKey
 _bt_mkscankey(Relation rel, IndexTuple itup)
 {
@@ -31,35 +38,67 @@ _bt_mkscankey(Relation rel, IndexTuple itup)
        TupleDesc       itupdesc;
        int                     natts;
        int                     i;
-       Datum           arg;
        RegProcedure proc;
+       Datum           arg;
        bool            null;
        bits16          flag;
 
-       natts = rel->rd_rel->relnatts;
        itupdesc = RelationGetDescr(rel);
+       natts = RelationGetNumberOfAttributes(rel);
 
        skey = (ScanKey) palloc(natts * sizeof(ScanKeyData));
 
        for (i = 0; i < natts; i++)
        {
+               proc = index_getprocid(rel, i + 1, BTORDER_PROC);
                arg = index_getattr(itup, i + 1, itupdesc, &null);
-               if (null)
-               {
-                       proc = F_NULLVALUE;
-                       flag = SK_ISNULL;
-               }
-               else
-               {
-                       proc = index_getprocid(rel, i + 1, BTORDER_PROC);
-                       flag = 0x0;
-               }
-               ScanKeyEntryInitialize(&skey[i], flag, (AttrNumber) (i + 1), proc, arg);
+               flag = null ? SK_ISNULL : 0x0;
+               ScanKeyEntryInitialize(&skey[i],
+                                                          flag,
+                                                          (AttrNumber) (i + 1),
+                                                          proc,
+                                                          arg);
        }
 
        return skey;
 }
 
+/*
+ * _bt_mkscankey_nodata
+ *             Build a scan key that contains comparator routines appropriate to
+ *             the key datatypes, but no comparison data.
+ *
+ *             The result can be used with _bt_itemcmp() or _bt_tuplecompare(),
+ *             but not with _bt_skeycmp() or _bt_compare().
+ */
+ScanKey
+_bt_mkscankey_nodata(Relation rel)
+{
+       ScanKey         skey;
+       int                     natts;
+       int                     i;
+       RegProcedure proc;
+
+       natts = RelationGetNumberOfAttributes(rel);
+
+       skey = (ScanKey) palloc(natts * sizeof(ScanKeyData));
+
+       for (i = 0; i < natts; i++)
+       {
+               proc = index_getprocid(rel, i + 1, BTORDER_PROC);
+               ScanKeyEntryInitialize(&skey[i],
+                                                          SK_ISNULL,
+                                                          (AttrNumber) (i + 1),
+                                                          proc,
+                                                          (Datum) NULL);
+       }
+
+       return skey;
+}
+
+/*
+ * free a scan key made by either _bt_mkscankey or _bt_mkscankey_nodata.
+ */
 void
 _bt_freeskey(ScanKey skey)
 {
index 1d0ed4e9f2f06e7e2fea04f41926eb81fea9e0d9..be80b246a2b99949e0b8bcbdd2919437663bc6e3 100644 (file)
@@ -78,7 +78,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplesort.c,v 1.5 2000/01/26 05:57:33 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplesort.c,v 1.6 2000/02/18 06:32:30 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -253,6 +253,7 @@ struct Tuplesortstate
         * by tuplesort_begin_index and used only by the IndexTuple routines.
         */
        Relation        indexRel;
+       ScanKey         indexScanKey;
        bool            enforceUnique;  /* complain if we find duplicate tuples */
 
        /*
@@ -476,6 +477,8 @@ tuplesort_begin_index(Relation indexRel,
        state->tuplesize = tuplesize_index;
 
        state->indexRel = indexRel;
+       /* see comments below about btree dependence of this code... */
+       state->indexScanKey = _bt_mkscankey_nodata(indexRel);
        state->enforceUnique = enforceUnique;
 
        return state;
@@ -1745,40 +1748,56 @@ tuplesize_heap(Tuplesortstate *state, void *tup)
 static int
 comparetup_index(Tuplesortstate *state, const void *a, const void *b)
 {
-       IndexTuple      ltup = (IndexTuple) a;
-       IndexTuple      rtup = (IndexTuple) b;
-       TupleDesc       itdesc = state->indexRel->rd_att;
-       bool            equal_isnull = false;
+       /*
+        * This is almost the same as _bt_tuplecompare(), but we need to
+        * keep track of whether any null fields are present.
+        */
+       IndexTuple      tuple1 = (IndexTuple) a;
+       IndexTuple      tuple2 = (IndexTuple) b;
+       Relation        rel = state->indexRel;
+       Size            keysz = RelationGetNumberOfAttributes(rel);
+       ScanKey         scankey = state->indexScanKey;
+       TupleDesc       tupDes;
        int                     i;
+       bool            equal_hasnull = false;
 
-       for (i = 1; i <= itdesc->natts; i++)
-       {
-               Datum           lattr,
-                                       rattr;
-               bool            isnull1,
-                                       isnull2;
-
-               lattr = index_getattr(ltup, i, itdesc, &isnull1);
-               rattr = index_getattr(rtup, i, itdesc, &isnull2);
+       tupDes = RelationGetDescr(rel);
 
-               if (isnull1)
+       for (i = 1; i <= keysz; i++)
+       {
+               ScanKey         entry = &scankey[i - 1];
+               Datum           attrDatum1,
+                                       attrDatum2;
+               bool            isFirstNull,
+                                       isSecondNull;
+               int32           compare;
+
+               attrDatum1 = index_getattr(tuple1, i, tupDes, &isFirstNull);
+               attrDatum2 = index_getattr(tuple2, i, tupDes, &isSecondNull);
+
+               /* see comments about NULLs handling in btbuild */
+               if (isFirstNull)                /* attr in tuple1 is NULL */
                {
-                       if (!isnull2)
-                               return 1;               /* NULL sorts after non-NULL */
-                       equal_isnull = true;
-                       continue;
+                       if (isSecondNull)       /* attr in tuple2 is NULL too */
+                       {
+                               compare = 0;
+                               equal_hasnull = true;
+                       }
+                       else
+                               compare = 1;    /* NULL ">" not-NULL */
+               }
+               else if (isSecondNull)  /* attr in tuple1 is NOT_NULL and */
+               {                                               /* attr in tuple2 is NULL */
+                       compare = -1;           /* not-NULL "<" NULL */
+               }
+               else
+               {
+                       compare = (int32) FMGR_PTR2(&entry->sk_func,
+                                                                               attrDatum1, attrDatum2);
                }
-               else if (isnull2)
-                       return -1;
 
-               if (_bt_invokestrat(state->indexRel, i,
-                                                       BTGreaterStrategyNumber,
-                                                       lattr, rattr))
-                       return 1;
-               if (_bt_invokestrat(state->indexRel, i,
-                                                       BTGreaterStrategyNumber,
-                                                       rattr, lattr))
-                       return -1;
+               if (compare != 0)
+                       return (int) compare; /* done when we find unequal attributes */
        }
 
        /*
@@ -1790,7 +1809,7 @@ comparetup_index(Tuplesortstate *state, const void *a, const void *b)
         * the sort algorithm wouldn't have checked whether one must appear
         * before the other.
         */
-       if (state->enforceUnique && !equal_isnull)
+       if (state->enforceUnique && !equal_hasnull)
                elog(ERROR, "Cannot create unique index. Table contains non-unique values");
 
        return 0;
index 486d193622f069011fb5a2378201f23036cd64b0..7262402dcb9c2ae750fa5cfe367ef68009803ab9 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nbtree.h,v 1.33 2000/01/26 05:57:50 momjian Exp $
+ * $Id: nbtree.h,v 1.34 2000/02/18 06:32:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -204,11 +204,11 @@ typedef struct BTPageState
  * prototypes for functions in nbtinsert.c
  */
 extern InsertIndexResult _bt_doinsert(Relation rel, BTItem btitem,
-                        bool index_is_unique, Relation heapRel);
-
- /* default is to allow duplicates */
-extern bool _bt_itemcmp(Relation rel, Size keysz, BTItem item1, BTItem item2,
-                       StrategyNumber strat);
+                                                                         bool index_is_unique, Relation heapRel);
+extern int32 _bt_tuplecompare(Relation rel, Size keysz, ScanKey scankey,
+                                                         IndexTuple tuple1, IndexTuple tuple2);
+extern bool _bt_itemcmp(Relation rel, Size keysz, ScanKey scankey,
+                                               BTItem item1, BTItem item2, StrategyNumber strat);
 
 /*
  * prototypes for functions in nbtpage.c
@@ -272,14 +272,13 @@ extern bool _bt_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir);
  * prototypes for functions in nbtstrat.c
  */
 extern StrategyNumber _bt_getstrat(Relation rel, AttrNumber attno,
-                        RegProcedure proc);
-extern bool _bt_invokestrat(Relation rel, AttrNumber attno,
-                               StrategyNumber strat, Datum left, Datum right);
+                                                                  RegProcedure proc);
 
 /*
  * prototypes for functions in nbtutils.c
  */
 extern ScanKey _bt_mkscankey(Relation rel, IndexTuple itup);
+extern ScanKey _bt_mkscankey_nodata(Relation rel);
 extern void _bt_freeskey(ScanKey skey);
 extern void _bt_freestack(BTStack stack);
 extern void _bt_orderkeys(Relation relation, BTScanOpaque so);