@@ -4733,11 +4733,48 @@ string_agg_finalfn(PG_FUNCTION_ARGS)
47334733 PG_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{
47474784 text * result ;
47484785 StringInfoData str ;
4786+ FmgrInfo * foutcache ;
47494787 bool first_arg = true;
47504788 int i ;
47514789
@@ -4787,14 +4825,16 @@ concat_internal(const char *sepstr, int argidx,
47874825 /* Normal case without explicit VARIADIC marker */
47884826 initStringInfo (& 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+
47904833 for (i = argidx ; i < PG_NARGS (); i ++ )
47914834 {
47924835 if (!PG_ARGISNULL (i ))
47934836 {
47944837 Datum value = PG_GETARG_DATUM (i );
4795- Oid valtype ;
4796- Oid typOutput ;
4797- bool typIsVarlena ;
47984838
47994839 /* add separator if appropriate */
48004840 if (first_arg )
@@ -4803,12 +4843,8 @@ concat_internal(const char *sepstr, int argidx,
48034843 appendStringInfoString (& 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 );
48104846 appendStringInfoString (& str ,
4811- OidOutputFunctionCall ( typOutput , value ));
4847+ OutputFunctionCall ( & foutcache [ i ] , value ));
48124848 }
48134849 }
48144850
0 commit comments