/* ----------------------------------------------------------------
 *   FILE
 *	ex_utils.c
 *	
 *   DESCRIPTION
 *	miscellanious executor utility routines
 *
 *   INTERFACE ROUTINES
 *	ExecAssignNodeBaseInfo	\
 *	ExecAssignDebugHooks	 >  preforms misc work done in all the
 *	ExecAssignExprContext	/   init node routines.
 *
 *	ExecGetTypeInfo	  	\
 *	ExecMakeTypeInfo  	 \
 *	ExecOrderTypeInfo  	  \
 *	ExecSetTypeInfo    	  |  old execCStructs interface
 *	ExecFreeTypeInfo 	  |  code from the version 1
 *	ExecMakeSkeys 	  	  |  lisp system.  These should
 *	ExecSetSkeys 	  	  |  go away or be updated soon.
 *	ExecSetSkeysValue 	  |  -cim 11/1/89
 *	ExecFreeSkeys 	  	  |
 *	ExecMakeTLValues 	  |
 *	ExecSetTLValues		  /
 *	ExecFreeTLValues	 /
 *	ExecTupleAttributes	/
 *
 *	get_innerPlan	\  convience accessors to eliminate confusion
 *	get_outerPlan	/    between right/left inner/outer
 *
 *	QueryDescGetTypeInfo - moved here from main.c
 *				am not sure what uses it -cim 10/12/89
 *
 *	ExecCollect		   \
 *	ExecUniqueCons		    \
 *	ExecGetVarAttlistFromExpr    >	support routines for
 *	ExecGetVarAttlistFromTLE    /	ExecInitScanAttributes
 *	ExecMakeAttsFromList	   /
 *
 *	ExecInitScanAttributes	\    creates/destroys array of attribute
 *	ExecFreeScanAttributes	/    numbers actually examined by the executor
 *					(needed by the rule manager -cim)
 *
 *   NOTES
 *	This file has traditionally been the place to stick misc.
 *	executor support stuff that doesn't really go anyplace else.
 *	
 *   IDENTIFICATION
 *	$Header: /private/postgres/src/executor/RCS/ex_utils.c,v 1.10 1992/08/21 05:38:56 mer Exp $
 * ----------------------------------------------------------------
 */
 
#include "executor/executor.h"
#include "nodes/relation.h"	/* needed before including keys.h */
#include "planner/keys.h"	/* needed for definition of INNER */

 RcsId("$Header: /private/postgres/src/executor/RCS/ex_utils.c,v 1.10 1992/08/21 05:38:56 mer Exp $");
/* ----------------------------------------------------------------
 *      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(statfp)
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
 * ----------------------------------------------------------------
 */

/* ----------------
 *	ExecGetPrivateState
 *
 *	This is used to get a pointer to a node's private state.
 * ----------------
 */
BaseNode
ExecGetPrivateState(node)
    Plan node;
{
    switch(NodeType(node)) {
    case classTag(Result):
	return (BaseNode) get_resstate((Result) node);
    
    case classTag(Append):
	return (BaseNode) get_unionstate((Append) node);
    
    case classTag(NestLoop):
	return (BaseNode) get_nlstate((NestLoop) node);
    
    case classTag(MergeJoin):
	return (BaseNode) get_mergestate((MergeJoin) node);
    
    case classTag(HashJoin):
	return (BaseNode) get_hashjoinstate((HashJoin) node);
    
    case classTag(SeqScan):
	return (BaseNode) get_scanstate((Scan) node);
    
    case classTag(IndexScan):
	return (BaseNode) get_indxstate((IndexScan) node);
    
    case classTag(Material):
	return (BaseNode) get_matstate((Material) node);
    
    case classTag(Sort):
	return (BaseNode) get_sortstate((Sort) node);
    
    case classTag(Unique):
	return (BaseNode) get_uniquestate((Unique) node);
    
    case classTag(Hash):
	return (BaseNode) get_hashstate((Hash) node);

    default:
	return NULL;
    }
}

/* ----------------
 *	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, basenode, parent)
    EState	estate;
    BaseNode	basenode;
    Plan	parent;
{
    int		baseid;
    BaseNode	parentstate;
	
    baseid = get_es_BaseId(estate);
    set_base_id(basenode, baseid);
    baseid++;
    set_es_BaseId(estate, baseid);
    
    set_base_parent(basenode, (Pointer) parent);

    if (parent != NULL) 
	parentstate = ExecGetPrivateState(parent);
    else
	parentstate = (BaseNode) NULL;
    
    set_base_parent_state(basenode, (Pointer) parentstate);
}

/* ----------------
 *	ExecAssignDebugHooks
 *
 *	this assigns the executor's debugging hooks, if we compile
 *	with EXEC_ASSIGNDEBUGHOOKS set.
 * ----------------
 */
void
ExecAssignDebugHooks(node, basenode)
    Plan	node;
    BaseNode	basenode;
{
#ifdef EXEC_ASSIGNDEBUGHOOKS
    HookNode	 hook;
    HookFunction proc;
    
    if (_debug_hook_id_ > 0) {
	hook = (HookNode) _debug_hooks_[ _debug_hook_id_ ];
	set_base_hook(basenode, hook); 
	proc = (HookFunction) get_hook_at_initnode(hook);
	if (proc != NULL)
	    (*proc)(node, basenode);
    }
#endif EXEC_ASSIGNDEBUGHOOKS
}

/* ----------------
 *	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, commonstate)
    EState	estate;
    CommonState	commonstate;
{
    ExprContext    econtext;
    ParamListInfo  paraminfo;
    List           rangeTable;
    
    paraminfo = get_es_param_list_info(estate);
    rangeTable = get_es_range_table(estate);

    econtext = MakeExprContext(NULL,		/* scan tuple slot */
			       NULL,		/* inner tuple slot */
			       NULL,		/* outer tuple slot */
			       NULL,		/* relation */
			       0,		/* relid */
			       paraminfo,	/* param list info */
			       rangeTable);	/* range table */

    set_cs_ExprContext(commonstate, econtext);
}

/* ----------------------------------------------------------------
 *	Result slot tuple type and ProjectionInfo support
 * ----------------------------------------------------------------
 */

/* ----------------
 *	ExecAssignResultType
 * ----------------
 */
void
ExecAssignResultType(commonstate, execTupDesc, tupDesc)
    CommonState		commonstate;
    ExecTupDescriptor	execTupDesc;
    TupleDescriptor	tupDesc;
{
    TupleTableSlot	slot;
    
    slot = get_cs_ResultTupleSlot(commonstate);
    ExecSetSlotExecDescriptor(slot, execTupDesc);
    (void) ExecSetSlotDescriptor((Pointer) slot, tupDesc);
}

/* ----------------
 *	ExecAssignResultTypeFromOuterPlan
 * ----------------
 */
void
ExecAssignResultTypeFromOuterPlan(node, commonstate)
    Plan 	node;
    CommonState	commonstate;
{
    Plan		outerPlan;
    ExecTupDescriptor	execTupDesc;
    TupleDescriptor	tupDesc;
    
    outerPlan =   get_outerPlan(node);
    execTupDesc = ExecGetExecTupDesc(outerPlan);
    tupDesc = ExecGetTupType(outerPlan);
    
    ExecAssignResultType(commonstate, execTupDesc, tupDesc);
}

/* ----------------
 *	ExecAssignResultTypeFromTL
 * ----------------
 */
void
ExecAssignResultTypeFromTL(node, commonstate)
    Plan 	node;
    CommonState	commonstate;
{
    List	        targetList;
    Var			tlvar;
    int			i;
    int			len;
    List		tl, tle;
    List		fjtl;
    ExecTupDescriptor	execTupDesc;
    TupleDescriptor	tupDesc;
    int			fjcount;
    int			varlen;
    TupleDescriptor	varTupDesc;
    TupleDescriptor	origTupDesc;
    
    targetList =  get_qptargetlist(node);
    origTupDesc = ExecTypeFromTL(targetList);
    if ((len = ExecTargetListLength(targetList)) != 0)
	execTupDesc = ExecMakeExecTupDesc(len);
    else
	execTupDesc = (ExecTupDescriptor)NULL;

    fjtl = LispNil;
    tl = targetList;
    i = 0;
    while (!lispNullp(tl) || !lispNullp(fjtl)) {
	if (!lispNullp(fjtl)) {
	    tle = CAR(fjtl);
	    fjtl = CDR(fjtl);
	  }
	else {
	    tle = CAR(tl);
	    tl = CDR(tl);
	  }
	if (!tl_is_resdom(tle)) {
	    /* it is a FJoin */
	    fjtl = CDR(tle);
	    tle = get_fj_innerNode((Fjoin)CAR(tle));
	  }
	if (get_rescomplex((Resdom)CAR(tle))) {
	    /* if it is a composite type, i.e., a tuple */
	    tlvar = (Var)get_expr(tle);
	    Assert(IsA(tlvar,Var));
	    varlen = ExecGetVarLen(node, commonstate, tlvar);
	    varTupDesc = ExecGetVarTupDesc(node, commonstate, tlvar);
	    execTupDesc->data[i] = MakeExecAttDesc(ATTTUP, varlen, varTupDesc);
	  }
	else {
	    /* this means that it is a base type */
	    execTupDesc->data[i] = ExecMakeExecAttDesc(ATTVAL, 1);
	    execTupDesc->data[i]->attdesc->data[0] = origTupDesc->data[i];
	  }
	i++;
      }
    if (len > 0) {
	tupDesc = ExecTupDescToTupDesc(execTupDesc, len);
	ExecAssignResultType(commonstate, execTupDesc, tupDesc);
    }
    else
	ExecAssignResultType(commonstate,
			     (ExecTupDescriptor)NULL,
			     (TupleDescriptor)NULL);
}

/* ----------------
 *	ExecGetResultType
 * ----------------
 */
TupleDescriptor
ExecGetResultType(commonstate)
    CommonState	commonstate;
{
    TupleTableSlot	slot = get_cs_ResultTupleSlot(commonstate);
    
    return 
	ExecSlotDescriptor((Pointer) slot);
}

/* ----------------
 *	ExecFreeResultType
 * ----------------
 */
void
ExecFreeResultType(commonstate)
    CommonState	commonstate;
{
    TupleTableSlot	slot;
    TupleDescriptor	tupType;
    
    slot = 	  get_cs_ResultTupleSlot(commonstate);
    tupType = 	  ExecSlotDescriptor((Pointer) slot);
    
    ExecFreeTypeInfo((struct attribute **) tupType);	/* BUG -- glass */
}


/* ----------------
 *	ExecAssignProjectionInfo
 * ----------------
 */
void
ExecAssignProjectionInfo(node, commonstate)
    Plan 	node;
    CommonState	commonstate;
{
    ProjectionInfo	projInfo;
    List	        targetList;
    int      		len;
    Pointer	 	tupValue;
	
    targetList =  get_qptargetlist(node);
    len = 	  ExecTargetListLength(targetList);
    tupValue =    (Pointer) ExecMakeTLValues(len);

    projInfo = 	MakeProjectionInfo(targetList, len, tupValue,
				   get_cs_ExprContext(commonstate),
				   get_cs_ResultTupleSlot(commonstate));
    set_cs_ProjInfo(commonstate, projInfo);
/*
    set_pi_targetlist(projInfo, targetList);
    set_pi_len(projInfo, len);
    set_pi_tupValue(projInfo, tupValue);
    set_pi_exprContext(projInfo, get_cs_ExprContext(commonstate));
    set_pi_slot(projInfo, get_cs_ResultTupleSlot(commonstate));
*/
}


/* ----------------
 *	ExecFreeProjectionInfo
 * ----------------
 */
void
ExecFreeProjectionInfo(commonstate)
    CommonState	commonstate;
{
    ProjectionInfo	projInfo;
    Pointer	 	tupValue;

    /* ----------------
     *	get projection info.  if NULL then this node has
     *  none so we just return.
     * ----------------
     */
    projInfo = get_cs_ProjInfo(commonstate);
    if (projInfo == NULL)
	return;

    /* ----------------
     *	clean up memory used.
     * ----------------
     */
    tupValue = get_pi_tupValue(projInfo);
    ExecFreeTLValues(tupValue);
    
    pfree(projInfo);
    set_cs_ProjInfo(commonstate, 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
 * ----------------
 */
TupleDescriptor
ExecGetScanType(csstate)
    CommonScanState	csstate;
{
    TupleTableSlot slot = (TupleTableSlot)
	get_css_ScanTupleSlot(csstate);
    return ExecSlotDescriptor((Pointer) slot);
}

/* ----------------
 *	ExecFreeScanType
 * ----------------
 */
void
ExecFreeScanType(csstate)
    CommonScanState csstate;
{
    TupleTableSlot	slot;
    TupleDescriptor	tupType;
    
    slot = 	  (TupleTableSlot) get_css_ScanTupleSlot(csstate);
    tupType = 	  ExecSlotDescriptor((Pointer) slot);
    
    ExecFreeTypeInfo((struct attribute **) tupType); /* bug -- glass */
}

/* ----------------
 *	ExecAssignScanType
 * ----------------
 */
void
ExecAssignScanType(csstate, execTupDesc, tupDesc)
    CommonScanState	csstate;
    ExecTupDescriptor	execTupDesc;
    TupleDescriptor	tupDesc;
{
    TupleTableSlot	slot;
    
    slot = (TupleTableSlot) get_css_ScanTupleSlot(csstate);
    (void) ExecSetSlotDescriptor((Pointer) slot, tupDesc);
    ExecSetSlotExecDescriptor(slot, execTupDesc);
}

/* ----------------
 *	ExecAssignScanTypeFromOuterPlan
 * ----------------
 */
void
ExecAssignScanTypeFromOuterPlan(node, commonstate)
    Plan 	node;
    CommonState	commonstate;
{
    Plan		outerPlan;
    TupleDescriptor	tupDesc;
    ExecTupDescriptor	execTupDesc;
    
    outerPlan =   get_outerPlan(node);
    tupDesc = 	  ExecGetTupType(outerPlan);
    execTupDesc = ExecGetExecTupDesc(outerPlan);
    
    ExecAssignScanType((CommonScanState) commonstate, execTupDesc, tupDesc);
}


/* ----------------------------------------------------------------
 *			stuff from execCStructs
 *
 *	execCStructs was a file used in the Lisp system to do
 *	stuff with C-allocated structures.  These routines were
 *	called from the lisp executor across the foreign function
 *	interface.  Since it was easier to just keep these when
 *	we converted from lisp to C, that's what we did.  The usefulness
 *	of these functions should be reevaluated sometime soon and
 *	the code rewritten accordingly once an interface is settled on.
 *	-cim 11/1/89
 * ----------------------------------------------------------------
 */

/* ----------------------------------------------------------------
 *	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:
 *
 *	ExecGetTypeInfo(relDesc) --
 *		returns the structure 'attribute' from the relation desc.
 *	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'.
 * ----------------------------------------------------------------
 */

/* ----------------
 *	ExecGetTypeInfo
 * ----------------
 */
/**** xxref:
 *           <apparently-unused>
 ****/
Attribute
ExecGetTypeInfo(relDesc)
    Relation 	relDesc;
{
    return
	((Attribute) &relDesc->rd_att);
}

/* ----------------
 *	ExecMakeTypeInfo
 *
 *	This creates a pre-initialized array of pointers to
 *	attribute structures.  The structures themselves are
 *	expected to be initialized via calls to ExecSetTypeInfo.
 *
 *	The structure returned is a single area of memory which
 *	looks like:
 *
 *      +------+------+-----+------------+------------+-----+
 *	| ptr0 | ptr1 | ... | attribute0 | attribute1 | ... |
 *      +------+------+-----+------------+------------+-----+
 *	
 *	where ptr0 = &attribute0, ptr1 = &attribute1, etc..
 * ----------------
 */
TupleDescriptor
ExecMakeTypeInfo(nelts)
    int	nelts;
{
    struct attribute 	*ap;
    struct attribute	**info;
    int     		i;
    int     		size;

    /* ----------------
     *	calculate the size of the entire structure
     * ----------------
     */
    if (nelts <= 0)
	return NULL;

    size = (nelts * sizeof(struct attribute)) +
	((nelts + 1) * sizeof(struct attribute *));

    /* ----------------
     *	allocate the whole structure and initialize all
     *  the pointers in the initial array. The array is made
     *  one element too large so that it is NULL terminated,
     *  just in case..
     * ----------------
     */
    info = (struct attribute **) palloc(size);
    ap =   (struct attribute *) (info + (nelts + 1));
	
    for (i=0; i<nelts; i++) {
	info[i] = ap++;
    }
    info[i] = NULL;

    return
	(TupleDescriptor) info;
}

/* ----------------
 *	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.
 * ----------------
 */
void
ExecSetTypeInfo(index, typeInfo, typeID, attNum, attLen, attName, attbyVal)
    int 		index;
    struct attribute 	**typeInfo;
    ObjectId			typeID;
    int			attNum;
    int			attLen;
    char		*attName;
    Boolean		attbyVal;
{
    struct attribute	*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, attName, 16);
    else
	bzero(att->attname, 16);
    
    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;
}

ExecTupDescriptor
ExecMakeExecTupDesc(len)
int len;
{
    ExecTupDescriptor retval;

    retval = (ExecTupDescriptor)palloc(len * sizeof(ExecTupDescriptorData));
    return retval;
}

ExecAttDesc
ExecMakeExecAttDesc(tag, len)
AttributeTag tag;
int len;
{
    ExecAttDesc attdesc;
    attdesc = (ExecAttDesc)palloc(sizeof(ExecAttDescData));
    attdesc->tag = tag;
    attdesc->len = len;
    attdesc->attdesc = CreateTemplateTupleDesc(len);
    return attdesc;
}

ExecAttDesc
MakeExecAttDesc(tag, len, tupdesc)
AttributeTag tag;
int len;
TupleDescriptor tupdesc;
{
    ExecAttDesc attdesc;
    attdesc = (ExecAttDesc)palloc(sizeof(ExecAttDescData));
    attdesc->tag = tag;
    attdesc->len = len;
    attdesc->attdesc = tupdesc;
    return attdesc;
}

/* ----------------
 *	ExecFreeTypeInfo frees the array of attrbutes
 *	created by ExecMakeTypeInfo and returned by ExecTypeFromTL...
 * ----------------
 */
void
ExecFreeTypeInfo(typeInfo)
    struct attribute **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
 * ----------------------------------------------------------------
 */
/**** xxref:
 *           <apparently-unused>
 ****/
List
QueryDescGetTypeInfo(queryDesc)
    List queryDesc;
{
    Plan            plan;
    TupleDesc       tupleType;
    List            targetList;
    
    plan = 		    QdGetPlan(queryDesc);
    tupleType = (TupleDesc) ExecGetTupType(plan);
    targetList = 	    get_qptargetlist(plan);
    
    return (List)
	MakeList(lispInteger(ExecTargetListLength(targetList)), tupleType, -1);
}

/* ----------------------------------------------------------------
 *		   ExecInitScanAttributes support
 * ----------------------------------------------------------------
 */

/* --------------------------------
 *	ExecCollect
 *
 *	This function calls its collect function on the results
 *	of calling its apply function on successive elements
 *	of the list passed to it.
 * --------------------------------
 */
/**** xxref:
 *           ExecGetVarAttlistFromExpr
 *           ExecInitScanAttributes
 ****/
List
ExecCollect(l, applyFunction, collectFunction, applyParameters)
    List l;
    List (*applyFunction)();
    List (*collectFunction)();
    List applyParameters;
{
    List cdrEntry;
    List entry;
    List applyResult;
    List collection;
    collection = LispNil;
    
    foreach(cdrEntry, l) {
	entry = CAR(cdrEntry);
	applyResult = (*applyFunction)(entry, applyParameters);
	collection = (*collectFunction)(applyResult, collection);
    }
    
    return collection;
}
 
/* --------------------------------
 *	ExecUniqueCons
 *
 *	This function returns a list of unique integers, given
 *	two lists as input.  Since our lists are short and this
 *	is only done once each query, we don't bother worring
 *	about efficiency.. (this should probably be done in the
 *	planner anyways..)
 *
 *      Note: list2 had better be free of duplicates already.
 *            list1 can have duplicates - they get tossed.
 *
 *	Final list consists elts of list1 on the head of list2,
 *	unless one of the lists is nil, in which case the other
 *	is returned..
 * --------------------------------
 */
/**** xxref:
 *           <apparently-unused>
 ****/
List
ExecUniqueCons(list1, list2)
    List list1;
    List list2;
{
    List 	current1;
    List 	current2;
    LispValue 	current1Int;
    LispValue 	current2Int;
    bool	foundDuplicate;
    
    /* ----------------
     *	make sure both lists contain something
     * ----------------
     */
    if (lispNullp(list1))
	return list2;
    
    if (lispNullp(list2))
	return list1;
    
    /* ----------------
     *	for each entry in the first list 
     *     see if it's already in the second list
     *     if so, then move onto the next entry in the first list
     *     if not, then add the entry to the front of the second list.
     *
     *  note: this trashes list1.. non-duplicates are moved to list2
     *        and duplicates are left stranded in memory..
     * ----------------
     */
    
    current1 = list1;
    while (! lispNullp(current1)) {
	current1Int = CAR(current1);
	current2 = list2;
	foundDuplicate = false;
	
	/* ----------------
	 *  see if current item from list 1 is already in list2
	 * ----------------
	 */
	while (! lispNullp(current2)) {
	    current2Int = CAR(current2);
	    if (CInteger(current2Int) == CInteger(current1Int)) {
		foundDuplicate = true;
		break;
	    } 
	    current2 = CDR(current2);
	}
	
	/* ----------------
	 *  foundDuplicate is now true if current item is in list2
	 *  and is false if we traversed all of list2 and no item there
	 *  matched it..
	 * ----------------
	 */
	if (! foundDuplicate) {
	    List temp;
	    /* ----------------
	     *  since current1 is not in list2, move current1 onto the head
	     *  of list2 and then move to the next element in list1.
	     * ----------------
	     */
	    temp =          CDR(current1);
	    CDR(current1) = list2;
	    list2 =         current1;
	    current1 =      temp;
	} else {
	    /* ----------------
	     *  current1 is already in list2 so we just
	     *	advance current1 to the next element in list1
	     * ----------------
	     */
	    current1 = CDR(current1);
	}
    }
    
    /* ----------------
     *	at this point, all elts of list1 not originally in list2
     *  are on the head of list2 so we can just return list2.
     * ----------------
     */
    return list2;
}
 
/* --------------------------------
 *	ExecGetVarAttlistFromExpr
 *
 *	This is a recursive function which returns a list
 *	containing the attribute numbers of all var nodes
 * --------------------------------
 */
/**** xxref:
 *           ExecGetVarAttlistFromExpr
 *           ExecGetVarAttlistFromTLE
 ****/
List
ExecGetVarAttlistFromExpr(expr, relationNum)
    Node expr;
    List relationNum;
{
    /* ----------------
     *	const nodes have no information for us, so we return nil.
     * ----------------
     */
    if (ExactNodeType(expr,Const))
	return LispNil;
    
    /* ----------------
     *	var nodes are what we want.. so we check if
     *  the var node applies to the relation we want
     *  and if it does, we return the var's attribute number
     *  in a list.  If the var is not associated with
     *  the relation we are interested in then we just return nil.
     * ----------------
     */
    if (ExactNodeType(expr,Var)) {
	Index varno;
	AttributeNumber relno;
	AttributeNumber attno;
    
	relno = CInteger(CAR(relationNum));
	varno = get_varno((Var)expr);
	attno = get_varattno((Var) expr);
	
	if (varno == relno)
	    return lispCons(lispInteger(attno), LispNil);
	else
	    return LispNil;
    }
    /* ----------------
     *	operator expressions may have var nodes in their
     *  opargs so we recursively search for var nodes there..
     * ----------------
     */
    if (is_clause(expr)) {
	List opargs;
	opargs = (List) get_opargs(expr);
	return ExecCollect(opargs, 		      /* list */
			   ExecGetVarAttlistFromExpr, /* apply function */
			   ExecUniqueCons,	      /* collect function */
			   relationNum); 	      /* apply parameters */
    } 
    /* ----------------
     *	function expressions are just like operator expressions..
     *  we scan the function expression's arg list to find the var nodes
     *  from which we get attribute numbers
     * ----------------
     */
    if (is_funcclause(expr)) {
	List funcargs;
	funcargs = (List) get_funcargs(expr);
	return ExecCollect(funcargs, 		      /* list */
			   ExecGetVarAttlistFromExpr, /* apply function */
			   ExecUniqueCons,	      /* collect function */
			   relationNum); 	      /* apply parameters */
    }
    /* ----------------
     *	for or clauses, we scan each of the or expressions
     *  because they may contain var nodes also..
     * ----------------
     */
    if (or_clause(expr)) {
	List clauseargs;
	clauseargs = (List) get_orclauseargs(expr);
	return ExecCollect(clauseargs, 		      /* list */
			   ExecGetVarAttlistFromExpr, /* apply function */
			   ExecUniqueCons,	      /* collect function */
			   relationNum); 	      /* apply parameters */
    }
    /* ----------------
     *	finally, not clauses are easy, we just return the
     *  attributes from the not clause's argument..
     * ----------------
     */
    if (not_clause(expr)) {
	List notclausearg;
	notclausearg = (List) get_notclausearg(expr);
	return
	    ExecGetVarAttlistFromExpr((Node) notclausearg, relationNum);
    }
    
    /* ----------------
     *	if expr is not one of the above, our structure is likely
     *  corrupted but then we know there ain't no var nodes so
     *  we return nil and keep-a-processing...
     * ----------------
     */
    elog(DEBUG, "ExecGetVarAttlistFromExpr: invalid node type in expr!");
    return LispNil;
}
 
/* --------------------------------
 *	ExecGetVarAttlistFromTLE
 *
 *	This is simple.. Just extract the expression from
 *	the target list entry and have ExecGetAttlistFromExpr
 *	do our work for us..
 * --------------------------------
 */
/**** xxref:
 *           <apparently-unused>
 ****/
List
ExecGetVarAttlistFromTLE(tle, relationNum)
    List tle;
    List relationNum;    
{
    Node expr;
    
    expr =  (Node) tl_expr(tle);
    return
	ExecGetVarAttlistFromExpr(expr, relationNum);
}
 
/* --------------------------------
 *	ExecMakeAttsFromList
 *
 *	Returns an array of AttributeNumber's given a list,
 *      and returns the size of the array in it's second parameter.
 * --------------------------------
 */
/**** xxref:
 *           ExecInitScanAttributes
 ****/
AttributeNumberPtr
ExecMakeAttsFromList(attlist, numAttsPtr)
    List attlist;
    int	 *numAttsPtr;
{
    List		cdrEntry;
    List		entry;
    int 		len;
    AttributeNumberPtr  attnums;
    int			i;
    
    len = length(attlist);
    CXT1_printf("ExecMakeAttsFromList: context is %d\n", CurrentMemoryContext);
    attnums = (AttributeNumberPtr)
	palloc(len * sizeof(AttributeNumber));
    i = 0;
    foreach (cdrEntry, attlist) {
	entry = CAR(cdrEntry);
	attnums[i++] = CInteger(entry);
    }
    if (numAttsPtr != NULL)
	(*numAttsPtr) = i;
    
    return attnums;
}
 
/* --------------------------------
 *	ExecInitScanAttributes
 *
 *	This inspects the node's target list and initializes
 *	an array of attribute numbers stored in the node.
 *
 *	This array describe which attributes of the scanned
 *	tuple are ever examined or returned.  The rule manager
 *	uses this information to know which attributes are going
 *	to be inspected.
 *
 *	This is nontrivial because we have to walk the
 *	entire target list structure and find all the var
 *	nodes with varno's equal to the index (in the range table)
 *	of the relation being scanned by the node..
 *
 *	XXX:  If a user defined function/operator references
 *	      attributes in some wierd indirect way, then the
 *	      rule manager might not know to do the right thing
 *	      because we don't detect this.
 *
 *	      In these circumstance, we have to have the rule manager
 *	      message every attribute of the tuple and we need to
 *	      know somehow that the function can manipulate the tuple
 *	      in some unexpected manner..
 *
 *	Note: the memory used by the cons cells in our
 *	temporary lists is not reclaimed until the end of transaction.
 *	(A better setup would free the memory as we go.)
 *
 *	Here is one instance where it would be much easier
 *	to write this in lisp..
 * --------------------------------
 */
/**** xxref:
 *           ExecInitIndexScan
 *           ExecInitSeqScan
 ****/
void
ExecInitScanAttributes(node)
    Plan node;
{
    ScanState		scanstate;
    List		targetList;
    AttributeNumberPtr 	scanAtts;
    int			numScanAtts;
    List		attlist;
    
    /* ----------------
     *	make sure we have a scan node
     * ----------------
     */
    if (!ExecIsSeqScan(node) && !ExecIsIndexScan(node)) {
	elog(DEBUG, "ExecInitScanAttributes: called on non scan node");
	return;
    }
    
    /* ----------------
     *	XXX currently we assign attlist = LispNil which forces
     *      ExecScan() to generate the attribute information
     *      at runtime when the first tuple is retrieved.
     *
     *	    This is a poor long-term solution because that
     *	    means the rule-manager ends up inspecting every
     *	    attribute of every tuple scanned..  But this will
     *	    work for now.. -cim 10/12/89
     * ----------------
     */
    attlist = LispNil;

    /* ----------------
     *  get information from the node.. 
     *	Note: both indexscans and seqscans have scanstates since
     *  indexscans inherit from seqscans.
     * ----------------
     */
    scanstate =  get_scanstate((Scan) node);
    
#ifdef PERHAPSNEVER
    /* ----------------
     *	need the range table index of the scanned relation
     *  into relno so we know which var nodes to inspect.
     *  ExecCollect expects a list so we put it in one..
     * ----------------
     */
    targetList =  get_qptargetlist(node);
    
    relno = 	  get_scanrelid(node);
    relationNum = lispCons(lispInteger(relno), LispNil);
    
    /* ----------------
     *	construct a list of all the attributes using ExecCollect
     * ----------------
     */
    attlist = ExecCollect(targetList, 		    /* list */
			  ExecGetVarAttlistFromTLE, /* apply function */
			  ExecUniqueCons,	    /* collect function */
			  relationNum); 	    /* apply parameters */
    
    if (ExecIsIndexScan(node)) {
	/* ----------------
	 *  we might also inspect the indxqual clauses in the
	 *  index node for additional attribute number information
	 *  but I don't understand how to do this now.. -cim 9/21/89
	 * ----------------
	 */
    }

    /* XXX should also inspect qpqual */
#endif PERHAPSNEVER
    
    /* ----------------
     *	make attribute array from attlist.
     * ----------------
     */
    if (lispNullp(attlist)) {
	scanAtts = NULL;
	numScanAtts = 0;
    } else
	scanAtts = ExecMakeAttsFromList(attlist, &numScanAtts);
    
    /* ----------------
     *	set the node's attribute information
     * ----------------
     */
    set_cs_ScanAttributes((CommonState) scanstate, scanAtts);
    set_cs_NumScanAttributes((CommonState) scanstate, numScanAtts);
}

/* --------------------------------
 *	ExecMakeBogusScanAttributes
 *
 *	This makes an array of size natts containing the
 *	attribute numbers from 1 to natts.
 * --------------------------------
 */
AttributeNumberPtr
ExecMakeBogusScanAttributes(natts)
    int natts;
{
    extern MemoryContext PortalExecutorHeapMemory;
    AttributeNumberPtr   scanAtts;
    int			 scanAttSize;
    int			 i;

    /* ----------------
     *	calculate size of our array
     * ----------------
     */
    scanAttSize = natts * sizeof(AttributeNumber);
	    
    /* ----------------
     *  if we are running in a portal, we have to make
     *  sure our allocations occur in the proper context
     *  lest they go away unexpectedly.  This is a hack
     *  to preserve this memory for the lifetime of the
     *  portal (I think).  -cim 3/15/90
     * ----------------
     */
    if (PortalExecutorHeapMemory != NULL)
	scanAtts = (AttributeNumberPtr)
	    MemoryContextAlloc(PortalExecutorHeapMemory, scanAttSize);
    else
	scanAtts = (AttributeNumberPtr)
	    palloc(scanAttSize);
    
    /* ----------------
     *	fill the scan attributes array
     * ----------------
     */
    for (i=1; i<=natts; i++) {
	scanAtts[i-1] = i;
    }	

    return scanAtts;
}
    

/* --------------------------------
 *	ExecFreeScanAttributes
 *
 *	This frees the allocated array of attribute numbers.
 *
 *	Note: it is not an error to pass NULL.  That just means
 *	that no attribute information was allocated.
 * --------------------------------
 */
 
/**** xxref:
 *           ExecEndIndexScan
 *           ExecEndSeqScan
 ****/
void
ExecFreeScanAttributes(ptr)
    AttributeNumberPtr ptr;
{
    extern MemoryContext PortalExecutorHeapMemory;

    /* ----------------
     *	don't free an invalid pointer
     * ----------------
     */
    if (ptr == NULL)
	return;

    /* ----------------
     *	make certain we free the attribute list in the proper
     *  memory context.  Again, this is a crappy hack which comes
     *  from retrofitting portals into the executor.
     * ----------------
     */
    if (PortalExecutorHeapMemory != NULL)
	MemoryContextFree(PortalExecutorHeapMemory, (Pointer) ptr);
    else
	pfree(ptr);
}
 
/* function that returns number of atts in a var */
int
ExecGetVarLen(node, commonstate, var)
Plan node;
CommonState commonstate;
Var var;
{
    int varno, varattno;
    TupleTableSlot    slot;
    ExecTupDescriptor   execTupDesc;
    int len;
    Plan varplan;

    if (node == NULL) return 0;
    varno = get_varno(var);
    varattno = get_varattno(var);
    if (varno == INNER)
	varplan = get_innerPlan(node);
    else
	varplan = get_outerPlan(node);
    if (varattno == 0) {
	if (varplan == NULL) {
	    /* this must be a scan */
	    Relation curRel;
	    curRel = get_css_currentRelation((CommonScanState)commonstate);
	    len = curRel->rd_rel->relnatts;
	  }
	else
	    len = ExecTargetListLength(get_qptargetlist(varplan));
      }
    else {
	    slot = NodeGetResultTupleSlot(varplan);
	    execTupDesc = ExecSlotExecDescriptor(slot);
	    len = execTupDesc->data[varattno-1]->len;
      }
    return len;
}

/* function that returns the Tuple Descriptor for a var */
TupleDescriptor
ExecGetVarTupDesc(node, commonstate, var)
Plan node;
CommonState commonstate;
Var var;
{
    int varno, varattno;
    TupleTableSlot    slot;
    ExecTupDescriptor   execTupDesc;
    TupleDescriptor tupdesc;
    Plan varplan;

    if (node == NULL) return 0;
    varno = get_varno(var);
    varattno = get_varattno(var);
    if (varno == INNER)
	varplan = get_innerPlan(node);
    else
	varplan = get_outerPlan(node);
    if (varattno == 0) {
	if (varplan == NULL) {
	    /* this must be a scan */
	    Relation curRel;
	    curRel = get_css_currentRelation((CommonScanState)commonstate);
	    tupdesc = &curRel->rd_att;
	  }
	else
	    tupdesc = ExecGetTupType(varplan);
      }
    else {
	    execTupDesc = ExecGetExecTupDesc(varplan);
	    tupdesc = execTupDesc->data[varattno-1]->attdesc;
      }
    return tupdesc;
}
