ITPub博客

首页 > > > 十分钟成为 Contributor 系列 | 重构内建函数进度报

十分钟成为 Contributor 系列 | 重构内建函数进度报

作者:TigerJin 时间:2017-07-17 14:33:59 0 删除 编辑

6 月 22 日,TiDB 发布了一篇如何十分钟成为 TiDB Contributor 系列的第二篇文章,向大家介绍如何为 TiDB 重构 built-in 函数。

截止到目前,得到了来自社区的积极支持与热情反馈,TiDB 参考社区 contributors 的建议,对计算框架进行了部分修改以降低社区同学参与的难度。

本文完成以下2 项工作,希望帮助社区更好的参与进 TiDB 的项目中来:

  1. 对尚未重写的 built-in 函数进行陈列
  2. 对继上篇文章后,计算框架所进行的修改,进行详细介绍

一. 尚未重写的 built-in 函数陈列如下:

共计 165 个

在 expression 目录下运行grep -rn "^\tbaseBuiltinFunc$" -B 1 * | grep "Sig struct {" | awk -F "Sig" '{print $1}' | awk -F "builtin" '{print $3}' > ~/Desktop/func.txt命令可以获得所有未实现的 built-in 函数

  • Coalesce
  • Greatest
  • Least
  • Interval
  • CaseWhen
  • If
  • IfNull
  • NullIf
  • AesDecrypt
  • AesEncrypt
  • Compress
  • Decode
  • DesDecrypt
  • DesEncrypt
  • Encode
  • Encrypt
  • OldPassword
  • RandomBytes
  • SHA1
  • SHA2
  • Uncompress
  • UncompressedLength
  • ValidatePasswordStrength
  • Database
  • FoundRows
  • CurrentUser
  • User
  • ConnectionID
  • LastInsertID
  • Version
  • Benchmark
  • Charset
  • Coercibility
  • Collation
  • RowCount
  • Regexp
  • Abs
  • Ceil
  • Floor
  • Log
  • Log10
  • Rand
  • Pow
  • Round
  • Conv
  • CRC32
  • Sqrt
  • Arithmetic
  • Acos
  • Asin
  • Atan
  • Cot
  • Exp
  • PI
  • Radians
  • Truncate
  • Sleep
  • Lock
  • ReleaseLock
  • AnyValue
  • Default
  • InetAton
  • InetNtoa
  • Inet6Aton
  • Inet6Ntoa
  • IsFreeLock
  • IsIPv4
  • IsIPv4Prefixed
  • IsIPv6
  • IsUsedLock
  • MasterPosWait
  • NameConst
  • ReleaseAllLocks
  • UUID
  • UUIDShort
  • AndAnd
  • OrOr
  • LogicXor
  • BitOp
  • IsTrueOp
  • UnaryOp
  • IsNull
  • In
  • Row
  • SetVar
  • GetVar
  • Values
  • BitCount
  • Reverse
  • Convert
  • Substring
  • SubstringIndex
  • Locate
  • Hex
  • UnHex
  • Trim
  • LTrim
  • RTrim
  • Rpad
  • BitLength
  • Char
  • CharLength
  • FindInSet
  • Field
  • MakeSet
  • Oct
  • Quote
  • Bin
  • Elt
  • ExportSet
  • Format
  • FromBase64
  • InsertFunc
  • Instr
  • LoadFile
  • Lpad
  • Date
  • DateDiff
  • TimeDiff
  • DateFormat
  • FromDays
  • Hour
  • Minute
  • Second
  • MicroSecond
  • Month
  • MonthName
  • Now
  • DayName
  • DayOfMonth
  • DayOfWeek
  • DayOfYear
  • Week
  • WeekDay
  • WeekOfYear
  • Year
  • YearWeek
  • FromUnixTime
  • GetFormat
  • StrToDate
  • SysDate
  • CurrentDate
  • CurrentTime
  • Time
  • UTCDate
  • UTCTimestamp
  • Extract
  • DateArith
  • TimestampDiff
  • UnixTimestamp
  • Timestamp
  • AddTime
  • ConvertTz
  • MakeTime
  • PeriodAdd
  • PeriodDiff
  • Quarter
  • SecToTime
  • SubTime
  • TimeFormat
  • TimeToSec
  • TimestampAdd
  • ToDays
  • ToSeconds
  • UTCTim

二. 计算框架进行的修改:

此处依然使用 Length 函数( expression/builtin_string.go )为例进行说明,与前文采取相同目录结构:

1. expression/builtin_string.go

(1)lengthFunctionClass.getFunction() 方法: 简化类型推导实现

getFunction 方法用来生成 built-in 函数对应的函数签名,在构造 ScalarFunction 时被调用

  1. func (c *lengthFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
  2. // 此处简化类型推导过程,对 newBaseBuiltinFuncWithTp() 实现进行修改,新的实现中,传入 Length 返回值类型 tpInt 表示返回值类型为 int,参数类型 tpString 表示返回值类型为 string
  3. bf, err := newBaseBuiltinFuncWithTp(args, ctx, tpInt, tpString)
  4. if err != nil {
  5. return nil, errors.Trace(err)
  6. }
  7. // 此处参考 MySQL 实现,设置返回值长度为 10(character length)
  8. // 对于 int/double/decimal/time/duration 类型返回值,已在 newBaseBuiltinFuncWithTp() 中默认调用 types.setBinChsClnFlag() 方法,此处无需再进行设置
  9. bf.tp.Flen = 10
  10. sig := &builtinLengthSig{baseIntBuiltinFunc{bf}}
  11. return sig.setSelf(sig), errors.Trace(c.verifyArgs(args))
  12. }

注:

a. 对于返回值类型为 string 的函数,需要,注意参考 MySQL 行为设置 bf.tp.[charset | collate | flag]

查看 MySQL 行为可以通过在终端启动$ mysql -uroot \-\-column-type-info,这样对于每一个查询语句,可以查看每一列详细的 metadata

对于返回值类型为 string 的函数,以 concat 为例,当存在类型为 string 且包含 binary flag 的参数时,其返回值也应设置 binary flag

b. 对于返回值类型为 Time 的函数,需要注意,根据函数行为,设置 bf.tp.Tp = [ TypeDate | TypeDatetime | TypeTimestamp ] ,若为 TypeDate/ TypeDatetime,还需注意推导 bf.tp.Decimal (即小数位数)

c. 不确定性的函数:

  • Rand
  • ConnectionID
  • CurrentUser
  • User
  • Database
  • Schema
  • FoundRows
  • LastInsertId
  • Version
  • Sleep
  • GetVar
  • SetVar
  • Values
  • SessionUser
  • SystemUser
  • RowCount
  • UUID

(2)实现 builtinLengthSig.evalInt() 方法:保持不变,此处请注意修改该函数的注释 (s/ eval/ evalXXX)

2. expression/builtin_string_test.go

  1. func (s *testEvaluatorSuite) TestLength(c *C) {
  2. defer testleak.AfterTest(c)()
  3. cases := []struct {
  4. args interface{}
  5. expected int64
  6. isNil bool
  7. getErr bool
  8. }{
  9. ......
  10. }
  11. for _, t := range cases {
  12. f, err := newFunctionForTest(s.ctx, ast.Length, primitiveValsToConstants([]interface{}{t.args})...)
  13. c.Assert(err, IsNil)
  14. d, err := f.Eval(nil)
  15. // 注意此处不再对 LENGTH 函数的返回值类型进行测试,相应测试被移动到 plan/typeinfer_test.go/TestInferType 函数中,(注意不是expression/typeinferer_test.go)
  16. if t.getErr {
  17. c.Assert(err, NotNil)
  18. } else {
  19. c.Assert(err, IsNil)
  20. if t.isNil {
  21. c.Assert(d.Kind(), Equals, types.KindNull)
  22. } else {
  23. c.Assert(d.GetInt64(), Equals, t.expected)
  24. }
  25. }
  26. }
  27. // 测试函数是否具有确定性
  28. // 在 review 社区的 PRs 过程中发现,这个测试经常会被遗漏,烦请留意
  29. f, err := funcs[ast.Length].getFunction([]Expression{Zero}, s.ctx)
  30. c.Assert(err, IsNil)
  31. c.Assert(f.isDeterministic(), IsTrue)
  32. }

3. executor/executor_test.go

与上一篇文章保持不变,需要注意的是,为了保证可读性, TestStringBuiltin() 方法仅对 expression/builtin_string.go 文件中的 built-in 函数进行测试。如果 executor_test.go 文件中不存在对应的 TestXXXBuiltin() 方法,可以新建一个对应的测试函数。

4. plan/typeinfer_test.go

  1. func (s *testPlanSuite) TestInferType(c *C) {
  2. ....
  3. tests := []struct {
  4. sql string
  5. tp byte
  6. chs string
  7. flag byte
  8. flen int
  9. decimal int
  10. }{
  11. ...
  12. // 此处添加对 length 函数返回值类型的测试
  13. // 此处注意,对于返回值类型、长度等受参数影响的函数,此处测试请尽量覆盖全面
  14. {"length(c_char, c_char)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag, 10, 0},
  15. ...
  16. }
  17. for _, tt := range tests {
  18. ...
  19. }
  20. }

注:

当有多个 PR 同时在该文件中添加测试时,若有别的 contributor 的 PR 先于自己的 PR merge 进 master,有可能会发生冲突,此时在本地 merge 一下 master 分支,解决一下再 push 一下即可。

PS:欢迎小伙伴们加入 TiDB Contributor Club ,在这里将和你一起分享开源的力量,加入 TiDB Contributor Club 请添加我们的 AI 微信号:tidbai

原文作者:;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2020-06-28

  • 博文量
    494
  • 访问量
    25779