从这篇开始跟随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)。
暂时先看这么多,今天写到这里啦。