]> granicus.if.org Git - postgresql/commitdiff
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,