/*-------------------------------------------------------------------------
 *
 * execUtils.c--
 *    miscellanious executor utility routines
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *    $Header: /usr/local/devel/pglite/cvs/src/backend/executor/execUtils.c,v 1.16 1996/02/24 00:13:16 jolly 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);
}

