From 6191beefc99b61029620e45813528f861d9e26e8 Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Thu, 2 Apr 2026 14:29:05 +0100 Subject: [PATCH] Use Go 1.23 Run go fix ./... --- .github/workflows/test.yml | 2 +- array.go | 8 ++++---- array_test.go | 2 +- conn_test.go | 20 +++++++------------- connector.go | 28 ++++++++++------------------ connector_test.go | 8 +++----- copy_test.go | 5 +---- deprecated_test.go | 2 -- encode_test.go | 4 ++-- error_test.go | 2 +- go.mod | 2 +- internal/pqtest/pqtest.go | 8 -------- internal/pqtime/loc_test.go | 4 ++-- internal/pqtime/pqtime_test.go | 2 -- issues_test.go | 2 +- notify_test.go | 2 +- rows.go | 20 ++++++++++---------- rows_test.go | 31 ++++++++++++++++--------------- ssl_test.go | 4 ---- 19 files changed, 61 insertions(+), 95 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4253d4a5d..b21e16ba5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,7 +28,7 @@ jobs: fail-fast: false matrix: pg: ['14', '15', '16', '17', '18'] - go: ['1.21', '1.26'] + go: ['1.23', '1.26'] steps: - uses: 'actions/checkout@v6' - uses: 'actions/setup-go@v6' diff --git a/array.go b/array.go index 4a5328687..bdd97d3fe 100644 --- a/array.go +++ b/array.go @@ -11,9 +11,9 @@ import ( "strings" ) -var typeByteSlice = reflect.TypeOf([]byte{}) -var typeDriverValuer = reflect.TypeOf((*driver.Valuer)(nil)).Elem() -var typeSQLScanner = reflect.TypeOf((*sql.Scanner)(nil)).Elem() +var typeByteSlice = reflect.TypeFor[[]byte]() +var typeDriverValuer = reflect.TypeFor[driver.Valuer]() +var typeSQLScanner = reflect.TypeFor[sql.Scanner]() // Array returns the optimal driver.Valuer and sql.Scanner for an array or // slice of any dimension. @@ -129,7 +129,7 @@ func (a BoolArray) Value() (driver.Value, error) { // and N-1 bytes of delimiters. b := make([]byte, 1+2*n) - for i := 0; i < n; i++ { + for i := range n { b[2*i] = ',' if a[i] { b[1+2*i] = 't' diff --git a/array_test.go b/array_test.go index 15454bd92..55fb8cff8 100644 --- a/array_test.go +++ b/array_test.go @@ -578,7 +578,7 @@ func BenchmarkArray(b *testing.B) { byts = make([][]byte, 10) strs = make([]string, 10) ) - for i := 0; i < len(bools); i++ { + for i := range bools { bools[i] = rnd.Intn(2) == 0 floats[i] = rnd.NormFloat64() ints[i] = rnd.Int63() diff --git a/conn_test.go b/conn_test.go index 20d0edf90..09b2337fe 100644 --- a/conn_test.go +++ b/conn_test.go @@ -9,6 +9,7 @@ import ( "encoding/json" "fmt" "io" + "maps" "math" "net" "os" @@ -69,7 +70,6 @@ func TestOpen(t *testing.T) { } for _, tt := range tests { - tt := tt t.Run(tt.dsn, func(t *testing.T) { t.Parallel() _, err := pqtest.DB(t, tt.dsn) @@ -96,9 +96,7 @@ func TestPgpass(t *testing.T) { "client_encoding": "UTF8", "datestyle": "ISO, MDY", } - for k, v := range extra { - o[k] = v - } + maps.Copy(o, extra) have := pgpass.PasswordFromPgpass(o["passfile"], o["user"], o["password"], o["host"], o["port"], o["dbname"]) if have != want { t.Fatalf("wrong password\nhave: %q\nwant: %q", have, want) @@ -1212,7 +1210,6 @@ func TestStmtQueryContext(t *testing.T) { }, } for _, tt := range tests { - tt := tt t.Run("", func(t *testing.T) { if !pqtest.Pgpool() { t.Parallel() @@ -1256,7 +1253,6 @@ func TestStmtExecContext(t *testing.T) { }, } for _, tt := range tests { - tt := tt t.Run("", func(t *testing.T) { if !pqtest.Pgpool() { t.Parallel() @@ -1301,7 +1297,7 @@ func TestContextCancelExec(t *testing.T) { t.Fatalf("unexpected error: %s", err) } - for i := 0; i < 100; i++ { + for range 100 { func() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -1337,7 +1333,7 @@ func TestContextCancelQuery(t *testing.T) { t.Fatalf("unexpected error: %s", err) } - for i := 0; i < 100; i++ { + for range 100 { func() { ctx, cancel := context.WithCancel(context.Background()) rows, err := db.QueryContext(ctx, "select 1") @@ -1364,7 +1360,7 @@ func TestIssue617(t *testing.T) { const N = 10 numGoroutineStart := runtime.NumGoroutine() - for i := 0; i < N; i++ { + for range N { func() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -1379,7 +1375,7 @@ func TestIssue617(t *testing.T) { iterations := int(waitTime / delayTime) var numGoroutineFinish int - for i := 0; i < iterations; i++ { + for range iterations { time.Sleep(delayTime) numGoroutineFinish = runtime.NumGoroutine() @@ -1426,7 +1422,7 @@ func TestContextCancelBegin(t *testing.T) { t.Fatalf("unexpected error: %s", err) } - for i := 0; i < 100; i++ { + for range 100 { func() { ctx, cancel := context.WithCancel(context.Background()) tx, err := db.BeginTx(ctx, nil) @@ -1692,7 +1688,6 @@ func TestBytea(t *testing.T) { } for _, tt := range tests { - tt := tt t.Run("", func(t *testing.T) { db := pqtest.MustDB(t) pqtest.Exec(t, db, `create temp table tbl (b bytea)`) @@ -1743,7 +1738,6 @@ func TestPreProtocolError(t *testing.T) { } for _, tt := range tests { - tt := tt t.Run("", func(t *testing.T) { t.Parallel() f := pqtest.NewFake(t, func(f pqtest.Fake, cn net.Conn) { diff --git a/connector.go b/connector.go index a2a8fb282..5c8d58aac 100644 --- a/connector.go +++ b/connector.go @@ -5,6 +5,7 @@ import ( "crypto/tls" "database/sql/driver" "fmt" + "maps" "math/rand" "net" "net/netip" @@ -515,9 +516,7 @@ func NewConfig(dsn string) (Config, error) { // Clone returns a copy of the [Config]. func (cfg Config) Clone() Config { rt := make(map[string]string) - for k, v := range cfg.Runtime { - rt[k] = v - } + maps.Copy(rt, cfg.Runtime) c := cfg c.Runtime = rt c.set = append([]string{}, cfg.set...) @@ -817,7 +816,7 @@ func (cfg *Config) setFromTag(o map[string]string, tag string, service bool) err f = "pq: wrong value for $%s: " } var ( - types = reflect.TypeOf(cfg).Elem() + types = reflect.TypeFor[Config]() values = reflect.ValueOf(cfg).Elem() ) for i := 0; i < types.NumField(); i++ { @@ -856,7 +855,7 @@ func (cfg *Config) setFromTag(o map[string]string, tag string, service bool) err default: return fmt.Errorf("don't know how to set %s: unknown type %s", rt.Name, rt.Type.Kind()) case reflect.Struct: - if rt.Type == reflect.TypeOf(netip.Addr{}) { + if rt.Type == reflect.TypeFor[netip.Addr]() { if hostaddr { vv := strings.Split(v, ",") v = vv[0] @@ -949,21 +948,16 @@ func (cfg *Config) setFromTag(o map[string]string, tag string, service bool) err } } + // Set run-time; we delete map keys as they're set in the struct. For the + // service file we don't support extra parameters and error out. if service && len(o) > 0 { - // TODO(go1.23): use maps.Keys once we require Go 1.23. var key string - for k := range o { - key = k - break - } + maps.Keys(o)(func(k string) bool { key = k; return false }) return fmt.Errorf("pq: unknown setting %q in service file for service %q", key, cfg.Service) } - - // Set run-time; we delete map keys as they're set in the struct. if !service && tag == "postgres" { // Make sure database= sets dbname=, as that previously worked (kind of - // by accident). - // TODO(v2): remove + // by accident). TODO(v2): remove if d, ok := o["database"]; ok { cfg.Database = d delete(o, "database") @@ -985,7 +979,7 @@ func (cfg Config) tomap() map[string]string { var ( o = make(map[string]string) values = reflect.ValueOf(cfg) - types = reflect.TypeOf(cfg) + types = reflect.TypeFor[Config]() ) for i := 0; i < types.NumField(); i++ { var ( @@ -1022,9 +1016,7 @@ func (cfg Config) tomap() map[string]string { } } } - for k, v := range cfg.Runtime { - o[k] = v - } + maps.Copy(o, cfg.Runtime) return o } diff --git a/connector_test.go b/connector_test.go index fc149d396..d776222f9 100644 --- a/connector_test.go +++ b/connector_test.go @@ -124,7 +124,7 @@ func TestNewConnector(t *testing.T) { `or:pq: database "two" does not exist (3D000)|pq: no such database: two (08P01)` // Make sure database= consistently take precedence over dbname= - for i := 0; i < 10; i++ { + for range 10 { _, err := pqtest.DB(t, "database=err") if !pqtest.ErrorContains(err, want1) { t.Errorf("wrong error:\nhave: %s\nwant: %s", err, want1) @@ -653,7 +653,7 @@ func TestConnectMulti(t *testing.T) { t.Run("load_balance_hosts=random", func(t *testing.T) { hosts := [3]int{} - for i := 0; i < 25; i++ { + for range 25 { connectedTo = [3]bool{} _ = pqtest.MustDB(t, fmt.Sprintf("host=%s,%s,%s port=%s,%s,%s load_balance_hosts=random", f1.Host(), f2.Host(), f3.Host(), f1.Port(), f2.Port(), f3.Port())) @@ -706,7 +706,6 @@ func TestConnectionTargetSessionAttrs(t *testing.T) { } for _, tt := range tests { - tt := tt t.Run("", func(t *testing.T) { t.Parallel() @@ -763,7 +762,7 @@ func TestProtocolVersion(t *testing.T) { key30 = []byte{1, 2, 3, 4} key32 = make([]byte, 32) ) - for i := 0; i < 32; i++ { + for i := range 32 { key32[i] = byte(i) } accept := func(version float32) (*[]byte, func(f pqtest.Fake, cn net.Conn)) { @@ -826,7 +825,6 @@ func TestProtocolVersion(t *testing.T) { } for _, tt := range tests { - tt := tt t.Run("", func(t *testing.T) { t.Parallel() have, a := accept(tt.serverVersion) diff --git a/copy_test.go b/copy_test.go index 30606171e..b6051eb16 100644 --- a/copy_test.go +++ b/copy_test.go @@ -25,7 +25,6 @@ func TestCopyInError(t *testing.T) { } for _, tt := range tests { - tt := tt t.Run("", func(t *testing.T) { t.Parallel() tx := pqtest.Begin(t, pqtest.MustDB(t)) @@ -96,7 +95,6 @@ func TestCopyInNull(t *testing.T) { } for _, tt := range tests { - tt := tt t.Run("", func(t *testing.T) { t.Parallel() db := pqtest.MustDB(t) @@ -130,7 +128,6 @@ func TestCopyInMultipleValues(t *testing.T) { } for _, tt := range tests { - tt := tt t.Run("", func(t *testing.T) { t.Parallel() db := pqtest.MustDB(t) @@ -138,7 +135,7 @@ func TestCopyInMultipleValues(t *testing.T) { pqtest.Exec(t, tx, `create temp table tbl (a int, b varchar)`) stmt := pqtest.Prepare(t, tx, tt.query, db) - for i := 0; i < 500; i++ { + for i := range 500 { stmt.MustExec(t, int64(i), strings.Repeat("#", 500)) } diff --git a/deprecated_test.go b/deprecated_test.go index 21277fe6a..a25d572ff 100644 --- a/deprecated_test.go +++ b/deprecated_test.go @@ -14,7 +14,6 @@ func TestCopyInStmt(t *testing.T) { } for _, tt := range tests { - tt := tt t.Run("", func(t *testing.T) { t.Parallel() have := CopyIn(tt.inTable, tt.inCols...) @@ -43,7 +42,6 @@ func TestCopyInSchemaStmt(t *testing.T) { } for _, tt := range tests { - tt := tt t.Run("", func(t *testing.T) { t.Parallel() have := CopyInSchema(tt.inSchema, tt.inTable, tt.inCols...) diff --git a/encode_test.go b/encode_test.go index 07c8d9432..4ba3a9ef5 100644 --- a/encode_test.go +++ b/encode_test.go @@ -436,14 +436,14 @@ func BenchmarkDecode(b *testing.B) { x := []byte("2013-09-17 22:15:32.360754-07") f := func(wg *sync.WaitGroup, loops int) { defer wg.Done() - for i := 0; i < loops; i++ { + for range loops { decode(¶meterStatus{}, x, oid.T_timestamptz, formatText) } } wg := &sync.WaitGroup{} b.ResetTimer() - for j := 0; j < 10; j++ { + for range 10 { wg.Add(1) go f(wg, b.N/10) } diff --git a/error_test.go b/error_test.go index a3e30ad94..7d0e5bd23 100644 --- a/error_test.go +++ b/error_test.go @@ -234,7 +234,7 @@ func TestRetryError(t *testing.T) { }) // Make write fail once so that safeRetryError{} is used. - for i := 0; i < 10; i++ { + for range 10 { os.Setenv("PQTEST_FAILNUM", "1") tx, err := db.Begin() if err != nil { diff --git a/go.mod b/go.mod index d0bc6668b..f49eafe9a 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module github.com/lib/pq -go 1.21 +go 1.23 diff --git a/internal/pqtest/pqtest.go b/internal/pqtest/pqtest.go index 019725cd7..21ce854d9 100644 --- a/internal/pqtest/pqtest.go +++ b/internal/pqtest/pqtest.go @@ -290,11 +290,3 @@ func QueryRow[T any](t testing.TB, db interface { } return nil } - -// Null represents a value that may be null. -// -// TODO(go1.22): replace with sql.Null -type Null[T any] struct { - V T - Valid bool -} diff --git a/internal/pqtime/loc_test.go b/internal/pqtime/loc_test.go index a40733973..27ee08bf8 100644 --- a/internal/pqtime/loc_test.go +++ b/internal/pqtime/loc_test.go @@ -22,14 +22,14 @@ func BenchmarkLocationCacheMultiThread(b *testing.B) { f := func(wg *sync.WaitGroup, loops int) { defer wg.Done() - for i := 0; i < loops; i++ { + for range loops { globalLocationCache.getLocation(rand.Intn(10000)) } } wg := &sync.WaitGroup{} b.ResetTimer() - for j := 0; j < 10; j++ { + for range 10 { wg.Add(1) go f(wg, b.N/10) } diff --git a/internal/pqtime/pqtime_test.go b/internal/pqtime/pqtime_test.go index 261b3bb93..f58b36019 100644 --- a/internal/pqtime/pqtime_test.go +++ b/internal/pqtime/pqtime_test.go @@ -79,7 +79,6 @@ func TestParse(t *testing.T) { db := pqtest.MustDB(t, "timezone='Etc/UTC'") t.Parallel() for _, tt := range tests { - tt := tt t.Run(tt.str, func(t *testing.T) { { // Parse() have, err := Parse(nil, tt.str) @@ -139,7 +138,6 @@ func TestFormat(t *testing.T) { db := pqtest.MustDB(t) t.Parallel() for _, tt := range tests { - tt := tt t.Run("", func(t *testing.T) { { // Format() have := string(Format(tt.in)) diff --git a/issues_test.go b/issues_test.go index 4bc40184f..52c0ac6b7 100644 --- a/issues_test.go +++ b/issues_test.go @@ -44,7 +44,7 @@ func TestQueryRowContextBad(t *testing.T) { db := pqtest.MustDB(t) // Ensure that cancelling a QueryRowContext does not result in an ErrBadConn. - for i := 0; i < 100; i++ { + for range 100 { ctx, cancel := context.WithCancel(context.Background()) go cancel() row := db.QueryRowContext(ctx, "select 1") diff --git a/notify_test.go b/notify_test.go index 6a248c952..ec1f0cd81 100644 --- a/notify_test.go +++ b/notify_test.go @@ -73,7 +73,7 @@ func channelName() string { b := []byte("pqtest") sel := "abcdefghjkmnpqrstuvwxyz" m := big.NewInt(int64(len(sel))) - for i := 0; i < 10; i++ { + for range 10 { n, _ := rand.Int(rand.Reader, m) b = append(b, sel[n.Int64()]) } diff --git a/rows.go b/rows.go index 2029bfed2..86b178d4f 100644 --- a/rows.go +++ b/rows.go @@ -193,25 +193,25 @@ type fieldDesc struct { func (fd fieldDesc) Type() reflect.Type { switch fd.OID { case oid.T_int8: - return reflect.TypeOf(int64(0)) + return reflect.TypeFor[int64]() case oid.T_int4: - return reflect.TypeOf(int32(0)) + return reflect.TypeFor[int32]() case oid.T_int2: - return reflect.TypeOf(int16(0)) + return reflect.TypeFor[int16]() case oid.T_float8: - return reflect.TypeOf(float64(0)) + return reflect.TypeFor[float64]() case oid.T_float4: - return reflect.TypeOf(float32(0)) + return reflect.TypeFor[float32]() case oid.T_varchar, oid.T_text, oid.T_varbit, oid.T_bit: - return reflect.TypeOf("") + return reflect.TypeFor[string]() case oid.T_bool: - return reflect.TypeOf(false) + return reflect.TypeFor[bool]() case oid.T_date, oid.T_time, oid.T_timetz, oid.T_timestamp, oid.T_timestamptz: - return reflect.TypeOf(time.Time{}) + return reflect.TypeFor[time.Time]() case oid.T_bytea: - return reflect.TypeOf([]byte(nil)) + return reflect.TypeFor[[]byte]() default: - return reflect.TypeOf(new(any)).Elem() + return reflect.TypeFor[any]() } } diff --git a/rows_test.go b/rows_test.go index 491a9bcce..241bea478 100644 --- a/rows_test.go +++ b/rows_test.go @@ -1,6 +1,7 @@ package pq import ( + "database/sql" "errors" "math" "reflect" @@ -151,8 +152,8 @@ func TestRowsColumnTypes(t *testing.T) { type h struct { name string typeName string - length pqtest.Null[int64] - decimalSize pqtest.Null[[2]int64] + length sql.Null[int64] + decimalSize sql.Null[[2]int64] scanType reflect.Type } @@ -164,8 +165,8 @@ func TestRowsColumnTypes(t *testing.T) { name: c.Name(), typeName: c.DatabaseTypeName(), scanType: c.ScanType(), - length: pqtest.Null[int64]{V: l, Valid: lok}, - decimalSize: pqtest.Null[[2]int64]{V: [2]int64{prec, scale}, Valid: dok}, + length: sql.Null[int64]{V: l, Valid: lok}, + decimalSize: sql.Null[[2]int64]{V: [2]int64{prec, scale}, Valid: dok}, }) } @@ -173,36 +174,36 @@ func TestRowsColumnTypes(t *testing.T) { { name: "a", typeName: "INT4", - scanType: reflect.TypeOf(int32(0)), + scanType: reflect.TypeFor[int32](), }, { name: "bar", typeName: "TEXT", - length: pqtest.Null[int64]{V: math.MaxInt64, Valid: true}, - scanType: reflect.TypeOf(""), + length: sql.Null[int64]{V: math.MaxInt64, Valid: true}, + scanType: reflect.TypeFor[string](), }, { name: "dec", typeName: "NUMERIC", - decimalSize: pqtest.Null[[2]int64]{V: [2]int64{9, 2}, Valid: true}, - scanType: reflect.TypeOf(new(any)).Elem(), + decimalSize: sql.Null[[2]int64]{V: [2]int64{9, 2}, Valid: true}, + scanType: reflect.TypeFor[any](), }, { name: "f", typeName: "FLOAT8", - scanType: reflect.TypeOf(float64(0)), + scanType: reflect.TypeFor[float64](), }, { name: "bit4", typeName: "BIT", - length: pqtest.Null[int64]{V: 4, Valid: true}, - scanType: reflect.TypeOf(""), + length: sql.Null[int64]{V: 4, Valid: true}, + scanType: reflect.TypeFor[string](), }, { name: "varbit10", typeName: "VARBIT", - length: pqtest.Null[int64]{V: 10, Valid: true}, - scanType: reflect.TypeOf(""), + length: sql.Null[int64]{V: 10, Valid: true}, + scanType: reflect.TypeFor[string](), }, } @@ -270,7 +271,7 @@ func TestRowsConcurrentUse(t *testing.T) { db := pqtest.MustDB(t, "") var wg sync.WaitGroup - for i := 0; i < 20; i++ { + for range 20 { wg.Add(1) go func() { defer wg.Done() diff --git a/ssl_test.go b/ssl_test.go index e30885d72..2564fb723 100644 --- a/ssl_test.go +++ b/ssl_test.go @@ -97,7 +97,6 @@ func TestSSLMode(t *testing.T) { } for _, tt := range tests { - tt := tt t.Run("", func(t *testing.T) { t.Parallel() @@ -145,7 +144,6 @@ func TestSSLClientCertificates(t *testing.T) { } for _, tt := range tests { - tt := tt t.Run("", func(t *testing.T) { t.Parallel() db, err := pqtest.DB(t, tt.connect) @@ -210,7 +208,6 @@ func TestSSLClientCertificateIntermediate(t *testing.T) { } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() db, err := pqtest.DB(t, tt.connect) @@ -287,7 +284,6 @@ func TestSSLSNI(t *testing.T) { } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel()