mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-08-23 19:47:17 +02:00
Fix code for re-finding scan position in a multicolumn GIN index.
collectMatchBitmap() needs to re-find the index tuple it was previously looking at, after transiently dropping lock on the index page it's on. The tuple should still exist and be at its prior position or somewhere to the right of that, since ginvacuum never removes tuples but concurrent insertions could add one. However, there was a thinko in that logic, to the effect of expecting any inserted tuples to have the same index "attnum" as what we'd been scanning. Since there's no physical separation of tuples with different attnums, it's not terribly hard to devise scenarios where this fails, leading to transient "lost saved point in index" errors. (While I've duplicated this with manual testing, it seems impossible to make a reproducible test case with our available testing technology.) Fix by just continuing the scan when the attnum doesn't match. While here, improve the error message used if we do fail, so that it matches the wording used in btree for a similar case. collectMatchBitmap()'s posting-tree code path was previously not exercised at all by our regression tests. While I can't make a regression test that exhibits the bug, I can at least improve the code coverage here, so do that. The test case I made for this is an extension of one added by4b754d6c1
, so it only works in HEAD and v13; didn't seem worth trying hard to back-patch it. Per bug #16595 from Jesse Kinkead. This has been broken since multicolumn capability was added to GIN (commit27cb66fdf
), so back-patch to all supported branches. Discussion: https://postgr.es/m/16595-633118be8eef9ce2@postgresql.org
This commit is contained in:
parent
b8d768813a
commit
11ecf4bd28
@ -264,24 +264,28 @@ collectMatchBitmap(GinBtreeData *btree, GinBtreeStack *stack,
|
||||
/* Search forward to re-find idatum */
|
||||
for (;;)
|
||||
{
|
||||
Datum newDatum;
|
||||
GinNullCategory newCategory;
|
||||
|
||||
if (moveRightIfItNeeded(btree, stack, snapshot) == false)
|
||||
elog(ERROR, "lost saved point in index"); /* must not happen !!! */
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INTERNAL_ERROR),
|
||||
errmsg("failed to re-find tuple within index \"%s\"",
|
||||
RelationGetRelationName(btree->index))));
|
||||
|
||||
page = BufferGetPage(stack->buffer);
|
||||
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stack->off));
|
||||
|
||||
if (gintuple_get_attrnum(btree->ginstate, itup) != attnum)
|
||||
elog(ERROR, "lost saved point in index"); /* must not happen !!! */
|
||||
newDatum = gintuple_get_key(btree->ginstate, itup,
|
||||
&newCategory);
|
||||
if (gintuple_get_attrnum(btree->ginstate, itup) == attnum)
|
||||
{
|
||||
Datum newDatum;
|
||||
GinNullCategory newCategory;
|
||||
|
||||
if (ginCompareEntries(btree->ginstate, attnum,
|
||||
newDatum, newCategory,
|
||||
idatum, icategory) == 0)
|
||||
break; /* Found! */
|
||||
newDatum = gintuple_get_key(btree->ginstate, itup,
|
||||
&newCategory);
|
||||
|
||||
if (ginCompareEntries(btree->ginstate, attnum,
|
||||
newDatum, newCategory,
|
||||
idatum, icategory) == 0)
|
||||
break; /* Found! */
|
||||
}
|
||||
|
||||
stack->off++;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user