]> granicus.if.org Git - postgresql/commitdiff
Fix GiST index-only scans for opclasses with different storage type.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Thu, 26 Mar 2015 21:07:52 +0000 (23:07 +0200)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Thu, 26 Mar 2015 21:07:52 +0000 (23:07 +0200)
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.

src/backend/access/gist/gistscan.c
src/backend/access/gist/gistutil.c
src/include/access/gist_private.h

index 3522d75a49674ff05f9ffefc6e192556da892efe..6f6539823026052b2690469c373ee564898fa2a8 100644 (file)
@@ -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);
index 1680251a18b647998e8aeab9c507b71b62220a8a..bf9fbf30a8b0f30d970acefbf79b722ba15a8c31 100644 (file)
@@ -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
index 3693893e261dde172cb690d2262342a8ca312ca2..9d3714d27d207e22c552b4035849ceb5d53c9ddb 100644 (file)
@@ -78,6 +78,8 @@ typedef struct GISTSTATE
        MemoryContext tempCxt;          /* short-term context for calling functions */
 
        TupleDesc       tupdesc;                /* index's tuple descriptor */
+       TupleDesc       fetchTupdesc;   /* tuple descriptor for tuples returned in an
+                                                                * index-only scan */
 
        FmgrInfo        consistentFn[INDEX_MAX_KEYS];
        FmgrInfo        unionFn[INDEX_MAX_KEYS];