diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c index 0b43a9b969..87c02e8751 100644 --- a/src/backend/executor/nodeIndexonlyscan.c +++ b/src/backend/executor/nodeIndexonlyscan.c @@ -41,13 +41,14 @@ #include "miscadmin.h" #include "storage/bufmgr.h" #include "storage/predicate.h" +#include "utils/builtins.h" #include "utils/memutils.h" #include "utils/rel.h" static TupleTableSlot *IndexOnlyNext(IndexOnlyScanState *node); -static void StoreIndexTuple(TupleTableSlot *slot, IndexTuple itup, - TupleDesc itupdesc); +static void StoreIndexTuple(IndexOnlyScanState *node, TupleTableSlot *slot, + IndexTuple itup, TupleDesc itupdesc); /* ---------------------------------------------------------------- @@ -206,7 +207,7 @@ IndexOnlyNext(IndexOnlyScanState *node) ExecForceStoreHeapTuple(scandesc->xs_hitup, slot, false); } else if (scandesc->xs_itup) - StoreIndexTuple(slot, scandesc->xs_itup, scandesc->xs_itupdesc); + StoreIndexTuple(node, slot, scandesc->xs_itup, scandesc->xs_itupdesc); else elog(ERROR, "no data returned for index-only scan"); @@ -264,7 +265,8 @@ IndexOnlyNext(IndexOnlyScanState *node) * right now we don't need it elsewhere. */ static void -StoreIndexTuple(TupleTableSlot *slot, IndexTuple itup, TupleDesc itupdesc) +StoreIndexTuple(IndexOnlyScanState *node, TupleTableSlot *slot, + IndexTuple itup, TupleDesc itupdesc) { /* * Note: we must use the tupdesc supplied by the AM in index_deform_tuple, @@ -277,6 +279,26 @@ StoreIndexTuple(TupleTableSlot *slot, IndexTuple itup, TupleDesc itupdesc) ExecClearTuple(slot); index_deform_tuple(itup, itupdesc, slot->tts_values, slot->tts_isnull); + + if (node->ioss_ConvertDatumIdxs != NULL) + { + for (int i = 0; i < node->ioss_ConvertDatumCount; i++) + { + int j = node->ioss_ConvertDatumIdxs[i]; + Name name; + + /* skip null Datums */ + if (slot->tts_isnull[j]) + continue; + + name = (Name) MemoryContextAlloc(node->ss.ps.ps_ExprContext->ecxt_per_tuple_memory, + NAMEDATALEN); + + namestrcpy(name, DatumGetCString(slot->tts_values[j])); + slot->tts_values[j] = NameGetDatum(name); + } + } + ExecStoreVirtualTuple(slot); } @@ -620,6 +642,32 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags) indexstate->ioss_RuntimeContext = NULL; } + indexstate->ioss_ConvertDatumIdxs = NULL; + indexstate->ioss_ConvertDatumCount = 0; + + { + int name_count = 0; + for (int i = 0; i < tupDesc->natts; i++) + { + if (tupDesc->attrs[i].atttypid == NAMEOID) + name_count++; + } + + if (name_count > 0) + { + int j = 0; + indexstate->ioss_ConvertDatumIdxs = palloc(sizeof(int) * name_count); + + for (int i = 0; i < tupDesc->natts; i++) + { + if (tupDesc->attrs[i].atttypid == NAMEOID) + indexstate->ioss_ConvertDatumIdxs[j++] = i; + } + } + + indexstate->ioss_ConvertDatumCount = name_count; + } + /* * all done. */ diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index d97f5a8e7d..6a64d4aa35 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -1587,6 +1587,8 @@ typedef struct IndexScanState * TableSlot slot for holding tuples fetched from the table * VMBuffer buffer in use for visibility map testing, if any * PscanLen size of parallel index-only scan descriptor + * ConvertDatumIdxs Index of Datums from the index to convert to heap type + * ConvertDatumCount Number of elements in ConvertDatumIdxs * ---------------- */ typedef struct IndexOnlyScanState @@ -1606,6 +1608,8 @@ typedef struct IndexOnlyScanState TupleTableSlot *ioss_TableSlot; Buffer ioss_VMBuffer; Size ioss_PscanLen; + int *ioss_ConvertDatumIdxs; + int ioss_ConvertDatumCount; } IndexOnlyScanState; /* ----------------