...

Source file src/github.com/jackc/pgtype/timestamptz_array.go

Documentation: github.com/jackc/pgtype

     1  // Code generated by erb. DO NOT EDIT.
     2  
     3  package pgtype
     4  
     5  import (
     6  	"database/sql/driver"
     7  	"encoding/binary"
     8  	"fmt"
     9  	"reflect"
    10  	"time"
    11  
    12  	"github.com/jackc/pgio"
    13  )
    14  
    15  type TimestamptzArray struct {
    16  	Elements   []Timestamptz
    17  	Dimensions []ArrayDimension
    18  	Status     Status
    19  }
    20  
    21  func (dst *TimestamptzArray) Set(src interface{}) error {
    22  	// untyped nil and typed nil interfaces are different
    23  	if src == nil {
    24  		*dst = TimestamptzArray{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 = TimestamptzArray{Status: Null}
    41  		} else if len(value) == 0 {
    42  			*dst = TimestamptzArray{Status: Present}
    43  		} else {
    44  			elements := make([]Timestamptz, len(value))
    45  			for i := range value {
    46  				if err := elements[i].Set(value[i]); err != nil {
    47  					return err
    48  				}
    49  			}
    50  			*dst = TimestamptzArray{
    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 = TimestamptzArray{Status: Null}
    60  		} else if len(value) == 0 {
    61  			*dst = TimestamptzArray{Status: Present}
    62  		} else {
    63  			elements := make([]Timestamptz, len(value))
    64  			for i := range value {
    65  				if err := elements[i].Set(value[i]); err != nil {
    66  					return err
    67  				}
    68  			}
    69  			*dst = TimestamptzArray{
    70  				Elements:   elements,
    71  				Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
    72  				Status:     Present,
    73  			}
    74  		}
    75  
    76  	case []Timestamptz:
    77  		if value == nil {
    78  			*dst = TimestamptzArray{Status: Null}
    79  		} else if len(value) == 0 {
    80  			*dst = TimestamptzArray{Status: Present}
    81  		} else {
    82  			*dst = TimestamptzArray{
    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 = TimestamptzArray{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 TimestamptzArray", src)
   101  		}
   102  		if elementsLength == 0 {
   103  			*dst = TimestamptzArray{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 TimestamptzArray", src)
   111  		}
   112  
   113  		*dst = TimestamptzArray{
   114  			Elements:   make([]Timestamptz, 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([]Timestamptz, 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 TimestamptzArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
   142  		}
   143  	}
   144  
   145  	return nil
   146  }
   147  
   148  func (dst *TimestamptzArray) 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 TimestamptzArray")
   173  	}
   174  	if err := dst.Elements[index].Set(value.Interface()); err != nil {
   175  		return 0, fmt.Errorf("%v in TimestamptzArray", err)
   176  	}
   177  	index++
   178  
   179  	return index, nil
   180  }
   181  
   182  func (dst TimestamptzArray) 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  
   193  func (src *TimestamptzArray) 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  
   263  func (src *TimestamptzArray) 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 TimestamptzArray")
   298  	}
   299  	addr := value.Addr()
   300  	if !addr.CanInterface() {
   301  		return 0, fmt.Errorf("cannot assign all values from TimestamptzArray")
   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  
   310  func (dst *TimestamptzArray) DecodeText(ci *ConnInfo, src []byte) error {
   311  	if src == nil {
   312  		*dst = TimestamptzArray{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 []Timestamptz
   322  
   323  	if len(uta.Elements) > 0 {
   324  		elements = make([]Timestamptz, len(uta.Elements))
   325  
   326  		for i, s := range uta.Elements {
   327  			var elem Timestamptz
   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 = TimestamptzArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
   342  
   343  	return nil
   344  }
   345  
   346  func (dst *TimestamptzArray) DecodeBinary(ci *ConnInfo, src []byte) error {
   347  	if src == nil {
   348  		*dst = TimestamptzArray{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 = TimestamptzArray{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([]Timestamptz, 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 = TimestamptzArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
   385  	return nil
   386  }
   387  
   388  func (src TimestamptzArray) 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  
   445  func (src TimestamptzArray) 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("timestamptz"); ok {
   458  		arrayHeader.ElementOID = int32(dt.OID)
   459  	} else {
   460  		return nil, fmt.Errorf("unable to find oid for type name %v", "timestamptz")
   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.
   490  func (dst *TimestamptzArray) 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.
   508  func (src TimestamptzArray) 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  

View as plain text