aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/gist
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2015-03-26 23:07:52 +0200
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2015-03-26 23:07:52 +0200
commit55b59eda13a742f8af913734e22ecc8a21754414 (patch)
tree4bbe77575d9eb2f27d0c770d07fc10095ea329f6 /src/backend/access/gist
parent785941cdc359c6e595201ffb0df9d28f3f7173a4 (diff)
downloadpostgresql-55b59eda13a742f8af913734e22ecc8a21754414.tar.gz
postgresql-55b59eda13a742f8af913734e22ecc8a21754414.zip
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.
Diffstat (limited to 'src/backend/access/gist')
-rw-r--r--src/backend/access/gist/gistscan.c34
-rw-r--r--src/backend/access/gist/gistutil.c2
2 files changed, 28 insertions, 8 deletions
diff --git a/src/backend/access/gist/gistscan.c b/src/backend/access/gist/gistscan.c
index 3522d75a496..6f653982302 100644
--- a/src/backend/access/gist/gistscan.c
+++ b/src/backend/access/gist/gistscan.c
@@ -89,11 +89,9 @@ gistbeginscan(PG_FUNCTION_ARGS)
scan->opaque = so;
/*
- * All fields required for index-only scans are null until gistrescan.
- * However, we set up scan->xs_itupdesc whether we'll need it or not,
- * since that's cheap.
+ * All fields required for index-only scans are initialized in gistrescan,
+ * as we don't know yet if we're doing an index-only scan or not.
*/
- scan->xs_itupdesc = RelationGetDescr(r);
MemoryContextSwitchTo(oldCxt);
@@ -149,15 +147,37 @@ gistrescan(PG_FUNCTION_ARGS)
}
/*
- * If we're doing an index-only scan, also create a memory context to hold
- * the returned tuples.
+ * If we're doing an index-only scan, on the first call, also initialize
+ * 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,
"GiST page data context",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
+ }
/* create new, empty RBTree for search queue */
oldCxt = MemoryContextSwitchTo(so->queueCxt);
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 1680251a18b..bf9fbf30a8b 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -657,7 +657,7 @@ gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
}
MemoryContextSwitchTo(oldcxt);
- return index_form_tuple(giststate->tupdesc, fetchatt, isnull);
+ return index_form_tuple(giststate->fetchTupdesc, fetchatt, isnull);
}
float