从这篇开始跟随commit记录来分析每一次的PR,来继续加深对tidb的理解。
这里以每次merge来整体分析。
#1
这次合并包含了一次commit:
这次commit只是修改了一下README.md。就不做什么分析了。
#3
这是第二个被合并进来的PR,也只包含了一次commit:
store: update boltdb package import.:
修复了之前引用了另外一个没包含进来的bolt包(在这之前其实没法正常编译的)。
#2
这个PR包含2个commit,不过都是针对gitignore的的修改。
这个也没什么好说的。
#4
这个PR包含一个commit,修改了Read.me的描述。
Improvement Documentation: various corrections of the English usage in readme
这个commit修改了一些描述的英语语法。
#5
这个PR也只有一次commit,
fix CurrentTimestamp check error for different timezones:
修改了expression/expressions/helper_test.go中“1970-01-01 08:20:34“由time.Unix(1234, 0).Format(mysql.TimeFormat)生成,并非直接写结果字符串,以修复在不同时区的带来的时差。
在test的检查函数里面找到原因:
v, err := GetTimeValue(ctx, t.Expr, mysql.TypeTimestamp, mysql.MinFsp) c.Assert(err, IsNil) switch x := v.(type) { case mysql.Time: c.Assert(x.String(), DeepEquals, t.Ret) default: c.Assert(x, DeepEquals, t.Ret) } }
进入GetTimeValue:
// GetTimeValue gets the time value with type tp. func GetTimeValue(ctx context.Context, v interface{}, tp byte, fsp int) (interface{}, error) { return getTimeValue(ctx, v, tp, fsp) } func getTimeValue(ctx context.Context, v interface{}, tp byte, fsp int) (interface{}, error) { value := mysql.Time{ Type: tp, Fsp: fsp, } defaultTime, err := getSystemTimestamp(ctx) if err != nil { return nil, errors.Trace(err) } switch x := v.(type) { case string: if x == CurrentTimestamp { value.Time = defaultTime } else if x == ZeroTimestamp { value, _ = mysql.ParseTimeFromNum(0, tp, fsp) } else { value, err = mysql.ParseTime(x, tp, fsp) if err != nil { return nil, errors.Trace(err) } }
这里传入的是string类型的CURRENT_TIMESTAMP,所以从getSystemTimestamp获得defaultTime后直接赋值给了结果value,然后进入getSystemTimestamp看一下:
func getSystemTimestamp(ctx context.Context) (time.Time, error) { value := time.Now() if ctx == nil { return value, nil } // check whether use timestamp varibale sessionVars := variable.GetSessionVars(ctx) if v, ok := sessionVars.Systems["timestamp"]; ok { if v != "" { timestamp, err := strconv.ParseInt(v, 10, 64) if err != nil { return time.Time{}, errors.Trace(err) } if timestamp <= 0 { return value, nil } return time.Unix(timestamp, 0), nil } } return value, nil }
这边判断了传入的ctx的SessionVars的map的timestamp值,而之前已经给这个值设置了”1234″:
sessionVars.Systems["timestamp"] = "1234" tbl := []struct { Expr interface{} Ret interface{} }{ {"2012-12-12 00:00:00", "2012-12-12 00:00:00"}, {CurrentTimestamp, time.Unix(1234, 0).Format(mysql.TimeFormat)}, {ZeroTimestamp, "0000-00-00 00:00:00"}, {Value{"2012-12-12 00:00:00"}, "2012-12-12 00:00:00"}, {Value{int64(0)}, "0000-00-00 00:00:00"}, {Value{}, nil}, {CurrentTimeExpr, CurrentTimestamp}, {NewUnaryOperation(opcode.Minus, Value{int64(0)}), "0000-00-00 00:00:00"}, {mockExpr{}, nil}, }
所以会返回return time.Unix(timestamp, 0), nil。和最新的修改的time.Unix(1234, 0).Format(mysql.TimeFormat)所匹配,如果还是之前的固定的时间”1970-01-01 08:20:34“的话,不在东八区运行的话时间就不是这个了。
Fix mysqldef test(#6)
这个PR包含两个commit:
min/max datetime use local location:
这两个commit需要一起看,首先在第一个commit删除的那行测试数据下面的测试函数:
for _, test := range table { // test ParseDatetimeFromNum t, err := ParseDatetimeFromNum(test.Input) if test.ExpectDateTimeError { c.Assert(err, NotNil) } else { c.Assert(err, IsNil) c.Assert(t.Type, Equals, TypeDatetime) } c.Assert(t.String(), Equals, test.ExpectDateTimeValue) // test ParseTimestampFromNum t, err = ParseTimestampFromNum(test.Input) if test.ExpectTimeStampError { c.Assert(err, NotNil) } else { c.Assert(err, IsNil) c.Assert(t.Type, Equals, TypeTimestamp) } c.Assert(t.String(), Equals, test.ExpectTimeStampValue) // test ParseDateFromNum t, err = ParseDateFromNum(test.Input) if test.ExpectDateTimeError { c.Assert(err, NotNil) } else { c.Assert(err, IsNil) c.Assert(t.Type, Equals, TypeDate) } c.Assert(t.String(), Equals, test.ExpectDateValue) } }
进入ParseDatetimeFromNum:
// ParseDatetimeFromNum is a helper function wrapping ParseTimeFromNum with datetime type and default fsp. func ParseDatetimeFromNum(num int64) (Time, error) { return ParseTimeFromNum(num, TypeDatetime, DefaultFsp) }
继续进入:
// ParseTimeFromNum parses a formatted int64, // returns the value which type is tp. func ParseTimeFromNum(num int64, tp byte, fsp int) (Time, error) { fsp, err := checkFsp(fsp) if err != nil { return Time{Time: ZeroTime, Type: tp}, errors.Trace(err) } t, err := parseDateTimeFromNum(num) if err != nil { return Time{Time: ZeroTime, Type: tp}, errors.Trace(err) } if !checkDatetime(t) { return Time{Time: ZeroTime, Type: tp}, ErrInvalidTimeFormat } t.Fsp = fsp return t.Convert(tp) }
这里面有个checkDatetime()来检查合法性:
func checkDatetime(t Time) bool { if t.IsZero() { return true } if t.Time.After(MaxDatetime) || t.Time.Before(MinDatetime) { return false } return true }
这里用t.Time.After(MaxDatetime) || t.Time.Before(MinDatetime)检查了是否超过最大最小范围,而MaxDatetime和MinDatetime的定义为:
// MinDatetime is the minimum for mysql datetime type. MinDatetime = time.Date(1000, 1, 1, 0, 0, 0, 0, time.Local) // MaxDatetime is the maximum for mysql datetime type. MaxDatetime = time.Date(9999, 12, 31, 23, 59, 59, 999999, time.Local)
而由于t.Time.After(MaxDatetime)和t.Time.Before(MinDatetime)都是用时间戳比较的,而t是在这里生成的:
return time.Date(year, time.Month(month), day, hour, minute, second, frac*1000, time.Local), nil }
所以必须统一时区。就有了第二个commit的把UTC时区改成了Local。
tools: add .travis.yml(#7)
这个PR增加了travis ci的脚本,也不必要多说了。
Update README.md(#9)
此PR在README.md增加了travis的构建图标。
types: Improve Convert function(#8)
这个PR把这段代码实现的功能写到了Convert函数:
if f.Tp.Tp == mysql.TypeString && f.Tp.Charset == charset.CharsetBin { nv = []byte(nv.(string)) } if f.Tp.Flen != types.UnspecifiedLength { switch f.Tp.Tp { case mysql.TypeString: v := nv.(string) if len(v) > int(f.Tp.Flen) { v = v[:f.Tp.Flen] } return v, nil } } if f.Tp.Tp == mysql.TypeLonglong { if mysql.HasUnsignedFlag(f.Tp.Flag) { return uint64(nv.(int64)), nil } }
然后:
if f.Tp.Flen != types.UnspecifiedLength { switch f.Tp.Tp { case mysql.TypeString: v := nv.(string) if len(v) > int(f.Tp.Flen) { v = v[:f.Tp.Flen] } return v, nil } }
这段功能已经包含在:
x = truncateStr(x, target.Flen)
最后加上对应的测试数据。
tools: use go1.5 for CI(#11)
这个PR把CI的go版本升级到了1.5
init stores when declare(#13)
这个PR谢大合并了stores = make(map[string]kv.Driver)的申明方式。
*: Remove conversion function(#14)
删除了conversion (并不是CONVERT)函数以及相关测试数据等,申砾说在mysql中没有用到这个。
util/types: support convert year(#10)
给Convert函数增加支持转换val值到mysql.TypeYear(是个int16)。
暂时先看这么多,今天写到这里啦。