diff options
Diffstat (limited to 'src/backend/executor/execQual.c')
-rw-r--r-- | src/backend/executor/execQual.c | 1929 |
1 files changed, 0 insertions, 1929 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c deleted file mode 100644 index 0b2f24d917a..00000000000 --- a/src/backend/executor/execQual.c +++ /dev/null @@ -1,1929 +0,0 @@ -/*------------------------------------------------------------------------- - * - * execQual.c - * Routines to evaluate qualification and targetlist expressions - * - * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.94 2002/06/20 20:29:27 momjian Exp $ - * - *------------------------------------------------------------------------- - */ -/* - * INTERFACE ROUTINES - * ExecEvalExpr - evaluate an expression and return a datum - * ExecEvalExprSwitchContext - same, but switch into eval memory context - * ExecQual - return true/false if qualification is satisfied - * ExecProject - 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. - * - * ExecProject() 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 - * - */ - -#include "postgres.h" - -#include "access/heapam.h" -#include "executor/execdebug.h" -#include "executor/functions.h" -#include "executor/nodeSubplan.h" -#include "utils/array.h" -#include "utils/builtins.h" -#include "utils/fcache.h" - - -/* static function decls */ -static Datum ExecEvalAggref(Aggref *aggref, ExprContext *econtext, - bool *isNull); -static Datum ExecEvalArrayRef(ArrayRef *arrayRef, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); -static Datum ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull); -static Datum ExecEvalOper(Expr *opClause, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); -static Datum ExecEvalFunc(Expr *funcClause, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); -static ExprDoneCond ExecEvalFuncArgs(FunctionCallInfo fcinfo, - List *argList, ExprContext *econtext); -static Datum ExecEvalNot(Expr *notclause, ExprContext *econtext, bool *isNull); -static Datum ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull); -static Datum ExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull); -static Datum ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); -static Datum ExecEvalNullTest(NullTest *ntest, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); -static Datum ExecEvalBooleanTest(BooleanTest *btest, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); - - -/*---------- - * ExecEvalArrayRef - * - * This function takes an ArrayRef and returns the extracted Datum - * if it's a simple reference, or the modified array value if it's - * an array assignment (i.e., array element or slice insertion). - * - * NOTE: if we get a NULL result from a subexpression, we return NULL when - * it's an array reference, or the unmodified source array when it's an - * array assignment. This may seem peculiar, but if we return NULL (as was - * done in versions up through 7.0) then an assignment like - * UPDATE table SET arrayfield[4] = NULL - * will result in setting the whole array to NULL, which is certainly not - * very desirable. By returning the source array we make the assignment - * into a no-op, instead. (Eventually we need to redesign arrays so that - * individual elements can be NULL, but for now, let's try to protect users - * from shooting themselves in the foot.) - * - * NOTE: we deliberately refrain from applying DatumGetArrayTypeP() here, - * even though that might seem natural, because this code needs to support - * both varlena arrays and fixed-length array types. DatumGetArrayTypeP() - * only works for the varlena kind. The routines we call in arrayfuncs.c - * have to know the difference (that's what they need refattrlength for). - *---------- - */ -static Datum -ExecEvalArrayRef(ArrayRef *arrayRef, - ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) -{ - ArrayType *array_source; - ArrayType *resultArray; - bool isAssignment = (arrayRef->refassgnexpr != NULL); - List *elt; - int i = 0, - j = 0; - IntArray upper, - lower; - int *lIndex; - - if (arrayRef->refexpr != NULL) - { - array_source = (ArrayType *) - DatumGetPointer(ExecEvalExpr(arrayRef->refexpr, - econtext, - isNull, - isDone)); - - /* - * If refexpr yields NULL, result is always NULL, for now anyway. - * (This means you cannot assign to an element or slice of an - * array that's NULL; it'll just stay NULL.) - */ - if (*isNull) - return (Datum) NULL; - } - else - { - /* - * Empty refexpr indicates we are doing an INSERT into an array - * column. For now, we just take the refassgnexpr (which the - * parser will have ensured is an array value) and return it - * as-is, ignoring any subscripts that may have been supplied in - * the INSERT column list. This is a kluge, but it's not real - * clear what the semantics ought to be... - */ - array_source = NULL; - } - - foreach(elt, arrayRef->refupperindexpr) - { - if (i >= MAXDIM) - elog(ERROR, "ExecEvalArrayRef: can only handle %d dimensions", - MAXDIM); - - upper.indx[i++] = DatumGetInt32(ExecEvalExpr((Node *) lfirst(elt), - econtext, - isNull, - NULL)); - /* If any index expr yields NULL, result is NULL or source array */ - if (*isNull) - { - if (!isAssignment || array_source == NULL) - return (Datum) NULL; - *isNull = false; - return PointerGetDatum(array_source); - } - } - - if (arrayRef->reflowerindexpr != NIL) - { - foreach(elt, arrayRef->reflowerindexpr) - { - if (j >= MAXDIM) - elog(ERROR, "ExecEvalArrayRef: can only handle %d dimensions", - MAXDIM); - - lower.indx[j++] = DatumGetInt32(ExecEvalExpr((Node *) lfirst(elt), - econtext, - isNull, - NULL)); - - /* - * If any index expr yields NULL, result is NULL or source - * array - */ - if (*isNull) - { - if (!isAssignment || array_source == NULL) - return (Datum) NULL; - *isNull = false; - return PointerGetDatum(array_source); - } - } - if (i != j) - elog(ERROR, - "ExecEvalArrayRef: upper and lower indices mismatch"); - lIndex = lower.indx; - } - else - lIndex = NULL; - - if (isAssignment) - { - Datum sourceData = ExecEvalExpr(arrayRef->refassgnexpr, - econtext, - isNull, - NULL); - - /* - * For now, can't cope with inserting NULL into an array, so make - * it a no-op per discussion above... - */ - if (*isNull) - { - if (array_source == NULL) - return (Datum) NULL; - *isNull = false; - return PointerGetDatum(array_source); - } - - if (array_source == NULL) - return sourceData; /* XXX do something else? */ - - if (lIndex == NULL) - resultArray = array_set(array_source, i, - upper.indx, - sourceData, - arrayRef->refelembyval, - arrayRef->refelemlength, - arrayRef->refattrlength, - isNull); - else - resultArray = array_set_slice(array_source, i, - upper.indx, lower.indx, - (ArrayType *) DatumGetPointer(sourceData), - arrayRef->refelembyval, - arrayRef->refelemlength, - arrayRef->refattrlength, - isNull); - return PointerGetDatum(resultArray); - } - - if (lIndex == NULL) - return array_ref(array_source, i, - upper.indx, - arrayRef->refelembyval, - arrayRef->refelemlength, - arrayRef->refattrlength, - isNull); - else - { - resultArray = array_get_slice(array_source, i, - upper.indx, lower.indx, - arrayRef->refelembyval, - arrayRef->refelemlength, - arrayRef->refattrlength, - isNull); - return PointerGetDatum(resultArray); - } -} - - -/* ---------------------------------------------------------------- - * ExecEvalAggref - * - * Returns a Datum whose value is the value of the precomputed - * aggregate found in the given expression context. - * ---------------------------------------------------------------- - */ -static Datum -ExecEvalAggref(Aggref *aggref, ExprContext *econtext, bool *isNull) -{ - if (econtext->ecxt_aggvalues == NULL) /* safety check */ - elog(ERROR, "ExecEvalAggref: no aggregates in this expression context"); - - *isNull = econtext->ecxt_aggnulls[aggref->aggno]; - return econtext->ecxt_aggvalues[aggref->aggno]; -} - -/* ---------------------------------------------------------------- - * ExecEvalVar - * - * Returns a Datum whose value is the value of a range - * variable with respect to given expression context. - * - * - * As an entry condition, we expect that the datatype the - * plan expects to get (as told by our "variable" argument) is in - * fact the datatype of the attribute the plan says to fetch (as - * seen in the current context, identified by our "econtext" - * argument). - * - * If we fetch a Type A attribute and Caller treats it as if it - * were Type B, there will be undefined results (e.g. crash). - * One way these might mismatch now is that we're accessing a - * catalog class and the type information in the pg_attribute - * class does not match the hardcoded pg_attribute information - * (in pg_attribute.h) for the class in question. - * - * We have an Assert to make sure this entry condition is met. - * - * ---------------------------------------------------------------- */ -static Datum -ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull) -{ - Datum result; - TupleTableSlot *slot; - AttrNumber attnum; - HeapTuple heapTuple; - TupleDesc tuple_type; - - /* - * get the slot we want - */ - switch (variable->varno) - { - case INNER: /* get the tuple from the inner node */ - slot = econtext->ecxt_innertuple; - break; - - case OUTER: /* get the tuple from the outer node */ - slot = econtext->ecxt_outertuple; - break; - - default: /* get the tuple from the relation being - * scanned */ - slot = econtext->ecxt_scantuple; - break; - } - - /* - * extract tuple information from the slot - */ - heapTuple = slot->val; - tuple_type = slot->ttc_tupleDescriptor; - - attnum = variable->varattno; - - /* (See prolog for explanation of this Assert) */ - Assert(attnum <= 0 || - (attnum - 1 <= tuple_type->natts - 1 && - tuple_type->attrs[attnum - 1] != NULL && - variable->vartype == tuple_type->attrs[attnum - 1]->atttypid)); - - /* - * 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. - * - * XXX this is a horrid crock: since the pointer to the slot might live - * longer than the current evaluation context, we are forced to copy - * the tuple and slot into a long-lived context --- we use - * TransactionCommandContext which should be safe enough. This - * represents a serious memory leak if many such tuples are processed - * in one command, however. We ought to redesign the representation - * of whole-tuple datums so that this is not necessary. - * - * We assume it's OK to point to the existing tupleDescriptor, rather - * than copy that too. - */ - if (attnum == InvalidAttrNumber) - { - MemoryContext oldContext; - TupleTableSlot *tempSlot; - HeapTuple tup; - - oldContext = MemoryContextSwitchTo(TransactionCommandContext); - tempSlot = MakeTupleTableSlot(); - tup = heap_copytuple(heapTuple); - ExecStoreTuple(tup, tempSlot, InvalidBuffer, true); - ExecSetSlotDescriptor(tempSlot, tuple_type, false); - MemoryContextSwitchTo(oldContext); - return PointerGetDatum(tempSlot); - } - - result = heap_getattr(heapTuple, /* tuple containing attribute */ - attnum, /* attribute number of desired - * attribute */ - tuple_type, /* tuple descriptor of tuple */ - isNull); /* return: is attribute null? */ - - 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. - * ---------------------------------------------------------------- - */ -Datum -ExecEvalParam(Param *expression, ExprContext *econtext, bool *isNull) -{ - char *thisParameterName; - int thisParameterKind = expression->paramkind; - AttrNumber thisParameterId = expression->paramid; - int matchFound; - ParamListInfo paramList; - - if (thisParameterKind == PARAM_EXEC) - { - ParamExecData *prm; - - prm = &(econtext->ecxt_param_exec_vals[thisParameterId]); - if (prm->execPlan != NULL) - { - ExecSetParamPlan(prm->execPlan, econtext); - /* ExecSetParamPlan should have processed this param... */ - Assert(prm->execPlan == NULL); - } - *isNull = prm->isnull; - return prm->value; - } - - thisParameterName = expression->paramname; - paramList = econtext->ecxt_param_list_info; - - *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 && - strcmp(paramList->name, thisParameterName) == 0) - 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 (strcmp(paramList->name, thisParameterName) != 0) - { - elog(ERROR, - "ExecEvalParam: new/old params with same id & diff names"); - } - } - break; - default: - - /* - * oops! this is not supposed to happen! - */ - elog(ERROR, "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(ERROR, "ExecEvalParam: Unknown value for parameter %s", - thisParameterName); - } - - /* - * return the value. - */ - *isNull = paramList->isnull; - 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(). - */ -Datum -GetAttributeByNum(TupleTableSlot *slot, - AttrNumber attrno, - bool *isNull) -{ - Datum retval; - - if (!AttributeNumberIsValid(attrno)) - elog(ERROR, "GetAttributeByNum: Invalid attribute number"); - - if (!AttrNumberIsForUserDefinedAttr(attrno)) - elog(ERROR, "GetAttributeByNum: cannot access system attributes here"); - - if (isNull == (bool *) NULL) - elog(ERROR, "GetAttributeByNum: a NULL isNull flag was passed"); - - if (TupIsNull(slot)) - { - *isNull = true; - return (Datum) 0; - } - - retval = heap_getattr(slot->val, - attrno, - slot->ttc_tupleDescriptor, - isNull); - if (*isNull) - return (Datum) 0; - - return retval; -} - -Datum -GetAttributeByName(TupleTableSlot *slot, char *attname, bool *isNull) -{ - AttrNumber attrno; - TupleDesc tupdesc; - Datum retval; - int natts; - int i; - - if (attname == NULL) - elog(ERROR, "GetAttributeByName: Invalid attribute name"); - - if (isNull == (bool *) NULL) - elog(ERROR, "GetAttributeByName: a NULL isNull flag was passed"); - - if (TupIsNull(slot)) - { - *isNull = true; - return (Datum) 0; - } - - tupdesc = slot->ttc_tupleDescriptor; - natts = slot->val->t_data->t_natts; - - attrno = InvalidAttrNumber; - for (i = 0; i < tupdesc->natts; i++) - { - if (namestrcmp(&(tupdesc->attrs[i]->attname), attname) == 0) - { - attrno = tupdesc->attrs[i]->attnum; - break; - } - } - - if (attrno == InvalidAttrNumber) - elog(ERROR, "GetAttributeByName: attribute %s not found", attname); - - retval = heap_getattr(slot->val, - attrno, - tupdesc, - isNull); - if (*isNull) - return (Datum) 0; - - return retval; -} - -/* - * Evaluate arguments for a function. - */ -static ExprDoneCond -ExecEvalFuncArgs(FunctionCallInfo fcinfo, - List *argList, - ExprContext *econtext) -{ - ExprDoneCond argIsDone; - int i; - List *arg; - - argIsDone = ExprSingleResult; /* default assumption */ - - i = 0; - foreach(arg, argList) - { - ExprDoneCond thisArgIsDone; - - fcinfo->arg[i] = ExecEvalExpr((Node *) lfirst(arg), - econtext, - &fcinfo->argnull[i], - &thisArgIsDone); - - if (thisArgIsDone != ExprSingleResult) - { - /* - * We allow only one argument to have a set value; we'd need - * much more complexity to keep track of multiple set - * arguments (cf. ExecTargetList) and it doesn't seem worth - * it. - */ - if (argIsDone != ExprSingleResult) - elog(ERROR, "Functions and operators can take only one set argument"); - argIsDone = thisArgIsDone; - } - i++; - } - - fcinfo->nargs = i; - - return argIsDone; -} - -/* - * ExecMakeFunctionResult - * - * Evaluate the arguments to a function and then the function itself. - * - * NOTE: econtext is used only for evaluating the argument expressions; - * it is not passed to the function itself. - */ -Datum -ExecMakeFunctionResult(FunctionCachePtr fcache, - List *arguments, - ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) -{ - Datum result; - FunctionCallInfoData fcinfo; - ReturnSetInfo rsinfo; /* for functions returning sets */ - ExprDoneCond argDone; - bool hasSetArg; - int i; - - /* - * arguments is a list of expressions to evaluate before passing to - * the function manager. We skip the evaluation if it was already - * done in the previous call (ie, we are continuing the evaluation of - * a set-valued function). Otherwise, collect the current argument - * values into fcinfo. - */ - if (!fcache->setArgsValid) - { - /* Need to prep callinfo structure */ - MemSet(&fcinfo, 0, sizeof(fcinfo)); - fcinfo.flinfo = &(fcache->func); - argDone = ExecEvalFuncArgs(&fcinfo, arguments, econtext); - if (argDone == ExprEndResult) - { - /* input is an empty set, so return an empty set. */ - *isNull = true; - if (isDone) - *isDone = ExprEndResult; - else - elog(ERROR, "Set-valued function called in context that cannot accept a set"); - return (Datum) 0; - } - hasSetArg = (argDone != ExprSingleResult); - } - else - { - /* Copy callinfo from previous evaluation */ - memcpy(&fcinfo, &fcache->setArgs, sizeof(fcinfo)); - hasSetArg = fcache->setHasSetArg; - /* Reset flag (we may set it again below) */ - fcache->setArgsValid = false; - } - - /* - * If function returns set, prepare a resultinfo node for - * communication - */ - if (fcache->func.fn_retset) - { - fcinfo.resultinfo = (Node *) &rsinfo; - rsinfo.type = T_ReturnSetInfo; - rsinfo.econtext = econtext; - } - - /* - * now return the value gotten by calling the function manager, - * passing the function the evaluated parameter values. - */ - if (fcache->func.fn_retset || hasSetArg) - { - /* - * We need to return a set result. Complain if caller not ready - * to accept one. - */ - if (isDone == NULL) - elog(ERROR, "Set-valued function called in context that cannot accept a set"); - - /* - * This loop handles the situation where we have both a set - * argument and a set-valued function. Once we have exhausted the - * function's value(s) for a particular argument value, we have to - * get the next argument value and start the function over again. - * We might have to do it more than once, if the function produces - * an empty result set for a particular input value. - */ - for (;;) - { - /* - * If function is strict, and there are any NULL arguments, - * skip calling the function (at least for this set of args). - */ - bool callit = true; - - if (fcache->func.fn_strict) - { - for (i = 0; i < fcinfo.nargs; i++) - { - if (fcinfo.argnull[i]) - { - callit = false; - break; - } - } - } - - if (callit) - { - fcinfo.isnull = false; - rsinfo.isDone = ExprSingleResult; - result = FunctionCallInvoke(&fcinfo); - *isNull = fcinfo.isnull; - *isDone = rsinfo.isDone; - } - else - { - result = (Datum) 0; - *isNull = true; - *isDone = ExprEndResult; - } - - if (*isDone != ExprEndResult) - { - /* - * Got a result from current argument. If function itself - * returns set, save the current argument values to re-use - * on the next call. - */ - if (fcache->func.fn_retset) - { - memcpy(&fcache->setArgs, &fcinfo, sizeof(fcinfo)); - fcache->setHasSetArg = hasSetArg; - fcache->setArgsValid = true; - } - - /* - * Make sure we say we are returning a set, even if the - * function itself doesn't return sets. - */ - *isDone = ExprMultipleResult; - break; - } - - /* Else, done with this argument */ - if (!hasSetArg) - break; /* input not a set, so done */ - - /* Re-eval args to get the next element of the input set */ - argDone = ExecEvalFuncArgs(&fcinfo, arguments, econtext); - - if (argDone != ExprMultipleResult) - { - /* End of argument set, so we're done. */ - *isNull = true; - *isDone = ExprEndResult; - result = (Datum) 0; - break; - } - - /* - * If we reach here, loop around to run the function on the - * new argument. - */ - } - } - else - { - /* - * Non-set case: much easier. - * - * If function is strict, and there are any NULL arguments, skip - * calling the function and return NULL. - */ - if (fcache->func.fn_strict) - { - for (i = 0; i < fcinfo.nargs; i++) - { - if (fcinfo.argnull[i]) - { - *isNull = true; - return (Datum) 0; - } - } - } - fcinfo.isnull = false; - result = FunctionCallInvoke(&fcinfo); - *isNull = fcinfo.isnull; - } - - return result; -} - - -/* ---------------------------------------------------------------- - * ExecEvalOper - * ExecEvalFunc - * - * Evaluate the functional result of a list of arguments by calling the - * function manager. - * ---------------------------------------------------------------- - */ - -/* ---------------------------------------------------------------- - * ExecEvalOper - * ---------------------------------------------------------------- - */ -static Datum -ExecEvalOper(Expr *opClause, - ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) -{ - Oper *op; - List *argList; - FunctionCachePtr fcache; - - /* - * 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 *) opClause->oper; - argList = opClause->args; - - /* - * get the fcache from the Oper node. If it is NULL, then initialize - * it - */ - fcache = op->op_fcache; - if (fcache == NULL) - { - fcache = init_fcache(op->opid, length(argList), - econtext->ecxt_per_query_memory); - op->op_fcache = fcache; - } - - return ExecMakeFunctionResult(fcache, argList, econtext, - isNull, isDone); -} - -/* ---------------------------------------------------------------- - * ExecEvalFunc - * ---------------------------------------------------------------- - */ - -static Datum -ExecEvalFunc(Expr *funcClause, - ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) -{ - Func *func; - List *argList; - FunctionCachePtr fcache; - - /* - * 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 *) funcClause->oper; - argList = funcClause->args; - - /* - * get the fcache from the Func node. If it is NULL, then initialize - * it - */ - fcache = func->func_fcache; - if (fcache == NULL) - { - fcache = init_fcache(func->funcid, length(argList), - econtext->ecxt_per_query_memory); - func->func_fcache = fcache; - } - - return ExecMakeFunctionResult(fcache, 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... - * ---------------------------------------------------------------- - */ -static Datum -ExecEvalNot(Expr *notclause, ExprContext *econtext, bool *isNull) -{ - Node *clause; - Datum expr_value; - - clause = lfirst(notclause->args); - - expr_value = ExecEvalExpr(clause, econtext, isNull, NULL); - - /* - * 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. - */ - return BoolGetDatum(!DatumGetBool(expr_value)); -} - -/* ---------------------------------------------------------------- - * ExecEvalOr - * ---------------------------------------------------------------- - */ -static Datum -ExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull) -{ - List *clauses; - List *clause; - bool AnyNull; - Datum clause_value; - - clauses = orExpr->args; - AnyNull = false; - - /* - * If any of the clauses is TRUE, the OR result is TRUE regardless of - * the states of the rest of the clauses, so we can stop evaluating - * and return TRUE immediately. If none are TRUE and one or more is - * NULL, we return NULL; otherwise we return FALSE. This makes sense - * when you interpret NULL as "don't know": if we have a TRUE then the - * OR is TRUE even if we aren't sure about some of the other inputs. - * If all the known inputs are FALSE, but we have one or more "don't - * knows", then we have to report that we "don't know" what the OR's - * result should be --- perhaps one of the "don't knows" would have - * been TRUE if we'd known its value. Only when all the inputs are - * known to be FALSE can we state confidently that the OR's result is - * FALSE. - */ - foreach(clause, clauses) - { - clause_value = ExecEvalExpr((Node *) lfirst(clause), - econtext, isNull, NULL); - - /* - * if we have a non-null true result, then return it. - */ - if (*isNull) - AnyNull = true; /* remember we got a null */ - else if (DatumGetBool(clause_value)) - return clause_value; - } - - /* AnyNull is true if at least one clause evaluated to NULL */ - *isNull = AnyNull; - return BoolGetDatum(false); -} - -/* ---------------------------------------------------------------- - * ExecEvalAnd - * ---------------------------------------------------------------- - */ -static Datum -ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull) -{ - List *clauses; - List *clause; - bool AnyNull; - Datum clause_value; - - clauses = andExpr->args; - AnyNull = false; - - /* - * If any of the clauses is FALSE, the AND result is FALSE regardless - * of the states of the rest of the clauses, so we can stop evaluating - * and return FALSE immediately. If none are FALSE and one or more is - * NULL, we return NULL; otherwise we return TRUE. This makes sense - * when you interpret NULL as "don't know", using the same sort of - * reasoning as for OR, above. - */ - foreach(clause, clauses) - { - clause_value = ExecEvalExpr((Node *) lfirst(clause), - econtext, isNull, NULL); - - /* - * if we have a non-null false result, then return it. - */ - if (*isNull) - AnyNull = true; /* remember we got a null */ - else if (!DatumGetBool(clause_value)) - return clause_value; - } - - /* AnyNull is true if at least one clause evaluated to NULL */ - *isNull = AnyNull; - return BoolGetDatum(!AnyNull); -} - -/* ---------------------------------------------------------------- - * ExecEvalCase - * - * Evaluate a CASE clause. Will have boolean expressions - * inside the WHEN clauses, and will have expressions - * for results. - * - thomas 1998-11-09 - * ---------------------------------------------------------------- - */ -static Datum -ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone) -{ - List *clauses; - List *clause; - Datum clause_value; - - clauses = caseExpr->args; - - /* - * we evaluate each of the WHEN clauses in turn, as soon as one is - * true we return the corresponding result. If none are true then we - * return the value of the default clause, or NULL if there is none. - */ - foreach(clause, clauses) - { - CaseWhen *wclause = lfirst(clause); - - clause_value = ExecEvalExpr(wclause->expr, - econtext, - isNull, - NULL); - - /* - * if we have a true test, then we return the result, since the - * case statement is satisfied. A NULL result from the test is - * not considered true. - */ - if (DatumGetBool(clause_value) && !*isNull) - { - return ExecEvalExpr(wclause->result, - econtext, - isNull, - isDone); - } - } - - if (caseExpr->defresult) - { - return ExecEvalExpr(caseExpr->defresult, - econtext, - isNull, - isDone); - } - - *isNull = true; - return (Datum) 0; -} - -/* ---------------------------------------------------------------- - * ExecEvalNullTest - * - * Evaluate a NullTest node. - * ---------------------------------------------------------------- - */ -static Datum -ExecEvalNullTest(NullTest *ntest, - ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) -{ - Datum result; - - result = ExecEvalExpr(ntest->arg, econtext, isNull, isDone); - switch (ntest->nulltesttype) - { - case IS_NULL: - if (*isNull) - { - *isNull = false; - return BoolGetDatum(true); - } - else - return BoolGetDatum(false); - case IS_NOT_NULL: - if (*isNull) - { - *isNull = false; - return BoolGetDatum(false); - } - else - return BoolGetDatum(true); - default: - elog(ERROR, "ExecEvalNullTest: unexpected nulltesttype %d", - (int) ntest->nulltesttype); - return (Datum) 0; /* keep compiler quiet */ - } -} - -/* ---------------------------------------------------------------- - * ExecEvalBooleanTest - * - * Evaluate a BooleanTest node. - * ---------------------------------------------------------------- - */ -static Datum -ExecEvalBooleanTest(BooleanTest *btest, - ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) -{ - Datum result; - - result = ExecEvalExpr(btest->arg, econtext, isNull, isDone); - switch (btest->booltesttype) - { - case IS_TRUE: - if (*isNull) - { - *isNull = false; - return BoolGetDatum(false); - } - else if (DatumGetBool(result)) - return BoolGetDatum(true); - else - return BoolGetDatum(false); - case IS_NOT_TRUE: - if (*isNull) - { - *isNull = false; - return BoolGetDatum(true); - } - else if (DatumGetBool(result)) - return BoolGetDatum(false); - else - return BoolGetDatum(true); - case IS_FALSE: - if (*isNull) - { - *isNull = false; - return BoolGetDatum(false); - } - else if (DatumGetBool(result)) - return BoolGetDatum(false); - else - return BoolGetDatum(true); - case IS_NOT_FALSE: - if (*isNull) - { - *isNull = false; - return BoolGetDatum(true); - } - else if (DatumGetBool(result)) - return BoolGetDatum(true); - else - return BoolGetDatum(false); - case IS_UNKNOWN: - if (*isNull) - { - *isNull = false; - return BoolGetDatum(true); - } - else - return BoolGetDatum(false); - case IS_NOT_UNKNOWN: - if (*isNull) - { - *isNull = false; - return BoolGetDatum(false); - } - else - return BoolGetDatum(true); - default: - elog(ERROR, "ExecEvalBooleanTest: unexpected booltesttype %d", - (int) btest->booltesttype); - return (Datum) 0; /* keep compiler quiet */ - } -} - -/* ---------------------------------------------------------------- - * ExecEvalFieldSelect - * - * Evaluate a FieldSelect node. - * ---------------------------------------------------------------- - */ -static Datum -ExecEvalFieldSelect(FieldSelect *fselect, - ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) -{ - Datum result; - TupleTableSlot *resSlot; - - result = ExecEvalExpr(fselect->arg, econtext, isNull, isDone); - if (*isNull) - return result; - resSlot = (TupleTableSlot *) DatumGetPointer(result); - Assert(resSlot != NULL && IsA(resSlot, TupleTableSlot)); - result = heap_getattr(resSlot->val, - fselect->fieldnum, - resSlot->ttc_tupleDescriptor, - isNull); - return result; -} - -/* ---------------------------------------------------------------- - * ExecEvalExpr - * - * Recursively evaluate a targetlist or qualification expression. - * - * Inputs: - * expression: the expression tree to evaluate - * econtext: evaluation context information - * - * Outputs: - * return value: Datum value of result - * *isNull: set to TRUE if result is NULL (actual return value is - * meaningless if so); set to FALSE if non-null result - * *isDone: set to indicator of set-result status - * - * A caller that can only accept a singleton (non-set) result should pass - * NULL for isDone; if the expression computes a set result then an elog() - * error will be reported. If the caller does pass an isDone pointer then - * *isDone is set to one of these three states: - * ExprSingleResult singleton result (not a set) - * ExprMultipleResult return value is one element of a set - * ExprEndResult there are no more elements in the set - * When ExprMultipleResult is returned, the caller should invoke - * ExecEvalExpr() repeatedly until ExprEndResult is returned. ExprEndResult - * is returned after the last real set element. For convenience isNull will - * always be set TRUE when ExprEndResult is returned, but this should not be - * taken as indicating a NULL element of the set. Note that these return - * conventions allow us to distinguish among a singleton NULL, a NULL element - * of a set, and an empty set. - * - * The caller should already have switched into the temporary memory - * context econtext->ecxt_per_tuple_memory. The convenience entry point - * ExecEvalExprSwitchContext() is provided for callers who don't prefer to - * do the switch in an outer loop. We do not do the switch here because - * it'd be a waste of cycles during recursive entries to ExecEvalExpr(). - * - * This routine is an inner loop routine and must be as fast as possible. - * ---------------------------------------------------------------- - */ -Datum -ExecEvalExpr(Node *expression, - ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) -{ - Datum retDatum; - - /* Set default values for result flags: non-null, not a set result */ - *isNull = false; - if (isDone) - *isDone = ExprSingleResult; - - /* Is this still necessary? Doubtful... */ - if (expression == NULL) - { - *isNull = true; - return (Datum) 0; - } - - /* - * here we dispatch the work to the appropriate type of function given - * the type of our expression. - */ - switch (nodeTag(expression)) - { - case T_Var: - retDatum = ExecEvalVar((Var *) expression, econtext, isNull); - break; - case T_Const: - { - Const *con = (Const *) expression; - - retDatum = con->constvalue; - *isNull = con->constisnull; - break; - } - case T_Param: - retDatum = ExecEvalParam((Param *) expression, econtext, isNull); - break; - case T_Aggref: - retDatum = ExecEvalAggref((Aggref *) expression, econtext, isNull); - break; - case T_ArrayRef: - retDatum = ExecEvalArrayRef((ArrayRef *) expression, - econtext, - isNull, - isDone); - break; - case T_Expr: - { - Expr *expr = (Expr *) expression; - - switch (expr->opType) - { - case OP_EXPR: - retDatum = ExecEvalOper(expr, econtext, - isNull, isDone); - break; - case FUNC_EXPR: - retDatum = ExecEvalFunc(expr, econtext, - isNull, isDone); - break; - case OR_EXPR: - retDatum = ExecEvalOr(expr, econtext, isNull); - break; - case AND_EXPR: - retDatum = ExecEvalAnd(expr, econtext, isNull); - break; - case NOT_EXPR: - retDatum = ExecEvalNot(expr, econtext, isNull); - break; - case SUBPLAN_EXPR: - retDatum = ExecSubPlan((SubPlan *) expr->oper, - expr->args, econtext, - isNull); - break; - default: - elog(ERROR, "ExecEvalExpr: unknown expression type %d", - expr->opType); - retDatum = 0; /* keep compiler quiet */ - break; - } - break; - } - case T_FieldSelect: - retDatum = ExecEvalFieldSelect((FieldSelect *) expression, - econtext, - isNull, - isDone); - break; - case T_RelabelType: - retDatum = ExecEvalExpr(((RelabelType *) expression)->arg, - econtext, - isNull, - isDone); - break; - case T_CaseExpr: - retDatum = ExecEvalCase((CaseExpr *) expression, - econtext, - isNull, - isDone); - break; - case T_NullTest: - retDatum = ExecEvalNullTest((NullTest *) expression, - econtext, - isNull, - isDone); - break; - case T_BooleanTest: - retDatum = ExecEvalBooleanTest((BooleanTest *) expression, - econtext, - isNull, - isDone); - break; - - default: - elog(ERROR, "ExecEvalExpr: unknown expression type %d", - nodeTag(expression)); - retDatum = 0; /* keep compiler quiet */ - break; - } - - return retDatum; -} /* ExecEvalExpr() */ - - -/* - * Same as above, but get into the right allocation context explicitly. - */ -Datum -ExecEvalExprSwitchContext(Node *expression, - ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) -{ - Datum retDatum; - MemoryContext oldContext; - - oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); - retDatum = ExecEvalExpr(expression, econtext, isNull, isDone); - MemoryContextSwitchTo(oldContext); - return retDatum; -} - - -/* ---------------------------------------------------------------- - * ExecQual / ExecTargetList / ExecProject - * ---------------------------------------------------------------- - */ - -/* ---------------------------------------------------------------- - * ExecQual - * - * Evaluates a conjunctive boolean expression (qual list) and - * returns true iff none of the subexpressions are false. - * (We also return true if the list is empty.) - * - * If some of the subexpressions yield NULL but none yield FALSE, - * then the result of the conjunction is NULL (ie, unknown) - * according to three-valued boolean logic. In this case, - * we return the value specified by the "resultForNull" parameter. - * - * Callers evaluating WHERE clauses should pass resultForNull=FALSE, - * since SQL specifies that tuples with null WHERE results do not - * get selected. On the other hand, callers evaluating constraint - * conditions should pass resultForNull=TRUE, since SQL also specifies - * that NULL constraint conditions are not failures. - * - * NOTE: it would not be correct to use this routine to evaluate an - * AND subclause of a boolean expression; for that purpose, a NULL - * result must be returned as NULL so that it can be properly treated - * in the next higher operator (cf. ExecEvalAnd and ExecEvalOr). - * This routine is only used in contexts where a complete expression - * is being evaluated and we know that NULL can be treated the same - * as one boolean result or the other. - * - * ---------------------------------------------------------------- - */ -bool -ExecQual(List *qual, ExprContext *econtext, bool resultForNull) -{ - bool result; - MemoryContext oldContext; - List *qlist; - - /* - * debugging stuff - */ - EV_printf("ExecQual: qual is "); - EV_nodeDisplay(qual); - EV_printf("\n"); - - IncrProcessed(); - - /* - * Run in short-lived per-tuple context while computing expressions. - */ - oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); - - /* - * Evaluate the qual conditions one at a time. If we find a FALSE - * result, we can stop evaluating and return FALSE --- the AND result - * must be FALSE. Also, if we find a NULL result when resultForNull - * is FALSE, we can stop and return FALSE --- the AND result must be - * FALSE or NULL in that case, and the caller doesn't care which. - * - * If we get to the end of the list, we can return TRUE. This will - * happen when the AND result is indeed TRUE, or when the AND result - * is NULL (one or more NULL subresult, with all the rest TRUE) and - * the caller has specified resultForNull = TRUE. - */ - result = true; - - foreach(qlist, qual) - { - Node *clause = (Node *) lfirst(qlist); - Datum expr_value; - bool isNull; - - expr_value = ExecEvalExpr(clause, econtext, &isNull, NULL); - - if (isNull) - { - if (resultForNull == false) - { - result = false; /* treat NULL as FALSE */ - break; - } - } - else - { - if (!DatumGetBool(expr_value)) - { - result = false; /* definitely FALSE */ - break; - } - } - } - - MemoryContextSwitchTo(oldContext); - - return result; -} - -/* - * Number of items in a tlist (including any resjunk items!) - */ -int -ExecTargetListLength(List *targetlist) -{ - int len = 0; - List *tl; - - foreach(tl, targetlist) - { - TargetEntry *curTle = (TargetEntry *) lfirst(tl); - - if (curTle->resdom != NULL) - len++; - else - len += curTle->fjoin->fj_nNodes; - } - return len; -} - -/* - * Number of items in a tlist, not including any resjunk items - */ -int -ExecCleanTargetListLength(List *targetlist) -{ - int len = 0; - List *tl; - - foreach(tl, targetlist) - { - TargetEntry *curTle = (TargetEntry *) lfirst(tl); - - if (curTle->resdom != NULL) - { - if (!curTle->resdom->resjunk) - len++; - } - else - len += curTle->fjoin->fj_nNodes; - } - return len; -} - -/* ---------------------------------------------------------------- - * ExecTargetList - * - * Evaluates a targetlist with respect to the current - * expression context and return a tuple. - * - * As with ExecEvalExpr, the caller should pass isDone = NULL if not - * prepared to deal with sets of result tuples. Otherwise, a return - * of *isDone = ExprMultipleResult signifies a set element, and a return - * of *isDone = ExprEndResult signifies end of the set of tuple. - * ---------------------------------------------------------------- - */ -static HeapTuple -ExecTargetList(List *targetlist, - int nodomains, - TupleDesc targettype, - Datum *values, - ExprContext *econtext, - ExprDoneCond *isDone) -{ - MemoryContext oldContext; - -#define NPREALLOCDOMAINS 64 - char nullsArray[NPREALLOCDOMAINS]; - bool fjIsNullArray[NPREALLOCDOMAINS]; - ExprDoneCond itemIsDoneArray[NPREALLOCDOMAINS]; - char *nulls; - bool *fjIsNull; - ExprDoneCond *itemIsDone; - List *tl; - TargetEntry *tle; - AttrNumber resind; - HeapTuple newTuple; - bool isNull; - bool haveDoneSets; - static struct tupleDesc NullTupleDesc; /* we assume this inits to - * zeroes */ - - /* - * debugging stuff - */ - EV_printf("ExecTargetList: tl is "); - EV_nodeDisplay(targetlist); - EV_printf("\n"); - - /* - * Run in short-lived per-tuple context while computing expressions. - */ - oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); - - /* - * There used to be some klugy and demonstrably broken code here that - * special-cased the situation where targetlist == NIL. Now we just - * fall through and return an empty-but-valid tuple. We do, however, - * have to cope with the possibility that targettype is NULL --- - * heap_formtuple won't like that, so pass a dummy descriptor with - * natts = 0 to deal with it. - */ - if (targettype == NULL) - targettype = &NullTupleDesc; - - /* - * allocate an array of char's to hold the "null" information only if - * we have a really large targetlist. otherwise we use the stack. - * - * We also allocate a bool array that is used to hold fjoin result state, - * and another array that holds the isDone status for each targetlist - * item. The isDone status is needed so that we can iterate, - * generating multiple tuples, when one or more tlist items return - * sets. (We expect the caller to call us again if we return: - * - * isDone = ExprMultipleResult.) - */ - if (nodomains > NPREALLOCDOMAINS) - { - nulls = (char *) palloc(nodomains * sizeof(char)); - fjIsNull = (bool *) palloc(nodomains * sizeof(bool)); - itemIsDone = (ExprDoneCond *) palloc(nodomains * sizeof(ExprDoneCond)); - } - else - { - nulls = nullsArray; - fjIsNull = fjIsNullArray; - itemIsDone = itemIsDoneArray; - } - - /* - * evaluate all the expressions in the target list - */ - - if (isDone) - *isDone = ExprSingleResult; /* until proven otherwise */ - - haveDoneSets = false; /* any exhausted set exprs in tlist? */ - - foreach(tl, targetlist) - { - tle = lfirst(tl); - - if (tle->resdom != NULL) - { - resind = tle->resdom->resno - 1; - - values[resind] = ExecEvalExpr(tle->expr, - econtext, - &isNull, - &itemIsDone[resind]); - nulls[resind] = isNull ? 'n' : ' '; - - if (itemIsDone[resind] != ExprSingleResult) - { - /* We have a set-valued expression in the tlist */ - if (isDone == NULL) - elog(ERROR, "Set-valued function called in context that cannot accept a set"); - if (itemIsDone[resind] == ExprMultipleResult) - { - /* we have undone sets in the tlist, set flag */ - *isDone = ExprMultipleResult; - } - else - { - /* we have done sets in the tlist, set flag for that */ - haveDoneSets = true; - } - } - } - else - { -#ifdef SETS_FIXED - int curNode; - Resdom *fjRes; - List *fjTlist = (List *) tle->expr; - Fjoin *fjNode = tle->fjoin; - int nNodes = fjNode->fj_nNodes; - DatumPtr results = fjNode->fj_results; - - ExecEvalFjoin(tle, econtext, fjIsNull, isDone); - - /* - * XXX this is wrong, but since fjoin code is completely - * broken anyway, I'm not going to worry about it now --- tgl - * 8/23/00 - */ - if (isDone && *isDone == ExprEndResult) - { - MemoryContextSwitchTo(oldContext); - newTuple = NULL; - goto exit; - } - - /* - * get the result from the inner node - */ - fjRes = (Resdom *) fjNode->fj_innerNode; - resind = fjRes->resno - 1; - values[resind] = results[0]; - nulls[resind] = fjIsNull[0] ? 'n' : ' '; - - /* - * Get results from all of the outer nodes - */ - for (curNode = 1; - curNode < nNodes; - curNode++, fjTlist = lnext(fjTlist)) - { - Node *outernode = lfirst(fjTlist); - - fjRes = (Resdom *) outernode->iterexpr; - resind = fjRes->resno - 1; - values[resind] = results[curNode]; - nulls[resind] = fjIsNull[curNode] ? 'n' : ' '; - } -#else - elog(ERROR, "ExecTargetList: fjoin nodes not currently supported"); -#endif - } - } - - if (haveDoneSets) - { - /* - * note: can't get here unless we verified isDone != NULL - */ - if (*isDone == ExprSingleResult) - { - /* - * all sets are done, so report that tlist expansion is - * complete. - */ - *isDone = ExprEndResult; - MemoryContextSwitchTo(oldContext); - newTuple = NULL; - goto exit; - } - else - { - /* - * We have some done and some undone sets. Restart the done - * ones so that we can deliver a tuple (if possible). - */ - foreach(tl, targetlist) - { - tle = lfirst(tl); - - if (tle->resdom != NULL) - { - resind = tle->resdom->resno - 1; - - if (itemIsDone[resind] == ExprEndResult) - { - values[resind] = ExecEvalExpr(tle->expr, - econtext, - &isNull, - &itemIsDone[resind]); - nulls[resind] = isNull ? 'n' : ' '; - - if (itemIsDone[resind] == ExprEndResult) - { - /* - * Oh dear, this item is returning an empty - * set. Guess we can't make a tuple after all. - */ - *isDone = ExprEndResult; - break; - } - } - } - } - - /* - * If we cannot make a tuple because some sets are empty, we - * still have to cycle the nonempty sets to completion, else - * resources will not be released from subplans etc. - */ - if (*isDone == ExprEndResult) - { - foreach(tl, targetlist) - { - tle = lfirst(tl); - - if (tle->resdom != NULL) - { - resind = tle->resdom->resno - 1; - - while (itemIsDone[resind] == ExprMultipleResult) - { - (void) ExecEvalExpr(tle->expr, - econtext, - &isNull, - &itemIsDone[resind]); - } - } - } - - MemoryContextSwitchTo(oldContext); - newTuple = NULL; - goto exit; - } - } - } - - /* - * form the new result tuple (in the caller's memory context!) - */ - MemoryContextSwitchTo(oldContext); - - newTuple = (HeapTuple) heap_formtuple(targettype, values, nulls); - -exit: - - /* - * free the status arrays if we palloc'd them - */ - if (nodomains > NPREALLOCDOMAINS) - { - pfree(nulls); - pfree(fjIsNull); - pfree(itemIsDone); - } - - return newTuple; -} - -/* ---------------------------------------------------------------- - * ExecProject - * - * projects a tuple based on 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(ProjectionInfo *projInfo, ExprDoneCond *isDone) -{ - TupleTableSlot *slot; - List *targetlist; - int len; - TupleDesc tupType; - Datum *tupValue; - ExprContext *econtext; - HeapTuple newTuple; - - /* - * sanity checks - */ - if (projInfo == NULL) - return (TupleTableSlot *) NULL; - - /* - * get the projection info we want - */ - slot = projInfo->pi_slot; - targetlist = projInfo->pi_targetlist; - len = projInfo->pi_len; - tupType = slot->ttc_tupleDescriptor; - - tupValue = projInfo->pi_tupValue; - econtext = projInfo->pi_exprContext; - - /* - * form a new result tuple (if possible --- result can be NULL) - */ - newTuple = ExecTargetList(targetlist, - len, - tupType, - tupValue, - econtext, - isDone); - - /* - * store the tuple in the projection slot and return the slot. - */ - return ExecStoreTuple(newTuple, /* tuple to store */ - slot, /* slot to store in */ - InvalidBuffer, /* tuple has no buffer */ - true); -} |