mirror of
https://github.com/postgres/postgres.git
synced 2025-04-27 22:56:53 +03:00
Generate index-only scan tuple descriptor from the plan node's indextlist.
Dept. of second thoughts: as long as we've got that tlist hanging around anyway, we can apply ExecTypeFromTL to it to get a suitable descriptor for the ScanTupleSlot. This is a nicer solution than the previous one because it eliminates some hard-wired knowledge about btree name_ops, and because it avoids the somewhat shaky assumption that we needn't set up the scan tuple descriptor in EXPLAIN_ONLY mode. It doesn't change what actually happens at run-time though, and I'm still a bit nervous about that.
This commit is contained in:
parent
e991930e8a
commit
cb6771fb32
@ -26,8 +26,6 @@
|
|||||||
|
|
||||||
#include "access/relscan.h"
|
#include "access/relscan.h"
|
||||||
#include "access/visibilitymap.h"
|
#include "access/visibilitymap.h"
|
||||||
#include "catalog/pg_opfamily.h"
|
|
||||||
#include "catalog/pg_type.h"
|
|
||||||
#include "executor/execdebug.h"
|
#include "executor/execdebug.h"
|
||||||
#include "executor/nodeIndexonlyscan.h"
|
#include "executor/nodeIndexonlyscan.h"
|
||||||
#include "executor/nodeIndexscan.h"
|
#include "executor/nodeIndexscan.h"
|
||||||
@ -162,8 +160,10 @@ StoreIndexTuple(TupleTableSlot *slot, IndexTuple itup, Relation indexRel)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: we must use the index relation's tupdesc in index_getattr,
|
* Note: we must use the index relation's tupdesc in index_getattr, not
|
||||||
* not the slot's tupdesc, because of index_descriptor_hack().
|
* the slot's tupdesc, in case the latter has different datatypes (this
|
||||||
|
* happens for btree name_ops in particular). They'd better have the same
|
||||||
|
* number of columns though.
|
||||||
*/
|
*/
|
||||||
Assert(slot->tts_tupleDescriptor->natts == nindexatts);
|
Assert(slot->tts_tupleDescriptor->natts == nindexatts);
|
||||||
|
|
||||||
@ -173,45 +173,6 @@ StoreIndexTuple(TupleTableSlot *slot, IndexTuple itup, Relation indexRel)
|
|||||||
ExecStoreVirtualTuple(slot);
|
ExecStoreVirtualTuple(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* index_descriptor_hack -- ugly kluge to make index's tupdesc OK for slot
|
|
||||||
*
|
|
||||||
* This is necessary because, alone among btree opclasses, name_ops uses
|
|
||||||
* a storage type (cstring) different from its input type. The index
|
|
||||||
* tuple descriptor will show "cstring", which is correct, but we have to
|
|
||||||
* expose "name" as the slot datatype or ExecEvalVar will whine. If we
|
|
||||||
* ever want to have any other cases with a different storage type, we ought
|
|
||||||
* to think of a cleaner solution than this.
|
|
||||||
*/
|
|
||||||
static TupleDesc
|
|
||||||
index_descriptor_hack(Relation indexRel)
|
|
||||||
{
|
|
||||||
TupleDesc tupdesc = RelationGetDescr(indexRel);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* copy so we can scribble on it safely */
|
|
||||||
tupdesc = CreateTupleDescCopy(tupdesc);
|
|
||||||
|
|
||||||
for (i = 0; i < tupdesc->natts; i++)
|
|
||||||
{
|
|
||||||
if (indexRel->rd_opfamily[i] == NAME_BTREE_FAM_OID &&
|
|
||||||
tupdesc->attrs[i]->atttypid == CSTRINGOID)
|
|
||||||
{
|
|
||||||
tupdesc->attrs[i]->atttypid = NAMEOID;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We set attlen to match the type OID just in case anything looks
|
|
||||||
* at it. Note that this is safe only because StoreIndexTuple
|
|
||||||
* will insert the data as a virtual tuple, and we don't expect
|
|
||||||
* anything will try to materialize the scan tuple slot.
|
|
||||||
*/
|
|
||||||
tupdesc->attrs[i]->attlen = NAMEDATALEN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return tupdesc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IndexOnlyRecheck -- access method routine to recheck a tuple in EvalPlanQual
|
* IndexOnlyRecheck -- access method routine to recheck a tuple in EvalPlanQual
|
||||||
*
|
*
|
||||||
@ -426,9 +387,20 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
|
|||||||
indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
|
indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize result tuple type.
|
* Build the scan tuple type using the indextlist generated by the
|
||||||
|
* planner. We use this, rather than the index's physical tuple
|
||||||
|
* descriptor, because the latter contains storage column types not the
|
||||||
|
* types of the original datums. (It's the AM's responsibility to return
|
||||||
|
* suitable data anyway.)
|
||||||
|
*/
|
||||||
|
tupDesc = ExecTypeFromTL(node->indextlist, false);
|
||||||
|
ExecAssignScanType(&indexstate->ss, tupDesc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize result tuple type and projection info.
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromTL(&indexstate->ss.ps);
|
ExecAssignResultTypeFromTL(&indexstate->ss.ps);
|
||||||
|
ExecAssignScanProjectionInfo(&indexstate->ss);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
|
* If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
|
||||||
@ -449,14 +421,6 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
|
|||||||
indexstate->ioss_RelationDesc = index_open(node->indexid,
|
indexstate->ioss_RelationDesc = index_open(node->indexid,
|
||||||
relistarget ? NoLock : AccessShareLock);
|
relistarget ? NoLock : AccessShareLock);
|
||||||
|
|
||||||
/*
|
|
||||||
* Now we can get the scan tuple's type (which is the index's rowtype,
|
|
||||||
* not the heap's) and initialize result projection info.
|
|
||||||
*/
|
|
||||||
tupDesc = index_descriptor_hack(indexstate->ioss_RelationDesc);
|
|
||||||
ExecAssignScanType(&indexstate->ss, tupDesc);
|
|
||||||
ExecAssignScanProjectionInfo(&indexstate->ss);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize index-specific scan state
|
* Initialize index-specific scan state
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user