error_response.go (7725B)
1 package pgproto3 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "encoding/json" 7 "strconv" 8 ) 9 10 type ErrorResponse struct { 11 Severity string 12 SeverityUnlocalized string // only in 9.6 and greater 13 Code string 14 Message string 15 Detail string 16 Hint string 17 Position int32 18 InternalPosition int32 19 InternalQuery string 20 Where string 21 SchemaName string 22 TableName string 23 ColumnName string 24 DataTypeName string 25 ConstraintName string 26 File string 27 Line int32 28 Routine string 29 30 UnknownFields map[byte]string 31 } 32 33 // Backend identifies this message as sendable by the PostgreSQL backend. 34 func (*ErrorResponse) Backend() {} 35 36 // Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message 37 // type identifier and 4 byte message length. 38 func (dst *ErrorResponse) Decode(src []byte) error { 39 *dst = ErrorResponse{} 40 41 buf := bytes.NewBuffer(src) 42 43 for { 44 k, err := buf.ReadByte() 45 if err != nil { 46 return err 47 } 48 if k == 0 { 49 break 50 } 51 52 vb, err := buf.ReadBytes(0) 53 if err != nil { 54 return err 55 } 56 v := string(vb[:len(vb)-1]) 57 58 switch k { 59 case 'S': 60 dst.Severity = v 61 case 'V': 62 dst.SeverityUnlocalized = v 63 case 'C': 64 dst.Code = v 65 case 'M': 66 dst.Message = v 67 case 'D': 68 dst.Detail = v 69 case 'H': 70 dst.Hint = v 71 case 'P': 72 s := v 73 n, _ := strconv.ParseInt(s, 10, 32) 74 dst.Position = int32(n) 75 case 'p': 76 s := v 77 n, _ := strconv.ParseInt(s, 10, 32) 78 dst.InternalPosition = int32(n) 79 case 'q': 80 dst.InternalQuery = v 81 case 'W': 82 dst.Where = v 83 case 's': 84 dst.SchemaName = v 85 case 't': 86 dst.TableName = v 87 case 'c': 88 dst.ColumnName = v 89 case 'd': 90 dst.DataTypeName = v 91 case 'n': 92 dst.ConstraintName = v 93 case 'F': 94 dst.File = v 95 case 'L': 96 s := v 97 n, _ := strconv.ParseInt(s, 10, 32) 98 dst.Line = int32(n) 99 case 'R': 100 dst.Routine = v 101 102 default: 103 if dst.UnknownFields == nil { 104 dst.UnknownFields = make(map[byte]string) 105 } 106 dst.UnknownFields[k] = v 107 } 108 } 109 110 return nil 111 } 112 113 // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. 114 func (src *ErrorResponse) Encode(dst []byte) []byte { 115 return append(dst, src.marshalBinary('E')...) 116 } 117 118 func (src *ErrorResponse) marshalBinary(typeByte byte) []byte { 119 var bigEndian BigEndianBuf 120 buf := &bytes.Buffer{} 121 122 buf.WriteByte(typeByte) 123 buf.Write(bigEndian.Uint32(0)) 124 125 if src.Severity != "" { 126 buf.WriteByte('S') 127 buf.WriteString(src.Severity) 128 buf.WriteByte(0) 129 } 130 if src.SeverityUnlocalized != "" { 131 buf.WriteByte('V') 132 buf.WriteString(src.SeverityUnlocalized) 133 buf.WriteByte(0) 134 } 135 if src.Code != "" { 136 buf.WriteByte('C') 137 buf.WriteString(src.Code) 138 buf.WriteByte(0) 139 } 140 if src.Message != "" { 141 buf.WriteByte('M') 142 buf.WriteString(src.Message) 143 buf.WriteByte(0) 144 } 145 if src.Detail != "" { 146 buf.WriteByte('D') 147 buf.WriteString(src.Detail) 148 buf.WriteByte(0) 149 } 150 if src.Hint != "" { 151 buf.WriteByte('H') 152 buf.WriteString(src.Hint) 153 buf.WriteByte(0) 154 } 155 if src.Position != 0 { 156 buf.WriteByte('P') 157 buf.WriteString(strconv.Itoa(int(src.Position))) 158 buf.WriteByte(0) 159 } 160 if src.InternalPosition != 0 { 161 buf.WriteByte('p') 162 buf.WriteString(strconv.Itoa(int(src.InternalPosition))) 163 buf.WriteByte(0) 164 } 165 if src.InternalQuery != "" { 166 buf.WriteByte('q') 167 buf.WriteString(src.InternalQuery) 168 buf.WriteByte(0) 169 } 170 if src.Where != "" { 171 buf.WriteByte('W') 172 buf.WriteString(src.Where) 173 buf.WriteByte(0) 174 } 175 if src.SchemaName != "" { 176 buf.WriteByte('s') 177 buf.WriteString(src.SchemaName) 178 buf.WriteByte(0) 179 } 180 if src.TableName != "" { 181 buf.WriteByte('t') 182 buf.WriteString(src.TableName) 183 buf.WriteByte(0) 184 } 185 if src.ColumnName != "" { 186 buf.WriteByte('c') 187 buf.WriteString(src.ColumnName) 188 buf.WriteByte(0) 189 } 190 if src.DataTypeName != "" { 191 buf.WriteByte('d') 192 buf.WriteString(src.DataTypeName) 193 buf.WriteByte(0) 194 } 195 if src.ConstraintName != "" { 196 buf.WriteByte('n') 197 buf.WriteString(src.ConstraintName) 198 buf.WriteByte(0) 199 } 200 if src.File != "" { 201 buf.WriteByte('F') 202 buf.WriteString(src.File) 203 buf.WriteByte(0) 204 } 205 if src.Line != 0 { 206 buf.WriteByte('L') 207 buf.WriteString(strconv.Itoa(int(src.Line))) 208 buf.WriteByte(0) 209 } 210 if src.Routine != "" { 211 buf.WriteByte('R') 212 buf.WriteString(src.Routine) 213 buf.WriteByte(0) 214 } 215 216 for k, v := range src.UnknownFields { 217 buf.WriteByte(k) 218 buf.WriteByte(0) 219 buf.WriteString(v) 220 buf.WriteByte(0) 221 } 222 223 buf.WriteByte(0) 224 225 binary.BigEndian.PutUint32(buf.Bytes()[1:5], uint32(buf.Len()-1)) 226 227 return buf.Bytes() 228 } 229 230 // MarshalJSON implements encoding/json.Marshaler. 231 func (src ErrorResponse) MarshalJSON() ([]byte, error) { 232 return json.Marshal(struct { 233 Type string 234 Severity string 235 SeverityUnlocalized string // only in 9.6 and greater 236 Code string 237 Message string 238 Detail string 239 Hint string 240 Position int32 241 InternalPosition int32 242 InternalQuery string 243 Where string 244 SchemaName string 245 TableName string 246 ColumnName string 247 DataTypeName string 248 ConstraintName string 249 File string 250 Line int32 251 Routine string 252 253 UnknownFields map[byte]string 254 }{ 255 Type: "ErrorResponse", 256 Severity: src.Severity, 257 SeverityUnlocalized: src.SeverityUnlocalized, 258 Code: src.Code, 259 Message: src.Message, 260 Detail: src.Detail, 261 Hint: src.Hint, 262 Position: src.Position, 263 InternalPosition: src.InternalPosition, 264 InternalQuery: src.InternalQuery, 265 Where: src.Where, 266 SchemaName: src.SchemaName, 267 TableName: src.TableName, 268 ColumnName: src.ColumnName, 269 DataTypeName: src.DataTypeName, 270 ConstraintName: src.ConstraintName, 271 File: src.File, 272 Line: src.Line, 273 Routine: src.Routine, 274 UnknownFields: src.UnknownFields, 275 }) 276 } 277 278 // UnmarshalJSON implements encoding/json.Unmarshaler. 279 func (dst *ErrorResponse) UnmarshalJSON(data []byte) error { 280 // Ignore null, like in the main JSON package. 281 if string(data) == "null" { 282 return nil 283 } 284 285 var msg struct { 286 Type string 287 Severity string 288 SeverityUnlocalized string // only in 9.6 and greater 289 Code string 290 Message string 291 Detail string 292 Hint string 293 Position int32 294 InternalPosition int32 295 InternalQuery string 296 Where string 297 SchemaName string 298 TableName string 299 ColumnName string 300 DataTypeName string 301 ConstraintName string 302 File string 303 Line int32 304 Routine string 305 306 UnknownFields map[byte]string 307 } 308 if err := json.Unmarshal(data, &msg); err != nil { 309 return err 310 } 311 312 dst.Severity = msg.Severity 313 dst.SeverityUnlocalized = msg.SeverityUnlocalized 314 dst.Code = msg.Code 315 dst.Message = msg.Message 316 dst.Detail = msg.Detail 317 dst.Hint = msg.Hint 318 dst.Position = msg.Position 319 dst.InternalPosition = msg.InternalPosition 320 dst.InternalQuery = msg.InternalQuery 321 dst.Where = msg.Where 322 dst.SchemaName = msg.SchemaName 323 dst.TableName = msg.TableName 324 dst.ColumnName = msg.ColumnName 325 dst.DataTypeName = msg.DataTypeName 326 dst.ConstraintName = msg.ConstraintName 327 dst.File = msg.File 328 dst.Line = msg.Line 329 dst.Routine = msg.Routine 330 331 dst.UnknownFields = msg.UnknownFields 332 333 return nil 334 }