@@ -4733,11 +4733,48 @@ string_agg_finalfn(PG_FUNCTION_ARGS)
47334733PG_RETURN_NULL ();
47344734}
47354735
4736+ /*
4737+ * Prepare cache with fmgr info for the output functions of the datatypes of
4738+ * the arguments of a concat-like function, beginning with argument "argidx".
4739+ * (Arguments before that will have corresponding slots in the resulting
4740+ * FmgrInfo array, but we don't fill those slots.)
4741+ */
4742+ static FmgrInfo *
4743+ build_concat_foutcache (FunctionCallInfo fcinfo ,int argidx )
4744+ {
4745+ FmgrInfo * foutcache ;
4746+ int i ;
4747+
4748+ /* We keep the info in fn_mcxt so it survives across calls */
4749+ foutcache = (FmgrInfo * )MemoryContextAlloc (fcinfo -> flinfo -> fn_mcxt ,
4750+ PG_NARGS ()* sizeof (FmgrInfo ));
4751+
4752+ for (i = argidx ;i < PG_NARGS ();i ++ )
4753+ {
4754+ Oid valtype ;
4755+ Oid typOutput ;
4756+ bool typIsVarlena ;
4757+
4758+ valtype = get_fn_expr_argtype (fcinfo -> flinfo ,i );
4759+ if (!OidIsValid (valtype ))
4760+ elog (ERROR ,"could not determine data type of concat() input" );
4761+
4762+ getTypeOutputInfo (valtype ,& typOutput ,& typIsVarlena );
4763+ fmgr_info_cxt (typOutput ,& foutcache [i ],fcinfo -> flinfo -> fn_mcxt );
4764+ }
4765+
4766+ fcinfo -> flinfo -> fn_extra = foutcache ;
4767+
4768+ return foutcache ;
4769+ }
4770+
47364771/*
47374772 * Implementation of both concat() and concat_ws().
47384773 *
47394774 * sepstr is the separator string to place between values.
4740- * argidx identifies the first argument to concatenate (counting from zero).
4775+ * argidx identifies the first argument to concatenate (counting from zero);
4776+ * note that this must be constant across any one series of calls.
4777+ *
47414778 * Returns NULL if result should be NULL, else text value.
47424779 */
47434780static text *
@@ -4746,6 +4783,7 @@ concat_internal(const char *sepstr, int argidx,
47464783{
47474784text * result ;
47484785StringInfoData str ;
4786+ FmgrInfo * foutcache ;
47494787bool first_arg = true;
47504788int i ;
47514789
@@ -4787,14 +4825,16 @@ concat_internal(const char *sepstr, int argidx,
47874825/* Normal case without explicit VARIADIC marker */
47884826initStringInfo (& str );
47894827
4828+ /* Get output function info, building it if first time through */
4829+ foutcache = (FmgrInfo * )fcinfo -> flinfo -> fn_extra ;
4830+ if (foutcache == NULL )
4831+ foutcache = build_concat_foutcache (fcinfo ,argidx );
4832+
47904833for (i = argidx ;i < PG_NARGS ();i ++ )
47914834{
47924835if (!PG_ARGISNULL (i ))
47934836{
47944837Datum value = PG_GETARG_DATUM (i );
4795- Oid valtype ;
4796- Oid typOutput ;
4797- bool typIsVarlena ;
47984838
47994839/* add separator if appropriate */
48004840if (first_arg )
@@ -4803,12 +4843,8 @@ concat_internal(const char *sepstr, int argidx,
48034843appendStringInfoString (& str ,sepstr );
48044844
48054845/* call the appropriate type output function, append the result */
4806- valtype = get_fn_expr_argtype (fcinfo -> flinfo ,i );
4807- if (!OidIsValid (valtype ))
4808- elog (ERROR ,"could not determine data type of concat() input" );
4809- getTypeOutputInfo (valtype ,& typOutput ,& typIsVarlena );
48104846appendStringInfoString (& str ,
4811- OidOutputFunctionCall ( typOutput ,value ));
4847+ OutputFunctionCall ( & foutcache [ i ] ,value ));
48124848}
48134849}
48144850