1package pgproto3 2 3import ( 4 "bytes" 5 "encoding/binary" 6 "encoding/json" 7 8 "github.com/jackc/pgx/pgio" 9) 10 11const ( 12 TextFormat = 0 13 BinaryFormat = 1 14) 15 16type FieldDescription struct { 17 Name string 18 TableOID uint32 19 TableAttributeNumber uint16 20 DataTypeOID uint32 21 DataTypeSize int16 22 TypeModifier int32 23 Format int16 24} 25 26type RowDescription struct { 27 Fields []FieldDescription 28} 29 30func (*RowDescription) Backend() {} 31 32func (dst *RowDescription) Decode(src []byte) error { 33 buf := bytes.NewBuffer(src) 34 35 if buf.Len() < 2 { 36 return &invalidMessageFormatErr{messageType: "RowDescription"} 37 } 38 fieldCount := int(binary.BigEndian.Uint16(buf.Next(2))) 39 40 *dst = RowDescription{Fields: make([]FieldDescription, fieldCount)} 41 42 for i := 0; i < fieldCount; i++ { 43 var fd FieldDescription 44 bName, err := buf.ReadBytes(0) 45 if err != nil { 46 return err 47 } 48 fd.Name = string(bName[:len(bName)-1]) 49 50 // Since buf.Next() doesn't return an error if we hit the end of the buffer 51 // check Len ahead of time 52 if buf.Len() < 18 { 53 return &invalidMessageFormatErr{messageType: "RowDescription"} 54 } 55 56 fd.TableOID = binary.BigEndian.Uint32(buf.Next(4)) 57 fd.TableAttributeNumber = binary.BigEndian.Uint16(buf.Next(2)) 58 fd.DataTypeOID = binary.BigEndian.Uint32(buf.Next(4)) 59 fd.DataTypeSize = int16(binary.BigEndian.Uint16(buf.Next(2))) 60 fd.TypeModifier = int32(binary.BigEndian.Uint32(buf.Next(4))) 61 fd.Format = int16(binary.BigEndian.Uint16(buf.Next(2))) 62 63 dst.Fields[i] = fd 64 } 65 66 return nil 67} 68 69func (src *RowDescription) Encode(dst []byte) []byte { 70 dst = append(dst, 'T') 71 sp := len(dst) 72 dst = pgio.AppendInt32(dst, -1) 73 74 dst = pgio.AppendUint16(dst, uint16(len(src.Fields))) 75 for _, fd := range src.Fields { 76 dst = append(dst, fd.Name...) 77 dst = append(dst, 0) 78 79 dst = pgio.AppendUint32(dst, fd.TableOID) 80 dst = pgio.AppendUint16(dst, fd.TableAttributeNumber) 81 dst = pgio.AppendUint32(dst, fd.DataTypeOID) 82 dst = pgio.AppendInt16(dst, fd.DataTypeSize) 83 dst = pgio.AppendInt32(dst, fd.TypeModifier) 84 dst = pgio.AppendInt16(dst, fd.Format) 85 } 86 87 pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) 88 89 return dst 90} 91 92func (src *RowDescription) MarshalJSON() ([]byte, error) { 93 return json.Marshal(struct { 94 Type string 95 Fields []FieldDescription 96 }{ 97 Type: "RowDescription", 98 Fields: src.Fields, 99 }) 100} 101