How to write a heterogeneous variadic function
1
vote
0
answers
119
views
I am trying to write a postgres stored procedure that can take a variable number of arguments of potentially different types (i.e. a heterogeneous list of arguments). As I learned from here , the heterogeneous variadic argument list is only possible in C.
To learn how to write such a C function, I worked on a simple example that takes the heterogeneous list , converts each argument to a json string, and then returns the concatenated string. My code for this minimal example is listed below.
I think I got the shape of this function right my mimicking how jsonb_build_object() works. But I can't figure out how to convert each argument value to json be and then turn it into a c-string. I tried to adapt the code of the
to_json
function (as indicated by //problem_lines
marker below). But couldn't get the code to even compile.
I am not very familiar with the internals of server side C programming with PostgreSQL (as of 16).
*Could anyone with the expertise help explain how to make the conversion to json string work?*
-- My code so far --
#include "postgres.h"
#include "catalog/pg_type.h"
#include "fmgr.h"
#include "funcapi.h"
//#include "utils/array.h"
// for var_concat
//#include "common/jsonapi.h"
#include "utils/json.h"
#include "utils/jsonb.h"
#include "utils/jsonfuncs.h"
PG_MODULE_MAGIC;
// take a heterogeneous variadic list of values; convert them into json string, and then return the concatenated string
Datum
var_concat_worker(int nargs, const Datum *args, const bool *nulls, const Oid *types,
bool absent_on_null, bool unique_keys)
{
int i;
Jsonb *jb;
char *strVal;
char *result;
int bufLen = 16;
result = (char*)malloc(bufLen*sizeof(char));
Datum val;
if (nargs flinfo, 0);
JsonTypeCategory tcategory;
Oid outfuncoid;
if (val_type == InvalidOid)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("could not determine input data type")));
json_categorize_type(val_type, true, &tcategory, &outfuncoid);
//
jb = datum_to_jsonb(val, tcategory, outfuncoid);
strVal = JsonbToCString(NULL, &jb->root, VARSIZE(jb));
if (strlen(strVal) + strlen(result) >= bufLen) {
bufLen = bufLen * 2;
result = realloc(result, bufLen);
}
strcat(result, strVal);
}
PG_RETURN_CSTRING(result);
}
/* SQL function var_concat(variadic "any") */
Datum
var_concat(PG_FUNCTION_ARGS)
{
Datum *args;
bool *nulls;
Oid *types;
/* build argument values to build the object */
int nargs = extract_variadic_args(fcinfo, 0, true, &args, &types, &nulls);
if (nargs < 0)
PG_RETURN_NULL();
PG_RETURN_DATUM(var_concat_worker(nargs, args, nulls, types, false, false));
}
Related:
https://dba.stackexchange.com/questions/264327
Asked by tinlyx
(3820 rep)
Oct 31, 2023, 02:02 AM