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/* ----------------------------------------------------------------
@@ -206,7 +208,7 @@ IndexOnlyNext(IndexOnlyScanState *node)
206208ExecForceStoreHeapTuple (scandesc -> xs_hitup ,slot , false);
207209}
208210else if (scandesc -> xs_itup )
209- StoreIndexTuple (slot ,scandesc -> xs_itup ,scandesc -> xs_itupdesc );
211+ StoreIndexTuple (node , slot ,scandesc -> xs_itup ,scandesc -> xs_itupdesc );
210212else
211213elog (ERROR ,"no data returned for index-only scan" );
212214
@@ -264,7 +266,8 @@ IndexOnlyNext(IndexOnlyScanState *node)
264266 * right now we don't need it elsewhere.
265267 */
266268static void
267- StoreIndexTuple (TupleTableSlot * slot ,IndexTuple itup ,TupleDesc itupdesc )
269+ StoreIndexTuple (IndexOnlyScanState * node ,TupleTableSlot * slot ,
270+ IndexTuple itup ,TupleDesc itupdesc )
268271{
269272/*
270273 * Note: we must use the tupdesc supplied by the AM in index_deform_tuple,
@@ -277,6 +280,37 @@ StoreIndexTuple(TupleTableSlot *slot, IndexTuple itup, TupleDesc itupdesc)
277280
278281ExecClearTuple (slot );
279282index_deform_tuple (itup ,itupdesc ,slot -> tts_values ,slot -> tts_isnull );
283+
284+ /*
285+ * Copy all name columns stored as cstrings back into a NAMEDATALEN byte
286+ * sized allocation. We mark this branch as unlikely as generally "name"
287+ * is used only for the system catalogs and this would have to be a user
288+ * query running on those or some other user table with an index on a name
289+ * column.
290+ */
291+ if (unlikely (node -> ioss_NameCStringAttNums != NULL ))
292+ {
293+ int attcount = node -> ioss_NameCStringCount ;
294+
295+ for (int idx = 0 ;idx < attcount ;idx ++ )
296+ {
297+ int attnum = node -> ioss_NameCStringAttNums [idx ];
298+ Name name ;
299+
300+ /* skip null Datums */
301+ if (slot -> tts_isnull [attnum ])
302+ continue ;
303+
304+ /* allocate the NAMEDATALEN and copy the datum into that memory */
305+ name = (Name )MemoryContextAlloc (node -> ss .ps .ps_ExprContext -> ecxt_per_tuple_memory ,
306+ NAMEDATALEN );
307+
308+ /* use namestrcpy to zero-pad all trailing bytes */
309+ namestrcpy (name ,DatumGetCString (slot -> tts_values [attnum ]));
310+ slot -> tts_values [attnum ]= NameGetDatum (name );
311+ }
312+ }
313+
280314ExecStoreVirtualTuple (slot );
281315}
282316
@@ -490,8 +524,11 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
490524{
491525IndexOnlyScanState * indexstate ;
492526Relation currentRelation ;
527+ Relation indexRelation ;
493528LOCKMODE lockmode ;
494529TupleDesc tupDesc ;
530+ int indnkeyatts ;
531+ int namecount ;
495532
496533/*
497534 * create state structure
@@ -564,7 +601,8 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
564601
565602/* Open the index relation. */
566603lockmode = exec_rt_fetch (node -> scan .scanrelid ,estate )-> rellockmode ;
567- indexstate -> ioss_RelationDesc = index_open (node -> indexid ,lockmode );
604+ indexRelation = index_open (node -> indexid ,lockmode );
605+ indexstate -> ioss_RelationDesc = indexRelation ;
568606
569607/*
570608 * Initialize index-specific scan state
@@ -577,7 +615,7 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
577615 * build the index scan keys from the index qualification
578616 */
579617ExecIndexBuildScanKeys ((PlanState * )indexstate ,
580- indexstate -> ioss_RelationDesc ,
618+ indexRelation ,
581619node -> indexqual ,
582620 false,
583621& indexstate -> ioss_ScanKeys ,
@@ -591,7 +629,7 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
591629 * any ORDER BY exprs have to be turned into scankeys in the same way
592630 */
593631ExecIndexBuildScanKeys ((PlanState * )indexstate ,
594- indexstate -> ioss_RelationDesc ,
632+ indexRelation ,
595633node -> indexorderby ,
596634 true,
597635& indexstate -> ioss_OrderByKeys ,
@@ -620,6 +658,49 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
620658indexstate -> ioss_RuntimeContext = NULL ;
621659}
622660
661+ indexstate -> ioss_NameCStringAttNums = NULL ;
662+ indnkeyatts = indexRelation -> rd_index -> indnkeyatts ;
663+ namecount = 0 ;
664+
665+ /*
666+ * The "name" type for btree uses text_ops which results in storing
667+ * cstrings in the indexed keys rather than names. Here we detect that in
668+ * a generic way in case other index AMs want to do the same optimization.
669+ * Check for opclasses with an opcintype of NAMEOID and an index tuple
670+ * descriptor with CSTRINGOID. If any of these are found, create an array
671+ * marking the index attribute number of each of them. StoreIndexTuple()
672+ * handles copying the name Datums into a NAMEDATALEN-byte allocation.
673+ */
674+
675+ /* First, count the number of such index keys */
676+ for (int attnum = 0 ;attnum < indnkeyatts ;attnum ++ )
677+ {
678+ if (indexRelation -> rd_att -> attrs [attnum ].atttypid == CSTRINGOID &&
679+ indexRelation -> rd_opcintype [attnum ]== NAMEOID )
680+ namecount ++ ;
681+ }
682+
683+ if (namecount > 0 )
684+ {
685+ int idx = 0 ;
686+
687+ /*
688+ * Now create an array to mark the attribute numbers of the keys that
689+ * need to be converted from cstring to name.
690+ */
691+ indexstate -> ioss_NameCStringAttNums = (AttrNumber * )
692+ palloc (sizeof (AttrNumber )* namecount );
693+
694+ for (int attnum = 0 ;attnum < indnkeyatts ;attnum ++ )
695+ {
696+ if (indexRelation -> rd_att -> attrs [attnum ].atttypid == CSTRINGOID &&
697+ indexRelation -> rd_opcintype [attnum ]== NAMEOID )
698+ indexstate -> ioss_NameCStringAttNums [idx ++ ]= (AttrNumber )attnum ;
699+ }
700+ }
701+
702+ indexstate -> ioss_NameCStringCount = namecount ;
703+
623704/*
624705 * all done.
625706 */