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