func (s *testEvaluatorSuite) TestStrToDate(c *C) { tests := []struct { Date string Format string Success bool Expect time.Time }{ {"20161122165022", "%Y%m%d%H%i%s", true, time.Date(2016, 11, 22, 16, 50, 22, 0, time.Local)}, {"2016 11 22 16 50 22", "%Y%m%d%H%i%s", true, time.Date(2016, 11, 22, 16, 50, 22, 0, time.Local)}, {"16-50-22 2016 11 22", "%H-%i-%s%Y%m%d", true, time.Date(2016, 11, 22, 16, 50, 22, 0, time.Local)}, {"16-50 2016 11 22", "%H-%i-%s%Y%m%d", false, time.Time{}}, } for _, test := range tests { date := types.NewStringDatum(test.Date) format := types.NewStringDatum(test.Format) result, err := builtinStrToDate([]types.Datum{date, format}, s.ctx) if !test.Success { c.Assert(err, IsNil) c.Assert(result.IsNull(), IsTrue) continue } c.Assert(result.Kind(), Equals, types.KindMysqlTime) value := result.GetMysqlTime() t1, _ := value.Time.GoTime() c.Assert(t1, Equals, test.Expect) } }
func (s *testEvalSuite) TestEvalCoalesce(c *C) { colID := int64(1) row := make(map[int64]types.Datum) row[colID] = types.NewIntDatum(100) xevaluator := &Evaluator{Row: row} nullDatum := types.Datum{} nullDatum.SetNull() notNullDatum := types.NewStringDatum("not-null") cases := []struct { expr *tipb.Expr result types.Datum }{ { expr: buildExpr(tipb.ExprType_Coalesce, nullDatum, nullDatum, nullDatum), result: nullDatum, }, { expr: buildExpr(tipb.ExprType_Coalesce, nullDatum, notNullDatum, nullDatum), result: notNullDatum, }, { expr: buildExpr(tipb.ExprType_Coalesce, nullDatum, notNullDatum, types.NewStringDatum("not-null-2"), nullDatum), result: notNullDatum, }, } for _, ca := range cases { result, err := xevaluator.Eval(ca.expr) c.Assert(err, IsNil) c.Assert(result.Kind(), Equals, ca.result.Kind()) cmp, err := result.CompareDatum(xevaluator.sc, ca.result) c.Assert(err, IsNil) c.Assert(cmp, Equals, 0) } }
func (s *testEvalSuite) TestEvalIfNull(c *C) { colID := int64(1) xevaluator := NewEvaluator(new(variable.StatementContext)) xevaluator.Row[colID] = types.NewDatum(100) null, notNull, expr := types.Datum{}, types.NewStringDatum("left"), types.NewStringDatum("right") cases := []struct { expr *tipb.Expr result types.Datum }{ { expr: buildExpr(tipb.ExprType_IfNull, null, expr), result: expr, }, { expr: buildExpr(tipb.ExprType_IfNull, notNull, expr), result: notNull, }, { expr: buildExpr(tipb.ExprType_IfNull, notNull, null), result: notNull, }, } for _, ca := range cases { result, err := xevaluator.Eval(ca.expr) c.Assert(err, IsNil) c.Assert(result.Kind(), Equals, ca.result.Kind()) cmp, err := result.CompareDatum(xevaluator.sc, ca.result) c.Assert(err, IsNil) c.Assert(cmp, Equals, 0) } }
func (s *testEvaluatorSuite) TestFromUnixTime(c *C) { defer testleak.AfterTest(c)() tbl := []struct { isDecimal bool integralPart int64 fractionalPart int64 decimal float64 format string ansLen int }{ {false, 1451606400, 0, 0, "", 19}, {true, 1451606400, 123456000, 1451606400.123456, "", 26}, {true, 1451606400, 999999000, 1451606400.999999, "", 26}, {true, 1451606400, 999999900, 1451606400.9999999, "", 19}, {false, 1451606400, 0, 0, "%Y %D %M %h:%i:%s %x", 19}, {true, 1451606400, 123456000, 1451606400.123456, "%Y %D %M %h:%i:%s %x", 26}, {true, 1451606400, 999999000, 1451606400.999999, "%Y %D %M %h:%i:%s %x", 26}, {true, 1451606400, 999999900, 1451606400.9999999, "%Y %D %M %h:%i:%s %x", 19}, } for _, t := range tbl { var timestamp types.Datum if !t.isDecimal { timestamp.SetInt64(t.integralPart) } else { timestamp.SetFloat64(t.decimal) } // result of from_unixtime() is dependent on specific time zone. unixTime := time.Unix(t.integralPart, t.fractionalPart).Round(time.Microsecond).String()[:t.ansLen] if len(t.format) == 0 { v, err := builtinFromUnixTime([]types.Datum{timestamp}, s.ctx) c.Assert(err, IsNil) ans := v.GetMysqlTime() c.Assert(ans.String(), Equals, unixTime) } else { format := types.NewStringDatum(t.format) v, err := builtinFromUnixTime([]types.Datum{timestamp, format}, s.ctx) c.Assert(err, IsNil) result, err := builtinDateFormat([]types.Datum{types.NewStringDatum(unixTime), format}, s.ctx) c.Assert(err, IsNil) c.Assert(v.GetString(), Equals, result.GetString()) } } v, err := builtinFromUnixTime([]types.Datum{types.NewIntDatum(-12345)}, s.ctx) c.Assert(err, IsNil) c.Assert(v.Kind(), Equals, types.KindNull) _, err = builtinFromUnixTime([]types.Datum{types.NewIntDatum(math.MaxInt32 + 1)}, s.ctx) c.Assert(err, IsNil) c.Assert(v.Kind(), Equals, types.KindNull) }
// HashCode implements Expression interface. func (col *Column) HashCode() []byte { if len(col.hashcode) != 0 { return col.hashcode } col.hashcode, _ = codec.EncodeValue(col.hashcode, types.NewStringDatum(col.FromID), types.NewIntDatum(int64(col.Position))) return col.hashcode }
func (s *testEvaluatorSuite) TestTimeDiff(c *C) { // Test cases from https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_timediff tests := []struct { t1 string t2 string expectStr string }{ {"2000:01:01 00:00:00", "2000:01:01 00:00:00.000001", "-00:00:00.000001"}, {"2008-12-31 23:59:59.000001", "2008-12-30 01:01:01.000002", "46:58:57.999999"}, } for _, test := range tests { t1 := types.NewStringDatum(test.t1) t2 := types.NewStringDatum(test.t2) result, err := builtinTimeDiff([]types.Datum{t1, t2}, s.ctx) c.Assert(err, IsNil) c.Assert(result.GetMysqlDuration().String(), Equals, test.expectStr) } }
func (*testSessionSuite) TestSession(c *C) { ctx := mock.NewContext() variable.BindSessionVars(ctx) v := variable.GetSessionVars(ctx) c.Assert(v, NotNil) // For AffectedRows v.AddAffectedRows(1) c.Assert(v.AffectedRows, Equals, uint64(1)) v.AddAffectedRows(1) c.Assert(v.AffectedRows, Equals, uint64(2)) // For FoundRows v.AddFoundRows(1) c.Assert(v.FoundRows, Equals, uint64(1)) v.AddFoundRows(1) c.Assert(v.FoundRows, Equals, uint64(2)) // For last insert id v.SetLastInsertID(uint64(1)) c.Assert(v.LastInsertID, Equals, uint64(1)) v.SetSystemVar("autocommit", types.NewStringDatum("1")) val := v.GetSystemVar("autocommit") c.Assert(val.GetString(), Equals, "1") c.Assert(v.SetSystemVar("autocommit", types.Datum{}), NotNil) v.SetSystemVar("sql_mode", types.NewStringDatum("strict_trans_tables")) val = v.GetSystemVar("sql_mode") c.Assert(val.GetString(), Equals, "STRICT_TRANS_TABLES") c.Assert(v.StrictSQLMode, IsTrue) v.SetSystemVar("sql_mode", types.NewStringDatum("")) c.Assert(v.StrictSQLMode, IsFalse) v.SetSystemVar("character_set_connection", types.NewStringDatum("utf8")) v.SetSystemVar("collation_connection", types.NewStringDatum("utf8_general_ci")) charset, collation := variable.GetCharsetInfo(ctx) c.Assert(charset, Equals, "utf8") c.Assert(collation, Equals, "utf8_general_ci") c.Assert(v.SetSystemVar("character_set_results", types.Datum{}), IsNil) }
func (e *SetExecutor) getVarValue(v *expression.VarAssignment, sysVar *variable.SysVar) (value types.Datum, err error) { if v.IsDefault { // To set a SESSION variable to the GLOBAL value or a GLOBAL value // to the compiled-in MySQL default value, use the DEFAULT keyword. // See http://dev.mysql.com/doc/refman/5.7/en/set-statement.html if sysVar != nil { value = types.NewStringDatum(sysVar.Value) } else { s, err1 := e.ctx.GetSessionVars().GlobalVarsAccessor.GetGlobalSysVar(strings.ToLower(v.Name)) if err1 != nil { return value, errors.Trace(err1) } value = types.NewStringDatum(s) } return } value, err = v.Expr.Eval(nil, e.ctx) return value, errors.Trace(err) }
func (e *SimpleExec) getVarValue(v *ast.VariableAssignment, sysVar *variable.SysVar, globalVars variable.GlobalVarAccessor) (value types.Datum, err error) { switch v.Value.(type) { case *ast.DefaultExpr: // To set a SESSION variable to the GLOBAL value or a GLOBAL value // to the compiled-in MySQL default value, use the DEFAULT keyword. // See http://dev.mysql.com/doc/refman/5.7/en/set-statement.html if sysVar != nil { value = types.NewStringDatum(sysVar.Value) } else { s, err1 := globalVars.GetGlobalSysVar(e.ctx, strings.ToLower(v.Name)) if err1 != nil { return value, errors.Trace(err1) } value = types.NewStringDatum(s) } default: value, err = evaluator.Eval(e.ctx, v.Value) } return value, errors.Trace(err) }
// HashCode implements Expression interface. func (sf *ScalarFunction) HashCode() []byte { var bytes []byte v := make([]types.Datum, 0, len(sf.Args)+1) bytes, _ = codec.EncodeValue(bytes, types.NewStringDatum(sf.FuncName.L)) v = append(v, types.NewBytesDatum(bytes)) for _, arg := range sf.Args { v = append(v, types.NewBytesDatum(arg.HashCode())) } bytes = bytes[:0] bytes, _ = codec.EncodeValue(bytes, v...) return bytes }
func (e *SimpleExec) setCharset(cs, co string) error { var err error if len(co) == 0 { co, err = charset.GetDefaultCollation(cs) if err != nil { return errors.Trace(err) } } sessionVars := variable.GetSessionVars(e.ctx) for _, v := range variable.SetNamesVariables { err = sessionVars.SetSystemVar(v, types.NewStringDatum(cs)) if err != nil { return errors.Trace(err) } } err = sessionVars.SetSystemVar(variable.CollationConnection, types.NewStringDatum(co)) if err != nil { return errors.Trace(err) } return nil }
func (e *SimpleExec) executeUse(s *ast.UseStmt) error { dbname := model.NewCIStr(s.DBName) dbinfo, exists := sessionctx.GetDomain(e.ctx).InfoSchema().SchemaByName(dbname) if !exists { return infoschema.ErrDatabaseNotExists.Gen("database %s not exists", dbname) } db.BindCurrentSchema(e.ctx, dbname.O) // character_set_database is the character set used by the default database. // The server sets this variable whenever the default database changes. // See http://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_character_set_database sessionVars := variable.GetSessionVars(e.ctx) err := sessionVars.SetSystemVar(variable.CharsetDatabase, types.NewStringDatum(dbinfo.Charset)) if err != nil { return errors.Trace(err) } err = sessionVars.SetSystemVar(variable.CollationDatabase, types.NewStringDatum(dbinfo.Collate)) if err != nil { return errors.Trace(err) } return nil }
func (e *SimpleExec) executeSetCharset(s *ast.SetCharsetStmt) error { collation := s.Collate var err error if len(collation) == 0 { collation, err = charset.GetDefaultCollation(s.Charset) if err != nil { return errors.Trace(err) } } sessionVars := variable.GetSessionVars(e.ctx) for _, v := range variable.SetNamesVariables { err = sessionVars.SetSystemVar(v, types.NewStringDatum(s.Charset)) if err != nil { return errors.Trace(err) } } err = sessionVars.SetSystemVar(variable.CollationConnection, types.NewStringDatum(collation)) if err != nil { return errors.Trace(err) } return nil }
func (s *testVarsutilSuite) TestVarsutil(c *C) { defer testleak.AfterTest(c)() v := variable.NewSessionVars() SetSystemVar(v, "autocommit", types.NewStringDatum("1")) val := GetSystemVar(v, "autocommit") c.Assert(val.GetString(), Equals, "1") c.Assert(SetSystemVar(v, "autocommit", types.Datum{}), NotNil) SetSystemVar(v, "sql_mode", types.NewStringDatum("strict_trans_tables")) val = GetSystemVar(v, "sql_mode") c.Assert(val.GetString(), Equals, "STRICT_TRANS_TABLES") c.Assert(v.StrictSQLMode, IsTrue) SetSystemVar(v, "sql_mode", types.NewStringDatum("")) c.Assert(v.StrictSQLMode, IsFalse) SetSystemVar(v, "character_set_connection", types.NewStringDatum("utf8")) SetSystemVar(v, "collation_connection", types.NewStringDatum("utf8_general_ci")) charset, collation := v.GetCharsetInfo() c.Assert(charset, Equals, "utf8") c.Assert(collation, Equals, "utf8_general_ci") c.Assert(SetSystemVar(v, "character_set_results", types.Datum{}), IsNil) // Test case for get TiDBSkipConstraintCheck session variable d := GetSystemVar(v, variable.TiDBSkipConstraintCheck) c.Assert(d.GetString(), Equals, "0") // Test case for tidb_skip_constraint_check c.Assert(v.SkipConstraintCheck, IsFalse) SetSystemVar(v, variable.TiDBSkipConstraintCheck, types.NewStringDatum("0")) c.Assert(v.SkipConstraintCheck, IsFalse) SetSystemVar(v, variable.TiDBSkipConstraintCheck, types.NewStringDatum("1")) c.Assert(v.SkipConstraintCheck, IsTrue) SetSystemVar(v, variable.TiDBSkipConstraintCheck, types.NewStringDatum("0")) c.Assert(v.SkipConstraintCheck, IsFalse) // Test case for change TiDBSkipConstraintCheck session variable. SetSystemVar(v, variable.TiDBSkipConstraintCheck, types.NewStringDatum("1")) d = GetSystemVar(v, variable.TiDBSkipConstraintCheck) c.Assert(d.GetString(), Equals, "1") }
func abbrDayOfMonth(arg types.Datum, ctx context.Context) (types.Datum, error) { day, err := builtinDayOfMonth([]types.Datum{arg}, ctx) if err != nil || arg.IsNull() { return types.Datum{}, errors.Trace(err) } var str string switch day.GetInt64() { case 1, 21, 31: str = "st" case 2, 22: str = "nd" case 3, 23: str = "rd" default: str = "th" } d := types.NewStringDatum(fmt.Sprintf("%d%s", day.GetInt64(), str)) return d, nil }
func (er *expressionRewriter) rewriteVariable(v *ast.VariableExpr) bool { stkLen := len(er.ctxStack) name := strings.ToLower(v.Name) sessionVars := variable.GetSessionVars(er.b.ctx) globalVars := variable.GetGlobalVarAccessor(er.b.ctx) if !v.IsSystem { var d types.Datum var err error if v.Value != nil { d, err = er.ctxStack[stkLen-1].Eval(nil, er.b.ctx) if err != nil { er.err = errors.Trace(err) return false } er.ctxStack = er.ctxStack[:stkLen-1] } if !d.IsNull() { strVal, err := d.ToString() if err != nil { er.err = errors.Trace(err) return false } sessionVars.Users[name] = strings.ToLower(strVal) er.ctxStack = append(er.ctxStack, datumToConstant(d, mysql.TypeString)) } else if value, ok := sessionVars.Users[name]; ok { er.ctxStack = append(er.ctxStack, datumToConstant(types.NewStringDatum(value), mysql.TypeString)) } else { // select null user vars is permitted. er.ctxStack = append(er.ctxStack, &expression.Constant{RetType: types.NewFieldType(mysql.TypeNull)}) } return true } sysVar, ok := variable.SysVars[name] if !ok { // select null sys vars is not permitted er.err = variable.UnknownSystemVar.Gen("Unknown system variable '%s'", name) return false } if sysVar.Scope == variable.ScopeNone { er.ctxStack = append(er.ctxStack, datumToConstant(types.NewDatum(sysVar.Value), mysql.TypeString)) return true } if v.IsGlobal { value, err := globalVars.GetGlobalSysVar(er.b.ctx, name) if err != nil { er.err = errors.Trace(err) return false } er.ctxStack = append(er.ctxStack, datumToConstant(types.NewDatum(value), mysql.TypeString)) return true } d := sessionVars.GetSystemVar(name) if d.IsNull() { if sysVar.Scope&variable.ScopeGlobal == 0 { d.SetString(sysVar.Value) } else { // Get global system variable and fill it in session. globalVal, err := globalVars.GetGlobalSysVar(er.b.ctx, name) if err != nil { er.err = errors.Trace(err) return false } d.SetString(globalVal) err = sessionVars.SetSystemVar(name, d) if err != nil { er.err = errors.Trace(err) return false } } } er.ctxStack = append(er.ctxStack, datumToConstant(d, mysql.TypeString)) return true }
// TODO: add more tests. func (s *testEvalSuite) TestEval(c *C) { colID := int64(1) row := make(map[int64]types.Datum) row[colID] = types.NewIntDatum(100) xevaluator := &Evaluator{Row: row} cases := []struct { expr *tipb.Expr result types.Datum }{ // Datums. { datumExpr(types.NewFloat32Datum(1.1)), types.NewFloat32Datum(1.1), }, { datumExpr(types.NewFloat64Datum(1.1)), types.NewFloat64Datum(1.1), }, { datumExpr(types.NewIntDatum(1)), types.NewIntDatum(1), }, { datumExpr(types.NewUintDatum(1)), types.NewUintDatum(1), }, { datumExpr(types.NewBytesDatum([]byte("abc"))), types.NewBytesDatum([]byte("abc")), }, { datumExpr(types.NewStringDatum("abc")), types.NewStringDatum("abc"), }, { datumExpr(types.Datum{}), types.Datum{}, }, { datumExpr(types.NewDurationDatum(mysql.Duration{Duration: time.Hour})), types.NewDurationDatum(mysql.Duration{Duration: time.Hour}), }, { datumExpr(types.NewDecimalDatum(mysql.NewDecFromFloatForTest(1.1))), types.NewDecimalDatum(mysql.NewDecFromFloatForTest(1.1)), }, { columnExpr(1), types.NewIntDatum(100), }, // Comparison operations. { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(1), tipb.ExprType_LT), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(1), types.NewIntDatum(100), tipb.ExprType_LT), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_LT), types.Datum{}, }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(1), tipb.ExprType_LE), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(1), types.NewIntDatum(1), tipb.ExprType_LE), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_LE), types.Datum{}, }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(1), tipb.ExprType_EQ), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(100), tipb.ExprType_EQ), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_EQ), types.Datum{}, }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(100), tipb.ExprType_NE), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(1), tipb.ExprType_NE), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_NE), types.Datum{}, }, { binaryExpr(types.NewIntDatum(1), types.NewIntDatum(100), tipb.ExprType_GE), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(100), tipb.ExprType_GE), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_GE), types.Datum{}, }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(100), tipb.ExprType_GT), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(100), types.NewIntDatum(1), tipb.ExprType_GT), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(100), types.Datum{}, tipb.ExprType_GT), types.Datum{}, }, { binaryExpr(types.NewIntDatum(1), types.Datum{}, tipb.ExprType_NullEQ), types.NewIntDatum(0), }, { binaryExpr(types.Datum{}, types.Datum{}, tipb.ExprType_NullEQ), types.NewIntDatum(1), }, // Logic operation. { binaryExpr(types.NewIntDatum(0), types.NewIntDatum(1), tipb.ExprType_And), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(1), types.NewIntDatum(1), tipb.ExprType_And), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(0), types.Datum{}, tipb.ExprType_And), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(1), types.Datum{}, tipb.ExprType_And), types.Datum{}, }, { binaryExpr(types.NewIntDatum(0), types.NewIntDatum(0), tipb.ExprType_Or), types.NewIntDatum(0), }, { binaryExpr(types.NewIntDatum(0), types.NewIntDatum(1), tipb.ExprType_Or), types.NewIntDatum(1), }, { binaryExpr(types.NewIntDatum(0), types.Datum{}, tipb.ExprType_Or), types.Datum{}, }, { binaryExpr(types.NewIntDatum(1), types.Datum{}, tipb.ExprType_Or), types.NewIntDatum(1), }, { binaryExpr( binaryExpr(types.NewIntDatum(1), types.NewIntDatum(1), tipb.ExprType_EQ), binaryExpr(types.NewIntDatum(1), types.NewIntDatum(1), tipb.ExprType_EQ), tipb.ExprType_And), types.NewIntDatum(1), }, { notExpr(datumExpr(types.NewIntDatum(1))), types.NewIntDatum(0), }, { notExpr(datumExpr(types.NewIntDatum(0))), types.NewIntDatum(1), }, { notExpr(datumExpr(types.Datum{})), types.Datum{}, }, } for _, ca := range cases { result, err := xevaluator.Eval(ca.expr) c.Assert(err, IsNil) c.Assert(result.Kind(), Equals, ca.result.Kind()) cmp, err := result.CompareDatum(ca.result) c.Assert(err, IsNil) c.Assert(cmp, Equals, 0) } }
func likeExpr(target, pattern string) *tipb.Expr { targetExpr := datumExpr(types.NewStringDatum(target)) patternExpr := datumExpr(types.NewStringDatum(pattern)) return &tipb.Expr{Tp: tipb.ExprType_Like, Children: []*tipb.Expr{targetExpr, patternExpr}} }
func (s *testColumnSuite) TestGetZeroValue(c *C) { cases := []struct { ft *types.FieldType value types.Datum }{ { types.NewFieldType(mysql.TypeLong), types.NewIntDatum(0), }, { &types.FieldType{ Tp: mysql.TypeLonglong, Flag: mysql.UnsignedFlag, }, types.NewUintDatum(0), }, { types.NewFieldType(mysql.TypeFloat), types.NewFloat32Datum(0), }, { types.NewFieldType(mysql.TypeDouble), types.NewFloat64Datum(0), }, { types.NewFieldType(mysql.TypeNewDecimal), types.NewDecimalDatum(mysql.NewDecimalFromInt(0, 0)), }, { types.NewFieldType(mysql.TypeVarchar), types.NewStringDatum(""), }, { types.NewFieldType(mysql.TypeBlob), types.NewBytesDatum([]byte{}), }, { types.NewFieldType(mysql.TypeDuration), types.NewDurationDatum(mysql.ZeroDuration), }, { types.NewFieldType(mysql.TypeDatetime), types.NewDatum(mysql.ZeroDatetime), }, { types.NewFieldType(mysql.TypeTimestamp), types.NewDatum(mysql.ZeroTimestamp), }, { types.NewFieldType(mysql.TypeDate), types.NewDatum(mysql.ZeroDate), }, { types.NewFieldType(mysql.TypeBit), types.NewDatum(mysql.Bit{Value: 0, Width: mysql.MinBitWidth}), }, { types.NewFieldType(mysql.TypeSet), types.NewDatum(mysql.Set{}), }, } for _, ca := range cases { colInfo := &model.ColumnInfo{FieldType: *ca.ft} zv := getZeroValue(colInfo) c.Assert(zv.Kind(), Equals, ca.value.Kind()) cmp, err := zv.CompareDatum(ca.value) c.Assert(err, IsNil) c.Assert(cmp, Equals, 0) } }
func (s *testEvalSuite) TestEvalCaseWhen(c *C) { colID := int64(1) xevaluator := NewEvaluator(new(variable.StatementContext)) xevaluator.Row[colID] = types.NewIntDatum(100) trueCond := types.NewIntDatum(1) falseCond := types.NewIntDatum(0) nullCond := types.Datum{} nullCond.SetNull() cases := []struct { expr *tipb.Expr result types.Datum }{ { expr: buildExpr(tipb.ExprType_Case, falseCond, types.NewStringDatum("case1"), trueCond, types.NewStringDatum("case2"), trueCond, types.NewStringDatum("case3")), result: types.NewStringDatum("case2"), }, { expr: buildExpr(tipb.ExprType_Case, falseCond, types.NewStringDatum("case1"), falseCond, types.NewStringDatum("case2"), falseCond, types.NewStringDatum("case3"), types.NewStringDatum("Else")), result: types.NewStringDatum("Else"), }, { expr: buildExpr(tipb.ExprType_Case, falseCond, types.NewStringDatum("case1"), falseCond, types.NewStringDatum("case2"), falseCond, types.NewStringDatum("case3")), result: types.Datum{}, }, { expr: buildExpr(tipb.ExprType_Case, buildExpr(tipb.ExprType_Case, falseCond, types.NewIntDatum(0), trueCond, types.NewIntDatum(1), ), types.NewStringDatum("nested case when"), falseCond, types.NewStringDatum("case1"), trueCond, types.NewStringDatum("case2"), trueCond, types.NewStringDatum("case3")), result: types.NewStringDatum("nested case when"), }, { expr: buildExpr(tipb.ExprType_Case, nullCond, types.NewStringDatum("case1"), falseCond, types.NewStringDatum("case2"), trueCond, types.NewStringDatum("case3")), result: types.NewStringDatum("case3"), }, } for _, ca := range cases { result, err := xevaluator.Eval(ca.expr) c.Assert(err, IsNil) c.Assert(result.Kind(), Equals, ca.result.Kind()) cmp, err := result.CompareDatum(xevaluator.sc, ca.result) c.Assert(err, IsNil) c.Assert(cmp, Equals, 0) } }
func (s *testEvalSuite) TestEvalIf(c *C) { colID := int64(1) xevaluator := NewEvaluator(new(variable.StatementContext)) xevaluator.Row[colID] = types.NewIntDatum(100) trueCond, falseCond, null := types.NewIntDatum(1), types.NewIntDatum(0), types.Datum{} expr1, expr2 := types.NewStringDatum("expr1"), types.NewStringDatum("expr2") cases := []struct { expr *tipb.Expr result types.Datum }{ { expr: buildExpr(tipb.ExprType_If, trueCond, types.NewStringDatum("expr1"), types.NewStringDatum("expr2")), result: expr1, }, { expr: buildExpr(tipb.ExprType_If, falseCond, types.NewStringDatum("expr1"), types.NewStringDatum("expr2")), result: expr2, }, { expr: buildExpr(tipb.ExprType_If, null, types.NewStringDatum("expr1"), types.NewStringDatum("expr2")), result: expr2, }, { expr: buildExpr(tipb.ExprType_If, trueCond, null, types.NewStringDatum("expr2")), result: null, }, { expr: buildExpr(tipb.ExprType_If, falseCond, types.NewStringDatum("expr1"), null), result: null, }, { expr: buildExpr(tipb.ExprType_If, trueCond, types.NewStringDatum("expr1"), types.NewStringDatum("expr2")), result: expr1, }, { expr: buildExpr(tipb.ExprType_If, buildExpr(tipb.ExprType_If, trueCond, null, trueCond), buildExpr(tipb.ExprType_If, trueCond, expr1, expr2), buildExpr(tipb.ExprType_If, falseCond, expr1, expr2)), result: expr2, }, } for _, ca := range cases { result, err := xevaluator.Eval(ca.expr) c.Assert(err, IsNil) c.Assert(result.Kind(), Equals, ca.result.Kind()) cmp, err := result.CompareDatum(xevaluator.sc, ca.result) c.Assert(err, IsNil) c.Assert(cmp, Equals, 0) } }
func (er *expressionRewriter) rewriteVariable(v *ast.VariableExpr) { stkLen := len(er.ctxStack) name := strings.ToLower(v.Name) sessionVars := variable.GetSessionVars(er.b.ctx) globalVars := variable.GetGlobalVarAccessor(er.b.ctx) if !v.IsSystem { if v.Value != nil { er.ctxStack[stkLen-1], er.err = expression.NewFunction(ast.SetVar, er.ctxStack[stkLen-1].GetType(), datumToConstant(types.NewDatum(name), mysql.TypeString), er.ctxStack[stkLen-1]) return } if _, ok := sessionVars.Users[name]; ok { f, err := expression.NewFunction(ast.GetVar, // TODO: Here is wrong, the sessionVars should store a name -> Datum map. Will fix it later. types.NewFieldType(mysql.TypeString), datumToConstant(types.NewStringDatum(name), mysql.TypeString)) if err != nil { er.err = errors.Trace(err) return } er.ctxStack = append(er.ctxStack, f) } else { // select null user vars is permitted. er.ctxStack = append(er.ctxStack, &expression.Constant{RetType: types.NewFieldType(mysql.TypeNull)}) } return } sysVar, ok := variable.SysVars[name] if !ok { // select null sys vars is not permitted er.err = variable.UnknownSystemVar.Gen("Unknown system variable '%s'", name) return } if sysVar.Scope == variable.ScopeNone { er.ctxStack = append(er.ctxStack, datumToConstant(types.NewDatum(sysVar.Value), mysql.TypeString)) return } if v.IsGlobal { value, err := globalVars.GetGlobalSysVar(er.b.ctx, name) if err != nil { er.err = errors.Trace(err) return } er.ctxStack = append(er.ctxStack, datumToConstant(types.NewDatum(value), mysql.TypeString)) return } d := sessionVars.GetSystemVar(name) if d.IsNull() { if sysVar.Scope&variable.ScopeGlobal == 0 { d.SetString(sysVar.Value) } else { // Get global system variable and fill it in session. globalVal, err := globalVars.GetGlobalSysVar(er.b.ctx, name) if err != nil { er.err = errors.Trace(err) return } d.SetString(globalVal) err = sessionVars.SetSystemVar(name, d) if err != nil { er.err = errors.Trace(err) return } } } er.ctxStack = append(er.ctxStack, datumToConstant(d, mysql.TypeString)) return }
func (r *rangeBuilder) newBuildFromPatternLike(expr *expression.ScalarFunction) []rangePoint { pattern, err := expr.Args[1].(*expression.Constant).Value.ToString() if err != nil { r.err = errors.Trace(err) return fullRange } if pattern == "" { startPoint := rangePoint{value: types.NewStringDatum(""), start: true} endPoint := rangePoint{value: types.NewStringDatum("")} return []rangePoint{startPoint, endPoint} } lowValue := make([]byte, 0, len(pattern)) escape := byte(expr.Args[2].(*expression.Constant).Value.GetInt64()) var exclude bool isExactMatch := true for i := 0; i < len(pattern); i++ { if pattern[i] == escape { i++ if i < len(pattern) { lowValue = append(lowValue, pattern[i]) } else { lowValue = append(lowValue, escape) } continue } if pattern[i] == '%' { // Get the prefix. isExactMatch = false break } else if pattern[i] == '_' { // Get the prefix, but exclude the prefix. // e.g., "abc_x", the start point exclude "abc", // because the string length is more than 3. exclude = true isExactMatch = false break } lowValue = append(lowValue, pattern[i]) } if len(lowValue) == 0 { return []rangePoint{{value: types.MinNotNullDatum(), start: true}, {value: types.MaxValueDatum()}} } if isExactMatch { val := types.NewStringDatum(string(lowValue)) return []rangePoint{{value: val, start: true}, {value: val}} } startPoint := rangePoint{start: true, excl: exclude} startPoint.value.SetBytesAsString(lowValue) highValue := make([]byte, len(lowValue)) copy(highValue, lowValue) endPoint := rangePoint{excl: true} for i := len(highValue) - 1; i >= 0; i-- { // Make the end point value more than the start point value, // and the length of the end point value is the same as the length of the start point value. // e.g., the start point value is "abc", so the end point value is "abd". highValue[i]++ if highValue[i] != 0 { endPoint.value.SetBytesAsString(highValue) break } // If highValue[i] is 255 and highValue[i]++ is 0, then the end point value is max value. if i == 0 { endPoint.value = types.MaxValueDatum() } } return []rangePoint{startPoint, endPoint} }
func (s *testBinlogSuite) TestBinlog(c *C) { tk := testkit.NewTestKit(c, s.store) tk.MustExec("use test") pump := s.pump tk.MustExec("drop table if exists local_binlog") ddlQuery := "create table local_binlog (id int primary key, name varchar(10))" tk.MustExec(ddlQuery) time.Sleep(time.Millisecond) checkLatestBinlogDDL(c, pump, ddlQuery) tk.MustExec("insert local_binlog values (1, 'abc'), (2, 'cde')") prewriteVal := getLatestBinlogPrewriteValue(c, pump) c.Assert(prewriteVal.SchemaVersion, Greater, int64(0)) c.Assert(prewriteVal.Mutations[0].TableId, Greater, int64(0)) expected := [][]types.Datum{ {types.NewIntDatum(1), types.NewStringDatum("abc")}, {types.NewIntDatum(2), types.NewStringDatum("cde")}, } gotRows := mutationRowsToRows(c, prewriteVal.Mutations[0].InsertedRows, 0, 2) c.Assert(gotRows, DeepEquals, expected) tk.MustExec("update local_binlog set name = 'xyz' where id = 2") prewriteVal = getLatestBinlogPrewriteValue(c, pump) expected = [][]types.Datum{ {types.NewIntDatum(2), types.NewStringDatum("xyz")}, } gotRows = mutationRowsToRows(c, prewriteVal.Mutations[0].UpdatedRows, 2, 4) c.Assert(gotRows, DeepEquals, expected) tk.MustExec("delete from local_binlog where id = 1") prewriteVal = getLatestBinlogPrewriteValue(c, pump) c.Assert(prewriteVal.Mutations[0].DeletedIds, DeepEquals, []int64{1}) // Test table primary key is not integer. tk.MustExec("create table local_binlog2 (name varchar(64) primary key, age int)") tk.MustExec("insert local_binlog2 values ('abc', 16), ('def', 18)") tk.MustExec("delete from local_binlog2 where name = 'def'") prewriteVal = getLatestBinlogPrewriteValue(c, pump) _, deletedPK, _ := codec.DecodeOne(prewriteVal.Mutations[0].DeletedPks[0]) c.Assert(deletedPK.GetString(), Equals, "def") // Test Table don't have primary key. tk.MustExec("create table local_binlog3 (c1 int, c2 int)") tk.MustExec("insert local_binlog3 values (1, 2), (1, 3), (2, 3)") tk.MustExec("update local_binlog3 set c1 = 3 where c1 = 2") prewriteVal = getLatestBinlogPrewriteValue(c, pump) gotRows = mutationRowsToRows(c, prewriteVal.Mutations[0].UpdatedRows, 5, 7) expected = [][]types.Datum{ {types.NewIntDatum(3), types.NewIntDatum(3)}, } c.Assert(gotRows, DeepEquals, expected) tk.MustExec("delete from local_binlog3 where c1 = 3 and c2 = 3") prewriteVal = getLatestBinlogPrewriteValue(c, pump) gotRows = mutationRowsToRows(c, prewriteVal.Mutations[0].DeletedRows, 1, 3) expected = [][]types.Datum{ {types.NewIntDatum(3), types.NewIntDatum(3)}, } c.Assert(gotRows, DeepEquals, expected) checkBinlogCount(c, pump) pump.mu.Lock() originBinlogLen := len(pump.mu.payloads) pump.mu.Unlock() tk.MustExec("set @@global.autocommit = 0") tk.MustExec("set @@global.autocommit = 1") pump.mu.Lock() newBinlogLen := len(pump.mu.payloads) pump.mu.Unlock() c.Assert(newBinlogLen, Equals, originBinlogLen) }
func (s *testEvaluatorSuite) TestGetTimeValue(c *C) { defer testleak.AfterTest(c)() v, err := GetTimeValue(nil, "2012-12-12 00:00:00", mysql.TypeTimestamp, mysql.MinFsp) c.Assert(err, IsNil) c.Assert(v.Kind(), Equals, types.KindMysqlTime) timeValue := v.GetMysqlTime() c.Assert(timeValue.String(), Equals, "2012-12-12 00:00:00") ctx := mock.NewContext() variable.BindSessionVars(ctx) sessionVars := variable.GetSessionVars(ctx) sessionVars.SetSystemVar("timestamp", types.NewStringDatum("")) v, err = GetTimeValue(ctx, "2012-12-12 00:00:00", mysql.TypeTimestamp, mysql.MinFsp) c.Assert(err, IsNil) c.Assert(v.Kind(), Equals, types.KindMysqlTime) timeValue = v.GetMysqlTime() c.Assert(timeValue.String(), Equals, "2012-12-12 00:00:00") sessionVars.SetSystemVar("timestamp", types.NewStringDatum("0")) v, err = GetTimeValue(ctx, "2012-12-12 00:00:00", mysql.TypeTimestamp, mysql.MinFsp) c.Assert(err, IsNil) c.Assert(v.Kind(), Equals, types.KindMysqlTime) timeValue = v.GetMysqlTime() c.Assert(timeValue.String(), Equals, "2012-12-12 00:00:00") sessionVars.SetSystemVar("timestamp", types.Datum{}) v, err = GetTimeValue(ctx, "2012-12-12 00:00:00", mysql.TypeTimestamp, mysql.MinFsp) c.Assert(err, IsNil) c.Assert(v.Kind(), Equals, types.KindMysqlTime) timeValue = v.GetMysqlTime() c.Assert(timeValue.String(), Equals, "2012-12-12 00:00:00") sessionVars.SetSystemVar("timestamp", types.NewStringDatum("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"}, {ast.NewValueExpr("2012-12-12 00:00:00"), "2012-12-12 00:00:00"}, {ast.NewValueExpr(int64(0)), "0000-00-00 00:00:00"}, {ast.NewValueExpr(nil), nil}, {&ast.FuncCallExpr{FnName: model.NewCIStr(CurrentTimestamp)}, CurrentTimestamp}, {&ast.UnaryOperationExpr{Op: opcode.Minus, V: ast.NewValueExpr(int64(0))}, "0000-00-00 00:00:00"}, } for i, t := range tbl { comment := Commentf("expr: %d", i) v, err := GetTimeValue(ctx, t.Expr, mysql.TypeTimestamp, mysql.MinFsp) c.Assert(err, IsNil) switch v.Kind() { case types.KindMysqlTime: c.Assert(v.GetMysqlTime().String(), DeepEquals, t.Ret, comment) default: c.Assert(v.GetValue(), DeepEquals, t.Ret, comment) } } errTbl := []struct { Expr interface{} }{ {"2012-13-12 00:00:00"}, {ast.NewValueExpr("2012-13-12 00:00:00")}, {ast.NewValueExpr(int64(1))}, {&ast.FuncCallExpr{FnName: model.NewCIStr("xxx")}}, {&ast.UnaryOperationExpr{Op: opcode.Minus, V: ast.NewValueExpr(int64(1))}}, } for _, t := range errTbl { _, err := GetTimeValue(ctx, t.Expr, mysql.TypeTimestamp, mysql.MinFsp) c.Assert(err, NotNil) } }
// TODO: add more tests. func (s *testEvalSuite) TestEval(c *C) { colID := int64(1) row := make(map[int64]types.Datum) row[colID] = types.NewIntDatum(100) xevaluator := &Evaluator{Row: row} cases := []struct { expr *tipb.Expr result types.Datum }{ // Datums. { datumExpr(types.NewFloat32Datum(1.1)), types.NewFloat32Datum(1.1), }, { datumExpr(types.NewFloat64Datum(1.1)), types.NewFloat64Datum(1.1), }, { datumExpr(types.NewIntDatum(1)), types.NewIntDatum(1), }, { datumExpr(types.NewUintDatum(1)), types.NewUintDatum(1), }, { datumExpr(types.NewBytesDatum([]byte("abc"))), types.NewBytesDatum([]byte("abc")), }, { datumExpr(types.NewStringDatum("abc")), types.NewStringDatum("abc"), }, { datumExpr(types.Datum{}), types.Datum{}, }, { datumExpr(types.NewDurationDatum(mysql.Duration{Duration: time.Hour})), types.NewDurationDatum(mysql.Duration{Duration: time.Hour}), }, { datumExpr(types.NewDecimalDatum(mysql.NewDecFromFloatForTest(1.1))), types.NewDecimalDatum(mysql.NewDecFromFloatForTest(1.1)), }, { columnExpr(1), types.NewIntDatum(100), }, // Comparison operations. { buildExpr(tipb.ExprType_LT, types.NewIntDatum(100), types.NewIntDatum(1)), types.NewIntDatum(0), }, { buildExpr(tipb.ExprType_LT, types.NewIntDatum(1), types.NewIntDatum(100)), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_LT, types.NewIntDatum(100), types.Datum{}), types.Datum{}, }, { buildExpr(tipb.ExprType_LE, types.NewIntDatum(100), types.NewIntDatum(1)), types.NewIntDatum(0), }, { buildExpr(tipb.ExprType_LE, types.NewIntDatum(1), types.NewIntDatum(1)), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_LE, types.NewIntDatum(100), types.Datum{}), types.Datum{}, }, { buildExpr(tipb.ExprType_EQ, types.NewIntDatum(100), types.NewIntDatum(1)), types.NewIntDatum(0), }, { buildExpr(tipb.ExprType_EQ, types.NewIntDatum(100), types.NewIntDatum(100)), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_EQ, types.NewIntDatum(100), types.Datum{}), types.Datum{}, }, { buildExpr(tipb.ExprType_NE, types.NewIntDatum(100), types.NewIntDatum(100)), types.NewIntDatum(0), }, { buildExpr(tipb.ExprType_NE, types.NewIntDatum(100), types.NewIntDatum(1)), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_NE, types.NewIntDatum(100), types.Datum{}), types.Datum{}, }, { buildExpr(tipb.ExprType_GE, types.NewIntDatum(1), types.NewIntDatum(100)), types.NewIntDatum(0), }, { buildExpr(tipb.ExprType_GE, types.NewIntDatum(100), types.NewIntDatum(100)), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_GE, types.NewIntDatum(100), types.Datum{}), types.Datum{}, }, { buildExpr(tipb.ExprType_GT, types.NewIntDatum(100), types.NewIntDatum(100)), types.NewIntDatum(0), }, { buildExpr(tipb.ExprType_GT, types.NewIntDatum(100), types.NewIntDatum(1)), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_GT, types.NewIntDatum(100), types.Datum{}), types.Datum{}, }, { buildExpr(tipb.ExprType_NullEQ, types.NewIntDatum(1), types.Datum{}), types.NewIntDatum(0), }, { buildExpr(tipb.ExprType_NullEQ, types.Datum{}, types.Datum{}), types.NewIntDatum(1), }, // Logic operation. { buildExpr(tipb.ExprType_And, types.NewIntDatum(0), types.NewIntDatum(1)), types.NewIntDatum(0), }, { buildExpr(tipb.ExprType_And, types.NewIntDatum(1), types.NewIntDatum(1)), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_And, types.NewIntDatum(0), types.Datum{}), types.NewIntDatum(0), }, { buildExpr(tipb.ExprType_And, types.NewIntDatum(1), types.Datum{}), types.Datum{}, }, { buildExpr(tipb.ExprType_Or, types.NewIntDatum(0), types.NewIntDatum(0)), types.NewIntDatum(0), }, { buildExpr(tipb.ExprType_Or, types.NewIntDatum(0), types.NewIntDatum(1)), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_Or, types.NewIntDatum(0), types.Datum{}), types.Datum{}, }, { buildExpr(tipb.ExprType_Or, types.NewIntDatum(1), types.Datum{}), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_And, buildExpr(tipb.ExprType_EQ, types.NewIntDatum(1), types.NewIntDatum(1)), buildExpr(tipb.ExprType_EQ, types.NewIntDatum(1), types.NewIntDatum(1))), types.NewIntDatum(1), }, { notExpr(datumExpr(types.NewIntDatum(1))), types.NewIntDatum(0), }, { notExpr(datumExpr(types.NewIntDatum(0))), types.NewIntDatum(1), }, { notExpr(datumExpr(types.Datum{})), types.Datum{}, }, // Arithmetic operation. { buildExpr(tipb.ExprType_Plus, types.NewIntDatum(-1), types.NewIntDatum(1)), types.NewIntDatum(0), }, { buildExpr(tipb.ExprType_Plus, types.NewIntDatum(-1), types.NewFloat64Datum(1.5)), types.NewFloat64Datum(0.5), }, { buildExpr(tipb.ExprType_Minus, types.NewIntDatum(-1), types.NewIntDatum(1)), types.NewIntDatum(-2), }, { buildExpr(tipb.ExprType_Minus, types.NewIntDatum(-1), types.NewFloat64Datum(1.5)), types.NewFloat64Datum(-2.5), }, { buildExpr(tipb.ExprType_Mul, types.NewFloat64Datum(-1), types.NewFloat64Datum(1)), types.NewFloat64Datum(-1), }, { buildExpr(tipb.ExprType_Mul, types.NewFloat64Datum(-1.5), types.NewFloat64Datum(2)), types.NewFloat64Datum(-3), }, { buildExpr(tipb.ExprType_Div, types.NewFloat64Datum(-3), types.NewFloat64Datum(2)), types.NewFloat64Datum(-1.5), }, { buildExpr(tipb.ExprType_Div, types.NewFloat64Datum(-3), types.NewFloat64Datum(0)), types.NewDatum(nil), }, { buildExpr(tipb.ExprType_IntDiv, types.NewIntDatum(3), types.NewIntDatum(2)), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_IntDiv, types.NewFloat64Datum(3.0), types.NewFloat64Datum(1.9)), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_Mod, types.NewIntDatum(3), types.NewIntDatum(2)), types.NewIntDatum(1), }, { buildExpr(tipb.ExprType_Mod, types.NewFloat64Datum(3.0), types.NewFloat64Datum(1.9)), types.NewFloat64Datum(1.1), }, } for _, ca := range cases { result, err := xevaluator.Eval(ca.expr) c.Assert(err, IsNil) c.Assert(result.Kind(), Equals, ca.result.Kind()) cmp, err := result.CompareDatum(ca.result) c.Assert(err, IsNil) c.Assert(cmp, Equals, 0) } }
func (r *rangeBuilder) buildFromPatternLike(x *ast.PatternLikeExpr) []rangePoint { if x.Not { // Pattern not like is not supported. r.err = ErrUnsupportedType.Gen("NOT LIKE is not supported.") return fullRange } pattern, err := types.ToString(x.Pattern.GetValue()) if err != nil { r.err = errors.Trace(err) return fullRange } if pattern == "" { startPoint := rangePoint{value: types.NewStringDatum(""), start: true} endPoint := rangePoint{value: types.NewStringDatum("")} return []rangePoint{startPoint, endPoint} } lowValue := make([]byte, 0, len(pattern)) // escape the pattern var exclude bool for i := 0; i < len(pattern); i++ { if pattern[i] == x.Escape { i++ if i < len(pattern) { lowValue = append(lowValue, pattern[i]) } else { lowValue = append(lowValue, x.Escape) } continue } if pattern[i] == '%' { break } else if pattern[i] == '_' { exclude = true break } lowValue = append(lowValue, pattern[i]) } if len(lowValue) == 0 { return []rangePoint{{value: types.MinNotNullDatum(), start: true}, {value: types.MaxValueDatum()}} } startPoint := rangePoint{start: true, excl: exclude} startPoint.value.SetBytesAsString(lowValue) highValue := make([]byte, len(lowValue)) copy(highValue, lowValue) endPoint := rangePoint{excl: true} for i := len(highValue) - 1; i >= 0; i-- { highValue[i]++ if highValue[i] != 0 { endPoint.value.SetBytesAsString(highValue) break } if i == 0 { endPoint.value = types.MaxValueDatum() break } } ranges := make([]rangePoint, 2) ranges[0] = startPoint ranges[1] = endPoint return ranges }
func (s *testBinlogSuite) TestBinlog(c *C) { tk := s.tk pump := s.pump tk.MustExec("drop table if exists local_binlog") ddlQuery := "create table local_binlog (id int primary key, name varchar(10))" tk.MustExec(ddlQuery) var matched bool // got matched pre DDL and commit DDL for i := 0; i < 10; i++ { preDDL, commitDDL := getLatestDDLBinlog(c, pump, ddlQuery) if preDDL.DdlJobId == commitDDL.DdlJobId { c.Assert(commitDDL.StartTs, Equals, preDDL.StartTs) c.Assert(commitDDL.CommitTs, Greater, commitDDL.StartTs) matched = true break } time.Sleep(time.Millisecond * 10) } c.Assert(matched, IsTrue) tk.MustExec("insert local_binlog values (1, 'abc'), (2, 'cde')") prewriteVal := getLatestBinlogPrewriteValue(c, pump) c.Assert(prewriteVal.SchemaVersion, Greater, int64(0)) c.Assert(prewriteVal.Mutations[0].TableId, Greater, int64(0)) expected := [][]types.Datum{ {types.NewIntDatum(1), types.NewStringDatum("abc")}, {types.NewIntDatum(2), types.NewStringDatum("cde")}, } gotRows := mutationRowsToRows(c, prewriteVal.Mutations[0].InsertedRows, 0, 2) c.Assert(gotRows, DeepEquals, expected) tk.MustExec("update local_binlog set name = 'xyz' where id = 2") prewriteVal = getLatestBinlogPrewriteValue(c, pump) expected = [][]types.Datum{ {types.NewIntDatum(2), types.NewStringDatum("xyz")}, } gotRows = mutationRowsToRows(c, prewriteVal.Mutations[0].UpdatedRows, 2, 4) c.Assert(gotRows, DeepEquals, expected) tk.MustExec("delete from local_binlog where id = 1") prewriteVal = getLatestBinlogPrewriteValue(c, pump) c.Assert(prewriteVal.Mutations[0].DeletedIds, DeepEquals, []int64{1}) // Test table primary key is not integer. tk.MustExec("create table local_binlog2 (name varchar(64) primary key, age int)") tk.MustExec("insert local_binlog2 values ('abc', 16), ('def', 18)") tk.MustExec("delete from local_binlog2 where name = 'def'") prewriteVal = getLatestBinlogPrewriteValue(c, pump) c.Assert(prewriteVal.Mutations[0].Sequence[0], Equals, binlog.MutationType_DeletePK) _, deletedPK, _ := codec.DecodeOne(prewriteVal.Mutations[0].DeletedPks[0]) c.Assert(deletedPK.GetString(), Equals, "def") // Test Table don't have primary key. tk.MustExec("create table local_binlog3 (c1 int, c2 int)") tk.MustExec("insert local_binlog3 values (1, 2), (1, 3), (2, 3)") tk.MustExec("update local_binlog3 set c1 = 3 where c1 = 2") prewriteVal = getLatestBinlogPrewriteValue(c, pump) gotRows = mutationRowsToRows(c, prewriteVal.Mutations[0].UpdatedRows, 5, 7) expected = [][]types.Datum{ {types.NewIntDatum(3), types.NewIntDatum(3)}, } c.Assert(gotRows, DeepEquals, expected) tk.MustExec("delete from local_binlog3 where c1 = 3 and c2 = 3") prewriteVal = getLatestBinlogPrewriteValue(c, pump) c.Assert(prewriteVal.Mutations[0].Sequence[0], Equals, binlog.MutationType_DeleteRow) gotRows = mutationRowsToRows(c, prewriteVal.Mutations[0].DeletedRows, 1, 3) expected = [][]types.Datum{ {types.NewIntDatum(3), types.NewIntDatum(3)}, } c.Assert(gotRows, DeepEquals, expected) // Test Mutation Sequence. tk.MustExec("create table local_binlog4 (c1 int primary key, c2 int)") tk.MustExec("insert local_binlog4 values (1, 1), (2, 2), (3, 2)") tk.MustExec("begin") tk.MustExec("delete from local_binlog4 where c1 = 1") tk.MustExec("insert local_binlog4 values (1, 1)") tk.MustExec("update local_binlog4 set c2 = 3 where c1 = 3") tk.MustExec("commit") prewriteVal = getLatestBinlogPrewriteValue(c, pump) c.Assert(prewriteVal.Mutations[0].Sequence, DeepEquals, []binlog.MutationType{ binlog.MutationType_DeleteID, binlog.MutationType_Insert, binlog.MutationType_Update, }) checkBinlogCount(c, pump) pump.mu.Lock() originBinlogLen := len(pump.mu.payloads) pump.mu.Unlock() tk.MustExec("set @@global.autocommit = 0") tk.MustExec("set @@global.autocommit = 1") pump.mu.Lock() newBinlogLen := len(pump.mu.payloads) pump.mu.Unlock() c.Assert(newBinlogLen, Equals, originBinlogLen) }