@@ -4733,11 +4733,48 @@ string_agg_finalfn(PG_FUNCTION_ARGS)
4733
4733
PG_RETURN_NULL ();
4734
4734
}
4735
4735
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
+
4736
4771
/*
4737
4772
* Implementation of both concat() and concat_ws().
4738
4773
*
4739
4774
* 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
+ *
4741
4778
* Returns NULL if result should be NULL, else text value.
4742
4779
*/
4743
4780
static text *
@@ -4746,6 +4783,7 @@ concat_internal(const char *sepstr, int argidx,
4746
4783
{
4747
4784
text * result ;
4748
4785
StringInfoData str ;
4786
+ FmgrInfo * foutcache ;
4749
4787
bool first_arg = true;
4750
4788
int i ;
4751
4789
@@ -4787,14 +4825,16 @@ concat_internal(const char *sepstr, int argidx,
4787
4825
/* Normal case without explicit VARIADIC marker */
4788
4826
initStringInfo (& str );
4789
4827
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
+
4790
4833
for (i = argidx ; i < PG_NARGS (); i ++ )
4791
4834
{
4792
4835
if (!PG_ARGISNULL (i ))
4793
4836
{
4794
4837
Datum value = PG_GETARG_DATUM (i );
4795
- Oid valtype ;
4796
- Oid typOutput ;
4797
- bool typIsVarlena ;
4798
4838
4799
4839
/* add separator if appropriate */
4800
4840
if (first_arg )
@@ -4803,12 +4843,8 @@ concat_internal(const char *sepstr, int argidx,
4803
4843
appendStringInfoString (& str , sepstr );
4804
4844
4805
4845
/* 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 );
4810
4846
appendStringInfoString (& str ,
4811
- OidOutputFunctionCall ( typOutput , value ));
4847
+ OutputFunctionCall ( & foutcache [ i ] , value ));
4812
4848
}
4813
4849
}
4814
4850
0 commit comments