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/executor.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/rel.h"
45
47
46
48
47
49
static 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 );
50
52
51
53
52
54
/* ----------------------------------------------------------------
@@ -205,7 +207,7 @@ IndexOnlyNext(IndexOnlyScanState *node)
205
207
ExecForceStoreHeapTuple (scandesc -> xs_hitup , slot , false);
206
208
}
207
209
else if (scandesc -> xs_itup )
208
- StoreIndexTuple (slot , scandesc -> xs_itup , scandesc -> xs_itupdesc );
210
+ StoreIndexTuple (node , slot , scandesc -> xs_itup , scandesc -> xs_itupdesc );
209
211
else
210
212
elog (ERROR , "no data returned for index-only scan" );
211
213
@@ -263,7 +265,8 @@ IndexOnlyNext(IndexOnlyScanState *node)
263
265
* right now we don't need it elsewhere.
264
266
*/
265
267
static void
266
- StoreIndexTuple (TupleTableSlot * slot , IndexTuple itup , TupleDesc itupdesc )
268
+ StoreIndexTuple (IndexOnlyScanState * node , TupleTableSlot * slot ,
269
+ IndexTuple itup , TupleDesc itupdesc )
267
270
{
268
271
/*
269
272
* 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)
276
279
277
280
ExecClearTuple (slot );
278
281
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
+
279
313
ExecStoreVirtualTuple (slot );
280
314
}
281
315
@@ -473,8 +507,11 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
473
507
{
474
508
IndexOnlyScanState * indexstate ;
475
509
Relation currentRelation ;
510
+ Relation indexRelation ;
476
511
LOCKMODE lockmode ;
477
512
TupleDesc tupDesc ;
513
+ int indnkeyatts ;
514
+ int namecount ;
478
515
479
516
/*
480
517
* create state structure
@@ -547,7 +584,8 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
547
584
548
585
/* Open the index relation. */
549
586
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 ;
551
589
552
590
/*
553
591
* Initialize index-specific scan state
@@ -560,7 +598,7 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
560
598
* build the index scan keys from the index qualification
561
599
*/
562
600
ExecIndexBuildScanKeys ((PlanState * ) indexstate ,
563
- indexstate -> ioss_RelationDesc ,
601
+ indexRelation ,
564
602
node -> indexqual ,
565
603
false,
566
604
& indexstate -> ioss_ScanKeys ,
@@ -574,7 +612,7 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
574
612
* any ORDER BY exprs have to be turned into scankeys in the same way
575
613
*/
576
614
ExecIndexBuildScanKeys ((PlanState * ) indexstate ,
577
- indexstate -> ioss_RelationDesc ,
615
+ indexRelation ,
578
616
node -> indexorderby ,
579
617
true,
580
618
& indexstate -> ioss_OrderByKeys ,
@@ -603,6 +641,49 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
603
641
indexstate -> ioss_RuntimeContext = NULL ;
604
642
}
605
643
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
+
606
687
/*
607
688
* all done.
608
689
*/
0 commit comments