diff options
Diffstat (limited to 'src/backend/utils/adt/varlena.c')
| -rw-r--r-- | src/backend/utils/adt/varlena.c | 77 |
1 files changed, 38 insertions, 39 deletions
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index 8683188df1..09d7c7e858 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -30,6 +30,7 @@ #include "regex/regex.h" #include "utils/builtins.h" #include "utils/bytea.h" +#include "utils/expandedstring.h" #include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/pg_locale.h" @@ -4357,16 +4358,6 @@ pg_column_size(PG_FUNCTION_ARGS) PG_RETURN_INT32(result); } -/* - * string_agg - Concatenates values and returns string. - * - * Syntax: string_agg(value text, delimiter text) RETURNS text - * - * Note: Any NULL values are ignored. The first-call delimiter isn't - * actually used at all, and on subsequent calls the delimiter precedes - * the associated value. - */ - /* subroutine to initialize state */ static StringInfo makeStringAggState(FunctionCallInfo fcinfo) @@ -4392,46 +4383,54 @@ makeStringAggState(FunctionCallInfo fcinfo) return state; } +/* + * string_agg - Concatenates values and returns string. + * + * Syntax: string_agg(value text, delimiter text) RETURNS text + * + * Note: Any NULL values are ignored. The first-call delimiter isn't + * actually used at all, and on subsequent calls the delimiter precedes + * the associated value. + */ Datum string_agg_transfn(PG_FUNCTION_ARGS) { - StringInfo state; + ExpandedStringInfoHeader *state; - state = PG_ARGISNULL(0) ? NULL : (StringInfo) PG_GETARG_POINTER(0); - - /* Append the value unless null. */ - if (!PG_ARGISNULL(1)) + /* If the second argument is NULL, just return the first argument. */ + if (PG_ARGISNULL(1)) { - /* On the first time through, we ignore the delimiter. */ - if (state == NULL) - state = makeStringAggState(fcinfo); - else if (!PG_ARGISNULL(2)) - appendStringInfoText(state, PG_GETARG_TEXT_PP(2)); /* delimiter */ - - appendStringInfoText(state, PG_GETARG_TEXT_PP(1)); /* value */ + if (PG_ARGISNULL(0)) + PG_RETURN_NULL(); + PG_RETURN_DATUM(PG_GETARG_DATUM(0)); } /* - * The transition type for string_agg() is declared to be "internal", - * which is a pass-by-value type the same size as a pointer. + * Expand the first argument if needed; then, add any delimeter (unless + * the first argument is NULL). */ - PG_RETURN_POINTER(state); -} - -Datum -string_agg_finalfn(PG_FUNCTION_ARGS) -{ - StringInfo state; - - /* cannot be called directly because of internal-type argument */ - Assert(AggCheckCallContext(fcinfo, NULL)); + if (!PG_ARGISNULL(0) && VARATT_IS_EXTERNAL_EXPANDED_RW(PG_GETARG_DATUM(0))) + { + state = (ExpandedStringInfoHeader *) DatumGetEOHP(PG_GETARG_DATUM(0)); + if (!PG_ARGISNULL(2)) + appendStringInfoText(&state->buf, PG_GETARG_TEXT_PP(2)); + } + else + { + state = GetExpandedStringInfo(); + /* Note that if the transition state is NULL, we skip the delimiter. */ + if (!PG_ARGISNULL(0)) + { + appendStringInfoText(&state->buf, PG_GETARG_TEXT_PP(0)); + if (!PG_ARGISNULL(2)) + appendStringInfoText(&state->buf, PG_GETARG_TEXT_PP(2)); + } + } - state = PG_ARGISNULL(0) ? NULL : (StringInfo) PG_GETARG_POINTER(0); + /* Append second argument to first. */ + appendStringInfoText(&state->buf, PG_GETARG_TEXT_PP(1)); - if (state != NULL) - PG_RETURN_TEXT_P(cstring_to_text_with_len(state->data, state->len)); - else - PG_RETURN_NULL(); + PG_RETURN_DATUM(EOHPGetRWDatum(&state->hdr)); } /* |
