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