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