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
/* ----------------------------------------------------------------
@@ -206,7 +208,7 @@ IndexOnlyNext(IndexOnlyScanState *node)
206
208
ExecForceStoreHeapTuple (scandesc -> xs_hitup , slot , false);
207
209
}
208
210
else if (scandesc -> xs_itup )
209
- StoreIndexTuple (slot , scandesc -> xs_itup , scandesc -> xs_itupdesc );
211
+ StoreIndexTuple (node , slot , scandesc -> xs_itup , scandesc -> xs_itupdesc );
210
212
else
211
213
elog (ERROR , "no data returned for index-only scan" );
212
214
@@ -264,7 +266,8 @@ IndexOnlyNext(IndexOnlyScanState *node)
264
266
* right now we don't need it elsewhere.
265
267
*/
266
268
static void
267
- StoreIndexTuple (TupleTableSlot * slot , IndexTuple itup , TupleDesc itupdesc )
269
+ StoreIndexTuple (IndexOnlyScanState * node , TupleTableSlot * slot ,
270
+ IndexTuple itup , TupleDesc itupdesc )
268
271
{
269
272
/*
270
273
* 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)
277
280
278
281
ExecClearTuple (slot );
279
282
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
+
280
314
ExecStoreVirtualTuple (slot );
281
315
}
282
316
@@ -490,8 +524,11 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
490
524
{
491
525
IndexOnlyScanState * indexstate ;
492
526
Relation currentRelation ;
527
+ Relation indexRelation ;
493
528
LOCKMODE lockmode ;
494
529
TupleDesc tupDesc ;
530
+ int indnkeyatts ;
531
+ int namecount ;
495
532
496
533
/*
497
534
* create state structure
@@ -564,7 +601,8 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
564
601
565
602
/* Open the index relation. */
566
603
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 ;
568
606
569
607
/*
570
608
* Initialize index-specific scan state
@@ -577,7 +615,7 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
577
615
* build the index scan keys from the index qualification
578
616
*/
579
617
ExecIndexBuildScanKeys ((PlanState * ) indexstate ,
580
- indexstate -> ioss_RelationDesc ,
618
+ indexRelation ,
581
619
node -> indexqual ,
582
620
false,
583
621
& indexstate -> ioss_ScanKeys ,
@@ -591,7 +629,7 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
591
629
* any ORDER BY exprs have to be turned into scankeys in the same way
592
630
*/
593
631
ExecIndexBuildScanKeys ((PlanState * ) indexstate ,
594
- indexstate -> ioss_RelationDesc ,
632
+ indexRelation ,
595
633
node -> indexorderby ,
596
634
true,
597
635
& indexstate -> ioss_OrderByKeys ,
@@ -620,6 +658,49 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
620
658
indexstate -> ioss_RuntimeContext = NULL ;
621
659
}
622
660
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
+
623
704
/*
624
705
* all done.
625
706
*/
0 commit comments