diff --git a/expression/builtin_encryption.go b/expression/builtin_encryption.go index b4e902b3ac..5c0874ba09 100644 --- a/expression/builtin_encryption.go +++ b/expression/builtin_encryption.go @@ -28,6 +28,7 @@ import ( "github.com/juju/errors" "github.com/pingcap/tidb/context" "github.com/pingcap/tidb/mysql" + "github.com/pingcap/tidb/util" "github.com/pingcap/tidb/util/encrypt" "github.com/pingcap/tidb/util/types" ) @@ -395,7 +396,29 @@ type builtinPasswordSig struct { // eval evals a builtinPasswordSig. // See https://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html#function_password func (b *builtinPasswordSig) eval(row []types.Datum) (d types.Datum, err error) { - return d, errFunctionNotExists.GenByArgs("PASSWORD") + args, err := b.evalArgs(row) + if err != nil { + return d, errors.Trace(err) + } + + arg := args[0] + if arg.IsNull() { + d.SetString("") + return d, nil + } + + pass, err := args[0].ToString() + if err != nil { + return d, errors.Trace(err) + } + + if len(pass) == 0 { + d.SetString("") + return d, nil + } + + d.SetString(util.EncodePassword(pass)) + return d, nil } type randomBytesFunctionClass struct { diff --git a/expression/builtin_encryption_test.go b/expression/builtin_encryption_test.go index 8cacc34c65..0184ce23f3 100644 --- a/expression/builtin_encryption_test.go +++ b/expression/builtin_encryption_test.go @@ -300,3 +300,24 @@ func (s *testEvaluatorSuite) TestUncompressLength(c *C) { c.Assert(out.GetInt64(), Equals, test.expect) } } +func (s *testEvaluatorSuite) TestPassword(c *C) { + defer testleak.AfterTest(c)() + tests := []struct { + in interface{} + expect interface{} + }{ + {nil, string("")}, + {string(""), string("")}, + {string("abc"), string("*0D3CED9BEC10A777AEC23CCC353A8C08A633045E")}, + } + + fc := funcs[ast.PasswordFunc] + for _, test := range tests { + arg := types.NewDatum(test.in) + f, err := fc.getFunction(datumsToConstants([]types.Datum{arg}), s.ctx) + c.Assert(err, IsNil) + out, err := f.eval(nil) + c.Assert(err, IsNil) + c.Assert(out.GetString(), Equals, test.expect) + } +} diff --git a/expression/typeinferer.go b/expression/typeinferer.go index c0aecbe6bb..772d1a3d23 100644 --- a/expression/typeinferer.go +++ b/expression/typeinferer.go @@ -431,6 +431,9 @@ func (v *typeInferrer) handleFuncCallExpr(x *ast.FuncCallExpr) { tp = x.Args[0].GetType() case ast.RowFunc: tp = x.Args[0].GetType() + case ast.PasswordFunc: + tp = types.NewFieldType(mysql.TypeVarString) + chs = v.defaultCharset default: tp = types.NewFieldType(mysql.TypeUnspecified) } diff --git a/expression/typeinferer_test.go b/expression/typeinferer_test.go index 041e20fdf4..28b9bf5ead 100644 --- a/expression/typeinferer_test.go +++ b/expression/typeinferer_test.go @@ -329,6 +329,7 @@ func (ts *testTypeInferrerSuite) TestInferType(c *C) { {`inet6_ntoa(inet6_aton('FE80::AAAA:0000:00C2:0002'))`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {`is_ipv4_mapped(c_varbinary)`, mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, + {`password("abc")`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {`json_type('3')`, mysql.TypeVarString, charset.CharsetUTF8, 0}, } for _, tt := range tests {