Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

expression, executor: allow insert strings with overflowed trailing spaces (#20987) #21282

Merged
merged 5 commits into from
Nov 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions executor/insert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1268,3 +1268,19 @@ func (s *testSuite9) TestIssue20768(c *C) {
tk.MustQuery("select /*+ inl_merge_join(t1) */ * from t1 join t2 on t1.a = t2.a").Check(testkit.Rows("0 0"))
tk.MustQuery("select /*+ merge_join(t1) */ * from t1 join t2 on t1.a = t2.a").Check(testkit.Rows("0 0"))
}

func (s *testSuite9) TestIssue10402(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("use test")
tk.MustExec("create table vctt (v varchar(4), c char(4))")
tk.MustExec("insert into vctt values ('ab ', 'ab ')")
tk.MustQuery("select * from vctt").Check(testkit.Rows("ab ab"))
tk.MustExec("delete from vctt")
tk.Se.GetSessionVars().StmtCtx.SetWarnings(nil)
tk.MustExec("insert into vctt values ('ab\\n\\n\\n', 'ab\\n\\n\\n'), ('ab\\t\\t\\t', 'ab\\t\\t\\t'), ('ab ', 'ab '), ('ab\\r\\r\\r', 'ab\\r\\r\\r')")
c.Check(tk.Se.GetSessionVars().StmtCtx.WarningCount(), Equals, uint16(4))
warns := tk.Se.GetSessionVars().StmtCtx.GetWarnings()
c.Check(fmt.Sprintf("%v", warns), Equals, "[{Warning [types:1265]Data truncated, field len 4, data len 5} {Warning [types:1265]Data truncated, field len 4, data len 5} {Warning [types:1265]Data truncated, field len 4, data len 6} {Warning [types:1265]Data truncated, field len 4, data len 5}]")
tk.MustQuery("select * from vctt").Check(testkit.Rows("ab\n\n ab\n\n", "ab\t\t ab\t\t", "ab ab", "ab\r\r ab\r\r"))
tk.MustQuery("select length(v), length(c) from vctt").Check(testkit.Rows("4 4", "4 4", "4 2", "4 4"))
}
26 changes: 22 additions & 4 deletions types/datum.go
Original file line number Diff line number Diff line change
Expand Up @@ -952,10 +952,14 @@ 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.Flen, tp.Charset
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 part is all whitespaces
var overflowed string
var characterLen int
// Flen is the rune length, not binary length, for UTF8 charset, we need to calculate the
// rune count and truncate to Flen runes if it is too long.
if chs == charset.CharsetUTF8 || chs == charset.CharsetUTF8MB4 {
characterLen := utf8.RuneCountInString(s)
characterLen = utf8.RuneCountInString(s)
if characterLen > flen {
// 1. If len(s) is 0 and flen is 0, truncateLen will be 0, don't truncate s.
// CREATE TABLE t (a char(0));
Expand All @@ -972,13 +976,27 @@ func ProduceStrWithSpecifiedTp(s string, tp *FieldType, sc *stmtctx.StatementCon
}
runeCount++
}
err = ErrDataTooLong.GenWithStack("Data Too Long, field len %d, data len %d", flen, characterLen)
overflowed = s[truncateLen:]
s = truncateStr(s, truncateLen)
}
} else if len(s) > flen {
err = ErrDataTooLong.GenWithStack("Data Too Long, field len %d, data len %d", flen, len(s))
characterLen = len(s)
overflowed = s[flen:]
s = truncateStr(s, flen)
} else if tp.Tp == mysql.TypeString && IsBinaryStr(tp) && len(s) < flen && padZero {
}

if len(overflowed) != 0 {
trimed := strings.TrimRight(overflowed, " \t\n\r")
if len(trimed) == 0 && !IsBinaryStr(tp) && IsTypeChar(tp.Tp) {
if tp.Tp == mysql.TypeVarchar {
sc.AppendWarning(ErrTruncated.GenWithStack("Data truncated, field len %d, data len %d", flen, characterLen))
}
} else {
err = ErrDataTooLong.GenWithStack("Data Too Long, field len %d, data len %d", flen, characterLen)
}
}

if tp.Tp == mysql.TypeString && IsBinaryStr(tp) && len(s) < flen && padZero {
padding := make([]byte, flen-len(s))
s = string(append([]byte(s), padding...))
}
Expand Down