decodeJSONB works for text and binary format

pull/220/head
Jack Christensen 2016-11-23 12:52:04 -06:00
parent c952d48a5c
commit e96c105b55
2 changed files with 47 additions and 37 deletions

View File

@ -2087,13 +2087,16 @@ func decodeJSONB(vr *ValueReader, d interface{}) error {
}
bytes := vr.ReadBytes(vr.Len())
if bytes[0] != 1 {
err := ProtocolError(fmt.Sprintf("Unknown jsonb format byte: %x", bytes[0]))
vr.Fatal(err)
return err
if vr.Type().FormatCode == BinaryFormatCode {
if bytes[0] != 1 {
err := ProtocolError(fmt.Sprintf("Unknown jsonb format byte: %x", bytes[0]))
vr.Fatal(err)
return err
}
bytes = bytes[1:]
}
err := json.Unmarshal(bytes[1:], d)
err := json.Unmarshal(bytes, d)
if err != nil {
vr.Fatal(err)
}

View File

@ -88,67 +88,74 @@ func TestJsonAndJsonbTranscode(t *testing.T) {
if _, ok := conn.PgTypes[oid]; !ok {
return // No JSON/JSONB type -- must be running against old PostgreSQL
}
typename := conn.PgTypes[oid].Name
testJsonString(t, conn, typename)
testJsonStringPointer(t, conn, typename)
testJsonSingleLevelStringMap(t, conn, typename)
testJsonNestedMap(t, conn, typename)
testJsonStringArray(t, conn, typename)
testJsonInt64Array(t, conn, typename)
testJsonInt16ArrayFailureDueToOverflow(t, conn, typename)
testJsonStruct(t, conn, typename)
for _, format := range []int16{pgx.TextFormatCode, pgx.BinaryFormatCode} {
pgtype := conn.PgTypes[oid]
pgtype.DefaultFormat = format
conn.PgTypes[oid] = pgtype
typename := conn.PgTypes[oid].Name
testJsonString(t, conn, typename, format)
testJsonStringPointer(t, conn, typename, format)
testJsonSingleLevelStringMap(t, conn, typename, format)
testJsonNestedMap(t, conn, typename, format)
testJsonStringArray(t, conn, typename, format)
testJsonInt64Array(t, conn, typename, format)
testJsonInt16ArrayFailureDueToOverflow(t, conn, typename, format)
testJsonStruct(t, conn, typename, format)
}
}
}
func testJsonString(t *testing.T, conn *pgx.Conn, typename string) {
func testJsonString(t *testing.T, conn *pgx.Conn, typename string, format int16) {
input := `{"key": "value"}`
expectedOutput := map[string]string{"key": "value"}
var output map[string]string
err := conn.QueryRow("select $1::"+typename, input).Scan(&output)
if err != nil {
t.Errorf("%s: QueryRow Scan failed: %v", typename, err)
t.Errorf("%s %d: QueryRow Scan failed: %v", typename, format, err)
return
}
if !reflect.DeepEqual(expectedOutput, output) {
t.Errorf("%s: Did not transcode map[string]string successfully: %v is not %v", typename, expectedOutput, output)
t.Errorf("%s %d: Did not transcode map[string]string successfully: %v is not %v", typename, format, expectedOutput, output)
return
}
}
func testJsonStringPointer(t *testing.T, conn *pgx.Conn, typename string) {
func testJsonStringPointer(t *testing.T, conn *pgx.Conn, typename string, format int16) {
input := `{"key": "value"}`
expectedOutput := map[string]string{"key": "value"}
var output map[string]string
err := conn.QueryRow("select $1::"+typename, &input).Scan(&output)
if err != nil {
t.Errorf("%s: QueryRow Scan failed: %v", typename, err)
t.Errorf("%s %d: QueryRow Scan failed: %v", typename, format, err)
return
}
if !reflect.DeepEqual(expectedOutput, output) {
t.Errorf("%s: Did not transcode map[string]string successfully: %v is not %v", typename, expectedOutput, output)
t.Errorf("%s %d: Did not transcode map[string]string successfully: %v is not %v", typename, format, expectedOutput, output)
return
}
}
func testJsonSingleLevelStringMap(t *testing.T, conn *pgx.Conn, typename string) {
func testJsonSingleLevelStringMap(t *testing.T, conn *pgx.Conn, typename string, format int16) {
input := map[string]string{"key": "value"}
var output map[string]string
err := conn.QueryRow("select $1::"+typename, input).Scan(&output)
if err != nil {
t.Errorf("%s: QueryRow Scan failed: %v", typename, err)
t.Errorf("%s %d: QueryRow Scan failed: %v", typename, format, err)
return
}
if !reflect.DeepEqual(input, output) {
t.Errorf("%s: Did not transcode map[string]string successfully: %v is not %v", typename, input, output)
t.Errorf("%s %d: Did not transcode map[string]string successfully: %v is not %v", typename, format, input, output)
return
}
}
func testJsonNestedMap(t *testing.T, conn *pgx.Conn, typename string) {
func testJsonNestedMap(t *testing.T, conn *pgx.Conn, typename string, format int16) {
input := map[string]interface{}{
"name": "Uncanny",
"stats": map[string]interface{}{"hp": float64(107), "maxhp": float64(150)},
@ -157,52 +164,52 @@ func testJsonNestedMap(t *testing.T, conn *pgx.Conn, typename string) {
var output map[string]interface{}
err := conn.QueryRow("select $1::"+typename, input).Scan(&output)
if err != nil {
t.Errorf("%s: QueryRow Scan failed: %v", typename, err)
t.Errorf("%s %d: QueryRow Scan failed: %v", typename, format, err)
return
}
if !reflect.DeepEqual(input, output) {
t.Errorf("%s: Did not transcode map[string]interface{} successfully: %v is not %v", typename, input, output)
t.Errorf("%s %d: Did not transcode map[string]interface{} successfully: %v is not %v", typename, format, input, output)
return
}
}
func testJsonStringArray(t *testing.T, conn *pgx.Conn, typename string) {
func testJsonStringArray(t *testing.T, conn *pgx.Conn, typename string, format int16) {
input := []string{"foo", "bar", "baz"}
var output []string
err := conn.QueryRow("select $1::"+typename, input).Scan(&output)
if err != nil {
t.Errorf("%s: QueryRow Scan failed: %v", typename, err)
t.Errorf("%s %d: QueryRow Scan failed: %v", typename, format, err)
}
if !reflect.DeepEqual(input, output) {
t.Errorf("%s: Did not transcode []string successfully: %v is not %v", typename, input, output)
t.Errorf("%s %d: Did not transcode []string successfully: %v is not %v", typename, format, input, output)
}
}
func testJsonInt64Array(t *testing.T, conn *pgx.Conn, typename string) {
func testJsonInt64Array(t *testing.T, conn *pgx.Conn, typename string, format int16) {
input := []int64{1, 2, 234432}
var output []int64
err := conn.QueryRow("select $1::"+typename, input).Scan(&output)
if err != nil {
t.Errorf("%s: QueryRow Scan failed: %v", typename, err)
t.Errorf("%s %d: QueryRow Scan failed: %v", typename, format, err)
}
if !reflect.DeepEqual(input, output) {
t.Errorf("%s: Did not transcode []int64 successfully: %v is not %v", typename, input, output)
t.Errorf("%s %d: Did not transcode []int64 successfully: %v is not %v", typename, format, input, output)
}
}
func testJsonInt16ArrayFailureDueToOverflow(t *testing.T, conn *pgx.Conn, typename string) {
func testJsonInt16ArrayFailureDueToOverflow(t *testing.T, conn *pgx.Conn, typename string, format int16) {
input := []int{1, 2, 234432}
var output []int16
err := conn.QueryRow("select $1::"+typename, input).Scan(&output)
if err == nil || err.Error() != "can't scan into dest[0]: json: cannot unmarshal number 234432 into Go value of type int16" {
t.Errorf("%s: Expected *json.UnmarkalTypeError, but got %v", typename, err)
t.Errorf("%s %d: Expected *json.UnmarkalTypeError, but got %v", typename, format, err)
}
}
func testJsonStruct(t *testing.T, conn *pgx.Conn, typename string) {
func testJsonStruct(t *testing.T, conn *pgx.Conn, typename string, format int16) {
type person struct {
Name string `json:"name"`
Age int `json:"age"`
@ -217,11 +224,11 @@ func testJsonStruct(t *testing.T, conn *pgx.Conn, typename string) {
err := conn.QueryRow("select $1::"+typename, input).Scan(&output)
if err != nil {
t.Errorf("%s: QueryRow Scan failed: %v", typename, err)
t.Errorf("%s %d: QueryRow Scan failed: %v", typename, format, err)
}
if !reflect.DeepEqual(input, output) {
t.Errorf("%s: Did not transcode struct successfully: %v is not %v", typename, input, output)
t.Errorf("%s %d: Did not transcode struct successfully: %v is not %v", typename, format, input, output)
}
}