Generate index-only scan tuple descriptor from the plan node's indextlist.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 11 Oct 2011 22:11:51 +0000 (18:11 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 11 Oct 2011 22:12:57 +0000 (18:12 -0400)
Dept. of second thoughts: as long as we've got that tlist hanging around
anyway, we can apply ExecTypeFromTL to it to get a suitable descriptor for
the ScanTupleSlot.  This is a nicer solution than the previous one because
it eliminates some hard-wired knowledge about btree name_ops, and because
it avoids the somewhat shaky assumption that we needn't set up the scan
tuple descriptor in EXPLAIN_ONLY mode.  It doesn't change what actually
happens at run-time though, and I'm still a bit nervous about that.

src/backend/executor/nodeIndexonlyscan.c

index 487373b49703fe3c6729f1c39d985fdbb590d351..e3742cf71d05c88e8e7a557144261eacc5837654 100644 (file)
@@ -26,8 +26,6 @@
 
 #include "access/relscan.h"
 #include "access/visibilitymap.h"
-#include "catalog/pg_opfamily.h"
-#include "catalog/pg_type.h"
 #include "executor/execdebug.h"
 #include "executor/nodeIndexonlyscan.h"
 #include "executor/nodeIndexscan.h"
@@ -162,8 +160,10 @@ StoreIndexTuple(TupleTableSlot *slot, IndexTuple itup, Relation indexRel)
        int                     i;
 
        /*
-        * Note: we must use the index relation's tupdesc in index_getattr,
-        * not the slot's tupdesc, because of index_descriptor_hack().
+        * Note: we must use the index relation's tupdesc in index_getattr, not
+        * the slot's tupdesc, in case the latter has different datatypes (this
+        * happens for btree name_ops in particular).  They'd better have the same
+        * number of columns though.
         */
        Assert(slot->tts_tupleDescriptor->natts == nindexatts);
 
@@ -173,45 +173,6 @@ StoreIndexTuple(TupleTableSlot *slot, IndexTuple itup, Relation indexRel)
        ExecStoreVirtualTuple(slot);
 }
 
-/*
- * index_descriptor_hack -- ugly kluge to make index's tupdesc OK for slot
- *
- * This is necessary because, alone among btree opclasses, name_ops uses
- * a storage type (cstring) different from its input type.  The index
- * tuple descriptor will show "cstring", which is correct, but we have to
- * expose "name" as the slot datatype or ExecEvalVar will whine.  If we
- * ever want to have any other cases with a different storage type, we ought
- * to think of a cleaner solution than this.
- */
-static TupleDesc
-index_descriptor_hack(Relation indexRel)
-{
-       TupleDesc       tupdesc = RelationGetDescr(indexRel);
-       int                     i;
-
-       /* copy so we can scribble on it safely */
-       tupdesc = CreateTupleDescCopy(tupdesc);
-
-       for (i = 0; i < tupdesc->natts; i++)
-       {
-               if (indexRel->rd_opfamily[i] == NAME_BTREE_FAM_OID &&
-                       tupdesc->attrs[i]->atttypid == CSTRINGOID)
-               {
-                       tupdesc->attrs[i]->atttypid = NAMEOID;
-
-                       /*
-                        * We set attlen to match the type OID just in case anything looks
-                        * at it.  Note that this is safe only because StoreIndexTuple
-                        * will insert the data as a virtual tuple, and we don't expect
-                        * anything will try to materialize the scan tuple slot.
-                        */
-                       tupdesc->attrs[i]->attlen = NAMEDATALEN;
-               }
-       }
-
-       return tupdesc;
-}
-
 /*
  * IndexOnlyRecheck -- access method routine to recheck a tuple in EvalPlanQual
  *
@@ -426,9 +387,20 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
        indexstate->ss.ss_currentScanDesc = NULL;       /* no heap scan here */
 
        /*
-        * Initialize result tuple type.
+        * Build the scan tuple type using the indextlist generated by the
+        * planner.  We use this, rather than the index's physical tuple
+        * descriptor, because the latter contains storage column types not the
+        * types of the original datums.  (It's the AM's responsibility to return
+        * suitable data anyway.)
+        */
+       tupDesc = ExecTypeFromTL(node->indextlist, false);
+       ExecAssignScanType(&indexstate->ss, tupDesc);
+
+       /*
+        * Initialize result tuple type and projection info.
         */
        ExecAssignResultTypeFromTL(&indexstate->ss.ps);
+       ExecAssignScanProjectionInfo(&indexstate->ss);
 
        /*
         * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
@@ -449,14 +421,6 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
        indexstate->ioss_RelationDesc = index_open(node->indexid,
                                                                         relistarget ? NoLock : AccessShareLock);
 
-       /*
-        * Now we can get the scan tuple's type (which is the index's rowtype,
-        * not the heap's) and initialize result projection info.
-        */
-       tupDesc = index_descriptor_hack(indexstate->ioss_RelationDesc);
-       ExecAssignScanType(&indexstate->ss, tupDesc);
-       ExecAssignScanProjectionInfo(&indexstate->ss);
-
        /*
         * Initialize index-specific scan state
         */