diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c index 3a5eda3ad8c4e086eaa0d0c82aad4150da85e5dc..0ad8b4ab36f996f5efccfa17e1d0f990e8feb82c 100644 --- a/src/backend/access/nbtree/nbtsearch.c +++ b/src/backend/access/nbtree/nbtsearch.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.53 1999/07/17 20:16:43 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.54 1999/09/27 18:20:21 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -727,11 +727,15 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) RegProcedure proc; int result; BTScanOpaque so; - ScanKeyData skdata; Size keysok; - int i; - int nKeyIndex = -1; + bool strategyCheck; + ScanKey scankeys = 0; + int keysCount = 0; + int *nKeyIs = 0; + int i, j; + StrategyNumber strat_total; + rel = scan->relation; so = (BTScanOpaque) scan->opaque; @@ -742,38 +746,57 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) so->numberOfFirstKeys = 0; /* may be changed by _bt_orderkeys */ so->qual_ok = 1; /* may be changed by _bt_orderkeys */ scan->scanFromEnd = false; + strategyCheck = false; if (so->numberOfKeys > 0) { _bt_orderkeys(rel, so); - if (ScanDirectionIsBackward(dir)) + if (so->qual_ok) + strategyCheck = true; + } + strat_total = BTEqualStrategyNumber; + if (strategyCheck) + { + AttrNumber attno; + + nKeyIs = (int *)palloc(so->numberOfKeys*sizeof(int)); + for (i=0; i < so->numberOfKeys; i++) { - for (i = 0; i < so->numberOfKeys; i++) + attno = so->keyData[i].sk_attno; + if (attno == keysCount) + continue; + if (attno > keysCount + 1) + break; + strat = _bt_getstrat(rel, attno, + so->keyData[i].sk_procedure); + if (strat == strat_total || + strat == BTEqualStrategyNumber) { - if (so->keyData[i].sk_attno != 1) + nKeyIs[keysCount++] = i; + continue; + } + if (ScanDirectionIsBackward(dir) && + (strat == BTLessStrategyNumber || + strat == BTLessEqualStrategyNumber) ) + { + nKeyIs[keysCount++] = i; + strat_total = strat; + if (strat == BTLessStrategyNumber) break; - strat = _bt_getstrat(rel, so->keyData[i].sk_attno, - so->keyData[i].sk_procedure); - if (strat == BTLessStrategyNumber || - strat == BTLessEqualStrategyNumber || - strat == BTEqualStrategyNumber) - { - nKeyIndex = i; + continue; + } + if (ScanDirectionIsForward(dir) && + (strat == BTGreaterStrategyNumber || + strat == BTGreaterEqualStrategyNumber) ) + { + nKeyIs[keysCount++] = i; + strat_total = strat; + if (strat == BTGreaterStrategyNumber) break; - } + continue; } } - else - { - strat = _bt_getstrat(rel, 1, so->keyData[0].sk_procedure); - - if (strat == BTLessStrategyNumber || - strat == BTLessEqualStrategyNumber) - ; - else - nKeyIndex = 0; - } - if (nKeyIndex < 0) + if (!keysCount) scan->scanFromEnd = true; } else @@ -784,7 +807,11 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) /* if we just need to walk down one edge of the tree, do that */ if (scan->scanFromEnd) + { + if (nKeyIs) + pfree(nKeyIs); return _bt_endpoint(scan, dir); + } itupdesc = RelationGetDescr(rel); current = &(scan->currentItemData); @@ -796,16 +823,24 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) * at the right place in the scan. */ /* _bt_orderkeys disallows it, but it's place to add some code latter */ - if (so->keyData[0].sk_flags & SK_ISNULL) + scankeys = (ScanKey)palloc(keysCount*sizeof(ScanKeyData)); + for (i=0; i < keysCount; i++) { - elog(ERROR, "_bt_first: btree doesn't support is(not)null, yet"); - return (RetrieveIndexResult) NULL; + j = nKeyIs[i]; + if (so->keyData[j].sk_flags & SK_ISNULL) + { + pfree(nKeyIs); + pfree(scankeys); + elog(ERROR, "_bt_first: btree doesn't support is(not)null, yet"); + return ((RetrieveIndexResult) NULL); + } + proc = index_getprocid(rel, i+1, BTORDER_PROC); + ScanKeyEntryInitialize(scankeys+i, so->keyData[j].sk_flags, + i+1, proc, so->keyData[j].sk_argument); } - proc = index_getprocid(rel, 1, BTORDER_PROC); - ScanKeyEntryInitialize(&skdata, so->keyData[nKeyIndex].sk_flags, - 1, proc, so->keyData[nKeyIndex].sk_argument); + if (nKeyIs) pfree(nKeyIs); - stack = _bt_search(rel, 1, &skdata, &buf); + stack = _bt_search(rel, keysCount, scankeys, &buf); _bt_freestack(stack); blkno = BufferGetBlockNumber(buf); @@ -823,6 +858,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) ItemPointerSetInvalid(current); so->btso_curbuf = InvalidBuffer; _bt_relbuf(rel, buf, BT_READ); + pfree(scankeys); return (RetrieveIndexResult) NULL; } maxoff = PageGetMaxOffsetNumber(page); @@ -835,7 +871,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) */ while (maxoff == P_HIKEY && !P_RIGHTMOST(pop) && - _bt_skeycmp(rel, 1, &skdata, page, + _bt_skeycmp(rel, keysCount, scankeys, page, PageGetItemId(page, P_HIKEY), BTGreaterEqualStrategyNumber)) { @@ -849,6 +885,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) ItemPointerSetInvalid(current); so->btso_curbuf = InvalidBuffer; _bt_relbuf(rel, buf, BT_READ); + pfree(scankeys); return (RetrieveIndexResult) NULL; } maxoff = PageGetMaxOffsetNumber(page); @@ -857,7 +894,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) /* find the nearest match to the manufactured scan key on the page */ - offnum = _bt_binsrch(rel, buf, 1, &skdata, BT_DESCENT); + offnum = _bt_binsrch(rel, buf, keysCount, scankeys, BT_DESCENT); if (offnum > maxoff) { @@ -872,12 +909,11 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) * we're looking for minus the value we're looking at in the index. */ - result = _bt_compare(rel, itupdesc, page, 1, &skdata, offnum); + result = _bt_compare(rel, itupdesc, page, keysCount, scankeys, offnum); /* it's yet other place to add some code latter for is(not)null */ - strat = _bt_getstrat(rel, 1, so->keyData[nKeyIndex].sk_procedure); - + strat = strat_total; switch (strat) { case BTLessStrategyNumber: @@ -890,7 +926,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) offnum = ItemPointerGetOffsetNumber(current); page = BufferGetPage(buf); - result = _bt_compare(rel, itupdesc, page, 1, &skdata, offnum); + result = _bt_compare(rel, itupdesc, page, keysCount, scankeys, offnum); } while (result <= 0); } @@ -906,12 +942,11 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) offnum = ItemPointerGetOffsetNumber(current); page = BufferGetPage(buf); - result = _bt_compare(rel, itupdesc, page, 1, &skdata, offnum); + result = _bt_compare(rel, itupdesc, page, keysCount, scankeys, offnum); } while (result >= 0); - - if (result < 0) - _bt_twostep(scan, &buf, BackwardScanDirection); } + if (result < 0) + _bt_twostep(scan, &buf, BackwardScanDirection); break; case BTEqualStrategyNumber: @@ -920,6 +955,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) _bt_relbuf(scan->relation, buf, BT_READ); so->btso_curbuf = InvalidBuffer; ItemPointerSetInvalid(&(scan->currentItemData)); + pfree(scankeys); return (RetrieveIndexResult) NULL; } else if (ScanDirectionIsBackward(dir)) @@ -931,7 +967,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) offnum = ItemPointerGetOffsetNumber(current); page = BufferGetPage(buf); - result = _bt_compare(rel, itupdesc, page, 1, &skdata, offnum); + result = _bt_compare(rel, itupdesc, page, keysCount, scankeys, offnum); } while (result == 0); if (result < 0) @@ -950,6 +986,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) _bt_relbuf(scan->relation, buf, BT_READ); so->btso_curbuf = InvalidBuffer; ItemPointerSetInvalid(&(scan->currentItemData)); + pfree(scankeys); return (RetrieveIndexResult) NULL; } } @@ -974,7 +1011,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) page = BufferGetPage(buf); offnum = ItemPointerGetOffsetNumber(current); - result = _bt_compare(rel, itupdesc, page, 1, &skdata, offnum); + result = _bt_compare(rel, itupdesc, page, keysCount, scankeys, offnum); } while (result < 0); if (result > 0) @@ -993,12 +1030,13 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) offnum = ItemPointerGetOffsetNumber(current); page = BufferGetPage(buf); - result = _bt_compare(rel, itupdesc, page, 1, &skdata, offnum); + result = _bt_compare(rel, itupdesc, page, keysCount, scankeys, offnum); } while (result >= 0); } break; } + pfree(scankeys); /* okay, current item pointer for the scan is right */ offnum = ItemPointerGetOffsetNumber(current); page = BufferGetPage(buf); diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index 2a5e7578d2f196888b7b0b5bcba61f93448a7f8b..ee0cd1483b4279670ee082b2dc1b0e747a51e775 100644 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtutils.c,v 1.32 1999/07/17 20:16:43 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtutils.c,v 1.33 1999/09/27 18:20:21 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -101,6 +101,7 @@ _bt_orderkeys(Relation relation, BTScanOpaque so) uint16 numberOfKeys = so->numberOfKeys; uint16 new_numberOfKeys = 0; AttrNumber attno = 1; + bool equalStrategyEnd, underEqualStrategy; if (numberOfKeys < 1) return; @@ -136,6 +137,8 @@ _bt_orderkeys(Relation relation, BTScanOpaque so) for (j = 0; j <= BTMaxStrategyNumber; j++) init[j] = 0; + equalStrategyEnd = false; + underEqualStrategy = true; /* check each key passed in */ for (i = 0;;) { @@ -150,6 +153,7 @@ _bt_orderkeys(Relation relation, BTScanOpaque so) if (cur->sk_attno != attno + 1 && i < numberOfKeys) elog(ERROR, "_bt_orderkeys: key(s) for attribute %d missed", attno + 1); + underEqualStrategy = (!equalStrategyEnd); /* * If = has been specified, no other key will be used. In case * of key < 2 && key == 1 and so on we have to set qual_ok to @@ -175,6 +179,8 @@ _bt_orderkeys(Relation relation, BTScanOpaque so) init[BTGreaterEqualStrategyNumber - 1] = 0; init[BTGreaterStrategyNumber - 1] = 0; } + else + equalStrategyEnd = true; /* only one of <, <= */ if (init[BTLessStrategyNumber - 1] @@ -223,7 +229,7 @@ _bt_orderkeys(Relation relation, BTScanOpaque so) if (init[j]) key[new_numberOfKeys++] = xform[j]; - if (attno == 1) + if (underEqualStrategy) so->numberOfFirstKeys = new_numberOfKeys; if (i == numberOfKeys)