Cache datatype-output-function lookup info across calls of concat().

Testing indicates this can save a third to a half of the runtime
of the function.

Pavel Stehule, reviewed by Alexander Kuzmenkov

Discussion: https://postgr.es/m/CAFj8pRAT62pRgjoHbgTfJUc2uLmeQ4saUj+yVJAEZUiMwNCmdg@mail.gmail.com
This commit is contained in:
Tom Lane 2017-09-19 15:09:34 -04:00
parent 890faaf195
commit ed22fb8b00
1 changed files with 45 additions and 9 deletions

View File

@ -4733,11 +4733,48 @@ string_agg_finalfn(PG_FUNCTION_ARGS)
PG_RETURN_NULL();
}
/*
* Prepare cache with fmgr info for the output functions of the datatypes of
* the arguments of a concat-like function, beginning with argument "argidx".
* (Arguments before that will have corresponding slots in the resulting
* FmgrInfo array, but we don't fill those slots.)
*/
static FmgrInfo *
build_concat_foutcache(FunctionCallInfo fcinfo, int argidx)
{
FmgrInfo *foutcache;
int i;
/* We keep the info in fn_mcxt so it survives across calls */
foutcache = (FmgrInfo *) MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
PG_NARGS() * sizeof(FmgrInfo));
for (i = argidx; i < PG_NARGS(); i++)
{
Oid valtype;
Oid typOutput;
bool typIsVarlena;
valtype = get_fn_expr_argtype(fcinfo->flinfo, i);
if (!OidIsValid(valtype))
elog(ERROR, "could not determine data type of concat() input");
getTypeOutputInfo(valtype, &typOutput, &typIsVarlena);
fmgr_info_cxt(typOutput, &foutcache[i], fcinfo->flinfo->fn_mcxt);
}
fcinfo->flinfo->fn_extra = foutcache;
return foutcache;
}
/*
* Implementation of both concat() and concat_ws().
*
* sepstr is the separator string to place between values.
* argidx identifies the first argument to concatenate (counting from zero).
* argidx identifies the first argument to concatenate (counting from zero);
* note that this must be constant across any one series of calls.
*
* Returns NULL if result should be NULL, else text value.
*/
static text *
@ -4746,6 +4783,7 @@ concat_internal(const char *sepstr, int argidx,
{
text *result;
StringInfoData str;
FmgrInfo *foutcache;
bool first_arg = true;
int i;
@ -4787,14 +4825,16 @@ concat_internal(const char *sepstr, int argidx,
/* Normal case without explicit VARIADIC marker */
initStringInfo(&str);
/* Get output function info, building it if first time through */
foutcache = (FmgrInfo *) fcinfo->flinfo->fn_extra;
if (foutcache == NULL)
foutcache = build_concat_foutcache(fcinfo, argidx);
for (i = argidx; i < PG_NARGS(); i++)
{
if (!PG_ARGISNULL(i))
{
Datum value = PG_GETARG_DATUM(i);
Oid valtype;
Oid typOutput;
bool typIsVarlena;
/* add separator if appropriate */
if (first_arg)
@ -4803,12 +4843,8 @@ concat_internal(const char *sepstr, int argidx,
appendStringInfoString(&str, sepstr);
/* call the appropriate type output function, append the result */
valtype = get_fn_expr_argtype(fcinfo->flinfo, i);
if (!OidIsValid(valtype))
elog(ERROR, "could not determine data type of concat() input");
getTypeOutputInfo(valtype, &typOutput, &typIsVarlena);
appendStringInfoString(&str,
OidOutputFunctionCall(typOutput, value));
OutputFunctionCall(&foutcache[i], value));
}
}