2
0

Add support to ErrorResponse for unlocalized severity

Add missing 'V' field for unlocalized severity added in PG versions 9.6
and greater. See https://www.postgresql.org/docs/current/protocol-error-fields.html
This commit is contained in:
Yuli Khodorkovskiy
2020-12-16 03:42:55 +00:00
committed by Jack Christensen
parent 88b6398594
commit 1213b69774
2 changed files with 63 additions and 17 deletions
+26 -17
View File
@@ -7,23 +7,24 @@ import (
) )
type ErrorResponse struct { type ErrorResponse struct {
Severity string Severity string
Code string SeverityUnlocalized string // only in 9.6 and greater
Message string Code string
Detail string Message string
Hint string Detail string
Position int32 Hint string
InternalPosition int32 Position int32
InternalQuery string InternalPosition int32
Where string InternalQuery string
SchemaName string Where string
TableName string SchemaName string
ColumnName string TableName string
DataTypeName string ColumnName string
ConstraintName string DataTypeName string
File string ConstraintName string
Line int32 File string
Routine string Line int32
Routine string
UnknownFields map[byte]string UnknownFields map[byte]string
} }
@@ -56,6 +57,8 @@ func (dst *ErrorResponse) Decode(src []byte) error {
switch k { switch k {
case 'S': case 'S':
dst.Severity = v dst.Severity = v
case 'V':
dst.SeverityUnlocalized = v
case 'C': case 'C':
dst.Code = v dst.Code = v
case 'M': case 'M':
@@ -123,6 +126,11 @@ func (src *ErrorResponse) marshalBinary(typeByte byte) []byte {
buf.WriteString(src.Severity) buf.WriteString(src.Severity)
buf.WriteByte(0) buf.WriteByte(0)
} }
if src.SeverityUnlocalized != "" {
buf.WriteByte('V')
buf.WriteString(src.SeverityUnlocalized)
buf.WriteByte(0)
}
if src.Code != "" { if src.Code != "" {
buf.WriteByte('C') buf.WriteByte('C')
buf.WriteString(src.Code) buf.WriteString(src.Code)
@@ -210,6 +218,7 @@ func (src *ErrorResponse) marshalBinary(typeByte byte) []byte {
buf.WriteString(v) buf.WriteString(v)
buf.WriteByte(0) buf.WriteByte(0)
} }
buf.WriteByte(0) buf.WriteByte(0)
binary.BigEndian.PutUint32(buf.Bytes()[1:5], uint32(buf.Len()-1)) binary.BigEndian.PutUint32(buf.Bytes()[1:5], uint32(buf.Len()-1))
+37
View File
@@ -6,6 +6,7 @@ import (
"github.com/jackc/pgproto3/v2" "github.com/jackc/pgproto3/v2"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
type interruptReader struct { type interruptReader struct {
@@ -78,3 +79,39 @@ func TestFrontendReceiveUnexpectedEOF(t *testing.T) {
assert.Nil(t, msg) assert.Nil(t, msg)
assert.Equal(t, io.ErrUnexpectedEOF, err) assert.Equal(t, io.ErrUnexpectedEOF, err)
} }
func TestErrorResponse(t *testing.T) {
t.Parallel()
want := &pgproto3.ErrorResponse{
Severity: "ERROR",
SeverityUnlocalized: "ERROR",
Message: `column "foo" does not exist`,
File: "parse_relation.c",
Code: "42703",
Position: 8,
Line: 3513,
Routine: "errorMissingColumn",
}
raw := []byte{
'E', 0, 0, 0, 'f',
'S', 'E', 'R', 'R', 'O', 'R', 0,
'V', 'E', 'R', 'R', 'O', 'R', 0,
'C', '4', '2', '7', '0', '3', 0,
'M', 'c', 'o', 'l', 'u', 'm', 'n', 32, '"', 'f', 'o', 'o', '"', 32, 'd', 'o', 'e', 's', 32, 'n', 'o', 't', 32, 'e', 'x', 'i', 's', 't', 0,
'P', '8', 0,
'F', 'p', 'a', 'r', 's', 'e', '_', 'r', 'e', 'l', 'a', 't', 'i', 'o', 'n', '.', 'c', 0,
'L', '3', '5', '1', '3', 0,
'R', 'e', 'r', 'r', 'o', 'r', 'M', 'i', 's', 's', 'i', 'n', 'g', 'C', 'o', 'l', 'u', 'm', 'n', 0, 0,
}
server := &interruptReader{}
server.push(raw)
frontend := pgproto3.NewFrontend(pgproto3.NewChunkReader(server), nil)
got, err := frontend.Receive()
require.NoError(t, err)
assert.Equal(t, want, got)
}