summaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/varlena.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/varlena.c')
-rw-r--r--src/backend/utils/adt/varlena.c77
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));
}
/*