示例#1
0
文件: range.go 项目: astaxie/tidb
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
}
示例#2
0
文件: math.go 项目: js-for-kids/tidb
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)
	}
}
示例#3
0
文件: range.go 项目: 52Jolynn/tidb
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
}
示例#4
0
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
}
示例#5
0
文件: math.go 项目: js-for-kids/tidb
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
}
示例#6
0
文件: time.go 项目: lovedboy/tidb
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
}
示例#7
0
文件: from.go 项目: lovedboy/tidb
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
}
示例#8
0
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
}
示例#9
0
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)
}
示例#10
0
文件: evaluator.go 项目: mrtoms/tidb
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)
}
示例#11
0
文件: binop.go 项目: nengwang/tidb
// 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)
	}
}
示例#12
0
// 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
}
示例#13
0
// 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
}
示例#14
0
文件: evaluator.go 项目: mrtoms/tidb
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
}
示例#15
0
文件: evaluator.go 项目: mrtoms/tidb
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
}
示例#16
0
// 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
}
示例#17
0
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))
}
示例#18
0
文件: evaluator.go 项目: mrtoms/tidb
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
}
示例#19
0
文件: tables.go 项目: lovedboy/tidb
// 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
}
示例#20
0
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)
}
示例#21
0
文件: unary.go 项目: npk/tidb
// 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")
	}
}
示例#22
0
文件: tables.go 项目: zlxy/tidb
// 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
}