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)
206208 ExecForceStoreHeapTuple (scandesc -> xs_hitup , slot , false);
207209 }
208210 else if (scandesc -> xs_itup )
209- StoreIndexTuple (slot , scandesc -> xs_itup , scandesc -> xs_itupdesc );
211+ StoreIndexTuple (node , slot , scandesc -> xs_itup , scandesc -> xs_itupdesc );
210212 else
211213 elog (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
278281 ExecClearTuple (slot );
279282 index_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+
280314 ExecStoreVirtualTuple (slot );
281315}
282316
@@ -490,8 +524,11 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
490524{
491525 IndexOnlyScanState * indexstate ;
492526 Relation currentRelation ;
527+ Relation indexRelation ;
493528 LOCKMODE lockmode ;
494529 TupleDesc 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. */
566603 lockmode = 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 */
579617 ExecIndexBuildScanKeys ((PlanState * ) indexstate ,
580- indexstate -> ioss_RelationDesc ,
618+ indexRelation ,
581619 node -> 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 */
593631 ExecIndexBuildScanKeys ((PlanState * ) indexstate ,
594- indexstate -> ioss_RelationDesc ,
632+ indexRelation ,
595633 node -> indexorderby ,
596634 true,
597635 & indexstate -> ioss_OrderByKeys ,
@@ -620,6 +658,49 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
620658 indexstate -> 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 */
0 commit comments