📄 execqual.c
字号:
* original tuple). */ attnum = variable->varattno; switch (variable->varno) { case INNER: /* get the tuple from the inner node */ slot = econtext->ecxt_innertuple; Assert(attnum > 0); break; case OUTER: /* get the tuple from the outer node */ slot = econtext->ecxt_outertuple; Assert(attnum > 0); break; default: /* get the tuple from the relation being * scanned */ slot = econtext->ecxt_scantuple; break; }#ifdef USE_ASSERT_CHECKING /* * Some checks that are only applied for user attribute numbers (bogus * system attnums will be caught inside slot_getattr). */ if (attnum > 0) { TupleDesc tuple_type = slot->tts_tupleDescriptor; /* * This assert checks that the attnum is valid. */ Assert(attnum <= tuple_type->natts); /* * This assert checks that the datatype the plan expects to get (as * told by our "variable" argument) is in fact the datatype of the * attribute being fetched (as seen in the current context, identified * by our "econtext" argument). Otherwise crashes are likely. * * Note that we can't check dropped columns, since their atttypid has * been zeroed. */ Assert(variable->vartype == tuple_type->attrs[attnum - 1]->atttypid || tuple_type->attrs[attnum - 1]->attisdropped); }#endif /* USE_ASSERT_CHECKING */ return slot_getattr(slot, attnum, isNull);}/* ---------------------------------------------------------------- * ExecEvalWholeRowVar * * Returns a Datum for a whole-row variable. * * This could be folded into ExecEvalVar, but we make it a separate * routine so as not to slow down ExecEvalVar with tests for this * uncommon case. * ---------------------------------------------------------------- */static DatumExecEvalWholeRowVar(ExprState *exprstate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone){ Var *variable = (Var *) exprstate->expr; TupleTableSlot *slot; HeapTuple tuple; TupleDesc tupleDesc; HeapTupleHeader dtuple; if (isDone) *isDone = ExprSingleResult; *isNull = false; Assert(variable->varattno == InvalidAttrNumber); /* * Whole-row Vars can only appear at the level of a relation scan, never * in a join. */ Assert(variable->varno != INNER); Assert(variable->varno != OUTER); slot = econtext->ecxt_scantuple; tuple = ExecFetchSlotTuple(slot); tupleDesc = slot->tts_tupleDescriptor; /* * We have to make a copy of the tuple so we can safely insert the Datum * overhead fields, which are not set in on-disk tuples. */ dtuple = (HeapTupleHeader) palloc(tuple->t_len); memcpy((char *) dtuple, (char *) tuple->t_data, tuple->t_len); HeapTupleHeaderSetDatumLength(dtuple, tuple->t_len); /* * If the Var identifies a named composite type, label the tuple with that * type; otherwise use what is in the tupleDesc. * * It's likely that the slot's tupleDesc is a record type; if so, make * sure it's been "blessed", so that the Datum can be interpreted later. */ if (variable->vartype != RECORDOID) { HeapTupleHeaderSetTypeId(dtuple, variable->vartype); HeapTupleHeaderSetTypMod(dtuple, variable->vartypmod); } else { if (tupleDesc->tdtypeid == RECORDOID && tupleDesc->tdtypmod < 0) assign_record_type_typmod(tupleDesc); HeapTupleHeaderSetTypeId(dtuple, tupleDesc->tdtypeid); HeapTupleHeaderSetTypMod(dtuple, tupleDesc->tdtypmod); } return PointerGetDatum(dtuple);}/* ---------------------------------------------------------------- * ExecEvalConst * * Returns the value of a constant. * * Note that for pass-by-ref datatypes, we return a pointer to the * actual constant node. This is one of the reasons why functions * must treat their input arguments as read-only. * ---------------------------------------------------------------- */static DatumExecEvalConst(ExprState *exprstate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone){ Const *con = (Const *) exprstate->expr; if (isDone) *isDone = ExprSingleResult; *isNull = con->constisnull; return con->constvalue;}/* ---------------------------------------------------------------- * 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 find and return the appropriate datum ("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 could return NULL)? -cim 10/13/89 * ---------------------------------------------------------------- */static DatumExecEvalParam(ExprState *exprstate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone){ Param *expression = (Param *) exprstate->expr; int thisParamKind = expression->paramkind; AttrNumber thisParamId = expression->paramid; if (isDone) *isDone = ExprSingleResult; if (thisParamKind == PARAM_EXEC) { /* * PARAM_EXEC params (internal executor parameters) are stored in the * ecxt_param_exec_vals array, and can be accessed by array index. */ ParamExecData *prm; prm = &(econtext->ecxt_param_exec_vals[thisParamId]); if (prm->execPlan != NULL) { /* Parameter not evaluated yet, so go do it */ ExecSetParamPlan(prm->execPlan, econtext); /* ExecSetParamPlan should have processed this param... */ Assert(prm->execPlan == NULL); } *isNull = prm->isnull; return prm->value; } else { /* * All other parameter types must be sought in ecxt_param_list_info. */ ParamListInfo paramInfo; paramInfo = lookupParam(econtext->ecxt_param_list_info, thisParamKind, expression->paramname, thisParamId, false); Assert(paramInfo->ptype == expression->paramtype); *isNull = paramInfo->isnull; return paramInfo->value; }}/* ---------------------------------------------------------------- * ExecEvalOper / ExecEvalFunc support routines * ---------------------------------------------------------------- *//* * GetAttributeByName * GetAttributeByNum * * These functions return the value of the requested attribute * out of the given tuple Datum. * C functions which take a tuple as an argument are expected * to use these. Ex: overpaid(EMP) might call GetAttributeByNum(). * Note: these are actually rather slow because they do a typcache * lookup on each call. */DatumGetAttributeByNum(HeapTupleHeader tuple, AttrNumber attrno, bool *isNull){ Datum result; Oid tupType; int32 tupTypmod; TupleDesc tupDesc; HeapTupleData tmptup; if (!AttributeNumberIsValid(attrno)) elog(ERROR, "invalid attribute number %d", attrno); if (isNull == NULL) elog(ERROR, "a NULL isNull pointer was passed"); if (tuple == NULL) { /* Kinda bogus but compatible with old behavior... */ *isNull = true; return (Datum) 0; } tupType = HeapTupleHeaderGetTypeId(tuple); tupTypmod = HeapTupleHeaderGetTypMod(tuple); tupDesc = lookup_rowtype_tupdesc(tupType, tupTypmod); /* * heap_getattr needs a HeapTuple not a bare HeapTupleHeader. We set all * the fields in the struct just in case user tries to inspect system * columns. */ tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple); ItemPointerSetInvalid(&(tmptup.t_self)); tmptup.t_tableOid = InvalidOid; tmptup.t_data = tuple; result = heap_getattr(&tmptup, attrno, tupDesc, isNull); return result;}DatumGetAttributeByName(HeapTupleHeader tuple, const char *attname, bool *isNull){ AttrNumber attrno; Datum result; Oid tupType; int32 tupTypmod; TupleDesc tupDesc; HeapTupleData tmptup; int i; if (attname == NULL) elog(ERROR, "invalid attribute name"); if (isNull == NULL) elog(ERROR, "a NULL isNull pointer was passed"); if (tuple == NULL) { /* Kinda bogus but compatible with old behavior... */ *isNull = true; return (Datum) 0; } tupType = HeapTupleHeaderGetTypeId(tuple); tupTypmod = HeapTupleHeaderGetTypMod(tuple); tupDesc = lookup_rowtype_tupdesc(tupType, tupTypmod); 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); /* * heap_getattr needs a HeapTuple not a bare HeapTupleHeader. We set all * the fields in the struct just in case user tries to inspect system * columns. */ tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple); ItemPointerSetInvalid(&(tmptup.t_self)); tmptup.t_tableOid = InvalidOid; tmptup.t_data = tuple; result = heap_getattr(&tmptup, attrno, tupDesc, isNull); return result;}/* * 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 on nargs. Under normal circumstances this should never * fail, as parser should check sooner. But possibly it might fail if * server has been compiled with FUNC_MAX_ARGS smaller than some functions * declared in pg_proc? */ if (list_length(fcache->args) > FUNC_MAX_ARGS) ereport(ERROR, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), errmsg("cannot pass more than %d arguments to a function", FUNC_MAX_ARGS))); /* 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; ListCell *arg; argIsDone = ExprSingleResult; /* default assumption */ i = 0; foreach(arg, argList) { ExprState *argstate = (ExprState *) lfirst(arg); ExprDoneCond thisArgIsDone; fcinfo->arg[i] = ExecEvalExpr(argstate, 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; /* Guard against stack overflow due to overly complex expressions */ check_stack_depth(); /* * 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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -