podman
299 строк · 6.7 Кб
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 any) error {
27// Common cases, without reflect.
28switch s := src.(type) {
29case string:
30switch d := dest.(type) {
31case *string:
32if d == nil {
33return errNilPtr
34}
35*d = s
36return nil
37case *[]byte:
38if d == nil {
39return errNilPtr
40}
41*d = []byte(s)
42return nil
43case *sql.RawBytes:
44if d == nil {
45return errNilPtr
46}
47*d = append((*d)[:0], s...)
48return nil
49}
50case []byte:
51switch d := dest.(type) {
52case *string:
53if d == nil {
54return errNilPtr
55}
56*d = string(s)
57return nil
58case *any:
59if d == nil {
60return errNilPtr
61}
62*d = cloneBytes(s)
63return nil
64case *[]byte:
65if d == nil {
66return errNilPtr
67}
68*d = cloneBytes(s)
69return nil
70case *sql.RawBytes:
71if d == nil {
72return errNilPtr
73}
74*d = s
75return nil
76}
77case time.Time:
78switch d := dest.(type) {
79case *time.Time:
80*d = s
81return nil
82case *string:
83*d = s.Format(time.RFC3339Nano)
84return nil
85case *[]byte:
86if d == nil {
87return errNilPtr
88}
89*d = []byte(s.Format(time.RFC3339Nano))
90return nil
91case *sql.RawBytes:
92if d == nil {
93return errNilPtr
94}
95*d = s.AppendFormat((*d)[:0], time.RFC3339Nano)
96return nil
97}
98case nil:
99switch d := dest.(type) {
100case *any:
101if d == nil {
102return errNilPtr
103}
104*d = nil
105return nil
106case *[]byte:
107if d == nil {
108return errNilPtr
109}
110*d = nil
111return nil
112case *sql.RawBytes:
113if d == nil {
114return errNilPtr
115}
116*d = nil
117return nil
118}
119}
120
121var sv reflect.Value
122
123switch d := dest.(type) {
124case *string:
125sv = reflect.ValueOf(src)
126switch sv.Kind() {
127case reflect.Bool,
128reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
129reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
130reflect.Float32, reflect.Float64:
131*d = asString(src)
132return nil
133}
134case *[]byte:
135sv = reflect.ValueOf(src)
136if b, ok := asBytes(nil, sv); ok {
137*d = b
138return nil
139}
140case *sql.RawBytes:
141sv = reflect.ValueOf(src)
142if b, ok := asBytes([]byte(*d)[:0], sv); ok {
143*d = sql.RawBytes(b)
144return nil
145}
146case *bool:
147bv, err := driver.Bool.ConvertValue(src)
148if err == nil {
149*d = bv.(bool)
150}
151return err
152case *any:
153*d = src
154return nil
155}
156
157if scanner, ok := dest.(sql.Scanner); ok {
158return scanner.Scan(src)
159}
160
161dpv := reflect.ValueOf(dest)
162if dpv.Kind() != reflect.Ptr {
163return errors.New("destination not a pointer")
164}
165if dpv.IsNil() {
166return errNilPtr
167}
168
169if !sv.IsValid() {
170sv = reflect.ValueOf(src)
171}
172
173dv := reflect.Indirect(dpv)
174if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) {
175switch b := src.(type) {
176case []byte:
177dv.Set(reflect.ValueOf(cloneBytes(b)))
178default:
179dv.Set(sv)
180}
181return nil
182}
183
184if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) {
185dv.Set(sv.Convert(dv.Type()))
186return 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.
194switch dv.Kind() {
195case reflect.Ptr:
196if src == nil {
197dv.Set(reflect.Zero(dv.Type()))
198return nil
199}
200dv.Set(reflect.New(dv.Type().Elem()))
201return convertAssign(dv.Interface(), src)
202case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
203s := asString(src)
204i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())
205if err != nil {
206err = strconvErr(err)
207return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
208}
209dv.SetInt(i64)
210return nil
211case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
212s := asString(src)
213u64, err := strconv.ParseUint(s, 10, dv.Type().Bits())
214if err != nil {
215err = strconvErr(err)
216return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
217}
218dv.SetUint(u64)
219return nil
220case reflect.Float32, reflect.Float64:
221s := asString(src)
222f64, err := strconv.ParseFloat(s, dv.Type().Bits())
223if err != nil {
224err = strconvErr(err)
225return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
226}
227dv.SetFloat(f64)
228return nil
229case reflect.String:
230switch v := src.(type) {
231case string:
232dv.SetString(v)
233return nil
234case []byte:
235dv.SetString(string(v))
236return nil
237}
238}
239
240return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest)
241}
242
243func strconvErr(err error) error {
244if ne, ok := err.(*strconv.NumError); ok {
245return ne.Err
246}
247return err
248}
249
250func cloneBytes(b []byte) []byte {
251if b == nil {
252return nil
253}
254c := make([]byte, len(b))
255copy(c, b)
256return c
257}
258
259func asString(src any) string {
260switch v := src.(type) {
261case string:
262return v
263case []byte:
264return string(v)
265}
266rv := reflect.ValueOf(src)
267switch rv.Kind() {
268case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
269return strconv.FormatInt(rv.Int(), 10)
270case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
271return strconv.FormatUint(rv.Uint(), 10)
272case reflect.Float64:
273return strconv.FormatFloat(rv.Float(), 'g', -1, 64)
274case reflect.Float32:
275return strconv.FormatFloat(rv.Float(), 'g', -1, 32)
276case reflect.Bool:
277return strconv.FormatBool(rv.Bool())
278}
279return fmt.Sprintf("%v", src)
280}
281
282func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {
283switch rv.Kind() {
284case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
285return strconv.AppendInt(buf, rv.Int(), 10), true
286case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
287return strconv.AppendUint(buf, rv.Uint(), 10), true
288case reflect.Float32:
289return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true
290case reflect.Float64:
291return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true
292case reflect.Bool:
293return strconv.AppendBool(buf, rv.Bool()), true
294case reflect.String:
295s := rv.String()
296return append(buf, s...), true
297}
298return
299}
300