1
2
3 package pgtype
4
5 import (
6 "database/sql/driver"
7 "encoding/binary"
8 "fmt"
9 "reflect"
10
11 "github.com/jackc/pgio"
12 )
13
14 type NumericArray struct {
15 Elements []Numeric
16 Dimensions []ArrayDimension
17 Status Status
18 }
19
20 func (dst *NumericArray) Set(src interface{}) error {
21
22 if src == nil {
23 *dst = NumericArray{Status: Null}
24 return nil
25 }
26
27 if value, ok := src.(interface{ Get() interface{} }); ok {
28 value2 := value.Get()
29 if value2 != value {
30 return dst.Set(value2)
31 }
32 }
33
34
35 switch value := src.(type) {
36
37 case []float32:
38 if value == nil {
39 *dst = NumericArray{Status: Null}
40 } else if len(value) == 0 {
41 *dst = NumericArray{Status: Present}
42 } else {
43 elements := make([]Numeric, len(value))
44 for i := range value {
45 if err := elements[i].Set(value[i]); err != nil {
46 return err
47 }
48 }
49 *dst = NumericArray{
50 Elements: elements,
51 Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
52 Status: Present,
53 }
54 }
55
56 case []*float32:
57 if value == nil {
58 *dst = NumericArray{Status: Null}
59 } else if len(value) == 0 {
60 *dst = NumericArray{Status: Present}
61 } else {
62 elements := make([]Numeric, len(value))
63 for i := range value {
64 if err := elements[i].Set(value[i]); err != nil {
65 return err
66 }
67 }
68 *dst = NumericArray{
69 Elements: elements,
70 Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
71 Status: Present,
72 }
73 }
74
75 case []float64:
76 if value == nil {
77 *dst = NumericArray{Status: Null}
78 } else if len(value) == 0 {
79 *dst = NumericArray{Status: Present}
80 } else {
81 elements := make([]Numeric, len(value))
82 for i := range value {
83 if err := elements[i].Set(value[i]); err != nil {
84 return err
85 }
86 }
87 *dst = NumericArray{
88 Elements: elements,
89 Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
90 Status: Present,
91 }
92 }
93
94 case []*float64:
95 if value == nil {
96 *dst = NumericArray{Status: Null}
97 } else if len(value) == 0 {
98 *dst = NumericArray{Status: Present}
99 } else {
100 elements := make([]Numeric, len(value))
101 for i := range value {
102 if err := elements[i].Set(value[i]); err != nil {
103 return err
104 }
105 }
106 *dst = NumericArray{
107 Elements: elements,
108 Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
109 Status: Present,
110 }
111 }
112
113 case []int64:
114 if value == nil {
115 *dst = NumericArray{Status: Null}
116 } else if len(value) == 0 {
117 *dst = NumericArray{Status: Present}
118 } else {
119 elements := make([]Numeric, len(value))
120 for i := range value {
121 if err := elements[i].Set(value[i]); err != nil {
122 return err
123 }
124 }
125 *dst = NumericArray{
126 Elements: elements,
127 Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
128 Status: Present,
129 }
130 }
131
132 case []*int64:
133 if value == nil {
134 *dst = NumericArray{Status: Null}
135 } else if len(value) == 0 {
136 *dst = NumericArray{Status: Present}
137 } else {
138 elements := make([]Numeric, len(value))
139 for i := range value {
140 if err := elements[i].Set(value[i]); err != nil {
141 return err
142 }
143 }
144 *dst = NumericArray{
145 Elements: elements,
146 Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
147 Status: Present,
148 }
149 }
150
151 case []uint64:
152 if value == nil {
153 *dst = NumericArray{Status: Null}
154 } else if len(value) == 0 {
155 *dst = NumericArray{Status: Present}
156 } else {
157 elements := make([]Numeric, len(value))
158 for i := range value {
159 if err := elements[i].Set(value[i]); err != nil {
160 return err
161 }
162 }
163 *dst = NumericArray{
164 Elements: elements,
165 Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
166 Status: Present,
167 }
168 }
169
170 case []*uint64:
171 if value == nil {
172 *dst = NumericArray{Status: Null}
173 } else if len(value) == 0 {
174 *dst = NumericArray{Status: Present}
175 } else {
176 elements := make([]Numeric, len(value))
177 for i := range value {
178 if err := elements[i].Set(value[i]); err != nil {
179 return err
180 }
181 }
182 *dst = NumericArray{
183 Elements: elements,
184 Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
185 Status: Present,
186 }
187 }
188
189 case []Numeric:
190 if value == nil {
191 *dst = NumericArray{Status: Null}
192 } else if len(value) == 0 {
193 *dst = NumericArray{Status: Present}
194 } else {
195 *dst = NumericArray{
196 Elements: value,
197 Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
198 Status: Present,
199 }
200 }
201 default:
202
203
204
205 reflectedValue := reflect.ValueOf(src)
206 if !reflectedValue.IsValid() || reflectedValue.IsZero() {
207 *dst = NumericArray{Status: Null}
208 return nil
209 }
210
211 dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
212 if !ok {
213 return fmt.Errorf("cannot find dimensions of %v for NumericArray", src)
214 }
215 if elementsLength == 0 {
216 *dst = NumericArray{Status: Present}
217 return nil
218 }
219 if len(dimensions) == 0 {
220 if originalSrc, ok := underlyingSliceType(src); ok {
221 return dst.Set(originalSrc)
222 }
223 return fmt.Errorf("cannot convert %v to NumericArray", src)
224 }
225
226 *dst = NumericArray{
227 Elements: make([]Numeric, elementsLength),
228 Dimensions: dimensions,
229 Status: Present,
230 }
231 elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
232 if err != nil {
233
234 if len(dst.Dimensions) > 1 {
235 dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
236 elementsLength = 0
237 for _, dim := range dst.Dimensions {
238 if elementsLength == 0 {
239 elementsLength = int(dim.Length)
240 } else {
241 elementsLength *= int(dim.Length)
242 }
243 }
244 dst.Elements = make([]Numeric, elementsLength)
245 elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
246 if err != nil {
247 return err
248 }
249 } else {
250 return err
251 }
252 }
253 if elementCount != len(dst.Elements) {
254 return fmt.Errorf("cannot convert %v to NumericArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
255 }
256 }
257
258 return nil
259 }
260
261 func (dst *NumericArray) setRecursive(value reflect.Value, index, dimension int) (int, error) {
262 switch value.Kind() {
263 case reflect.Array:
264 fallthrough
265 case reflect.Slice:
266 if len(dst.Dimensions) == dimension {
267 break
268 }
269
270 valueLen := value.Len()
271 if int32(valueLen) != dst.Dimensions[dimension].Length {
272 return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
273 }
274 for i := 0; i < valueLen; i++ {
275 var err error
276 index, err = dst.setRecursive(value.Index(i), index, dimension+1)
277 if err != nil {
278 return 0, err
279 }
280 }
281
282 return index, nil
283 }
284 if !value.CanInterface() {
285 return 0, fmt.Errorf("cannot convert all values to NumericArray")
286 }
287 if err := dst.Elements[index].Set(value.Interface()); err != nil {
288 return 0, fmt.Errorf("%v in NumericArray", err)
289 }
290 index++
291
292 return index, nil
293 }
294
295 func (dst NumericArray) Get() interface{} {
296 switch dst.Status {
297 case Present:
298 return dst
299 case Null:
300 return nil
301 default:
302 return dst.Status
303 }
304 }
305
306 func (src *NumericArray) AssignTo(dst interface{}) error {
307 switch src.Status {
308 case Present:
309 if len(src.Dimensions) <= 1 {
310
311 switch v := dst.(type) {
312
313 case *[]float32:
314 *v = make([]float32, len(src.Elements))
315 for i := range src.Elements {
316 if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
317 return err
318 }
319 }
320 return nil
321
322 case *[]*float32:
323 *v = make([]*float32, len(src.Elements))
324 for i := range src.Elements {
325 if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
326 return err
327 }
328 }
329 return nil
330
331 case *[]float64:
332 *v = make([]float64, len(src.Elements))
333 for i := range src.Elements {
334 if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
335 return err
336 }
337 }
338 return nil
339
340 case *[]*float64:
341 *v = make([]*float64, len(src.Elements))
342 for i := range src.Elements {
343 if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
344 return err
345 }
346 }
347 return nil
348
349 case *[]int64:
350 *v = make([]int64, len(src.Elements))
351 for i := range src.Elements {
352 if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
353 return err
354 }
355 }
356 return nil
357
358 case *[]*int64:
359 *v = make([]*int64, len(src.Elements))
360 for i := range src.Elements {
361 if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
362 return err
363 }
364 }
365 return nil
366
367 case *[]uint64:
368 *v = make([]uint64, len(src.Elements))
369 for i := range src.Elements {
370 if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
371 return err
372 }
373 }
374 return nil
375
376 case *[]*uint64:
377 *v = make([]*uint64, len(src.Elements))
378 for i := range src.Elements {
379 if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
380 return err
381 }
382 }
383 return nil
384
385 }
386 }
387
388
389 if nextDst, retry := GetAssignToDstType(dst); retry {
390 return src.AssignTo(nextDst)
391 }
392
393
394
395
396 value := reflect.ValueOf(dst)
397 if value.Kind() == reflect.Ptr {
398 value = value.Elem()
399 }
400
401 switch value.Kind() {
402 case reflect.Array, reflect.Slice:
403 default:
404 return fmt.Errorf("cannot assign %T to %T", src, dst)
405 }
406
407 if len(src.Elements) == 0 {
408 if value.Kind() == reflect.Slice {
409 value.Set(reflect.MakeSlice(value.Type(), 0, 0))
410 return nil
411 }
412 }
413
414 elementCount, err := src.assignToRecursive(value, 0, 0)
415 if err != nil {
416 return err
417 }
418 if elementCount != len(src.Elements) {
419 return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
420 }
421
422 return nil
423 case Null:
424 return NullAssignTo(dst)
425 }
426
427 return fmt.Errorf("cannot decode %#v into %T", src, dst)
428 }
429
430 func (src *NumericArray) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
431 switch kind := value.Kind(); kind {
432 case reflect.Array:
433 fallthrough
434 case reflect.Slice:
435 if len(src.Dimensions) == dimension {
436 break
437 }
438
439 length := int(src.Dimensions[dimension].Length)
440 if reflect.Array == kind {
441 typ := value.Type()
442 if typ.Len() != length {
443 return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
444 }
445 value.Set(reflect.New(typ).Elem())
446 } else {
447 value.Set(reflect.MakeSlice(value.Type(), length, length))
448 }
449
450 var err error
451 for i := 0; i < length; i++ {
452 index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
453 if err != nil {
454 return 0, err
455 }
456 }
457
458 return index, nil
459 }
460 if len(src.Dimensions) != dimension {
461 return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
462 }
463 if !value.CanAddr() {
464 return 0, fmt.Errorf("cannot assign all values from NumericArray")
465 }
466 addr := value.Addr()
467 if !addr.CanInterface() {
468 return 0, fmt.Errorf("cannot assign all values from NumericArray")
469 }
470 if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
471 return 0, err
472 }
473 index++
474 return index, nil
475 }
476
477 func (dst *NumericArray) DecodeText(ci *ConnInfo, src []byte) error {
478 if src == nil {
479 *dst = NumericArray{Status: Null}
480 return nil
481 }
482
483 uta, err := ParseUntypedTextArray(string(src))
484 if err != nil {
485 return err
486 }
487
488 var elements []Numeric
489
490 if len(uta.Elements) > 0 {
491 elements = make([]Numeric, len(uta.Elements))
492
493 for i, s := range uta.Elements {
494 var elem Numeric
495 var elemSrc []byte
496 if s != "NULL" || uta.Quoted[i] {
497 elemSrc = []byte(s)
498 }
499 err = elem.DecodeText(ci, elemSrc)
500 if err != nil {
501 return err
502 }
503
504 elements[i] = elem
505 }
506 }
507
508 *dst = NumericArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
509
510 return nil
511 }
512
513 func (dst *NumericArray) DecodeBinary(ci *ConnInfo, src []byte) error {
514 if src == nil {
515 *dst = NumericArray{Status: Null}
516 return nil
517 }
518
519 var arrayHeader ArrayHeader
520 rp, err := arrayHeader.DecodeBinary(ci, src)
521 if err != nil {
522 return err
523 }
524
525 if len(arrayHeader.Dimensions) == 0 {
526 *dst = NumericArray{Dimensions: arrayHeader.Dimensions, Status: Present}
527 return nil
528 }
529
530 elementCount := arrayHeader.Dimensions[0].Length
531 for _, d := range arrayHeader.Dimensions[1:] {
532 elementCount *= d.Length
533 }
534
535 elements := make([]Numeric, elementCount)
536
537 for i := range elements {
538 elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
539 rp += 4
540 var elemSrc []byte
541 if elemLen >= 0 {
542 elemSrc = src[rp : rp+elemLen]
543 rp += elemLen
544 }
545 err = elements[i].DecodeBinary(ci, elemSrc)
546 if err != nil {
547 return err
548 }
549 }
550
551 *dst = NumericArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
552 return nil
553 }
554
555 func (src NumericArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
556 switch src.Status {
557 case Null:
558 return nil, nil
559 case Undefined:
560 return nil, errUndefined
561 }
562
563 if len(src.Dimensions) == 0 {
564 return append(buf, '{', '}'), nil
565 }
566
567 buf = EncodeTextArrayDimensions(buf, src.Dimensions)
568
569
570
571
572
573
574 dimElemCounts := make([]int, len(src.Dimensions))
575 dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
576 for i := len(src.Dimensions) - 2; i > -1; i-- {
577 dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
578 }
579
580 inElemBuf := make([]byte, 0, 32)
581 for i, elem := range src.Elements {
582 if i > 0 {
583 buf = append(buf, ',')
584 }
585
586 for _, dec := range dimElemCounts {
587 if i%dec == 0 {
588 buf = append(buf, '{')
589 }
590 }
591
592 elemBuf, err := elem.EncodeText(ci, inElemBuf)
593 if err != nil {
594 return nil, err
595 }
596 if elemBuf == nil {
597 buf = append(buf, `NULL`...)
598 } else {
599 buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
600 }
601
602 for _, dec := range dimElemCounts {
603 if (i+1)%dec == 0 {
604 buf = append(buf, '}')
605 }
606 }
607 }
608
609 return buf, nil
610 }
611
612 func (src NumericArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
613 switch src.Status {
614 case Null:
615 return nil, nil
616 case Undefined:
617 return nil, errUndefined
618 }
619
620 arrayHeader := ArrayHeader{
621 Dimensions: src.Dimensions,
622 }
623
624 if dt, ok := ci.DataTypeForName("numeric"); ok {
625 arrayHeader.ElementOID = int32(dt.OID)
626 } else {
627 return nil, fmt.Errorf("unable to find oid for type name %v", "numeric")
628 }
629
630 for i := range src.Elements {
631 if src.Elements[i].Status == Null {
632 arrayHeader.ContainsNull = true
633 break
634 }
635 }
636
637 buf = arrayHeader.EncodeBinary(ci, buf)
638
639 for i := range src.Elements {
640 sp := len(buf)
641 buf = pgio.AppendInt32(buf, -1)
642
643 elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
644 if err != nil {
645 return nil, err
646 }
647 if elemBuf != nil {
648 buf = elemBuf
649 pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
650 }
651 }
652
653 return buf, nil
654 }
655
656
657 func (dst *NumericArray) Scan(src interface{}) error {
658 if src == nil {
659 return dst.DecodeText(nil, nil)
660 }
661
662 switch src := src.(type) {
663 case string:
664 return dst.DecodeText(nil, []byte(src))
665 case []byte:
666 srcCopy := make([]byte, len(src))
667 copy(srcCopy, src)
668 return dst.DecodeText(nil, srcCopy)
669 }
670
671 return fmt.Errorf("cannot scan %T", src)
672 }
673
674
675 func (src NumericArray) Value() (driver.Value, error) {
676 buf, err := src.EncodeText(nil, nil)
677 if err != nil {
678 return nil, err
679 }
680 if buf == nil {
681 return nil, nil
682 }
683
684 return string(buf), nil
685 }
686
View as plain text