aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execUtils.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/execUtils.c')
-rw-r--r--src/backend/executor/execUtils.c1092
1 files changed, 1092 insertions, 0 deletions
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
new file mode 100644
index 00000000000..8d1108aca25
--- /dev/null
+++ b/src/backend/executor/execUtils.c
@@ -0,0 +1,1092 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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.1.1.1 1996/07/09 06:21:25 scrappy 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 "executor/executor.h"
+#include "access/itup.h"
+#include "optimizer/clauses.h"
+#include "utils/palloc.h"
+#include "commands/command.h"
+#include "catalog/index.h"
+
+/* ----------------------------------------------------------------
+ * 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
+ * ----------------------------------------------------------------
+ */
+void
+ResetTupleCount()
+{
+ NTupleProcessed = 0;
+ NTupleRetrieved = 0;
+ NTupleAppended = 0;
+ NTupleDeleted = 0;
+ NTupleReplaced = 0;
+ NIndexTupleProcessed = 0;
+}
+
+/* ----------------------------------------------------------------
+ * PrintTupleCount
+ * ----------------------------------------------------------------
+ */
+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");
+}
+
+/* ----------------------------------------------------------------
+ * 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
+ * ----------------
+ */
+void
+ExecFreeResultType(CommonState *commonstate)
+{
+ TupleTableSlot *slot;
+ TupleDesc tupType;
+
+ slot = commonstate->cs_ResultTupleSlot;
+ tupType = slot->ttc_tupleDescriptor;
+
+/* ExecFreeTypeInfo(tupType); */
+ pfree(tupType);
+}
+
+
+/* ----------------
+ * 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
+ * ----------------
+ */
+void
+ExecFreeScanType(CommonScanState *csstate)
+{
+ TupleTableSlot *slot;
+ TupleDesc tupType;
+
+ slot = csstate->css_ScanTupleSlot;
+ tupType = slot->ttc_tupleDescriptor;
+
+/* ExecFreeTypeInfo(tupType); */
+ pfree(tupType);
+}
+
+/* ----------------
+ * 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.
+ * ----------------
+ */
+#if 0
+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(WARN, "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->attnvals = 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.
+ * ----------------------------------------------------------------
+ */
+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 */
+ NowTimeQual, /* time qual */
+ 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..
+ * ----------------------------------------------------------------
+ */
+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;
+}
+
+/* ----------------------------------------------------------------
+ * 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)
+{
+ HeapTuple heapTuple;
+ RelationInfo *resultRelationInfo;
+ int i;
+ int numIndices;
+ RelationPtr relationDescs;
+ Relation heapRelation;
+ IndexInfo **indexInfoArray;
+ Node *predicate;
+ bool satisfied;
+ ExprContext *econtext;
+ IndexTuple indexTuple;
+ InsertIndexResult result;
+
+ 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;
+
+ predicate = indexInfoArray[i]->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;
+ }
+
+ indexTuple = ExecFormIndexTuple(heapTuple,
+ heapRelation,
+ relationDescs[i],
+ indexInfoArray[i]);
+
+ indexTuple->t_tid = (*tupleid); /* structure assignment */
+
+ result = index_insert(relationDescs[i], /* index relation */
+ indexTuple); /* index tuple */
+
+ /* ----------------
+ * keep track of index inserts for debugging
+ * ----------------
+ */
+ IncrIndexInserted();
+
+ /* ----------------
+ * free index tuple after insertion
+ * ----------------
+ */
+ if (result) pfree(result);
+ pfree(indexTuple);
+ }
+ if (econtext != NULL) pfree(econtext);
+}
+