Skip to content

Commit 91ce49a

Browse files
committed
builtins: change concat_ws() to accept arguments of types.Any type
Previously, concat_ws() required all arguments to be of type string, this patch changes the requirement such that the first argument (the delimiter) must be a string but that all follow-on arguments may be of any type. Release note (sql change): concat_ws() now accepts arguments of any type in the second and later positions (the separator must still be a string).
1 parent de2df36 commit 91ce49a

File tree

4 files changed

+17
-16
lines changed

4 files changed

+17
-16
lines changed

docs/generated/sql/functions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2914,7 +2914,7 @@ Can be used to define the tile bounds required by ST_AsMVTGeom to convert geomet
29142914
</span></td><td>Immutable</td></tr>
29152915
<tr><td><a name="concat"></a><code>concat(any...) &rarr; <a href="string.html">string</a></code></td><td><span class="funcdesc"><p>Concatenates a comma-separated list of strings.</p>
29162916
</span></td><td>Immutable</td></tr>
2917-
<tr><td><a name="concat_ws"></a><code>concat_ws(<a href="string.html">string</a>...) &rarr; <a href="string.html">string</a></code></td><td><span class="funcdesc"><p>Uses the first argument as a separator between the concatenation of the subsequent arguments.</p>
2917+
<tr><td><a name="concat_ws"></a><code>concat_ws(<a href="string.html">string</a>, any...) &rarr; <a href="string.html">string</a></code></td><td><span class="funcdesc"><p>Uses the first argument as a separator between the concatenation of the subsequent arguments.</p>
29182918
<p>For example <code>concat_ws('!','wow','great')</code> returns <code>wow!great</code>.</p>
29192919
</span></td><td>Immutable</td></tr>
29202920
<tr><td><a name="convert_from"></a><code>convert_from(str: <a href="bytes.html">bytes</a>, enc: <a href="string.html">string</a>) &rarr; <a href="string.html">string</a></code></td><td><span class="funcdesc"><p>Decode the bytes in <code>str</code> into a string using encoding <code>enc</code>. Supports encodings ‘UTF8’ and ‘LATIN1’.</p>

pkg/sql/logictest/testdata/logic_test/builtin_function

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,8 +428,10 @@ SELECT concat_ws(',', 'abcde', '2')
428428
----
429429
abcde,2
430430

431-
statement error unknown signature: concat_ws\(string, string, int, unknown, int\)
431+
query T
432432
SELECT concat_ws(',', 'abcde', 2, NULL, 22)
433+
----
434+
abcde,2,22
433435

434436
query T
435437
SELECT split_part('abc~@~def~@~ghi', '~@~', 2)

pkg/sql/sem/builtins/builtins.go

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ var regularBuiltins = map[string]builtinDefinition{
472472
"concat_ws": makeBuiltin(
473473
defProps(),
474474
tree.Overload{
475-
Types: tree.VariadicType{VarType: types.String},
475+
Types: tree.VariadicType{FixedTypes: []*types.T{types.String}, VarType: types.Any},
476476
ReturnType: tree.FixedReturnType(types.String),
477477
Fn: func(_ context.Context, _ *eval.Context, args tree.Datums) (tree.Datum, error) {
478478
if len(args) == 0 {
@@ -481,25 +481,24 @@ var regularBuiltins = map[string]builtinDefinition{
481481
if args[0] == tree.DNull {
482482
return tree.DNull, nil
483483
}
484-
sep := string(tree.MustBeDString(args[0]))
485-
var buf bytes.Buffer
486-
prefix := ""
487-
length := 0
484+
sep := tree.MustBeDString(args[0])
485+
ctx := tree.NewFmtCtx(tree.FmtPgwireText)
486+
prefix := false
488487
for _, d := range args[1:] {
489488
if d == tree.DNull {
490489
continue
491490
}
492-
length += len(prefix) + len(string(tree.MustBeDString(d)))
493-
if length > builtinconstants.MaxAllocatedStringSize {
491+
if ctx.Buffer.Len()+int(d.Size())+int(sep.Size()) > builtinconstants.MaxAllocatedStringSize {
494492
return nil, errStringTooLarge
495493
}
496-
// Note: we can't use the range index here because that
497-
// would break when the 2nd argument is NULL.
498-
buf.WriteString(prefix)
499-
prefix = sep
500-
buf.WriteString(string(tree.MustBeDString(d)))
494+
if prefix {
495+
sep.Format(ctx)
496+
} else {
497+
prefix = true
498+
}
499+
d.Format(ctx)
501500
}
502-
return tree.NewDString(buf.String()), nil
501+
return tree.NewDString(ctx.CloseAndGetString()), nil
503502
},
504503
Info: "Uses the first argument as a separator between the concatenation of the " +
505504
"subsequent arguments. \n\nFor example `concat_ws('!','wow','great')` " +

pkg/sql/sem/builtins/fixed_oids.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -822,7 +822,7 @@ var builtinOidsArray = []string{
822822
846: `substring(input: bytes, start_pos: int) -> bytes`,
823823
847: `substring(input: bytes, start_pos: int, length: int) -> bytes`,
824824
848: `concat(any...) -> string`,
825-
849: `concat_ws(string...) -> string`,
825+
849: `concat_ws(string, any...) -> string`,
826826
850: `convert_from(str: bytes, enc: string) -> string`,
827827
851: `convert_to(str: string, enc: string) -> bytes`,
828828
852: `get_bit(bit_string: varbit, index: int) -> int`,

0 commit comments

Comments
 (0)