From 74cdf928687ac62db73b72509e1e11b9008a6bf2 Mon Sep 17 00:00:00 2001
From: "Marc G. Fournier" <scrappy@hub.org>
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" <root@ais.sable.krasnoyarsk.su>
---
 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 d5c37a23950..051fb8f6eb0 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 06016119964..5829e8afe07 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 d7a7fc7d62e..3756c2fc30c 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 695a2b637c8..d06b857851e 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 */
-- 
GitLab