304 lines · 7.3 KB · Go
RawDownload
// 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. // Type conversions for Scan. package sql import (	"database/sql/driver"	"errors"	"fmt"	"reflect"	"strconv") var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error // driverArgs converts arguments from callers of Stmt.Exec and// Stmt.Query into driver Values.//// The statement ds may be nil, if no statement is available.func driverArgs(ds *driverStmt, args []interface{}) ([]driver.Value, error) {	dargs := make([]driver.Value, len(args))	var si driver.Stmt	if ds != nil {		si = ds.si	}	cc, ok := si.(driver.ColumnConverter) 	// Normal path, for a driver.Stmt that is not a ColumnConverter.	if !ok {		for n, arg := range args {			var err error			dargs[n], err = driver.DefaultParameterConverter.ConvertValue(arg)			if err != nil {				return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err)			}		}		return dargs, nil	} 	// Let the Stmt convert its own arguments.	for n, arg := range args {		// First, see if the value itself knows how to convert		// itself to a driver type.  For example, a NullString		// struct changing into a string or nil.		if svi, ok := arg.(driver.Valuer); ok {			sv, err := svi.Value()			if err != nil {				return nil, fmt.Errorf("sql: argument index %d from Value: %v", n, err)			}			if !driver.IsValue(sv) {				return nil, fmt.Errorf("sql: argument index %d: non-subset type %T returned from Value", n, sv)			}			arg = sv		} 		// Second, ask the column to sanity check itself. For		// example, drivers might use this to make sure that		// an int64 values being inserted into a 16-bit		// integer field is in range (before getting		// truncated), or that a nil can't go into a NOT NULL		// column before going across the network to get the		// same error.		var err error		ds.Lock()		dargs[n], err = cc.ColumnConverter(n).ConvertValue(arg)		ds.Unlock()		if err != nil {			return nil, fmt.Errorf("sql: converting argument #%d's type: %v", n, err)		}		if !driver.IsValue(dargs[n]) {			return nil, fmt.Errorf("sql: driver ColumnConverter error converted %T to unsupported type %T",				arg, dargs[n])		}	} 	return dargs, nil} // convertAssign copies to dest the value in src, converting it if possible.// An error is returned if the copy would result in loss of information.// dest should be a pointer type.func convertAssign(dest, src interface{}) error {	// Common cases, without reflect.	switch s := src.(type) {	case string:		switch d := dest.(type) {		case *string:			if d == nil {				return errNilPtr			}			*d = s			return nil		case *[]byte:			if d == nil {				return errNilPtr			}			*d = []byte(s)			return nil		}	case []byte:		switch d := dest.(type) {		case *string:			if d == nil {				return errNilPtr			}			*d = string(s)			return nil		case *interface{}:			if d == nil {				return errNilPtr			}			*d = cloneBytes(s)			return nil		case *[]byte:			if d == nil {				return errNilPtr			}			*d = cloneBytes(s)			return nil		case *RawBytes:			if d == nil {				return errNilPtr			}			*d = s			return nil		}	case nil:		switch d := dest.(type) {		case *interface{}:			if d == nil {				return errNilPtr			}			*d = nil			return nil		case *[]byte:			if d == nil {				return errNilPtr			}			*d = nil			return nil		case *RawBytes:			if d == nil {				return errNilPtr			}			*d = nil			return nil		}	} 	var sv reflect.Value 	switch d := dest.(type) {	case *string:		sv = reflect.ValueOf(src)		switch sv.Kind() {		case reflect.Bool,			reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,			reflect.Float32, reflect.Float64:			*d = asString(src)			return nil		}	case *[]byte:		sv = reflect.ValueOf(src)		if b, ok := asBytes(nil, sv); ok {			*d = b			return nil		}	case *RawBytes:		sv = reflect.ValueOf(src)		if b, ok := asBytes([]byte(*d)[:0], sv); ok {			*d = RawBytes(b)			return nil		}	case *bool:		bv, err := driver.Bool.ConvertValue(src)		if err == nil {			*d = bv.(bool)		}		return err	case *interface{}:		*d = src		return nil	} 	if scanner, ok := dest.(Scanner); ok {		return scanner.Scan(src)	} 	dpv := reflect.ValueOf(dest)	if dpv.Kind() != reflect.Ptr {		return errors.New("destination not a pointer")	}	if dpv.IsNil() {		return errNilPtr	} 	if !sv.IsValid() {		sv = reflect.ValueOf(src)	} 	dv := reflect.Indirect(dpv)	if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) {		dv.Set(sv)		return nil	} 	if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) {		dv.Set(sv.Convert(dv.Type()))		return nil	} 	switch dv.Kind() {	case reflect.Ptr:		if src == nil {			dv.Set(reflect.Zero(dv.Type()))			return nil		} else {			dv.Set(reflect.New(dv.Type().Elem()))			return convertAssign(dv.Interface(), src)		}	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:		s := asString(src)		i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())		if err != nil {			return fmt.Errorf("converting string %q to a %s: %v", s, dv.Kind(), err)		}		dv.SetInt(i64)		return nil	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:		s := asString(src)		u64, err := strconv.ParseUint(s, 10, dv.Type().Bits())		if err != nil {			return fmt.Errorf("converting string %q to a %s: %v", s, dv.Kind(), err)		}		dv.SetUint(u64)		return nil	case reflect.Float32, reflect.Float64:		s := asString(src)		f64, err := strconv.ParseFloat(s, dv.Type().Bits())		if err != nil {			return fmt.Errorf("converting string %q to a %s: %v", s, dv.Kind(), err)		}		dv.SetFloat(f64)		return nil	} 	return fmt.Errorf("unsupported driver -> Scan pair: %T -> %T", src, dest)} func cloneBytes(b []byte) []byte {	if b == nil {		return nil	} else {		c := make([]byte, len(b))		copy(c, b)		return c	}} func asString(src interface{}) string {	switch v := src.(type) {	case string:		return v	case []byte:		return string(v)	}	rv := reflect.ValueOf(src)	switch rv.Kind() {	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:		return strconv.FormatInt(rv.Int(), 10)	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:		return strconv.FormatUint(rv.Uint(), 10)	case reflect.Float64:		return strconv.FormatFloat(rv.Float(), 'g', -1, 64)	case reflect.Float32:		return strconv.FormatFloat(rv.Float(), 'g', -1, 32)	case reflect.Bool:		return strconv.FormatBool(rv.Bool())	}	return fmt.Sprintf("%v", src)} func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {	switch rv.Kind() {	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:		return strconv.AppendInt(buf, rv.Int(), 10), true	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:		return strconv.AppendUint(buf, rv.Uint(), 10), true	case reflect.Float32:		return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true	case reflect.Float64:		return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true	case reflect.Bool:		return strconv.AppendBool(buf, rv.Bool()), true	case reflect.String:		s := rv.String()		return append(buf, s...), true	}	return}