Beispiel #1
0
// 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
}
Beispiel #2
0
// 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
}