Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign up
Fetching contributors…
| // 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" | |
| "time" | |
| ) | |
| // ValueConverter is the interface providing the ConvertValue method. | |
| // | |
| // Various implementations of ValueConverter are provided by the | |
| // driver package to provide consistent implementations of conversions | |
| // between drivers. The ValueConverters have several uses: | |
| // | |
| // * converting from the Value types as provided by the sql package | |
| // into a database table's specific column type and making sure it | |
| // fits, such as making sure a particular int64 fits in a | |
| // table's uint16 column. | |
| // | |
| // * converting a value as given from the database into one of the | |
| // driver Value types. | |
| // | |
| // * by the sql package, for converting from a driver's Value type | |
| // to a user's type in a scan. | |
| type ValueConverter interface { | |
| // ConvertValue converts a value to a driver Value. | |
| ConvertValue(v interface{}) (Value, error) | |
| } | |
| // Valuer is the interface providing the Value method. | |
| // | |
| // Types implementing Valuer interface are able to convert | |
| // themselves to a driver Value. | |
| type Valuer interface { | |
| // Value returns a driver Value. | |
| Value() (Value, error) | |
| } | |
| // Bool is a ValueConverter that converts input values to bools. | |
| // | |
| // The conversion rules are: | |
| // - booleans are returned unchanged | |
| // - for integer types, | |
| // 1 is true | |
| // 0 is false, | |
| // other integers are an error | |
| // - for strings and []byte, same rules as strconv.ParseBool | |
| // - all other types are an error | |
| var Bool boolType | |
| type boolType struct{} | |
| var _ ValueConverter = boolType{} | |
| func (boolType) String() string { return "Bool" } | |
| func (boolType) ConvertValue(src interface{}) (Value, error) { | |
| switch s := src.(type) { | |
| case bool: | |
| return s, nil | |
| case string: | |
| b, err := strconv.ParseBool(s) | |
| if err != nil { | |
| return nil, fmt.Errorf("sql/driver: couldn't convert %q into type bool", s) | |
| } | |
| return b, nil | |
| case []byte: | |
| b, err := strconv.ParseBool(string(s)) | |
| if err != nil { | |
| return nil, fmt.Errorf("sql/driver: couldn't convert %q into type bool", s) | |
| } | |
| return b, nil | |
| } | |
| sv := reflect.ValueOf(src) | |
| switch sv.Kind() { | |
| case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | |
| iv := sv.Int() | |
| if iv == 1 || iv == 0 { | |
| return iv == 1, nil | |
| } | |
| return nil, fmt.Errorf("sql/driver: couldn't convert %d into type bool", iv) | |
| case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | |
| uv := sv.Uint() | |
| if uv == 1 || uv == 0 { | |
| return uv == 1, nil | |
| } | |
| return nil, fmt.Errorf("sql/driver: couldn't convert %d into type bool", uv) | |
| } | |
| return nil, fmt.Errorf("sql/driver: couldn't convert %v (%T) into type bool", src, src) | |
| } | |
| // 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{}) (Value, 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{}) (Value, error) { | |
| switch v.(type) { | |
| case string, []byte: | |
| return v, nil | |
| } | |
| return fmt.Sprintf("%v", v), nil | |
| } | |
| // Null is a type that implements ValueConverter by allowing nil | |
| // values but otherwise delegating to another ValueConverter. | |
| type Null struct { | |
| Converter ValueConverter | |
| } | |
| func (n Null) ConvertValue(v interface{}) (Value, error) { | |
| if v == nil { | |
| return nil, nil | |
| } | |
| return n.Converter.ConvertValue(v) | |
| } | |
| // NotNull is a type that implements ValueConverter by disallowing nil | |
| // values but otherwise delegating to another ValueConverter. | |
| type NotNull struct { | |
| Converter ValueConverter | |
| } | |
| func (n NotNull) ConvertValue(v interface{}) (Value, error) { | |
| if v == nil { | |
| return nil, fmt.Errorf("nil value not allowed") | |
| } | |
| return n.Converter.ConvertValue(v) | |
| } | |
| // IsValue reports whether v is a valid Value parameter type. | |
| func IsValue(v interface{}) bool { | |
| if v == nil { | |
| return true | |
| } | |
| switch v.(type) { | |
| case []byte, bool, float64, int64, string, time.Time: | |
| return true | |
| } | |
| return false | |
| } | |
| // IsScanValue is equivalent to IsValue. | |
| // It exists for compatibility. | |
| func IsScanValue(v interface{}) bool { | |
| return IsValue(v) | |
| } | |
| // DefaultParameterConverter is the default implementation of | |
| // ValueConverter that's used when a Stmt doesn't implement | |
| // ColumnConverter. | |
| // | |
| // DefaultParameterConverter returns its argument directly if | |
| // IsValue(arg). Otherwise, if the argument implements Valuer, its | |
| // Value method is used to return a Value. As a fallback, the provided | |
| // argument's underlying type is used to convert it to a Value: | |
| // underlying integer types are converted to int64, floats to float64, | |
| // bool, string, and []byte to themselves. If the argument is a nil | |
| // pointer, ConvertValue returns a nil Value. If the argument is a | |
| // non-nil pointer, it is dereferenced and ConvertValue is called | |
| // recursively. Other types are an error. | |
| var DefaultParameterConverter defaultConverter | |
| type defaultConverter struct{} | |
| var _ ValueConverter = defaultConverter{} | |
| var valuerReflectType = reflect.TypeOf((*Valuer)(nil)).Elem() | |
| // callValuerValue returns vr.Value(), with one exception: | |
| // If vr.Value is an auto-generated method on a pointer type and the | |
| // pointer is nil, it would panic at runtime in the panicwrap | |
| // method. Treat it like nil instead. | |
| // Issue 8415. | |
| // | |
| // This is so people can implement driver.Value on value types and | |
| // still use nil pointers to those types to mean nil/NULL, just like | |
| // string/*string. | |
| // | |
| // This function is mirrored in the database/sql package. | |
| func callValuerValue(vr Valuer) (v Value, err error) { | |
| if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr && | |
| rv.IsNil() && | |
| rv.Type().Elem().Implements(valuerReflectType) { | |
| return nil, nil | |
| } | |
| return vr.Value() | |
| } | |
| func (defaultConverter) ConvertValue(v interface{}) (Value, error) { | |
| if IsValue(v) { | |
| return v, nil | |
| } | |
| if vr, ok := v.(Valuer); ok { | |
| sv, err := callValuerValue(vr) | |
| if err != nil { | |
| return nil, err | |
| } | |
| if !IsValue(sv) { | |
| return nil, fmt.Errorf("non-Value type %T returned from Value", sv) | |
| } | |
| return sv, nil | |
| } | |
| rv := reflect.ValueOf(v) | |
| switch rv.Kind() { | |
| case reflect.Ptr: | |
| // indirect pointers | |
| if rv.IsNil() { | |
| return nil, nil | |
| } else { | |
| return defaultConverter{}.ConvertValue(rv.Elem().Interface()) | |
| } | |
| 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 | |
| case reflect.Bool: | |
| return rv.Bool(), nil | |
| case reflect.Slice: | |
| ek := rv.Type().Elem().Kind() | |
| if ek == reflect.Uint8 { | |
| return rv.Bytes(), nil | |
| } | |
| return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, ek) | |
| case reflect.String: | |
| return rv.String(), nil | |
| } | |
| return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind()) | |
| } |