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()) bytes := vr.ReadBytes(vr.Len())
if bytes[0] != 1 { if vr.Type().FormatCode == BinaryFormatCode {
err := ProtocolError(fmt.Sprintf("Unknown jsonb format byte: %x", bytes[0])) if bytes[0] != 1 {
vr.Fatal(err) err := ProtocolError(fmt.Sprintf("Unknown jsonb format byte: %x", bytes[0]))
return err vr.Fatal(err)
return err
}
bytes = bytes[1:]
} }
err := json.Unmarshal(bytes[1:], d) err := json.Unmarshal(bytes, d)
if err != nil { if err != nil {
vr.Fatal(err) vr.Fatal(err)
} }

View File

@ -88,67 +88,74 @@ func TestJsonAndJsonbTranscode(t *testing.T) {
if _, ok := conn.PgTypes[oid]; !ok { if _, ok := conn.PgTypes[oid]; !ok {
return // No JSON/JSONB type -- must be running against old PostgreSQL return // No JSON/JSONB type -- must be running against old PostgreSQL
} }
typename := conn.PgTypes[oid].Name
testJsonString(t, conn, typename) for _, format := range []int16{pgx.TextFormatCode, pgx.BinaryFormatCode} {
testJsonStringPointer(t, conn, typename) pgtype := conn.PgTypes[oid]
testJsonSingleLevelStringMap(t, conn, typename) pgtype.DefaultFormat = format
testJsonNestedMap(t, conn, typename) conn.PgTypes[oid] = pgtype
testJsonStringArray(t, conn, typename)
testJsonInt64Array(t, conn, typename) typename := conn.PgTypes[oid].Name
testJsonInt16ArrayFailureDueToOverflow(t, conn, typename)
testJsonStruct(t, conn, typename) 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"}` input := `{"key": "value"}`
expectedOutput := map[string]string{"key": "value"} expectedOutput := map[string]string{"key": "value"}
var output map[string]string var output map[string]string
err := conn.QueryRow("select $1::"+typename, input).Scan(&output) err := conn.QueryRow("select $1::"+typename, input).Scan(&output)
if err != nil { if err != nil {
t.Errorf("%s: QueryRow Scan failed: %v", typename, err) t.Errorf("%s %d: QueryRow Scan failed: %v", typename, format, err)
return return
} }
if !reflect.DeepEqual(expectedOutput, output) { 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 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"}` input := `{"key": "value"}`
expectedOutput := map[string]string{"key": "value"} expectedOutput := map[string]string{"key": "value"}
var output map[string]string var output map[string]string
err := conn.QueryRow("select $1::"+typename, &input).Scan(&output) err := conn.QueryRow("select $1::"+typename, &input).Scan(&output)
if err != nil { if err != nil {
t.Errorf("%s: QueryRow Scan failed: %v", typename, err) t.Errorf("%s %d: QueryRow Scan failed: %v", typename, format, err)
return return
} }
if !reflect.DeepEqual(expectedOutput, output) { 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 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"} input := map[string]string{"key": "value"}
var output map[string]string var output map[string]string
err := conn.QueryRow("select $1::"+typename, input).Scan(&output) err := conn.QueryRow("select $1::"+typename, input).Scan(&output)
if err != nil { if err != nil {
t.Errorf("%s: QueryRow Scan failed: %v", typename, err) t.Errorf("%s %d: QueryRow Scan failed: %v", typename, format, err)
return return
} }
if !reflect.DeepEqual(input, output) { 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 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{}{ input := map[string]interface{}{
"name": "Uncanny", "name": "Uncanny",
"stats": map[string]interface{}{"hp": float64(107), "maxhp": float64(150)}, "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{} var output map[string]interface{}
err := conn.QueryRow("select $1::"+typename, input).Scan(&output) err := conn.QueryRow("select $1::"+typename, input).Scan(&output)
if err != nil { if err != nil {
t.Errorf("%s: QueryRow Scan failed: %v", typename, err) t.Errorf("%s %d: QueryRow Scan failed: %v", typename, format, err)
return return
} }
if !reflect.DeepEqual(input, output) { 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 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"} input := []string{"foo", "bar", "baz"}
var output []string var output []string
err := conn.QueryRow("select $1::"+typename, input).Scan(&output) err := conn.QueryRow("select $1::"+typename, input).Scan(&output)
if err != nil { 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) { 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} input := []int64{1, 2, 234432}
var output []int64 var output []int64
err := conn.QueryRow("select $1::"+typename, input).Scan(&output) err := conn.QueryRow("select $1::"+typename, input).Scan(&output)
if err != nil { 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) { 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} input := []int{1, 2, 234432}
var output []int16 var output []int16
err := conn.QueryRow("select $1::"+typename, input).Scan(&output) 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" { 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 { type person struct {
Name string `json:"name"` Name string `json:"name"`
Age int `json:"age"` 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) err := conn.QueryRow("select $1::"+typename, input).Scan(&output)
if err != nil { 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) { 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)
} }
} }