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