func (e *Evaluator) handleLogicOperation(o *ast.BinaryOperationExpr) bool { leftVal, err := types.Convert(o.L.GetValue(), o.GetType()) if err != nil { e.err = err return false } rightVal, err := types.Convert(o.R.GetValue(), o.GetType()) if err != nil { e.err = err return false } if leftVal == nil || rightVal == nil { o.SetValue(nil) return true } var boolVal bool switch o.Op { case opcode.AndAnd: boolVal = leftVal != zeroI64 && rightVal != zeroI64 case opcode.OrOr: boolVal = leftVal != zeroI64 || rightVal != zeroI64 case opcode.LogicXor: boolVal = (leftVal == zeroI64 && rightVal != zeroI64) || (leftVal != zeroI64 && rightVal == zeroI64) default: panic("should never happen") } if boolVal { o.SetValue(oneI64) } else { o.SetValue(zeroI64) } return true }
// Eval implements the Expression Eval interface. func (e *Extract) Eval(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) { v, err := e.Date.Eval(ctx, args) if v == nil || err != nil { return nil, errors.Trace(err) } f := types.NewFieldType(mysql.TypeDatetime) f.Decimal = mysql.MaxFsp v, err = types.Convert(v, f) if v == nil || err != nil { return nil, errors.Trace(err) } t, ok := v.(mysql.Time) if !ok { return nil, errors.Errorf("need time type, but got %T", v) } n, err1 := extractTime(e.Unit, t) if err1 != nil { return nil, errors.Trace(err1) } return n, nil }
func (e *Evaluator) funcExtract(v *ast.FuncExtractExpr) bool { val := v.Date.GetValue() if val == nil { v.SetValue(nil) return true } f := types.NewFieldType(mysql.TypeDatetime) f.Decimal = mysql.MaxFsp var err error val, err = types.Convert(val, f) if err != nil { e.err = errors.Trace(err) return false } if val == nil { v.SetValue(nil) return true } t, ok := val.(mysql.Time) if !ok { e.err = ErrInvalidOperation.Gen("need time type, but got %T", val) return false } n, err1 := mysql.ExtractTimeNum(v.Unit, t) if err1 != nil { e.err = errors.Trace(err1) return false } v.SetValue(n) return true }
// Next implements Executor Next interface. func (e *IndexRangeExec) Next() (*Row, error) { if e.iter == nil { seekVals := make([]interface{}, len(e.scan.idx.Columns)) for i := 0; i < len(e.lowVals); i++ { var err error if e.lowVals[i] == plan.MinNotNullVal { seekVals[i] = []byte{} } else { seekVals[i], err = types.Convert(e.lowVals[i], e.scan.valueTypes[i]) if err != nil { return nil, errors.Trace(err) } } } txn, err := e.scan.ctx.GetTxn(false) if err != nil { return nil, errors.Trace(err) } e.iter, _, err = e.scan.idx.X.Seek(txn, seekVals) if err != nil { return nil, types.EOFAsNil(err) } } for { if e.finished { return nil, nil } idxKey, h, err := e.iter.Next() if err != nil { return nil, types.EOFAsNil(err) } if !e.skipLowCmp { var cmp int cmp, err = indexCompare(idxKey, e.lowVals) if err != nil { return nil, errors.Trace(err) } if cmp < 0 || (cmp == 0 && e.lowExclude) { continue } e.skipLowCmp = true } cmp, err := indexCompare(idxKey, e.highVals) if err != nil { return nil, errors.Trace(err) } if cmp > 0 || (cmp == 0 && e.highExclude) { // This span has finished iteration. e.finished = true continue } var row *Row row, err = e.lookupRow(h) if err != nil { return nil, errors.Trace(err) } return row, nil } }
// Next implements Executor Next interface. func (e *UnionExec) Next() (*Row, error) { for { if e.cursor >= len(e.Sels) { return nil, nil } sel := e.Sels[e.cursor] row, err := sel.Next() if err != nil { return nil, errors.Trace(err) } if row == nil { e.cursor++ continue } if e.cursor != 0 { for i := range row.Data { // The column value should be casted as the same type of the first select statement in corresponding position rf := e.fields[i] row.Data[i], err = types.Convert(row.Data[i], &rf.Column.FieldType) if err != nil { return nil, errors.Trace(err) } } } for i, v := range row.Data { e.fields[i].Expr.SetValue(v) } return row, nil } }
// Eval implements the Expression Eval interface. func (c *Conversion) Eval(ctx context.Context, args map[interface{}]interface{}) (v interface{}, err error) { Val, err := c.Val.Eval(ctx, args) if err != nil { return } ft := types.NewFieldType(c.Tp) return types.Convert(Val, ft) }
func (d *ddl) backfillColumnData(t table.Table, columnInfo *model.ColumnInfo, handles []int64, reorgInfo *reorgInfo) error { for _, handle := range handles { log.Info("[ddl] backfill column...", handle) err := kv.RunInNewTxn(d.store, true, func(txn kv.Transaction) error { if err := d.isReorgRunnable(txn); err != nil { return errors.Trace(err) } // First check if row exists. exist, err := checkRowExist(txn, t, handle) if err != nil { return errors.Trace(err) } else if !exist { // If row doesn't exist, skip it. return nil } backfillKey := t.RecordKey(handle, &column.Col{ColumnInfo: *columnInfo}) backfillValue, err := txn.Get(backfillKey) if err != nil && !kv.IsErrNotFound(err) { return errors.Trace(err) } if backfillValue != nil { return nil } value, _, err := tables.GetColDefaultValue(nil, columnInfo) if err != nil { return errors.Trace(err) } // must convert to the column field type. v, err := types.Convert(value, &columnInfo.FieldType) if err != nil { return errors.Trace(err) } err = lockRow(txn, t, handle) if err != nil { return errors.Trace(err) } err = t.SetColValue(txn, backfillKey, v) if err != nil { return errors.Trace(err) } return errors.Trace(reorgInfo.UpdateHandle(txn, handle)) }) if err != nil { return errors.Trace(err) } } return nil }
func (e *Evaluator) binaryOperation(o *ast.BinaryOperationExpr) bool { // all operands must have same column. if e.err = hasSameColumnCount(o.L, o.R); e.err != nil { return false } // row constructor only supports comparison operation. switch o.Op { case opcode.LT, opcode.LE, opcode.GE, opcode.GT, opcode.EQ, opcode.NE, opcode.NullEQ: default: if !checkAllOneColumn(o.L) { e.err = errors.Errorf("Operand should contain 1 column(s)") return false } } leftVal, err := types.Convert(o.L.GetValue(), o.GetType()) if err != nil { e.err = err return false } rightVal, err := types.Convert(o.R.GetValue(), o.GetType()) if err != nil { e.err = err return false } if leftVal == nil || rightVal == nil { o.SetValue(nil) return true } switch o.Op { case opcode.AndAnd, opcode.OrOr, opcode.LogicXor: return e.handleLogicOperation(o) case opcode.LT, opcode.LE, opcode.GE, opcode.GT, opcode.EQ, opcode.NE, opcode.NullEQ: return e.handleComparisonOp(o) case opcode.RightShift, opcode.LeftShift, opcode.And, opcode.Or, opcode.Xor: // TODO: MySQL doesn't support and not, we should remove it later. return e.handleBitOp(o) case opcode.Plus, opcode.Minus, opcode.Mod, opcode.Div, opcode.Mul, opcode.IntDiv: return e.handleArithmeticOp(o) default: panic("should never happen") } }
// castValues casts values based on columns type. func castValues(rec []interface{}, cols []*model.ColumnInfo) (err error) { for _, c := range cols { rec[c.Offset], err = types.Convert(rec[c.Offset], &c.FieldType) if err != nil { return errors.Trace(err) } } return nil }
func (r *TableDefaultPlan) filterBinOp(ctx context.Context, x *expression.BinaryOperation) (plan.Plan, bool, error) { ok, name, rval, err := x.IsIdentCompareVal() if err != nil { return r, false, errors.Trace(err) } if !ok { return r, false, nil } if rval == nil { // if nil, any <, <=, >, >=, =, != operator will do nothing // any value compared null returns null // TODO: if we support <=> later, we must handle null return &NullPlan{r.GetFields()}, true, nil } _, tn, cn := field.SplitQualifiedName(name) t := r.T if tn != "" && tn != t.TableName().L { return r, false, nil } c := column.FindCol(t.Cols(), cn) if c == nil { return nil, false, errors.Errorf("No such column: %s", cn) } var seekVal interface{} if seekVal, err = types.Convert(rval, &c.FieldType); err != nil { return nil, false, errors.Trace(err) } spans := toSpans(x.Op, rval, seekVal) if c.IsPKHandleColumn(r.T.Meta()) { if r.rangeScan { spans = filterSpans(r.spans, spans) } return &TableDefaultPlan{ T: r.T, Fields: r.Fields, rangeScan: true, spans: spans, }, true, nil } else if r.rangeScan { // Already filtered on PK handle column, should not switch to index plan. return r, false, nil } ix := t.FindIndexByColName(cn) if ix == nil { // Column cn has no index. return r, false, nil } return &indexPlan{ src: t, col: c, unique: ix.Unique, idxName: ix.Name.O, idx: ix.X, spans: spans, }, true, nil }
// CastValues casts values based on columns type. func CastValues(ctx context.Context, rec []interface{}, cols []*Col) (err error) { for _, c := range cols { rec[c.Offset], err = types.Convert(rec[c.Offset], &c.FieldType) if err != nil { return errors.Trace(err) } } return nil }
// Filter implements plan.Plan Filter interface. // Filter merges BinaryOperations and determines the lower and upper bound. func (r *indexPlan) Filter(ctx context.Context, expr expression.Expression) (plan.Plan, bool, error) { var spans []*indexSpan switch x := expr.(type) { case *expression.BinaryOperation: ok, name, val, err := x.IsIdentCompareVal() if err != nil { return nil, false, err } if !ok { break } _, tname, cname := field.SplitQualifiedName(name) if tname != "" && r.src.TableName().L != tname { break } if r.col.ColumnInfo.Name.L != cname { break } seekVal, err := types.Convert(val, &r.col.FieldType) if err != nil { return nil, false, errors.Trace(err) } spans = filterSpans(r.spans, toSpans(x.Op, val, seekVal)) case *expression.Ident: if r.col.Name.L != x.L { break } spans = filterSpans(r.spans, toSpans(opcode.GE, minNotNullVal, nil)) case *expression.UnaryOperation: if x.Op != '!' { break } cname, ok := x.V.(*expression.Ident) if !ok { break } if r.col.Name.L != cname.L { break } spans = filterSpans(r.spans, toSpans(opcode.EQ, nil, nil)) } if spans == nil { return r, false, nil } return &indexPlan{ src: r.src, col: r.col, unique: r.unique, idxName: r.idxName, idx: r.idx, spans: spans, }, true, nil }
func (p *UnionPlan) fetchSrc(ctx context.Context, i int, t memkv.Temp) error { src := p.Srcs[i+1] distinct := p.Distincts[i] // Use the ResultFields of the first select statement as the final ResultFields rfs := p.Srcs[0].GetFields() if len(src.GetFields()) != len(rfs) { return errors.New("The used SELECT statements have a different number of columns") } for { row, err := src.Next(ctx) if row == nil || err != nil { return errors.Trace(err) } srcRfs := src.GetFields() for i := range row.Data { // The column value should be casted as the same type of the first select statement in corresponding position srcRf := srcRfs[i] rf := rfs[i] /* * The lengths of the columns in the UNION result take into account the values retrieved by all of the SELECT statements * SELECT REPEAT('a',1) UNION SELECT REPEAT('b',10); * +---------------+ * | REPEAT('a',1) | * +---------------+ * | a | * | bbbbbbbbbb | * +---------------+ */ if srcRf.Flen > rf.Col.Flen { rf.Col.Flen = srcRf.Col.Flen } row.Data[i], err = types.Convert(row.Data[i], &rf.Col.FieldType) if err != nil { return errors.Trace(err) } } if distinct { // distinct union, check duplicate v, getErr := t.Get(row.Data) if getErr != nil { return errors.Trace(getErr) } if len(v) > 0 { // Find duplicate, ignore it continue } } p.rows = append(p.rows, row) if err := t.Set(row.Data, []interface{}{true}); err != nil { return errors.Trace(err) } } }
// Eval implements the Expression Eval interface. func (da *DateAdd) Eval(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) { dv, err := da.Date.Eval(ctx, args) if dv == nil || err != nil { return nil, errors.Trace(err) } sv, err := types.ToString(dv) if err != nil { return nil, errors.Trace(err) } f := types.NewFieldType(mysql.TypeDatetime) f.Decimal = mysql.MaxFsp dv, err = types.Convert(sv, f) if dv == nil || err != nil { return nil, errors.Trace(err) } t, ok := dv.(mysql.Time) if !ok { return nil, errors.Errorf("need time type, but got %T", dv) } iv, err := da.Interval.Eval(ctx, args) if iv == nil || err != nil { return nil, errors.Trace(err) } format, err := types.ToString(iv) if err != nil { return nil, errors.Trace(err) } years, months, days, durations, err := mysql.ExtractTimeValue(da.Unit, strings.TrimSpace(format)) if err != nil { return nil, errors.Trace(err) } t.Time = t.Time.Add(durations) t.Time = t.Time.AddDate(int(years), int(months), int(days)) // "2011-11-11 10:10:20.000000" outputs "2011-11-11 10:10:20". if t.Time.Nanosecond() == 0 { t.Fsp = 0 } return t, nil }
func (da *DateArith) evalArgs(ctx context.Context, args map[interface{}]interface{}) ( *evalArgsResult, error) { ret := &evalArgsResult{time: mysql.ZeroTimestamp} dVal, err := da.Date.Eval(ctx, args) if dVal == nil || err != nil { return ret, errors.Trace(err) } dValStr, err := types.ToString(dVal) if err != nil { return ret, errors.Trace(err) } f := types.NewFieldType(mysql.TypeDatetime) f.Decimal = mysql.MaxFsp dVal, err = types.Convert(dValStr, f) if dVal == nil || err != nil { return ret, errors.Trace(err) } var ok bool ret.time, ok = dVal.(mysql.Time) if !ok { return ret, errors.Errorf("need time type, but got %T", dVal) } iVal, err := da.Interval.Eval(ctx, args) if iVal == nil || err != nil { ret.time = mysql.ZeroTimestamp return ret, errors.Trace(err) } // handle adddate(expr,days) or subdate(expr,days) form if da.Form == DateArithDaysForm { if iVal, err = da.evalDaysForm(iVal); err != nil { return ret, errors.Trace(err) } } iValStr, err := types.ToString(iVal) if err != nil { return ret, errors.Trace(err) } ret.year, ret.month, ret.day, ret.duration, err = mysql.ExtractTimeValue(da.Unit, strings.TrimSpace(iValStr)) if err != nil { return ret, errors.Trace(err) } return ret, nil }
// Filter implements plan.Plan Filter interface. // Filter merges BinaryOperations, and determines the lower and upper bound. func (r *indexPlan) Filter(ctx context.Context, expr expression.Expression) (plan.Plan, bool, error) { switch x := expr.(type) { case *expression.BinaryOperation: ok, cname, val, err := x.IsIdentRelOpVal() if err != nil { return nil, false, err } if !ok || r.colName != cname { break } col := column.FindCol(r.src.Cols(), cname) if col == nil { break } if val, err = types.Convert(val, &col.FieldType); err != nil { return nil, false, err } r.spans = filterSpans(r.spans, toSpans(x.Op, val)) return r, true, nil case *expression.Ident: if r.colName != x.L { break } r.spans = filterSpans(r.spans, toSpans(opcode.GE, minNotNullVal)) return r, true, nil case *expression.UnaryOperation: if x.Op != '!' { break } operand, ok := x.V.(*expression.Ident) if !ok { break } cname := operand.L if r.colName != cname { break } r.spans = filterSpans(r.spans, toSpans(opcode.EQ, nil)) return r, true, nil } return r, false, nil }
// Eval implements the Expression Eval interface. func (f *FunctionCast) Eval(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) { value, err := f.Expr.Eval(ctx, args) if err != nil { return nil, err } // Casting nil to any type returns null if value == nil { return nil, nil } nv, err := types.Convert(value, f.Tp) if err != nil { return nil, err } return nv, nil }
func (r *TableDefaultPlan) filterBinOp(ctx context.Context, x *expression.BinaryOperation) (plan.Plan, bool, error) { ok, name, rval, err := x.IsIdentCompareVal() if err != nil { return r, false, err } if !ok { return r, false, nil } if rval == nil { // if nil, any <, <=, >, >=, =, != operator will do nothing // any value compared null returns null // TODO: if we support <=> later, we must handle null return &NullPlan{r.GetFields()}, true, nil } _, tn, cn := field.SplitQualifiedName(name) t := r.T if tn != "" && tn != t.TableName().L { return r, false, nil } c := column.FindCol(t.Cols(), cn) if c == nil { return nil, false, errors.Errorf("No such column: %s", cn) } ix := t.FindIndexByColName(cn) if ix == nil { // Column cn has no index. return r, false, nil } var seekVal interface{} if seekVal, err = types.Convert(rval, &c.FieldType); err != nil { return nil, false, err } return &indexPlan{ src: t, col: c, idxName: ix.Name.O, idx: ix.X, spans: toSpans(x.Op, rval, seekVal), }, true, nil }
func convertToDuration(arg interface{}, fsp int) (interface{}, error) { f := types.NewFieldType(mysql.TypeDuration) f.Decimal = fsp v, err := types.Convert(arg, f) if err != nil { return nil, err } if types.IsNil(v) { return nil, nil } t, ok := v.(mysql.Duration) if !ok { return nil, errors.Errorf("need duration type, but got %T", v) } return t, nil }
func convertToTime(arg interface{}, tp byte) (interface{}, error) { f := types.NewFieldType(tp) f.Decimal = mysql.MaxFsp v, err := types.Convert(arg, f) if err != nil { return nil, err } if types.IsNil(v) { return nil, nil } t, ok := v.(mysql.Time) if !ok { return nil, errors.Errorf("need time type, but got %T", v) } return t, nil }
func (s *testColumnSuite) checkColumnKVExist(c *C, ctx context.Context, t table.Table, handle int64, col *column.Col, columnValue interface{}, isExist bool) { txn, err := ctx.GetTxn(true) c.Assert(err, IsNil) key := t.RecordKey(handle, col) data, err := txn.Get(key) if isExist { c.Assert(err, IsNil) v, err1 := t.DecodeValue(data, col) c.Assert(err1, IsNil) value, err1 := types.Convert(v, &col.FieldType) c.Assert(err1, IsNil) c.Assert(value, Equals, columnValue) } else { c.Assert(err, NotNil) } err = ctx.FinishTxn(false) c.Assert(err, IsNil) }
// Eval implements the Expression Eval interface. func (f *FunctionCast) Eval(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) { value, err := f.Expr.Eval(ctx, args) if err != nil { return nil, err } // Casting nil to any type returns null if value == nil { return nil, nil } // TODO: we need a better function convert between any two types according to FieldType. // Not only check Type, but also consider Flen/Decimal/Charset and so on. nv, err := types.Convert(value, f.Tp) if err != nil { return nil, err } 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 } } return nv, nil }
func (da *DateArith) evalArgs(ctx context.Context, args map[interface{}]interface{}) ( mysql.Time, int64, int64, int64, time.Duration, error) { dVal, err := da.Date.Eval(ctx, args) if dVal == nil || err != nil { return mysql.ZeroTimestamp, 0, 0, 0, 0, errors.Trace(err) } dValStr, err := types.ToString(dVal) if err != nil { return mysql.ZeroTimestamp, 0, 0, 0, 0, errors.Trace(err) } f := types.NewFieldType(mysql.TypeDatetime) f.Decimal = mysql.MaxFsp dVal, err = types.Convert(dValStr, f) if dVal == nil || err != nil { return mysql.ZeroTimestamp, 0, 0, 0, 0, errors.Trace(err) } t, ok := dVal.(mysql.Time) if !ok { return mysql.ZeroTimestamp, 0, 0, 0, 0, errors.Errorf("need time type, but got %T", dVal) } iVal, err := da.Interval.Eval(ctx, args) if iVal == nil || err != nil { return mysql.ZeroTimestamp, 0, 0, 0, 0, errors.Trace(err) } iValStr, err := types.ToString(iVal) if err != nil { return mysql.ZeroTimestamp, 0, 0, 0, 0, errors.Trace(err) } years, months, days, durations, err := mysql.ExtractTimeValue(da.Unit, strings.TrimSpace(iValStr)) if err != nil { return mysql.ZeroTimestamp, 0, 0, 0, 0, errors.Trace(err) } return t, years, months, days, durations, nil }
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) } } case Value: switch xval := x.Val.(type) { case string: value, err = mysql.ParseTime(xval, tp, fsp) if err != nil { return nil, errors.Trace(err) } case int64: value, err = mysql.ParseTimeFromNum(int64(xval), tp, fsp) if err != nil { return nil, errors.Trace(err) } case nil: return nil, nil default: return nil, errors.Trace(errDefaultValue) } case *Ident: if x.Equal(CurrentTimeExpr) { return CurrentTimestamp, nil } return nil, errors.Trace(errDefaultValue) case *UnaryOperation: // support some expression, like `-1` m := map[interface{}]interface{}{} v := Eval(x, nil, m) ft := types.NewFieldType(mysql.TypeLonglong) xval, err := types.Convert(v, ft) if err != nil { return nil, errors.Trace(err) } value, err = mysql.ParseTimeFromNum(xval.(int64), tp, fsp) if err != nil { return nil, errors.Trace(err) } default: return nil, nil } return value, nil }
// Do implements plan.Plan Do interface. // In union plan, we should evaluate each selects from left to right, and union them according to distinct option // Use the first select ResultFields as the final ResultFields but we should adjust its Flen for the rest Select ResultFields. func (p *UnionPlan) Do(ctx context.Context, f plan.RowIterFunc) error { if len(p.Srcs) == 0 { return nil } t, err := memkv.CreateTemp(true) if err != nil { return err } defer func() { if derr := t.Drop(); derr != nil && err == nil { err = derr } }() // The final result var rows [][]interface{} // Eval the first select statement src := p.Srcs[0] src.Do(ctx, func(rid interface{}, in []interface{}) (bool, error) { rows = append(rows, in) if err := t.Set(in, []interface{}{true}); err != nil { return false, err } return true, nil }) // Use the ResultFields of the first select statement as the final ResultFields rfs := src.GetFields() // Eval the following select statements for i, distinct := range p.Distincts { src = p.Srcs[i+1] // Eval src if len(src.GetFields()) != len(rfs) { return errors.New("The used SELECT statements have a different number of columns") } src.Do(ctx, func(rid interface{}, in []interface{}) (bool, error) { srcRfs := src.GetFields() for i := range in { // The column value should be casted as the same type of the first select statement in corresponding position srcRf := srcRfs[i] rf := rfs[i] /* * The lengths of the columns in the UNION result take into account the values retrieved by all of the SELECT statements * SELECT REPEAT('a',1) UNION SELECT REPEAT('b',10); * +---------------+ * | REPEAT('a',1) | * +---------------+ * | a | * | bbbbbbbbbb | * +---------------+ */ if srcRf.Flen > rf.Col.Flen { rf.Col.Flen = srcRf.Col.Flen } in[i], err = types.Convert(in[i], &rf.Col.FieldType) if err != nil { return false, err } } if distinct { // distinct union, check duplicate v, getErr := t.Get(in) if getErr != nil { return false, getErr } if len(v) > 0 { // Find duplicate, ignore it return true, nil } } rows = append(rows, in) if err := t.Set(in, []interface{}{true}); err != nil { return false, err } return true, nil }) } var more bool for _, row := range rows { if more, err = f(nil, row); !more || err != nil { break } } return nil }
func (e *Evaluator) funcDateArith(v *ast.FuncDateArithExpr) bool { // health check for date and interval nodeDate := v.Date.GetValue() if types.IsNil(nodeDate) { v.SetValue(nil) return true } nodeInterval := v.Interval.GetValue() if types.IsNil(nodeInterval) { v.SetValue(nil) return true } // parse date fieldType := mysql.TypeDate var resultField *types.FieldType switch x := nodeDate.(type) { case mysql.Time: if (x.Type == mysql.TypeDatetime) || (x.Type == mysql.TypeTimestamp) { fieldType = mysql.TypeDatetime } case string: if !mysql.IsDateFormat(x) { fieldType = mysql.TypeDatetime } case int64: if t, err := mysql.ParseTimeFromInt64(x); err == nil { if (t.Type == mysql.TypeDatetime) || (t.Type == mysql.TypeTimestamp) { fieldType = mysql.TypeDatetime } } } if mysql.IsClockUnit(v.Unit) { fieldType = mysql.TypeDatetime } resultField = types.NewFieldType(fieldType) resultField.Decimal = mysql.MaxFsp value, err := types.Convert(nodeDate, resultField) if err != nil { e.err = ErrInvalidOperation.Gen("DateArith invalid args, need date but get %T", nodeDate) return false } if types.IsNil(value) { e.err = ErrInvalidOperation.Gen("DateArith invalid args, need date but get %v", value) return false } result, ok := value.(mysql.Time) if !ok { e.err = ErrInvalidOperation.Gen("DateArith need time type, but got %T", value) return false } // parse interval var interval string if strings.ToLower(v.Unit) == "day" { day, err2 := parseDayInterval(nodeInterval) if err2 != nil { e.err = ErrInvalidOperation.Gen("DateArith invalid day interval, need int but got %T", nodeInterval) return false } interval = fmt.Sprintf("%d", day) } else { interval = fmt.Sprintf("%v", nodeInterval) } year, month, day, duration, err := mysql.ExtractTimeValue(v.Unit, interval) if err != nil { e.err = errors.Trace(err) return false } if v.Op == ast.DateSub { year, month, day, duration = -year, -month, -day, -duration } result.Time = result.Time.Add(duration) result.Time = result.Time.AddDate(int(year), int(month), int(day)) if result.Time.Nanosecond() == 0 { result.Fsp = 0 } v.SetValue(result) return true }
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: upperX := strings.ToUpper(x) if upperX == CurrentTimestamp { value.Time = defaultTime } else if upperX == ZeroTimestamp { value, _ = mysql.ParseTimeFromNum(0, tp, fsp) } else { value, err = mysql.ParseTime(x, tp, fsp) if err != nil { return nil, errors.Trace(err) } } case *ast.ValueExpr: switch x.Kind() { case types.KindString: value, err = mysql.ParseTime(x.GetString(), tp, fsp) if err != nil { return nil, errors.Trace(err) } case types.KindInt64: value, err = mysql.ParseTimeFromNum(x.GetInt64(), tp, fsp) if err != nil { return nil, errors.Trace(err) } case types.KindNull: return nil, nil default: return nil, errors.Trace(errDefaultValue) } case *ast.FuncCallExpr: if x.FnName.L == currentTimestampL { return CurrentTimestamp, nil } return nil, errors.Trace(errDefaultValue) case *ast.UnaryOperationExpr: // support some expression, like `-1` v, err := Eval(ctx, x) if err != nil { return nil, errors.Trace(err) } ft := types.NewFieldType(mysql.TypeLonglong) xval, err := types.Convert(v, ft) if err != nil { return nil, errors.Trace(err) } value, err = mysql.ParseTimeFromNum(xval.(int64), tp, fsp) if err != nil { return nil, errors.Trace(err) } default: return nil, nil } return value, nil }
// 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 }
// AddRecord implements table.Table AddRecord interface. func (t *Table) AddRecord(ctx context.Context, r []interface{}) (recordID int64, err error) { id := variable.GetSessionVars(ctx).LastInsertID // Already have auto increment ID if id != 0 { recordID = int64(id) } else { 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) } 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(txn, 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(txn, 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() { var value interface{} key := t.RecordKey(recordID, col) 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] } err = t.SetColValue(txn, key, value) if err != nil { return 0, errors.Trace(err) } } variable.GetSessionVars(ctx).AddAffectedRows(1) return recordID, nil }
func (p *UnionPlan) fetchSrc(ctx context.Context, i int, t memkv.Temp) error { src := p.Srcs[i+1] distinct := p.Distincts[i] rfs := p.GetFields() if len(src.GetFields()) != len(rfs) { return errors.New("The used SELECT statements have a different number of columns") } for { row, err := src.Next(ctx) if row == nil || err != nil { return errors.Trace(err) } srcRfs := src.GetFields() for i := range row.Data { // The column value should be casted as the same type of the first select statement in corresponding position srcRf := srcRfs[i] rf := rfs[i] /* * The lengths of the columns in the UNION result take into account the values retrieved by all of the SELECT statements * SELECT REPEAT('a',1) UNION SELECT REPEAT('b',10); * +---------------+ * | REPEAT('a',1) | * +---------------+ * | a | * | bbbbbbbbbb | * +---------------+ */ if srcRf.Flen > rf.Col.Flen { rf.Col.Flen = srcRf.Col.Flen } if rf.Col.FieldType.Tp > 0 { row.Data[i], err = types.Convert(row.Data[i], &rf.Col.FieldType) } else { // First select result doesn't contain enough type information, e,g, select null union select 1. // We cannot get the proper data type for select null. // Now we just use the first correct return data types with following select. // TODO: Try to merge all data types for all select like select null union select 1 union select "abc" if tp := srcRf.Col.FieldType.Tp; tp > 0 { rf.Col.FieldType.Tp = tp } } if err != nil { return errors.Trace(err) } } if distinct { // distinct union, check duplicate v, getErr := t.Get(row.Data) if getErr != nil { return errors.Trace(getErr) } if len(v) > 0 { // Find duplicate, ignore it continue } } p.rows = append(p.rows, row) if err := t.Set(row.Data, []interface{}{true}); err != nil { return errors.Trace(err) } } }