forked from jackc/pgproto3
-
Notifications
You must be signed in to change notification settings - Fork 0
/
row_description.go
173 lines (150 loc) · 4.99 KB
/
row_description.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package pgproto3
import (
"bytes"
"encoding/binary"
"github.com/jackc/pgio"
)
const (
TextFormat = 0
BinaryFormat = 1
)
type FieldDescription struct {
Name []byte `json:"name" yaml:"name,omitempty"`
FieldName string `json:"field_name" yaml:"field_name"`
TableOID uint32 `json:"table_oid" yaml:"table_oid"`
TableAttributeNumber uint16 `json:"table_attribute_number" yaml:"table_attribute_number"`
DataTypeOID uint32 `json:"data_type_oid" yaml:"data_type_oid"`
DataTypeSize int16 `json:"data_type_size" yaml:"data_type_size"`
TypeModifier int32 `json:"type_modifier" yaml:"type_modifier"`
Format int16 `json:"format" yaml:"format"`
}
// // MarshalJSON implements encoding/json.Marshaler.
// func (fd FieldDescription) MarshalJSON() ([]byte, error) {
// return json.Marshal(struct {
// Name string
// TableOID uint32
// TableAttributeNumber uint16
// DataTypeOID uint32
// DataTypeSize int16
// TypeModifier int32
// Format int16
// }{
// Name: string(fd.Name),
// TableOID: fd.TableOID,
// TableAttributeNumber: fd.TableAttributeNumber,
// DataTypeOID: fd.DataTypeOID,
// DataTypeSize: fd.DataTypeSize,
// TypeModifier: fd.TypeModifier,
// Format: fd.Format,
// })
// }
type RowDescription struct {
Fields []FieldDescription
}
// Backend identifies this message as sendable by the PostgreSQL backend.
func (*RowDescription) Backend() {}
// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
// type identifier and 4 byte message length.
func (dst *RowDescription) Decode(src []byte) error {
//println("RowDescription.Decode")
if len(src) < 2 {
return &invalidMessageFormatErr{messageType: "RowDescription"}
}
fieldCount := int(binary.BigEndian.Uint16(src))
rp := 2
dst.Fields = dst.Fields[0:0]
for i := 0; i < fieldCount; i++ {
var fd FieldDescription
idx := bytes.IndexByte(src[rp:], 0)
if idx < 0 {
return &invalidMessageFormatErr{messageType: "RowDescription"}
}
fd.Name = src[rp : rp+idx]
fd.FieldName = string(fd.Name)
// now empty the buffer
fd.Name = []byte{}
rp += idx + 1
// Since buf.Next() doesn't return an error if we hit the end of the buffer
// check Len ahead of time
if len(src[rp:]) < 18 {
return &invalidMessageFormatErr{messageType: "RowDescription"}
}
fd.TableOID = binary.BigEndian.Uint32(src[rp:])
rp += 4
fd.TableAttributeNumber = binary.BigEndian.Uint16(src[rp:])
rp += 2
fd.DataTypeOID = binary.BigEndian.Uint32(src[rp:])
rp += 4
fd.DataTypeSize = int16(binary.BigEndian.Uint16(src[rp:]))
rp += 2
fd.TypeModifier = int32(binary.BigEndian.Uint32(src[rp:]))
rp += 4
fd.Format = int16(binary.BigEndian.Uint16(src[rp:]))
rp += 2
dst.Fields = append(dst.Fields, fd)
}
return nil
}
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *RowDescription) Encode(dst []byte) []byte {
//println("RowDescription.Encode")
dst = append(dst, 'T')
sp := len(dst)
dst = pgio.AppendInt32(dst, -1)
dst = pgio.AppendUint16(dst, uint16(len(src.Fields)))
for _, fd := range src.Fields {
if len(fd.Name) == 0 {
fd.Name = []byte(fd.FieldName)
}
dst = append(dst, fd.Name...)
dst = append(dst, 0)
dst = pgio.AppendUint32(dst, fd.TableOID)
dst = pgio.AppendUint16(dst, fd.TableAttributeNumber)
dst = pgio.AppendUint32(dst, fd.DataTypeOID)
dst = pgio.AppendInt16(dst, fd.DataTypeSize)
dst = pgio.AppendInt32(dst, fd.TypeModifier)
dst = pgio.AppendInt16(dst, fd.Format)
}
pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
return dst
}
// MarshalJSON implements encoding/json.Marshaler.
// func (src RowDescription) MarshalJSON() ([]byte, error) {
// return json.Marshal(struct {
// Type string
// Fields []FieldDescription
// }{
// Type: "RowDescription",
// Fields: src.Fields,
// })
// }
// UnmarshalJSON implements encoding/json.Unmarshaler.
// func (dst *RowDescription) UnmarshalJSON(data []byte) error {
// var msg struct {
// Fields []struct {
// Name string
// TableOID uint32
// TableAttributeNumber uint16
// DataTypeOID uint32
// DataTypeSize int16
// TypeModifier int32
// Format int16
// }
// }
// if err := json.Unmarshal(data, &msg); err != nil {
// return err
// }
// dst.Fields = make([]FieldDescription, len(msg.Fields))
// for n, field := range msg.Fields {
// dst.Fields[n] = FieldDescription{
// Name: []byte(field.Name),
// TableOID: field.TableOID,
// TableAttributeNumber: field.TableAttributeNumber,
// DataTypeOID: field.DataTypeOID,
// DataTypeSize: field.DataTypeSize,
// TypeModifier: field.TypeModifier,
// Format: field.Format,
// }
// }
// return nil
// }