Skip to content

Commit 428d4e6

Browse files
authored
Remove go.mod replace directive that breaks 'go install ...@latest' (#4401)
1 parent dadc7ed commit 428d4e6

File tree

4 files changed

+83
-39
lines changed

4 files changed

+83
-39
lines changed

go.mod

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,3 @@ require (
5858
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516 // indirect
5959
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
6060
)
61-
62-
replace github.com/go-sql-driver/mysql => github.com/sqlc-dev/mysql v0.0.0-20251129233104-d81e1cac6db2

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
2222
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
2323
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
2424
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
25+
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
26+
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
2527
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
2628
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
2729
github.com/google/cel-go v0.28.0 h1:KjSWstCpz/MN5t4a8gnGJNIYUsJRpdi/r97xWDphIQc=
@@ -81,8 +83,6 @@ github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
8183
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
8284
github.com/sqlc-dev/doubleclick v1.0.0 h1:2/OApfQ2eLgcfa/Fqs8WSMA6atH0G8j9hHbQIgMfAXI=
8385
github.com/sqlc-dev/doubleclick v1.0.0/go.mod h1:ODHRroSrk/rr5neRHlWMSRijqOak8YmNaO3VAZCNl5Y=
84-
github.com/sqlc-dev/mysql v0.0.0-20251129233104-d81e1cac6db2 h1:kmCAKKtOgK6EXXQX9oPdEASIhgor7TCpWxD8NtcqVcU=
85-
github.com/sqlc-dev/mysql v0.0.0-20251129233104-d81e1cac6db2/go.mod h1:TrDMWzjNTKvJeK2GC8uspG+PWyPLiY9QKvwdWpAdlZE=
8686
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
8787
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
8888
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=

gomod_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package sqlc
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"strings"
7+
"testing"
8+
)
9+
10+
// TestGoModHasNoReplaceDirectives guards against regressions of
11+
// https://github.com/sqlc-dev/sqlc/issues/4397.
12+
//
13+
// When go.mod contains a replace directive, the Go toolchain refuses to run
14+
// `go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest` (and the equivalent
15+
// `go run ...@latest`):
16+
//
17+
// go: github.com/sqlc-dev/sqlc/cmd/sqlc@latest (in github.com/sqlc-dev/sqlc@v...):
18+
// The go.mod file for the module providing named packages contains one or
19+
// more replace directives. It must not contain directives that would cause
20+
// it to be interpreted differently than if it were the main module.
21+
//
22+
// https://docs.sqlc.dev/en/latest/overview/install.html tells users to run
23+
// exactly that command, so any replace directive slipping into go.mod breaks
24+
// the advertised installation path for the next release.
25+
func TestGoModHasNoReplaceDirectives(t *testing.T) {
26+
data, err := os.ReadFile("go.mod")
27+
if err != nil {
28+
t.Fatalf("read go.mod: %v", err)
29+
}
30+
31+
var (
32+
inBlock bool
33+
offenders []string
34+
)
35+
for i, raw := range strings.Split(string(data), "\n") {
36+
line := strings.TrimSpace(raw)
37+
if idx := strings.Index(line, "//"); idx >= 0 {
38+
line = strings.TrimSpace(line[:idx])
39+
}
40+
41+
if inBlock {
42+
if line == ")" {
43+
inBlock = false
44+
continue
45+
}
46+
if line != "" {
47+
offenders = append(offenders, fmt.Sprintf(" go.mod:%d: %s", i+1, raw))
48+
}
49+
continue
50+
}
51+
52+
switch {
53+
case line == "replace (":
54+
inBlock = true
55+
case strings.HasPrefix(line, "replace "):
56+
offenders = append(offenders, fmt.Sprintf(" go.mod:%d: %s", i+1, raw))
57+
}
58+
}
59+
60+
if len(offenders) > 0 {
61+
t.Fatalf("go.mod must not contain replace directives; "+
62+
"they break `go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest`.\n"+
63+
"See https://github.com/sqlc-dev/sqlc/issues/4397\n%s",
64+
strings.Join(offenders, "\n"))
65+
}
66+
}

internal/x/expander/expander_test.go

Lines changed: 15 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@ package expander
33
import (
44
"context"
55
"database/sql"
6-
"database/sql/driver"
7-
"fmt"
86
"os"
97
"testing"
108

11-
"github.com/go-sql-driver/mysql"
9+
_ "github.com/go-sql-driver/mysql"
1210
"github.com/jackc/pgx/v5/pgxpool"
1311
"github.com/ncruces/go-sqlite3"
1412
_ "github.com/ncruces/go-sqlite3/embed"
@@ -45,46 +43,28 @@ func (g *PostgreSQLColumnGetter) GetColumnNames(ctx context.Context, query strin
4543
return columns, nil
4644
}
4745

48-
// MySQLColumnGetter implements ColumnGetter for MySQL using the forked driver's StmtMetadata.
46+
// MySQLColumnGetter implements ColumnGetter for MySQL. Column names are read
47+
// from the result set metadata returned by executing the query; the test
48+
// tables are empty, so no real rows are transferred.
49+
//
50+
// An earlier implementation pulled column metadata straight out of a prepared
51+
// statement via a forked mysql driver exposing StmtMetadata. That fork
52+
// required a `replace` directive in go.mod, which broke `go install
53+
// github.com/sqlc-dev/sqlc/cmd/sqlc@latest` (see
54+
// https://github.com/sqlc-dev/sqlc/issues/4397). Reading columns from sql.Rows
55+
// works with the upstream driver and keeps the test covering the same
56+
// behavior.
4957
type MySQLColumnGetter struct {
5058
db *sql.DB
5159
}
5260

5361
func (g *MySQLColumnGetter) GetColumnNames(ctx context.Context, query string) ([]string, error) {
54-
conn, err := g.db.Conn(ctx)
62+
rows, err := g.db.QueryContext(ctx, query)
5563
if err != nil {
5664
return nil, err
5765
}
58-
defer conn.Close()
59-
60-
var columns []string
61-
err = conn.Raw(func(driverConn any) error {
62-
preparer, ok := driverConn.(driver.ConnPrepareContext)
63-
if !ok {
64-
return fmt.Errorf("driver connection does not support PrepareContext")
65-
}
66-
67-
stmt, err := preparer.PrepareContext(ctx, query)
68-
if err != nil {
69-
return err
70-
}
71-
defer stmt.Close()
72-
73-
meta, ok := stmt.(mysql.StmtMetadata)
74-
if !ok {
75-
return fmt.Errorf("prepared statement does not implement StmtMetadata")
76-
}
77-
78-
for _, col := range meta.ColumnMetadata() {
79-
columns = append(columns, col.Name)
80-
}
81-
return nil
82-
})
83-
if err != nil {
84-
return nil, err
85-
}
86-
87-
return columns, nil
66+
defer rows.Close()
67+
return rows.Columns()
8868
}
8969

9070
// SQLiteColumnGetter implements ColumnGetter for SQLite using the native ncruces/go-sqlite3 API.

0 commit comments

Comments
 (0)