文档章节

十分钟成为 TiDB Contributor,还送限量版马克杯

TiDB
 TiDB
发布于 2017/03/15 11:40
字数 1170
阅读 63
收藏 0

背景知识

SQL 语句发送到 TiDB 后首先会经过 parser,从文本 parse 成为 AST(抽象语法树),通过 Query Optimizer 生成执行计划,得到一个可以执行的 plan,通过执行这个 plan 即可得到结果,这期间会涉及到如何获取 table 中的数据,如何对数据进行过滤、计算、排序、聚合、滤重以及如何对表达式进行求值。 对于一个 builtin 函数,比较重要的是进行语法解析以及如何求值。其中语法解析部分需要了解如何写 yacc 以及如何修改 TiDB 的词法解析器,较为繁琐,我们已经将这部分工作提前做好,大多数 builtin 函数的语法解析工作已经做完。 对 builtin 函数的求值需要在 TiDB 的表达式求值框架下完成,每个 builtin 函数被认为是一个表达式,用一个 ScalarFunction 来表示,每个 builtin 函数通过其函数名以及参数,获取对应的函数类型以及函数签名,然后通过函数签名进行求值。 总体而言,上述流程对于不熟悉 TiDB 的朋友而言比较复杂,我们对这部分做了些工作,将一些流程性、较为繁琐的工作做了统一处理,目前已经将大多数未实现的 buitlin 函数的语法解析以及寻找函数签名的工作完成,但是函数实现部分留空。换句话说,只要找到留空的函数实现,将其补充完整,即可作为一个 PR。

添加 builtin 函数整体流程

  • 找到未实现的函数 在 TiDB 源码中的 expression 目录下搜索 errFunctionNotExists,即可找到所有未实现的函数,从中选择一个感兴趣的函数,比如 SHA2 函数:
func (b *builtinSHA2Sig) eval(row []types.Datum) (d types.Datum, err error) {
    return d, errFunctionNotExists.GenByArgs("SHA2")
}
  • 实现函数签名 接下来要做的事情就是实现 eval 方法,函数的功能请参考 MySQL 文档,具体的实现方法可以参考目前已经实现函数。

  • 在 typeinferer 中添加类型推导信息 在 plan/typeinferer.go 中的 handleFuncCallExpr() 里面添加这个函数的返回结果类型,请保持和 MySQL 的结果一致。全部类型定义参见 MySQL Const

    * 注意大多数函数除了需要填写返回值类型之外,还需要获取返回值的长度。
  • 写单元测试 在 expression 目录下,为函数的实现增加单元测试,同时也要在 plan/typeinferer_test.go 文件中添加 typeinferer 的单元测试

  • 运行 make dev,确保所有的 test case 都能跑过

示例

这里以新增 SHA1() 函数的 PR 为例,进行详细说明 首先看 expression/builtin_encryption.go: 将 SHA1() 的求值方法补充完整

func (b *builtinSHA1Sig) eval(row []types.Datum) (d types.Datum, err error) {
    // 首先对参数进行求值,这块一般不用修改
    args, err := b.evalArgs(row)
    if err != nil {
        return types.Datum{}, errors.Trace(err)
    }
    // 每个参数的意义请参考 MySQL 文档
    // SHA/SHA1 function only accept 1 parameter
    arg := args[0]
    if arg.IsNull() {
        return d, nil
    }
    // 这里对参数值做了一个类型转换,函数的实现请参考 util/types/datum.go
    bin, err := arg.ToBytes()
    if err != nil {
        return d, errors.Trace(err)
    }
    hasher := sha1.New()
    hasher.Write(bin)
    data := fmt.Sprintf("%x", hasher.Sum(nil))
    // 设置返回值
    d.SetString(data)
    return d, nil
}

接下来给函数实现添加单元测试,参见 expression/builtin_encryption_test.go

var shaCases = []struct {
    origin interface{}
    crypt  string
 }{
    {"test", "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"},
    {"c4pt0r", "034923dcabf099fc4c8917c0ab91ffcd4c2578a6"},
    {"pingcap", "73bf9ef43a44f42e2ea2894d62f0917af149a006"},
    {"foobar", "8843d7f92416211de9ebb963ff4ce28125932878"},
    {1024, "128351137a9c47206c4507dcf2e6fbeeca3a9079"},
    {123.45, "22f8b438ad7e89300b51d88684f3f0b9fa1d7a32"},
 }
 
 func (s *testEvaluatorSuite) TestShaEncrypt(c *C) {
    defer testleak.AfterTest(c)() // 监测 goroutine 泄漏的工具,可以直接照搬
    fc := funcs[ast.SHA]
    for _, test := range shaCases {
        in := types.NewDatum(test.origin)
        f, _ := fc.getFunction(datumsToConstants([]types.Datum{in}), s.ctx)
        crypt, err := f.eval(nil)
        c.Assert(err, IsNil)
        res, err := crypt.ToString()
        c.Assert(err, IsNil)
        c.Assert(res, Equals, test.crypt)
    }
    // test NULL input for sha
    var argNull types.Datum
    f, _ := fc.getFunction(datumsToConstants([]types.Datum{argNull}), s.ctx)
    crypt, err := f.eval(nil)
    c.Assert(err, IsNil)
    c.Assert(crypt.IsNull(), IsTrue)
}
* 注意,除了正常 case 之外,最好能添加一些异常的case,如输入值为 nil,或者是多种类型的参数

最后还需要添加类型推导信息以及 test case,参见 plan/typeinferer.goplan/typeinferer_test.go

case ast.SHA, ast.SHA1:
        tp = types.NewFieldType(mysql.TypeVarString)
        chs = v.defaultCharset
        tp.Flen = 40
        {`sha1(123)`, mysql.TypeVarString, "utf8"},
        {`sha(123)`, mysql.TypeVarString, "utf8"},

编辑按:添加 TiDB Robot 微信,加入 TiDB Contributor Club,无门槛参与开源项目,改变世界从这里开始吧(萌萌哒)。

输入图片说明 听说现在成为 TiDB Contributor 就送限量版马克杯呦~ 输入图片说明

© 著作权归作者所有

TiDB
粉丝 173
博文 228
码字总数 604829
作品 4
海淀
私信 提问
十分钟成为 TiDB Contributor | 添加內建函数

最近我们对 TiDB 代码做了些改进,大幅度简化了添加內建函数的流程,这篇教程将为大家分享如何为 TiDB 新增 builtin 函数。文章会先介绍一些必需的背景知识,再介绍增加 builtin 函数的流程,...

TiDB
2017/03/15
0
0
PingCAP 开源 TiDB 自动化部署运维工具 TiDB Operator

TiDB Operator 是 TiDB 在 Kubernetes 平台上的自动化部署运维工具,目前,TiDB Operator 已经正式开源。 借助 TiDB Operator,TiDB 可以无缝运行在公有云厂商提供的 Kubernetes 平台上,让 ...

TiDB
2018/08/23
2.5K
2
开源 TiDB Operator 让 TiDB 成为真正的 Cloud-Native 数据库

TiDB Operator 是 TiDB 在 Kubernetes 平台上的自动化部署运维工具,借助 TiDB Operator,TiDB 可以无缝运行在公有云厂商提供的 Kubernetes 平台上,让 TiDB 成为真正的 Cloud-Native 数据库...

CSDN资讯
2018/08/23
0
0
三十分钟成为 Contributor | 为 TiKV 添加 built-in 函数

作者:吴雪莲 背景知识 SQL 语句发送到 TiDB 后经过 parser 生成 AST(抽象语法树),再经过 Query Optimizer 生成执行计划,执行计划切分成很多子任务,这些子任务以表达式的方式最后下推到...

TiDB
2018/08/02
38
0
TiDB 社区成长足迹与小红花 | TiDB DevCon 2019

2018 年 TiDB 产品变得更加成熟和稳定,同时 TiDB 社区力量也在发展壮大。在 TiDB DevCon 2019 上,我司联合创始人崔秋带大家一起回顾了 2018 年 TiDB 社区成长足迹,在社区荣誉时刻环节,我...

TiDB
02/14
74
0

没有更多内容

加载失败,请刷新页面

加载更多

计算机实现原理专题--二进制减法器(二)

在计算机实现原理专题--二进制减法器(一)中说明了基本原理,现准备说明如何来实现。 首先第一步255-b运算相当于对b进行按位取反,因此可将8个非门组成如下图的形式: 由于每次做减法时,我...

FAT_mt
今天
5
0
好程序员大数据学习路线分享函数+map映射+元祖

好程序员大数据学习路线分享函数+map映射+元祖,大数据各个平台上的语言实现 hadoop 由java实现,2003年至今,三大块:数据处理,数据存储,数据计算 存储: hbase --> 数据成表 处理: hive --> 数...

好程序员官方
今天
7
0
tabel 中含有复选框的列 数据理解

1、el-ui中实现某一列为复选框 实现多选非常简单: 手动添加一个el-table-column,设type属性为selction即可; 2、@selection-change事件:选项发生勾选状态变化时触发该事件 <el-table @sel...

everthing
今天
6
0
【技术分享】TestFlight测试的流程文档

上架基本需求资料 1、苹果开发者账号(如还没账号先申请-苹果开发者账号申请教程) 2、开发好的APP 通过本篇教程,可以学习到ios证书申请和打包ipa上传到appstoreconnect.apple.com进行TestF...

qtb999
今天
10
0
再见 Spring Boot 1.X,Spring Boot 2.X 走向舞台中心

2019年8月6日,Spring 官方在其博客宣布,Spring Boot 1.x 停止维护,Spring Boot 1.x 生命周期正式结束。 其实早在2018年7月30号,Spring 官方就已经在博客进行过预告,Spring Boot 1.X 将维...

Java技术剑
今天
18
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部