On 10/22/2017 04:35 PM, Michael Paquier wrote: > On Mon, Oct 23, 2017 at 1:44 AM, Andrew Dunstan > <andrew.duns...@2ndquadrant.com> wrote: > >> here's a patch that works that way, based on Michael's code. > Patch not attached :) > I still have a patch half-cooked, that I can send if necessary, but > you are on it, right?
Sorry. Here it is. cheers andrew -- Andrew Dunstan https://www.2ndQuadrant.com PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c index 9c3f451..dfd5d8c 100644 --- a/src/backend/utils/fmgr/funcapi.c +++ b/src/backend/utils/fmgr/funcapi.c @@ -1400,3 +1400,120 @@ TypeGetTupleDesc(Oid typeoid, List *colaliases) return tupdesc; } + +/* + * Extract a set of variadic argument values, types and NULL markers. This is + * useful for abstracting away whether or not the call has been done + * with an explicit VARIADIC array or a normal set of arguments, for a + * VARIADIC "any" function. When doing a VARIADIC call, the caller has + * provided one argument made of an array of keys, so deconstruct the + * array data before using it for the next processing. + * If no explicit VARIADIC call is used, just fill in the data based on + * all the arguments given by the caller. + * This function returns the number of arguments generated. In the event + * where the caller provided a NULL array input, return -1. + * nfixed is the number of non-variadic arguments to the function - these + * will be ignored by this function. + * If required by the caller, values of type "unknown" will be converted + * to text datums. + */ +int +extract_variadic_args(FunctionCallInfo fcinfo, Datum **args, + Oid **types, bool **nulls, int nfixed, + bool convert_unknown_to_text) +{ + bool variadic = get_fn_expr_variadic(fcinfo->flinfo); + Datum *args_res; + bool *nulls_res; + Oid *types_res; + int nargs, i; + + *args = NULL; + *types = NULL; + *nulls = NULL; + + if (variadic) + { + ArrayType *array_in; + Oid element_type; + bool typbyval; + char typalign; + int16 typlen; + + Assert(PG_NARGS() == nfixed + 1); + + if (PG_ARGISNULL(nfixed)) + return -1; + + array_in = PG_GETARG_ARRAYTYPE_P(nfixed); + element_type = ARR_ELEMTYPE(array_in); + + get_typlenbyvalalign(element_type, + &typlen, &typbyval, &typalign); + deconstruct_array(array_in, element_type, typlen, typbyval, + typalign, &args_res, &nulls_res, + &nargs); + + /* All the elements of the array have the same type */ + types_res = (Oid *) palloc0(nargs * sizeof(Oid)); + for (i = 0; i < nargs; i++) + types_res[i] = element_type; + } + else + { + nargs = PG_NARGS() - nfixed; + Assert (nargs > 0); + nulls_res = (bool *) palloc0(nargs * sizeof(bool)); + args_res = (Datum *) palloc0(nargs * sizeof(Datum)); + types_res = (Oid *) palloc0(nargs * sizeof(Oid)); + + for (i = 0; i < nargs; i++) + { + nulls_res[i] = PG_ARGISNULL(i + nfixed); + types_res[i] = get_fn_expr_argtype(fcinfo->flinfo, i + nfixed); + + if (!OidIsValid(types_res[i])) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("could not determine data type for argument %d", + i + nfixed + 1))); + + /* + * Turn a constant (more or less literal) value that's of unknown + * type into text if required . Unknowns come in as a cstring + * pointer. + */ + if (convert_unknown_to_text && types_res[i] == UNKNOWNOID && + get_fn_expr_arg_stable(fcinfo->flinfo, i + nfixed)) + { + types_res[i] = TEXTOID; + + /* important for value, key cannot being NULL */ + if (PG_ARGISNULL(i + nfixed)) + args_res[i] = (Datum) 0; + else + args_res[i] = + CStringGetTextDatum(PG_GETARG_POINTER(i + nfixed)); + } + else + { + /* no conversion needed, just take the datum as given */ + args_res[i] = PG_GETARG_DATUM(i + nfixed); + } + + if (!OidIsValid(types_res[i]) || + (convert_unknown_to_text && (types_res[i] == UNKNOWNOID))) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("could not determine data type for argument %d", + i + nfixed + 1))); + } + } + + /* Fill in results */ + *args = args_res; + *nulls = nulls_res; + *types = types_res; + + return nargs; +} diff --git a/src/include/funcapi.h b/src/include/funcapi.h index 951af2a..0550c07 100644 --- a/src/include/funcapi.h +++ b/src/include/funcapi.h @@ -281,6 +281,9 @@ extern TupleTableSlot *TupleDescGetSlot(TupleDesc tupdesc); extern FuncCallContext *init_MultiFuncCall(PG_FUNCTION_ARGS); extern FuncCallContext *per_MultiFuncCall(PG_FUNCTION_ARGS); extern void end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx); +extern int extract_variadic_args(FunctionCallInfo fcinfo, Datum **args, + Oid **types, bool **nulls, int nfixed, + bool convert_unknown_to_text); #define SRF_IS_FIRSTCALL() (fcinfo->flinfo->fn_extra == NULL)
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers