diff options
Diffstat (limited to 'src/backend/utils')
-rw-r--r-- | src/backend/utils/adt/arrayfuncs.c | 85 | ||||
-rw-r--r-- | src/backend/utils/adt/selfuncs.c | 15 | ||||
-rw-r--r-- | src/backend/utils/fmgr/fmgr.c | 12 |
3 files changed, 42 insertions, 70 deletions
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index d1f2fe7d958..ca04b13e825 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -3092,21 +3092,18 @@ array_set(ArrayType *array, int nSubscripts, int *indx, /* * array_map() * - * Map an array through an arbitrary function. Return a new array with - * same dimensions and each source element transformed by fn(). Each - * source element is passed as the first argument to fn(); additional - * arguments to be passed to fn() can be specified by the caller. - * The output array can have a different element type than the input. + * Map an array through an arbitrary expression. Return a new array with + * the same dimensions and each source element transformed by the given, + * already-compiled expression. Each source element is placed in the + * innermost_caseval/innermost_casenull fields of the ExprState. * * Parameters are: - * * fcinfo: a function-call data structure pre-constructed by the caller - * to be ready to call the desired function, with everything except the - * first argument position filled in. In particular, flinfo identifies - * the function fn(), and if nargs > 1 then argument positions after the - * first must be preset to the additional values to be passed. The - * first argument position initially holds the input array value. + * * arrayd: Datum representing array argument. + * * exprstate: ExprState representing the per-element transformation. + * * econtext: context for expression evaluation. * * retType: OID of element type of output array. This must be the same as, - * or binary-compatible with, the result type of fn(). + * or binary-compatible with, the result type of the expression. It might + * be different from the input array's element type. * * amstate: workspace for array_map. Must be zeroed by caller before * first call, and not touched after that. * @@ -3116,11 +3113,14 @@ array_set(ArrayType *array, int nSubscripts, int *indx, * * NB: caller must assure that input array is not NULL. NULL elements in * the array are OK however. + * NB: caller should be running in econtext's per-tuple memory context. */ Datum -array_map(FunctionCallInfo fcinfo, Oid retType, ArrayMapState *amstate) +array_map(Datum arrayd, + ExprState *exprstate, ExprContext *econtext, + Oid retType, ArrayMapState *amstate) { - AnyArrayType *v; + AnyArrayType *v = DatumGetAnyArrayP(arrayd); ArrayType *result; Datum *values; bool *nulls; @@ -3141,13 +3141,8 @@ array_map(FunctionCallInfo fcinfo, Oid retType, ArrayMapState *amstate) array_iter iter; ArrayMetaState *inp_extra; ArrayMetaState *ret_extra; - - /* Get input array */ - if (fcinfo->nargs < 1) - elog(ERROR, "invalid nargs: %d", fcinfo->nargs); - if (PG_ARGISNULL(0)) - elog(ERROR, "null input array"); - v = PG_GETARG_ANY_ARRAY_P(0); + Datum *transform_source = exprstate->innermost_caseval; + bool *transform_source_isnull = exprstate->innermost_casenull; inpType = AARR_ELEMTYPE(v); ndim = AARR_NDIM(v); @@ -3158,7 +3153,7 @@ array_map(FunctionCallInfo fcinfo, Oid retType, ArrayMapState *amstate) if (nitems <= 0) { /* Return empty array */ - PG_RETURN_ARRAYTYPE_P(construct_empty_array(retType)); + return PointerGetDatum(construct_empty_array(retType)); } /* @@ -3203,39 +3198,15 @@ array_map(FunctionCallInfo fcinfo, Oid retType, ArrayMapState *amstate) for (i = 0; i < nitems; i++) { - bool callit = true; - /* Get source element, checking for NULL */ - fcinfo->arg[0] = array_iter_next(&iter, &fcinfo->argnull[0], i, - inp_typlen, inp_typbyval, inp_typalign); - - /* - * Apply the given function to source elt and extra args. - */ - if (fcinfo->flinfo->fn_strict) - { - int j; + *transform_source = + array_iter_next(&iter, transform_source_isnull, i, + inp_typlen, inp_typbyval, inp_typalign); - for (j = 0; j < fcinfo->nargs; j++) - { - if (fcinfo->argnull[j]) - { - callit = false; - break; - } - } - } + /* Apply the given expression to source element */ + values[i] = ExecEvalExpr(exprstate, econtext, &nulls[i]); - if (callit) - { - fcinfo->isnull = false; - values[i] = FunctionCallInvoke(fcinfo); - } - else - fcinfo->isnull = true; - - nulls[i] = fcinfo->isnull; - if (fcinfo->isnull) + if (nulls[i]) hasnulls = true; else { @@ -3254,7 +3225,7 @@ array_map(FunctionCallInfo fcinfo, Oid retType, ArrayMapState *amstate) } } - /* Allocate and initialize the result array */ + /* Allocate and fill the result array */ if (hasnulls) { dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nitems); @@ -3273,18 +3244,18 @@ array_map(FunctionCallInfo fcinfo, Oid retType, ArrayMapState *amstate) memcpy(ARR_DIMS(result), AARR_DIMS(v), ndim * sizeof(int)); memcpy(ARR_LBOUND(result), AARR_LBOUND(v), ndim * sizeof(int)); - /* - * Note: do not risk trying to pfree the results of the called function - */ CopyArrayEls(result, values, nulls, nitems, typlen, typbyval, typalign, false); + /* + * Note: do not risk trying to pfree the results of the called expression + */ pfree(values); pfree(nulls); - PG_RETURN_ARRAYTYPE_P(result); + return PointerGetDatum(result); } /* diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index db1792bf8d4..7361e9d43ca 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -1816,10 +1816,19 @@ strip_array_coercion(Node *node) { for (;;) { - if (node && IsA(node, ArrayCoerceExpr) && - ((ArrayCoerceExpr *) node)->elemfuncid == InvalidOid) + if (node && IsA(node, ArrayCoerceExpr)) { - node = (Node *) ((ArrayCoerceExpr *) node)->arg; + ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; + + /* + * If the per-element expression is just a RelabelType on top of + * CaseTestExpr, then we know it's a binary-compatible relabeling. + */ + if (IsA(acoerce->elemexpr, RelabelType) && + IsA(((RelabelType *) acoerce->elemexpr)->arg, CaseTestExpr)) + node = (Node *) acoerce->arg; + else + break; } else if (node && IsA(node, RelabelType)) { diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c index a7b07827e01..919733517bd 100644 --- a/src/backend/utils/fmgr/fmgr.c +++ b/src/backend/utils/fmgr/fmgr.c @@ -1941,8 +1941,6 @@ get_call_expr_argtype(Node *expr, int argnum) args = ((DistinctExpr *) expr)->args; else if (IsA(expr, ScalarArrayOpExpr)) args = ((ScalarArrayOpExpr *) expr)->args; - else if (IsA(expr, ArrayCoerceExpr)) - args = list_make1(((ArrayCoerceExpr *) expr)->arg); else if (IsA(expr, NullIfExpr)) args = ((NullIfExpr *) expr)->args; else if (IsA(expr, WindowFunc)) @@ -1956,16 +1954,12 @@ get_call_expr_argtype(Node *expr, int argnum) argtype = exprType((Node *) list_nth(args, argnum)); /* - * special hack for ScalarArrayOpExpr and ArrayCoerceExpr: what the - * underlying function will actually get passed is the element type of the - * array. + * special hack for ScalarArrayOpExpr: what the underlying function will + * actually get passed is the element type of the array. */ if (IsA(expr, ScalarArrayOpExpr) && argnum == 1) argtype = get_base_element_type(argtype); - else if (IsA(expr, ArrayCoerceExpr) && - argnum == 0) - argtype = get_base_element_type(argtype); return argtype; } @@ -2012,8 +2006,6 @@ get_call_expr_arg_stable(Node *expr, int argnum) args = ((DistinctExpr *) expr)->args; else if (IsA(expr, ScalarArrayOpExpr)) args = ((ScalarArrayOpExpr *) expr)->args; - else if (IsA(expr, ArrayCoerceExpr)) - args = list_make1(((ArrayCoerceExpr *) expr)->arg); else if (IsA(expr, NullIfExpr)) args = ((NullIfExpr *) expr)->args; else if (IsA(expr, WindowFunc)) |