Skip to content

Commit

Permalink
builtins: array_to_string should traverse nested arrays
Browse files Browse the repository at this point in the history
Fixes #95588

In Postgres, `array_to_string` traverses nested arrays and prints
their contents. In CRDB, the nested array structures are printed
out. For example,
`SELECT array_to_string(ARRAY[ARRAY[ARRAY[5,6], ARRAY[2,3]]], ' ');`

CRDB Result: `ARRAY[ARRAY[5:::INT8,6:::INT8],ARRAY[2:::INT8,3:::INT8]]`
Postgres Result: `5 6 2 3`

This fix brings the behavior of `array_to_string` in line with
Postgres, and avoids printing the nested ARRAY structures.

Some tools like GoldenGate rely on Postgres-compatible  behavior of
`array_to_string` for proper functioning.

Release note (bug fix): This patch fixes the array_to_string built-in
function so that nested arrays are traversed without printing 'ARRAY'
at each nesting level.
  • Loading branch information
Mark Sirek committed Jan 25, 2023
1 parent 782f94a commit eb88269
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 2 deletions.
12 changes: 12 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/builtin_function
Original file line number Diff line number Diff line change
Expand Up @@ -2517,6 +2517,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

# Examples from https://www.postgresql.org/docs/9.3/functions-string.html#FUNCTIONS-STRING-FORMAT
query T
SELECT format('Hello %s', 'World')
Expand Down
15 changes: 13 additions & 2 deletions pkg/sql/sem/builtins/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -9857,6 +9857,13 @@ func arrayToString(
evalCtx *eval.Context, 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 *eval.Context, arr *tree.DArray, delim string, nullStr *string, f *tree.FmtCtx,
) {

for i := range arr.Array {
if arr.Array[i] == tree.DNull {
Expand All @@ -9865,13 +9872,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
Expand Down

0 comments on commit eb88269

Please sign in to comment.