Skip to content

Commit 8934e0c

Browse files
c4pt0rcoocood
authored andcommitted
builtin: add sha/sha1 built-in function (pingcap#2781)
* mod: add sha/sha1 built-in function * Address comment * unify return style * address comments, add some test cases
1 parent 0391820 commit 8934e0c

File tree

4 files changed

+61
-4
lines changed

4 files changed

+61
-4
lines changed

expression/builtin_encryption.go

+23-4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ package expression
1515

1616
import (
1717
"crypto/md5"
18+
"crypto/sha1"
1819
"fmt"
1920

2021
"github.com/juju/errors"
@@ -105,12 +106,12 @@ type builtinAesDecryptSig struct {
105106
func (b *builtinAesDecryptSig) eval(row []types.Datum) (d types.Datum, err error) {
106107
args, err := b.evalArgs(row)
107108
if err != nil {
108-
return types.Datum{}, errors.Trace(err)
109+
return d, errors.Trace(err)
109110
}
110111
for _, arg := range args {
111112
// If either function argument is NULL, the function returns NULL.
112113
if arg.IsNull() {
113-
return
114+
return d, nil
114115
}
115116
}
116117
cryptStr := args[0].GetBytes()
@@ -123,7 +124,7 @@ func (b *builtinAesDecryptSig) eval(row []types.Datum) (d types.Datum, err error
123124
return d, errors.Trace(err)
124125
}
125126
d.SetString(string(data))
126-
return
127+
return d, nil
127128
}
128129

129130
type aesEncryptFunctionClass struct {
@@ -533,8 +534,26 @@ type builtinSHA1Sig struct {
533534
}
534535

535536
// See https://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html#function_sha1
537+
// The value is returned as a string of 40 hexadecimal digits, or NULL if the argument was NULL.
536538
func (b *builtinSHA1Sig) eval(row []types.Datum) (d types.Datum, err error) {
537-
return d, errFunctionNotExists.GenByArgs("SHA1")
539+
args, err := b.evalArgs(row)
540+
if err != nil {
541+
return types.Datum{}, errors.Trace(err)
542+
}
543+
// SHA/SHA1 function only accept 1 parameter
544+
arg := args[0]
545+
if arg.IsNull() {
546+
return d, nil
547+
}
548+
bin, err := arg.ToBytes()
549+
if err != nil {
550+
return d, errors.Trace(err)
551+
}
552+
hasher := sha1.New()
553+
hasher.Write(bin)
554+
data := fmt.Sprintf("%x", hasher.Sum(nil))
555+
d.SetString(data)
556+
return d, nil
538557
}
539558

540559
type sha2FunctionClass struct {

expression/builtin_encryption_test.go

+32
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,38 @@ var md5Cases = []md5Test{
5151
{nil, nil},
5252
}
5353

54+
var shaCases = []struct {
55+
origin interface{}
56+
crypt string
57+
}{
58+
{"test", "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"},
59+
{"c4pt0r", "034923dcabf099fc4c8917c0ab91ffcd4c2578a6"},
60+
{"pingcap", "73bf9ef43a44f42e2ea2894d62f0917af149a006"},
61+
{"foobar", "8843d7f92416211de9ebb963ff4ce28125932878"},
62+
{1024, "128351137a9c47206c4507dcf2e6fbeeca3a9079"},
63+
{123.45, "22f8b438ad7e89300b51d88684f3f0b9fa1d7a32"},
64+
}
65+
66+
func (s *testEvaluatorSuite) TestShaEncrypt(c *C) {
67+
defer testleak.AfterTest(c)()
68+
fc := funcs[ast.SHA]
69+
for _, test := range shaCases {
70+
in := types.NewDatum(test.origin)
71+
f, _ := fc.getFunction(datumsToConstants([]types.Datum{in}), s.ctx)
72+
crypt, err := f.eval(nil)
73+
c.Assert(err, IsNil)
74+
res, err := crypt.ToString()
75+
c.Assert(err, IsNil)
76+
c.Assert(res, Equals, test.crypt)
77+
}
78+
// test NULL input for sha
79+
var argNull types.Datum
80+
f, _ := fc.getFunction(datumsToConstants([]types.Datum{argNull}), s.ctx)
81+
crypt, err := f.eval(nil)
82+
c.Assert(err, IsNil)
83+
c.Assert(crypt.IsNull(), IsTrue)
84+
}
85+
5486
func (s *testEvaluatorSuite) TestAESEncrypt(c *C) {
5587
defer testleak.AfterTest(c)()
5688
fc := funcs[ast.AesEncrypt]

plan/typeinferer.go

+4
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,10 @@ func (v *typeInferrer) handleFuncCallExpr(x *ast.FuncCallExpr) {
400400
tp = types.NewFieldType(mysql.TypeVarString)
401401
chs = v.defaultCharset
402402
tp.Flen = 32
403+
case ast.SHA, ast.SHA1:
404+
tp = types.NewFieldType(mysql.TypeVarString)
405+
chs = v.defaultCharset
406+
tp.Flen = 40
403407
default:
404408
tp = types.NewFieldType(mysql.TypeUnspecified)
405409
}

plan/typeinferer_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@ func (ts *testTypeInferrerSuite) TestInferType(c *C) {
235235
{`aes_encrypt("pingcap", "fit2cloud@2014")`, mysql.TypeVarString, "utf8"},
236236
{`aes_decrypt("pingcap", "fit2cloud@2014")`, mysql.TypeVarString, "utf8"},
237237
{`md5(123)`, mysql.TypeVarString, "utf8"},
238+
{`sha1(123)`, mysql.TypeVarString, "utf8"},
239+
{`sha(123)`, mysql.TypeVarString, "utf8"},
238240
}
239241
for _, ca := range cases {
240242
ctx := testKit.Se.(context.Context)

0 commit comments

Comments
 (0)