Skip to content

Commit

Permalink
expression: support builtin func password for GBK (pingcap#29202)
Browse files Browse the repository at this point in the history
  • Loading branch information
Defined2014 authored Nov 5, 2021
1 parent 1b5b440 commit 9409d54
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 12 deletions.
11 changes: 11 additions & 0 deletions cmd/explaintest/r/new_character_set_builtin.result
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,14 @@ select decode(encode(a,"monty"),"monty") = a, md5(decode(encode(b,"monty"),"mont
decode(encode(a,"monty"),"monty") = a md5(decode(encode(b,"monty"),"monty")) = md5(b) decode(encode(c,"monty"),"monty") = c
1 1 1
set @@tidb_enable_vectorized_expression = false;
drop table if exists t;
create table t (a char(20) charset utf8mb4, b char(20) charset gbk, c binary(20));
insert into t values ('一二三', '一二三', '一二三');
select password(a), password(b), password(c) from t;
password(a) password(b) password(c)
*D13577D198CA3F0AF5C548195065991E0E3EE665 *A669F2B2DD49E2463FE62D8F72DDF4F858687EA5 *9FC0B2ABDF3EC9895E852B15BE432EE0EA0C26BA
set @@tidb_enable_vectorized_expression = true;
select password(a), password(b), password(c) from t;
password(a) password(b) password(c)
*D13577D198CA3F0AF5C548195065991E0E3EE665 *A669F2B2DD49E2463FE62D8F72DDF4F858687EA5 *9FC0B2ABDF3EC9895E852B15BE432EE0EA0C26BA
set @@tidb_enable_vectorized_expression = false;
9 changes: 9 additions & 0 deletions cmd/explaintest/t/new_character_set_builtin.test
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,12 @@ select decode(encode(a,"monty"),"monty") = a, md5(decode(encode(b,"monty"),"mont
set @@tidb_enable_vectorized_expression = true;
select decode(encode(a,"monty"),"monty") = a, md5(decode(encode(b,"monty"),"monty")) = md5(b), decode(encode(c,"monty"),"monty") = c from t;
set @@tidb_enable_vectorized_expression = false;

-- test for builtin function password()
drop table if exists t;
create table t (a char(20) charset utf8mb4, b char(20) charset gbk, c binary(20));
insert into t values ('一二三', '一二三', '一二三');
select password(a), password(b), password(c) from t;
set @@tidb_enable_vectorized_expression = true;
select password(a), password(b), password(c) from t;
set @@tidb_enable_vectorized_expression = false;
9 changes: 7 additions & 2 deletions expression/builtin_encryption.go
Original file line number Diff line number Diff line change
Expand Up @@ -549,18 +549,23 @@ func (b *builtinPasswordSig) Clone() builtinFunc {
func (b *builtinPasswordSig) evalString(row chunk.Row) (d string, isNull bool, err error) {
pass, isNull, err := b.args[0].EvalString(b.ctx, row)
if isNull || err != nil {
return "", err != nil, err
return "", isNull, err
}

if len(pass) == 0 {
return "", false, nil
}

dStr, err := charset.NewEncoding(b.args[0].GetType().Charset).EncodeString(pass)
if err != nil {
return "", false, err
}

// We should append a warning here because function "PASSWORD" is deprecated since MySQL 5.7.6.
// See https://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html#function_password
b.ctx.GetSessionVars().StmtCtx.AppendWarning(errDeprecatedSyntaxNoReplacement.GenWithStackByArgs("PASSWORD"))

return auth.EncodePassword(pass), false, nil
return auth.EncodePassword(dStr), false, nil
}

type randomBytesFunctionClass struct {
Expand Down
23 changes: 17 additions & 6 deletions expression/builtin_encryption_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -521,23 +521,34 @@ func TestPassword(t *testing.T) {
cases := []struct {
args interface{}
expected string
charset string
isNil bool
getErr bool
getWarn bool
}{
{nil, "", false, false, false},
{"", "", false, false, false},
{"abc", "*0D3CED9BEC10A777AEC23CCC353A8C08A633045E", false, false, true},
{123, "*23AE809DDACAF96AF0FD78ED04B6A265E05AA257", false, false, true},
{1.23, "*A589EEBA8D3F9E1A34A7EE518FAC4566BFAD5BB6", false, false, true},
{types.NewDecFromFloatForTest(123.123), "*B15B84262DB34BFB2C817A45A55C405DC7C52BB1", false, false, true},
{nil, "", "", false, false, false},
{"", "", "", false, false, false},
{"abc", "*0D3CED9BEC10A777AEC23CCC353A8C08A633045E", "", false, false, true},
{"abc", "*0D3CED9BEC10A777AEC23CCC353A8C08A633045E", "gbk", false, false, true},
{123, "*23AE809DDACAF96AF0FD78ED04B6A265E05AA257", "", false, false, true},
{1.23, "*A589EEBA8D3F9E1A34A7EE518FAC4566BFAD5BB6", "", false, false, true},
{"一二三四", "*D207780722F22B23C254CAC0580D3B6738C19E18", "", false, false, true},
{"一二三四", "*48E0460AD45CF66AC6B8C18CB8B4BC8A403D935B", "gbk", false, false, true},
{"ㅂ123", "", "gbk", false, true, false},
{types.NewDecFromFloatForTest(123.123), "*B15B84262DB34BFB2C817A45A55C405DC7C52BB1", "", false, false, true},
}

warnCount := len(ctx.GetSessionVars().StmtCtx.GetWarnings())
for _, c := range cases {
err := ctx.GetSessionVars().SetSystemVar(variable.CharacterSetConnection, c.charset)
require.NoError(t, err)
f, err := newFunctionForTest(ctx, ast.PasswordFunc, primitiveValsToConstants(ctx, []interface{}{c.args})...)
require.NoError(t, err)
d, err := f.Eval(chunk.Row{})
if c.getErr {
require.Error(t, err)
continue
}
require.NoError(t, err)
if c.isNil {
require.Equal(t, types.KindNull, d.Kind())
Expand Down
16 changes: 13 additions & 3 deletions expression/builtin_encryption_vec.go
Original file line number Diff line number Diff line change
Expand Up @@ -710,22 +710,32 @@ func (b *builtinPasswordSig) vecEvalString(input *chunk.Chunk, result *chunk.Col
if err := b.args[0].VecEvalString(b.ctx, input, buf); err != nil {
return err
}

var dBytes []byte
enc := charset.NewEncoding(b.args[0].GetType().Charset)
result.ReserveString(n)
for i := 0; i < n; i++ {
if buf.IsNull(i) {
result.AppendString("")
continue
}
pass := buf.GetString(i)
if len(pass) == 0 {

passBytes := buf.GetBytes(i)
if len(passBytes) == 0 {
result.AppendString("")
continue
}

dBytes, err := enc.Encode(dBytes, passBytes)
if err != nil {
return err
}

// We should append a warning here because function "PASSWORD" is deprecated since MySQL 5.7.6.
// See https://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html#function_password
b.ctx.GetSessionVars().StmtCtx.AppendWarning(errDeprecatedSyntaxNoReplacement.GenWithStackByArgs("PASSWORD"))

result.AppendString(auth.EncodePassword(pass))
result.AppendString(auth.EncodePasswordBytes(dBytes))
}
return nil
}
Expand Down
13 changes: 12 additions & 1 deletion parser/auth/mysql_native_password.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func Sha1Hash(bs []byte) []byte {
return crypt.Sum(nil)
}

// EncodePassword converts plaintext password to hashed hex string.
// EncodePassword converts plaintext password(type is string) to hashed hex string.
func EncodePassword(pwd string) string {
if len(pwd) == 0 {
return ""
Expand All @@ -75,6 +75,17 @@ func EncodePassword(pwd string) string {
return fmt.Sprintf("*%X", hash2)
}

// EncodePasswordBytes converts plaintext password(type is []byte) to hashed hex string.
func EncodePasswordBytes(pwd []byte) string {
if len(pwd) == 0 {
return ""
}
hash1 := Sha1Hash(pwd)
hash2 := Sha1Hash(hash1)

return fmt.Sprintf("*%X", hash2)
}

// DecodePassword converts hex string password without prefix '*' to byte array.
func DecodePassword(pwd string) ([]byte, error) {
x, err := hex.DecodeString(pwd[1:])
Expand Down
1 change: 1 addition & 0 deletions parser/auth/mysql_native_password_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func TestEncodePassword(t *testing.T) {
t.Parallel()
pwd := "123"
require.Equal(t, "*23AE809DDACAF96AF0FD78ED04B6A265E05AA257", EncodePassword(pwd))
require.Equal(t, EncodePasswordBytes([]byte(pwd)), EncodePassword(pwd))
}

func TestDecodePassword(t *testing.T) {
Expand Down

0 comments on commit 9409d54

Please sign in to comment.