📄 execqual.c
字号:
char *thisParamName = expression->paramname; bool matchFound = false; if (paramList != NULL) { while (paramList->kind != PARAM_INVALID && !matchFound) { if (thisParamKind == paramList->kind) { switch (thisParamKind) { case PARAM_NAMED: if (strcmp(paramList->name, thisParamName) == 0) matchFound = true; break; case PARAM_NUM: if (paramList->id == thisParamId) matchFound = true; break; default: elog(ERROR, "unrecognized paramkind: %d", thisParamKind); } } if (!matchFound) paramList++; } /* while */ } /* if */ if (!matchFound) { if (thisParamKind == PARAM_NAMED) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("no value found for parameter \"%s\"", thisParamName))); else ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("no value found for parameter %d", thisParamId))); } *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(). */DatumGetAttributeByNum(TupleTableSlot *slot, AttrNumber attrno, bool *isNull){ Datum retval; if (!AttributeNumberIsValid(attrno)) elog(ERROR, "invalid attribute number %d", attrno); if (isNull == (bool *) NULL) elog(ERROR, "a NULL isNull pointer 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;}DatumGetAttributeByName(TupleTableSlot *slot, char *attname, bool *isNull){ AttrNumber attrno; TupleDesc tupdesc; Datum retval; int natts; int i; if (attname == NULL) elog(ERROR, "invalid attribute name"); if (isNull == (bool *) NULL) elog(ERROR, "a NULL isNull pointer 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, "attribute \"%s\" does not exist", attname); retval = heap_getattr(slot->val, attrno, tupdesc, isNull); if (*isNull) return (Datum) 0; return retval;}/* * init_fcache - initialize a FuncExprState node during first use */voidinit_fcache(Oid foid, FuncExprState *fcache, MemoryContext fcacheCxt){ AclResult aclresult; /* Check permission to call function */ aclresult = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(foid)); /* Safety check (should never fail, as parser should check sooner) */ if (length(fcache->args) > FUNC_MAX_ARGS) elog(ERROR, "too many arguments"); /* Set up the primary fmgr lookup information */ fmgr_info_cxt(foid, &(fcache->func), fcacheCxt); /* Initialize additional info */ fcache->setArgsValid = false; fcache->shutdown_reg = false; fcache->func.fn_expr = (Node *) fcache->xprstate.expr;}/* * callback function in case a FuncExpr returning a set needs to be shut down * before it has been run to completion */static voidShutdownFuncExpr(Datum arg){ FuncExprState *fcache = (FuncExprState *) DatumGetPointer(arg); /* Clear any active set-argument state */ fcache->setArgsValid = false; /* execUtils will deregister the callback... */ fcache->shutdown_reg = false;}/* * Evaluate arguments for a function. */static ExprDoneCondExecEvalFuncArgs(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((ExprState *) 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) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("functions and operators can take at most one set argument"))); argIsDone = thisArgIsDone; } i++; } fcinfo->nargs = i; return argIsDone;}/* * ExecMakeFunctionResult * * Evaluate the arguments to a function and then the function itself. */DatumExecMakeFunctionResult(FuncExprState *fcache, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone){ List *arguments = fcache->args; 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 ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("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; rsinfo.expectedDesc = NULL; rsinfo.allowedModes = (int) SFRM_ValuePerCall; rsinfo.returnMode = SFRM_ValuePerCall; /* isDone is filled below */ rsinfo.setResult = NULL; rsinfo.setDesc = NULL; } /* * 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) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("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; /* Register cleanup callback if we didn't already */ if (!fcache->shutdown_reg) { RegisterExprContextCallback(econtext, ShutdownFuncExpr, PointerGetDatum(fcache)); fcache->shutdown_reg = 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;}/* * ExecMakeTableFunctionResult * * Evaluate a table function, producing a materialized result in a Tuplestore * object. (If function returns an empty set, we just return NULL instead.) */Tuplestorestate *ExecMakeTableFunctionResult(ExprState *funcexpr, ExprContext *econtext, TupleDesc expectedDesc, TupleDesc *returnDesc){ Tuplestorestate *tupstore = NULL; TupleDesc tupdesc = NULL; Oid funcrettype; FunctionCallInfoData fcinfo; ReturnSetInfo rsinfo; MemoryContext callerContext; MemoryContext oldcontext; TupleTableSlot *slot; bool direct_function_call; bool first_time = true; bool returnsTuple = false; /* * Normally the passed expression tree will be a FuncExprState, since * the grammar only allows a function call at the top level of a table * function reference. However, if the function doesn't return set * then the planner might have replaced the function call via * constant-folding or inlining. So if we see any other kind of * expression node, execute it via the general ExecEvalExpr() code; * the only difference is that we don't get a chance to pass a special * ReturnSetInfo to any functions buried in the expression. */ if (funcexpr && IsA(funcexpr, FuncExprState) && IsA(funcexpr->expr, FuncExpr)) { FuncExprState *fcache = (FuncExprState *) funcexpr; ExprDoneCond argDone;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -