...

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

View as plain text