35
35
#include "access/tableam.h"
36
36
#include "access/tupdesc.h"
37
37
#include "access/visibilitymap.h"
38
+ #include "catalog/pg_type.h"
38
39
#include "executor/execdebug.h"
39
40
#include "executor/nodeIndexonlyscan.h"
40
41
#include "executor/nodeIndexscan.h"
41
42
#include "miscadmin.h"
42
43
#include "storage/bufmgr.h"
43
44
#include "storage/predicate.h"
45
+ #include "utils/builtins.h"
44
46
#include "utils/memutils.h"
45
47
#include "utils/rel.h"
46
48
47
49
48
50
static 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 );
51
53
52
54
53
55
/* ----------------------------------------------------------------
@@ -208,7 +210,7 @@ IndexOnlyNext(IndexOnlyScanState *node)
208
210
ExecForceStoreHeapTuple (scandesc -> xs_hitup , slot , false);
209
211
}
210
212
else if (scandesc -> xs_itup )
211
- StoreIndexTuple (slot , scandesc -> xs_itup , scandesc -> xs_itupdesc );
213
+ StoreIndexTuple (node , slot , scandesc -> xs_itup , scandesc -> xs_itupdesc );
212
214
else
213
215
elog (ERROR , "no data returned for index-only scan" );
214
216
@@ -266,7 +268,8 @@ IndexOnlyNext(IndexOnlyScanState *node)
266
268
* right now we don't need it elsewhere.
267
269
*/
268
270
static void
269
- StoreIndexTuple (TupleTableSlot * slot , IndexTuple itup , TupleDesc itupdesc )
271
+ StoreIndexTuple (IndexOnlyScanState * node , TupleTableSlot * slot ,
272
+ IndexTuple itup , TupleDesc itupdesc )
270
273
{
271
274
/*
272
275
* 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)
279
282
280
283
ExecClearTuple (slot );
281
284
index_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
+
282
316
ExecStoreVirtualTuple (slot );
283
317
}
284
318
@@ -492,8 +526,11 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
492
526
{
493
527
IndexOnlyScanState * indexstate ;
494
528
Relation currentRelation ;
529
+ Relation indexRelation ;
495
530
LOCKMODE lockmode ;
496
531
TupleDesc tupDesc ;
532
+ int indnkeyatts ;
533
+ int namecount ;
497
534
498
535
/*
499
536
* create state structure
@@ -566,7 +603,8 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
566
603
567
604
/* Open the index relation. */
568
605
lockmode = 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 ;
570
608
571
609
/*
572
610
* Initialize index-specific scan state
@@ -579,7 +617,7 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
579
617
* build the index scan keys from the index qualification
580
618
*/
581
619
ExecIndexBuildScanKeys ((PlanState * ) indexstate ,
582
- indexstate -> ioss_RelationDesc ,
620
+ indexRelation ,
583
621
node -> indexqual ,
584
622
false,
585
623
& indexstate -> ioss_ScanKeys ,
@@ -593,7 +631,7 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
593
631
* any ORDER BY exprs have to be turned into scankeys in the same way
594
632
*/
595
633
ExecIndexBuildScanKeys ((PlanState * ) indexstate ,
596
- indexstate -> ioss_RelationDesc ,
634
+ indexRelation ,
597
635
node -> indexorderby ,
598
636
true,
599
637
& indexstate -> ioss_OrderByKeys ,
@@ -622,6 +660,49 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
622
660
indexstate -> ioss_RuntimeContext = NULL ;
623
661
}
624
662
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
+
625
706
/*
626
707
* all done.
627
708
*/
0 commit comments