1 package pq
2
3 import (
4 "bytes"
5 "database/sql"
6 "database/sql/driver"
7 "encoding/hex"
8 "fmt"
9 "reflect"
10 "strconv"
11 "strings"
12 )
13
14 var typeByteSlice = reflect.TypeOf([]byte{})
15 var typeDriverValuer = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
16 var typeSQLScanner = reflect.TypeOf((*sql.Scanner)(nil)).Elem()
17
18
19
20
21
22
23
24
25
26
27
28
29 func Array(a interface{}) interface {
30 driver.Valuer
31 sql.Scanner
32 } {
33 switch a := a.(type) {
34 case []bool:
35 return (*BoolArray)(&a)
36 case []float64:
37 return (*Float64Array)(&a)
38 case []float32:
39 return (*Float32Array)(&a)
40 case []int64:
41 return (*Int64Array)(&a)
42 case []int32:
43 return (*Int32Array)(&a)
44 case []string:
45 return (*StringArray)(&a)
46 case [][]byte:
47 return (*ByteaArray)(&a)
48
49 case *[]bool:
50 return (*BoolArray)(a)
51 case *[]float64:
52 return (*Float64Array)(a)
53 case *[]float32:
54 return (*Float32Array)(a)
55 case *[]int64:
56 return (*Int64Array)(a)
57 case *[]int32:
58 return (*Int32Array)(a)
59 case *[]string:
60 return (*StringArray)(a)
61 case *[][]byte:
62 return (*ByteaArray)(a)
63 }
64
65 return GenericArray{a}
66 }
67
68
69
70 type ArrayDelimiter interface {
71
72 ArrayDelimiter() string
73 }
74
75
76 type BoolArray []bool
77
78
79 func (a *BoolArray) Scan(src interface{}) error {
80 switch src := src.(type) {
81 case []byte:
82 return a.scanBytes(src)
83 case string:
84 return a.scanBytes([]byte(src))
85 case nil:
86 *a = nil
87 return nil
88 }
89
90 return fmt.Errorf("pq: cannot convert %T to BoolArray", src)
91 }
92
93 func (a *BoolArray) scanBytes(src []byte) error {
94 elems, err := scanLinearArray(src, []byte{','}, "BoolArray")
95 if err != nil {
96 return err
97 }
98 if *a != nil && len(elems) == 0 {
99 *a = (*a)[:0]
100 } else {
101 b := make(BoolArray, len(elems))
102 for i, v := range elems {
103 if len(v) != 1 {
104 return fmt.Errorf("pq: could not parse boolean array index %d: invalid boolean %q", i, v)
105 }
106 switch v[0] {
107 case 't':
108 b[i] = true
109 case 'f':
110 b[i] = false
111 default:
112 return fmt.Errorf("pq: could not parse boolean array index %d: invalid boolean %q", i, v)
113 }
114 }
115 *a = b
116 }
117 return nil
118 }
119
120
121 func (a BoolArray) Value() (driver.Value, error) {
122 if a == nil {
123 return nil, nil
124 }
125
126 if n := len(a); n > 0 {
127
128
129 b := make([]byte, 1+2*n)
130
131 for i := 0; i < n; i++ {
132 b[2*i] = ','
133 if a[i] {
134 b[1+2*i] = 't'
135 } else {
136 b[1+2*i] = 'f'
137 }
138 }
139
140 b[0] = '{'
141 b[2*n] = '}'
142
143 return string(b), nil
144 }
145
146 return "{}", nil
147 }
148
149
150 type ByteaArray [][]byte
151
152
153 func (a *ByteaArray) Scan(src interface{}) error {
154 switch src := src.(type) {
155 case []byte:
156 return a.scanBytes(src)
157 case string:
158 return a.scanBytes([]byte(src))
159 case nil:
160 *a = nil
161 return nil
162 }
163
164 return fmt.Errorf("pq: cannot convert %T to ByteaArray", src)
165 }
166
167 func (a *ByteaArray) scanBytes(src []byte) error {
168 elems, err := scanLinearArray(src, []byte{','}, "ByteaArray")
169 if err != nil {
170 return err
171 }
172 if *a != nil && len(elems) == 0 {
173 *a = (*a)[:0]
174 } else {
175 b := make(ByteaArray, len(elems))
176 for i, v := range elems {
177 b[i], err = parseBytea(v)
178 if err != nil {
179 return fmt.Errorf("could not parse bytea array index %d: %s", i, err.Error())
180 }
181 }
182 *a = b
183 }
184 return nil
185 }
186
187
188
189 func (a ByteaArray) Value() (driver.Value, error) {
190 if a == nil {
191 return nil, nil
192 }
193
194 if n := len(a); n > 0 {
195
196
197 size := 1 + 6*n
198 for _, x := range a {
199 size += hex.EncodedLen(len(x))
200 }
201
202 b := make([]byte, size)
203
204 for i, s := 0, b; i < n; i++ {
205 o := copy(s, `,"\\x`)
206 o += hex.Encode(s[o:], a[i])
207 s[o] = '"'
208 s = s[o+1:]
209 }
210
211 b[0] = '{'
212 b[size-1] = '}'
213
214 return string(b), nil
215 }
216
217 return "{}", nil
218 }
219
220
221
222 type Float64Array []float64
223
224
225 func (a *Float64Array) Scan(src interface{}) error {
226 switch src := src.(type) {
227 case []byte:
228 return a.scanBytes(src)
229 case string:
230 return a.scanBytes([]byte(src))
231 case nil:
232 *a = nil
233 return nil
234 }
235
236 return fmt.Errorf("pq: cannot convert %T to Float64Array", src)
237 }
238
239 func (a *Float64Array) scanBytes(src []byte) error {
240 elems, err := scanLinearArray(src, []byte{','}, "Float64Array")
241 if err != nil {
242 return err
243 }
244 if *a != nil && len(elems) == 0 {
245 *a = (*a)[:0]
246 } else {
247 b := make(Float64Array, len(elems))
248 for i, v := range elems {
249 if b[i], err = strconv.ParseFloat(string(v), 64); err != nil {
250 return fmt.Errorf("pq: parsing array element index %d: %v", i, err)
251 }
252 }
253 *a = b
254 }
255 return nil
256 }
257
258
259 func (a Float64Array) Value() (driver.Value, error) {
260 if a == nil {
261 return nil, nil
262 }
263
264 if n := len(a); n > 0 {
265
266
267 b := make([]byte, 1, 1+2*n)
268 b[0] = '{'
269
270 b = strconv.AppendFloat(b, a[0], 'f', -1, 64)
271 for i := 1; i < n; i++ {
272 b = append(b, ',')
273 b = strconv.AppendFloat(b, a[i], 'f', -1, 64)
274 }
275
276 return string(append(b, '}')), nil
277 }
278
279 return "{}", nil
280 }
281
282
283
284 type Float32Array []float32
285
286
287 func (a *Float32Array) Scan(src interface{}) error {
288 switch src := src.(type) {
289 case []byte:
290 return a.scanBytes(src)
291 case string:
292 return a.scanBytes([]byte(src))
293 case nil:
294 *a = nil
295 return nil
296 }
297
298 return fmt.Errorf("pq: cannot convert %T to Float32Array", src)
299 }
300
301 func (a *Float32Array) scanBytes(src []byte) error {
302 elems, err := scanLinearArray(src, []byte{','}, "Float32Array")
303 if err != nil {
304 return err
305 }
306 if *a != nil && len(elems) == 0 {
307 *a = (*a)[:0]
308 } else {
309 b := make(Float32Array, len(elems))
310 for i, v := range elems {
311 var x float64
312 if x, err = strconv.ParseFloat(string(v), 32); err != nil {
313 return fmt.Errorf("pq: parsing array element index %d: %v", i, err)
314 }
315 b[i] = float32(x)
316 }
317 *a = b
318 }
319 return nil
320 }
321
322
323 func (a Float32Array) Value() (driver.Value, error) {
324 if a == nil {
325 return nil, nil
326 }
327
328 if n := len(a); n > 0 {
329
330
331 b := make([]byte, 1, 1+2*n)
332 b[0] = '{'
333
334 b = strconv.AppendFloat(b, float64(a[0]), 'f', -1, 32)
335 for i := 1; i < n; i++ {
336 b = append(b, ',')
337 b = strconv.AppendFloat(b, float64(a[i]), 'f', -1, 32)
338 }
339
340 return string(append(b, '}')), nil
341 }
342
343 return "{}", nil
344 }
345
346
347
348 type GenericArray struct{ A interface{} }
349
350 func (GenericArray) evaluateDestination(rt reflect.Type) (reflect.Type, func([]byte, reflect.Value) error, string) {
351 var assign func([]byte, reflect.Value) error
352 var del = ","
353
354
355
356 {
357 if reflect.PtrTo(rt).Implements(typeSQLScanner) {
358
359 assign = func(src []byte, dest reflect.Value) (err error) {
360 ss := dest.Addr().Interface().(sql.Scanner)
361 if src == nil {
362 err = ss.Scan(nil)
363 } else {
364 err = ss.Scan(src)
365 }
366 return
367 }
368 goto FoundType
369 }
370
371 assign = func([]byte, reflect.Value) error {
372 return fmt.Errorf("pq: scanning to %s is not implemented; only sql.Scanner", rt)
373 }
374 }
375
376 FoundType:
377
378 if ad, ok := reflect.Zero(rt).Interface().(ArrayDelimiter); ok {
379 del = ad.ArrayDelimiter()
380 }
381
382 return rt, assign, del
383 }
384
385
386 func (a GenericArray) Scan(src interface{}) error {
387 dpv := reflect.ValueOf(a.A)
388 switch {
389 case dpv.Kind() != reflect.Ptr:
390 return fmt.Errorf("pq: destination %T is not a pointer to array or slice", a.A)
391 case dpv.IsNil():
392 return fmt.Errorf("pq: destination %T is nil", a.A)
393 }
394
395 dv := dpv.Elem()
396 switch dv.Kind() {
397 case reflect.Slice:
398 case reflect.Array:
399 default:
400 return fmt.Errorf("pq: destination %T is not a pointer to array or slice", a.A)
401 }
402
403 switch src := src.(type) {
404 case []byte:
405 return a.scanBytes(src, dv)
406 case string:
407 return a.scanBytes([]byte(src), dv)
408 case nil:
409 if dv.Kind() == reflect.Slice {
410 dv.Set(reflect.Zero(dv.Type()))
411 return nil
412 }
413 }
414
415 return fmt.Errorf("pq: cannot convert %T to %s", src, dv.Type())
416 }
417
418 func (a GenericArray) scanBytes(src []byte, dv reflect.Value) error {
419 dtype, assign, del := a.evaluateDestination(dv.Type().Elem())
420 dims, elems, err := parseArray(src, []byte(del))
421 if err != nil {
422 return err
423 }
424
425
426
427 if len(dims) > 1 {
428 return fmt.Errorf("pq: scanning from multidimensional ARRAY%s is not implemented",
429 strings.Replace(fmt.Sprint(dims), " ", "][", -1))
430 }
431
432
433 if len(dims) == 0 {
434 dims = append(dims, 0)
435 }
436
437 for i, rt := 0, dv.Type(); i < len(dims); i, rt = i+1, rt.Elem() {
438 switch rt.Kind() {
439 case reflect.Slice:
440 case reflect.Array:
441 if rt.Len() != dims[i] {
442 return fmt.Errorf("pq: cannot convert ARRAY%s to %s",
443 strings.Replace(fmt.Sprint(dims), " ", "][", -1), dv.Type())
444 }
445 default:
446
447 }
448 }
449
450 values := reflect.MakeSlice(reflect.SliceOf(dtype), len(elems), len(elems))
451 for i, e := range elems {
452 if err := assign(e, values.Index(i)); err != nil {
453 return fmt.Errorf("pq: parsing array element index %d: %v", i, err)
454 }
455 }
456
457
458
459 switch dv.Kind() {
460 case reflect.Slice:
461 dv.Set(values.Slice(0, dims[0]))
462 case reflect.Array:
463 for i := 0; i < dims[0]; i++ {
464 dv.Index(i).Set(values.Index(i))
465 }
466 }
467
468 return nil
469 }
470
471
472 func (a GenericArray) Value() (driver.Value, error) {
473 if a.A == nil {
474 return nil, nil
475 }
476
477 rv := reflect.ValueOf(a.A)
478
479 switch rv.Kind() {
480 case reflect.Slice:
481 if rv.IsNil() {
482 return nil, nil
483 }
484 case reflect.Array:
485 default:
486 return nil, fmt.Errorf("pq: Unable to convert %T to array", a.A)
487 }
488
489 if n := rv.Len(); n > 0 {
490
491
492 b := make([]byte, 0, 1+2*n)
493
494 b, _, err := appendArray(b, rv, n)
495 return string(b), err
496 }
497
498 return "{}", nil
499 }
500
501
502 type Int64Array []int64
503
504
505 func (a *Int64Array) Scan(src interface{}) error {
506 switch src := src.(type) {
507 case []byte:
508 return a.scanBytes(src)
509 case string:
510 return a.scanBytes([]byte(src))
511 case nil:
512 *a = nil
513 return nil
514 }
515
516 return fmt.Errorf("pq: cannot convert %T to Int64Array", src)
517 }
518
519 func (a *Int64Array) scanBytes(src []byte) error {
520 elems, err := scanLinearArray(src, []byte{','}, "Int64Array")
521 if err != nil {
522 return err
523 }
524 if *a != nil && len(elems) == 0 {
525 *a = (*a)[:0]
526 } else {
527 b := make(Int64Array, len(elems))
528 for i, v := range elems {
529 if b[i], err = strconv.ParseInt(string(v), 10, 64); err != nil {
530 return fmt.Errorf("pq: parsing array element index %d: %v", i, err)
531 }
532 }
533 *a = b
534 }
535 return nil
536 }
537
538
539 func (a Int64Array) Value() (driver.Value, error) {
540 if a == nil {
541 return nil, nil
542 }
543
544 if n := len(a); n > 0 {
545
546
547 b := make([]byte, 1, 1+2*n)
548 b[0] = '{'
549
550 b = strconv.AppendInt(b, a[0], 10)
551 for i := 1; i < n; i++ {
552 b = append(b, ',')
553 b = strconv.AppendInt(b, a[i], 10)
554 }
555
556 return string(append(b, '}')), nil
557 }
558
559 return "{}", nil
560 }
561
562
563 type Int32Array []int32
564
565
566 func (a *Int32Array) Scan(src interface{}) error {
567 switch src := src.(type) {
568 case []byte:
569 return a.scanBytes(src)
570 case string:
571 return a.scanBytes([]byte(src))
572 case nil:
573 *a = nil
574 return nil
575 }
576
577 return fmt.Errorf("pq: cannot convert %T to Int32Array", src)
578 }
579
580 func (a *Int32Array) scanBytes(src []byte) error {
581 elems, err := scanLinearArray(src, []byte{','}, "Int32Array")
582 if err != nil {
583 return err
584 }
585 if *a != nil && len(elems) == 0 {
586 *a = (*a)[:0]
587 } else {
588 b := make(Int32Array, len(elems))
589 for i, v := range elems {
590 x, err := strconv.ParseInt(string(v), 10, 32)
591 if err != nil {
592 return fmt.Errorf("pq: parsing array element index %d: %v", i, err)
593 }
594 b[i] = int32(x)
595 }
596 *a = b
597 }
598 return nil
599 }
600
601
602 func (a Int32Array) Value() (driver.Value, error) {
603 if a == nil {
604 return nil, nil
605 }
606
607 if n := len(a); n > 0 {
608
609
610 b := make([]byte, 1, 1+2*n)
611 b[0] = '{'
612
613 b = strconv.AppendInt(b, int64(a[0]), 10)
614 for i := 1; i < n; i++ {
615 b = append(b, ',')
616 b = strconv.AppendInt(b, int64(a[i]), 10)
617 }
618
619 return string(append(b, '}')), nil
620 }
621
622 return "{}", nil
623 }
624
625
626 type StringArray []string
627
628
629 func (a *StringArray) Scan(src interface{}) error {
630 switch src := src.(type) {
631 case []byte:
632 return a.scanBytes(src)
633 case string:
634 return a.scanBytes([]byte(src))
635 case nil:
636 *a = nil
637 return nil
638 }
639
640 return fmt.Errorf("pq: cannot convert %T to StringArray", src)
641 }
642
643 func (a *StringArray) scanBytes(src []byte) error {
644 elems, err := scanLinearArray(src, []byte{','}, "StringArray")
645 if err != nil {
646 return err
647 }
648 if *a != nil && len(elems) == 0 {
649 *a = (*a)[:0]
650 } else {
651 b := make(StringArray, len(elems))
652 for i, v := range elems {
653 if b[i] = string(v); v == nil {
654 return fmt.Errorf("pq: parsing array element index %d: cannot convert nil to string", i)
655 }
656 }
657 *a = b
658 }
659 return nil
660 }
661
662
663 func (a StringArray) Value() (driver.Value, error) {
664 if a == nil {
665 return nil, nil
666 }
667
668 if n := len(a); n > 0 {
669
670
671 b := make([]byte, 1, 1+3*n)
672 b[0] = '{'
673
674 b = appendArrayQuotedBytes(b, []byte(a[0]))
675 for i := 1; i < n; i++ {
676 b = append(b, ',')
677 b = appendArrayQuotedBytes(b, []byte(a[i]))
678 }
679
680 return string(append(b, '}')), nil
681 }
682
683 return "{}", nil
684 }
685
686
687
688
689
690 func appendArray(b []byte, rv reflect.Value, n int) ([]byte, string, error) {
691 var del string
692 var err error
693
694 b = append(b, '{')
695
696 if b, del, err = appendArrayElement(b, rv.Index(0)); err != nil {
697 return b, del, err
698 }
699
700 for i := 1; i < n; i++ {
701 b = append(b, del...)
702 if b, del, err = appendArrayElement(b, rv.Index(i)); err != nil {
703 return b, del, err
704 }
705 }
706
707 return append(b, '}'), del, nil
708 }
709
710
711
712
713
714
715
716
717
718 func appendArrayElement(b []byte, rv reflect.Value) ([]byte, string, error) {
719 if k := rv.Kind(); k == reflect.Array || k == reflect.Slice {
720 if t := rv.Type(); t != typeByteSlice && !t.Implements(typeDriverValuer) {
721 if n := rv.Len(); n > 0 {
722 return appendArray(b, rv, n)
723 }
724
725 return b, "", nil
726 }
727 }
728
729 var del = ","
730 var err error
731 var iv interface{} = rv.Interface()
732
733 if ad, ok := iv.(ArrayDelimiter); ok {
734 del = ad.ArrayDelimiter()
735 }
736
737 if iv, err = driver.DefaultParameterConverter.ConvertValue(iv); err != nil {
738 return b, del, err
739 }
740
741 switch v := iv.(type) {
742 case nil:
743 return append(b, "NULL"...), del, nil
744 case []byte:
745 return appendArrayQuotedBytes(b, v), del, nil
746 case string:
747 return appendArrayQuotedBytes(b, []byte(v)), del, nil
748 }
749
750 b, err = appendValue(b, iv)
751 return b, del, err
752 }
753
754 func appendArrayQuotedBytes(b, v []byte) []byte {
755 b = append(b, '"')
756 for {
757 i := bytes.IndexAny(v, `"\`)
758 if i < 0 {
759 b = append(b, v...)
760 break
761 }
762 if i > 0 {
763 b = append(b, v[:i]...)
764 }
765 b = append(b, '\\', v[i])
766 v = v[i+1:]
767 }
768 return append(b, '"')
769 }
770
771 func appendValue(b []byte, v driver.Value) ([]byte, error) {
772 return append(b, encode(nil, v, 0)...), nil
773 }
774
775
776
777
778
779
780
781 func parseArray(src, del []byte) (dims []int, elems [][]byte, err error) {
782 var depth, i int
783
784 if len(src) < 1 || src[0] != '{' {
785 return nil, nil, fmt.Errorf("pq: unable to parse array; expected %q at offset %d", '{', 0)
786 }
787
788 Open:
789 for i < len(src) {
790 switch src[i] {
791 case '{':
792 depth++
793 i++
794 case '}':
795 elems = make([][]byte, 0)
796 goto Close
797 default:
798 break Open
799 }
800 }
801 dims = make([]int, i)
802
803 Element:
804 for i < len(src) {
805 switch src[i] {
806 case '{':
807 if depth == len(dims) {
808 break Element
809 }
810 depth++
811 dims[depth-1] = 0
812 i++
813 case '"':
814 var elem = []byte{}
815 var escape bool
816 for i++; i < len(src); i++ {
817 if escape {
818 elem = append(elem, src[i])
819 escape = false
820 } else {
821 switch src[i] {
822 default:
823 elem = append(elem, src[i])
824 case '\\':
825 escape = true
826 case '"':
827 elems = append(elems, elem)
828 i++
829 break Element
830 }
831 }
832 }
833 default:
834 for start := i; i < len(src); i++ {
835 if bytes.HasPrefix(src[i:], del) || src[i] == '}' {
836 elem := src[start:i]
837 if len(elem) == 0 {
838 return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i)
839 }
840 if bytes.Equal(elem, []byte("NULL")) {
841 elem = nil
842 }
843 elems = append(elems, elem)
844 break Element
845 }
846 }
847 }
848 }
849
850 for i < len(src) {
851 if bytes.HasPrefix(src[i:], del) && depth > 0 {
852 dims[depth-1]++
853 i += len(del)
854 goto Element
855 } else if src[i] == '}' && depth > 0 {
856 dims[depth-1]++
857 depth--
858 i++
859 } else {
860 return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i)
861 }
862 }
863
864 Close:
865 for i < len(src) {
866 if src[i] == '}' && depth > 0 {
867 depth--
868 i++
869 } else {
870 return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i)
871 }
872 }
873 if depth > 0 {
874 err = fmt.Errorf("pq: unable to parse array; expected %q at offset %d", '}', i)
875 }
876 if err == nil {
877 for _, d := range dims {
878 if (len(elems) % d) != 0 {
879 err = fmt.Errorf("pq: multidimensional arrays must have elements with matching dimensions")
880 }
881 }
882 }
883 return
884 }
885
886 func scanLinearArray(src, del []byte, typ string) (elems [][]byte, err error) {
887 dims, elems, err := parseArray(src, del)
888 if err != nil {
889 return nil, err
890 }
891 if len(dims) > 1 {
892 return nil, fmt.Errorf("pq: cannot convert ARRAY%s to %s", strings.Replace(fmt.Sprint(dims), " ", "][", -1), typ)
893 }
894 return elems, err
895 }
896
View as plain text