]>
Commit | Line | Data |
---|---|---|
d8f41257 ILT |
1 | // Copyright 2011 The Go Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style | |
3 | // license that can be found in the LICENSE file. | |
4 | ||
5 | // Type conversions for Scan. | |
6 | ||
7 | package sql | |
8 | ||
9 | import ( | |
af92e385 | 10 | "database/sql/driver" |
2fd401c8 | 11 | "errors" |
d8f41257 | 12 | "fmt" |
d8f41257 ILT |
13 | "reflect" |
14 | "strconv" | |
f98dd1a3 | 15 | "time" |
c2047754 ILT |
16 | "unicode" |
17 | "unicode/utf8" | |
d8f41257 ILT |
18 | ) |
19 | ||
be47d6ec ILT |
20 | var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error |
21 | ||
c2047754 ILT |
22 | func describeNamedValue(nv *driver.NamedValue) string { |
23 | if len(nv.Name) == 0 { | |
24 | return fmt.Sprintf("$%d", nv.Ordinal) | |
25 | } | |
26 | return fmt.Sprintf("with name %q", nv.Name) | |
27 | } | |
28 | ||
29 | func validateNamedValueName(name string) error { | |
30 | if len(name) == 0 { | |
31 | return nil | |
32 | } | |
33 | r, _ := utf8.DecodeRuneInString(name) | |
34 | if unicode.IsLetter(r) { | |
35 | return nil | |
36 | } | |
37 | return fmt.Errorf("name %q does not begin with a letter", name) | |
38 | } | |
39 | ||
bc998d03 ILT |
40 | // ccChecker wraps the driver.ColumnConverter and allows it to be used |
41 | // as if it were a NamedValueChecker. If the driver ColumnConverter | |
42 | // is not present then the NamedValueChecker will return driver.ErrSkip. | |
43 | type ccChecker struct { | |
bc998d03 ILT |
44 | cci driver.ColumnConverter |
45 | want int | |
46 | } | |
47 | ||
48 | func (c ccChecker) CheckNamedValue(nv *driver.NamedValue) error { | |
49 | if c.cci == nil { | |
50 | return driver.ErrSkip | |
51 | } | |
52 | // The column converter shouldn't be called on any index | |
53 | // it isn't expecting. The final error will be thrown | |
54 | // in the argument converter loop. | |
55 | index := nv.Ordinal - 1 | |
56 | if c.want <= index { | |
57 | return nil | |
58 | } | |
59 | ||
60 | // First, see if the value itself knows how to convert | |
61 | // itself to a driver type. For example, a NullString | |
62 | // struct changing into a string or nil. | |
63 | if vr, ok := nv.Value.(driver.Valuer); ok { | |
64 | sv, err := callValuerValue(vr) | |
65 | if err != nil { | |
66 | return err | |
67 | } | |
68 | if !driver.IsValue(sv) { | |
69 | return fmt.Errorf("non-subset type %T returned from Value", sv) | |
70 | } | |
71 | nv.Value = sv | |
72 | } | |
73 | ||
74 | // Second, ask the column to sanity check itself. For | |
75 | // example, drivers might use this to make sure that | |
76 | // an int64 values being inserted into a 16-bit | |
77 | // integer field is in range (before getting | |
78 | // truncated), or that a nil can't go into a NOT NULL | |
79 | // column before going across the network to get the | |
80 | // same error. | |
81 | var err error | |
82 | arg := nv.Value | |
bc998d03 | 83 | nv.Value, err = c.cci.ColumnConverter(index).ConvertValue(arg) |
bc998d03 ILT |
84 | if err != nil { |
85 | return err | |
86 | } | |
87 | if !driver.IsValue(nv.Value) { | |
88 | return fmt.Errorf("driver ColumnConverter error converted %T to unsupported type %T", arg, nv.Value) | |
89 | } | |
90 | return nil | |
91 | } | |
92 | ||
93 | // defaultCheckNamedValue wraps the default ColumnConverter to have the same | |
94 | // function signature as the CheckNamedValue in the driver.NamedValueChecker | |
95 | // interface. | |
96 | func defaultCheckNamedValue(nv *driver.NamedValue) (err error) { | |
97 | nv.Value, err = driver.DefaultParameterConverter.ConvertValue(nv.Value) | |
98 | return err | |
99 | } | |
100 | ||
aa8901e9 | 101 | // driverArgsConnLocked converts arguments from callers of Stmt.Exec and |
4ccad563 ILT |
102 | // Stmt.Query into driver Values. |
103 | // | |
be47d6ec | 104 | // The statement ds may be nil, if no statement is available. |
aa8901e9 ILT |
105 | // |
106 | // ci must be locked. | |
1a2f01ef | 107 | func driverArgsConnLocked(ci driver.Conn, ds *driverStmt, args []interface{}) ([]driver.NamedValue, error) { |
c2047754 | 108 | nvargs := make([]driver.NamedValue, len(args)) |
bc998d03 ILT |
109 | |
110 | // -1 means the driver doesn't know how to count the number of | |
111 | // placeholders, so we won't sanity check input here and instead let the | |
112 | // driver deal with errors. | |
113 | want := -1 | |
114 | ||
be47d6ec | 115 | var si driver.Stmt |
bc998d03 | 116 | var cc ccChecker |
be47d6ec ILT |
117 | if ds != nil { |
118 | si = ds.si | |
1a2f01ef | 119 | want = ds.si.NumInput() |
bc998d03 | 120 | cc.want = want |
be47d6ec | 121 | } |
4ccad563 | 122 | |
bc998d03 ILT |
123 | // Check all types of interfaces from the start. |
124 | // Drivers may opt to use the NamedValueChecker for special | |
125 | // argument types, then return driver.ErrSkip to pass it along | |
126 | // to the column converter. | |
127 | nvc, ok := si.(driver.NamedValueChecker) | |
4ccad563 | 128 | if !ok { |
bc998d03 ILT |
129 | nvc, ok = ci.(driver.NamedValueChecker) |
130 | } | |
131 | cci, ok := si.(driver.ColumnConverter) | |
132 | if ok { | |
133 | cc.cci = cci | |
4ccad563 ILT |
134 | } |
135 | ||
bc998d03 ILT |
136 | // Loop through all the arguments, checking each one. |
137 | // If no error is returned simply increment the index | |
138 | // and continue. However if driver.ErrRemoveArgument | |
139 | // is returned the argument is not included in the query | |
140 | // argument list. | |
141 | var err error | |
142 | var n int | |
143 | for _, arg := range args { | |
c2047754 | 144 | nv := &nvargs[n] |
c2047754 | 145 | if np, ok := arg.(NamedArg); ok { |
bc998d03 | 146 | if err = validateNamedValueName(np.Name); err != nil { |
c2047754 ILT |
147 | return nil, err |
148 | } | |
149 | arg = np.Value | |
150 | nv.Name = np.Name | |
151 | } | |
bc998d03 ILT |
152 | nv.Ordinal = n + 1 |
153 | nv.Value = arg | |
154 | ||
155 | // Checking sequence has four routes: | |
156 | // A: 1. Default | |
157 | // B: 1. NamedValueChecker 2. Column Converter 3. Default | |
158 | // C: 1. NamedValueChecker 3. Default | |
159 | // D: 1. Column Converter 2. Default | |
160 | // | |
161 | // The only time a Column Converter is called is first | |
162 | // or after NamedValueConverter. If first it is handled before | |
163 | // the nextCheck label. Thus for repeats tries only when the | |
164 | // NamedValueConverter is selected should the Column Converter | |
165 | // be used in the retry. | |
166 | checker := defaultCheckNamedValue | |
167 | nextCC := false | |
168 | switch { | |
169 | case nvc != nil: | |
170 | nextCC = cci != nil | |
171 | checker = nvc.CheckNamedValue | |
172 | case cci != nil: | |
173 | checker = cc.CheckNamedValue | |
4ccad563 ILT |
174 | } |
175 | ||
bc998d03 ILT |
176 | nextCheck: |
177 | err = checker(nv) | |
178 | switch err { | |
179 | case nil: | |
180 | n++ | |
181 | continue | |
182 | case driver.ErrRemoveArgument: | |
183 | nvargs = nvargs[:len(nvargs)-1] | |
184 | continue | |
185 | case driver.ErrSkip: | |
186 | if nextCC { | |
187 | nextCC = false | |
188 | checker = cc.CheckNamedValue | |
189 | } else { | |
190 | checker = defaultCheckNamedValue | |
191 | } | |
192 | goto nextCheck | |
193 | default: | |
c2047754 | 194 | return nil, fmt.Errorf("sql: converting argument %s type: %v", describeNamedValue(nv), err) |
4ccad563 | 195 | } |
bc998d03 ILT |
196 | } |
197 | ||
1a2f01ef | 198 | // Check the length of arguments after conversion to allow for omitted |
bc998d03 ILT |
199 | // arguments. |
200 | if want != -1 && len(nvargs) != want { | |
201 | return nil, fmt.Errorf("sql: expected %d arguments, got %d", want, len(nvargs)) | |
ab61e9c4 | 202 | } |
4ccad563 | 203 | |
c2047754 | 204 | return nvargs, nil |
bc998d03 | 205 | |
ab61e9c4 ILT |
206 | } |
207 | ||
4f4a855d ILT |
208 | // convertAssign is the same as convertAssignRows, but without the optional |
209 | // rows argument. | |
2fd401c8 | 210 | func convertAssign(dest, src interface{}) error { |
4f4a855d ILT |
211 | return convertAssignRows(dest, src, nil) |
212 | } | |
213 | ||
214 | // convertAssignRows copies to dest the value in src, converting it if possible. | |
215 | // An error is returned if the copy would result in loss of information. | |
216 | // dest should be a pointer type. If rows is passed in, the rows will | |
217 | // be used as the parent for any cursor values converted from a | |
218 | // driver.Rows to a *Rows. | |
219 | func convertAssignRows(dest, src interface{}, rows *Rows) error { | |
be47d6ec | 220 | // Common cases, without reflect. |
d8f41257 ILT |
221 | switch s := src.(type) { |
222 | case string: | |
223 | switch d := dest.(type) { | |
224 | case *string: | |
be47d6ec ILT |
225 | if d == nil { |
226 | return errNilPtr | |
227 | } | |
d8f41257 ILT |
228 | *d = s |
229 | return nil | |
9af4cb95 | 230 | case *[]byte: |
be47d6ec ILT |
231 | if d == nil { |
232 | return errNilPtr | |
233 | } | |
9af4cb95 ILT |
234 | *d = []byte(s) |
235 | return nil | |
1a2f01ef ILT |
236 | case *RawBytes: |
237 | if d == nil { | |
238 | return errNilPtr | |
239 | } | |
240 | *d = append((*d)[:0], s...) | |
241 | return nil | |
d8f41257 ILT |
242 | } |
243 | case []byte: | |
244 | switch d := dest.(type) { | |
245 | case *string: | |
be47d6ec ILT |
246 | if d == nil { |
247 | return errNilPtr | |
248 | } | |
d8f41257 ILT |
249 | *d = string(s) |
250 | return nil | |
94252f4b | 251 | case *interface{}: |
be47d6ec ILT |
252 | if d == nil { |
253 | return errNilPtr | |
254 | } | |
255 | *d = cloneBytes(s) | |
94252f4b | 256 | return nil |
d8f41257 | 257 | case *[]byte: |
be47d6ec ILT |
258 | if d == nil { |
259 | return errNilPtr | |
260 | } | |
261 | *d = cloneBytes(s) | |
262 | return nil | |
263 | case *RawBytes: | |
264 | if d == nil { | |
265 | return errNilPtr | |
266 | } | |
d8f41257 ILT |
267 | *d = s |
268 | return nil | |
269 | } | |
f98dd1a3 ILT |
270 | case time.Time: |
271 | switch d := dest.(type) { | |
1a2f01ef ILT |
272 | case *time.Time: |
273 | *d = s | |
274 | return nil | |
f98dd1a3 ILT |
275 | case *string: |
276 | *d = s.Format(time.RFC3339Nano) | |
277 | return nil | |
278 | case *[]byte: | |
279 | if d == nil { | |
280 | return errNilPtr | |
281 | } | |
282 | *d = []byte(s.Format(time.RFC3339Nano)) | |
283 | return nil | |
1a2f01ef ILT |
284 | case *RawBytes: |
285 | if d == nil { | |
286 | return errNilPtr | |
287 | } | |
288 | *d = s.AppendFormat((*d)[:0], time.RFC3339Nano) | |
289 | return nil | |
f98dd1a3 | 290 | } |
aa8901e9 ILT |
291 | case decimalDecompose: |
292 | switch d := dest.(type) { | |
293 | case decimalCompose: | |
294 | return d.Compose(s.Decompose(nil)) | |
295 | } | |
9af4cb95 ILT |
296 | case nil: |
297 | switch d := dest.(type) { | |
be47d6ec ILT |
298 | case *interface{}: |
299 | if d == nil { | |
300 | return errNilPtr | |
301 | } | |
302 | *d = nil | |
303 | return nil | |
9af4cb95 | 304 | case *[]byte: |
be47d6ec ILT |
305 | if d == nil { |
306 | return errNilPtr | |
307 | } | |
308 | *d = nil | |
309 | return nil | |
310 | case *RawBytes: | |
311 | if d == nil { | |
312 | return errNilPtr | |
313 | } | |
9af4cb95 ILT |
314 | *d = nil |
315 | return nil | |
316 | } | |
4f4a855d ILT |
317 | // The driver is returning a cursor the client may iterate over. |
318 | case driver.Rows: | |
319 | switch d := dest.(type) { | |
320 | case *Rows: | |
321 | if d == nil { | |
322 | return errNilPtr | |
323 | } | |
324 | if rows == nil { | |
325 | return errors.New("invalid context to convert cursor rows, missing parent *Rows") | |
326 | } | |
327 | rows.closemu.Lock() | |
328 | *d = Rows{ | |
329 | dc: rows.dc, | |
330 | releaseConn: func(error) {}, | |
331 | rowsi: s, | |
332 | } | |
333 | // Chain the cancel function. | |
334 | parentCancel := rows.cancel | |
335 | rows.cancel = func() { | |
336 | // When Rows.cancel is called, the closemu will be locked as well. | |
337 | // So we can access rs.lasterr. | |
338 | d.close(rows.lasterr) | |
339 | if parentCancel != nil { | |
340 | parentCancel() | |
341 | } | |
342 | } | |
343 | rows.closemu.Unlock() | |
344 | return nil | |
345 | } | |
d8f41257 ILT |
346 | } |
347 | ||
9c63abc9 | 348 | var sv reflect.Value |
d8f41257 ILT |
349 | |
350 | switch d := dest.(type) { | |
351 | case *string: | |
9c63abc9 | 352 | sv = reflect.ValueOf(src) |
d8f41257 ILT |
353 | switch sv.Kind() { |
354 | case reflect.Bool, | |
355 | reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, | |
356 | reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, | |
357 | reflect.Float32, reflect.Float64: | |
6736ef96 | 358 | *d = asString(src) |
d8f41257 ILT |
359 | return nil |
360 | } | |
be47d6ec ILT |
361 | case *[]byte: |
362 | sv = reflect.ValueOf(src) | |
6736ef96 ILT |
363 | if b, ok := asBytes(nil, sv); ok { |
364 | *d = b | |
be47d6ec ILT |
365 | return nil |
366 | } | |
367 | case *RawBytes: | |
368 | sv = reflect.ValueOf(src) | |
6736ef96 ILT |
369 | if b, ok := asBytes([]byte(*d)[:0], sv); ok { |
370 | *d = RawBytes(b) | |
be47d6ec ILT |
371 | return nil |
372 | } | |
9c63abc9 ILT |
373 | case *bool: |
374 | bv, err := driver.Bool.ConvertValue(src) | |
375 | if err == nil { | |
376 | *d = bv.(bool) | |
377 | } | |
378 | return err | |
94252f4b ILT |
379 | case *interface{}: |
380 | *d = src | |
381 | return nil | |
d8f41257 ILT |
382 | } |
383 | ||
cbb6491d ILT |
384 | if scanner, ok := dest.(Scanner); ok { |
385 | return scanner.Scan(src) | |
d8f41257 ILT |
386 | } |
387 | ||
388 | dpv := reflect.ValueOf(dest) | |
389 | if dpv.Kind() != reflect.Ptr { | |
2fd401c8 | 390 | return errors.New("destination not a pointer") |
d8f41257 | 391 | } |
be47d6ec ILT |
392 | if dpv.IsNil() { |
393 | return errNilPtr | |
394 | } | |
d8f41257 | 395 | |
9c63abc9 ILT |
396 | if !sv.IsValid() { |
397 | sv = reflect.ValueOf(src) | |
398 | } | |
399 | ||
d8f41257 | 400 | dv := reflect.Indirect(dpv) |
f98dd1a3 | 401 | if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) { |
22b955cc ILT |
402 | switch b := src.(type) { |
403 | case []byte: | |
404 | dv.Set(reflect.ValueOf(cloneBytes(b))) | |
405 | default: | |
406 | dv.Set(sv) | |
407 | } | |
d8f41257 ILT |
408 | return nil |
409 | } | |
410 | ||
f98dd1a3 ILT |
411 | if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) { |
412 | dv.Set(sv.Convert(dv.Type())) | |
413 | return nil | |
414 | } | |
415 | ||
bc998d03 ILT |
416 | // The following conversions use a string value as an intermediate representation |
417 | // to convert between various numeric types. | |
418 | // | |
419 | // This also allows scanning into user defined types such as "type Int int64". | |
420 | // For symmetry, also check for string destination types. | |
d8f41257 | 421 | switch dv.Kind() { |
cbb6491d ILT |
422 | case reflect.Ptr: |
423 | if src == nil { | |
424 | dv.Set(reflect.Zero(dv.Type())) | |
425 | return nil | |
cbb6491d | 426 | } |
dd931d9b | 427 | dv.Set(reflect.New(dv.Type().Elem())) |
4f4a855d | 428 | return convertAssignRows(dv.Interface(), src, rows) |
d8f41257 | 429 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: |
aa8901e9 ILT |
430 | if src == nil { |
431 | return fmt.Errorf("converting NULL to %s is unsupported", dv.Kind()) | |
432 | } | |
9c63abc9 | 433 | s := asString(src) |
9a0e3259 | 434 | i64, err := strconv.ParseInt(s, 10, dv.Type().Bits()) |
9c63abc9 | 435 | if err != nil { |
f98dd1a3 ILT |
436 | err = strconvErr(err) |
437 | return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) | |
9c63abc9 | 438 | } |
9c63abc9 ILT |
439 | dv.SetInt(i64) |
440 | return nil | |
d8f41257 | 441 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: |
aa8901e9 ILT |
442 | if src == nil { |
443 | return fmt.Errorf("converting NULL to %s is unsupported", dv.Kind()) | |
444 | } | |
9c63abc9 | 445 | s := asString(src) |
9a0e3259 | 446 | u64, err := strconv.ParseUint(s, 10, dv.Type().Bits()) |
9c63abc9 | 447 | if err != nil { |
f98dd1a3 ILT |
448 | err = strconvErr(err) |
449 | return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) | |
9c63abc9 | 450 | } |
9c63abc9 ILT |
451 | dv.SetUint(u64) |
452 | return nil | |
453 | case reflect.Float32, reflect.Float64: | |
aa8901e9 ILT |
454 | if src == nil { |
455 | return fmt.Errorf("converting NULL to %s is unsupported", dv.Kind()) | |
456 | } | |
9c63abc9 | 457 | s := asString(src) |
9a0e3259 | 458 | f64, err := strconv.ParseFloat(s, dv.Type().Bits()) |
9c63abc9 | 459 | if err != nil { |
f98dd1a3 ILT |
460 | err = strconvErr(err) |
461 | return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) | |
9c63abc9 | 462 | } |
9c63abc9 ILT |
463 | dv.SetFloat(f64) |
464 | return nil | |
bc998d03 | 465 | case reflect.String: |
aa8901e9 ILT |
466 | if src == nil { |
467 | return fmt.Errorf("converting NULL to %s is unsupported", dv.Kind()) | |
468 | } | |
bc998d03 ILT |
469 | switch v := src.(type) { |
470 | case string: | |
471 | dv.SetString(v) | |
472 | return nil | |
473 | case []byte: | |
474 | dv.SetString(string(v)) | |
475 | return nil | |
476 | } | |
d8f41257 ILT |
477 | } |
478 | ||
f98dd1a3 ILT |
479 | return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest) |
480 | } | |
481 | ||
482 | func strconvErr(err error) error { | |
483 | if ne, ok := err.(*strconv.NumError); ok { | |
484 | return ne.Err | |
485 | } | |
486 | return err | |
d8f41257 ILT |
487 | } |
488 | ||
be47d6ec ILT |
489 | func cloneBytes(b []byte) []byte { |
490 | if b == nil { | |
491 | return nil | |
be47d6ec | 492 | } |
dd931d9b ILT |
493 | c := make([]byte, len(b)) |
494 | copy(c, b) | |
495 | return c | |
be47d6ec ILT |
496 | } |
497 | ||
9c63abc9 | 498 | func asString(src interface{}) string { |
d8f41257 ILT |
499 | switch v := src.(type) { |
500 | case string: | |
9c63abc9 | 501 | return v |
d8f41257 | 502 | case []byte: |
9c63abc9 | 503 | return string(v) |
d8f41257 | 504 | } |
6736ef96 ILT |
505 | rv := reflect.ValueOf(src) |
506 | switch rv.Kind() { | |
507 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | |
508 | return strconv.FormatInt(rv.Int(), 10) | |
509 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | |
510 | return strconv.FormatUint(rv.Uint(), 10) | |
511 | case reflect.Float64: | |
512 | return strconv.FormatFloat(rv.Float(), 'g', -1, 64) | |
513 | case reflect.Float32: | |
514 | return strconv.FormatFloat(rv.Float(), 'g', -1, 32) | |
515 | case reflect.Bool: | |
516 | return strconv.FormatBool(rv.Bool()) | |
517 | } | |
9c63abc9 | 518 | return fmt.Sprintf("%v", src) |
d8f41257 | 519 | } |
6736ef96 ILT |
520 | |
521 | func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) { | |
522 | switch rv.Kind() { | |
523 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | |
524 | return strconv.AppendInt(buf, rv.Int(), 10), true | |
525 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | |
526 | return strconv.AppendUint(buf, rv.Uint(), 10), true | |
527 | case reflect.Float32: | |
528 | return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true | |
529 | case reflect.Float64: | |
530 | return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true | |
531 | case reflect.Bool: | |
532 | return strconv.AppendBool(buf, rv.Bool()), true | |
533 | case reflect.String: | |
534 | s := rv.String() | |
535 | return append(buf, s...), true | |
536 | } | |
537 | return | |
538 | } | |
c2047754 ILT |
539 | |
540 | var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem() | |
541 | ||
542 | // callValuerValue returns vr.Value(), with one exception: | |
543 | // If vr.Value is an auto-generated method on a pointer type and the | |
544 | // pointer is nil, it would panic at runtime in the panicwrap | |
545 | // method. Treat it like nil instead. | |
546 | // Issue 8415. | |
547 | // | |
548 | // This is so people can implement driver.Value on value types and | |
549 | // still use nil pointers to those types to mean nil/NULL, just like | |
550 | // string/*string. | |
551 | // | |
552 | // This function is mirrored in the database/sql/driver package. | |
553 | func callValuerValue(vr driver.Valuer) (v driver.Value, err error) { | |
554 | if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr && | |
555 | rv.IsNil() && | |
556 | rv.Type().Elem().Implements(valuerReflectType) { | |
557 | return nil, nil | |
558 | } | |
559 | return vr.Value() | |
560 | } | |
aa8901e9 ILT |
561 | |
562 | // decimal composes or decomposes a decimal value to and from individual parts. | |
563 | // There are four parts: a boolean negative flag, a form byte with three possible states | |
564 | // (finite=0, infinite=1, NaN=2), a base-2 big-endian integer | |
565 | // coefficient (also known as a significand) as a []byte, and an int32 exponent. | |
566 | // These are composed into a final value as "decimal = (neg) (form=finite) coefficient * 10 ^ exponent". | |
567 | // A zero length coefficient is a zero value. | |
5a8ea165 | 568 | // The big-endian integer coefficient stores the most significant byte first (at coefficient[0]). |
aa8901e9 ILT |
569 | // If the form is not finite the coefficient and exponent should be ignored. |
570 | // The negative parameter may be set to true for any form, although implementations are not required | |
571 | // to respect the negative parameter in the non-finite form. | |
572 | // | |
573 | // Implementations may choose to set the negative parameter to true on a zero or NaN value, | |
574 | // but implementations that do not differentiate between negative and positive | |
575 | // zero or NaN values should ignore the negative parameter without error. | |
576 | // If an implementation does not support Infinity it may be converted into a NaN without error. | |
577 | // If a value is set that is larger than what is supported by an implementation, | |
578 | // an error must be returned. | |
579 | // Implementations must return an error if a NaN or Infinity is attempted to be set while neither | |
580 | // are supported. | |
581 | // | |
582 | // NOTE(kardianos): This is an experimental interface. See https://golang.org/issue/30870 | |
583 | type decimal interface { | |
584 | decimalDecompose | |
585 | decimalCompose | |
586 | } | |
587 | ||
588 | type decimalDecompose interface { | |
589 | // Decompose returns the internal decimal state in parts. | |
590 | // If the provided buf has sufficient capacity, buf may be returned as the coefficient with | |
591 | // the value set and length set as appropriate. | |
592 | Decompose(buf []byte) (form byte, negative bool, coefficient []byte, exponent int32) | |
593 | } | |
594 | ||
595 | type decimalCompose interface { | |
596 | // Compose sets the internal decimal value from parts. If the value cannot be | |
597 | // represented then an error should be returned. | |
598 | Compose(form byte, negative bool, coefficient []byte, exponent int32) error | |
599 | } |