From 2e73d1e8eeccb2882ca43d09345c6d0c1048b406 Mon Sep 17 00:00:00 2001
From: Jack Christensen <jack@jackchristensen.com>
Date: Mon, 22 Aug 2022 20:56:36 -0500
Subject: [PATCH] Improve error message when failing to scan a NULL::json

---
 pgtype/json.go      |  3 +++
 pgtype/json_test.go | 35 +++++++++++++++++++++++++++++++++++
 2 files changed, 38 insertions(+)

diff --git a/pgtype/json.go b/pgtype/json.go
index de2f08df..51f2509f 100644
--- a/pgtype/json.go
+++ b/pgtype/json.go
@@ -3,6 +3,7 @@ package pgtype
 import (
 	"database/sql/driver"
 	"encoding/json"
+	"fmt"
 	"reflect"
 )
 
@@ -129,6 +130,8 @@ func (scanPlanJSONToJSONUnmarshal) Scan(src []byte, dst any) error {
 				return nil
 			}
 		}
+
+		return fmt.Errorf("cannot scan null into %T", dst)
 	}
 
 	return json.Unmarshal(src, dst)
diff --git a/pgtype/json_test.go b/pgtype/json_test.go
index c349fa24..04964e8c 100644
--- a/pgtype/json_test.go
+++ b/pgtype/json_test.go
@@ -4,7 +4,9 @@ import (
 	"context"
 	"testing"
 
+	pgx "github.com/jackc/pgx/v5"
 	"github.com/jackc/pgx/v5/pgxtest"
+	"github.com/stretchr/testify/require"
 )
 
 func isExpectedEqMap(a any) func(any) bool {
@@ -58,3 +60,36 @@ func TestJSONCodec(t *testing.T) {
 		{jsonStruct{Name: "Adam", Age: 10}, new(jsonStruct), isExpectedEq(jsonStruct{Name: "Adam", Age: 10})},
 	})
 }
+
+// https://github.com/jackc/pgx/issues/1273#issuecomment-1221414648
+func TestJSONCodecUnmarshalSQLNull(t *testing.T) {
+	defaultConnTestRunner.RunTest(context.Background(), t, func(ctx context.Context, t testing.TB, conn *pgx.Conn) {
+		// Slices are nilified
+		slice := []string{"foo", "bar", "baz"}
+		err := conn.QueryRow(ctx, "select null::json").Scan(&slice)
+		require.NoError(t, err)
+		require.Nil(t, slice)
+
+		// Maps are nilified
+		m := map[string]any{"foo": "bar"}
+		err = conn.QueryRow(ctx, "select null::json").Scan(&m)
+		require.NoError(t, err)
+		require.Nil(t, m)
+
+		// Pointer to pointer are nilified
+		n := 42
+		p := &n
+		err = conn.QueryRow(ctx, "select null::json").Scan(&p)
+		require.NoError(t, err)
+		require.Nil(t, p)
+
+		// A string cannot scan a NULL.
+		str := "foobar"
+		err = conn.QueryRow(ctx, "select null::json").Scan(&str)
+		require.EqualError(t, err, "can't scan into dest[0]: cannot scan null into *string")
+
+		// A non-string cannot scan a NULL.
+		err = conn.QueryRow(ctx, "select null::json").Scan(&n)
+		require.EqualError(t, err, "can't scan into dest[0]: cannot scan null into *int")
+	})
+}