From 74cdf928687ac62db73b72509e1e11b9008a6bf2 Mon Sep 17 00:00:00 2001 From: "Marc G. Fournier" Date: Tue, 30 Jul 1996 07:56:04 +0000 Subject: [PATCH] Fixes: > INDEXED searches in some cases DO NOT WORK. > Although simple search expressions (i.e. with a constant value on > the right side of an operator) work, performing a join (by putting > a field of some other table on the right side of an operator) produces > empty output. > WITHOUT indices, everything works fine. > submitted by: "Vadim B. Mikheev" --- src/backend/access/nbtree.h | 10 +++- src/backend/access/nbtree/nbtree.c | 66 ++++++++++++++++----------- src/backend/access/nbtree/nbtsearch.c | 11 +++-- src/backend/access/nbtree/nbtutils.c | 37 ++++++++++++--- 4 files changed, 86 insertions(+), 38 deletions(-) diff --git a/src/backend/access/nbtree.h b/src/backend/access/nbtree.h index d5c37a2395..051fb8f6eb 100644 --- a/src/backend/access/nbtree.h +++ b/src/backend/access/nbtree.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: nbtree.h,v 1.1.1.1 1996/07/09 06:21:08 scrappy Exp $ + * $Id: nbtree.h,v 1.2 1996/07/30 07:55:10 scrappy Exp $ * *------------------------------------------------------------------------- */ @@ -60,11 +60,17 @@ typedef BTPageOpaqueData *BTPageOpaque; * and recorded in the opaque entry of the scan in order to avoid * doing a ReadBuffer() for every tuple in the index. This avoids * semop() calls, which are expensive. + * + * And it's used to remember actual scankey info (we need in it + * if some scankeys evaled at runtime. */ typedef struct BTScanOpaqueData { Buffer btso_curbuf; Buffer btso_mrkbuf; + uint16 qual_ok; /* 0 for quals like key == 1 && key > 2 */ + uint16 numberOfKeys; /* number of key attributes */ + ScanKey keyData; /* key descriptor */ } BTScanOpaqueData; typedef BTScanOpaqueData *BTScanOpaque; @@ -248,7 +254,7 @@ extern ScanKey _bt_mkscankey(Relation rel, IndexTuple itup); extern void _bt_freeskey(ScanKey skey); extern void _bt_freestack(BTStack stack); extern void _bt_orderkeys(Relation relation, uint16 *numberOfKeys, - ScanKey key); + ScanKey key, uint16 *qual_ok); extern bool _bt_checkqual(IndexScanDesc scan, IndexTuple itup); extern BTItem _bt_formitem(IndexTuple itup); diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index 0601611996..5829e8afe0 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.1.1.1 1996/07/09 06:21:12 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.2 1996/07/30 07:56:00 scrappy Exp $ * * NOTES * This file contains only the public interface routines. @@ -330,32 +330,9 @@ char * btbeginscan(Relation rel, bool fromEnd, uint16 keysz, ScanKey scankey) { IndexScanDesc scan; - StrategyNumber strat; - BTScanOpaque so; - /* first order the keys in the qualification */ - if (keysz > 1) - _bt_orderkeys(rel, &keysz, scankey); - - /* now get the scan */ + /* get the scan */ scan = RelationGetIndexScan(rel, fromEnd, keysz, scankey); - so = (BTScanOpaque) palloc(sizeof(BTScanOpaqueData)); - so->btso_curbuf = so->btso_mrkbuf = InvalidBuffer; - scan->opaque = so; - - /* finally, be sure that the scan exploits the tree order */ - scan->scanFromEnd = false; - scan->flags = 0x0; - if (keysz > 0) { - strat = _bt_getstrat(scan->relation, 1 /* XXX */, - scankey[0].sk_procedure); - - if (strat == BTLessStrategyNumber - || strat == BTLessEqualStrategyNumber) - scan->scanFromEnd = true; - } else { - scan->scanFromEnd = true; - } /* register scan in case we change pages it's using */ _bt_regscan(scan); @@ -371,6 +348,7 @@ btrescan(IndexScanDesc scan, bool fromEnd, ScanKey scankey) { ItemPointer iptr; BTScanOpaque so; + StrategyNumber strat; so = (BTScanOpaque) scan->opaque; @@ -388,12 +366,45 @@ btrescan(IndexScanDesc scan, bool fromEnd, ScanKey scankey) ItemPointerSetInvalid(iptr); } + if ( so == NULL ) /* if called from btbeginscan */ + { + so = (BTScanOpaque) palloc(sizeof(BTScanOpaqueData)); + so->btso_curbuf = so->btso_mrkbuf = InvalidBuffer; + so->keyData = (ScanKey) NULL; + if ( scan->numberOfKeys > 0) + so->keyData = (ScanKey) palloc (scan->numberOfKeys * sizeof(ScanKeyData)); + scan->opaque = so; + scan->flags = 0x0; + } + /* reset the scan key */ + so->numberOfKeys = scan->numberOfKeys; + so->qual_ok = 1; /* may be changed by _bt_orderkeys */ if (scan->numberOfKeys > 0) { memmove(scan->keyData, scankey, scan->numberOfKeys * sizeof(ScanKeyData)); + memmove(so->keyData, + scankey, + so->numberOfKeys * sizeof(ScanKeyData)); + /* order the keys in the qualification */ + if (so->numberOfKeys > 1) + _bt_orderkeys(scan->relation, &so->numberOfKeys, so->keyData, &so->qual_ok); } + + /* finally, be sure that the scan exploits the tree order */ + scan->scanFromEnd = false; + if ( so->numberOfKeys > 0 ) { + strat = _bt_getstrat(scan->relation, 1 /* XXX */, + so->keyData[0].sk_procedure); + + if (strat == BTLessStrategyNumber + || strat == BTLessEqualStrategyNumber) + scan->scanFromEnd = true; + } else { + scan->scanFromEnd = true; + } + } void @@ -411,7 +422,8 @@ btmovescan(IndexScanDesc scan, Datum v) ItemPointerSetInvalid(iptr); } - scan->keyData[0].sk_argument = v; +/* scan->keyData[0].sk_argument = v; */ + so->keyData[0].sk_argument = v; } /* @@ -445,6 +457,8 @@ btendscan(IndexScanDesc scan) /* be tidy */ #ifdef PERFECT_MMGR + if ( so->keyData != (ScanKey) NULL ) + pfree (so->keyData); pfree (scan->opaque); #endif /* PERFECT_MMGR */ } diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c index d7a7fc7d62..3756c2fc30 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.1.1.1 1996/07/09 06:21:12 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.2 1996/07/30 07:56:02 scrappy Exp $ * *------------------------------------------------------------------------- */ @@ -604,6 +604,10 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) BTScanOpaque so; ScanKeyData skdata; + so = (BTScanOpaque) scan->opaque; + if ( so->qual_ok == 0 ) /* may be set by _bt_orderkeys */ + return ((RetrieveIndexResult) NULL); + /* if we just need to walk down one edge of the tree, do that */ if (scan->scanFromEnd) return (_bt_endpoint(scan, dir)); @@ -611,7 +615,6 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) rel = scan->relation; itupdesc = RelationGetTupleDescriptor(scan->relation); current = &(scan->currentItemData); - so = (BTScanOpaque) scan->opaque; /* * Okay, we want something more complicated. What we'll do is use @@ -628,7 +631,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) */ proc = index_getprocid(rel, 1, BTORDER_PROC); ScanKeyEntryInitialize(&skdata, 0x0, 1, proc, - scan->keyData[0].sk_argument); + so->keyData[0].sk_argument); stack = _bt_search(rel, 1, &skdata, &buf); _bt_freestack(stack); @@ -666,7 +669,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) */ result = _bt_compare(rel, itupdesc, page, 1, &skdata, offnum); - strat = _bt_getstrat(rel, 1, scan->keyData[0].sk_procedure); + strat = _bt_getstrat(rel, 1, so->keyData[0].sk_procedure); switch (strat) { case BTLessStrategyNumber: diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index 695a2b637c..d06b857851 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.1.1.1 1996/07/09 06:21:12 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtutils.c,v 1.2 1996/07/30 07:56:04 scrappy Exp $ * *------------------------------------------------------------------------- */ @@ -82,7 +82,7 @@ _bt_freestack(BTStack stack) * more than one qual clauses using this index. */ void -_bt_orderkeys(Relation relation, uint16 *numberOfKeys, ScanKey key) +_bt_orderkeys(Relation relation, uint16 *numberOfKeys, ScanKey key, uint16 *qual_ok) { ScanKey xform; ScanKeyData *cur; @@ -133,6 +133,8 @@ _bt_orderkeys(Relation relation, uint16 *numberOfKeys, ScanKey key) cur->sk_argument, xform[j].sk_argument); if (test) xform[j].sk_argument = cur->sk_argument; + else if ( j == (BTEqualStrategyNumber - 1) ) + *qual_ok = 0; /* key == a && key == b, but a != b */ } else { /* nope, use this value */ memmove(&xform[j], cur, sizeof(*cur)); @@ -142,7 +144,30 @@ _bt_orderkeys(Relation relation, uint16 *numberOfKeys, ScanKey key) } /* if = has been specified, no other key will be used */ + /* + * XXX + * But in case of key < 2 && key == 1 and so on + * we have to set qual_ok to 0 + */ if (init[BTEqualStrategyNumber - 1]) { + + ScanKeyData *eq, *chk; + + eq = &xform[BTEqualStrategyNumber - 1]; + + for (j = BTMaxStrategyNumber; --j >= 0; ) + { + if ( j == (BTEqualStrategyNumber - 1) || init[j] == 0 ) + continue; + + chk = &xform[j]; + + test = (long) fmgr(chk->sk_procedure, eq->sk_argument, chk->sk_argument); + + if (!test) + *qual_ok = 0; + } + init[BTLessStrategyNumber - 1] = 0; init[BTLessEqualStrategyNumber - 1] = 0; init[BTGreaterEqualStrategyNumber - 1] = 0; @@ -166,7 +191,7 @@ _bt_orderkeys(Relation relation, uint16 *numberOfKeys, ScanKey key) * in the correct way. */ - test = (long) fmgr(le->sk_procedure, le->sk_argument, lt->sk_argument); + test = (long) fmgr(le->sk_procedure, lt->sk_argument, le->sk_argument); if (test) init[BTLessEqualStrategyNumber - 1] = 0; @@ -184,12 +209,12 @@ _bt_orderkeys(Relation relation, uint16 *numberOfKeys, ScanKey key) ge = &xform[BTGreaterEqualStrategyNumber - 1]; /* see note above on function cache */ - test = (long) fmgr(ge->sk_procedure, gt->sk_argument, gt->sk_argument); + test = (long) fmgr(ge->sk_procedure, gt->sk_argument, ge->sk_argument); if (test) - init[BTGreaterStrategyNumber - 1] = 0; - else init[BTGreaterEqualStrategyNumber - 1] = 0; + else + init[BTGreaterStrategyNumber - 1] = 0; } /* okay, reorder and count */