...
1 package pgproto3
2
3 import (
4 "encoding/binary"
5 "encoding/hex"
6 "encoding/json"
7 "errors"
8 "math"
9
10 "github.com/jackc/pgio"
11 )
12
13 type DataRow struct {
14 Values [][]byte
15 }
16
17
18 func (*DataRow) Backend() {}
19
20
21
22 func (dst *DataRow) Decode(src []byte) error {
23 if len(src) < 2 {
24 return &invalidMessageFormatErr{messageType: "DataRow"}
25 }
26 rp := 0
27 fieldCount := int(binary.BigEndian.Uint16(src[rp:]))
28 rp += 2
29
30
31
32
33 if cap(dst.Values) < fieldCount || cap(dst.Values)-fieldCount > 32 {
34 newCap := 32
35 if newCap < fieldCount {
36 newCap = fieldCount
37 }
38 dst.Values = make([][]byte, fieldCount, newCap)
39 } else {
40 dst.Values = dst.Values[:fieldCount]
41 }
42
43 for i := 0; i < fieldCount; i++ {
44 if len(src[rp:]) < 4 {
45 return &invalidMessageFormatErr{messageType: "DataRow"}
46 }
47
48 msgSize := int(int32(binary.BigEndian.Uint32(src[rp:])))
49 rp += 4
50
51
52 if msgSize == -1 {
53 dst.Values[i] = nil
54 } else {
55 if len(src[rp:]) < msgSize {
56 return &invalidMessageFormatErr{messageType: "DataRow"}
57 }
58
59 dst.Values[i] = src[rp : rp+msgSize : rp+msgSize]
60 rp += msgSize
61 }
62 }
63
64 return nil
65 }
66
67
68 func (src *DataRow) Encode(dst []byte) ([]byte, error) {
69 dst, sp := beginMessage(dst, 'D')
70
71 if len(src.Values) > math.MaxUint16 {
72 return nil, errors.New("too many values")
73 }
74 dst = pgio.AppendUint16(dst, uint16(len(src.Values)))
75 for _, v := range src.Values {
76 if v == nil {
77 dst = pgio.AppendInt32(dst, -1)
78 continue
79 }
80
81 dst = pgio.AppendInt32(dst, int32(len(v)))
82 dst = append(dst, v...)
83 }
84
85 return finishMessage(dst, sp)
86 }
87
88
89 func (src DataRow) MarshalJSON() ([]byte, error) {
90 formattedValues := make([]map[string]string, len(src.Values))
91 for i, v := range src.Values {
92 if v == nil {
93 continue
94 }
95
96 var hasNonPrintable bool
97 for _, b := range v {
98 if b < 32 {
99 hasNonPrintable = true
100 break
101 }
102 }
103
104 if hasNonPrintable {
105 formattedValues[i] = map[string]string{"binary": hex.EncodeToString(v)}
106 } else {
107 formattedValues[i] = map[string]string{"text": string(v)}
108 }
109 }
110
111 return json.Marshal(struct {
112 Type string
113 Values []map[string]string
114 }{
115 Type: "DataRow",
116 Values: formattedValues,
117 })
118 }
119
120
121 func (dst *DataRow) UnmarshalJSON(data []byte) error {
122
123 if string(data) == "null" {
124 return nil
125 }
126
127 var msg struct {
128 Values []map[string]string
129 }
130 if err := json.Unmarshal(data, &msg); err != nil {
131 return err
132 }
133
134 dst.Values = make([][]byte, len(msg.Values))
135 for n, parameter := range msg.Values {
136 var err error
137 dst.Values[n], err = getValueFromJSON(parameter)
138 if err != nil {
139 return err
140 }
141 }
142 return nil
143 }
144
View as plain text