Skip to content

Commit

Permalink
cherry pick pingcap#37242 to release-6.2
Browse files Browse the repository at this point in the history
Signed-off-by: ti-srebot <ti-srebot@pingcap.com>
  • Loading branch information
CbcWestwolf authored and ti-srebot committed Aug 24, 2022
1 parent daf2b17 commit 79a40c4
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 2 deletions.
65 changes: 65 additions & 0 deletions executor/executor_issue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/pingcap/tidb/config"
"github.com/pingcap/tidb/kv"
"github.com/pingcap/tidb/parser/auth"
"github.com/pingcap/tidb/parser/charset"
"github.com/pingcap/tidb/parser/mysql"
"github.com/pingcap/tidb/sessionctx/variable"
"github.com/pingcap/tidb/statistics"
Expand Down Expand Up @@ -409,6 +410,70 @@ func TestIssue30971(t *testing.T) {
}
}

func TestIssue31678(t *testing.T) {
// The issue31678 is mainly about type conversion in UNION
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("USE test")
tk.MustExec("DROP TABLE IF EXISTS t1, t2;")

// https://github.com/pingcap/tidb/issues/31678
tk.MustExec("CREATE TABLE t1 (c VARCHAR(11)) CHARACTER SET utf8mb4")
tk.MustExec("CREATE TABLE t2 (b CHAR(1) CHARACTER SET binary, i INT)")
tk.MustExec("INSERT INTO t1 (c) VALUES ('н1234567890')")
tk.MustExec("INSERT INTO t2 (b, i) VALUES ('1', 1)")
var tests = []struct {
query string
expectedFlen int
expectedCharset string
result []string
}{
{"SELECT c FROM t1 UNION SELECT b FROM t2", 44, "binary", []string{"1", "н1234567890"}},
{"SELECT c FROM t1 UNION SELECT i FROM t2", 20, "utf8mb4", []string{"1", "н1234567890"}},
{"SELECT i FROM t2 UNION SELECT c FROM t1", 20, "utf8mb4", []string{"1", "н1234567890"}},
{"SELECT b FROM t2 UNION SELECT c FROM t1", 44, "binary", []string{"1", "н1234567890"}},
}
for _, test := range tests {
tk.MustQuery(test.query).Sort().Check(testkit.Rows(test.result...))
rs, err := tk.Exec(test.query)
require.NoError(t, err)
resultFields := rs.Fields()
require.Equal(t, 1, len(resultFields), test.query)
require.Equal(t, test.expectedFlen, resultFields[0].Column.FieldType.GetFlen(), test.query)
require.Equal(t, test.expectedCharset, resultFields[0].Column.FieldType.GetCharset(), test.query)
}
tk.MustExec("DROP TABLE t1, t2;")

// test some other charset
tk.MustExec("CREATE TABLE t1 (c1 VARCHAR(5) CHARACTER SET utf8mb4, c2 VARCHAR(1) CHARACTER SET binary)")
tk.MustExec("CREATE TABLE t2 (c1 CHAR(10) CHARACTER SET GBK, c2 VARCHAR(50) CHARACTER SET binary)")
tk.MustExec("INSERT INTO t1 VALUES ('一二三四五', '1')")
tk.MustExec("INSERT INTO t2 VALUES ('一二三四五六七八九十', '1234567890')")
gbkResult, err := charset.NewCustomGBKEncoder().String("一二三四五六七八九十")
require.NoError(t, err)
tests = []struct {
query string
expectedFlen int
expectedCharset string
result []string
}{
{"SELECT c1 FROM t1 UNION SELECT c1 FROM t2", 10, "utf8mb4", []string{"一二三四五", "一二三四五六七八九十"}},
{"SELECT c1 FROM t1 UNION SELECT c2 FROM t2", 50, "binary", []string{"1234567890", "一二三四五"}},
{"SELECT c2 FROM t1 UNION SELECT c1 FROM t2", 20, "binary", []string{"1", gbkResult}},
{"SELECT c2 FROM t1 UNION SELECT c2 FROM t2", 50, "binary", []string{"1", "1234567890"}},
}
for _, test := range tests {
tk.MustQuery(test.query).Sort().Check(testkit.Rows(test.result...))
rs, err := tk.Exec(test.query)
require.NoError(t, err)
resultFields := rs.Fields()
require.Equal(t, 1, len(resultFields), test.query)
require.Equal(t, test.expectedFlen, resultFields[0].Column.FieldType.GetFlen(), test.query)
require.Equal(t, test.expectedCharset, resultFields[0].Column.FieldType.GetCharset(), test.query)
}
tk.MustExec("DROP TABLE t1, t2;")
}

func TestIndexJoin31494(t *testing.T) {
store, dom, clean := testkit.CreateMockStoreAndDomain(t)
defer clean()
Expand Down
19 changes: 19 additions & 0 deletions planner/core/logical_plan_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"github.com/pingcap/tidb/metrics"
"github.com/pingcap/tidb/parser"
"github.com/pingcap/tidb/parser/ast"
"github.com/pingcap/tidb/parser/charset"
"github.com/pingcap/tidb/parser/format"
"github.com/pingcap/tidb/parser/model"
"github.com/pingcap/tidb/parser/mysql"
Expand Down Expand Up @@ -1507,7 +1508,24 @@ func unionJoinFieldType(a, b *types.FieldType) *types.FieldType {
return resultTp
}

<<<<<<< HEAD
func (b *PlanBuilder) buildProjection4Union(ctx context.Context, u *LogicalUnionAll) error {
=======
// Set the flen of the union column using the max flen in children.
func (b *PlanBuilder) setUnionFlen(resultTp *types.FieldType, cols []expression.Expression) {
isBinary := resultTp.GetCharset() == charset.CharsetBin
for i := 0; i < len(cols); i++ {
childTp := cols[i].GetType()
childTpCharLen := 1
if isBinary {
childTpCharLen = charset.CharacterSetInfos[childTp.GetCharset()].Maxlen
}
resultTp.SetFlen(mathutil.Max(resultTp.GetFlen(), childTpCharLen*childTp.GetFlen()))
}
}

func (b *PlanBuilder) buildProjection4Union(_ context.Context, u *LogicalUnionAll) error {
>>>>>>> 25dda978f... types: fix a bug in casting str2str when `union` (#37242)
unionCols := make([]*expression.Column, 0, u.children[0].Schema().Len())
names := make([]*types.FieldName, 0, u.children[0].Schema().Len())

Expand All @@ -1527,6 +1545,7 @@ func (b *PlanBuilder) buildProjection4Union(ctx context.Context, u *LogicalUnion
}
resultTp.SetCharset(collation.Charset)
resultTp.SetCollate(collation.Collation)
b.setUnionFlen(resultTp, tmpExprs)
names = append(names, &types.FieldName{ColName: u.children[0].OutputNames()[i].ColName})
unionCols = append(unionCols, &expression.Column{
RetType: resultTp,
Expand Down
2 changes: 1 addition & 1 deletion types/convert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ func TestConvertToString(t *testing.T) {
sc := new(stmtctx.StatementContext)
outputDatum, err := inputDatum.ConvertTo(sc, ft)
if tt.input != tt.output {
require.True(t, ErrDataTooLong.Equal(err))
require.True(t, ErrDataTooLong.Equal(err), "flen: %d, charset: %s, input: %s, output: %s", tt.flen, tt.charset, tt.input, tt.output)
} else {
require.NoError(t, err)
}
Expand Down
2 changes: 1 addition & 1 deletion types/datum.go
Original file line number Diff line number Diff line change
Expand Up @@ -1069,7 +1069,7 @@ func (d *Datum) convertToString(sc *stmtctx.StatementContext, target *FieldType)
func ProduceStrWithSpecifiedTp(s string, tp *FieldType, sc *stmtctx.StatementContext, padZero bool) (_ string, err error) {
flen, chs := tp.GetFlen(), tp.GetCharset()
if flen >= 0 {
// overflowed stores the part of the string that is out of the length contraint, it is later checked to see if the
// overflowed stores the part of the string that is out of the length constraint, it is later checked to see if the
// overflowed part is all whitespaces
var overflowed string
var characterLen int
Expand Down

0 comments on commit 79a40c4

Please sign in to comment.