3535#include "access/tableam.h"
3636#include "access/tupdesc.h"
3737#include "access/visibilitymap.h"
38+ #include "catalog/pg_type.h"
3839#include "executor/executor.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/rel.h"
4547
4648
4749static TupleTableSlot * IndexOnlyNext (IndexOnlyScanState * node );
48- static void StoreIndexTuple (TupleTableSlot * slot , IndexTuple itup ,
49- TupleDesc itupdesc );
50+ static void StoreIndexTuple (IndexOnlyScanState * node , TupleTableSlot * slot ,
51+ IndexTuple itup , TupleDesc itupdesc );
5052
5153
5254/* ----------------------------------------------------------------
@@ -205,7 +207,7 @@ IndexOnlyNext(IndexOnlyScanState *node)
205207 ExecForceStoreHeapTuple (scandesc -> xs_hitup , slot , false);
206208 }
207209 else if (scandesc -> xs_itup )
208- StoreIndexTuple (slot , scandesc -> xs_itup , scandesc -> xs_itupdesc );
210+ StoreIndexTuple (node , slot , scandesc -> xs_itup , scandesc -> xs_itupdesc );
209211 else
210212 elog (ERROR , "no data returned for index-only scan" );
211213
@@ -263,7 +265,8 @@ IndexOnlyNext(IndexOnlyScanState *node)
263265 * right now we don't need it elsewhere.
264266 */
265267static void
266- StoreIndexTuple (TupleTableSlot * slot , IndexTuple itup , TupleDesc itupdesc )
268+ StoreIndexTuple (IndexOnlyScanState * node , TupleTableSlot * slot ,
269+ IndexTuple itup , TupleDesc itupdesc )
267270{
268271 /*
269272 * Note: we must use the tupdesc supplied by the AM in index_deform_tuple,
@@ -276,6 +279,37 @@ StoreIndexTuple(TupleTableSlot *slot, IndexTuple itup, TupleDesc itupdesc)
276279
277280 ExecClearTuple (slot );
278281 index_deform_tuple (itup , itupdesc , slot -> tts_values , slot -> tts_isnull );
282+
283+ /*
284+ * Copy all name columns stored as cstrings back into a NAMEDATALEN byte
285+ * sized allocation. We mark this branch as unlikely as generally "name"
286+ * is used only for the system catalogs and this would have to be a user
287+ * query running on those or some other user table with an index on a name
288+ * column.
289+ */
290+ if (unlikely (node -> ioss_NameCStringAttNums != NULL ))
291+ {
292+ int attcount = node -> ioss_NameCStringCount ;
293+
294+ for (int idx = 0 ; idx < attcount ; idx ++ )
295+ {
296+ int attnum = node -> ioss_NameCStringAttNums [idx ];
297+ Name name ;
298+
299+ /* skip null Datums */
300+ if (slot -> tts_isnull [attnum ])
301+ continue ;
302+
303+ /* allocate the NAMEDATALEN and copy the datum into that memory */
304+ name = (Name ) MemoryContextAlloc (node -> ss .ps .ps_ExprContext -> ecxt_per_tuple_memory ,
305+ NAMEDATALEN );
306+
307+ /* use namestrcpy to zero-pad all trailing bytes */
308+ namestrcpy (name , DatumGetCString (slot -> tts_values [attnum ]));
309+ slot -> tts_values [attnum ] = NameGetDatum (name );
310+ }
311+ }
312+
279313 ExecStoreVirtualTuple (slot );
280314}
281315
@@ -473,8 +507,11 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
473507{
474508 IndexOnlyScanState * indexstate ;
475509 Relation currentRelation ;
510+ Relation indexRelation ;
476511 LOCKMODE lockmode ;
477512 TupleDesc tupDesc ;
513+ int indnkeyatts ;
514+ int namecount ;
478515
479516 /*
480517 * create state structure
@@ -547,7 +584,8 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
547584
548585 /* Open the index relation. */
549586 lockmode = exec_rt_fetch (node -> scan .scanrelid , estate )-> rellockmode ;
550- indexstate -> ioss_RelationDesc = index_open (node -> indexid , lockmode );
587+ indexRelation = index_open (node -> indexid , lockmode );
588+ indexstate -> ioss_RelationDesc = indexRelation ;
551589
552590 /*
553591 * Initialize index-specific scan state
@@ -560,7 +598,7 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
560598 * build the index scan keys from the index qualification
561599 */
562600 ExecIndexBuildScanKeys ((PlanState * ) indexstate ,
563- indexstate -> ioss_RelationDesc ,
601+ indexRelation ,
564602 node -> indexqual ,
565603 false,
566604 & indexstate -> ioss_ScanKeys ,
@@ -574,7 +612,7 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
574612 * any ORDER BY exprs have to be turned into scankeys in the same way
575613 */
576614 ExecIndexBuildScanKeys ((PlanState * ) indexstate ,
577- indexstate -> ioss_RelationDesc ,
615+ indexRelation ,
578616 node -> indexorderby ,
579617 true,
580618 & indexstate -> ioss_OrderByKeys ,
@@ -603,6 +641,49 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
603641 indexstate -> ioss_RuntimeContext = NULL ;
604642 }
605643
644+ indexstate -> ioss_NameCStringAttNums = NULL ;
645+ indnkeyatts = indexRelation -> rd_index -> indnkeyatts ;
646+ namecount = 0 ;
647+
648+ /*
649+ * The "name" type for btree uses text_ops which results in storing
650+ * cstrings in the indexed keys rather than names. Here we detect that in
651+ * a generic way in case other index AMs want to do the same optimization.
652+ * Check for opclasses with an opcintype of NAMEOID and an index tuple
653+ * descriptor with CSTRINGOID. If any of these are found, create an array
654+ * marking the index attribute number of each of them. StoreIndexTuple()
655+ * handles copying the name Datums into a NAMEDATALEN-byte allocation.
656+ */
657+
658+ /* First, count the number of such index keys */
659+ for (int attnum = 0 ; attnum < indnkeyatts ; attnum ++ )
660+ {
661+ if (indexRelation -> rd_att -> attrs [attnum ].atttypid == CSTRINGOID &&
662+ indexRelation -> rd_opcintype [attnum ] == NAMEOID )
663+ namecount ++ ;
664+ }
665+
666+ if (namecount > 0 )
667+ {
668+ int idx = 0 ;
669+
670+ /*
671+ * Now create an array to mark the attribute numbers of the keys that
672+ * need to be converted from cstring to name.
673+ */
674+ indexstate -> ioss_NameCStringAttNums = (AttrNumber * )
675+ palloc (sizeof (AttrNumber ) * namecount );
676+
677+ for (int attnum = 0 ; attnum < indnkeyatts ; attnum ++ )
678+ {
679+ if (indexRelation -> rd_att -> attrs [attnum ].atttypid == CSTRINGOID &&
680+ indexRelation -> rd_opcintype [attnum ] == NAMEOID )
681+ indexstate -> ioss_NameCStringAttNums [idx ++ ] = (AttrNumber ) attnum ;
682+ }
683+ }
684+
685+ indexstate -> ioss_NameCStringCount = namecount ;
686+
606687 /*
607688 * all done.
608689 */
0 commit comments