Skip to content

Commit

Permalink
error: print non-printable chars in hex style for duplicate entry err…
Browse files Browse the repository at this point in the history
…or (#39485)

close #35289
  • Loading branch information
winkyao committed Dec 1, 2022
1 parent dcec972 commit 94ffc8e
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 0 deletions.
3 changes: 3 additions & 0 deletions ddl/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -1415,6 +1415,9 @@ func (w *addIndexWorker) checkHandleExists(key kv.Key, value []byte, handle kv.H
if err != nil {
str = string(val)
}
if types.IsBinaryStr(colInfos[i].Ft) || types.IsTypeBit(colInfos[i].Ft) {
str = util.FmtNonASCIIPrintableCharToHex(str)
}
valueStr = append(valueStr, str)
}
return kv.ErrKeyExists.FastGenByArgs(strings.Join(valueStr, "-"), indexName)
Expand Down
16 changes: 16 additions & 0 deletions executor/insert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,22 @@ func TestInsertErrorMsg(t *testing.T) {
tk.MustExec(`create table t (a int primary key, b datetime, d date)`)
tk.MustContainErrMsg(`insert into t values (1, '2019-02-11 30:00:00', '2019-01-31')`,
"Incorrect datetime value: '2019-02-11 30:00:00' for column 'b' at row 1")

// test for Issue #35289
tk.MustExec("CREATE TABLE t1 (a BINARY(16) PRIMARY KEY);")
tk.MustExec(`INSERT INTO t1 VALUES (AES_ENCRYPT('a','a'));`)
err := tk.ExecToErr(`INSERT INTO t1 VALUES (AES_ENCRYPT('a','a'));`)
require.Error(t, err, `ERROR 1062 (23000): Duplicate entry '{ W]\xA1\x06u\x9D\xBD\xB1\xA3.\xE2\xD9\xA7t' for key 't1.PRIMARY'`)

tk.MustExec(`INSERT INTO t1 VALUES (AES_ENCRYPT('b','b'));`)
err = tk.ExecToErr(`INSERT INTO t1 VALUES (AES_ENCRYPT('b','b'));`)
require.Error(t, err, "ERROR 1062 (23000): Duplicate entry '\\x0C\\x1E\\x8DG`\\xEB\\x93 F&BC\\xF0\\xB5\\xF4\\xB7' for key 't1.PRIMARY'")

tk.MustExec("drop table if exists t1")
tk.MustExec("create table t1 (a bit primary key) engine=innodb;")
tk.MustExec("insert into t1 values (b'0');")
err = tk.ExecToErr(`insert into t1 values (b'0');`)
require.Error(t, err, `ERROR 1062 (23000): Duplicate entry '\x00' for key 't1.PRIMARY'`)
}

func TestIssue16366(t *testing.T) {
Expand Down
1 change: 1 addition & 0 deletions store/driver/txn/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ go_library(
"//table/tables",
"//tablecodec",
"//types",
"//util",
"//util/logutil",
"@com_github_opentracing_opentracing_go//:opentracing-go",
"@com_github_pingcap_errors//:errors",
Expand Down
7 changes: 7 additions & 0 deletions store/driver/txn/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/pingcap/tidb/table/tables"
"github.com/pingcap/tidb/tablecodec"
"github.com/pingcap/tidb/types"
"github.com/pingcap/tidb/util"
"github.com/pingcap/tidb/util/logutil"
tikverr "github.com/tikv/client-go/v2/error"
"go.uber.org/zap"
Expand Down Expand Up @@ -100,6 +101,9 @@ func extractKeyExistsErrFromHandle(key kv.Key, value []byte, tblInfo *model.Tabl
if col.Length > 0 && len(str) > col.Length {
str = str[:col.Length]
}
if types.IsBinaryStr(&tblInfo.Columns[col.Offset].FieldType) || types.IsTypeBit(&tblInfo.Columns[col.Offset].FieldType) {
str = util.FmtNonASCIIPrintableCharToHex(str)
}
valueStr = append(valueStr, str)
}
return genKeyExistsError(name, strings.Join(valueStr, "-"), nil)
Expand Down Expand Up @@ -136,6 +140,9 @@ func extractKeyExistsErrFromIndex(key kv.Key, value []byte, tblInfo *model.Table
if err != nil {
return genKeyExistsError(name, key.String(), err)
}
if types.IsBinaryStr(colInfo[i].Ft) || types.IsTypeBit(colInfo[i].Ft) {
str = util.FmtNonASCIIPrintableCharToHex(str)
}
valueStr = append(valueStr, str)
}
return genKeyExistsError(name, strings.Join(valueStr, "-"), nil)
Expand Down
5 changes: 5 additions & 0 deletions types/etc.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ func IsTypeNumeric(tp byte) bool {
return false
}

// IsTypeBit returns a boolean indicating whether the tp is bit type.
func IsTypeBit(ft *FieldType) bool {
return ft.GetType() == mysql.TypeBit
}

// IsTemporalWithDate returns a boolean indicating
// whether the tp is time type with date.
func IsTemporalWithDate(tp byte) bool {
Expand Down
28 changes: 28 additions & 0 deletions util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package util

import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
Expand Down Expand Up @@ -174,3 +175,30 @@ func GenLogFields(costTime time.Duration, info *ProcessInfo, needTruncateSQL boo
logFields = append(logFields, zap.String("sql", sql))
return logFields
}

// PrintableASCII detects if b is a printable ASCII character.
// Ref to:http://facweb.cs.depaul.edu/sjost/it212/documents/ascii-pr.htm
func PrintableASCII(b byte) bool {
if b >= 0 && b < 32 || b > 127 {
return false
}

return true
}

// FmtNonASCIIPrintableCharToHex turns non-printable-ASCII characters into Hex
func FmtNonASCIIPrintableCharToHex(str string) string {
var b bytes.Buffer
b.Grow(len(str) * 2)
for i := 0; i < len(str); i++ {
if PrintableASCII(str[i]) {
b.WriteByte(str[i])
continue
}

b.WriteString(`\x`)
// turns non-printable-ASCII character into hex-string
b.WriteString(fmt.Sprintf("%02X", str[i]))
}
return b.String()
}

0 comments on commit 94ffc8e

Please sign in to comment.