Assert(BTScanPosIsPinned(so->currPos));
Assert(!so->needPrimScan);
- if (scan->parallel_scan)
- {
- /* allow next/prev page to be read by other worker without delay */
- if (ScanDirectionIsForward(dir))
- _bt_parallel_release(scan, so->currPos.nextPage,
- so->currPos.currPage);
- else
- _bt_parallel_release(scan, so->currPos.prevPage,
- so->currPos.currPage);
- }
-
- PredicateLockPage(rel, so->currPos.currPage, scan->xs_snapshot);
-
/* initialize local variables */
indnatts = IndexRelationGetNumberOfAttributes(rel);
arrayKeys = so->numArrayKeys != 0;
pstate.targetdistance = 0;
pstate.nskipadvances = 0;
+ if (scan->parallel_scan)
+ {
+ /* allow next/prev page to be read by other worker without delay */
+ if (ScanDirectionIsForward(dir))
+ _bt_parallel_release(scan, so->currPos.nextPage,
+ so->currPos.currPage);
+ else
+ _bt_parallel_release(scan, so->currPos.prevPage,
+ so->currPos.currPage);
+ }
+
+ PredicateLockPage(rel, so->currPos.currPage, scan->xs_snapshot);
+
if (ScanDirectionIsForward(dir))
{
/* SK_SEARCHARRAY forward scans must provide high key up front */
pstate.finaltup = (IndexTuple) PageGetItem(page, iid);
- if (so->scanBehind &&
+ if (unlikely(so->scanBehind) &&
!_bt_scanbehind_checkkeys(scan, dir, pstate.finaltup))
{
/* Schedule another primitive index scan after all */
{
int tupleOffset;
- /*
- * Set up state to return posting list, and remember first
- * TID
- */
+ /* Set up posting list state (and remember first TID) */
tupleOffset =
_bt_setuppostingitems(so, itemIndex, offnum,
BTreeTupleGetPostingN(itup, 0),
itup);
itemIndex++;
- /* Remember additional TIDs */
+
+ /* Remember all later TIDs (must be at least one) */
for (int i = 1; i < BTreeTupleGetNPosting(itup); i++)
{
_bt_savepostingitem(so, itemIndex, offnum,
pstate.finaltup = (IndexTuple) PageGetItem(page, iid);
- if (so->scanBehind &&
+ if (unlikely(so->scanBehind) &&
!_bt_scanbehind_checkkeys(scan, dir, pstate.finaltup))
{
/* Schedule another primitive index scan after all */
}
else
{
+ uint16 nitems = BTreeTupleGetNPosting(itup);
int tupleOffset;
- /*
- * Set up state to return posting list, and remember first
- * TID.
- *
- * Note that we deliberately save/return items from
- * posting lists in ascending heap TID order for backwards
- * scans. This allows _bt_killitems() to make a
- * consistent assumption about the order of items
- * associated with the same posting list tuple.
- */
+ /* Set up posting list state (and remember last TID) */
itemIndex--;
tupleOffset =
_bt_setuppostingitems(so, itemIndex, offnum,
- BTreeTupleGetPostingN(itup, 0),
+ BTreeTupleGetPostingN(itup, nitems - 1),
itup);
- /* Remember additional TIDs */
- for (int i = 1; i < BTreeTupleGetNPosting(itup); i++)
+
+ /* Remember all prior TIDs (must be at least one) */
+ for (int i = nitems - 2; i >= 0; i--)
{
itemIndex--;
_bt_savepostingitem(so, itemIndex, offnum,
#include "access/reloptions.h"
#include "access/relscan.h"
#include "commands/progress.h"
+#include "common/int.h"
+#include "lib/qunique.h"
#include "miscadmin.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
+static int _bt_compare_int(const void *va, const void *vb);
static int _bt_keep_natts(Relation rel, IndexTuple lastleft,
IndexTuple firstright, BTScanInsert itup_key);
}
}
+/*
+ * qsort comparison function for int arrays
+ */
+static int
+_bt_compare_int(const void *va, const void *vb)
+{
+ int a = *((const int *) va);
+ int b = *((const int *) vb);
+
+ return pg_cmp_s32(a, b);
+}
+
/*
* _bt_killitems - set LP_DEAD state for items an indexscan caller has
* told us were killed
/* Always invalidate so->killedItems[] before leaving so->currPos */
so->numKilled = 0;
+ /*
+ * so->killedItems[] is in whatever order the scan returned items in.
+ * Items will appear in descending order during backwards scans. And
+ * scrollable cursor scans might have duplicate items.
+ *
+ * Sort and uniqueify so->killedItems[] to deal with all this.
+ */
+ if (numKilled > 1)
+ {
+ qsort(so->killedItems, numKilled, sizeof(int), _bt_compare_int);
+ numKilled = qunique(so->killedItems, numKilled, sizeof(int),
+ _bt_compare_int);
+ }
+
if (!so->dropPin)
{
/*
int j;
/*
- * We rely on the convention that heap TIDs in the scanpos
- * items array are stored in ascending heap TID order for a
- * group of TIDs that originally came from a posting list
- * tuple. This convention even applies during backwards
- * scans, where returning the TIDs in descending order might
- * seem more natural. This is about effectiveness, not
- * correctness.
- *
* Note that the page may have been modified in almost any way
* since we first read it (in the !so->dropPin case), so it's
* possible that this posting list tuple wasn't a posting list