// Set ResultField info according to values // This is used for inferring calculated fields type/Flen/charset // For example "select count(*) from t;" will return a ResultField with type TypeLonglong, charset binary and Flen 21. func setResultFieldInfo(fields []*field.ResultField, values []interface{}) error { if len(fields) != len(values) { return errors.Errorf("Fields and Values length unmatch %d VS %d", len(fields), len(values)) } for i, rf := range fields { if mysql.IsUninitializedType(rf.Col.Tp) { // 0 == TypeDecimal, Tp maybe uninitialized rf.Col.Charset = charset.CharsetBin rf.Col.Collate = charset.CharsetBin c := values[i] switch v := c.(type) { case int8, int16, int, int32, int64: rf.Col.Tp = mysql.TypeLonglong case uint8, uint16, uint, uint32, uint64: rf.Col.Tp = mysql.TypeLonglong rf.Col.Flag |= mysql.UnsignedFlag case float32, float64: rf.Col.Tp = mysql.TypeFloat case string: rf.Col.Tp = mysql.TypeVarchar rf.Col.Flen = len(v) rf.Col.Charset = mysql.DefaultCharset rf.Col.Collate = mysql.DefaultCollationName case []byte: rf.Col.Tp = mysql.TypeBlob case mysql.Time: rf.Col.Tp = v.Type case mysql.Duration: rf.Col.Tp = mysql.TypeDuration case mysql.Decimal: rf.Col.Tp = mysql.TypeDecimal case nil: rf.Col.Tp = mysql.TypeNull default: return errors.Errorf("Unknown type %T", c) } if rf.Col.Flen == 0 { rf.Col.Flen = mysql.GetDefaultFieldLength(rf.Col.Tp) } // TODO: set flags } } return nil }
// Next implements plan.Plan Next interface. func (r *SelectFieldsDefaultPlan) Next(ctx context.Context) (row *plan.Row, err error) { if r.evalArgs == nil { r.evalArgs = map[interface{}]interface{}{} } srcRow, err := r.Src.Next(ctx) if err != nil || srcRow == nil { return nil, errors.Trace(err) } r.evalArgs[expression.ExprEvalIdentReferFunc] = func(name string, scope int, index int) (interface{}, error) { if scope == expression.IdentReferFromTable { return srcRow.FromData[index], nil } return getIdentValueFromOuterQuery(ctx, name) } row = &plan.Row{ Data: make([]interface{}, len(r.Fields)), // must save FromData info for inner sub query use. FromData: srcRow.Data, } for i, fld := range r.Fields { d, err := fld.Expr.Eval(ctx, r.evalArgs) if err != nil { return nil, errors.Trace(err) } di, ok := d.(*types.DataItem) if ok { if mysql.IsUninitializedType(r.ResultFields[i].Col.Tp) { r.ResultFields[i].Col.FieldType = *di.Type } } row.Data[i] = d } updateRowStack(ctx, row.Data, row.FromData) return }