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
9package sqlite3
10
11import (
12	"database/sql"
13	"database/sql/driver"
14	"errors"
15	"fmt"
16	"reflect"
17	"strconv"
18	"time"
19)
20
21var 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.
26func convertAssign(dest, src interface{}) 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 *interface{}:
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 *interface{}:
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 *interface{}:
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
243func strconvErr(err error) error {
244	if ne, ok := err.(*strconv.NumError); ok {
245		return ne.Err
246	}
247	return err
248}
249
250func 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
259func asString(src interface{}) 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
282func 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