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