aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/gin/ginget.c44
-rw-r--r--src/test/regress/expected/gin.out40
-rw-r--r--src/test/regress/sql/gin.sql18
3 files changed, 88 insertions, 14 deletions
diff --git a/src/backend/access/gin/ginget.c b/src/backend/access/gin/ginget.c
index b18ae2b3ed2..a5303c1af3e 100644
--- a/src/backend/access/gin/ginget.c
+++ b/src/backend/access/gin/ginget.c
@@ -801,9 +801,8 @@ entryGetItem(GinState *ginstate, GinScanEntry entry,
/* A bitmap result */
BlockNumber advancePastBlk = GinItemPointerGetBlockNumber(&advancePast);
OffsetNumber advancePastOff = GinItemPointerGetOffsetNumber(&advancePast);
- bool gotitem = false;
- do
+ for (;;)
{
/*
* If we've exhausted all items on this block, move to next block
@@ -852,7 +851,6 @@ entryGetItem(GinState *ginstate, GinScanEntry entry,
* estimate number of results on this page to support correct
* reducing of result even if it's enabled.
*/
- gotitem = true;
break;
}
@@ -865,7 +863,7 @@ entryGetItem(GinState *ginstate, GinScanEntry entry,
/*
* First, do a quick check against the last offset on the
* page. If that's > advancePast, so are all the other
- * offsets.
+ * offsets, so just go back to the top to get the next page.
*/
if (entry->matchResult->offsets[entry->matchResult->ntuples - 1] <= advancePastOff)
{
@@ -882,8 +880,11 @@ entryGetItem(GinState *ginstate, GinScanEntry entry,
entry->matchResult->blockno,
entry->matchResult->offsets[entry->offset]);
entry->offset++;
- gotitem = true;
- } while (!gotitem || (entry->reduceResult == true && dropItem(entry)));
+
+ /* Done unless we need to reduce the result */
+ if (!entry->reduceResult || !dropItem(entry))
+ break;
+ }
}
else if (!BufferIsValid(entry->buffer))
{
@@ -891,7 +892,7 @@ entryGetItem(GinState *ginstate, GinScanEntry entry,
* A posting list from an entry tuple, or the last page of a posting
* tree.
*/
- do
+ for (;;)
{
if (entry->offset >= entry->nlist)
{
@@ -901,13 +902,20 @@ entryGetItem(GinState *ginstate, GinScanEntry entry,
}
entry->curItem = entry->list[entry->offset++];
- } while (ginCompareItemPointers(&entry->curItem, &advancePast) <= 0);
- /* XXX: shouldn't we apply the fuzzy search limit here? */
+
+ /* If we're not past advancePast, keep scanning */
+ if (ginCompareItemPointers(&entry->curItem, &advancePast) <= 0)
+ continue;
+
+ /* Done unless we need to reduce the result */
+ if (!entry->reduceResult || !dropItem(entry))
+ break;
+ }
}
else
{
/* A posting tree */
- do
+ for (;;)
{
/* If we've processed the current batch, load more items */
while (entry->offset >= entry->nlist)
@@ -923,8 +931,20 @@ entryGetItem(GinState *ginstate, GinScanEntry entry,
entry->curItem = entry->list[entry->offset++];
- } while (ginCompareItemPointers(&entry->curItem, &advancePast) <= 0 ||
- (entry->reduceResult == true && dropItem(entry)));
+ /* If we're not past advancePast, keep scanning */
+ if (ginCompareItemPointers(&entry->curItem, &advancePast) <= 0)
+ continue;
+
+ /* Done unless we need to reduce the result */
+ if (!entry->reduceResult || !dropItem(entry))
+ break;
+
+ /*
+ * Advance advancePast (so that entryLoadMoreItems will load the
+ * right data), and keep scanning
+ */
+ advancePast = entry->curItem;
+ }
}
}
diff --git a/src/test/regress/expected/gin.out b/src/test/regress/expected/gin.out
index a3911a6c6c9..e26a961bbd1 100644
--- a/src/test/regress/expected/gin.out
+++ b/src/test/regress/expected/gin.out
@@ -1,7 +1,7 @@
--
-- Test GIN indexes.
--
--- There are other tests to test different GIN opclassed. This is for testing
+-- There are other tests to test different GIN opclasses. This is for testing
-- GIN itself.
-- Create and populate a test table with a GIN index.
create table gin_test_tbl(i int4[]) with (autovacuum_enabled = off);
@@ -35,3 +35,41 @@ insert into gin_test_tbl select array[1, 2, g] from generate_series(1, 1000) g;
insert into gin_test_tbl select array[1, 3, g] from generate_series(1, 1000) g;
delete from gin_test_tbl where i @> array[2];
vacuum gin_test_tbl;
+-- Test for "rare && frequent" searches
+explain (costs off)
+select count(*) from gin_test_tbl where i @> array[1, 999];
+ QUERY PLAN
+-------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on gin_test_tbl
+ Recheck Cond: (i @> '{1,999}'::integer[])
+ -> Bitmap Index Scan on gin_test_idx
+ Index Cond: (i @> '{1,999}'::integer[])
+(5 rows)
+
+select count(*) from gin_test_tbl where i @> array[1, 999];
+ count
+-------
+ 3
+(1 row)
+
+-- Very weak test for gin_fuzzy_search_limit
+set gin_fuzzy_search_limit = 1000;
+explain (costs off)
+select count(*) > 0 as ok from gin_test_tbl where i @> array[1];
+ QUERY PLAN
+---------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on gin_test_tbl
+ Recheck Cond: (i @> '{1}'::integer[])
+ -> Bitmap Index Scan on gin_test_idx
+ Index Cond: (i @> '{1}'::integer[])
+(5 rows)
+
+select count(*) > 0 as ok from gin_test_tbl where i @> array[1];
+ ok
+----
+ t
+(1 row)
+
+reset gin_fuzzy_search_limit;
diff --git a/src/test/regress/sql/gin.sql b/src/test/regress/sql/gin.sql
index c566e9b58c8..ef8b63d4c54 100644
--- a/src/test/regress/sql/gin.sql
+++ b/src/test/regress/sql/gin.sql
@@ -1,7 +1,7 @@
--
-- Test GIN indexes.
--
--- There are other tests to test different GIN opclassed. This is for testing
+-- There are other tests to test different GIN opclasses. This is for testing
-- GIN itself.
-- Create and populate a test table with a GIN index.
@@ -34,3 +34,19 @@ insert into gin_test_tbl select array[1, 3, g] from generate_series(1, 1000) g;
delete from gin_test_tbl where i @> array[2];
vacuum gin_test_tbl;
+
+-- Test for "rare && frequent" searches
+explain (costs off)
+select count(*) from gin_test_tbl where i @> array[1, 999];
+
+select count(*) from gin_test_tbl where i @> array[1, 999];
+
+-- Very weak test for gin_fuzzy_search_limit
+set gin_fuzzy_search_limit = 1000;
+
+explain (costs off)
+select count(*) > 0 as ok from gin_test_tbl where i @> array[1];
+
+select count(*) > 0 as ok from gin_test_tbl where i @> array[1];
+
+reset gin_fuzzy_search_limit;