Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 614167c

Browse files
committed
Fix bugs in GIN "fast scan" with partial match.
There were a couple of bugs here. First, if the fuzzy limit was exceeded, the loop in entryGetItem might drop out too soon if a whole block needs to be skipped because it's < advancePast ("continue" in a while-loop checks the loop condition too). Secondly, the loop checked when stepping to a new page that there is at least one offset on the page < advancePast, but we cannot rely on that on subsequent calls of entryGetItem, because advancePast might change in between. That caused the skipping loop to read bogus items in the TbmIterateResult's offset array. First item and fix by Alexander Korotkov, second bug pointed out by Fabrízio de Royes Mello, by a small variation of Alexander's test query.
1 parent ef29a88 commit 614167c

File tree

1 file changed

+32
-23
lines changed

1 file changed

+32
-23
lines changed

src/backend/access/gin/ginget.c

+32-23
Original file line numberDiff line numberDiff line change
@@ -729,11 +729,18 @@ entryGetItem(GinState *ginstate, GinScanEntry entry,
729729
/* A bitmap result */
730730
BlockNumber advancePastBlk = GinItemPointerGetBlockNumber(&advancePast);
731731
OffsetNumber advancePastOff = GinItemPointerGetOffsetNumber(&advancePast);
732+
bool gotitem = false;
732733

733734
do
734735
{
735-
if (entry->matchResult == NULL ||
736-
entry->offset >= entry->matchResult->ntuples)
736+
/*
737+
* If we've exhausted all items on this block, move to next block
738+
* in the bitmap.
739+
*/
740+
while (entry->matchResult == NULL ||
741+
(entry->matchResult->ntuples >= 0 &&
742+
entry->offset >= entry->matchResult->ntuples) ||
743+
entry->matchResult->blockno < advancePastBlk)
737744
{
738745
entry->matchResult = tbm_iterate(entry->matchIterator);
739746

@@ -746,18 +753,6 @@ entryGetItem(GinState *ginstate, GinScanEntry entry,
746753
break;
747754
}
748755

749-
/*
750-
* If all the matches on this page are <= advancePast, skip
751-
* to next page.
752-
*/
753-
if (entry->matchResult->blockno < advancePastBlk ||
754-
(entry->matchResult->blockno == advancePastBlk &&
755-
entry->matchResult->offsets[entry->offset] <= advancePastOff))
756-
{
757-
entry->offset = entry->matchResult->ntuples;
758-
continue;
759-
}
760-
761756
/*
762757
* Reset counter to the beginning of entry->matchResult. Note:
763758
* entry->offset is still greater than matchResult->ntuples if
@@ -766,30 +761,43 @@ entryGetItem(GinState *ginstate, GinScanEntry entry,
766761
*/
767762
entry->offset = 0;
768763
}
764+
if (entry->isFinished)
765+
break;
769766

767+
/*
768+
* We're now on the first page after advancePast which has any
769+
* items on it. If it's a lossy result, return that.
770+
*/
770771
if (entry->matchResult->ntuples < 0)
771772
{
772-
/*
773-
* lossy result, so we need to check the whole page
774-
*/
775773
ItemPointerSetLossyPage(&entry->curItem,
776774
entry->matchResult->blockno);
777775

778776
/*
779777
* We might as well fall out of the loop; we could not
780778
* estimate number of results on this page to support correct
781-
* reducing of result even if it's enabled
779+
* reducing of result even if it's enabled.
782780
*/
781+
gotitem = true;
783782
break;
784783
}
785-
784+
/*
785+
* Not a lossy page. Skip over any offsets <= advancePast, and
786+
* return that.
787+
*/
786788
if (entry->matchResult->blockno == advancePastBlk)
787789
{
788790
/*
789-
* Skip to the right offset on this page. We already checked
790-
* in above loop that there is at least one item > advancePast
791-
* on the page.
791+
* First, do a quick check against the last offset on the page.
792+
* If that's > advancePast, so are all the other offsets.
792793
*/
794+
if (entry->matchResult->offsets[entry->matchResult->ntuples - 1] <= advancePastOff)
795+
{
796+
entry->offset = entry->matchResult->ntuples;
797+
continue;
798+
}
799+
800+
/* Otherwise scan to find the first item > advancePast */
793801
while (entry->matchResult->offsets[entry->offset] <= advancePastOff)
794802
entry->offset++;
795803
}
@@ -798,7 +806,8 @@ entryGetItem(GinState *ginstate, GinScanEntry entry,
798806
entry->matchResult->blockno,
799807
entry->matchResult->offsets[entry->offset]);
800808
entry->offset++;
801-
} while (entry->reduceResult == TRUE && dropItem(entry));
809+
gotitem = true;
810+
} while (!gotitem || (entry->reduceResult == TRUE && dropItem(entry)));
802811
}
803812
else if (!BufferIsValid(entry->buffer))
804813
{

0 commit comments

Comments
 (0)