Commit 55b59eda authored by Heikki Linnakangas's avatar Heikki Linnakangas

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.
parent 785941cd
...@@ -89,11 +89,9 @@ gistbeginscan(PG_FUNCTION_ARGS) ...@@ -89,11 +89,9 @@ gistbeginscan(PG_FUNCTION_ARGS)
scan->opaque = so; scan->opaque = so;
/* /*
* All fields required for index-only scans are null until gistrescan. * All fields required for index-only scans are initialized in gistrescan,
* However, we set up scan->xs_itupdesc whether we'll need it or not, * as we don't know yet if we're doing an index-only scan or not.
* since that's cheap.
*/ */
scan->xs_itupdesc = RelationGetDescr(r);
MemoryContextSwitchTo(oldCxt); MemoryContextSwitchTo(oldCxt);
...@@ -149,15 +147,37 @@ gistrescan(PG_FUNCTION_ARGS) ...@@ -149,15 +147,37 @@ gistrescan(PG_FUNCTION_ARGS)
} }
/* /*
* If we're doing an index-only scan, also create a memory context to hold * If we're doing an index-only scan, on the first call, also initialize
* the returned tuples. * a tuple descriptor to represent the returned index tuples and create a
* memory context to hold them during the scan.
*/ */
if (scan->xs_want_itup && so->pageDataCxt == NULL) if (scan->xs_want_itup && !scan->xs_itupdesc)
{
int natts;
int attno;
/*
* The storage type of the index can be different from the original
* datatype being indexed, so we cannot just grab the index's tuple
* descriptor. Instead, construct a descriptor with the original data
* types.
*/
natts = RelationGetNumberOfAttributes(scan->indexRelation);
so->giststate->fetchTupdesc = CreateTemplateTupleDesc(natts, false);
for (attno = 1; attno <= natts; attno++)
{
TupleDescInitEntry(so->giststate->fetchTupdesc, attno, NULL,
scan->indexRelation->rd_opcintype[attno - 1],
-1, 0);
}
scan->xs_itupdesc = so->giststate->fetchTupdesc;
so->pageDataCxt = AllocSetContextCreate(so->giststate->scanCxt, so->pageDataCxt = AllocSetContextCreate(so->giststate->scanCxt,
"GiST page data context", "GiST page data context",
ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE); ALLOCSET_DEFAULT_MAXSIZE);
}
/* create new, empty RBTree for search queue */ /* create new, empty RBTree for search queue */
oldCxt = MemoryContextSwitchTo(so->queueCxt); oldCxt = MemoryContextSwitchTo(so->queueCxt);
......
...@@ -657,7 +657,7 @@ gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple) ...@@ -657,7 +657,7 @@ gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
} }
MemoryContextSwitchTo(oldcxt); MemoryContextSwitchTo(oldcxt);
return index_form_tuple(giststate->tupdesc, fetchatt, isnull); return index_form_tuple(giststate->fetchTupdesc, fetchatt, isnull);
} }
float float
......
...@@ -78,6 +78,8 @@ typedef struct GISTSTATE ...@@ -78,6 +78,8 @@ typedef struct GISTSTATE
MemoryContext tempCxt; /* short-term context for calling functions */ MemoryContext tempCxt; /* short-term context for calling functions */
TupleDesc tupdesc; /* index's tuple descriptor */ TupleDesc tupdesc; /* index's tuple descriptor */
TupleDesc fetchTupdesc; /* tuple descriptor for tuples returned in an
* index-only scan */
FmgrInfo consistentFn[INDEX_MAX_KEYS]; FmgrInfo consistentFn[INDEX_MAX_KEYS];
FmgrInfo unionFn[INDEX_MAX_KEYS]; FmgrInfo unionFn[INDEX_MAX_KEYS];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment