From 43cec5f3eb81f0fcb907176b1adf2f33ad9c4d17 Mon Sep 17 00:00:00 2001 From: James Cor Date: Fri, 12 Jan 2024 00:23:51 -0800 Subject: [PATCH 01/11] fix number overflow and add unit tests --- sql/expression/function/char.go | 130 ++++++++++++++++++++ sql/expression/function/char_test.go | 176 +++++++++++++++++++++++++++ sql/expression/function/registry.go | 1 + sql/types/number.go | 4 +- 4 files changed, 309 insertions(+), 2 deletions(-) create mode 100644 sql/expression/function/char.go create mode 100644 sql/expression/function/char_test.go diff --git a/sql/expression/function/char.go b/sql/expression/function/char.go new file mode 100644 index 0000000000..4afb7c4ffe --- /dev/null +++ b/sql/expression/function/char.go @@ -0,0 +1,130 @@ +// Copyright 2024 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package function + +import ( + "fmt" + "strings" + + "github.com/dolthub/go-mysql-server/sql" + "github.com/dolthub/go-mysql-server/sql/types" +) + +// Char implements the sql function "char" which returns the character for each integer passed +type Char struct { + // TODO: support using (charset/collation) clause + args []sql.Expression +} + +var _ sql.FunctionExpression = (*Char)(nil) +var _ sql.CollationCoercible = (*Char)(nil) + +func NewChar(args ...sql.Expression) (sql.Expression, error) { + return &Char{args: args}, nil +} + +// FunctionName implements sql.FunctionExpression +func (c *Char) FunctionName() string { + return "char" +} + +// Resolved implements sql.FunctionExpression +func (c *Char) Resolved() bool { + for _, arg := range c.args { + if !arg.Resolved() { + return false + } + } + return true +} + +// String implements sql.Expression +func (c *Char) String() string { + args := make([]string, len(c.args)) + for i, arg := range c.args { + args[i] = arg.String() + } + str := strings.Join(args, ", ") + return fmt.Sprintf("%s(%s)", c.FunctionName(), str) +} + +// Type implements sql.Expression +func (c *Char) Type() sql.Type { + return types.LongBlob +} + +// IsNullable implements sql.Expression +func (c *Char) IsNullable() bool { + return true +} + +// Description implements sql.FunctionExpression +func (c *Char) Description() string { + return "returns the numeric value of the leftmost character." +} + +// CollationCoercibility implements the interface sql.CollationCoercible. +func (c *Char) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { + return sql.Collation_binary, 5 +} + +func char(num uint32) []byte { + res := []byte{} + for num > 0 { + res = append([]byte{byte(num % 256)}, res...) + num = num / 256 + } + return res +} + +// Eval implements the sql.Expression interface +func (c *Char) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { + res := []byte{} + for _, arg := range c.args { + if arg == nil { + continue + } + + val, err := arg.Eval(ctx, row) + if err != nil { + return nil, err + } + + if val == nil { + continue + } + + v, _, err := types.Uint32.Convert(val) + if err != nil { + ctx.Warn(1292, "Truncated incorrect INTEGER value: '%v'", val) + res = append(res, 0) + continue + } + + res = append(res, char(v.(uint32))...) + } + + return res, nil +} + +// Children implements sql.Expression +func (c *Char) Children() []sql.Expression { + return c.args +} + +// WithChildren implements the sql.Expression interface +func (c *Char) WithChildren(children ...sql.Expression) (sql.Expression, error) { + return NewChar(children...) +} \ No newline at end of file diff --git a/sql/expression/function/char_test.go b/sql/expression/function/char_test.go new file mode 100644 index 0000000000..e0d36917d4 --- /dev/null +++ b/sql/expression/function/char_test.go @@ -0,0 +1,176 @@ +// Copyright 2024 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package function + +import ( + "github.com/shopspring/decimal" +"testing" + + "github.com/stretchr/testify/require" + + "github.com/dolthub/go-mysql-server/sql" + "github.com/dolthub/go-mysql-server/sql/expression" + "github.com/dolthub/go-mysql-server/sql/types" +) + +func TestChar(t *testing.T) { + tests := []struct { + name string + args []sql.Expression + exp interface{} + err bool + skip bool + }{ + { + name: "null", + args: []sql.Expression{ + nil, + }, + exp: []byte{}, + }, + { + name: "null literal", + args: []sql.Expression{ + expression.NewLiteral(nil, types.Null), + }, + exp: []byte{}, + }, + { + name: "nulls are skipped", + args: []sql.Expression{ + expression.NewLiteral(int32(1), types.Int32), + expression.NewLiteral(nil, types.Null), + expression.NewLiteral(int32(300), types.Int32), + expression.NewLiteral(int32(4000), types.Int32), + }, + exp: []byte{0x1, 0x01, 0x2c, 0xf, 0xa0}, + }, + { + name: "-1", + args: []sql.Expression{ + expression.NewLiteral(int32(-1), types.Int32), + }, + exp: []byte{0xff, 0xff, 0xff, 0xff}, + }, + { + name: "256", + args: []sql.Expression{ + expression.NewLiteral(int32(256), types.Int32), + }, + exp: []byte{0x1, 0x0}, + }, + { + name: "512", + args: []sql.Expression{ + expression.NewLiteral(int32(512), types.Int32), + }, + exp: []byte{0x2, 0x0}, + }, + { + name: "256 * 256", + args: []sql.Expression{ + expression.NewLiteral(int32(256 * 256), types.Int32), + }, + exp: []byte{0x1, 0x0, 0x0}, + }, + { + name: "1 2 3 4", + args: []sql.Expression{ + expression.NewLiteral(int32(1), types.Int32), + expression.NewLiteral(int32(2), types.Int32), + expression.NewLiteral(int32(3), types.Int32), + expression.NewLiteral(int32(4), types.Int32), + }, + exp: []byte{0x1, 0x2, 0x3, 0x4}, + }, + { + name: "1 20 300 4000", + args: []sql.Expression{ + expression.NewLiteral(int32(1), types.Int32), + expression.NewLiteral(int32(20), types.Int32), + expression.NewLiteral(int32(300), types.Int32), + expression.NewLiteral(int32(4000), types.Int32), + }, + exp: []byte{0x1, 0x14, 0x1, 0x2c, 0xf, 0xa0}, + }, + { + name: "float32 1.99", + args: []sql.Expression{ + expression.NewLiteral(float32(1.99), types.Float32), + }, + exp: []byte{0x2}, + }, + { + name: "float64 1.99", + args: []sql.Expression{ + expression.NewLiteral(1.99, types.Float64), + }, + exp: []byte{0x2}, + }, + { + name: "decimal 1.99", + args: []sql.Expression{ + expression.NewLiteral(decimal.NewFromFloat(1.99), types.DecimalType_{}), + }, + exp: []byte{0x2}, + }, + { + name: "good string", + args: []sql.Expression{ + expression.NewLiteral("12", types.Text), + }, + exp: []byte{0x0C}, + }, + { + name: "bad string", + args: []sql.Expression{ + expression.NewLiteral("abc", types.Text), + }, + exp: []byte{0x0}, + }, + { + name: "mix types", + args: []sql.Expression{ + expression.NewLiteral(1, types.Int32), + expression.NewLiteral(9999, types.Int32), + expression.NewLiteral(1.23, types.Int32), + expression.NewLiteral("78", types.Text), + expression.NewLiteral("abc", types.Text), + }, + exp: []byte{0x01, 0x27, 0x0F, 0x01, 0x4E, 0x0}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.skip { + t.Skip() + } + + ctx := sql.NewEmptyContext() + f, err := NewChar(tt.args...) + require.NoError(t, err) + + res, err := f.Eval(ctx, nil) + if tt.err { + require.Error(t, err) + return + } + + require.NoError(t, err) + require.Equal(t, tt.exp, res) + }) + } +} \ No newline at end of file diff --git a/sql/expression/function/registry.go b/sql/expression/function/registry.go index d4bf0c786b..c69e345b76 100644 --- a/sql/expression/function/registry.go +++ b/sql/expression/function/registry.go @@ -48,6 +48,7 @@ var BuiltIns = []sql.Function{ sql.Function1{Name: "bit_xor", Fn: func(e sql.Expression) sql.Expression { return aggregation.NewBitXor(e) }}, sql.Function1{Name: "ceil", Fn: NewCeil}, sql.Function1{Name: "ceiling", Fn: NewCeil}, + sql.FunctionN{Name: "char", Fn: NewChar}, sql.Function1{Name: "char_length", Fn: NewCharLength}, sql.Function1{Name: "character_length", Fn: NewCharLength}, sql.FunctionN{Name: "coalesce", Fn: NewCoalesce}, diff --git a/sql/types/number.go b/sql/types/number.go index 607a4628d4..e7870fa07c 100644 --- a/sql/types/number.go +++ b/sql/types/number.go @@ -1031,14 +1031,14 @@ func convertToUint32(t NumberTypeImpl_, v interface{}) (uint32, sql.ConvertInRan return uint32(v), sql.InRange, nil case int32: if v < 0 { - return uint32(math.MaxUint32 + uint(v)), sql.OutOfRange, nil + return uint32(math.MaxUint32 - uint(-v-1)), sql.OutOfRange, nil } else if int(v) > math.MaxUint32 { return uint32(math.MaxUint32), sql.OutOfRange, nil } return uint32(v), sql.InRange, nil case int64: if v < 0 { - return uint32(math.MaxUint32 + uint(v)), sql.OutOfRange, nil + return uint32(math.MaxUint32 - uint(-v-1)), sql.OutOfRange, nil } else if v > math.MaxUint32 { return uint32(math.MaxUint32), sql.OutOfRange, nil } From 07dd52fec11dac3823de529f6672fee08dc71893 Mon Sep 17 00:00:00 2001 From: James Cor Date: Fri, 12 Jan 2024 00:29:24 -0800 Subject: [PATCH 02/11] enginetest --- enginetest/queries/queries.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/enginetest/queries/queries.go b/enginetest/queries/queries.go index c38a4291e3..2ed6925926 100644 --- a/enginetest/queries/queries.go +++ b/enginetest/queries/queries.go @@ -8818,6 +8818,14 @@ from typestable`, {"6.141592653589793"}, }, }, + { + Query: "select char(i, i + 10, pi()) from mytable", + Expected: []sql.Row{ + {[]byte{0x01, 0x0B, 0x03}}, + {[]byte{0x02, 0x0C, 0x03}}, + {[]byte{0x03, 0x0D, 0x03}}, + }, + }, } var KeylessQueries = []QueryTest{ From 7e263380250d461ab99e0fa0b2ab676e3de3b414 Mon Sep 17 00:00:00 2001 From: jycor Date: Fri, 12 Jan 2024 08:42:50 +0000 Subject: [PATCH 03/11] [ga-format-pr] Run ./format_repo.sh to fix formatting --- sql/expression/function/char.go | 2 +- sql/expression/function/char_test.go | 38 ++++++++++++++-------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/sql/expression/function/char.go b/sql/expression/function/char.go index 4afb7c4ffe..77be574d7f 100644 --- a/sql/expression/function/char.go +++ b/sql/expression/function/char.go @@ -127,4 +127,4 @@ func (c *Char) Children() []sql.Expression { // WithChildren implements the sql.Expression interface func (c *Char) WithChildren(children ...sql.Expression) (sql.Expression, error) { return NewChar(children...) -} \ No newline at end of file +} diff --git a/sql/expression/function/char_test.go b/sql/expression/function/char_test.go index e0d36917d4..100aa5e535 100644 --- a/sql/expression/function/char_test.go +++ b/sql/expression/function/char_test.go @@ -15,9 +15,9 @@ package function import ( - "github.com/shopspring/decimal" -"testing" + "testing" + "github.com/shopspring/decimal" "github.com/stretchr/testify/require" "github.com/dolthub/go-mysql-server/sql" @@ -38,14 +38,14 @@ func TestChar(t *testing.T) { args: []sql.Expression{ nil, }, - exp: []byte{}, + exp: []byte{}, }, { name: "null literal", args: []sql.Expression{ expression.NewLiteral(nil, types.Null), }, - exp: []byte{}, + exp: []byte{}, }, { name: "nulls are skipped", @@ -55,35 +55,35 @@ func TestChar(t *testing.T) { expression.NewLiteral(int32(300), types.Int32), expression.NewLiteral(int32(4000), types.Int32), }, - exp: []byte{0x1, 0x01, 0x2c, 0xf, 0xa0}, + exp: []byte{0x1, 0x01, 0x2c, 0xf, 0xa0}, }, { name: "-1", args: []sql.Expression{ expression.NewLiteral(int32(-1), types.Int32), }, - exp: []byte{0xff, 0xff, 0xff, 0xff}, + exp: []byte{0xff, 0xff, 0xff, 0xff}, }, { name: "256", args: []sql.Expression{ expression.NewLiteral(int32(256), types.Int32), }, - exp: []byte{0x1, 0x0}, + exp: []byte{0x1, 0x0}, }, { name: "512", args: []sql.Expression{ expression.NewLiteral(int32(512), types.Int32), }, - exp: []byte{0x2, 0x0}, + exp: []byte{0x2, 0x0}, }, { name: "256 * 256", args: []sql.Expression{ - expression.NewLiteral(int32(256 * 256), types.Int32), + expression.NewLiteral(int32(256*256), types.Int32), }, - exp: []byte{0x1, 0x0, 0x0}, + exp: []byte{0x1, 0x0, 0x0}, }, { name: "1 2 3 4", @@ -93,7 +93,7 @@ func TestChar(t *testing.T) { expression.NewLiteral(int32(3), types.Int32), expression.NewLiteral(int32(4), types.Int32), }, - exp: []byte{0x1, 0x2, 0x3, 0x4}, + exp: []byte{0x1, 0x2, 0x3, 0x4}, }, { name: "1 20 300 4000", @@ -103,42 +103,42 @@ func TestChar(t *testing.T) { expression.NewLiteral(int32(300), types.Int32), expression.NewLiteral(int32(4000), types.Int32), }, - exp: []byte{0x1, 0x14, 0x1, 0x2c, 0xf, 0xa0}, + exp: []byte{0x1, 0x14, 0x1, 0x2c, 0xf, 0xa0}, }, { name: "float32 1.99", args: []sql.Expression{ expression.NewLiteral(float32(1.99), types.Float32), }, - exp: []byte{0x2}, + exp: []byte{0x2}, }, { name: "float64 1.99", args: []sql.Expression{ expression.NewLiteral(1.99, types.Float64), }, - exp: []byte{0x2}, + exp: []byte{0x2}, }, { name: "decimal 1.99", args: []sql.Expression{ expression.NewLiteral(decimal.NewFromFloat(1.99), types.DecimalType_{}), }, - exp: []byte{0x2}, + exp: []byte{0x2}, }, { name: "good string", args: []sql.Expression{ expression.NewLiteral("12", types.Text), }, - exp: []byte{0x0C}, + exp: []byte{0x0C}, }, { name: "bad string", args: []sql.Expression{ expression.NewLiteral("abc", types.Text), }, - exp: []byte{0x0}, + exp: []byte{0x0}, }, { name: "mix types", @@ -149,7 +149,7 @@ func TestChar(t *testing.T) { expression.NewLiteral("78", types.Text), expression.NewLiteral("abc", types.Text), }, - exp: []byte{0x01, 0x27, 0x0F, 0x01, 0x4E, 0x0}, + exp: []byte{0x01, 0x27, 0x0F, 0x01, 0x4E, 0x0}, }, } @@ -173,4 +173,4 @@ func TestChar(t *testing.T) { require.Equal(t, tt.exp, res) }) } -} \ No newline at end of file +} From fa865b7ca503635b2c474a957d97e8735f4758d6 Mon Sep 17 00:00:00 2001 From: James Cor Date: Fri, 12 Jan 2024 01:12:40 -0800 Subject: [PATCH 04/11] test with using clause --- enginetest/queries/queries.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/enginetest/queries/queries.go b/enginetest/queries/queries.go index 2ed6925926..f39ddb5494 100644 --- a/enginetest/queries/queries.go +++ b/enginetest/queries/queries.go @@ -8819,13 +8819,19 @@ from typestable`, }, }, { - Query: "select char(i, i + 10, pi()) from mytable", + Query: "select char(i, i + 10, pi()) from mytable;", Expected: []sql.Row{ {[]byte{0x01, 0x0B, 0x03}}, {[]byte{0x02, 0x0C, 0x03}}, {[]byte{0x03, 0x0D, 0x03}}, }, }, + { + Query: "select char(97, 98, 99 using utf8mb4);", + Expected: []sql.Row{ + {[]byte{97, 98, 99}}, + }, + }, } var KeylessQueries = []QueryTest{ From 38e7d0508544063189e32da2b9e5dca0dc3db21e Mon Sep 17 00:00:00 2001 From: James Cor Date: Fri, 12 Jan 2024 12:01:04 -0800 Subject: [PATCH 05/11] use bitops and recursion --- sql/expression/function/char.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sql/expression/function/char.go b/sql/expression/function/char.go index 77be574d7f..9d7ee96f95 100644 --- a/sql/expression/function/char.go +++ b/sql/expression/function/char.go @@ -80,13 +80,13 @@ func (c *Char) CollationCoercibility(ctx *sql.Context) (collation sql.CollationI return sql.Collation_binary, 5 } +// char converts num into a byte array +// This function is essentially converting the number to base 256 func char(num uint32) []byte { - res := []byte{} - for num > 0 { - res = append([]byte{byte(num % 256)}, res...) - num = num / 256 + if num == 0 { + return []byte{} } - return res + return append(char(num >> 8), byte(num & 255)) } // Eval implements the sql.Expression interface From a5f5a272ddc77cbd783d4d2468dc69e229168bd5 Mon Sep 17 00:00:00 2001 From: jycor Date: Fri, 12 Jan 2024 20:02:35 +0000 Subject: [PATCH 06/11] [ga-format-pr] Run ./format_repo.sh to fix formatting --- sql/expression/function/char.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/expression/function/char.go b/sql/expression/function/char.go index 9d7ee96f95..92215dd1f8 100644 --- a/sql/expression/function/char.go +++ b/sql/expression/function/char.go @@ -86,7 +86,7 @@ func char(num uint32) []byte { if num == 0 { return []byte{} } - return append(char(num >> 8), byte(num & 255)) + return append(char(num>>8), byte(num&255)) } // Eval implements the sql.Expression interface From d1a2b98b45ab8ea1e2bf5f7f237d5b6971f245f7 Mon Sep 17 00:00:00 2001 From: James Cor Date: Fri, 12 Jan 2024 14:45:29 -0800 Subject: [PATCH 07/11] some comments --- sql/expression/function/char.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sql/expression/function/char.go b/sql/expression/function/char.go index 92215dd1f8..f9d06a8f51 100644 --- a/sql/expression/function/char.go +++ b/sql/expression/function/char.go @@ -20,6 +20,7 @@ import ( "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/types" + "github.com/dolthub/vitess/go/sqltypes" ) // Char implements the sql function "char" which returns the character for each integer passed @@ -62,7 +63,7 @@ func (c *Char) String() string { // Type implements sql.Expression func (c *Char) Type() sql.Type { - return types.LongBlob + return types.MustCreateBinary(sqltypes.VarBinary, 0) } // IsNullable implements sql.Expression @@ -72,7 +73,7 @@ func (c *Char) IsNullable() bool { // Description implements sql.FunctionExpression func (c *Char) Description() string { - return "returns the numeric value of the leftmost character." + return "interprets each argument N as an integer and returns a string consisting of the characters given by the code values of those integers." } // CollationCoercibility implements the interface sql.CollationCoercible. From f201e19f7c47d7ca882811f3cfe6a088ca4c3029 Mon Sep 17 00:00:00 2001 From: James Cor Date: Sat, 13 Jan 2024 17:15:25 -0800 Subject: [PATCH 08/11] support charsets --- sql/expression/function/char.go | 8 ++++++-- sql/planbuilder/scalar.go | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/sql/expression/function/char.go b/sql/expression/function/char.go index f9d06a8f51..2b9275ff06 100644 --- a/sql/expression/function/char.go +++ b/sql/expression/function/char.go @@ -26,7 +26,8 @@ import ( // Char implements the sql function "char" which returns the character for each integer passed type Char struct { // TODO: support using (charset/collation) clause - args []sql.Expression + args []sql.Expression + Collation sql.CollationID } var _ sql.FunctionExpression = (*Char)(nil) @@ -63,7 +64,10 @@ func (c *Char) String() string { // Type implements sql.Expression func (c *Char) Type() sql.Type { - return types.MustCreateBinary(sqltypes.VarBinary, 0) + if c.Collation == sql.Collation_binary || c.Collation == sql.Collation_Unspecified { + return types.MustCreateString(sqltypes.VarBinary, int64(len(c.args) * 4), sql.Collation_binary) + } + return types.MustCreateString(sqltypes.VarChar, int64(len(c.args) * 16), c.Collation) } // IsNullable implements sql.Expression diff --git a/sql/planbuilder/scalar.go b/sql/planbuilder/scalar.go index 70102496bc..185c7c3564 100644 --- a/sql/planbuilder/scalar.go +++ b/sql/planbuilder/scalar.go @@ -175,6 +175,25 @@ func (b *Builder) buildScalar(inScope *scope, e ast.Expr) sql.Expression { b.handleErr(err) } return expression.NewConvertUsing(expr, charset) + case *ast.CharExpr: + args := make([]sql.Expression, len(v.Exprs)) + for i, e := range v.Exprs { + args[i] = b.selectExprToExpression(inScope, e) + } + + f, err := function.NewChar(args...) + if err != nil { + b.handleErr(err) + } + + collId, err := sql.ParseCollation(&v.Type, nil, true) + if err != nil { + b.handleErr(err) + } + + charFunc := f.(*function.Char) + charFunc.Collation = collId + return charFunc case *ast.ConvertExpr: var err error typeLength := 0 From 97b68c7f76207dfe59dd35498bbd0b4894cb2b2c Mon Sep 17 00:00:00 2001 From: James Cor Date: Sat, 13 Jan 2024 17:19:38 -0800 Subject: [PATCH 09/11] bump --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 04641f716c..19c79e6b14 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/dolthub/go-icu-regex v0.0.0-20230524105445-af7e7991c97e github.com/dolthub/jsonpath v0.0.2-0.20230525180605-8dc13778fd72 github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81 - github.com/dolthub/vitess v0.0.0-20240110233415-e46007d964c0 + github.com/dolthub/vitess v0.0.0-20240114011631-026d13a03203 github.com/go-kit/kit v0.10.0 github.com/go-sql-driver/mysql v1.7.2-0.20231213112541-0004702b931d github.com/gocraft/dbr/v2 v2.7.2 diff --git a/go.sum b/go.sum index 7a72693d91..a1355b16c7 100644 --- a/go.sum +++ b/go.sum @@ -58,8 +58,8 @@ github.com/dolthub/jsonpath v0.0.2-0.20230525180605-8dc13778fd72 h1:NfWmngMi1CYU github.com/dolthub/jsonpath v0.0.2-0.20230525180605-8dc13778fd72/go.mod h1:ZWUdY4iszqRQ8OcoXClkxiAVAoWoK3cq0Hvv4ddGRuM= github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81 h1:7/v8q9XGFa6q5Ap4Z/OhNkAMBaK5YeuEzwJt+NZdhiE= github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81/go.mod h1:siLfyv2c92W1eN/R4QqG/+RjjX5W2+gCTRjZxBjI3TY= -github.com/dolthub/vitess v0.0.0-20240110233415-e46007d964c0 h1:P8wb4dR5krirPa0swEJbEObc/I7GaAM/01nOnuQrl0c= -github.com/dolthub/vitess v0.0.0-20240110233415-e46007d964c0/go.mod h1:IwjNXSQPymrja5pVqmfnYdcy7Uv7eNJNBPK/MEh9OOw= +github.com/dolthub/vitess v0.0.0-20240114011631-026d13a03203 h1:pGarEaJIdJUOVYpZHqUE1t7uw91EjXbin8ZP7Pkf8bk= +github.com/dolthub/vitess v0.0.0-20240114011631-026d13a03203/go.mod h1:IwjNXSQPymrja5pVqmfnYdcy7Uv7eNJNBPK/MEh9OOw= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= From cedd2e9d9cd371cd38fd8e1b88ac77f7f505e00c Mon Sep 17 00:00:00 2001 From: jycor Date: Sun, 14 Jan 2024 01:20:57 +0000 Subject: [PATCH 10/11] [ga-format-pr] Run ./format_repo.sh to fix formatting --- sql/expression/function/char.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sql/expression/function/char.go b/sql/expression/function/char.go index 2b9275ff06..8b73356d36 100644 --- a/sql/expression/function/char.go +++ b/sql/expression/function/char.go @@ -18,9 +18,10 @@ import ( "fmt" "strings" + "github.com/dolthub/vitess/go/sqltypes" + "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/types" - "github.com/dolthub/vitess/go/sqltypes" ) // Char implements the sql function "char" which returns the character for each integer passed @@ -65,9 +66,9 @@ func (c *Char) String() string { // Type implements sql.Expression func (c *Char) Type() sql.Type { if c.Collation == sql.Collation_binary || c.Collation == sql.Collation_Unspecified { - return types.MustCreateString(sqltypes.VarBinary, int64(len(c.args) * 4), sql.Collation_binary) + return types.MustCreateString(sqltypes.VarBinary, int64(len(c.args)*4), sql.Collation_binary) } - return types.MustCreateString(sqltypes.VarChar, int64(len(c.args) * 16), c.Collation) + return types.MustCreateString(sqltypes.VarChar, int64(len(c.args)*16), c.Collation) } // IsNullable implements sql.Expression From 88e8569640f24002ec2af9f6bdbff486206ade53 Mon Sep 17 00:00:00 2001 From: James Cor Date: Tue, 16 Jan 2024 11:30:20 -0800 Subject: [PATCH 11/11] feedback --- enginetest/queries/queries.go | 2 +- sql/expression/function/char.go | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/enginetest/queries/queries.go b/enginetest/queries/queries.go index f39ddb5494..c4db234035 100644 --- a/enginetest/queries/queries.go +++ b/enginetest/queries/queries.go @@ -8829,7 +8829,7 @@ from typestable`, { Query: "select char(97, 98, 99 using utf8mb4);", Expected: []sql.Row{ - {[]byte{97, 98, 99}}, + {"abc"}, }, }, } diff --git a/sql/expression/function/char.go b/sql/expression/function/char.go index 8b73356d36..e034db7564 100644 --- a/sql/expression/function/char.go +++ b/sql/expression/function/char.go @@ -26,7 +26,6 @@ import ( // Char implements the sql function "char" which returns the character for each integer passed type Char struct { - // TODO: support using (charset/collation) clause args []sql.Expression Collation sql.CollationID } @@ -122,7 +121,12 @@ func (c *Char) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { res = append(res, char(v.(uint32))...) } - return res, nil + result, _, err := c.Type().Convert(res) + if err != nil { + return nil, err + } + + return result, nil } // Children implements sql.Expression