// Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package driver import ( "fmt" "reflect" "strconv" ) // ValueConverter is the interface providing the ConvertValue method. type ValueConverter interface { // ConvertValue converts a value to a restricted subset type. ConvertValue(v interface{}) (interface{}, error) } // Bool is a ValueConverter that converts input values to bools. // // The conversion rules are: // - .... TODO(bradfitz): TBD var Bool boolType type boolType struct{} var _ ValueConverter = boolType{} func (boolType) ConvertValue(v interface{}) (interface{}, error) { return nil, fmt.Errorf("TODO(bradfitz): bool conversions") } // Int32 is a ValueConverter that converts input values to int64, // respecting the limits of an int32 value. var Int32 int32Type type int32Type struct{} var _ ValueConverter = int32Type{} func (int32Type) ConvertValue(v interface{}) (interface{}, error) { rv := reflect.ValueOf(v) switch rv.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: i64 := rv.Int() if i64 > (1<<31)-1 || i64 < -(1<<31) { return nil, fmt.Errorf("sql/driver: value %d overflows int32", v) } return i64, nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: u64 := rv.Uint() if u64 > (1<<31)-1 { return nil, fmt.Errorf("sql/driver: value %d overflows int32", v) } return int64(u64), nil case reflect.String: i, err := strconv.Atoi(rv.String()) if err != nil { return nil, fmt.Errorf("sql/driver: value %q can't be converted to int32", v) } return int64(i), nil } return nil, fmt.Errorf("sql/driver: unsupported value %v (type %T) converting to int32", v, v) } // String is a ValueConverter that converts its input to a string. // If the value is already a string or []byte, it's unchanged. // If the value is of another type, conversion to string is done // with fmt.Sprintf("%v", v). var String stringType type stringType struct{} func (stringType) ConvertValue(v interface{}) (interface{}, error) { switch v.(type) { case string, []byte: return v, nil } return fmt.Sprintf("%v", v), nil } // IsParameterSubsetType reports whether v is of a valid type for a // parameter. These types are: // // int64 // float64 // bool // nil // []byte // string // // This is the ame list as IsScanSubsetType, with the addition of // string. func IsParameterSubsetType(v interface{}) bool { if IsScanSubsetType(v) { return true } if _, ok := v.(string); ok { return true } return false } // IsScanSubsetType reports whether v is of a valid type for a // value populated by Rows.Next. These types are: // // int64 // float64 // bool // nil // []byte // // This is the same list as IsParameterSubsetType, without string. func IsScanSubsetType(v interface{}) bool { if v == nil { return true } switch v.(type) { case int64, float64, []byte, bool: return true } return false } // DefaultParameterConverter is the default implementation of // ValueConverter that's used when a Stmt doesn't implement // ColumnConverter. // // DefaultParameterConverter returns the given value directly if // IsSubsetType(value). Otherwise integer type are converted to // int64, floats to float64, and strings to []byte. Other types are // an error. var DefaultParameterConverter defaultConverter type defaultConverter struct{} var _ ValueConverter = defaultConverter{} func (defaultConverter) ConvertValue(v interface{}) (interface{}, error) { if IsParameterSubsetType(v) { return v, nil } rv := reflect.ValueOf(v) switch rv.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return rv.Int(), nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32: return int64(rv.Uint()), nil case reflect.Uint64: u64 := rv.Uint() if u64 >= 1<<63 { return nil, fmt.Errorf("uint64 values with high bit set are not supported") } return int64(u64), nil case reflect.Float32, reflect.Float64: return rv.Float(), nil } return nil, fmt.Errorf("unsupported type %s", rv.Kind()) }