convert.go raw

   1  // Extracted from Go database/sql source code
   2  
   3  // Copyright 2011 The Go Authors. All rights reserved.
   4  // Use of this source code is governed by a BSD-style
   5  // license that can be found in the LICENSE file.
   6  
   7  // Type conversions for Scan.
   8  
   9  package sqlite3
  10  
  11  import (
  12  	"database/sql"
  13  	"database/sql/driver"
  14  	"errors"
  15  	"fmt"
  16  	"reflect"
  17  	"strconv"
  18  	"time"
  19  )
  20  
  21  var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error
  22  
  23  // convertAssign copies to dest the value in src, converting it if possible.
  24  // An error is returned if the copy would result in loss of information.
  25  // dest should be a pointer type.
  26  func convertAssign(dest, src any) error {
  27  	// Common cases, without reflect.
  28  	switch s := src.(type) {
  29  	case string:
  30  		switch d := dest.(type) {
  31  		case *string:
  32  			if d == nil {
  33  				return errNilPtr
  34  			}
  35  			*d = s
  36  			return nil
  37  		case *[]byte:
  38  			if d == nil {
  39  				return errNilPtr
  40  			}
  41  			*d = []byte(s)
  42  			return nil
  43  		case *sql.RawBytes:
  44  			if d == nil {
  45  				return errNilPtr
  46  			}
  47  			*d = append((*d)[:0], s...)
  48  			return nil
  49  		}
  50  	case []byte:
  51  		switch d := dest.(type) {
  52  		case *string:
  53  			if d == nil {
  54  				return errNilPtr
  55  			}
  56  			*d = string(s)
  57  			return nil
  58  		case *any:
  59  			if d == nil {
  60  				return errNilPtr
  61  			}
  62  			*d = cloneBytes(s)
  63  			return nil
  64  		case *[]byte:
  65  			if d == nil {
  66  				return errNilPtr
  67  			}
  68  			*d = cloneBytes(s)
  69  			return nil
  70  		case *sql.RawBytes:
  71  			if d == nil {
  72  				return errNilPtr
  73  			}
  74  			*d = s
  75  			return nil
  76  		}
  77  	case time.Time:
  78  		switch d := dest.(type) {
  79  		case *time.Time:
  80  			*d = s
  81  			return nil
  82  		case *string:
  83  			*d = s.Format(time.RFC3339Nano)
  84  			return nil
  85  		case *[]byte:
  86  			if d == nil {
  87  				return errNilPtr
  88  			}
  89  			*d = []byte(s.Format(time.RFC3339Nano))
  90  			return nil
  91  		case *sql.RawBytes:
  92  			if d == nil {
  93  				return errNilPtr
  94  			}
  95  			*d = s.AppendFormat((*d)[:0], time.RFC3339Nano)
  96  			return nil
  97  		}
  98  	case nil:
  99  		switch d := dest.(type) {
 100  		case *any:
 101  			if d == nil {
 102  				return errNilPtr
 103  			}
 104  			*d = nil
 105  			return nil
 106  		case *[]byte:
 107  			if d == nil {
 108  				return errNilPtr
 109  			}
 110  			*d = nil
 111  			return nil
 112  		case *sql.RawBytes:
 113  			if d == nil {
 114  				return errNilPtr
 115  			}
 116  			*d = nil
 117  			return nil
 118  		}
 119  	}
 120  
 121  	var sv reflect.Value
 122  
 123  	switch d := dest.(type) {
 124  	case *string:
 125  		sv = reflect.ValueOf(src)
 126  		switch sv.Kind() {
 127  		case reflect.Bool,
 128  			reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
 129  			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
 130  			reflect.Float32, reflect.Float64:
 131  			*d = asString(src)
 132  			return nil
 133  		}
 134  	case *[]byte:
 135  		sv = reflect.ValueOf(src)
 136  		if b, ok := asBytes(nil, sv); ok {
 137  			*d = b
 138  			return nil
 139  		}
 140  	case *sql.RawBytes:
 141  		sv = reflect.ValueOf(src)
 142  		if b, ok := asBytes([]byte(*d)[:0], sv); ok {
 143  			*d = sql.RawBytes(b)
 144  			return nil
 145  		}
 146  	case *bool:
 147  		bv, err := driver.Bool.ConvertValue(src)
 148  		if err == nil {
 149  			*d = bv.(bool)
 150  		}
 151  		return err
 152  	case *any:
 153  		*d = src
 154  		return nil
 155  	}
 156  
 157  	if scanner, ok := dest.(sql.Scanner); ok {
 158  		return scanner.Scan(src)
 159  	}
 160  
 161  	dpv := reflect.ValueOf(dest)
 162  	if dpv.Kind() != reflect.Ptr {
 163  		return errors.New("destination not a pointer")
 164  	}
 165  	if dpv.IsNil() {
 166  		return errNilPtr
 167  	}
 168  
 169  	if !sv.IsValid() {
 170  		sv = reflect.ValueOf(src)
 171  	}
 172  
 173  	dv := reflect.Indirect(dpv)
 174  	if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) {
 175  		switch b := src.(type) {
 176  		case []byte:
 177  			dv.Set(reflect.ValueOf(cloneBytes(b)))
 178  		default:
 179  			dv.Set(sv)
 180  		}
 181  		return nil
 182  	}
 183  
 184  	if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) {
 185  		dv.Set(sv.Convert(dv.Type()))
 186  		return nil
 187  	}
 188  
 189  	// The following conversions use a string value as an intermediate representation
 190  	// to convert between various numeric types.
 191  	//
 192  	// This also allows scanning into user defined types such as "type Int int64".
 193  	// For symmetry, also check for string destination types.
 194  	switch dv.Kind() {
 195  	case reflect.Ptr:
 196  		if src == nil {
 197  			dv.Set(reflect.Zero(dv.Type()))
 198  			return nil
 199  		}
 200  		dv.Set(reflect.New(dv.Type().Elem()))
 201  		return convertAssign(dv.Interface(), src)
 202  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 203  		s := asString(src)
 204  		i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())
 205  		if err != nil {
 206  			err = strconvErr(err)
 207  			return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
 208  		}
 209  		dv.SetInt(i64)
 210  		return nil
 211  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 212  		s := asString(src)
 213  		u64, err := strconv.ParseUint(s, 10, dv.Type().Bits())
 214  		if err != nil {
 215  			err = strconvErr(err)
 216  			return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
 217  		}
 218  		dv.SetUint(u64)
 219  		return nil
 220  	case reflect.Float32, reflect.Float64:
 221  		s := asString(src)
 222  		f64, err := strconv.ParseFloat(s, dv.Type().Bits())
 223  		if err != nil {
 224  			err = strconvErr(err)
 225  			return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
 226  		}
 227  		dv.SetFloat(f64)
 228  		return nil
 229  	case reflect.String:
 230  		switch v := src.(type) {
 231  		case string:
 232  			dv.SetString(v)
 233  			return nil
 234  		case []byte:
 235  			dv.SetString(string(v))
 236  			return nil
 237  		}
 238  	}
 239  
 240  	return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest)
 241  }
 242  
 243  func strconvErr(err error) error {
 244  	if ne, ok := err.(*strconv.NumError); ok {
 245  		return ne.Err
 246  	}
 247  	return err
 248  }
 249  
 250  func cloneBytes(b []byte) []byte {
 251  	if b == nil {
 252  		return nil
 253  	}
 254  	c := make([]byte, len(b))
 255  	copy(c, b)
 256  	return c
 257  }
 258  
 259  func asString(src any) string {
 260  	switch v := src.(type) {
 261  	case string:
 262  		return v
 263  	case []byte:
 264  		return string(v)
 265  	}
 266  	rv := reflect.ValueOf(src)
 267  	switch rv.Kind() {
 268  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 269  		return strconv.FormatInt(rv.Int(), 10)
 270  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 271  		return strconv.FormatUint(rv.Uint(), 10)
 272  	case reflect.Float64:
 273  		return strconv.FormatFloat(rv.Float(), 'g', -1, 64)
 274  	case reflect.Float32:
 275  		return strconv.FormatFloat(rv.Float(), 'g', -1, 32)
 276  	case reflect.Bool:
 277  		return strconv.FormatBool(rv.Bool())
 278  	}
 279  	return fmt.Sprintf("%v", src)
 280  }
 281  
 282  func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {
 283  	switch rv.Kind() {
 284  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 285  		return strconv.AppendInt(buf, rv.Int(), 10), true
 286  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 287  		return strconv.AppendUint(buf, rv.Uint(), 10), true
 288  	case reflect.Float32:
 289  		return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true
 290  	case reflect.Float64:
 291  		return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true
 292  	case reflect.Bool:
 293  		return strconv.AppendBool(buf, rv.Bool()), true
 294  	case reflect.String:
 295  		s := rv.String()
 296  		return append(buf, s...), true
 297  	}
 298  	return
 299  }
 300