func (r *rangeBuilder) buildTableRanges(rangePoints []rangePoint) []TableRange { tableRanges := make([]TableRange, 0, len(rangePoints)/2) for i := 0; i < len(rangePoints); i += 2 { startPoint := rangePoints[i] if startPoint.value.Kind() == types.KindNull || startPoint.value.Kind() == types.KindMinNotNull { startPoint.value.SetInt64(math.MinInt64) } startInt, err := types.ToInt64(startPoint.value.GetValue()) if err != nil { r.err = errors.Trace(err) return tableRanges } startDatum := types.NewDatum(startInt) cmp, err := startDatum.CompareDatum(startPoint.value) if err != nil { r.err = errors.Trace(err) return tableRanges } if cmp < 0 || (cmp == 0 && startPoint.excl) { startInt++ } endPoint := rangePoints[i+1] if endPoint.value.Kind() == types.KindNull { endPoint.value.SetInt64(math.MinInt64) } else if endPoint.value.Kind() == types.KindMaxValue { endPoint.value.SetInt64(math.MaxInt64) } endInt, err := types.ToInt64(endPoint.value.GetValue()) if err != nil { r.err = errors.Trace(err) return tableRanges } endDatum := types.NewDatum(endInt) cmp, err = endDatum.CompareDatum(endPoint.value) if err != nil { r.err = errors.Trace(err) return tableRanges } if cmp > 0 || (cmp == 0 && endPoint.excl) { endInt-- } if startInt > endInt { continue } tableRanges = append(tableRanges, TableRange{LowVal: startInt, HighVal: endInt}) } return tableRanges }
func builtinAbs(args []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { switch x := args[0].(type) { case nil: return nil, nil case uint, uint8, uint16, uint32, uint64: return x, nil case int, int8, int16, int32, int64: // we don't need to handle error here, it must be success v, _ := types.ToInt64(args[0]) if v >= 0 { return x, nil } // TODO: handle overflow if x is MinInt64 return -v, nil case *types.DataItem: args[0] = x.Data return builtinAbs(args, ctx) default: // we will try to convert other types to float // TODO: if time has no precision, it will be a integer f, err := types.ToFloat64(args[0]) return math.Abs(f), errors.Trace(err) } }
func (r *rangeBuilder) buildTableRanges(rangePoints []rangePoint) []TableRange { tableRanges := make([]TableRange, 0, len(rangePoints)/2) for i := 0; i < len(rangePoints); i += 2 { startPoint := rangePoints[i] if startPoint.value == nil || startPoint.value == MinNotNullVal { startPoint.value = math.MinInt64 } startInt, err := types.ToInt64(startPoint.value) if err != nil { r.err = errors.Trace(err) return tableRanges } cmp, err := types.Compare(startInt, startPoint.value) if err != nil { r.err = errors.Trace(err) return tableRanges } if cmp < 0 || (cmp == 0 && startPoint.excl) { startInt++ } endPoint := rangePoints[i+1] if endPoint.value == nil { endPoint.value = math.MinInt64 } else if endPoint.value == MaxVal { endPoint.value = math.MaxInt64 } endInt, err := types.ToInt64(endPoint.value) if err != nil { r.err = errors.Trace(err) return tableRanges } cmp, err = types.Compare(endInt, endPoint.value) if err != nil { r.err = errors.Trace(err) return tableRanges } if cmp > 0 || (cmp == 0 && endPoint.excl) { endInt-- } if startInt > endInt { continue } tableRanges = append(tableRanges, TableRange{LowVal: startInt, HighVal: endInt}) } return tableRanges }
func (v *typeInferrer) getFsp(x *ast.FuncCallExpr) int { if len(x.Args) == 1 { a := x.Args[0].GetValue() fsp, err := types.ToInt64(a) if err != nil { v.err = err } return int(fsp) } return 0 }
func builtinRand(args []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { if len(args) == 1 { seed, err := types.ToInt64(args[0]) if err != nil { return nil, errors.Trace(err) } rand.Seed(seed) } return rand.Float64(), nil }
func checkFsp(arg interface{}) (int, error) { fsp, err := types.ToInt64(arg) if err != nil { return 0, errors.Trace(err) } if int(fsp) > mysql.MaxFsp { return 0, errors.Errorf("Too big precision %d specified. Maximum is 6.", fsp) } else if fsp < 0 { return 0, errors.Errorf("Invalid negative %d specified, must in [0, 6].", fsp) } return int(fsp), nil }
func (r *TableDefaultPlan) toSeekKey(seekVal interface{}) (kv.Key, error) { var handle int64 var err error if seekVal == nil { handle = math.MinInt64 } else { handle, err = types.ToInt64(seekVal) if err != nil { return nil, errors.Trace(err) } } return tables.EncodeRecordKey(r.T.TableID(), handle, 0), nil }
func (e *Evaluator) handleBitOp(o *ast.BinaryOperationExpr) bool { a, b := types.Coerce(o.L.GetValue(), o.R.GetValue()) if types.IsNil(a) || types.IsNil(b) { o.SetValue(nil) return true } x, err := types.ToInt64(a) if err != nil { e.err = errors.Trace(err) return false } y, err := types.ToInt64(b) if err != nil { e.err = errors.Trace(err) return false } // use a int64 for bit operator, return uint64 switch o.Op { case opcode.And: o.SetValue(uint64(x & y)) case opcode.Or: o.SetValue(uint64(x | y)) case opcode.Xor: o.SetValue(uint64(x ^ y)) case opcode.RightShift: o.SetValue(uint64(x) >> uint64(y)) case opcode.LeftShift: o.SetValue(uint64(x) << uint64(y)) default: e.err = ErrInvalidOperation.Gen("invalid op %v in bit operation", o.Op) return false } return true }
func (da *DateArith) evalDaysForm(val interface{}) (interface{}, error) { switch val.(type) { case string: if strings.ToLower(val.(string)) == "false" { return 0, nil } if strings.ToLower(val.(string)) == "true" { return 1, nil } val = reg.FindString(val.(string)) } return types.ToInt64(val) }
func parseDayInterval(value interface{}) (int64, error) { switch v := value.(type) { case string: s := strings.ToLower(v) if s == "false" { return 0, nil } else if s == "true" { return 1, nil } value = reg.FindString(v) } return types.ToInt64(value) }
// Operator: &, ~, |, ^, <<, >> // See https://dev.mysql.com/doc/refman/5.7/en/bit-functions.html func (o *BinaryOperation) evalBitOp(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 { return nil, nil } x, err := types.ToInt64(a) if err != nil { return nil, o.traceErr(err) } y, err := types.ToInt64(b) if err != nil { return nil, o.traceErr(err) } // use a int64 for bit operator, return uint64 switch o.Op { case opcode.And: return uint64(x & y), nil case opcode.Or: return uint64(x | y), nil case opcode.Xor: return uint64(x ^ y), nil case opcode.RightShift: return uint64(x) >> uint64(y), nil case opcode.LeftShift: return uint64(x) << uint64(y), nil default: return nil, o.errorf("invalid op %v in bit operation", o.Op) } }
// Eval implements the Expression Eval interface. func (f *FunctionSubstringIndex) Eval(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) { fs, err := f.StrExpr.Eval(ctx, args) if err != nil { return nil, errors.Trace(err) } str, ok := fs.(string) if !ok { return nil, errors.Errorf("Substring_Index invalid args, need string but get %T", fs) } t, err := f.Delim.Eval(ctx, args) if err != nil { return nil, errors.Trace(err) } delim, ok := t.(string) if !ok { return nil, errors.Errorf("Substring_Index invalid delim, need string but get %T", t) } t, err = f.Count.Eval(ctx, args) if err != nil { return nil, errors.Trace(err) } c, err := types.ToInt64(t) if err != nil { return nil, errors.Trace(err) } count := int(c) strs := strings.Split(str, delim) var ( start = 0 end = len(strs) ) if count > 0 { // If count is positive, everything to the left of the final delimiter (counting from the left) is returned. if count < end { end = count } } else { // If count is negative, everything to the right of the final delimiter (counting from the right) is returned. count = -count if count < end { start = end - count } } substrs := strs[start:end] return strings.Join(substrs, delim), nil }
// Eval implements the Expression Eval interface. func (f *FunctionLocate) Eval(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) { // eval str fs, err := f.Str.Eval(ctx, args) if err != nil { return nil, errors.Trace(err) } if fs == nil { return nil, nil } str, err := types.ToString(fs) if err != nil { return nil, errors.Trace(err) } // eval substr fs, err = f.SubStr.Eval(ctx, args) if err != nil { return nil, errors.Trace(err) } if fs == nil { return nil, nil } substr, err := types.ToString(fs) if err != nil { return nil, errors.Trace(err) } // eval pos pos := 0 if f.Pos != nil { t, err := f.Pos.Eval(ctx, args) if err != nil { return nil, errors.Trace(err) } p, err := types.ToInt64(t) if err != nil { return nil, errors.Trace(err) } pos = int(p) } // eval locate if pos < 0 || pos > len(str) { return 0, errors.Errorf("Locate invalid pos args: %d", pos) } str = str[pos:] i := strings.Index(str, substr) return i + 1 + pos, nil }
func (e *Evaluator) funcLocate(v *ast.FuncLocateExpr) bool { // eval str fs := v.Str.GetValue() if types.IsNil(fs) { v.SetValue(nil) return true } str, err := types.ToString(fs) if err != nil { e.err = errors.Trace(err) return false } // eval substr fs = v.SubStr.GetValue() if types.IsNil(fs) { v.SetValue(nil) return true } substr, err := types.ToString(fs) if err != nil { e.err = errors.Trace(err) return false } // eval pos pos := 0 if v.Pos != nil { t := v.Pos.GetValue() p, err := types.ToInt64(t) if err != nil { e.err = errors.Trace(err) return false } pos = int(p) } // eval locate if pos < 0 || pos > len(str) { e.err = ErrInvalidOperation.Gen("Locate invalid pos args: %d", pos) return false } str = str[pos:] i := strings.Index(str, substr) v.SetValue(i + 1 + pos) return true }
func (e *Evaluator) funcSubstringIndex(v *ast.FuncSubstringIndexExpr) bool { fs := v.StrExpr.GetValue() str, err := types.ToString(fs) if err != nil { e.err = ErrInvalidOperation.Gen("Substring_Index invalid args, need string but get %T", fs) return false } t := v.Delim.GetValue() delim, err := types.ToString(t) if err != nil { e.err = ErrInvalidOperation.Gen("Substring_Index invalid delim, need string but get %T", t) return false } t = v.Count.GetValue() c, err := types.ToInt64(t) if err != nil { e.err = errors.Trace(err) return false } count := int(c) strs := strings.Split(str, delim) var ( start = 0 end = len(strs) ) if count > 0 { // If count is positive, everything to the left of the final delimiter (counting from the left) is returned. if count < end { end = count } } else { // If count is negative, everything to the right of the final delimiter (counting from the right) is returned. count = -count if count < end { start = end - count } } substrs := strs[start:end] v.SetValue(strings.Join(substrs, delim)) return true }
// AddRecord implements table.Table AddRecord interface. func (t *MemoryTable) AddRecord(ctx context.Context, r []types.Datum) (recordID int64, err error) { if t.pkHandleCol != nil { recordID, err = types.ToInt64(r[t.pkHandleCol.Offset].GetValue()) if err != nil { return 0, errors.Trace(err) } } else { recordID, err = t.alloc.Alloc(t.ID) if err != nil { return 0, errors.Trace(err) } } item := &itemPair{ handle: itemKey(recordID), data: r, } t.mu.Lock() defer t.mu.Unlock() if t.tree.Get(itemKey(recordID)) != nil { return 0, kv.ErrKeyExists } t.tree.ReplaceOrInsert(item) return }
func builtinNow(args []interface{}, ctx map[interface{}]interface{}) (interface{}, error) { fsp := int64(0) if len(args) == 1 { var err error fsp, err = types.ToInt64(args[0]) if err != nil { return nil, errors.Trace(err) } if int(fsp) > mysql.MaxFsp { return nil, errors.Errorf("Too big precision %d specified. Maximum is 6.", fsp) } else if fsp < 0 { return nil, errors.Errorf("Invalid negative %d specified, must in [0, 6].", fsp) } } t := mysql.Time{ Time: time.Now(), Type: mysql.TypeDatetime, // set unspecified for later round Fsp: mysql.UnspecifiedFsp, } return t.RoundFrac(int(fsp)) }
func (e *Evaluator) unaryOperation(u *ast.UnaryOperationExpr) bool { defer func() { if er := recover(); er != nil { e.err = errors.Errorf("%v", er) } }() a := u.V.GetValue() a = types.RawData(a) if a == nil { u.SetValue(nil) return true } switch op := u.Op; op { case opcode.Not: n, err := types.ToBool(a) if err != nil { e.err = errors.Trace(err) } else if n == 0 { u.SetValue(int64(1)) } else { u.SetValue(int64(0)) } case opcode.BitNeg: // for bit operation, we will use int64 first, then return uint64 n, err := types.ToInt64(a) if err != nil { e.err = errors.Trace(err) return false } u.SetValue(uint64(^n)) case opcode.Plus: switch x := a.(type) { case bool: u.SetValue(boolToInt64(x)) case float32: u.SetValue(+x) case float64: u.SetValue(+x) case int: u.SetValue(+x) case int8: u.SetValue(+x) case int16: u.SetValue(+x) case int32: u.SetValue(+x) case int64: u.SetValue(+x) case uint: u.SetValue(+x) case uint8: u.SetValue(+x) case uint16: u.SetValue(+x) case uint32: u.SetValue(+x) case uint64: u.SetValue(+x) case mysql.Duration: u.SetValue(x) case mysql.Time: u.SetValue(x) case string: u.SetValue(x) case mysql.Decimal: u.SetValue(x) case []byte: u.SetValue(x) case mysql.Hex: u.SetValue(x) case mysql.Bit: u.SetValue(x) case mysql.Enum: u.SetValue(x) case mysql.Set: u.SetValue(x) default: e.err = ErrInvalidOperation return false } case opcode.Minus: switch x := a.(type) { case bool: if x { u.SetValue(int64(-1)) } else { u.SetValue(int64(0)) } case float32: u.SetValue(-x) case float64: u.SetValue(-x) case int: u.SetValue(-x) case int8: u.SetValue(-x) case int16: u.SetValue(-x) case int32: u.SetValue(-x) case int64: u.SetValue(-x) case uint: u.SetValue(-int64(x)) case uint8: u.SetValue(-int64(x)) case uint16: u.SetValue(-int64(x)) case uint32: u.SetValue(-int64(x)) case uint64: // TODO: check overflow and do more test for unsigned type u.SetValue(-int64(x)) case mysql.Duration: u.SetValue(mysql.ZeroDecimal.Sub(x.ToNumber())) case mysql.Time: u.SetValue(mysql.ZeroDecimal.Sub(x.ToNumber())) case string: f, err := types.StrToFloat(x) e.err = errors.Trace(err) u.SetValue(-f) case mysql.Decimal: f, _ := x.Float64() u.SetValue(mysql.NewDecimalFromFloat(-f)) case []byte: f, err := types.StrToFloat(string(x)) e.err = errors.Trace(err) u.SetValue(-f) case mysql.Hex: u.SetValue(-x.ToNumber()) case mysql.Bit: u.SetValue(-x.ToNumber()) case mysql.Enum: u.SetValue(-x.ToNumber()) case mysql.Set: u.SetValue(-x.ToNumber()) default: e.err = ErrInvalidOperation return false } default: e.err = ErrInvalidOperation return false } return true }
// AddRecord implements table.Table AddRecord interface. func (t *Table) AddRecord(ctx context.Context, r []interface{}) (recordID int64, err error) { var hasRecordID bool for _, col := range t.Cols() { if col.IsPKHandleColumn(t.meta) { recordID, err = types.ToInt64(r[col.Offset]) if err != nil { return 0, errors.Trace(err) } hasRecordID = true break } } if !hasRecordID { recordID, err = t.alloc.Alloc(t.ID) if err != nil { return 0, errors.Trace(err) } } txn, err := ctx.GetTxn(false) if err != nil { return 0, errors.Trace(err) } bs := kv.NewBufferStore(txn) defer bs.Release() // Insert new entries into indices. h, err := t.addIndices(ctx, recordID, r, bs) if err != nil { return h, errors.Trace(err) } if err = t.LockRow(ctx, recordID); err != nil { return 0, errors.Trace(err) } // Set public and write only column value. for _, col := range t.writableCols() { if col.IsPKHandleColumn(t.meta) { continue } var value interface{} if col.State == model.StateWriteOnly || col.State == model.StateWriteReorganization { // if col is in write only or write reorganization state, we must add it with its default value. value, _, err = GetColDefaultValue(ctx, &col.ColumnInfo) if err != nil { return 0, errors.Trace(err) } value, err = types.Convert(value, &col.FieldType) if err != nil { return 0, errors.Trace(err) } } else { value = r[col.Offset] } key := t.RecordKey(recordID, col) err = t.SetColValue(txn, key, value) if err != nil { return 0, errors.Trace(err) } } if err = bs.SaveTo(txn); err != nil { return 0, errors.Trace(err) } variable.GetSessionVars(ctx).AddAffectedRows(1) return recordID, nil }
func (s *testDBSuite) testAddColumn(c *C) { done := make(chan struct{}, 1) num := 100 // add some rows for i := 0; i < num; i++ { s.mustExec(c, "insert into t2 values (?, ?, ?)", i, i, i) } go func() { s.mustExec(c, "alter table t2 add column c4 int default -1") done <- struct{}{} }() ticker := time.NewTicker(s.lease / 2) defer ticker.Stop() step := 10 LOOP: for { select { case <-done: break LOOP case <-ticker.C: // delete some rows, and add some data for i := num; i < num+step; i++ { n := rand.Intn(num) s.mustExec(c, "delete from t2 where c1 = ?", n) _, err := s.db.Exec("insert into t2 values (?, ?, ?)", i, i, i) if err != nil { // if err is failed, the column number must be 4 now. values := s.showColumns(c, "t2") c.Assert(values, HasLen, 4) } } num += step } } // add data, here c4 must exist for i := num; i < num+step; i++ { s.mustExec(c, "insert into t2 values (?, ?, ?, ?)", i, i, i, i) } rows := s.mustQuery(c, "select count(c4) from t2") values := dumpRows(c, rows) c.Assert(values, HasLen, 1) c.Assert(values[0], HasLen, 1) count, ok := values[0][0].(int64) c.Assert(ok, IsTrue) c.Assert(count, Greater, int64(0)) rows = s.mustQuery(c, "select count(c4) from t2 where c4 = -1") matchRows(c, rows, [][]interface{}{{count - int64(step)}}) for i := num; i < num+step; i++ { rows := s.mustQuery(c, "select c4 from t2 where c4 = ?", i) matchRows(c, rows, [][]interface{}{{i}}) } ctx := s.s.(context.Context) t := s.testGetTable(c, "t2") i := 0 j := 0 err := t.IterRecords(ctx, t.FirstKey(), t.Cols(), func(h int64, data []interface{}, cols []*column.Col) (bool, error) { i++ // c4 must be -1 or > 0 v, err := types.ToInt64(data[3]) c.Assert(err, IsNil) if v == -1 { j++ } else { c.Assert(v, Greater, int64(0)) } return true, nil }) c.Assert(err, IsNil) c.Assert(i, Equals, int(count)) c.Assert(i, LessEqual, num+step) c.Assert(j, Equals, int(count)-step) }
// Eval implements the Expression Eval interface. func (u *UnaryOperation) Eval(ctx context.Context, args map[interface{}]interface{}) (r interface{}, err error) { defer func() { if e := recover(); e != nil { r, err = nil, errors.Errorf("%v", e) } }() switch op := u.Op; op { case opcode.Not: a := Eval(u.V, ctx, args) if a == nil { return } n, err := types.ToBool(a) if err != nil { return types.UndOp(a, op) } else if n == 0 { return int8(1), nil } return int8(0), nil case opcode.BitNeg: a := Eval(u.V, ctx, args) if a == nil { return } // for bit operation, we will use int64 first, then return uint64 n, err := types.ToInt64(a) if err != nil { return types.UndOp(a, op) } return uint64(^n), nil case opcode.Plus: a := Eval(u.V, ctx, args) switch x := a.(type) { case nil: return nil, nil case float32: return +x, nil case float64: return +x, nil case int: return +x, nil case int8: return +x, nil case int16: return +x, nil case int32: return +x, nil case int64: return +x, nil case uint: return +x, nil case uint8: return +x, nil case uint16: return +x, nil case uint32: return +x, nil case uint64: return +x, nil case mysql.Duration: return x, nil case mysql.Time: return x, nil case string: return x, nil case mysql.Decimal: return x, nil default: return types.UndOp(a, op) } case opcode.Minus: a := Eval(u.V, ctx, args) switch x := a.(type) { case nil: return nil, nil case float32: return -x, nil case float64: return -x, nil case int: return -x, nil case int8: return -x, nil case int16: return -x, nil case int32: return -x, nil case int64: return -x, nil case uint: return -int64(x), nil case uint8: return -int64(x), nil case uint16: return -int64(x), nil case uint32: return -int64(x), nil case uint64: // TODO: check overflow and do more test for unsigned type return -int64(x), nil case mysql.Duration: return mysql.ZeroDecimal.Sub(x.ToNumber()), nil case mysql.Time: return mysql.ZeroDecimal.Sub(x.ToNumber()), nil case string: f, err := types.StrToFloat(x) return -f, err case mysql.Decimal: f, _ := x.Float64() return mysql.NewDecimalFromFloat(-f), nil default: return types.UndOp(a, op) } default: panic("should never happen") } }
// AddRecord implements table.Table AddRecord interface. func (t *Table) AddRecord(ctx context.Context, r []interface{}) (recordID int64, err error) { var hasRecordID bool for _, col := range t.Cols() { if col.IsPKHandleColumn(t.meta) { recordID, err = types.ToInt64(r[col.Offset]) if err != nil { return 0, errors.Trace(err) } hasRecordID = true break } } if !hasRecordID { recordID, err = t.alloc.Alloc(t.ID) if err != nil { return 0, errors.Trace(err) } } txn, err := ctx.GetTxn(false) if err != nil { return 0, errors.Trace(err) } bs := kv.NewBufferStore(txn) defer bs.Release() if t.meta.PKIsHandle { // Check key exists. recordKey := t.RecordKey(recordID, nil) _, err = txn.Get(recordKey) if err == nil { return recordID, kv.ErrKeyExists } else if !terror.ErrorEqual(err, kv.ErrNotExist) { return 0, errors.Trace(err) } } for _, v := range t.indices { if v == nil || v.State == model.StateDeleteOnly || v.State == model.StateDeleteReorganization { // if index is in delete only or delete reorganization state, we can't add it. continue } colVals, _ := v.FetchValues(r) if err = v.X.Create(bs, colVals, recordID); err != nil { if terror.ErrorEqual(err, kv.ErrKeyExists) { // Get the duplicate row handle // For insert on duplicate syntax, we should update the row iter, _, err1 := v.X.Seek(bs, colVals) if err1 != nil { return 0, errors.Trace(err1) } _, h, err1 := iter.Next() if err1 != nil { return 0, errors.Trace(err1) } return h, errors.Trace(err) } return 0, errors.Trace(err) } } if err = t.LockRow(ctx, recordID); err != nil { return 0, errors.Trace(err) } // Set public and write only column value. for _, col := range t.writableCols() { if col.IsPKHandleColumn(t.meta) { continue } var value interface{} if col.State == model.StateWriteOnly || col.State == model.StateWriteReorganization { // if col is in write only or write reorganization state, we must add it with its default value. value, _, err = GetColDefaultValue(ctx, &col.ColumnInfo) if err != nil { return 0, errors.Trace(err) } value, err = types.Convert(value, &col.FieldType) if err != nil { return 0, errors.Trace(err) } } else { value = r[col.Offset] } key := t.RecordKey(recordID, col) err = t.SetColValue(txn, key, value) if err != nil { return 0, errors.Trace(err) } } if err = bs.SaveTo(txn); err != nil { return 0, errors.Trace(err) } variable.GetSessionVars(ctx).AddAffectedRows(1) return recordID, nil }