1// Code generated by erb. DO NOT EDIT.
2
3<%
4 # defaults when not explicitly set on command line
5
6 binary_format ||= "true"
7 text_format ||= "true"
8
9 text_null ||= "NULL"
10
11 encode_binary ||= binary_format
12 decode_binary ||= binary_format
13%>
14
15package pgtype
16
17import (
18 "bytes"
19 "fmt"
20 "io"
21
22 "github.com/jackc/pgio"
23)
24
25type <%= pgtype_array_type %> struct {
26 Elements []<%= pgtype_element_type %>
27 Dimensions []ArrayDimension
28 Status Status
29}
30
31func (dst *<%= pgtype_array_type %>) Set(src interface{}) error {
32 // untyped nil and typed nil interfaces are different
33 if src == nil {
34 *dst = <%= pgtype_array_type %>{Status: Null}
35 return nil
36 }
37
38 if value, ok := src.(interface{ Get() interface{} }); ok {
39 value2 := value.Get()
40 if value2 != value {
41 return dst.Set(value2)
42 }
43 }
44
45 // Attempt to match to select common types:
46 switch value := src.(type) {
47 <% go_array_types.split(",").each do |t| %>
48 <% if t != "[]#{pgtype_element_type}" %>
49 case <%= t %>:
50 if value == nil {
51 *dst = <%= pgtype_array_type %>{Status: Null}
52 } else if len(value) == 0 {
53 *dst = <%= pgtype_array_type %>{Status: Present}
54 } else {
55 elements := make([]<%= pgtype_element_type %>, len(value))
56 for i := range value {
57 if err := elements[i].Set(value[i]); err != nil {
58 return err
59 }
60 }
61 *dst = <%= pgtype_array_type %>{
62 Elements: elements,
63 Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
64 Status: Present,
65 }
66 }
67 <% end %>
68 <% end %>
69 case []<%= pgtype_element_type %>:
70 if value == nil {
71 *dst = <%= pgtype_array_type %>{Status: Null}
72 } else if len(value) == 0 {
73 *dst = <%= pgtype_array_type %>{Status: Present}
74 } else {
75 *dst = <%= pgtype_array_type %>{
76 Elements: value,
77 Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
78 Status : Present,
79 }
80 }
81 default:
82 // Fallback to reflection if an optimised match was not found.
83 // The reflection is necessary for arrays and multidimensional slices,
84 // but it comes with a 20-50% performance penalty for large arrays/slices
85 reflectedValue := reflect.ValueOf(src)
86 if !reflectedValue.IsValid() || reflectedValue.IsZero() {
87 *dst = <%= pgtype_array_type %>{Status: Null}
88 return nil
89 }
90
91 dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
92 if !ok {
93 return fmt.Errorf("cannot find dimensions of %v for <%= pgtype_array_type %>", src)
94 }
95 if elementsLength == 0 {
96 *dst = <%= pgtype_array_type %>{Status: Present}
97 return nil
98 }
99 if len(dimensions) == 0 {
100 if originalSrc, ok := underlyingSliceType(src); ok {
101 return dst.Set(originalSrc)
102 }
103 return fmt.Errorf("cannot convert %v to <%= pgtype_array_type %>", src)
104 }
105
106 *dst = <%= pgtype_array_type %> {
107 Elements: make([]<%= pgtype_element_type %>, elementsLength),
108 Dimensions: dimensions,
109 Status: Present,
110 }
111 elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
112 if err != nil {
113 // Maybe the target was one dimension too far, try again:
114 if len(dst.Dimensions) > 1 {
115 dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
116 elementsLength = 0
117 for _, dim := range dst.Dimensions {
118 if elementsLength == 0 {
119 elementsLength = int(dim.Length)
120 } else {
121 elementsLength *= int(dim.Length)
122 }
123 }
124 dst.Elements = make([]<%= pgtype_element_type %>, elementsLength)
125 elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
126 if err != nil {
127 return err
128 }
129 } else {
130 return err
131 }
132 }
133 if elementCount != len(dst.Elements) {
134 return fmt.Errorf("cannot convert %v to <%= pgtype_array_type %>, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
135 }
136 }
137
138 return nil
139}
140
141func (dst *<%= pgtype_array_type %>) setRecursive(value reflect.Value, index, dimension int) (int, error) {
142 switch value.Kind() {
143 case reflect.Array:
144 fallthrough
145 case reflect.Slice:
146 if len(dst.Dimensions) == dimension {
147 break
148 }
149
150 valueLen := value.Len()
151 if int32(valueLen) != dst.Dimensions[dimension].Length {
152 return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
153 }
154 for i := 0; i < valueLen; i++ {
155 var err error
156 index, err = dst.setRecursive(value.Index(i), index, dimension+1)
157 if err != nil {
158 return 0, err
159 }
160 }
161
162 return index, nil
163 }
164 if !value.CanInterface() {
165 return 0, fmt.Errorf("cannot convert all values to <%= pgtype_array_type %>")
166 }
167 if err := dst.Elements[index].Set(value.Interface()); err != nil {
168 return 0, fmt.Errorf("%v in <%= pgtype_array_type %>", err)
169 }
170 index++
171
172 return index, nil
173}
174
175func (dst <%= pgtype_array_type %>) Get() interface{} {
176 switch dst.Status {
177 case Present:
178 return dst
179 case Null:
180 return nil
181 default:
182 return dst.Status
183 }
184}
185
186func (src *<%= pgtype_array_type %>) AssignTo(dst interface{}) error {
187 switch src.Status {
188 case Present:
189 if len(src.Dimensions) <= 1{
190 // Attempt to match to select common types:
191 switch v := dst.(type) {
192 <% go_array_types.split(",").each do |t| %>
193 case *<%= t %>:
194 *v = make(<%= t %>, len(src.Elements))
195 for i := range src.Elements {
196 if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
197 return err
198 }
199 }
200 return nil
201 <% end %>
202 }
203 }
204
205 // Try to convert to something AssignTo can use directly.
206 if nextDst, retry := GetAssignToDstType(dst); retry {
207 return src.AssignTo(nextDst)
208 }
209
210 // Fallback to reflection if an optimised match was not found.
211 // The reflection is necessary for arrays and multidimensional slices,
212 // but it comes with a 20-50% performance penalty for large arrays/slices
213 value := reflect.ValueOf(dst)
214 if value.Kind() == reflect.Ptr {
215 value = value.Elem()
216 }
217
218 switch value.Kind() {
219 case reflect.Array, reflect.Slice:
220 default:
221 return fmt.Errorf("cannot assign %T to %T", src, dst)
222 }
223
224 if len(src.Elements) == 0 {
225 if value.Kind() == reflect.Slice {
226 value.Set(reflect.MakeSlice(value.Type(), 0, 0))
227 return nil
228 }
229 }
230
231 elementCount, err := src.assignToRecursive(value, 0, 0)
232 if err != nil {
233 return err
234 }
235 if elementCount != len(src.Elements) {
236 return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
237 }
238
239 return nil
240 case Null:
241 return NullAssignTo(dst)
242 }
243
244 return fmt.Errorf("cannot decode %#v into %T", src, dst)
245}
246
247func (src *<%= pgtype_array_type %>) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
248 switch kind := value.Kind(); kind {
249 case reflect.Array:
250 fallthrough
251 case reflect.Slice:
252 if len(src.Dimensions) == dimension {
253 break
254 }
255
256 length := int(src.Dimensions[dimension].Length)
257 if reflect.Array == kind {
258 typ := value.Type()
259 if typ.Len() != length {
260 return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
261 }
262 value.Set(reflect.New(typ).Elem())
263 } else {
264 value.Set(reflect.MakeSlice(value.Type(), length, length))
265 }
266
267 var err error
268 for i := 0; i < length; i++ {
269 index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
270 if err != nil {
271 return 0, err
272 }
273 }
274
275 return index, nil
276 }
277 if len(src.Dimensions) != dimension {
278 return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
279 }
280 if !value.CanAddr(){
281 return 0, fmt.Errorf("cannot assign all values from <%= pgtype_array_type %>")
282 }
283 addr := value.Addr()
284 if !addr.CanInterface() {
285 return 0, fmt.Errorf("cannot assign all values from <%= pgtype_array_type %>")
286 }
287 if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
288 return 0, err
289 }
290 index++
291 return index, nil
292}
293
294<% if text_format == "true" %>
295func (dst *<%= pgtype_array_type %>) DecodeText(ci *ConnInfo, src []byte) error {
296 if src == nil {
297 *dst = <%= pgtype_array_type %>{Status: Null}
298 return nil
299 }
300
301 uta, err := ParseUntypedTextArray(string(src))
302 if err != nil {
303 return err
304 }
305
306 var elements []<%= pgtype_element_type %>
307
308 if len(uta.Elements) > 0 {
309 elements = make([]<%= pgtype_element_type %>, len(uta.Elements))
310
311 for i, s := range uta.Elements {
312 var elem <%= pgtype_element_type %>
313 var elemSrc []byte
314 if s != "NULL" || uta.Quoted[i] {
315 elemSrc = []byte(s)
316 }
317 err = elem.DecodeText(ci, elemSrc)
318 if err != nil {
319 return err
320 }
321
322 elements[i] = elem
323 }
324 }
325
326 *dst = <%= pgtype_array_type %>{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
327
328 return nil
329}
330<% end %>
331
332<% if decode_binary == "true" %>
333func (dst *<%= pgtype_array_type %>) DecodeBinary(ci *ConnInfo, src []byte) error {
334 if src == nil {
335 *dst = <%= pgtype_array_type %>{Status: Null}
336 return nil
337 }
338
339 var arrayHeader ArrayHeader
340 rp, err := arrayHeader.DecodeBinary(ci, src)
341 if err != nil {
342 return err
343 }
344
345 if len(arrayHeader.Dimensions) == 0 {
346 *dst = <%= pgtype_array_type %>{Dimensions: arrayHeader.Dimensions, Status: Present}
347 return nil
348 }
349
350 elementCount := arrayHeader.Dimensions[0].Length
351 for _, d := range arrayHeader.Dimensions[1:] {
352 elementCount *= d.Length
353 }
354
355 elements := make([]<%= pgtype_element_type %>, elementCount)
356
357 for i := range elements {
358 elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
359 rp += 4
360 var elemSrc []byte
361 if elemLen >= 0 {
362 elemSrc = src[rp:rp+elemLen]
363 rp += elemLen
364 }
365 err = elements[i].DecodeBinary(ci, elemSrc)
366 if err != nil {
367 return err
368 }
369 }
370
371 *dst = <%= pgtype_array_type %>{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
372 return nil
373}
374<% end %>
375
376<% if text_format == "true" %>
377func (src <%= pgtype_array_type %>) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
378 switch src.Status {
379 case Null:
380 return nil, nil
381 case Undefined:
382 return nil, errUndefined
383 }
384
385 if len(src.Dimensions) == 0 {
386 return append(buf, '{', '}'), nil
387 }
388
389 buf = EncodeTextArrayDimensions(buf, src.Dimensions)
390
391 // dimElemCounts is the multiples of elements that each array lies on. For
392 // example, a single dimension array of length 4 would have a dimElemCounts of
393 // [4]. A multi-dimensional array of lengths [3,5,2] would have a
394 // dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
395 // or '}'.
396 dimElemCounts := make([]int, len(src.Dimensions))
397 dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
398 for i := len(src.Dimensions) - 2; i > -1; i-- {
399 dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
400 }
401
402 inElemBuf := make([]byte, 0, 32)
403 for i, elem := range src.Elements {
404 if i > 0 {
405 buf = append(buf, ',')
406 }
407
408 for _, dec := range dimElemCounts {
409 if i%dec == 0 {
410 buf = append(buf, '{')
411 }
412 }
413
414 elemBuf, err := elem.EncodeText(ci, inElemBuf)
415 if err != nil {
416 return nil, err
417 }
418 if elemBuf == nil {
419 buf = append(buf, `<%= text_null %>`...)
420 } else {
421 buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
422 }
423
424 for _, dec := range dimElemCounts {
425 if (i+1)%dec == 0 {
426 buf = append(buf, '}')
427 }
428 }
429 }
430
431 return buf, nil
432}
433<% end %>
434
435<% if encode_binary == "true" %>
436 func (src <%= pgtype_array_type %>) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
437 switch src.Status {
438 case Null:
439 return nil, nil
440 case Undefined:
441 return nil, errUndefined
442 }
443
444 arrayHeader := ArrayHeader{
445 Dimensions: src.Dimensions,
446 }
447
448 if dt, ok := ci.DataTypeForName("<%= element_type_name %>"); ok {
449 arrayHeader.ElementOID = int32(dt.OID)
450 } else {
451 return nil, fmt.Errorf("unable to find oid for type name %v", "<%= element_type_name %>")
452 }
453
454 for i := range src.Elements {
455 if src.Elements[i].Status == Null {
456 arrayHeader.ContainsNull = true
457 break
458 }
459 }
460
461 buf = arrayHeader.EncodeBinary(ci, buf)
462
463 for i := range src.Elements {
464 sp := len(buf)
465 buf = pgio.AppendInt32(buf, -1)
466
467 elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
468 if err != nil {
469 return nil, err
470 }
471 if elemBuf != nil {
472 buf = elemBuf
473 pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
474 }
475 }
476
477 return buf, nil
478 }
479<% end %>
480
481<% if text_format == "true" %>
482// Scan implements the database/sql Scanner interface.
483func (dst *<%= pgtype_array_type %>) Scan(src interface{}) error {
484 if src == nil {
485 return dst.DecodeText(nil, nil)
486 }
487
488 switch src := src.(type) {
489 case string:
490 return dst.DecodeText(nil, []byte(src))
491 case []byte:
492 srcCopy := make([]byte, len(src))
493 copy(srcCopy, src)
494 return dst.DecodeText(nil, srcCopy)
495 }
496
497 return fmt.Errorf("cannot scan %T", src)
498}
499
500// Value implements the database/sql/driver Valuer interface.
501func (src <%= pgtype_array_type %>) Value() (driver.Value, error) {
502 buf, err := src.EncodeText(nil, nil)
503 if err != nil {
504 return nil, err
505 }
506 if buf == nil {
507 return nil, nil
508 }
509
510 return string(buf), nil
511}
512<% end %>
View as plain text