source: code/trunk/vendor/github.com/lib/pq/array.go@ 822

Last change on this file since 822 was 822, checked in by yakumo.izuru, 22 months ago

Prefer immortal.run over runit and rc.d, use vendored modules
for convenience.

Signed-off-by: Izuru Yakumo <yakumo.izuru@…>

File size: 20.2 KB
Line 
1package pq
2
3import (
4 "bytes"
5 "database/sql"
6 "database/sql/driver"
7 "encoding/hex"
8 "fmt"
9 "reflect"
10 "strconv"
11 "strings"
12)
13
14var typeByteSlice = reflect.TypeOf([]byte{})
15var typeDriverValuer = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
16var typeSQLScanner = reflect.TypeOf((*sql.Scanner)(nil)).Elem()
17
18// Array returns the optimal driver.Valuer and sql.Scanner for an array or
19// slice of any dimension.
20//
21// For example:
22// db.Query(`SELECT * FROM t WHERE id = ANY($1)`, pq.Array([]int{235, 401}))
23//
24// var x []sql.NullInt64
25// db.QueryRow(`SELECT ARRAY[235, 401]`).Scan(pq.Array(&x))
26//
27// Scanning multi-dimensional arrays is not supported. Arrays where the lower
28// bound is not one (such as `[0:0]={1}') are not supported.
29func 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// ArrayDelimiter may be optionally implemented by driver.Valuer or sql.Scanner
69// to override the array delimiter used by GenericArray.
70type ArrayDelimiter interface {
71 // ArrayDelimiter returns the delimiter character(s) for this element's type.
72 ArrayDelimiter() string
73}
74
75// BoolArray represents a one-dimensional array of the PostgreSQL boolean type.
76type BoolArray []bool
77
78// Scan implements the sql.Scanner interface.
79func (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
93func (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// Value implements the driver.Valuer interface.
121func (a BoolArray) Value() (driver.Value, error) {
122 if a == nil {
123 return nil, nil
124 }
125
126 if n := len(a); n > 0 {
127 // There will be exactly two curly brackets, N bytes of values,
128 // and N-1 bytes of delimiters.
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// ByteaArray represents a one-dimensional array of the PostgreSQL bytea type.
150type ByteaArray [][]byte
151
152// Scan implements the sql.Scanner interface.
153func (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
167func (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// Value implements the driver.Valuer interface. It uses the "hex" format which
188// is only supported on PostgreSQL 9.0 or newer.
189func (a ByteaArray) Value() (driver.Value, error) {
190 if a == nil {
191 return nil, nil
192 }
193
194 if n := len(a); n > 0 {
195 // There will be at least two curly brackets, 2*N bytes of quotes,
196 // 3*N bytes of hex formatting, and N-1 bytes of delimiters.
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// Float64Array represents a one-dimensional array of the PostgreSQL double
221// precision type.
222type Float64Array []float64
223
224// Scan implements the sql.Scanner interface.
225func (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
239func (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// Value implements the driver.Valuer interface.
259func (a Float64Array) Value() (driver.Value, error) {
260 if a == nil {
261 return nil, nil
262 }
263
264 if n := len(a); n > 0 {
265 // There will be at least two curly brackets, N bytes of values,
266 // and N-1 bytes of delimiters.
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// Float32Array represents a one-dimensional array of the PostgreSQL double
283// precision type.
284type Float32Array []float32
285
286// Scan implements the sql.Scanner interface.
287func (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
301func (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// Value implements the driver.Valuer interface.
323func (a Float32Array) Value() (driver.Value, error) {
324 if a == nil {
325 return nil, nil
326 }
327
328 if n := len(a); n > 0 {
329 // There will be at least two curly brackets, N bytes of values,
330 // and N-1 bytes of delimiters.
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// GenericArray implements the driver.Valuer and sql.Scanner interfaces for
347// an array or slice of any dimension.
348type GenericArray struct{ A interface{} }
349
350func (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 // TODO calculate the assign function for other types
355 // TODO repeat this section on the element type of arrays or slices (multidimensional)
356 {
357 if reflect.PtrTo(rt).Implements(typeSQLScanner) {
358 // dest is always addressable because it is an element of a slice.
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
376FoundType:
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// Scan implements the sql.Scanner interface.
386func (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
418func (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 // TODO allow multidimensional
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 // Treat a zero-dimensional array like an array with a single dimension of zero.
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 // TODO handle multidimensional
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 // TODO handle multidimensional
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// Value implements the driver.Valuer interface.
472func (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 // There will be at least two curly brackets, N bytes of values,
491 // and N-1 bytes of delimiters.
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// Int64Array represents a one-dimensional array of the PostgreSQL integer types.
502type Int64Array []int64
503
504// Scan implements the sql.Scanner interface.
505func (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
519func (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// Value implements the driver.Valuer interface.
539func (a Int64Array) Value() (driver.Value, error) {
540 if a == nil {
541 return nil, nil
542 }
543
544 if n := len(a); n > 0 {
545 // There will be at least two curly brackets, N bytes of values,
546 // and N-1 bytes of delimiters.
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// Int32Array represents a one-dimensional array of the PostgreSQL integer types.
563type Int32Array []int32
564
565// Scan implements the sql.Scanner interface.
566func (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
580func (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// Value implements the driver.Valuer interface.
602func (a Int32Array) Value() (driver.Value, error) {
603 if a == nil {
604 return nil, nil
605 }
606
607 if n := len(a); n > 0 {
608 // There will be at least two curly brackets, N bytes of values,
609 // and N-1 bytes of delimiters.
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// StringArray represents a one-dimensional array of the PostgreSQL character types.
626type StringArray []string
627
628// Scan implements the sql.Scanner interface.
629func (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
643func (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// Value implements the driver.Valuer interface.
663func (a StringArray) Value() (driver.Value, error) {
664 if a == nil {
665 return nil, nil
666 }
667
668 if n := len(a); n > 0 {
669 // There will be at least two curly brackets, 2*N bytes of quotes,
670 // and N-1 bytes of delimiters.
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// appendArray appends rv to the buffer, returning the extended buffer and
687// the delimiter used between elements.
688//
689// It panics when n <= 0 or rv's Kind is not reflect.Array nor reflect.Slice.
690func 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// appendArrayElement appends rv to the buffer, returning the extended buffer
711// and the delimiter to use before the next element.
712//
713// When rv's Kind is neither reflect.Array nor reflect.Slice, it is converted
714// using driver.DefaultParameterConverter and the resulting []byte or string
715// is double-quoted.
716//
717// See http://www.postgresql.org/docs/current/static/arrays.html#ARRAYS-IO
718func 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
754func 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
771func appendValue(b []byte, v driver.Value) ([]byte, error) {
772 return append(b, encode(nil, v, 0)...), nil
773}
774
775// parseArray extracts the dimensions and elements of an array represented in
776// text format. Only representations emitted by the backend are supported.
777// Notably, whitespace around brackets and delimiters is significant, and NULL
778// is case-sensitive.
779//
780// See http://www.postgresql.org/docs/current/static/arrays.html#ARRAYS-IO
781func 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
788Open:
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
803Element:
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
864Close:
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
886func 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}
Note: See TracBrowser for help on using the repository browser.