summaryrefslogtreecommitdiffstats
path: root/src/backend/executor/nodeIndexonlyscan.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/nodeIndexonlyscan.c')
-rw-r--r--src/backend/executor/nodeIndexonlyscan.c95
1 files changed, 88 insertions, 7 deletions
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 0b43a9b..45d1a67 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -35,19 +35,21 @@
#include "access/tableam.h"
#include "access/tupdesc.h"
#include "access/visibilitymap.h"
+#include "catalog/pg_type.h"
#include "executor/execdebug.h"
#include "executor/nodeIndexonlyscan.h"
#include "executor/nodeIndexscan.h"
#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 +208,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 +266,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 +280,37 @@ StoreIndexTuple(TupleTableSlot *slot, IndexTuple itup, TupleDesc itupdesc)
ExecClearTuple(slot);
index_deform_tuple(itup, itupdesc, slot->tts_values, slot->tts_isnull);
+
+ /*
+ * Copy all name columns stored as cstrings back into a NAMEDATALEN byte
+ * sized allocation. We mark this branch as unlikely as generally "name"
+ * is used only for the system catalogs and this would have to be a user
+ * query running on those or some other user table with an index on a name
+ * column.
+ */
+ if (unlikely(node->ioss_NameCStringAttNums != NULL))
+ {
+ int attcount = node->ioss_NameCStringCount;
+
+ for (int idx = 0; idx < attcount; idx++)
+ {
+ int attnum = node->ioss_NameCStringAttNums[idx];
+ Name name;
+
+ /* skip null Datums */
+ if (slot->tts_isnull[attnum])
+ continue;
+
+ /* allocate the NAMEDATALEN and copy the datum into that memory */
+ name = (Name) MemoryContextAlloc(node->ss.ps.ps_ExprContext->ecxt_per_tuple_memory,
+ NAMEDATALEN);
+
+ /* use namestrcpy to zero-pad all trailing bytes */
+ namestrcpy(name, DatumGetCString(slot->tts_values[attnum]));
+ slot->tts_values[attnum] = NameGetDatum(name);
+ }
+ }
+
ExecStoreVirtualTuple(slot);
}
@@ -490,8 +524,11 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
{
IndexOnlyScanState *indexstate;
Relation currentRelation;
+ Relation indexRelation;
LOCKMODE lockmode;
TupleDesc tupDesc;
+ int indnkeyatts;
+ int namecount;
/*
* create state structure
@@ -564,7 +601,8 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
/* Open the index relation. */
lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode;
- indexstate->ioss_RelationDesc = index_open(node->indexid, lockmode);
+ indexRelation = index_open(node->indexid, lockmode);
+ indexstate->ioss_RelationDesc = indexRelation;
/*
* Initialize index-specific scan state
@@ -577,7 +615,7 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
* build the index scan keys from the index qualification
*/
ExecIndexBuildScanKeys((PlanState *) indexstate,
- indexstate->ioss_RelationDesc,
+ indexRelation,
node->indexqual,
false,
&indexstate->ioss_ScanKeys,
@@ -591,7 +629,7 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
* any ORDER BY exprs have to be turned into scankeys in the same way
*/
ExecIndexBuildScanKeys((PlanState *) indexstate,
- indexstate->ioss_RelationDesc,
+ indexRelation,
node->indexorderby,
true,
&indexstate->ioss_OrderByKeys,
@@ -620,6 +658,49 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
indexstate->ioss_RuntimeContext = NULL;
}
+ indexstate->ioss_NameCStringAttNums = NULL;
+ indnkeyatts = indexRelation->rd_index->indnkeyatts;
+ namecount = 0;
+
+ /*
+ * The "name" type for btree uses text_ops which results in storing
+ * cstrings in the indexed keys rather than names. Here we detect that in
+ * a generic way in case other index AMs want to do the same optimization.
+ * Check for opclasses with an opcintype of NAMEOID and an index tuple
+ * descriptor with CSTRINGOID. If any of these are found, create an array
+ * marking the index attribute number of each of them. StoreIndexTuple()
+ * handles copying the name Datums into a NAMEDATALEN-byte allocation.
+ */
+
+ /* First, count the number of such index keys */
+ for (int attnum = 0; attnum < indnkeyatts; attnum++)
+ {
+ if (indexRelation->rd_att->attrs[attnum].atttypid == CSTRINGOID &&
+ indexRelation->rd_opcintype[attnum] == NAMEOID)
+ namecount++;
+ }
+
+ if (namecount > 0)
+ {
+ int idx = 0;
+
+ /*
+ * Now create an array to mark the attribute numbers of the keys that
+ * need to be converted from cstring to name.
+ */
+ indexstate->ioss_NameCStringAttNums = (AttrNumber *)
+ palloc(sizeof(AttrNumber) * namecount);
+
+ for (int attnum = 0; attnum < indnkeyatts; attnum++)
+ {
+ if (indexRelation->rd_att->attrs[attnum].atttypid == CSTRINGOID &&
+ indexRelation->rd_opcintype[attnum] == NAMEOID)
+ indexstate->ioss_NameCStringAttNums[idx++] = (AttrNumber) attnum;
+ }
+ }
+
+ indexstate->ioss_NameCStringCount = namecount;
+
/*
* all done.
*/