]> granicus.if.org Git - postgresql/commitdiff
Fix concat_ws() to not insert a separator after leading NULL argument(s).
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 29 Aug 2011 19:20:57 +0000 (15:20 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 29 Aug 2011 19:21:15 +0000 (15:21 -0400)
Per bug #6181 from Itagaki Takahiro.  Also do some marginal code cleanup
and improve error handling.

src/backend/utils/adt/varlena.c

index 3677b1c3bbc0f7ff05932feb53504239554ffc58..124000fe7f40051efb39ace85ba6c439d9c04ebb 100644 (file)
@@ -3622,11 +3622,19 @@ string_agg_finalfn(PG_FUNCTION_ARGS)
                PG_RETURN_NULL();
 }
 
+/*
+ * Implementation of both concat() and concat_ws().
+ *
+ * sepstr/seplen describe the separator.  argidx is the first argument
+ * to concatenate (counting from zero).
+ */
 static text *
-concat_internal(const char *sepstr, int seplen, int argidx, FunctionCallInfo fcinfo)
+concat_internal(const char *sepstr, int seplen, int argidx,
+                               FunctionCallInfo fcinfo)
 {
-       StringInfoData str;
        text       *result;
+       StringInfoData str;
+       bool            first_arg = true;
        int                     i;
 
        initStringInfo(&str);
@@ -3635,17 +3643,21 @@ concat_internal(const char *sepstr, int seplen, int argidx, FunctionCallInfo fci
        {
                if (!PG_ARGISNULL(i))
                {
+                       Datum           value = PG_GETARG_DATUM(i);
                        Oid                     valtype;
-                       Datum           value;
                        Oid                     typOutput;
                        bool            typIsVarlena;
 
-                       if (i > argidx)
+                       /* add separator if appropriate */
+                       if (first_arg)
+                               first_arg = false;
+                       else
                                appendBinaryStringInfo(&str, sepstr, seplen);
 
-                       /* append n-th value */
-                       value = PG_GETARG_DATUM(i);
+                       /* 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));
@@ -3664,12 +3676,12 @@ concat_internal(const char *sepstr, int seplen, int argidx, FunctionCallInfo fci
 Datum
 text_concat(PG_FUNCTION_ARGS)
 {
-       PG_RETURN_TEXT_P(concat_internal(NULL, 0, 0, fcinfo));
+       PG_RETURN_TEXT_P(concat_internal("", 0, 0, fcinfo));
 }
 
 /*
- * Concatenate all but first argument values with separators. The first
- * parameter is used as a separator. NULL arguments are ignored.
+ * Concatenate all but first argument value with separators. The first
+ * parameter is used as the separator. NULL arguments are ignored.
  */
 Datum
 text_concat_ws(PG_FUNCTION_ARGS)
@@ -3682,8 +3694,8 @@ text_concat_ws(PG_FUNCTION_ARGS)
 
        sep = PG_GETARG_TEXT_PP(0);
 
-       PG_RETURN_TEXT_P(concat_internal(
-                                          VARDATA_ANY(sep), VARSIZE_ANY_EXHDR(sep), 1, fcinfo));
+       PG_RETURN_TEXT_P(concat_internal(VARDATA_ANY(sep), VARSIZE_ANY_EXHDR(sep),
+                                                                        1, fcinfo));
 }
 
 /*