diff --git a/pkg/sql/logictest/testdata/logic_test/builtin_function b/pkg/sql/logictest/testdata/logic_test/builtin_function index dc06c78dfa91..0eb4228ee680 100644 --- a/pkg/sql/logictest/testdata/logic_test/builtin_function +++ b/pkg/sql/logictest/testdata/logic_test/builtin_function @@ -2480,6 +2480,18 @@ SELECT array_to_string(NULL, ','), array_to_string(NULL, 'foo', 'zerp') ---- NULL NULL +# Builtin array_to_string should recursively search nested arrays. +query T +SELECT array_to_string(ARRAY[ARRAY[ARRAY[5,6], ARRAY[2,3]], ARRAY[ARRAY[7,8], ARRAY[4,44]]], ' '); +---- +5 6 2 3 7 8 4 44 + +# Builtin array_to_string should recursively search nested arrays. +query T +SELECT array_to_string(ARRAY[(SELECT ARRAY[1,2]::int2vector)],' '); +---- +1 2 + subtest pg_is_in_recovery query B colnames diff --git a/pkg/sql/sem/builtins/builtins.go b/pkg/sql/sem/builtins/builtins.go index d2f127430f32..6c1d813fa566 100644 --- a/pkg/sql/sem/builtins/builtins.go +++ b/pkg/sql/sem/builtins/builtins.go @@ -8976,6 +8976,13 @@ func arrayToString( evalCtx *tree.EvalContext, arr *tree.DArray, delim string, nullStr *string, ) (tree.Datum, error) { f := evalCtx.FmtCtx(tree.FmtArrayToString) + arrayToStringHelper(evalCtx, arr, delim, nullStr, f) + return tree.NewDString(f.CloseAndGetString()), nil +} + +func arrayToStringHelper( + evalCtx *tree.EvalContext, arr *tree.DArray, delim string, nullStr *string, f *tree.FmtCtx, +) { for i := range arr.Array { if arr.Array[i] == tree.DNull { @@ -8984,13 +8991,17 @@ func arrayToString( } f.WriteString(*nullStr) } else { - f.FormatNode(arr.Array[i]) + if nestedArray, ok := arr.Array[i].(*tree.DArray); ok { + // "Unpack" nested arrays to be consistent with postgres. + arrayToStringHelper(evalCtx, nestedArray, delim, nullStr, f) + } else { + f.FormatNode(arr.Array[i]) + } } if i < len(arr.Array)-1 { f.WriteString(delim) } } - return tree.NewDString(f.CloseAndGetString()), nil } // encodeEscape implements the encode(..., 'escape') Postgres builtin. It's