Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Fix btmarkpos/btrestrpos to handle array keys.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 27 Sep 2012 20:59:59 +0000 (16:59 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 27 Sep 2012 21:01:02 +0000 (17:01 -0400)
This fixes another error in commit 9e8da0f75731aaa7605cf4656c21ea09e84d2eb1.
I neglected to make the mark/restore functionality save and restore the
current set of array key values, which led to strange behavior if an
IndexScan with ScalarArrayOpExpr quals was used as the inner side of a
mergejoin.  Per bug #7570 from Melese Tesfaye.

src/backend/access/nbtree/nbtree.c
src/backend/access/nbtree/nbtutils.c
src/include/access/nbtree.h

index 0fd595a2d4ebefb541dc35b00bcb3cae7e510e31..b055eaff5b26561bf3a05d248d6019b8bdb08822 100644 (file)
@@ -584,6 +584,10 @@ btmarkpos(PG_FUNCTION_ARGS)
    else
        so->markItemIndex = -1;
 
+   /* Also record the current positions of any array keys */
+   if (so->numArrayKeys)
+       _bt_mark_array_keys(scan);
+
    PG_RETURN_VOID();
 }
 
@@ -596,6 +600,10 @@ btrestrpos(PG_FUNCTION_ARGS)
    IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
    BTScanOpaque so = (BTScanOpaque) scan->opaque;
 
+   /* Restore the marked positions of any array keys */
+   if (so->numArrayKeys)
+       _bt_restore_array_keys(scan);
+
    if (so->markItemIndex >= 0)
    {
        /*
index 33ad8915f5a7982e6a7cef3216f5bffeb1e90894..50df5e0e5ba9f8512fb9c140c59c7a00c6a4d2aa 100644 (file)
@@ -595,6 +595,65 @@ _bt_advance_array_keys(IndexScanDesc scan, ScanDirection dir)
    return found;
 }
 
+/*
+ * _bt_mark_array_keys() -- Handle array keys during btmarkpos
+ *
+ * Save the current state of the array keys as the "mark" position.
+ */
+void
+_bt_mark_array_keys(IndexScanDesc scan)
+{
+   BTScanOpaque so = (BTScanOpaque) scan->opaque;
+   int         i;
+
+   for (i = 0; i < so->numArrayKeys; i++)
+   {
+       BTArrayKeyInfo *curArrayKey = &so->arrayKeys[i];
+
+       curArrayKey->mark_elem = curArrayKey->cur_elem;
+   }
+}
+
+/*
+ * _bt_restore_array_keys() -- Handle array keys during btrestrpos
+ *
+ * Restore the array keys to where they were when the mark was set.
+ */
+void
+_bt_restore_array_keys(IndexScanDesc scan)
+{
+   BTScanOpaque so = (BTScanOpaque) scan->opaque;
+   bool        changed = false;
+   int         i;
+
+   /* Restore each array key to its position when the mark was set */
+   for (i = 0; i < so->numArrayKeys; i++)
+   {
+       BTArrayKeyInfo *curArrayKey = &so->arrayKeys[i];
+       ScanKey     skey = &so->arrayKeyData[curArrayKey->scan_key];
+       int         mark_elem = curArrayKey->mark_elem;
+
+       if (curArrayKey->cur_elem != mark_elem)
+       {
+           curArrayKey->cur_elem = mark_elem;
+           skey->sk_argument = curArrayKey->elem_values[mark_elem];
+           changed = true;
+       }
+   }
+
+   /*
+    * If we changed any keys, we must redo _bt_preprocess_keys.  That might
+    * sound like overkill, but in cases with multiple keys per index column
+    * it seems necessary to do the full set of pushups.
+    */
+   if (changed)
+   {
+       _bt_preprocess_keys(scan);
+       /* The mark should have been set on a consistent set of keys... */
+       Assert(so->qual_ok);
+   }
+}
+
 
 /*
  * _bt_preprocess_keys() -- Preprocess scan keys
index f23ac3559ad6cc509fd6708cecdb5f64c348e444..d4941e0ff844f32f582b41c933f4af9dc3af0e31 100644 (file)
@@ -535,6 +535,7 @@ typedef struct BTArrayKeyInfo
 {
    int         scan_key;       /* index of associated key in arrayKeyData */
    int         cur_elem;       /* index of current element in elem_values */
+   int         mark_elem;      /* index of marked element in elem_values */
    int         num_elems;      /* number of elems in current array value */
    Datum      *elem_values;    /* array of num_elems Datums */
 } BTArrayKeyInfo;
@@ -665,6 +666,8 @@ extern void _bt_freestack(BTStack stack);
 extern void _bt_preprocess_array_keys(IndexScanDesc scan);
 extern void _bt_start_array_keys(IndexScanDesc scan, ScanDirection dir);
 extern bool _bt_advance_array_keys(IndexScanDesc scan, ScanDirection dir);
+extern void _bt_mark_array_keys(IndexScanDesc scan);
+extern void _bt_restore_array_keys(IndexScanDesc scan);
 extern void _bt_preprocess_keys(IndexScanDesc scan);
 extern IndexTuple _bt_checkkeys(IndexScanDesc scan,
              Page page, OffsetNumber offnum,