On 10/22/2017 04:35 PM, Michael Paquier wrote:
> On Mon, Oct 23, 2017 at 1:44 AM, Andrew Dunstan
> <[email protected]> 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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers