📄 execqual.c
字号:
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 (char *) NULL; } 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 (char *) NULL; return (char *) retval;}/* XXX name for catalogs */#ifdef NOT_USEDchar *att_by_name(TupleTableSlot *slot, char *attname, bool *isNull){ return GetAttributeByName(slot, attname, isNull);}#endifstatic voidExecEvalFuncArgs(FunctionCachePtr fcache, ExprContext *econtext, List *argList, Datum argV[], bool *argIsDone){ int i; bool argIsNull, *nullVect; List *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 *) lfirst(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 */static DatumExecMakeFunctionResult(Node *node, List *arguments, ExprContext *econtext, bool *isNull, bool *isDone){ Datum argV[MAXFMGRARGS]; FunctionCachePtr fcache; Func *funcNode = NULL; Oper *operNode = NULL; bool funcisset = false; /* * 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 (IsA(node, Func)) { funcNode = (Func *) node; fcache = funcNode->func_fcache; } else { operNode = (Oper *) node; fcache = operNode->op_fcache; } /* * 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(ERROR, "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; } } /* * If this function is really a set, we have to diddle with things. If * the function has already been called at least once, then the setArg * field of the fcache holds the OID of this set in pg_proc. (This is * not quite legit, since the setArg field is really for functions * which take sets of tuples as input - set functions take no inputs * at all. But it's a nice place to stash this value, for now.) * * If this is the first call of the set's function, then the call to * ExecEvalFuncArgs above just returned the OID of the pg_proc tuple * which defines this set. So replace the existing funcid in the * funcnode with the set's OID. Also, we want a new fcache which * points to the right function, so get that, now that we have the * right OID. Also zero out the argV, since the real set doesn't take * any arguments. */ if (((Func *) node)->funcid == F_SETEVAL) { funcisset = true; if (fcache->setArg) { argV[0] = 0; ((Func *) node)->funcid = (Oid) PointerGetDatum(fcache->setArg); } else { ((Func *) node)->funcid = (Oid) argV[0]; setFcache(node, argV[0], NIL, econtext); fcache = ((Func *) node)->func_fcache; fcache->setArg = (char *) argV[0]; argV[0] = (Datum) 0; } } /* * now return the value gotten by calling the function manager, * passing the function the evaluated parameter values. */ if (fcache->language == SQLlanguageId) { Datum result; Assert(funcNode); result = postquel_function(funcNode, (char **) 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)) { bool argDone; ExecEvalFuncArgs(fcache, econtext, arguments, argV, &argDone); if (argDone) { fcache->setArg = (char *) NULL; *isDone = true; result = (Datum) NULL; } else result = postquel_function(funcNode, (char **) argV, isNull, isDone); } if (funcisset) { /* * reset the funcid so that next call to this routine will * still recognize this func as a set. Note that for now we * assume that the set function in pg_proc must be a Postquel * function - the funcid is not reset below for C functions. */ ((Func *) node)->funcid = F_SETEVAL; /* * If we're done with the results of this function, get rid of * its func cache. */ if (*isDone) ((Func *) node)->func_fcache = NULL; } 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_c(&fcache->func, (FmgrValues *) 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 * ---------------------------------------------------------------- */static DatumExecEvalOper(Expr *opClause, ExprContext *econtext, bool *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 *) 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) { setFcache((Node *) op, op->opid, argList, econtext); fcache = op->op_fcache; } /* * 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 * ---------------------------------------------------------------- */static DatumExecEvalFunc(Expr *funcClause, ExprContext *econtext, bool *isNull, bool *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 *) 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) { setFcache((Node *) func, func->funcid, argList, econtext); fcache = func->func_fcache; } 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... * ---------------------------------------------------------------- */static DatumExecEvalNot(Expr *notclause, ExprContext *econtext, bool *isNull){ Datum expr_value; Node *clause; bool isDone; clause = lfirst(notclause->args); /* * We don't iterate over sets in the quals, so pass in an isDone flag, * but ignore it. */ expr_value = ExecEvalExpr(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 (DatumGetInt32(expr_value) == 0) return (Datum) true; return (Datum) false;}/* ---------------------------------------------------------------- * ExecEvalOr * ---------------------------------------------------------------- */static DatumExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull){ List *clauses; List *clause; bool isDone; bool IsNull; Datum const_value = 0; IsNull = false; clauses = orExpr->args; /* * 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 *) lfirst(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; /* * Many functions don't (or can't!) check if an argument is * NULL or NOT_NULL and may return TRUE (1) with *isNull TRUE * (an_int4_column <> 1: int4ne returns TRUE for NULLs). Not * having time to fix the function manager I want to fix OR: * if we had 'x <> 1 OR x isnull' then when x is NULL TRUE was * returned by the 'x <> 1' clause ... but ExecQualClause says * that the qualification should *fail* if isnull is TRUE for * any value returned by ExecEvalExpr. So, force this rule * here: if isnull is TRUE then the clause failed. Note: * nullvalue() & nonnullvalue() always sets isnull to FALSE * for NULLs. - vadim 09/22/97 */ const_value = 0; } /* * if we have a true result, then we return it. */ if (DatumGetInt32(const_value) != 0) return const_value; } /* IsNull is true if at least one clause evaluated to NULL */ *isNull = IsNull; return const_value;}/* ---------------------------------------------------------------- * ExecEvalAnd * ---------------------------------------------------------------- */static DatumExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull){ List *clauses; List *clause; Datum const_value = 0; bool isDone; bool IsNull; IsNull = false; clauses = andExpr->args; /* * 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 *) lfirst(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 (DatumGetInt32(const_value) == 0) return const_value; } *isNull = IsNull; return const_value;}/* ---------------------------------------------------------------- * ExecEvalCase *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -