// 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 any) (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 must not panic. 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 any) (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 any) (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 any) (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 any) (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 any) (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 any) bool { if v == nil { return true } switch v.(type) { case []byte, bool, float64, int64, string, time.Time: return true case decimalDecompose: return true } return false } // IsScanValue is equivalent to IsValue. // It exists for compatibility. func IsScanValue(v any) 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.Pointer && rv.IsNil() && rv.Type().Elem().Implements(valuerReflectType) { return nil, nil } return vr.Value() } func (defaultConverter) ConvertValue(v any) (Value, error) { if IsValue(v) { return v, nil } switch vr := v.(type) { case Valuer: 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 // For now, continue to prefer the Valuer interface over the decimal decompose interface. case decimalDecompose: return vr, nil } rv := reflect.ValueOf(v) switch rv.Kind() { case reflect.Pointer: // 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()) } type decimalDecompose interface { // Decompose returns the internal decimal state into parts. // If the provided buf has sufficient capacity, buf may be returned as the coefficient with // the value set and length set as appropriate. Decompose(buf []byte) (form byte, negative bool, coefficient []byte, exponent int32) }