TIDB源码分析-分析每一次PR(8)

继续分分析PR。

Pass go vet #16

这个修复了没有指定结构体中变量名的一些测试数据。

mysqldef: fix issue #19 #20

修复了issues#19中提到的make test错误。

原因就是Marshal()中没有使用本地时区导致的。

然后对Timestamp的测试案例修改了两个边界值。

Allow uses to shutdown the pprof #17

谢大对pprof增加了debug开关。

tidb: Add some comments #24

增加了pprof的注释。

mysqldef: save FSP and fix zone offset for codec #29

这个PR对mysqldef.Time的Marshal和UnmarshalInLocation的二进制编码解码增加了FSP信息,然后修复了时区偏移问题,并增加了测试数据。

Add convert type function #23

添加了一个mysql的函数 CONVERT(expr,type),

mysql文档说明了:Discussion of CONVERT(expr, type) syntax here also applies to CAST(expr AS type), which is equivalent。这个函数的具体实现和 CAST(expr AS type)等价(这个CAST已经实现过了),这里加了一个标志来区别是否为Convert,主要用在String()方法。然后对parser.y添加了这个语法。

Pass go tool vet –shadow #31

优化修改了一些变量的重复使用和格式。

Godeps: Update version of boltdb #30

更新boltdb 的版本。

Pass gofmt #32

格式化代码。

cleanup compare #35

把之前零散的不同类型之间的比较统一整合在了util/types/compare.go,并且以前用panic抛出的异常改为返回error。

tidb: update gitignore #38

修改了gitignore。

Update godep packages. #34

更新/改了依赖包。

expressions: operator supports []byte type #39

首先跟着代码跑会发现,select 1 + cast(“123” as binary);这样的语句还不支持,那么原因在这里:

// Operator: DIV / - % MOD + *
// See https://dev.mysql.com/doc/refman/5.7/en/arithmetic-functions.html#operator_divide
func (o *BinaryOperation) evalArithmeticOp(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) {
	a, b, err := o.get2(ctx, args)
	if err != nil {
		return nil, err
	}

	if a == nil || b == nil {
		// TODO: for <=>, if a and b are both nil, return true
		return nil, nil
	}

	if a, b, err = o.coerceArithmetic2(a, b); err != nil {
		return nil, o.traceErr(err)
	}

	// TODO: support logic division DIV
	switch o.Op {
	case opcode.Plus:
		return o.evalPlus(a, b)
	case opcode.Minus:
		return o.evalMinus(a, b)
	case opcode.Mul:
		return o.evalMul(a, b)
	case opcode.Div:
		return o.evalDiv(a, b)
	case opcode.Mod:
		return o.evalMod(a, b)
	case opcode.IntDiv:
		return o.evalIntDiv(a, b)
	default:
		return nil, o.errorf("invalid op %v in arithmetic operation", o.Op)
	}
}

https://github.com/pingcap/tidb/blob/dd19e36c2839345cfae8d8fa46a77d74cdc395fa/expression/expressions/binop.go#L692-L726

在a, b, err := o.get2(ctx, args)得到表达式左右两边的值一个是int64一个是[]byte,这个没问题,然后这个o.coerceArithmetic2(a, b)的作用是把需要做算术运算的两边转换成尽量统一的类型,比如一个int64一个float64,则会把两边都转换成float64,然后在coerceArithmetic2()先调用了:

func (o *BinaryOperation) coerceArithmetic(a interface{}) (interface{}, error) {
	switch x := a.(type) {
	case string:
		// MySQL will convert string to float for arithmetic operation
		f, err := types.StrToFloat(x)
		if err != nil {
			return nil, err
		}
		return f, err
	case mysql.Time:
		// TODO: if time has no precision, return int64
		return x.ToNumber(), nil
	case mysql.Duration:
		// TODO: if duration has no precision, return int64
		return x.ToNumber(), nil
	default:
		return x, nil
	}
}

https://github.com/pingcap/tidb/blob/dd19e36c2839345cfae8d8fa46a77d74cdc395fa/expression/expressions/binop.go#L650-L668

而这里还没定义[]byte的转换,所以这里直接返回的还是[]byte类型,而后面没有定义[]byte类型的加法等:

func (o *BinaryOperation) evalPlus(a interface{}, b interface{}) (interface{}, error) {
	// TODO: check overflow
	switch x := a.(type) {
	case int64:
		switch y := b.(type) {
		case int64:
			return x + y, nil
		case uint64:
			// For MySQL, if any is unsigned, return unsigned
			// TODO: check overflow
			return uint64(x) + y, nil
		}
	case uint64:
		switch y := b.(type) {
		case int64:
			// For MySQL, if any is unsigned, return unsigned
			// TODO: check overflow
			return x + uint64(y), nil
		case uint64:
			return x + y, nil
		}
	case float64:
		switch y := b.(type) {
		case float64:
			return x + y, nil
		}
	case mysql.Decimal:
		switch y := b.(type) {
		case mysql.Decimal:
			return x.Add(y), nil
		}
	}

	return types.InvOp2(a, b, opcode.Plus)
}

https://github.com/pingcap/tidb/blob/dd19e36c2839345cfae8d8fa46a77d74cdc395fa/expression/expressions/binop.go#L386-L420

所以只需要这样改coerceArithmetic就解决了。

而这次PR还改了unary.go。这个是为了解决类似:

select + cast("123" as binary);

的,只要跟着跑一下,同理的。

mysqldef: remove fsp codec, set out manually. #40

移除了PR#29中在编码解码中增加的offset,在测试数据改成手动设置offset。

发表评论

邮箱地址不会被公开。 必填项已用*标注

请输入正确的验证码