📄 execqual.c
字号:
{ 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){ ExprState *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 DatumExecEvalOr(BoolExprState *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((ExprState *) 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 DatumExecEvalAnd(BoolExprState *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((ExprState *) 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 DatumExecEvalCase(CaseExprState *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) { CaseWhenState *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;}/* ---------------------------------------------------------------- * ExecEvalArray - ARRAY[] expressions * * NOTE: currently, if any input value is NULL then we return a NULL array, * so the ARRAY[] construct can be considered strict. Eventually this will * change; when it does, be sure to fix contain_nonstrict_functions(). * ---------------------------------------------------------------- */static DatumExecEvalArray(ArrayExprState *astate, ExprContext *econtext, bool *isNull){ ArrayExpr *arrayExpr = (ArrayExpr *) astate->xprstate.expr; ArrayType *result; List *element; Oid element_type = arrayExpr->element_typeid; int ndims = 0; int dims[MAXDIM]; int lbs[MAXDIM]; if (!arrayExpr->multidims) { /* Elements are presumably of scalar type */ int nelems; Datum *dvalues; int i = 0; ndims = 1; nelems = length(astate->elements); /* Shouldn't happen here, but if length is 0, return NULL */ if (nelems == 0) { *isNull = true; return (Datum) 0; } dvalues = (Datum *) palloc(nelems * sizeof(Datum)); /* loop through and build array of datums */ foreach(element, astate->elements) { ExprState *e = (ExprState *) lfirst(element); bool eisnull; dvalues[i++] = ExecEvalExpr(e, econtext, &eisnull, NULL); if (eisnull) { *isNull = true; return (Datum) 0; } } /* setup for 1-D array of the given length */ dims[0] = nelems; lbs[0] = 1; result = construct_md_array(dvalues, ndims, dims, lbs, element_type, astate->elemlength, astate->elembyval, astate->elemalign); } else { /* Must be nested array expressions */ char *dat = NULL; Size ndatabytes = 0; int nbytes; int outer_nelems = length(astate->elements); int elem_ndims = 0; int *elem_dims = NULL; int *elem_lbs = NULL; bool firstone = true; int i; /* loop through and get data area from each element */ foreach(element, astate->elements) { ExprState *e = (ExprState *) lfirst(element); bool eisnull; Datum arraydatum; ArrayType *array; int elem_ndatabytes; arraydatum = ExecEvalExpr(e, econtext, &eisnull, NULL); if (eisnull) { *isNull = true; return (Datum) 0; } array = DatumGetArrayTypeP(arraydatum); /* run-time double-check on element type */ if (element_type != ARR_ELEMTYPE(array)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("cannot merge incompatible arrays"), errdetail("Array with element type %s cannot be " "included in ARRAY construct with element type %s.", format_type_be(ARR_ELEMTYPE(array)), format_type_be(element_type)))); if (firstone) { /* Get sub-array details from first member */ elem_ndims = ARR_NDIM(array); ndims = elem_ndims + 1; if (ndims <= 0 || ndims > MAXDIM) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("number of array dimensions (%d) exceeds " \ "the maximum allowed (%d)", ndims, MAXDIM))); elem_dims = (int *) palloc(elem_ndims * sizeof(int)); memcpy(elem_dims, ARR_DIMS(array), elem_ndims * sizeof(int)); elem_lbs = (int *) palloc(elem_ndims * sizeof(int)); memcpy(elem_lbs, ARR_LBOUND(array), elem_ndims * sizeof(int)); firstone = false; } else { /* Check other sub-arrays are compatible */ if (elem_ndims != ARR_NDIM(array) || memcmp(elem_dims, ARR_DIMS(array), elem_ndims * sizeof(int)) != 0 || memcmp(elem_lbs, ARR_LBOUND(array), elem_ndims * sizeof(int)) != 0) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("multidimensional arrays must have array " "expressions with matching dimensions"))); } elem_ndatabytes = ARR_SIZE(array) - ARR_OVERHEAD(elem_ndims); ndatabytes += elem_ndatabytes; if (dat == NULL) dat = (char *) palloc(ndatabytes); else dat = (char *) repalloc(dat, ndatabytes); memcpy(dat + (ndatabytes - elem_ndatabytes), ARR_DATA_PTR(array), elem_ndatabytes); } /* setup for multi-D array */ dims[0] = outer_nelems; lbs[0] = 1; for (i = 1; i < ndims; i++) { dims[i] = elem_dims[i - 1]; lbs[i] = elem_lbs[i - 1]; } nbytes = ndatabytes + ARR_OVERHEAD(ndims); result = (ArrayType *) palloc(nbytes); result->size = nbytes; result->ndim = ndims; result->flags = 0; result->elemtype = element_type; memcpy(ARR_DIMS(result), dims, ndims * sizeof(int)); memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int)); if (ndatabytes > 0) memcpy(ARR_DATA_PTR(result), dat, ndatabytes); if (dat != NULL) pfree(dat); } return PointerGetDatum(result);}/* ---------------------------------------------------------------- * ExecEvalCoalesce * ---------------------------------------------------------------- */static DatumExecEvalCoalesce(CoalesceExprState *coalesceExpr, ExprContext *econtext, bool *isNull){ List *arg; /* Simply loop through until something NOT NULL is found */ foreach(arg, coalesceExpr->args) { ExprState *e = (ExprState *) lfirst(arg); Datum value; value = ExecEvalExpr(e, econtext, isNull, NULL); if (!*isNull) return value; } /* Else return NULL */ *isNull = true; return (Datum) 0;}/* ---------------------------------------------------------------- * ExecEvalNullIf * * 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 DatumExecEvalNullIf(FuncExprState *fcache, ExprContext *econtext, bool *isNull){ Datum result; FunctionCallInfoData fcinfo; ExprDoneCond argDone; List *argList; /* * Initialize function cache if first time through */ if (fcache->func.fn_oid == InvalidOid) { NullIfExpr *op = (NullIfExpr *) 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 */ MemSet(&fcinfo, 0, sizeof(fcinfo)); fcinfo.flinfo = &(fcache->func); argDone = ExecEvalFuncArgs(&fcinfo, argList, econtext); if (argDone != ExprSingleResult) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("NULLIF does not support set arguments"))); Assert(fcinfo.nargs == 2); /* if either argument is NULL they can't be equal */ if (!fcinfo.argnull[0] && !fcinfo.argnull[1]) { fcinfo.isnull = false; result = FunctionCallInvoke(&fcinfo); /* if the arguments are equal return null */ if (!fcinfo.isnull && DatumGetBool(result)) { *isNull = true; return (Datum) 0; } } /* else return first argument */ *isNull = fcinfo.argnull[0]; return fcinfo.arg[0];}/* ---------------------------------------------------------------- * ExecEvalNullTest
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -