Skip to content

Commit 55b59ed

Browse files
committed
Fix GiST index-only scans for opclasses with different storage type.
We cannot use the index's tuple descriptor directly to describe the index tuples returned in an index-only scan. That's because the index might use a different datatype for the values stored on disk than the type originally indexed. As long as they were both pass-by-ref, it worked, but will not work for pass-by-value types of different sizes. I noticed this as a crash when I started hacking a patch to add fetch methods to btree_gist.
1 parent 785941c commit 55b59ed

File tree

3 files changed

+30
-8
lines changed

3 files changed

+30
-8
lines changed

src/backend/access/gist/gistscan.c

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,9 @@ gistbeginscan(PG_FUNCTION_ARGS)
8989
scan->opaque = so;
9090

9191
/*
92-
* All fields required for index-only scans are null until gistrescan.
93-
* However, we set up scan->xs_itupdesc whether we'll need it or not,
94-
* since that's cheap.
92+
* All fields required for index-only scans are initialized in gistrescan,
93+
* as we don't know yet if we're doing an index-only scan or not.
9594
*/
96-
scan->xs_itupdesc = RelationGetDescr(r);
9795

9896
MemoryContextSwitchTo(oldCxt);
9997

@@ -149,15 +147,37 @@ gistrescan(PG_FUNCTION_ARGS)
149147
}
150148

151149
/*
152-
* If we're doing an index-only scan, also create a memory context to hold
153-
* the returned tuples.
150+
* If we're doing an index-only scan, on the first call, also initialize
151+
* a tuple descriptor to represent the returned index tuples and create a
152+
* memory context to hold them during the scan.
154153
*/
155-
if (scan->xs_want_itup && so->pageDataCxt == NULL)
154+
if (scan->xs_want_itup && !scan->xs_itupdesc)
155+
{
156+
int natts;
157+
int attno;
158+
159+
/*
160+
* The storage type of the index can be different from the original
161+
* datatype being indexed, so we cannot just grab the index's tuple
162+
* descriptor. Instead, construct a descriptor with the original data
163+
* types.
164+
*/
165+
natts = RelationGetNumberOfAttributes(scan->indexRelation);
166+
so->giststate->fetchTupdesc = CreateTemplateTupleDesc(natts, false);
167+
for (attno = 1; attno <= natts; attno++)
168+
{
169+
TupleDescInitEntry(so->giststate->fetchTupdesc, attno, NULL,
170+
scan->indexRelation->rd_opcintype[attno - 1],
171+
-1, 0);
172+
}
173+
scan->xs_itupdesc = so->giststate->fetchTupdesc;
174+
156175
so->pageDataCxt = AllocSetContextCreate(so->giststate->scanCxt,
157176
"GiST page data context",
158177
ALLOCSET_DEFAULT_MINSIZE,
159178
ALLOCSET_DEFAULT_INITSIZE,
160179
ALLOCSET_DEFAULT_MAXSIZE);
180+
}
161181

162182
/* create new, empty RBTree for search queue */
163183
oldCxt = MemoryContextSwitchTo(so->queueCxt);

src/backend/access/gist/gistutil.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@ gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
657657
}
658658
MemoryContextSwitchTo(oldcxt);
659659

660-
return index_form_tuple(giststate->tupdesc, fetchatt, isnull);
660+
return index_form_tuple(giststate->fetchTupdesc, fetchatt, isnull);
661661
}
662662

663663
float

src/include/access/gist_private.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ typedef struct GISTSTATE
7878
MemoryContext tempCxt; /* short-term context for calling functions */
7979

8080
TupleDesc tupdesc; /* index's tuple descriptor */
81+
TupleDesc fetchTupdesc; /* tuple descriptor for tuples returned in an
82+
* index-only scan */
8183

8284
FmgrInfo consistentFn[INDEX_MAX_KEYS];
8385
FmgrInfo unionFn[INDEX_MAX_KEYS];

0 commit comments

Comments
 (0)