1package pgtype 2 3import ( 4 errors "golang.org/x/xerrors" 5) 6 7// CompositeFields scans the fields of a composite type into the elements of the CompositeFields value. To scan a 8// nullable value use a *CompositeFields. It will be set to nil in case of null. 9// 10// CompositeFields implements EncodeBinary and EncodeText. However, functionality is limited due to CompositeFields not 11// knowing the PostgreSQL schema of the composite type. Prefer using a registered CompositeType. 12type CompositeFields []interface{} 13 14func (cf CompositeFields) DecodeBinary(ci *ConnInfo, src []byte) error { 15 if len(cf) == 0 { 16 return errors.Errorf("cannot decode into empty CompositeFields") 17 } 18 19 if src == nil { 20 return errors.Errorf("cannot decode unexpected null into CompositeFields") 21 } 22 23 scanner := NewCompositeBinaryScanner(ci, src) 24 25 for _, f := range cf { 26 scanner.ScanValue(f) 27 } 28 29 if scanner.Err() != nil { 30 return scanner.Err() 31 } 32 33 return nil 34} 35 36func (cf CompositeFields) DecodeText(ci *ConnInfo, src []byte) error { 37 if len(cf) == 0 { 38 return errors.Errorf("cannot decode into empty CompositeFields") 39 } 40 41 if src == nil { 42 return errors.Errorf("cannot decode unexpected null into CompositeFields") 43 } 44 45 scanner := NewCompositeTextScanner(ci, src) 46 47 for _, f := range cf { 48 scanner.ScanValue(f) 49 } 50 51 if scanner.Err() != nil { 52 return scanner.Err() 53 } 54 55 return nil 56} 57 58// EncodeText encodes composite fields into the text format. Prefer registering a CompositeType to using 59// CompositeFields to encode directly. 60func (cf CompositeFields) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) { 61 b := NewCompositeTextBuilder(ci, buf) 62 63 for _, f := range cf { 64 if textEncoder, ok := f.(TextEncoder); ok { 65 b.AppendEncoder(textEncoder) 66 } else { 67 b.AppendValue(f) 68 } 69 } 70 71 return b.Finish() 72} 73 74// EncodeBinary encodes composite fields into the binary format. Unlike CompositeType the schema of the destination is 75// unknown. Prefer registering a CompositeType to using CompositeFields to encode directly. Because the binary 76// composite format requires the OID of each field to be specified the only types that will work are those known to 77// ConnInfo. 78// 79// In particular: 80// 81// * Nil cannot be used because there is no way to determine what type it. 82// * Integer types must be exact matches. e.g. A Go int32 into a PostgreSQL bigint will fail. 83// * No dereferencing will be done. e.g. *Text must be used instead of Text. 84func (cf CompositeFields) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) { 85 b := NewCompositeBinaryBuilder(ci, buf) 86 87 for _, f := range cf { 88 dt, ok := ci.DataTypeForValue(f) 89 if !ok { 90 return nil, errors.Errorf("Unknown OID for %#v", f) 91 } 92 93 if binaryEncoder, ok := f.(BinaryEncoder); ok { 94 b.AppendEncoder(dt.OID, binaryEncoder) 95 } else { 96 err := dt.Value.Set(f) 97 if err != nil { 98 return nil, err 99 } 100 if binaryEncoder, ok := dt.Value.(BinaryEncoder); ok { 101 b.AppendEncoder(dt.OID, binaryEncoder) 102 } else { 103 return nil, errors.Errorf("Cannot encode binary format for %v", f) 104 } 105 } 106 } 107 108 return b.Finish() 109} 110