]> Cypherpunks.ru repositories - gostls13.git/commitdiff
database/sql: add Null[T]
authorInada Naoki <songofacandy@gmail.com>
Sat, 5 Aug 2023 16:22:48 +0000 (16:22 +0000)
committerJonathan Amsterdam <jba@google.com>
Mon, 7 Aug 2023 14:26:37 +0000 (14:26 +0000)
Generic version of NullString, NullInt64, etc.

Fixes #60370

Change-Id: I166a05a6126e8b8571db5cbb026303bb6551d56b
GitHub-Last-Rev: 3c8d2d5141c36f034d2124e19ee090620363ba24
GitHub-Pull-Request: golang/go#60677
Reviewed-on: https://go-review.googlesource.com/c/go/+/501700
Reviewed-by: Jonathan Amsterdam <jba@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
api/next/60370.txt [new file with mode: 0644]
src/database/sql/sql.go
src/database/sql/sql_test.go

diff --git a/api/next/60370.txt b/api/next/60370.txt
new file mode 100644 (file)
index 0000000..66ced0b
--- /dev/null
@@ -0,0 +1,5 @@
+pkg database/sql, method (*Null[$0]) Scan(interface{}) error #60370
+pkg database/sql, method (Null[$0]) Value() (driver.Value, error) #60370
+pkg database/sql, type Null[$0 interface{}] struct #60370
+pkg database/sql, type Null[$0 interface{}] struct, Valid bool #60370
+pkg database/sql, type Null[$0 interface{}] struct, V $0 #60370
index 836fe83e2ec389e909c288c4d292e47a84298dde..7a57c7de36c9746ad8e7c766cbf0e5554dd3c524 100644 (file)
@@ -391,6 +391,39 @@ func (n NullTime) Value() (driver.Value, error) {
        return n.Time, nil
 }
 
+// Null represents a value that may be null.
+// Null implements the Scanner interface so
+// it can be used as a scan destination:
+//
+//     var s Null[string]
+//     err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&s)
+//     ...
+//     if s.Valid {
+//        // use s.V
+//     } else {
+//        // NULL value
+//     }
+type Null[T any] struct {
+       V     T
+       Valid bool
+}
+
+func (n *Null[T]) Scan(value any) error {
+       if value == nil {
+               n.V, n.Valid = *new(T), false
+               return nil
+       }
+       n.Valid = true
+       return convertAssign(&n.V, value)
+}
+
+func (n Null[T]) Value() (driver.Value, error) {
+       if !n.Valid {
+               return nil, nil
+       }
+       return n.V, nil
+}
+
 // Scanner is an interface used by Scan.
 type Scanner interface {
        // Scan assigns a value from a database driver.
index e6a5cd912ac361baeff7dbdacb650918987d8894..f1c946d4e46929af8d0084a3ac4df909684d9bf1 100644 (file)
@@ -1803,6 +1803,18 @@ func TestNullStringParam(t *testing.T) {
        nullTestRun(t, spec)
 }
 
+func TestGenericNullStringParam(t *testing.T) {
+       spec := nullTestSpec{"nullstring", "string", [6]nullTestRow{
+               {Null[string]{"aqua", true}, "", Null[string]{"aqua", true}},
+               {Null[string]{"brown", false}, "", Null[string]{"", false}},
+               {"chartreuse", "", Null[string]{"chartreuse", true}},
+               {Null[string]{"darkred", true}, "", Null[string]{"darkred", true}},
+               {Null[string]{"eel", false}, "", Null[string]{"", false}},
+               {"foo", Null[string]{"black", false}, nil},
+       }}
+       nullTestRun(t, spec)
+}
+
 func TestNullInt64Param(t *testing.T) {
        spec := nullTestSpec{"nullint64", "int64", [6]nullTestRow{
                {NullInt64{31, true}, 1, NullInt64{31, true}},
@@ -1916,8 +1928,9 @@ func nullTestRun(t *testing.T, spec nullTestSpec) {
        }
 
        // Can't put null val into non-null col
-       if _, err := stmt.Exec(6, "bob", spec.rows[5].nullParam, spec.rows[5].notNullParam); err == nil {
-               t.Errorf("expected error inserting nil val with prepared statement Exec")
+       row5 := spec.rows[5]
+       if _, err := stmt.Exec(6, "bob", row5.nullParam, row5.notNullParam); err == nil {
+               t.Errorf("expected error inserting nil val with prepared statement Exec: NULL=%#v, NOT-NULL=%#v", row5.nullParam, row5.notNullParam)
        }
 
        _, err = db.Exec("INSERT|t|id=?,name=?,nullf=?", 999, nil, nil)