Bruce Momjian c65ea0e040 New pg_attribute.atttypmod for type-specific information like
varchar length.

Cleans up code so attlen is always length.

Removed varchar() hack added earlier.

Will fix bug in selecting varchar() fields, and varchar() can be
variable length.
1998-01-16 23:21:07 +00:00

1180 lines
30 KiB
C

/*-------------------------------------------------------------------------
*
* execUtils.c--
* miscellanious executor utility routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.24 1998/01/16 23:19:52 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
* ExecAssignNodeBaseInfo \
* ExecAssignDebugHooks > preforms misc work done in all the
* ExecAssignExprContext / init node routines.
*
* ExecGetTypeInfo | old execCStructs interface
* ExecMakeTypeInfo | code from the version 1
* ExecOrderTypeInfo | lisp system. These should
* ExecSetTypeInfo | go away or be updated soon.
* ExecFreeTypeInfo | -cim 11/1/89
* ExecTupleAttributes /
*
* QueryDescGetTypeInfo - moved here from main.c
* am not sure what uses it -cim 10/12/89
*
* ExecGetIndexKeyInfo \
* ExecOpenIndices | referenced by InitPlan, EndPlan,
* ExecCloseIndices | ExecAppend, ExecReplace
* ExecFormIndexTuple |
* ExecInsertIndexTuple /
*
* NOTES
* This file has traditionally been the place to stick misc.
* executor support stuff that doesn't really go anyplace else.
*
*/
#include "postgres.h"
#include "fmgr.h"
#include "executor/executor.h"
#include "executor/execdebug.h"
#include "access/itup.h"
#include "access/heapam.h"
#include "access/genam.h"
#include "optimizer/clauses.h"
#include "utils/palloc.h"
#include "utils/mcxt.h"
#include "commands/command.h"
#include "catalog/index.h"
#include "catalog/catname.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "parser/parsetree.h"
static void
ExecGetIndexKeyInfo(IndexTupleForm indexTuple, int *numAttsOutP,
AttrNumber **attsOutP, FuncIndexInfoPtr fInfoP);
/* ----------------------------------------------------------------
* global counters for number of tuples processed, retrieved,
* appended, replaced, deleted.
* ----------------------------------------------------------------
*/
int NTupleProcessed;
int NTupleRetrieved;
int NTupleReplaced;
int NTupleAppended;
int NTupleDeleted;
int NIndexTupleInserted;
extern int NIndexTupleProcessed; /* have to be defined in the
* access method level so that the
* cinterface.a will link ok. */
/* ----------------------------------------------------------------
* statistic functions
* ----------------------------------------------------------------
*/
/* ----------------------------------------------------------------
* ResetTupleCount
* ----------------------------------------------------------------
*/
#ifdef NOT_USED
void
ResetTupleCount(void)
{
NTupleProcessed = 0;
NTupleRetrieved = 0;
NTupleAppended = 0;
NTupleDeleted = 0;
NTupleReplaced = 0;
NIndexTupleProcessed = 0;
}
#endif
/* ----------------------------------------------------------------
* PrintTupleCount
* ----------------------------------------------------------------
*/
#ifdef NOT_USED
void
DisplayTupleCount(FILE *statfp)
{
if (NTupleProcessed > 0)
fprintf(statfp, "!\t%d tuple%s processed, ", NTupleProcessed,
(NTupleProcessed == 1) ? "" : "s");
else
{
fprintf(statfp, "!\tno tuples processed.\n");
return;
}
if (NIndexTupleProcessed > 0)
fprintf(statfp, "%d indextuple%s processed, ", NIndexTupleProcessed,
(NIndexTupleProcessed == 1) ? "" : "s");
if (NIndexTupleInserted > 0)
fprintf(statfp, "%d indextuple%s inserted, ", NIndexTupleInserted,
(NIndexTupleInserted == 1) ? "" : "s");
if (NTupleRetrieved > 0)
fprintf(statfp, "%d tuple%s retrieved. ", NTupleRetrieved,
(NTupleRetrieved == 1) ? "" : "s");
if (NTupleAppended > 0)
fprintf(statfp, "%d tuple%s appended. ", NTupleAppended,
(NTupleAppended == 1) ? "" : "s");
if (NTupleDeleted > 0)
fprintf(statfp, "%d tuple%s deleted. ", NTupleDeleted,
(NTupleDeleted == 1) ? "" : "s");
if (NTupleReplaced > 0)
fprintf(statfp, "%d tuple%s replaced. ", NTupleReplaced,
(NTupleReplaced == 1) ? "" : "s");
fprintf(statfp, "\n");
}
#endif
/* ----------------------------------------------------------------
* miscellanious init node support functions
*
* ExecAssignNodeBaseInfo - assigns the baseid field of the node
* ExecAssignDebugHooks - assigns the node's debugging hooks
* ExecAssignExprContext - assigns the node's expression context
* ----------------------------------------------------------------
*/
/* ----------------
* ExecAssignNodeBaseInfo
*
* as it says, this assigns the baseid field of the node and
* increments the counter in the estate. In addition, it initializes
* the base_parent field of the basenode.
* ----------------
*/
void
ExecAssignNodeBaseInfo(EState *estate, CommonState *cstate, Plan *parent)
{
int baseId;
baseId = estate->es_BaseId;
cstate->cs_base_id = baseId;
estate->es_BaseId = baseId + 1;
}
/* ----------------
* ExecAssignExprContext
*
* This initializes the ExprContext field. It is only necessary
* to do this for nodes which use ExecQual or ExecTargetList
* because those routines depend on econtext. Other nodes which
* dont have to evaluate expressions don't need to do this.
* ----------------
*/
void
ExecAssignExprContext(EState *estate, CommonState *commonstate)
{
ExprContext *econtext;
ParamListInfo paraminfo;
List *rangeTable;
paraminfo = estate->es_param_list_info;
rangeTable = estate->es_range_table;
econtext = makeNode(ExprContext);
econtext->ecxt_scantuple = NULL; /* scan tuple slot */
econtext->ecxt_innertuple = NULL; /* inner tuple slot */
econtext->ecxt_outertuple = NULL; /* outer tuple slot */
econtext->ecxt_relation = NULL; /* relation */
econtext->ecxt_relid = 0; /* relid */
econtext->ecxt_param_list_info = paraminfo; /* param list info */
econtext->ecxt_range_table = rangeTable; /* range table */
commonstate->cs_ExprContext = econtext;
}
/* ----------------------------------------------------------------
* Result slot tuple type and ProjectionInfo support
* ----------------------------------------------------------------
*/
/* ----------------
* ExecAssignResultType
* ----------------
*/
void
ExecAssignResultType(CommonState *commonstate,
TupleDesc tupDesc)
{
TupleTableSlot *slot;
slot = commonstate->cs_ResultTupleSlot;
slot->ttc_tupleDescriptor = tupDesc;
}
/* ----------------
* ExecAssignResultTypeFromOuterPlan
* ----------------
*/
void
ExecAssignResultTypeFromOuterPlan(Plan *node, CommonState *commonstate)
{
Plan *outerPlan;
TupleDesc tupDesc;
outerPlan = outerPlan(node);
tupDesc = ExecGetTupType(outerPlan);
ExecAssignResultType(commonstate, tupDesc);
}
/* ----------------
* ExecAssignResultTypeFromTL
* ----------------
*/
void
ExecAssignResultTypeFromTL(Plan *node, CommonState *commonstate)
{
List *targetList;
int i;
int len;
List *tl;
TargetEntry *tle;
List *fjtl;
TupleDesc origTupDesc;
targetList = node->targetlist;
origTupDesc = ExecTypeFromTL(targetList);
len = ExecTargetListLength(targetList);
fjtl = NIL;
tl = targetList;
i = 0;
while (tl != NIL || fjtl != NIL)
{
if (fjtl != NIL)
{
tle = lfirst(fjtl);
fjtl = lnext(fjtl);
}
else
{
tle = lfirst(tl);
tl = lnext(tl);
}
#ifdef SETS_FIXED
if (!tl_is_resdom(tle))
{
Fjoin *fj = (Fjoin *) lfirst(tle);
/* it is a FJoin */
fjtl = lnext(tle);
tle = fj->fj_innerNode;
}
#endif
i++;
}
if (len > 0)
{
ExecAssignResultType(commonstate,
origTupDesc);
}
else
ExecAssignResultType(commonstate,
(TupleDesc) NULL);
}
/* ----------------
* ExecGetResultType
* ----------------
*/
TupleDesc
ExecGetResultType(CommonState *commonstate)
{
TupleTableSlot *slot = commonstate->cs_ResultTupleSlot;
return slot->ttc_tupleDescriptor;
}
/* ----------------
* ExecFreeResultType
* ----------------
*/
#ifdef NOT_USED
void
ExecFreeResultType(CommonState *commonstate)
{
TupleTableSlot *slot;
TupleDesc tupType;
slot = commonstate->cs_ResultTupleSlot;
tupType = slot->ttc_tupleDescriptor;
/* ExecFreeTypeInfo(tupType); */
pfree(tupType);
}
#endif
/* ----------------
* ExecAssignProjectionInfo
forms the projection information from the node's targetlist
* ----------------
*/
void
ExecAssignProjectionInfo(Plan *node, CommonState *commonstate)
{
ProjectionInfo *projInfo;
List *targetList;
int len;
targetList = node->targetlist;
len = ExecTargetListLength(targetList);
projInfo = makeNode(ProjectionInfo);
projInfo->pi_targetlist = targetList;
projInfo->pi_len = len;
projInfo->pi_tupValue =
(len <= 0) ? NULL : (Datum *) palloc(sizeof(Datum) * len);
projInfo->pi_exprContext = commonstate->cs_ExprContext;
projInfo->pi_slot = commonstate->cs_ResultTupleSlot;
commonstate->cs_ProjInfo = projInfo;
}
/* ----------------
* ExecFreeProjectionInfo
* ----------------
*/
void
ExecFreeProjectionInfo(CommonState *commonstate)
{
ProjectionInfo *projInfo;
/* ----------------
* get projection info. if NULL then this node has
* none so we just return.
* ----------------
*/
projInfo = commonstate->cs_ProjInfo;
if (projInfo == NULL)
return;
/* ----------------
* clean up memory used.
* ----------------
*/
if (projInfo->pi_tupValue != NULL)
pfree(projInfo->pi_tupValue);
pfree(projInfo);
commonstate->cs_ProjInfo = NULL;
}
/* ----------------------------------------------------------------
* the following scan type support functions are for
* those nodes which are stubborn and return tuples in
* their Scan tuple slot instead of their Result tuple
* slot.. luck fur us, these nodes do not do projections
* so we don't have to worry about getting the ProjectionInfo
* right for them... -cim 6/3/91
* ----------------------------------------------------------------
*/
/* ----------------
* ExecGetScanType
* ----------------
*/
TupleDesc
ExecGetScanType(CommonScanState *csstate)
{
TupleTableSlot *slot = csstate->css_ScanTupleSlot;
return slot->ttc_tupleDescriptor;
}
/* ----------------
* ExecFreeScanType
* ----------------
*/
#ifdef NOT_USED
void
ExecFreeScanType(CommonScanState *csstate)
{
TupleTableSlot *slot;
TupleDesc tupType;
slot = csstate->css_ScanTupleSlot;
tupType = slot->ttc_tupleDescriptor;
/* ExecFreeTypeInfo(tupType); */
pfree(tupType);
}
#endif
/* ----------------
* ExecAssignScanType
* ----------------
*/
void
ExecAssignScanType(CommonScanState *csstate,
TupleDesc tupDesc)
{
TupleTableSlot *slot;
slot = (TupleTableSlot *) csstate->css_ScanTupleSlot;
slot->ttc_tupleDescriptor = tupDesc;
}
/* ----------------
* ExecAssignScanTypeFromOuterPlan
* ----------------
*/
void
ExecAssignScanTypeFromOuterPlan(Plan *node, CommonScanState *csstate)
{
Plan *outerPlan;
TupleDesc tupDesc;
outerPlan = outerPlan(node);
tupDesc = ExecGetTupType(outerPlan);
ExecAssignScanType(csstate, tupDesc);
}
/* ----------------------------------------------------------------
* ExecTypeFromTL support routines.
*
* these routines are used mainly from ExecTypeFromTL.
* -cim 6/12/90
*
* old comments
* Routines dealing with the structure 'attribute' which conatains
* the type information about attributes in a tuple:
*
* ExecMakeTypeInfo(noType) --
* returns pointer to array of 'noType' structure 'attribute'.
* ExecSetTypeInfo(index, typeInfo, attNum, attLen) --
* sets the element indexed by 'index' in typeInfo with
* the values: attNum, attLen.
* ExecFreeTypeInfo(typeInfo) --
* frees the structure 'typeInfo'.
* ----------------------------------------------------------------
*/
/* ----------------
* ExecSetTypeInfo
*
* This initializes fields of a single attribute in a
* tuple descriptor from the specified parameters.
*
* XXX this duplicates much of the functionality of TupleDescInitEntry.
* the routines should be moved to the same place and be rewritten
* to share common code.
* ----------------
*/
#ifdef NOT_USED
void
ExecSetTypeInfo(int index,
TupleDesc typeInfo,
Oid typeID,
int attNum,
int attLen,
char *attName,
bool attbyVal,
char attalign)
{
AttributeTupleForm att;
/* ----------------
* get attribute pointer and preform a sanity check..
* ----------------
*/
att = typeInfo[index];
if (att == NULL)
elog(ERROR, "ExecSetTypeInfo: trying to assign through NULL");
/* ----------------
* assign values to the tuple descriptor, being careful not
* to copy a null attName..
*
* XXX it is unknown exactly what information is needed to
* initialize the attribute struct correctly so for now
* we use 0. this should be fixed -- otherwise we run the
* risk of using garbage data. -cim 5/5/91
* ----------------
*/
att->attrelid = 0; /* dummy value */
if (attName != (char *) NULL)
StrNCpy(att->attname.data, attName, NAMEDATALEN);
else
MemSet(att->attname.data, 0, NAMEDATALEN);
att->atttypid = typeID;
att->attdefrel = 0; /* dummy value */
att->attdisbursion = 0; /* dummy value */
att->atttyparg = 0; /* dummy value */
att->attlen = attLen;
att->attnum = attNum;
att->attbound = 0; /* dummy value */
att->attbyval = attbyVal;
att->attcanindex = 0; /* dummy value */
att->attproc = 0; /* dummy value */
att->attnelems = 0; /* dummy value */
att->attcacheoff = -1;
att->attisset = false;
att->attalign = attalign;
}
/* ----------------
* ExecFreeTypeInfo frees the array of attrbutes
* created by ExecMakeTypeInfo and returned by ExecTypeFromTL...
* ----------------
*/
void
ExecFreeTypeInfo(TupleDesc typeInfo)
{
/* ----------------
* do nothing if asked to free a null pointer
* ----------------
*/
if (typeInfo == NULL)
return;
/* ----------------
* the entire array of typeinfo pointers created by
* ExecMakeTypeInfo was allocated with a single palloc()
* so we can deallocate the whole array with a single pfree().
* (we should not try and free all the elements in the array)
* -cim 6/12/90
* ----------------
*/
pfree(typeInfo);
}
/* ----------------------------------------------------------------
* QueryDescGetTypeInfo
*
*| I don't know how this is used, all I know is that it
*| appeared one day in main.c so I moved it here. -cim 11/1/89
* ----------------------------------------------------------------
*/
TupleDesc
QueryDescGetTypeInfo(QueryDesc *queryDesc)
{
Plan *plan;
TupleDesc tupleType;
List *targetList;
AttrInfo *attinfo = (AttrInfo *) palloc(sizeof(AttrInfo));
plan = queryDesc->plantree;
tupleType = (TupleDesc) ExecGetTupType(plan);
/*
targetList = plan->targetlist;
attinfo->numAttr = ExecTargetListLength(targetList);
attinfo->attrs = tupleType;
*/
attinfo->numAttr = tupleType->natts;
attinfo->attrs = tupleType->attrs;
return attinfo;
}
#endif
/* ----------------------------------------------------------------
* ExecInsertIndexTuples support
* ----------------------------------------------------------------
*/
/* ----------------------------------------------------------------
* ExecGetIndexKeyInfo
*
* Extracts the index key attribute numbers from
* an index tuple form (i.e. a tuple from the pg_index relation)
* into an array of attribute numbers. The array and the
* size of the array are returned to the caller via return
* parameters.
* ----------------------------------------------------------------
*/
static void
ExecGetIndexKeyInfo(IndexTupleForm indexTuple,
int *numAttsOutP,
AttrNumber **attsOutP,
FuncIndexInfoPtr fInfoP)
{
int i;
int numKeys;
AttrNumber *attKeys;
/* ----------------
* check parameters
* ----------------
*/
if (numAttsOutP == NULL && attsOutP == NULL)
{
elog(DEBUG, "ExecGetIndexKeyInfo: %s",
"invalid parameters: numAttsOutP and attsOutP must be non-NULL");
}
/* ----------------
* set the procid for a possible functional index.
* ----------------
*/
FIsetProcOid(fInfoP, indexTuple->indproc);
/* ----------------
* count the number of keys..
* ----------------
*/
numKeys = 0;
for (i = 0; i < 8 && indexTuple->indkey[i] != 0; i++)
numKeys++;
/* ----------------
* place number keys in callers return area
* or the number of arguments for a functional index.
*
* If we have a functional index then the number of
* attributes defined in the index must 1 (the function's
* single return value).
* ----------------
*/
if (FIgetProcOid(fInfoP) != InvalidOid)
{
FIsetnArgs(fInfoP, numKeys);
(*numAttsOutP) = 1;
}
else
(*numAttsOutP) = numKeys;
if (numKeys < 1)
{
elog(DEBUG, "ExecGetIndexKeyInfo: %s",
"all index key attribute numbers are zero!");
(*attsOutP) = NULL;
return;
}
/* ----------------
* allocate and fill in array of key attribute numbers
* ----------------
*/
CXT1_printf("ExecGetIndexKeyInfo: context is %d\n", CurrentMemoryContext);
attKeys = (AttrNumber *)
palloc(numKeys * sizeof(AttrNumber));
for (i = 0; i < numKeys; i++)
attKeys[i] = indexTuple->indkey[i];
/* ----------------
* return array to caller.
* ----------------
*/
(*attsOutP) = attKeys;
}
/* ----------------------------------------------------------------
* ExecOpenIndices
*
* Here we scan the pg_index relation to find indices
* associated with a given heap relation oid. Since we
* don't know in advance how many indices we have, we
* form lists containing the information we need from
* pg_index and then process these lists.
*
* Note: much of this code duplicates effort done by
* the IndexCatalogInformation function in plancat.c
* because IndexCatalogInformation is poorly written.
*
* It would be much better the functionality provided
* by this function and IndexCatalogInformation was
* in the form of a small set of orthogonal routines..
* If you are trying to understand this, I suggest you
* look at the code to IndexCatalogInformation and
* FormIndexTuple.. -cim 9/27/89
* ----------------------------------------------------------------
*/
void
ExecOpenIndices(Oid resultRelationOid,
RelationInfo *resultRelationInfo)
{
Relation indexRd;
HeapScanDesc indexSd;
ScanKeyData key;
HeapTuple tuple;
IndexTupleForm indexStruct;
Oid indexOid;
List *oidList;
List *nkeyList;
List *keyList;
List *fiList;
char *predString;
List *predList;
List *indexoid;
List *numkeys;
List *indexkeys;
List *indexfuncs;
List *indexpreds;
int len;
RelationPtr relationDescs;
IndexInfo **indexInfoArray;
FuncIndexInfoPtr fInfoP;
int numKeyAtts;
AttrNumber *indexKeyAtts;
PredInfo *predicate;
int i;
/* ----------------
* open pg_index
* ----------------
*/
indexRd = heap_openr(IndexRelationName);
/* ----------------
* form a scan key
* ----------------
*/
ScanKeyEntryInitialize(&key, 0, Anum_pg_index_indrelid,
ObjectIdEqualRegProcedure,
ObjectIdGetDatum(resultRelationOid));
/* ----------------
* scan the index relation, looking for indices for our
* result relation..
* ----------------
*/
indexSd = heap_beginscan(indexRd, /* scan desc */
false, /* scan backward flag */
false, /* see self */
1, /* number scan keys */
&key); /* scan keys */
oidList = NIL;
nkeyList = NIL;
keyList = NIL;
fiList = NIL;
predList = NIL;
while (tuple = heap_getnext(indexSd, /* scan desc */
false, /* scan backward flag */
NULL), /* return: buffer */
HeapTupleIsValid(tuple))
{
/* ----------------
* For each index relation we find, extract the information
* we need and store it in a list..
*
* first get the oid of the index relation from the tuple
* ----------------
*/
indexStruct = (IndexTupleForm) GETSTRUCT(tuple);
indexOid = indexStruct->indexrelid;
/* ----------------
* allocate space for functional index information.
* ----------------
*/
fInfoP = (FuncIndexInfoPtr) palloc(sizeof(*fInfoP));
/* ----------------
* next get the index key information from the tuple
* ----------------
*/
ExecGetIndexKeyInfo(indexStruct,
&numKeyAtts,
&indexKeyAtts,
fInfoP);
/* ----------------
* next get the index predicate from the tuple
* ----------------
*/
if (VARSIZE(&indexStruct->indpred) != 0)
{
predString = fmgr(F_TEXTOUT, &indexStruct->indpred);
predicate = (PredInfo *) stringToNode(predString);
pfree(predString);
}
else
{
predicate = NULL;
}
/* ----------------
* save the index information into lists
* ----------------
*/
oidList = lconsi(indexOid, oidList);
nkeyList = lconsi(numKeyAtts, nkeyList);
keyList = lcons(indexKeyAtts, keyList);
fiList = lcons(fInfoP, fiList);
predList = lcons(predicate, predList);
}
/* ----------------
* we have the info we need so close the pg_index relation..
* ----------------
*/
heap_endscan(indexSd);
heap_close(indexRd);
/* ----------------
* Now that we've collected the index information into three
* lists, we open the index relations and store the descriptors
* and the key information into arrays.
* ----------------
*/
len = length(oidList);
if (len > 0)
{
/* ----------------
* allocate space for relation descs
* ----------------
*/
CXT1_printf("ExecOpenIndices: context is %d\n", CurrentMemoryContext);
relationDescs = (RelationPtr)
palloc(len * sizeof(Relation));
/* ----------------
* initialize index info array
* ----------------
*/
CXT1_printf("ExecOpenIndices: context is %d\n", CurrentMemoryContext);
indexInfoArray = (IndexInfo **)
palloc(len * sizeof(IndexInfo *));
for (i = 0; i < len; i++)
{
IndexInfo *ii = makeNode(IndexInfo);
ii->ii_NumKeyAttributes = 0;
ii->ii_KeyAttributeNumbers = (AttrNumber *) NULL;
ii->ii_FuncIndexInfo = (FuncIndexInfoPtr) NULL;
ii->ii_Predicate = NULL;
indexInfoArray[i] = ii;
}
/* ----------------
* attempt to open each of the indices. If we succeed,
* then store the index relation descriptor into the
* relation descriptor array.
* ----------------
*/
i = 0;
foreach(indexoid, oidList)
{
Relation indexDesc;
indexOid = lfirsti(indexoid);
indexDesc = index_open(indexOid);
if (indexDesc != NULL)
relationDescs[i++] = indexDesc;
}
/* ----------------
* store the relation descriptor array and number of
* descs into the result relation info.
* ----------------
*/
resultRelationInfo->ri_NumIndices = i;
resultRelationInfo->ri_IndexRelationDescs = relationDescs;
/* ----------------
* store the index key information collected in our
* lists into the index info array
* ----------------
*/
i = 0;
foreach(numkeys, nkeyList)
{
numKeyAtts = lfirsti(numkeys);
indexInfoArray[i++]->ii_NumKeyAttributes = numKeyAtts;
}
i = 0;
foreach(indexkeys, keyList)
{
indexKeyAtts = (AttrNumber *) lfirst(indexkeys);
indexInfoArray[i++]->ii_KeyAttributeNumbers = indexKeyAtts;
}
i = 0;
foreach(indexfuncs, fiList)
{
FuncIndexInfoPtr fiP = (FuncIndexInfoPtr) lfirst(indexfuncs);
indexInfoArray[i++]->ii_FuncIndexInfo = fiP;
}
i = 0;
foreach(indexpreds, predList)
{
indexInfoArray[i++]->ii_Predicate = lfirst(indexpreds);
}
/* ----------------
* store the index info array into relation info
* ----------------
*/
resultRelationInfo->ri_IndexRelationInfo = indexInfoArray;
}
/* ----------------
* All done, resultRelationInfo now contains complete information
* on the indices associated with the result relation.
* ----------------
*/
/* should free oidList, nkeyList and keyList here */
/* OK - let's do it -jolly */
freeList(oidList);
freeList(nkeyList);
freeList(keyList);
freeList(fiList);
freeList(predList);
}
/* ----------------------------------------------------------------
* ExecCloseIndices
*
* Close the index relations stored in resultRelationInfo
* ----------------------------------------------------------------
*/
void
ExecCloseIndices(RelationInfo *resultRelationInfo)
{
int i;
int numIndices;
RelationPtr relationDescs;
numIndices = resultRelationInfo->ri_NumIndices;
relationDescs = resultRelationInfo->ri_IndexRelationDescs;
for (i = 0; i < numIndices; i++)
if (relationDescs[i] != NULL)
index_close(relationDescs[i]);
/*
* XXX should free indexInfo array here too.
*/
}
/* ----------------------------------------------------------------
* ExecFormIndexTuple
*
* Most of this code is cannabilized from DefaultBuild().
* As said in the comments for ExecOpenIndices, most of
* this functionality should be rearranged into a proper
* set of routines..
* ----------------------------------------------------------------
*/
#ifdef NOT_USED
IndexTuple
ExecFormIndexTuple(HeapTuple heapTuple,
Relation heapRelation,
Relation indexRelation,
IndexInfo *indexInfo)
{
IndexTuple indexTuple;
TupleDesc heapDescriptor;
TupleDesc indexDescriptor;
Datum *datum;
char *nulls;
int numberOfAttributes;
AttrNumber *keyAttributeNumbers;
FuncIndexInfoPtr fInfoP;
/* ----------------
* get information from index info structure
* ----------------
*/
numberOfAttributes = indexInfo->ii_NumKeyAttributes;
keyAttributeNumbers = indexInfo->ii_KeyAttributeNumbers;
fInfoP = indexInfo->ii_FuncIndexInfo;
/* ----------------
* datum and null are arrays in which we collect the index attributes
* when forming a new index tuple.
* ----------------
*/
CXT1_printf("ExecFormIndexTuple: context is %d\n", CurrentMemoryContext);
datum = (Datum *) palloc(numberOfAttributes * sizeof *datum);
nulls = (char *) palloc(numberOfAttributes * sizeof *nulls);
/* ----------------
* get the tuple descriptors from the relations so we know
* how to form the index tuples..
* ----------------
*/
heapDescriptor = RelationGetTupleDescriptor(heapRelation);
indexDescriptor = RelationGetTupleDescriptor(indexRelation);
/* ----------------
* FormIndexDatum fills in its datum and null parameters
* with attribute information taken from the given heap tuple.
* ----------------
*/
FormIndexDatum(numberOfAttributes, /* num attributes */
keyAttributeNumbers, /* array of att nums to extract */
heapTuple, /* tuple from base relation */
heapDescriptor, /* heap tuple's descriptor */
InvalidBuffer, /* buffer associated with heap
* tuple */
datum, /* return: array of attributes */
nulls, /* return: array of char's */
fInfoP); /* functional index information */
indexTuple = index_formtuple(indexDescriptor,
datum,
nulls);
/* ----------------
* free temporary arrays
*
* XXX should store these in the IndexInfo instead of allocating
* and freeing on every insertion, but efficency here is not
* that important and FormIndexTuple is wasteful anyways..
* -cim 9/27/89
* ----------------
*/
pfree(nulls);
pfree(datum);
return indexTuple;
}
#endif
/* ----------------------------------------------------------------
* ExecInsertIndexTuples
*
* This routine takes care of inserting index tuples
* into all the relations indexing the result relation
* when a heap tuple is inserted into the result relation.
* Much of this code should be moved into the genam
* stuff as it only exists here because the genam stuff
* doesn't provide the functionality needed by the
* executor.. -cim 9/27/89
* ----------------------------------------------------------------
*/
void
ExecInsertIndexTuples(TupleTableSlot *slot,
ItemPointer tupleid,
EState *estate,
bool is_update)
{
HeapTuple heapTuple;
RelationInfo *resultRelationInfo;
int i;
int numIndices;
RelationPtr relationDescs;
Relation heapRelation;
IndexInfo **indexInfoArray;
IndexInfo *indexInfo;
Node *predicate;
bool satisfied;
ExprContext *econtext;
InsertIndexResult result;
int numberOfAttributes;
AttrNumber *keyAttributeNumbers;
FuncIndexInfoPtr fInfoP;
TupleDesc heapDescriptor;
Datum *datum;
char *nulls;
heapTuple = slot->val;
/* ----------------
* get information from the result relation info structure.
* ----------------
*/
resultRelationInfo = estate->es_result_relation_info;
numIndices = resultRelationInfo->ri_NumIndices;
relationDescs = resultRelationInfo->ri_IndexRelationDescs;
indexInfoArray = resultRelationInfo->ri_IndexRelationInfo;
heapRelation = resultRelationInfo->ri_RelationDesc;
/* ----------------
* for each index, form and insert the index tuple
* ----------------
*/
econtext = NULL;
for (i = 0; i < numIndices; i++)
{
if (relationDescs[i] == NULL)
continue;
indexInfo = indexInfoArray[i];
predicate = indexInfo->ii_Predicate;
if (predicate != NULL)
{
if (econtext == NULL)
{
econtext = makeNode(ExprContext);
}
econtext->ecxt_scantuple = slot;
/* Skip this index-update if the predicate isn't satisfied */
satisfied = ExecQual((List *) predicate, econtext);
if (satisfied == false)
continue;
}
/* ----------------
* get information from index info structure
* ----------------
*/
numberOfAttributes = indexInfo->ii_NumKeyAttributes;
keyAttributeNumbers = indexInfo->ii_KeyAttributeNumbers;
fInfoP = indexInfo->ii_FuncIndexInfo;
datum = (Datum *) palloc(numberOfAttributes * sizeof *datum);
nulls = (char *) palloc(numberOfAttributes * sizeof *nulls);
heapDescriptor = (TupleDesc) RelationGetTupleDescriptor(heapRelation);
FormIndexDatum(numberOfAttributes, /* num attributes */
keyAttributeNumbers, /* array of att nums to
* extract */
heapTuple, /* tuple from base relation */
heapDescriptor, /* heap tuple's descriptor */
InvalidBuffer, /* buffer associated with heap
* tuple */
datum, /* return: array of attributes */
nulls, /* return: array of char's */
fInfoP); /* functional index information */
result = index_insert(relationDescs[i], /* index relation */
datum, /* array of heaptuple Datums */
nulls, /* info on nulls */
&(heapTuple->t_ctid), /* oid of heap tuple */
heapRelation);
/* ----------------
* keep track of index inserts for debugging
* ----------------
*/
IncrIndexInserted();
/* ----------------
* free index tuple after insertion
* ----------------
*/
if (result)
pfree(result);
}
if (econtext != NULL)
pfree(econtext);
}