3535#include "access/tableam.h"
3636#include "access/tupdesc.h"
3737#include "access/visibilitymap.h"
38+ #include "catalog/pg_type.h"
3839#include "executor/execdebug.h"
3940#include "executor/nodeIndexonlyscan.h"
4041#include "executor/nodeIndexscan.h"
4142#include "miscadmin.h"
4243#include "storage/bufmgr.h"
4344#include "storage/predicate.h"
45+ #include "utils/builtins.h"
4446#include "utils/memutils.h"
4547#include "utils/rel.h"
4648
4749
4850static TupleTableSlot * IndexOnlyNext (IndexOnlyScanState * node );
49- static void StoreIndexTuple (TupleTableSlot * slot , IndexTuple itup ,
50- TupleDesc itupdesc );
51+ static void StoreIndexTuple (IndexOnlyScanState * node , TupleTableSlot * slot ,
52+ IndexTuple itup , TupleDesc itupdesc );
5153
5254
5355/* ----------------------------------------------------------------
@@ -208,7 +210,7 @@ IndexOnlyNext(IndexOnlyScanState *node)
208210ExecForceStoreHeapTuple (scandesc -> xs_hitup ,slot , false);
209211}
210212else if (scandesc -> xs_itup )
211- StoreIndexTuple (slot ,scandesc -> xs_itup ,scandesc -> xs_itupdesc );
213+ StoreIndexTuple (node , slot ,scandesc -> xs_itup ,scandesc -> xs_itupdesc );
212214else
213215elog (ERROR ,"no data returned for index-only scan" );
214216
@@ -266,7 +268,8 @@ IndexOnlyNext(IndexOnlyScanState *node)
266268 * right now we don't need it elsewhere.
267269 */
268270static void
269- StoreIndexTuple (TupleTableSlot * slot ,IndexTuple itup ,TupleDesc itupdesc )
271+ StoreIndexTuple (IndexOnlyScanState * node ,TupleTableSlot * slot ,
272+ IndexTuple itup ,TupleDesc itupdesc )
270273{
271274/*
272275 * Note: we must use the tupdesc supplied by the AM in index_deform_tuple,
@@ -279,6 +282,37 @@ StoreIndexTuple(TupleTableSlot *slot, IndexTuple itup, TupleDesc itupdesc)
279282
280283ExecClearTuple (slot );
281284index_deform_tuple (itup ,itupdesc ,slot -> tts_values ,slot -> tts_isnull );
285+
286+ /*
287+ * Copy all name columns stored as cstrings back into a NAMEDATALEN byte
288+ * sized allocation. We mark this branch as unlikely as generally "name"
289+ * is used only for the system catalogs and this would have to be a user
290+ * query running on those or some other user table with an index on a name
291+ * column.
292+ */
293+ if (unlikely (node -> ioss_NameCStringAttNums != NULL ))
294+ {
295+ int attcount = node -> ioss_NameCStringCount ;
296+
297+ for (int idx = 0 ;idx < attcount ;idx ++ )
298+ {
299+ int attnum = node -> ioss_NameCStringAttNums [idx ];
300+ Name name ;
301+
302+ /* skip null Datums */
303+ if (slot -> tts_isnull [attnum ])
304+ continue ;
305+
306+ /* allocate the NAMEDATALEN and copy the datum into that memory */
307+ name = (Name )MemoryContextAlloc (node -> ss .ps .ps_ExprContext -> ecxt_per_tuple_memory ,
308+ NAMEDATALEN );
309+
310+ /* use namestrcpy to zero-pad all trailing bytes */
311+ namestrcpy (name ,DatumGetCString (slot -> tts_values [attnum ]));
312+ slot -> tts_values [attnum ]= NameGetDatum (name );
313+ }
314+ }
315+
282316ExecStoreVirtualTuple (slot );
283317}
284318
@@ -492,8 +526,11 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
492526{
493527IndexOnlyScanState * indexstate ;
494528Relation currentRelation ;
529+ Relation indexRelation ;
495530LOCKMODE lockmode ;
496531TupleDesc tupDesc ;
532+ int indnkeyatts ;
533+ int namecount ;
497534
498535/*
499536 * create state structure
@@ -566,7 +603,8 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
566603
567604/* Open the index relation. */
568605lockmode = exec_rt_fetch (node -> scan .scanrelid ,estate )-> rellockmode ;
569- indexstate -> ioss_RelationDesc = index_open (node -> indexid ,lockmode );
606+ indexRelation = index_open (node -> indexid ,lockmode );
607+ indexstate -> ioss_RelationDesc = indexRelation ;
570608
571609/*
572610 * Initialize index-specific scan state
@@ -579,7 +617,7 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
579617 * build the index scan keys from the index qualification
580618 */
581619ExecIndexBuildScanKeys ((PlanState * )indexstate ,
582- indexstate -> ioss_RelationDesc ,
620+ indexRelation ,
583621node -> indexqual ,
584622 false,
585623& indexstate -> ioss_ScanKeys ,
@@ -593,7 +631,7 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
593631 * any ORDER BY exprs have to be turned into scankeys in the same way
594632 */
595633ExecIndexBuildScanKeys ((PlanState * )indexstate ,
596- indexstate -> ioss_RelationDesc ,
634+ indexRelation ,
597635node -> indexorderby ,
598636 true,
599637& indexstate -> ioss_OrderByKeys ,
@@ -622,6 +660,49 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
622660indexstate -> ioss_RuntimeContext = NULL ;
623661}
624662
663+ indexstate -> ioss_NameCStringAttNums = NULL ;
664+ indnkeyatts = indexRelation -> rd_index -> indnkeyatts ;
665+ namecount = 0 ;
666+
667+ /*
668+ * The "name" type for btree uses text_ops which results in storing
669+ * cstrings in the indexed keys rather than names. Here we detect that in
670+ * a generic way in case other index AMs want to do the same optimization.
671+ * Check for opclasses with an opcintype of NAMEOID and an index tuple
672+ * descriptor with CSTRINGOID. If any of these are found, create an array
673+ * marking the index attribute number of each of them. StoreIndexTuple()
674+ * handles copying the name Datums into a NAMEDATALEN-byte allocation.
675+ */
676+
677+ /* First, count the number of such index keys */
678+ for (int attnum = 0 ;attnum < indnkeyatts ;attnum ++ )
679+ {
680+ if (indexRelation -> rd_att -> attrs [attnum ].atttypid == CSTRINGOID &&
681+ indexRelation -> rd_opcintype [attnum ]== NAMEOID )
682+ namecount ++ ;
683+ }
684+
685+ if (namecount > 0 )
686+ {
687+ int idx = 0 ;
688+
689+ /*
690+ * Now create an array to mark the attribute numbers of the keys that
691+ * need to be converted from cstring to name.
692+ */
693+ indexstate -> ioss_NameCStringAttNums = (AttrNumber * )
694+ palloc (sizeof (AttrNumber )* namecount );
695+
696+ for (int attnum = 0 ;attnum < indnkeyatts ;attnum ++ )
697+ {
698+ if (indexRelation -> rd_att -> attrs [attnum ].atttypid == CSTRINGOID &&
699+ indexRelation -> rd_opcintype [attnum ]== NAMEOID )
700+ indexstate -> ioss_NameCStringAttNums [idx ++ ]= (AttrNumber )attnum ;
701+ }
702+ }
703+
704+ indexstate -> ioss_NameCStringCount = namecount ;
705+
625706/*
626707 * all done.
627708 */