📄 execqual.c
字号:
/* * Scalar type, so make a single-column descriptor */ tupdesc = CreateTemplateTupleDesc(1, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "column", funcrettype, -1, 0); } tupstore = tuplestore_begin_heap(true, false, work_mem); MemoryContextSwitchTo(oldcontext); rsinfo.setResult = tupstore; rsinfo.setDesc = tupdesc; } /* * Store current resultset item. */ if (returnsTuple) { HeapTupleHeader td; td = DatumGetHeapTupleHeader(result); /* * tuplestore_puttuple needs a HeapTuple not a bare * HeapTupleHeader, but it doesn't need all the fields. */ tmptup.t_len = HeapTupleHeaderGetDatumLength(td); tmptup.t_data = td; tuple = &tmptup; } else { tuple = heap_form_tuple(tupdesc, &result, &fcinfo.isnull); } oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory); tuplestore_puttuple(tupstore, tuple); MemoryContextSwitchTo(oldcontext); /* * Are we done? */ if (rsinfo.isDone != ExprMultipleResult) break; } else if (rsinfo.returnMode == SFRM_Materialize) { /* check we're on the same page as the function author */ if (!first_time || rsinfo.isDone != ExprSingleResult) ereport(ERROR, (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED), errmsg("table-function protocol for materialize mode was not followed"))); /* Done evaluating the set result */ break; } else ereport(ERROR, (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED), errmsg("unrecognized table-function returnMode: %d", (int) rsinfo.returnMode))); first_time = false; }no_function_result: /* * If we got nothing from the function (ie, an empty-set or NULL result), * we have to create the tuplestore to return, and if it's a * non-set-returning function then insert a single all-nulls row. */ if (rsinfo.setResult == NULL) { MemoryContextSwitchTo(econtext->ecxt_per_query_memory); tupstore = tuplestore_begin_heap(true, false, work_mem); rsinfo.setResult = tupstore; if (!returnsSet) { int natts = expectedDesc->natts; Datum *nulldatums; bool *nullflags; HeapTuple tuple; MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); nulldatums = (Datum *) palloc0(natts * sizeof(Datum)); nullflags = (bool *) palloc(natts * sizeof(bool)); memset(nullflags, true, natts * sizeof(bool)); tuple = heap_form_tuple(expectedDesc, nulldatums, nullflags); MemoryContextSwitchTo(econtext->ecxt_per_query_memory); tuplestore_puttuple(tupstore, tuple); } } MemoryContextSwitchTo(callerContext); /* The returned pointers are those in rsinfo */ *returnDesc = rsinfo.setDesc; return rsinfo.setResult;}/* ---------------------------------------------------------------- * ExecEvalFunc * ExecEvalOper * * Evaluate the functional result of a list of arguments by calling the * function manager. * ---------------------------------------------------------------- *//* ---------------------------------------------------------------- * ExecEvalFunc * ---------------------------------------------------------------- */static DatumExecEvalFunc(FuncExprState *fcache, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone){ /* This is called only the first time through */ FuncExpr *func = (FuncExpr *) fcache->xprstate.expr; /* Initialize function lookup info */ init_fcache(func->funcid, fcache, econtext->ecxt_per_query_memory); /* Go directly to ExecMakeFunctionResult on subsequent uses */ fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResult; return ExecMakeFunctionResult(fcache, econtext, isNull, isDone);}/* ---------------------------------------------------------------- * ExecEvalOper * ---------------------------------------------------------------- */static DatumExecEvalOper(FuncExprState *fcache, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone){ /* This is called only the first time through */ OpExpr *op = (OpExpr *) fcache->xprstate.expr; /* Initialize function lookup info */ init_fcache(op->opfuncid, fcache, econtext->ecxt_per_query_memory); /* Go directly to ExecMakeFunctionResult on subsequent uses */ fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResult; return ExecMakeFunctionResult(fcache, econtext, isNull, isDone);}/* ---------------------------------------------------------------- * ExecEvalDistinct * * IS DISTINCT FROM must evaluate arguments to determine whether * they are NULL; if either is NULL then the result is already * known. If neither is NULL, then proceed to evaluate the * function. Note that this is *always* derived from the equals * operator, but since we need special processing of the arguments * we can not simply reuse ExecEvalOper() or ExecEvalFunc(). * ---------------------------------------------------------------- */static DatumExecEvalDistinct(FuncExprState *fcache, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone){ Datum result; FunctionCallInfoData fcinfo; ExprDoneCond argDone; List *argList; /* Set default values for result flags: non-null, not a set result */ *isNull = false; if (isDone) *isDone = ExprSingleResult; /* * Initialize function cache if first time through */ if (fcache->func.fn_oid == InvalidOid) { DistinctExpr *op = (DistinctExpr *) fcache->xprstate.expr; init_fcache(op->opfuncid, fcache, econtext->ecxt_per_query_memory); Assert(!fcache->func.fn_retset); } /* * extract info from fcache */ argList = fcache->args; /* Need to prep callinfo structure */ InitFunctionCallInfoData(fcinfo, &(fcache->func), 0, NULL, NULL); argDone = ExecEvalFuncArgs(&fcinfo, argList, econtext); if (argDone != ExprSingleResult) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("IS DISTINCT FROM does not support set arguments"))); Assert(fcinfo.nargs == 2); if (fcinfo.argnull[0] && fcinfo.argnull[1]) { /* Both NULL? Then is not distinct... */ result = BoolGetDatum(FALSE); } else if (fcinfo.argnull[0] || fcinfo.argnull[1]) { /* Only one is NULL? Then is distinct... */ result = BoolGetDatum(TRUE); } else { fcinfo.isnull = false; result = FunctionCallInvoke(&fcinfo); *isNull = fcinfo.isnull; /* Must invert result of "=" */ result = BoolGetDatum(!DatumGetBool(result)); } return result;}/* * ExecEvalScalarArrayOp * * Evaluate "scalar op ANY/ALL (array)". The operator always yields boolean, * and we combine the results across all array elements using OR and AND * (for ANY and ALL respectively). Of course we short-circuit as soon as * the result is known. */static DatumExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone){ ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) sstate->fxprstate.xprstate.expr; bool useOr = opexpr->useOr; ArrayType *arr; int nitems; Datum result; bool resultnull; FunctionCallInfoData fcinfo; ExprDoneCond argDone; int i; int16 typlen; bool typbyval; char typalign; char *s; /* Set default values for result flags: non-null, not a set result */ *isNull = false; if (isDone) *isDone = ExprSingleResult; /* * Initialize function cache if first time through */ if (sstate->fxprstate.func.fn_oid == InvalidOid) { init_fcache(opexpr->opfuncid, &sstate->fxprstate, econtext->ecxt_per_query_memory); Assert(!sstate->fxprstate.func.fn_retset); } /* Need to prep callinfo structure */ InitFunctionCallInfoData(fcinfo, &(sstate->fxprstate.func), 0, NULL, NULL); argDone = ExecEvalFuncArgs(&fcinfo, sstate->fxprstate.args, econtext); if (argDone != ExprSingleResult) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("op ANY/ALL (array) does not support set arguments"))); Assert(fcinfo.nargs == 2); /* * If the array is NULL then we return NULL --- it's not very meaningful * to do anything else, even if the operator isn't strict. */ if (fcinfo.argnull[1]) { *isNull = true; return (Datum) 0; } /* Else okay to fetch and detoast the array */ arr = DatumGetArrayTypeP(fcinfo.arg[1]); /* * If the array is empty, we return either FALSE or TRUE per the useOr * flag. This is correct even if the scalar is NULL; since we would * evaluate the operator zero times, it matters not whether it would want * to return NULL. */ nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr)); if (nitems <= 0) return BoolGetDatum(!useOr); /* * If the scalar is NULL, and the function is strict, return NULL. This is * just to avoid having to test for strictness inside the loop. (XXX but * if arrays could have null elements, we'd need a test anyway.) */ if (fcinfo.argnull[0] && sstate->fxprstate.func.fn_strict) { *isNull = true; return (Datum) 0; } /* * We arrange to look up info about the element type only once per series * of calls, assuming the element type doesn't change underneath us. */ if (sstate->element_type != ARR_ELEMTYPE(arr)) { get_typlenbyvalalign(ARR_ELEMTYPE(arr), &sstate->typlen, &sstate->typbyval, &sstate->typalign); sstate->element_type = ARR_ELEMTYPE(arr); } typlen = sstate->typlen; typbyval = sstate->typbyval; typalign = sstate->typalign; result = BoolGetDatum(!useOr); resultnull = false; /* Loop over the array elements */ s = (char *) ARR_DATA_PTR(arr); for (i = 0; i < nitems; i++) { Datum elt; Datum thisresult; /* Get array element */ elt = fetch_att(s, typbyval, typlen); s = att_addlength(s, typlen, PointerGetDatum(s)); s = (char *) att_align(s, typalign); /* Call comparison function */ fcinfo.arg[1] = elt; fcinfo.argnull[1] = false; fcinfo.isnull = false; thisresult = FunctionCallInvoke(&fcinfo); /* Combine results per OR or AND semantics */ if (fcinfo.isnull) resultnull = true; else if (useOr) { if (DatumGetBool(thisresult)) { result = BoolGetDatum(true); resultnull = false; break; /* needn't look at any more elements */ } } else { if (!DatumGetBool(thisresult)) { result = BoolGetDatum(false); resultnull = false; break; /* needn't look at any more elements */ } } } *isNull = resultnull; return result;}/* ---------------------------------------------------------------- * ExecEvalNot * ExecEvalOr * ExecEvalAnd * * Evaluate boolean expressions, with appropriate short-circuiting. * * 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(BoolExprState *notclause, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone){ ExprState *clause = linitial(notclause->args); Datum expr_value; if (isDone) *isDone = ExprSingleResult; 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 DatumExecEvalOr(BoolExprState *orExpr, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone){ List *clauses = orExpr->args; ListCell *clause; bool AnyNull; if (isDone) *isDone = ExprSingleResult; 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) { ExprState *clausestate = (ExprState *) lfirst(clause);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -