...

Source file src/github.com/jackc/pgtype/numeric_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  
    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  	// untyped nil and typed nil interfaces are different
    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  	// Attempt to match to select common types:
    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  		// Fallback to reflection if an optimised match was not found.
   203  		// The reflection is necessary for arrays and multidimensional slices,
   204  		// but it comes with a 20-50% performance penalty for large arrays/slices
   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  			// Maybe the target was one dimension too far, try again:
   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  			// Attempt to match to select common types:
   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  		// Try to convert to something AssignTo can use directly.
   389  		if nextDst, retry := GetAssignToDstType(dst); retry {
   390  			return src.AssignTo(nextDst)
   391  		}
   392  
   393  		// Fallback to reflection if an optimised match was not found.
   394  		// The reflection is necessary for arrays and multidimensional slices,
   395  		// but it comes with a 20-50% performance penalty for large arrays/slices
   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  	// dimElemCounts is the multiples of elements that each array lies on. For
   570  	// example, a single dimension array of length 4 would have a dimElemCounts of
   571  	// [4]. A multi-dimensional array of lengths [3,5,2] would have a
   572  	// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
   573  	// or '}'.
   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  // Scan implements the database/sql Scanner interface.
   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  // Value implements the database/sql/driver Valuer interface.
   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