/* A bitmap result */
BlockNumber advancePastBlk = GinItemPointerGetBlockNumber(&advancePast);
OffsetNumber advancePastOff = GinItemPointerGetOffsetNumber(&advancePast);
+ bool gotitem = false;
do
{
- if (entry->matchResult == NULL ||
- entry->offset >= entry->matchResult->ntuples)
+ /*
+ * If we've exhausted all items on this block, move to next block
+ * in the bitmap.
+ */
+ while (entry->matchResult == NULL ||
+ (entry->matchResult->ntuples >= 0 &&
+ entry->offset >= entry->matchResult->ntuples) ||
+ entry->matchResult->blockno < advancePastBlk)
{
entry->matchResult = tbm_iterate(entry->matchIterator);
break;
}
- /*
- * If all the matches on this page are <= advancePast, skip
- * to next page.
- */
- if (entry->matchResult->blockno < advancePastBlk ||
- (entry->matchResult->blockno == advancePastBlk &&
- entry->matchResult->offsets[entry->offset] <= advancePastOff))
- {
- entry->offset = entry->matchResult->ntuples;
- continue;
- }
-
/*
* Reset counter to the beginning of entry->matchResult. Note:
* entry->offset is still greater than matchResult->ntuples if
*/
entry->offset = 0;
}
+ if (entry->isFinished)
+ break;
+ /*
+ * We're now on the first page after advancePast which has any
+ * items on it. If it's a lossy result, return that.
+ */
if (entry->matchResult->ntuples < 0)
{
- /*
- * lossy result, so we need to check the whole page
- */
ItemPointerSetLossyPage(&entry->curItem,
entry->matchResult->blockno);
/*
* We might as well fall out of the loop; we could not
* estimate number of results on this page to support correct
- * reducing of result even if it's enabled
+ * reducing of result even if it's enabled.
*/
+ gotitem = true;
break;
}
-
+ /*
+ * Not a lossy page. Skip over any offsets <= advancePast, and
+ * return that.
+ */
if (entry->matchResult->blockno == advancePastBlk)
{
/*
- * Skip to the right offset on this page. We already checked
- * in above loop that there is at least one item > advancePast
- * on the page.
+ * First, do a quick check against the last offset on the page.
+ * If that's > advancePast, so are all the other offsets.
*/
+ if (entry->matchResult->offsets[entry->matchResult->ntuples - 1] <= advancePastOff)
+ {
+ entry->offset = entry->matchResult->ntuples;
+ continue;
+ }
+
+ /* Otherwise scan to find the first item > advancePast */
while (entry->matchResult->offsets[entry->offset] <= advancePastOff)
entry->offset++;
}
entry->matchResult->blockno,
entry->matchResult->offsets[entry->offset]);
entry->offset++;
- } while (entry->reduceResult == TRUE && dropItem(entry));
+ gotitem = true;
+ } while (!gotitem || (entry->reduceResult == TRUE && dropItem(entry)));
}
else if (!BufferIsValid(entry->buffer))
{