home *** CD-ROM | disk | FTP | other *** search
- /* ----------------------------------------------------------------
- * FILE
- * ex_qual.c
- *
- * DESCRIPTION
- * Routines to evaluate qualification and targetlist expressions
- *
- * INTERFACE ROUTINES
- * ExecEvalExpr - evaluate an expression and return a datum
- * ExecQual - return true/false if qualification is satisified
- * ExecTargetList - form a new tuple by projecting the given tuple
- *
- * NOTES
- * ExecEvalExpr() and ExecEvalVar() are hotspots. making these faster
- * will speed up the entire system. Unfortunately they are currently
- * implemented recursively.. Eliminating the recursion is bound to
- * improve the speed of the executor.
- *
- * ExecTargetList() is used to make tuple projections. Rather then
- * trying to speed it up, the execution plan should be pre-processed
- * to facilitate attribute sharing between nodes wherever possible,
- * instead of doing needless copying. -cim 5/31/91
- *
- * IDENTIFICATION
- * $Header: /private/postgres/src/executor/RCS/ex_qual.c,v 1.24 1992/08/25 17:46:29 mer Exp $
- * ----------------------------------------------------------------
- */
-
- #include "tmp/align.h"
- #include "parser/parsetree.h"
- #include "parser/parse.h" /* for NOT used in macros in ExecEvalExpr */
- #include "nodes/primnodes.h"
- #include "nodes/relation.h"
- #include "planner/keys.h"
- #include "nodes/mnodes.h"
- #include "catalog/pg_language.h"
- #include "executor/executor.h"
- RcsId("$Header: /private/postgres/src/executor/RCS/ex_qual.c,v 1.24 1992/08/25 17:46:29 mer Exp $");
- /* ----------------
- * externs and constants
- * ----------------
- */
-
-
- /*
- * XXX Used so we can get rid of use of Const nodes in the executor.
- * Currently only used by ExecHashGetBucket and set only by ExecMakeVarConst
- * and by ExecEvalArrayRef.
- */
- Boolean execConstByVal;
- int execConstLen;
-
- /* ----------------
- * sysattrlen
- * sysattrbyval
- *
- * these have been moved to access/tuple/tuple.c
- * ----------------
- */
-
- /* --------------------------------
- * array_cast
- * --------------------------------
- */
- Datum
- array_cast(value, byval, len)
- char *value;
- bool byval;
- int len;
- {
- if (byval) {
- switch (len) {
- case 1:
- return((Datum) * value);
- case 2:
- return((Datum) * (int16 *) value);
- case 3:
- case 4:
- return((Datum) * (int32 *) value);
- default:
- elog(WARN, "ExecEvalArrayRef: byval and elt len > 4!");
- return(NULL);
- break;
- }
- } else
- return (Datum) value;
- }
-
- /* --------------------------------
- * ExecEvalArrayRef
- *
- * This function takes an ArrayRef and returns a Const Node which
- * is the actual array reference. It is used to de-reference an array.
- *
- * This code knows about the internal storage scheme for both fixed-length
- * arrays (like char16, int28, etc) and for variable length arrays. It
- * currently assumes that fixed-length arrays are contiguous blobs of memory
- * where the first element is in the starting position. Variable length
- * arrays are presumed to have the following format:
- *
- * <length_in_bytes><elem_1><elem_2>...<elem_n>
- *
- * It checks to see if <length_in_bytes> / <number_of_elements> = typlen
- * as a sanity check for variable length arrays.
- *
- * -Greg
- *
- * old comments:
- *
- * XXX this code should someday handle the case where there is
- * an expression of the form: a.b[ expression ] rather then
- * just a.b[ constant ] as it does now. 99% of this can be
- * done by using ExecEvalExpr() but it would mean some more
- * work in the parser. -cim 6/20/90
- * --------------------------------
- */
-
- #define MinArrayIndirection 1
-
- Datum
- ExecEvalArrayRef(arrayRef, econtext, isNull, isDone)
- ArrayRef arrayRef;
- ExprContext econtext;
- Boolean *isNull;
- Boolean *isDone;
- {
- int32 array_len;
- int32 element_len;
- int32 indirection;
- bool byval;
- bool dummy;
- int i;
- char *array_scanner;
- int nelems;
- int bytes;
- int nbytes;
- int offset;
- bool done = false;
- char *retval;
-
- *isNull = false;
- array_scanner = (char *)ExecEvalExpr((Node)get_refexpr(arrayRef),
- econtext,
- isNull,
- isDone);
- if (*isNull)
- return (Datum)NULL;
- /*
- * Array indices *cannot* be sets and are 1 based (convert to 0 based).
- */
- indirection = (int32)ExecEvalExpr((Node)get_refindexpr(arrayRef),
- econtext,
- isNull,
- &dummy);
- if (*isNull)
- return (Datum)NULL;
-
- if (indirection < MinArrayIndirection)
- {
- *isNull = true;
- return (Datum)NULL;
- }
- indirection--;
-
- byval = execConstByVal = get_refelembyval(arrayRef);
- element_len = get_refelemlength(arrayRef);
-
- if (get_refattrlength(arrayRef) < 0)
- {
- nbytes = (* (int32 *) array_scanner) - sizeof(int32);
- array_scanner += sizeof(int32);
- }
- else
- nbytes = get_refattrlength(arrayRef);
-
- if (element_len < 0) {
- bytes = nbytes;
- i = 0;
- while (bytes > 0 && !done) {
- if (i == indirection) {
- retval = array_scanner;
- done = true;
- }
- bytes -= LONGALIGN(* (int32 *) array_scanner);
- array_scanner += LONGALIGN(* (int32 *) array_scanner);
- i++;
- }
-
- if (! done) {
- if (bytes == 0) { /* array[i] does not exist */
- *isNull = true;
- return(NULL);
- } else { /* bytes < 0 - error */
- elog(WARN, "ExecEvalArrayRef: improperly formatted array");
- }
- }
- return (Datum) retval;
-
- } else {
- /* array of fixed length elements */
-
- offset = indirection * element_len;
-
- /*
- * off the end of the array
- */
- if (nbytes - offset < 1) {
- *isNull = true;
- return(NULL);
- }
-
- retval = array_scanner + offset;
-
- return array_cast(retval, byval, element_len);
- }
- }
-
- Datum
- ExecExtractResult(slot, attnum, isNull)
- TupleTableSlot slot;
- AttributeNumber attnum;
- Boolean *isNull;
- {
- ExecTupDescriptor execTd;
- TupleDescriptor td;
- HeapTuple tuple;
- Buffer buffer;
- DatumPtr values;
- char *nullVect;
- int count;
- int subTupNatts;
- AttributeNumber subTupAtt;
- TupleTableSlot resultSlot;
-
- execTd = SlotExecTupDescriptor(slot);
-
- *isNull = false;
- subTupNatts = execTd->data[attnum-1]->len;
- td = ExecSlotDescriptor(slot);
- tuple = (HeapTuple)ExecFetchTuple(slot);
- buffer = ExecSlotBuffer(slot);
-
- values = (DatumPtr)palloc(subTupNatts*sizeof(Datum));
- nullVect = (char *)palloc(subTupNatts*sizeof(char));
-
- /*
- * Figure out where in the context of the larger tuple to begin
- * searching for the sub tuples attributes. Note that attribute
- * numbers are 1 based.
- */
- count = 0;
- subTupAtt = 1;
- while (count < (attnum-1))
- subTupAtt += execTd->data[count++]->len;
-
- count = 0;
- while (count < subTupNatts)
- {
- bool attrIsNull;
-
- values[count] = (Datum)
- heap_getattr(tuple,
- buffer,
- subTupAtt,
- (struct attribute **)&td->data[0],
- &attrIsNull);
-
- if (attrIsNull)
- nullVect[count] = 'n';
- else
- nullVect[count] = ' ';
-
- count++;
- subTupAtt++;
- }
-
- td = execTd->data[attnum-1]->attdesc;
- tuple = heap_formtuple(subTupNatts, td, values, nullVect);
- resultSlot = MakeTupleTableSlot(false,
- true,
- ExecCopyTupType(td, subTupNatts),
- NULL,
- InvalidBuffer,
- -1);
- return (Datum)
- ExecStoreTuple((Pointer) tuple,
- (Pointer) resultSlot,
- InvalidBuffer,
- true);
- }
- /* ----------------------------------------------------------------
- * ExecEvalVar
- *
- * Returns a Datum whose value is the value of a range
- * variable with respect to given expression context.
- * ----------------------------------------------------------------
- */
-
- /**** xxref:
- * ExecEvalExpr
- ****/
- Datum
- ExecEvalVar(variable, econtext, isNull)
- Var variable;
- ExprContext econtext;
- Boolean *isNull;
- {
- Datum result;
- TupleTableSlot slot;
- AttributeNumber attnum;
- TupleDescriptor tupType;
- ExecTupDescriptor execTupDesc;
- Buffer tupBuffer;
- List array_info;
-
- HeapTuple heapTuple;
- TupleDescriptor tuple_type;
- Buffer buffer;
- ObjectId typeoid;
- bool byval;
- Pointer value;
- int16 len;
-
- /* ----------------
- * get the slot we want
- * ----------------
- */
- switch(get_varno(variable)) {
- case INNER: /* get the tuple from the inner node */
- slot = get_ecxt_innertuple(econtext);
- break;
-
- case OUTER: /* get the tuple from the outer node */
- slot = get_ecxt_outertuple(econtext);
- break;
-
- default: /* get the tuple from the relation being scanned */
- slot = get_ecxt_scantuple(econtext);
- break;
- }
-
- /* ----------------
- * extract tuple information from the slot
- * ----------------
- */
- heapTuple = (HeapTuple) ExecFetchTuple((Pointer) slot);
- tuple_type = ExecSlotDescriptor((Pointer)slot);
- buffer = ExecSlotBuffer((Pointer)slot);
-
- attnum = get_varattno(variable);
-
- /*
- * If the attribute number is invalid, then we are supposed to
- * return the entire tuple, we give back a whole slot so that
- * callers know what the tuple looks like.
- */
- if (attnum == InvalidAttributeNumber)
- {
- TupleTableSlot tempSlot;
- TupleDescriptor td;
- HeapTuple tup;
-
- tempSlot = MakeTupleTableSlot(false,
- true,
- (TupleDescriptor)NULL,
- (ExecTupDescriptor)NULL,
- InvalidBuffer,
- -1);
-
- tup = (HeapTuple)heap_copysimple(ExecFetchTuple(slot));
- td = (TupleDescriptor)
- ExecCopyTupType(ExecSlotDescriptor(slot), tup->t_natts);
- ExecSetSlotDescriptor((Pointer)tempSlot, td);
-
- ExecStoreTuple((Pointer)tup, (Pointer)tempSlot, InvalidBuffer, true);
- return (Datum) tempSlot;
- }
-
- /* ----------------
- * get the attribute our of the tuple. Note that
- * now the attribute could be much more than a simple datum.
- * ----------------
- */
- execTupDesc = SlotExecTupDescriptor(slot);
- if (execTupDesc != (ExecTupDescriptor)NULL &&
- AttributeNumberIsForUserDefinedAttribute(attnum) &&
- execTupDesc->data[attnum-1]->tag == ATTTUP)
- {
- result = ExecExtractResult(slot, attnum, isNull);
- }
- else
- {
- result = (Datum)
- heap_getattr(heapTuple, /* tuple containing attribute */
- buffer, /* buffer associated with tuple */
- attnum, /* attribute number of desired attribute */
- tuple_type, /* tuple descriptor of tuple */
- isNull); /* return: is attribute null? */
- }
-
- /* ----------------
- * return null if att is null
- * ----------------
- */
- if (*isNull)
- return NULL;
-
- /* ----------------
- * get length and type information..
- * ??? what should we do about variable length attributes
- * - variable length attributes have their length stored
- * in the first 4 bytes of the memory pointed to by the
- * returned value.. If we can determine that the type
- * is a variable length type, we can do the right thing.
- * -cim 9/15/89
- * ----------------
- */
- if (attnum < 0) {
- /* ----------------
- * If this is a pseudo-att, we get the type and fake the length.
- * There ought to be a routine to return the real lengths, so
- * we'll mark this one ... XXX -mao
- * ----------------
- */
- len = sysattrlen(attnum); /* XXX see -mao above */
- byval = sysattrbyval(attnum); /* XXX see -mao above */
- } else {
- len = tuple_type->data[ attnum-1 ]->attlen;
- byval = tuple_type->data[ attnum-1 ]->attbyval ? true : false ;
- }
-
- execConstByVal = byval;
- execConstLen = len;
-
- return result;
- }
-
- /* ----------------------------------------------------------------
- * ExecEvalParam
- *
- * Returns the value of a parameter. A param node contains
- * something like ($.name) and the expression context contains
- * the current parameter bindings (name = "sam") (age = 34)...
- * so our job is to replace the param node with the datum
- * containing the appropriate information ("sam").
- *
- * Q: if we have a parameter ($.foo) without a binding, i.e.
- * there is no (foo = xxx) in the parameter list info,
- * is this a fatal error or should this be a "not available"
- * (in which case we shoud return a Const node with the
- * isnull flag) ? -cim 10/13/89
- *
- * Minor modification: Param nodes now have an extra field,
- * `paramkind' which specifies the type of parameter
- * (see params.h). So while searching the paramList for
- * a paramname/value pair, we have also to check for `kind'.
- *
- * NOTE: The last entry in `paramList' is always an
- * entry with kind == PARAM_INVALID.
- * ----------------------------------------------------------------
- */
- /**** xxref:
- * ExecEvalExpr
- ****/
- Datum
- ExecEvalParam(expression, econtext, isNull)
- Param expression;
- ExprContext econtext;
- Boolean *isNull;
- {
-
- Name thisParameterName;
- int thisParameterKind;
- AttributeNumber thisParameterId;
- int i;
- int matchFound;
- Const constNode;
- ParamListInfo paramList;
-
- thisParameterName = get_paramname(expression);
- thisParameterKind = get_paramkind(expression);
- thisParameterId = get_paramid(expression);
- paramList = get_ecxt_param_list_info(econtext);
-
- *isNull = false;
- /*
- * search the list with the parameter info to find a matching name.
- * An entry with an InvalidName denotes the last element in the array.
- */
- matchFound = 0;
- if (paramList != NULL) {
- /*
- * search for an entry in 'paramList' that matches
- * the `expression'.
- */
- while(paramList->kind != PARAM_INVALID && !matchFound) {
- switch (thisParameterKind) {
- case PARAM_NAMED:
- if (thisParameterKind == paramList->kind &&
- NameIsEqual(paramList->name, thisParameterName)){
- matchFound = 1;
- }
- break;
- case PARAM_NUM:
- if (thisParameterKind == paramList->kind &&
- paramList->id == thisParameterId) {
- matchFound = 1;
- }
- break;
- case PARAM_OLD:
- case PARAM_NEW:
- if (thisParameterKind == paramList->kind &&
- paramList->id == thisParameterId)
- {
- matchFound = 1;
- /*
- * sanity check
- */
- if (! NameIsEqual(paramList->name, thisParameterName)){
- elog(WARN,
- "ExecEvalParam: new/old params with same id & diff names");
- }
- }
- break;
- default:
- /*
- * oops! this is not supposed to happen!
- */
- elog(WARN, "ExecEvalParam: invalid paramkind %d",
- thisParameterKind);
- }
- if (! matchFound) {
- paramList++;
- }
- } /*while*/
- } /*if*/
-
- if (!matchFound) {
- /*
- * ooops! we couldn't find this parameter
- * in the parameter list. Signal an error
- */
- elog(WARN, "ExecEvalParam: Unknown value for parameter %s",
- thisParameterName);
- }
-
- /*
- * return the value.
- */
- if (paramList->isnull)
- {
- *isNull = true;
- return (Datum)NULL;
- }
-
- if (get_param_tlist(expression) != (List)NULL)
- {
- HeapTuple tup;
- Datum value;
- List tlist = get_param_tlist(expression);
- List tle = CAR(tlist);
- TupleTableSlot slot = (TupleTableSlot)paramList->value;
-
- tup = (HeapTuple)ExecFetchTuple((Pointer)slot);
- value = ProjectAttribute(ExecSlotDescriptor(slot), tle, tup, isNull);
- return value;
- }
- return(paramList->value);
- }
-
-
- /* ----------------------------------------------------------------
- * ExecEvalOper / ExecEvalFunc support routines
- * ----------------------------------------------------------------
- */
-
- /* ----------------
- * GetAttributeByName
- * GetAttributeByNum
- *
- * These are functions which return the value of the
- * named attribute out of the tuple from the arg slot. User defined
- * C functions which take a tuple as an argument are expected
- * to use this. Ex: overpaid(EMP) might call GetAttributeByNum().
- * ----------------
- */
-
- GetAttributeByNum(slot, attrno, isNull)
- TupleTableSlot slot;
- AttributeNumber attrno;
- Boolean *isNull;
- {
- Datum retval;
-
- if (!AttributeNumberIsValid(attrno))
- elog(WARN, "GetAttributeByNum: Invalid attribute number");
-
- if (!AttributeNumberIsForUserDefinedAttribute(attrno))
- elog(WARN, "GetAttributeByNum: cannot access system attributes here");
-
- if (isNull == (Boolean *)NULL)
- elog(WARN, "GetAttributeByNum: a NULL isNull flag was passed");
-
- if (TupIsNull((Pointer)slot))
- {
- *isNull = true;
- return;
- }
-
- retval = (Datum)
- heap_getattr(ExecFetchTuple(slot),
- ExecSlotBuffer(slot),
- attrno,
- ExecSlotDescriptor(slot),
- isNull);
- if (*isNull)
- return NULL;
- else
- return retval;
- }
-
- GetAttributeByName(slot, attname, isNull)
- TupleTableSlot slot;
- Name attname;
- Boolean *isNull;
- {
- AttributeNumber attrno;
- TupleDescriptor tupdesc;
- HeapTuple tuple;
- ObjectId relid;
- Datum retval;
- int natts;
- int i;
-
- if (attname == (Name)NULL)
- elog(WARN, "GetAttributeByName: Invalid attribute name");
-
- if (isNull == (Boolean *)NULL)
- elog(WARN, "GetAttributeByName: a NULL isNull flag was passed");
-
- if (TupIsNull((Pointer)slot))
- {
- *isNull = true;
- return;
- }
-
- tupdesc = ExecSlotDescriptor(slot);
- tuple = (HeapTuple)ExecFetchTuple(slot);
-
- natts = tuple->t_natts;
-
- i = 0;
- attrno = InvalidAttributeNumber;
- while (i < natts)
- {
- /*
- * Given a slot we really don't know how many attributes
- * we have in the tuple, so I chose to use a completely
- * bogus check looking right into bogus memory. I can't
- * think of a reasonable way to do this and it is getting
- * late. I apologize to future post-boys and post-girls -mer
- */
- if (strncmp(attname,
- &(tupdesc->data[i]->attname),
- sizeof(NameData)) == 0)
- {
- attrno = tupdesc->data[i]->attnum;
- break;
- }
- i++;
- }
-
- if (attrno == InvalidAttributeNumber)
- elog(WARN, "GetAttributeByName: attribute %s not found", attname);
-
- retval = (Datum)
- heap_getattr(ExecFetchTuple(slot),
- ExecSlotBuffer(slot),
- attrno,
- tupdesc,
- isNull);
- if (*isNull)
- return NULL;
- else
- return retval;
- }
-
- void
- ExecEvalFuncArgs(fcache, econtext, argList, argV, argIsDone)
- FunctionCachePtr fcache;
- ExprContext econtext;
- List argList;
- Datum argV[];
- Boolean *argIsDone;
- {
- int i;
- bool argIsNull, *nullVect;
- LispValue arg;
-
- nullVect = fcache->nullVect;
-
- i = 0;
- foreach (arg, argList) {
- /* ----------------
- * evaluate the expression, in general functions cannot take
- * sets as arguments but we make an exception in the case of
- * nested dot expressions. We have to watch out for this case
- * here.
- * ----------------
- */
- argV[i] = (Datum)
- ExecEvalExpr((Node) CAR(arg),
- econtext,
- &argIsNull,
- argIsDone);
- if (! (*argIsDone))
- {
- Assert(i == 0);
- fcache->setArg = (char *)argV[0];
- fcache->hasSetArg = true;
- }
- if (argIsNull)
- nullVect[i] = true;
- else
- nullVect[i] = false;
- i++;
- }
- }
-
- /* ----------------
- * ExecMakeFunctionResult
- * ----------------
- */
- Datum
- ExecMakeFunctionResult(node, arguments, econtext, isNull, isDone)
- Node node;
- List arguments;
- ExprContext econtext;
- Boolean *isNull;
- Boolean *isDone;
- {
- List arg;
- Datum argv[MAXFMGRARGS];
- FunctionCachePtr fcache;
- Func funcNode = NULL;
- Oper operNode = NULL;
-
- /*
- * This is kind of ugly, Func nodes now have targetlists so that
- * we know when and what to project out from postquel function results.
- * This means we have to pass the func node all the way down instead
- * of using only the fcache struct as before. ExecMakeFunctionResult
- * becomes a little bit more of a dual personality as a result.
- */
- if (ExactNodeType(node,Func))
- {
- funcNode = (Func)node;
- fcache = get_func_fcache(funcNode);
- }
- else
- {
- operNode = (Oper)node;
- fcache = get_op_fcache(operNode);
- }
-
- /* ----------------
- * arguments is a list of expressions to evaluate
- * before passing to the function manager.
- * We collect the results of evaluating the expressions
- * into a datum array (argv) and pass this array to arrayFmgr()
- * ----------------
- */
- if (fcache->nargs != 0) {
- bool argDone;
-
- if (fcache->nargs > MAXFMGRARGS)
- elog(WARN, "ExecMakeFunctionResult: too many arguments");
-
- /*
- * If the setArg in the fcache is set we have an argument
- * returning a set of tuples (i.e. a nested dot expression). We
- * don't want to evaluate the arguments again until the function
- * is done. hasSetArg will always be false until we eval the args
- * for the first time. We should set this in the parser.
- */
- if ((fcache->hasSetArg) && fcache->setArg != NULL)
- {
- argv[0] = (Datum)fcache->setArg;
- argDone = false;
- }
- else
- ExecEvalFuncArgs(fcache, econtext, arguments, argv, &argDone);
-
- if ((fcache->hasSetArg) && (argDone)) {
- if (isDone) *isDone = true;
- return (Datum)NULL;
- }
- }
-
- /* ----------------
- * now return the value gotten by calling the function manager,
- * passing the function the evaluated parameter values.
- * ----------------
- */
- if (fcache->language == POSTQUELlanguageId) {
- Datum result;
-
- Assert(funcNode);
- result = postquel_function (funcNode, argv, isNull, isDone);
- /*
- * finagle the situation where we are iterating through all results
- * in a nested dot function (whose argument function returns a set
- * of tuples) and the current function finally finishes. We need to
- * get the next argument in the set and run the function all over
- * again. This is getting unclean.
- */
- if ((*isDone) && (fcache->hasSetArg)) {
- Boolean argDone;
-
- ExecEvalFuncArgs(fcache, econtext, arguments, argv, &argDone);
-
- if (argDone) {
- fcache->setArg = (char *)NULL;
- *isDone = true;
- result = (Datum)NULL;
- }
- else
- result = postquel_function(funcNode,
- argv,
- isNull,
- isDone,
- &argDone);
- }
- return result;
- }
- else
- {
- int i;
-
- if (isDone) *isDone = true;
- for (i = 0; i < fcache->nargs; i++)
- if (fcache->nullVect[i] == true) *isNull = true;
-
- return (Datum)
- fmgr_by_ptr_array_args(fcache->func, fcache->nargs, argv, isNull);
- }
- }
-
-
- /* ----------------------------------------------------------------
- * ExecEvalOper
- * ExecEvalFunc
- *
- * Evaluate the functional result of a list of arguments by calling the
- * function manager. Note that in the case of operator expressions, the
- * optimizer had better have already replaced the operator OID with the
- * appropriate function OID or we're hosed.
- *
- * old comments
- * Presumably the function manager will not take null arguments, so we
- * check for null arguments before sending the arguments to (fmgr).
- *
- * Returns the value of the functional expression.
- * ----------------------------------------------------------------
- */
-
- /* ----------------------------------------------------------------
- * ExecEvalOper
- * ----------------------------------------------------------------
- */
- /**** xxref:
- * ExecEvalExpr
- ****/
-
- Datum
- ExecEvalOper(opClause, econtext, isNull)
- List opClause;
- ExprContext econtext;
- Boolean *isNull;
- {
- Oper op;
- List argList;
- FunctionCachePtr fcache;
- bool isDone;
-
- /* ----------------
- * an opclause is a list (op args). (I think)
- *
- * we extract the oid of the function associated with
- * the op and then pass the work onto ExecMakeFunctionResult
- * which evaluates the arguments and returns the result of
- * calling the function on the evaluated arguments.
- * ----------------
- */
- op = (Oper) get_op(opClause);
- argList = (List) get_opargs(opClause);
-
- /*
- * get the fcache from the Oper node.
- * If it is NULL, then initialize it
- */
- fcache = get_op_fcache(op);
- if (fcache == NULL) {
- set_fcache(op, get_opid(op), cdr(opClause), econtext);
- fcache = get_op_fcache(op);
- }
-
- /* -----------
- * call ExecMakeFunctionResult() with a dummy isDone that we ignore.
- * We don't have operator whose arguments are sets.
- * -----------
- */
- return
- ExecMakeFunctionResult((Node)op, argList, econtext, isNull, &isDone);
- }
-
- /* ----------------------------------------------------------------
- * ExecEvalFunc
- * ----------------------------------------------------------------
- */
-
- /**** xxref:
- * ExecEvalExpr
- ****/
- Datum
- ExecEvalFunc(funcClause, econtext, isNull, isDone)
- LispValue funcClause;
- ExprContext econtext;
- Boolean *isNull;
- Boolean *isDone;
- {
- Func func;
- List argList;
- FunctionCachePtr fcache;
-
- /* ----------------
- * an funcclause is a list (func args). (I think)
- *
- * we extract the oid of the function associated with
- * the func node and then pass the work onto ExecMakeFunctionResult
- * which evaluates the arguments and returns the result of
- * calling the function on the evaluated arguments.
- *
- * this is nearly identical to the ExecEvalOper code.
- * ----------------
- */
- func = (Func) get_function(funcClause);
- argList = (List) get_funcargs(funcClause);
-
- /*
- * get the fcache from the Func node.
- * If it is NULL, then initialize it
- */
- fcache = get_func_fcache(func);
- if (fcache == NULL) {
- set_fcache(func, get_funcid(func), CDR(funcClause), econtext);
- fcache = get_func_fcache(func);
- }
-
- return
- ExecMakeFunctionResult((Node)func, argList, econtext, isNull, isDone);
- }
-
- /* ----------------------------------------------------------------
- * ExecEvalNot
- * ExecEvalOr
- * ExecEvalAnd
- *
- * Evaluate boolean expressions. Evaluation of 'or' is
- * short-circuited when the first true (or null) value is found.
- *
- * The query planner reformulates clause expressions in the
- * qualification to conjunctive normal form. If we ever get
- * an AND to evaluate, we can be sure that it's not a top-level
- * clause in the qualification, but appears lower (as a function
- * argument, for example), or in the target list. Not that you
- * need to know this, mind you...
- * ----------------------------------------------------------------
- */
- /**** xxref:
- * ExecEvalExpr
- ****/
- Datum
- ExecEvalNot(notclause, econtext, isNull)
- List notclause;
- ExprContext econtext;
- Boolean *isNull;
- {
- Datum expr_value;
- Datum const_value;
- List clause;
- bool isDone;
-
- clause = (List) get_notclausearg(notclause);
-
- /* ----------------
- * We don't iterate over sets in the quals, so pass in an isDone
- * flag, but ignore it.
- * ----------------
- */
- expr_value = ExecEvalExpr((Node) clause, econtext, isNull, &isDone);
-
- /* ----------------
- * if the expression evaluates to null, then we just
- * cascade the null back to whoever called us.
- * ----------------
- */
- if (*isNull)
- return expr_value;
-
- /* ----------------
- * evaluation of 'not' is simple.. expr is false, then
- * return 'true' and vice versa.
- * ----------------
- */
- if (ExecCFalse(DatumGetInt32(expr_value)))
- return (Datum) true;
-
- return (Datum) false;
- }
-
- /* ----------------------------------------------------------------
- * ExecEvalOr
- * ----------------------------------------------------------------
- */
-
- /**** xxref:
- * ExecEvalExpr
- ****/
- Datum
- ExecEvalOr(orExpr, econtext, isNull)
- List orExpr;
- ExprContext econtext;
- Boolean *isNull;
- {
- List clauses;
- List clause;
- Datum const_value;
- bool isDone;
- Boolean IsNull;
-
- IsNull = false;
- clauses = (List) get_orclauseargs(orExpr);
-
- /* ----------------
- * we use three valued logic functions here...
- * we evaluate each of the clauses in turn,
- * as soon as one is true we return that
- * value. If none is true and none of the
- * clauses evaluate to NULL we return
- * the value of the last clause evaluated (which
- * should be false) with *isNull set to false else
- * if none is true and at least one clause evaluated
- * to NULL we set *isNull flag to true -
- * ----------------
- */
- foreach (clause, clauses) {
-
- /* ----------------
- * We don't iterate over sets in the quals, so pass in an isDone
- * flag, but ignore it.
- * ----------------
- */
- const_value = ExecEvalExpr((Node) CAR(clause),
- econtext,
- isNull,
- &isDone);
-
- /* ----------------
- * if the expression evaluates to null, then we
- * remember it in the local IsNull flag, if none of the
- * clauses are true then we need to set *isNull
- * to true again.
- * ----------------
- */
- if (*isNull)
- IsNull = *isNull;
-
- /* ----------------
- * if we have a true result, then we return it.
- * ----------------
- */
- if (! ExecCFalse(DatumGetInt32(const_value)))
- return const_value;
- }
-
- /* IsNull is true if at least one clause evaluated to NULL */
- *isNull = IsNull;
- return const_value;
- }
-
- /* ----------------------------------------------------------------
- * ExecEvalAnd
- * ----------------------------------------------------------------
- */
-
- /**** xxref:
- * ExecEvalExpr
- ****/
- Datum
- ExecEvalAnd(andExpr, econtext, isNull)
- List andExpr;
- ExprContext econtext;
- Boolean *isNull;
- {
- List clauses;
- List clause;
- Datum const_value;
- bool isDone;
- Boolean IsNull;
-
- IsNull = false;
-
- clauses = (List) get_andclauseargs(andExpr);
-
- /* ----------------
- * we evaluate each of the clauses in turn,
- * as soon as one is false we return that
- * value. If none are false or NULL then we return
- * the value of the last clause evaluated, which
- * should be true.
- * ----------------
- */
- foreach (clause, clauses) {
-
- /* ----------------
- * We don't iterate over sets in the quals, so pass in an isDone
- * flag, but ignore it.
- * ----------------
- */
- const_value = ExecEvalExpr((Node) CAR(clause),
- econtext,
- isNull,
- &isDone);
-
- /* ----------------
- * if the expression evaluates to null, then we
- * remember it in IsNull, if none of the clauses after
- * this evaluates to false we will have to set *isNull
- * to true again.
- * ----------------
- */
- if (*isNull)
- IsNull = *isNull;
-
- /* ----------------
- * if we have a false result, then we return it, since the
- * conjunction must be false.
- * ----------------
- */
- if (ExecCFalse(DatumGetInt32(const_value)))
- return const_value;
- }
-
- *isNull = IsNull;
- return const_value;
- }
-
- /* ----------------------------------------------------------------
- * ExecEvalExpr
- *
- * Recursively evaluate a targetlist or qualification expression.
- *
- * This routine is an inner loop routine and should be as fast
- * as possible.
- *
- * Node comparison functions were replaced by macros for speed and to plug
- * memory leaks incurred by using the planner's Lispy stuff for
- * comparisons. Order of evaluation of node comparisons IS IMPORTANT;
- * the macros do no checks. Order of evaluation:
- *
- * o an isnull check, largely to avoid coredumps since greg doubts this
- * routine is called with a null ptr anyway in proper operation, but is
- * not completely sure...
- * o ExactNodeType checks.
- * o clause checks or other checks where we look at the CAR of something.
- * ----------------------------------------------------------------
- */
- Datum
- ExecEvalExpr(expression, econtext, isNull, isDone)
- Node expression;
- ExprContext econtext;
- Boolean *isNull;
- Boolean *isDone;
- {
- Datum retDatum;
-
- *isNull = false;
-
- /*
- * Some callers don't care about is done and only want 1 result. They
- * indicate this by passing NULL
- */
- if (isDone)
- *isDone = true;
-
- /* ----------------
- * here we dispatch the work to the appropriate type
- * of function given the type of our expression.
- * ----------------
- */
- if (expression == NULL) {
- *isNull = true;
- retDatum = (Datum) true;
- } else if (ExactNodeType(expression,Var))
- retDatum = (Datum) ExecEvalVar((Var) expression, econtext, isNull);
-
- else if (ExactNodeType(expression,Const)) {
- if (get_constisnull((Const) expression))
- *isNull = true;
-
- retDatum = get_constvalue((Const) expression);
- }
-
- else if (ExactNodeType(expression,Param))
- retDatum = (Datum) ExecEvalParam((Param) expression, econtext, isNull);
-
- else if (ExactNodeType(expression,Iter))
- retDatum = (Datum) ExecEvalIter((Iter) expression,
- econtext,
- isNull,
- isDone);
-
- else if (ExactNodeType(expression,ArrayRef))
- retDatum = (Datum) ExecEvalArrayRef((ArrayRef) expression,
- econtext,
- isNull,
- isDone);
- else if (fast_is_clause(expression)) /* car is a Oper node */
- retDatum = (Datum) ExecEvalOper((List) expression, econtext, isNull);
-
- else if (fast_is_funcclause(expression)) /* car is a Func node */
- retDatum = (Datum) ExecEvalFunc((LispValue) expression,
- econtext,
- isNull,
- isDone);
-
- else if (fast_or_clause(expression))
- retDatum = (Datum) ExecEvalOr((List) expression, econtext, isNull);
-
- else if (fast_and_clause(expression))
- retDatum = (Datum) ExecEvalAnd((List) expression, econtext, isNull);
-
- else if (fast_not_clause(expression))
- retDatum = (Datum) ExecEvalNot((List) expression, econtext, isNull);
-
- else
- elog(WARN, "ExecEvalExpr: unknown expression type");
-
- return retDatum;
- }
-
- /* ----------------------------------------------------------------
- * ExecQual / ExecTargetList
- * ----------------------------------------------------------------
- */
-
- /* ----------------------------------------------------------------
- * ExecQualClause
- *
- * this is a workhorse for ExecQual. ExecQual has to deal
- * with a list of qualifications, so it passes each qualification
- * in the list to this function one at a time. ExecQualClause
- * returns true when the qualification *fails* and false if
- * the qualification succeeded (meaning we have to test the
- * rest of the qualification)
- * ----------------------------------------------------------------
- */
- /**** xxref:
- * ExecQual
- ****/
- bool
- ExecQualClause(clause, econtext)
- List clause;
- ExprContext econtext;
- {
- Datum expr_value;
- Datum const_value;
- Boolean isNull;
- Boolean isDone;
-
- /*
- * pass isDone, but ignore it. We don't iterate over multiple
- * returns in the qualifications.
- */
- expr_value = (Datum)
- ExecEvalExpr((Node) clause, econtext, &isNull, &isDone);
-
- /* ----------------
- * this is interesting behaviour here. When a clause evaluates
- * to null, then we consider this as passing the qualification.
- * it seems kind of like, if the qual is NULL, then there's no
- * qual..
- * ----------------
- */
- if (isNull)
- return true;
-
- /* ----------------
- * remember, we return true when the qualification fails..
- * ----------------
- */
- if (ExecCFalse(DatumGetInt32(expr_value)))
- return true;
-
- return false;
- }
-
- /* ----------------------------------------------------------------
- * ExecQual
- *
- * Evaluates a conjunctive boolean expression and returns t
- * iff none of the subexpressions are false (or null).
- * ----------------------------------------------------------------
- */
-
- /**** xxref:
- * ExecMergeJoin
- * ExecNestLoop
- * ExecResult
- * ExecScan
- * prs2StubTestTuple
- ****/
- bool
- ExecQual(qual, econtext)
- List qual;
- ExprContext econtext;
- {
- List clause;
- bool result;
- MemoryContext oldContext;
- GlobalMemory qualContext;
-
- /* ----------------
- * debugging stuff
- * ----------------
- */
- EV_printf("ExecQual: qual is ");
- EV_lispDisplay(qual);
- EV_printf("\n");
-
- IncrProcessed();
-
- /* ----------------
- * return true immediately if no qual
- * ----------------
- */
- if (lispNullp(qual))
- return true;
-
- /* ----------------
- * a "qual" is a list of clauses. To evaluate the
- * qual, we evaluate each of the clauses in the list.
- *
- * ExecQualClause returns true when we know the qualification
- * *failed* so we just pass each clause in qual to it until
- * we know the qual failed or there are no more clauses.
- * ----------------
- */
- result = false;
- foreach (clause, qual) {
- result = ExecQualClause( CAR(clause), econtext);
- if (result == true)
- break;
- }
-
- /* ----------------
- * if result is true, then it means a clause failed so we
- * return false. if result is false then it means no clause
- * failed so we return true.
- * ----------------
- */
- if (result == true)
- return false;
-
- return true;
- }
-
- HeapTuple
- ExecFormComplexResult(tlist, natts, tdesc, values, nulls)
- List tlist;
- int natts;
- TupleDescriptor tdesc;
- Datum *values;
- char *nulls;
- {
- TupleDescriptor flatTd;
- Datum *flatValues;
- char *flatNulls;
- int flatInd;
- int flatNatts;
- int complexInd;
- TupleTableSlot *foundslots;
- TupleTableSlot *slotbase;
- TupleTableSlot slot;
- HeapTuple resultTup;
- List tlistP;
-
- slotbase = (TupleTableSlot *)palloc ((natts+1)*sizeof(TupleTableSlot));
- bzero(slotbase, ((natts+1)*sizeof(TupleTableSlot)));
- foundslots = slotbase;
-
- /*
- * we make two passes through the target list - one to figure
- * out just how many attributes we are dealing with and another
- * to get all the aforementioned attributes.
- */
- flatNatts = 0;
- complexInd = 0;
- foreach(tlistP, tlist)
- {
- List tle = CAR(tlistP);
- /*
- * Since we are dealing with a complex result we know that we
- * are not at the top of the plan tree and therefore we know
- * that we have only resdoms and expressions (i.e. no Fjoins)
- */
- if ( get_rescomplex((Resdom)tl_resdom(tle)) )
- {
- HeapTuple tuple;
-
- slot = (TupleTableSlot)values[complexInd];
- tuple = (HeapTuple)ExecFetchTuple(slot);
- flatNatts += tuple->t_natts;
- }
- else
- flatNatts++;
-
- complexInd++;
- }
- flatTd = CreateTemplateTupleDesc(flatNatts);
- flatValues = (Datum *)palloc(flatNatts*sizeof(Datum));
- flatNulls = (char *)palloc(flatNatts*sizeof(char));
-
- complexInd = flatInd = 0;
- foreach(tlistP, tlist)
- {
-
- List tle = CAR(tlistP);
- /*
- * Since we are dealing with a complex result we know that we
- * are not at the top of the plan tree and therefore we know
- * that we have only resdoms and expressions (i.e. no Fjoins)
- */
- if ( get_rescomplex((Resdom)tl_resdom(tle)) )
- {
- int i;
- HeapTuple tuple;
- TupleDescriptor subDesc;
- Resdom res = (Resdom)tl_resdom(tle);
-
- slot = (TupleTableSlot)values[complexInd];
- tuple = (HeapTuple)ExecFetchTuple(slot);
- subDesc = ExecSlotDescriptor(slot);
- heap_deformtuple(tuple,
- subDesc,
- &flatValues[flatInd],
- &flatNulls[flatInd]);
- *foundslots++ = slot;
- for (i = 0; i < tuple->t_natts; i++, flatInd++)
- {
- flatTd->data[flatInd] = (AttributeTupleForm)
- palloc(sizeof(AttributeTupleFormD));
- bcopy(subDesc->data[i],
- flatTd->data[flatInd],
- sizeof(AttributeTupleFormD));
- }
- }
- else
- {
- flatTd->data[flatInd] = (AttributeTupleForm)
- palloc(sizeof(AttributeTupleFormD));
-
- bcopy(tdesc->data[complexInd],
- flatTd->data[flatInd],
- sizeof(AttributeTupleFormD));
-
- flatValues[flatInd] = values[complexInd];
- flatInd++;
- }
- complexInd++;
- }
-
- resultTup = (HeapTuple)heap_formtuple(flatNatts,
- flatTd,
- flatValues,
- flatNulls);
- /*
- * Be tidy and free up our constructed tuple descriptor and all slots
- * that we found.
- */
- for (flatInd = 0; flatInd < flatNatts; flatInd++)
- pfree(flatTd->data[flatInd]);
- pfree (flatTd);
- foundslots = slotbase;
- while ((slot = *foundslots) != (TupleTableSlot)NULL)
- {
- pfree(ExecFetchTuple(slot));
- pfree(slot);
- foundslots++;
- }
- pfree (slotbase);
- return resultTup;
- }
-
- int
- ExecTargetListLength(targetlist)
- {
- int len;
- List tl;
-
- len = 0;
- foreach (tl, targetlist) {
- List curTle = CAR(tl);
-
- if (tl_is_resdom(curTle))
- len++;
- else
- len += get_fj_nNodes((Fjoin)tl_node(curTle));
- }
- return len;
- }
- /* ----------------------------------------------------------------
- * ExecTargetList
- *
- * Evaluates a targetlist with respect to the current
- * expression context and return a tuple.
- * ----------------------------------------------------------------
- */
-
- /**** xxref:
- * ExecMergeJoin
- * ExecNestLoop
- * ExecResult
- * ExecScan
- ****/
- HeapTuple
- ExecTargetList(targetlist, nodomains, targettype, values, econtext, isDone)
- List targetlist;
- int nodomains;
- TupleDescriptor targettype;
- Pointer values;
- ExprContext econtext;
- bool *isDone;
- {
- char nulls_array[64];
- bool fjNullArray[64];
- bool *fjIsNull;
- char *np, *null_head;
- List tl;
- List tle;
- int len;
- Expr expr;
- Resdom resdom;
- AttributeNumber resind;
- Const expr_value;
- Datum constvalue;
- HeapTuple newTuple;
- MemoryContext oldContext;
- GlobalMemory tlContext;
- Boolean complexResult;
- Boolean isNull;
-
- /* ----------------
- * debugging stuff
- * ----------------
- */
- EV_printf("ExecTargetList: tl is ");
- EV_lispDisplay(targetlist);
- EV_printf("\n");
-
- /* ----------------
- * Return a dummy tuple if the targetlist is empty .
- * the dummy tuple is necessary to differentiate
- * between passing and failing the qualification.
- * ----------------
- */
- if (lispNullp(targetlist)) {
- /* ----------------
- * I now think that the only time this makes
- * any sence is when we run a delete query. Then
- * we need to return something other than nil
- * so we know to delete the tuple associated
- * with the saved tupleid.. see what ExecutePlan
- * does with the returned tuple.. -cim 9/21/89
- *
- * It could also happen in queries like:
- * retrieve (foo.all) where bar.a = 3
- *
- * is this a new phenomenon? it might cause bogus behavior
- * if we try to free this tuple later!! I put a hook in
- * ExecProject to watch out for this case -mer 24 Aug 1992
- * ----------------
- */
- CXT1_printf("ExecTargetList: context is %d\n", CurrentMemoryContext);
- *isDone = true;
- return (HeapTuple) true;
- }
-
- /* ----------------
- * allocate an array of char's to hold the "null" information
- * only if we have a really large targetlist. otherwise we use
- * the stack.
- * ----------------
- */
- len = ExecTargetListLength(targetlist);
-
- if (len > 64) {
- np = (char *) palloc(len+1);
- fjIsNull = (bool *) palloc(len+1);
- } else {
- np = &nulls_array[0];
- fjIsNull = &fjNullArray[0];
- }
-
- null_head = np;
- bzero(np, len+1);
-
- /* ----------------
- * evaluate all the expressions in the target list
- * ----------------
- */
- EV_printf("ExecTargetList: setting target list values\n");
-
- *isDone = true;
- complexResult = false;
- foreach (tl, targetlist) {
- /* ----------------
- * remember, a target list is a list of lists:
- *
- * ((<resdom | fjoin> expr) (<resdom | fjoin> expr) ...)
- *
- * tl is a pointer to successive cdr's of the targetlist
- * tle is a pointer to the target list entry in tl
- * ----------------
- */
- tle = CAR(tl);
- if (lispNullp(tle))
- break;
-
- if (tl_is_resdom(tle)) {
- expr = (Expr) tl_expr(tle);
- resdom = (Resdom) tl_resdom(tle);
- resind = get_resno(resdom) - 1;
- constvalue = (Datum) ExecEvalExpr((Node)expr,
- econtext,
- &isNull,
- isDone);
-
- if ((ExactNodeType(expr,Iter)) && (*isDone))
- return (HeapTuple)NULL;
-
- if (get_rescomplex(resdom))
- complexResult = true;
-
- ExecSetTLValues(resind, values, constvalue);
-
- if (!isNull)
- null_head[resind] = ' ';
- else
- null_head[resind] = 'n';
- }
- else {
- int curNode;
- Resdom fjRes;
- List fjTlist = CDR(tle);
- Fjoin fjNode = (Fjoin)tl_node(tle);
- int nNodes = get_fj_nNodes(fjNode);
- DatumPtr results = get_fj_results(fjNode);
-
- ExecEvalFjoin(tle, econtext, fjIsNull, isDone);
- if (*isDone)
- return (HeapTuple)NULL;
-
- /*
- * get the result from the inner node
- */
- fjRes = (Resdom)CAR(get_fj_innerNode(fjNode));
- resind = get_resno(fjRes) - 1;
- if (fjIsNull[0])
- null_head[resind] = 'n';
- else
- {
- null_head[resind] = ' ';
- ExecSetTLValues(resind, values, results[0]);
- }
-
- /*
- * Get results from all of the outer nodes
- */
- for (curNode = 1;
- curNode < nNodes;
- curNode++, fjTlist = CDR(fjTlist))
- {
- fjRes = (Resdom)CAAR(fjTlist);
-
- resind = get_resno(fjRes) - 1;
- if (fjIsNull[curNode]) {
- null_head[resind] = 'n';
- }
- else
- {
- null_head[resind] = ' ';
- ExecSetTLValues(resind, values, results[curNode]);
- }
- }
- }
- }
-
- /* ----------------
- * form the new result tuple (in the "normal" context)
- * ----------------
- */
- if (complexResult)
- newTuple = (HeapTuple) ExecFormComplexResult(targetlist,
- nodomains,
- targettype,
- values,
- null_head);
- else
- newTuple = (HeapTuple)
- heap_formtuple(nodomains, targettype, values, null_head);
-
- /* ----------------
- * free the nulls array if we allocated one..
- * ----------------
- */
- if (len > 64) pfree(null_head);
-
- return
- newTuple;
- }
-
- /* ----------------------------------------------------------------
- * ExecProject
- *
- * projects a tuple based in projection info and stores
- * it in the specified tuple table slot.
- *
- * Note: someday soon the executor can be extended to eliminate
- * redundant projections by storing pointers to datums
- * in the tuple table and then passing these around when
- * possible. this should make things much quicker.
- * -cim 6/3/91
- * ----------------------------------------------------------------
- */
- TupleTableSlot
- ExecProject(projInfo, isDone)
- ProjectionInfo projInfo;
- bool *isDone;
- {
- TupleTableSlot slot;
- List targetlist;
- List tle;
- int len;
- TupleDescriptor tupType;
- Pointer tupValue;
- ExprContext econtext;
- HeapTuple newTuple;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- if (projInfo == NULL)
- return (TupleTableSlot) NULL;
-
- /* ----------------
- * get the projection info we want
- * ----------------
- */
- slot = get_pi_slot(projInfo);
- targetlist = get_pi_targetlist(projInfo);
- len = get_pi_len(projInfo);
- tupType = ExecSlotDescriptor((Pointer) slot);
-
- tupValue = get_pi_tupValue(projInfo);
- econtext = get_pi_exprContext(projInfo);
-
- /* ----------------
- * form a new (result) tuple
- * ----------------
- */
- newTuple = ExecTargetList(targetlist,
- len,
- tupType,
- tupValue,
- econtext,
- isDone);
-
- /* ----------------
- * store the tuple in the projection slot and return the slot.
- *
- * If there's no projection target list we don't want to pfree
- * the bogus tuple that ExecTargetList passes back to us.
- * -mer 24 Aug 1992
- * ----------------
- */
- return (TupleTableSlot)
- ExecStoreTuple((Pointer) newTuple, /* tuple to store */
- (Pointer) slot, /* slot to store in */
- InvalidBuffer, /* tuple has no buffer */
- /* ok to pfree this tuple */
- get_pi_targetlist(projInfo) ? true : false);
- }
-