From 0787b53cce306b1765d6c576dd81dae5205e7fcb Mon Sep 17 00:00:00 2001 From: Morgan Tocker Date: Sun, 6 Sep 2026 12:06:05 -0600 Subject: [PATCH 1/5] Make this a real fork: module path and driver name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The two capabilities this fork carries are reached from strata through `(*sql.Conn).Raw` and a structural interface assertion, which means a consumer that builds without the `replace` compiles clean and then fails at runtime on every statement. `replace` is not inherited across module boundaries, so any downstream module importing a library built on this fork silently links upstream instead — and a distinct module path is the only mechanism Go has for expressing a dependency that is not substitutable. So: `module github.com/block/mysql`, and the driver registers as `block-mysql`. The rename is required, not cosmetic — a dependency graph that still reaches upstream go-sql-driver anywhere links both packages, and two `sql.Register` calls under one name panic at init. Edits to upstream files are held to the module path and driver name so that merging upstream stays mechanical. Three `sql.Open("mysql", ...)` call sites in driver_test.go move to `driverNameTest` like every other site in the file, which is what upstream's own `-ldflags` override already assumed. The README gains a preamble stating what the fork adds, what it changes and why, the `errors.As` hazard when a binary links both drivers, and how to merge upstream forward. Verified: full suite green against MySQL 8.0.44, gofmt and staticcheck clean. --- README.md | 89 +++++++++++++++++++++++++++++++++++++++++++++++--- driver.go | 19 +++++++---- driver_test.go | 8 ++--- go.mod | 6 +++- utils.go | 2 +- 5 files changed, 108 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index abef7e808..3c0f1a328 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,86 @@ +# block/mysql + +**A tracking fork of [go-sql-driver/mysql](https://github.com/go-sql-driver/mysql).** + +Upstream is merged forward regularly and the delta is kept deliberately small: +this fork carries a short list of additive capabilities that upstream has not +adopted, and nothing else. The upstream README follows below the separator, +edited only where it names the import path or driver name. + +## What this fork adds + +| Capability | What it is | Upstream status | +| --- | --- | --- | +| [`QueryResultContext`](unified.go) | Executes arbitrary SQL and returns the response in the shape the server chose — exactly one of `driver.Rows` or `driver.Result`. Callers handling SQL they did not write (a proxy, a REPL) otherwise have to classify statements up front to pick between `QueryContext` and `ExecContext`, and a misclassification either discards a resultset or loses the OK-packet metadata. | Proposed as [go-sql-driver/mysql#1793](https://github.com/go-sql-driver/mysql/issues/1793); no maintainer response. Merged here as [#1](https://github.com/block/mysql/pull/1). | +| [`Warnings()`](warnings.go) | Exposes the warning count from the OK/EOF packet that terminated the last statement — the same number MySQL reports as `@@warning_count`. Warnings themselves live in per-connection state that only `SHOW WARNINGS` can read, so the count is what makes surfacing them affordable: it says whether that round trip would return anything. | Not proposed upstream. Merged here as [#2](https://github.com/block/mysql/pull/2). | + +Both are reached through `(*sql.Conn).Raw` and a structural interface +assertion, so a consumer can depend on the *capability* without a compile-time +dependency on this module. See the doc comments in `unified.go` and +`warnings.go` for the exact contracts. + +## What this fork changes + +Two things, both for packaging reasons only. Neither alters protocol behaviour. + +**The module path is `github.com/block/mysql`.** Upstream's path plus a +`replace` directive would work for a binary, but `replace` is not inherited +across module boundaries: a downstream module importing a *library* built on +this fork gets upstream go-sql-driver instead, with no diagnostic. Depending on +how the library reaches the fork's features that is either a compile failure or +— worse, and the case that motivated this change — a clean build that fails at +runtime. A distinct module path is the only mechanism Go has for expressing a +dependency that is not substitutable. + +**The driver registers as `block-mysql`, not `mysql`.** This is required rather +than cosmetic. Because the module path now differs, a dependency graph that +still reaches upstream go-sql-driver anywhere links both packages into one +binary, and two `sql.Register` calls under the same name panic at init. Open +connections with: + +```go +db, err := sql.Open("block-mysql", dsn) +``` + +The DSN format, `Config`, and the rest of the API are upstream's. + +## Linking both drivers + +Where a binary links this fork *and* upstream, remember that the two packages +declare distinct types even though the source is identical. Most importantly, +an `*mysql.MySQLError` produced by this package will not satisfy an +`errors.As` against upstream's `*mysql.MySQLError`, and vice versa — the check +silently returns false rather than failing loudly. Be deliberate about which +package each error-inspection site imports, and prefer moving code you control +onto one of the two. + +## Staying current + +```bash +git remote add upstream https://github.com/go-sql-driver/mysql.git +git fetch upstream +git merge upstream/master +``` + +Edits to upstream files are confined to the module path and driver name +(`go.mod`, `driver.go`, plus doc comments and test call sites that spell either +one out); the capabilities above live in files upstream does not have. That +keeps merges near-mechanical, and keeping it that way is a maintenance +requirement rather than a preference: anything that changes upstream's connect, +TLS, or packet paths belongs in a wrapper package, not here. + +## License + +MPL-2.0, unchanged from upstream, as are `LICENSE` and `AUTHORS`. Modified and +added files stay under the MPL and are published here in satisfaction of it. +Copyright in the original work remains with The Go-MySQL-Driver Authors. + +--------------------------------------- + # Go-MySQL-Driver +*Upstream README follows.* + [![DeepWiki](https://img.shields.io/badge/DeepWiki-go--sql--driver%2Fmysql-blue.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAyCAYAAAAnWDnqAAAAAXNSR0IArs4c6QAAA05JREFUaEPtmUtyEzEQhtWTQyQLHNak2AB7ZnyXZMEjXMGeK/AIi+QuHrMnbChYY7MIh8g01fJoopFb0uhhEqqcbWTp06/uv1saEDv4O3n3dV60RfP947Mm9/SQc0ICFQgzfc4CYZoTPAswgSJCCUJUnAAoRHOAUOcATwbmVLWdGoH//PB8mnKqScAhsD0kYP3j/Yt5LPQe2KvcXmGvRHcDnpxfL2zOYJ1mFwrryWTz0advv1Ut4CJgf5uhDuDj5eUcAUoahrdY/56ebRWeraTjMt/00Sh3UDtjgHtQNHwcRGOC98BJEAEymycmYcWwOprTgcB6VZ5JK5TAJ+fXGLBm3FDAmn6oPPjR4rKCAoJCal2eAiQp2x0vxTPB3ALO2CRkwmDy5WohzBDwSEFKRwPbknEggCPB/imwrycgxX2NzoMCHhPkDwqYMr9tRcP5qNrMZHkVnOjRMWwLCcr8ohBVb1OMjxLwGCvjTikrsBOiA6fNyCrm8V1rP93iVPpwaE+gO0SsWmPiXB+jikdf6SizrT5qKasx5j8ABbHpFTx+vFXp9EnYQmLx02h1QTTrl6eDqxLnGjporxl3NL3agEvXdT0WmEost648sQOYAeJS9Q7bfUVoMGnjo4AZdUMQku50McDcMWcBPvr0SzbTAFDfvJqwLzgxwATnCgnp4wDl6Aa+Ax283gghmj+vj7feE2KBBRMW3FzOpLOADl0Isb5587h/U4gGvkt5v60Z1VLG8BhYjbzRwyQZemwAd6cCR5/XFWLYZRIMpX39AR0tjaGGiGzLVyhse5C9RKC6ai42ppWPKiBagOvaYk8lO7DajerabOZP46Lby5wKjw1HCRx7p9sVMOWGzb/vA1hwiWc6jm3MvQDTogQkiqIhJV0nBQBTU+3okKCFDy9WwferkHjtxib7t3xIUQtHxnIwtx4mpg26/HfwVNVDb4oI9RHmx5WGelRVlrtiw43zboCLaxv46AZeB3IlTkwouebTr1y2NjSpHz68WNFjHvupy3q8TFn3Hos2IAk4Ju5dCo8B3wP7VPr/FGaKiG+T+v+TQqIrOqMTL1VdWV1DdmcbO8KXBz6esmYWYKPwDL5b5FA1a0hwapHiom0r/cKaoqr+27/XcrS5UwSMbQAAAABJRU5ErkJggg==)](https://deepwiki.com/go-sql-driver/mysql) @@ -60,26 +141,26 @@ A MySQL-Driver for Go's [database/sql](https://golang.org/pkg/database/sql/) pac ## Installation Simple install the package to your [$GOPATH](https://github.com/golang/go/wiki/GOPATH "GOPATH") with the [go tool](https://golang.org/cmd/go/ "go command") from shell: ```bash -go get -u github.com/go-sql-driver/mysql +go get -u github.com/block/mysql ``` Make sure [Git is installed](https://git-scm.com/downloads) on your machine and in your system's `PATH`. ## Usage _Go MySQL Driver_ is an implementation of Go's `database/sql/driver` interface. You only need to import the driver and can use the full [`database/sql`](https://golang.org/pkg/database/sql/) API then. -Use `mysql` as `driverName` and a valid [DSN](#dsn-data-source-name) as `dataSourceName`: +Use `block-mysql` as `driverName` and a valid [DSN](#dsn-data-source-name) as `dataSourceName`: ```go import ( "database/sql" "time" - _ "github.com/go-sql-driver/mysql" + _ "github.com/block/mysql" ) // ... -db, err := sql.Open("mysql", "user:password@/dbname") +db, err := sql.Open("block-mysql", "user:password@/dbname") if err != nil { panic(err) } diff --git a/driver.go b/driver.go index 105316b81..dfa0d41f7 100644 --- a/driver.go +++ b/driver.go @@ -6,14 +6,17 @@ // Package mysql provides a MySQL driver for Go's database/sql package. // -// The driver should be used via the database/sql package: +// This is Block's tracking fork of github.com/go-sql-driver/mysql. It +// registers itself as "block-mysql" rather than "mysql" so that it can be +// linked alongside upstream without a duplicate-registration panic: // // import "database/sql" -// import _ "github.com/go-sql-driver/mysql" +// import _ "github.com/block/mysql" // -// db, err := sql.Open("mysql", "user:password@/dbname") +// db, err := sql.Open("block-mysql", "user:password@/dbname") // -// See https://github.com/go-sql-driver/mysql#usage for details +// See https://github.com/block/mysql#usage for details, and the README for +// what this fork adds over upstream. package mysql import ( @@ -88,8 +91,12 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) { } // This variable can be replaced with -ldflags like below: -// go build "-ldflags=-X github.com/go-sql-driver/mysql.driverName=custom" -var driverName = "mysql" +// go build "-ldflags=-X github.com/block/mysql.driverName=custom" +// +// It is "block-mysql" rather than upstream's "mysql" because a build whose +// dependency graph still reaches upstream go-sql-driver links both packages, +// and two sql.Register calls under one name panic at init. +var driverName = "block-mysql" func init() { if driverName != "" { diff --git a/driver_test.go b/driver_test.go index 03486859c..8430f3850 100644 --- a/driver_test.go +++ b/driver_test.go @@ -36,7 +36,7 @@ import ( ) // This variable can be replaced with -ldflags like below: -// go test "-ldflags=-X github.com/go-sql-driver/mysql.driverNameTest=custom" +// go test "-ldflags=-X github.com/block/mysql.driverNameTest=custom" var driverNameTest string func init() { @@ -224,7 +224,7 @@ func runTestsParallel(t *testing.T, dsn string, tests ...func(dbt *DBTest, table t.Parallel() tableName := newTableName(t) - db, err := sql.Open("mysql", dsn) + db, err := sql.Open(driverNameTest, dsn) if err != nil { t.Fatalf("error connecting: %s", err.Error()) } @@ -243,7 +243,7 @@ func runTestsParallel(t *testing.T, dsn string, tests ...func(dbt *DBTest, table t.Parallel() tableName := newTableName(t) - db, err := sql.Open("mysql", dsn2) + db, err := sql.Open(driverNameTest, dsn2) if err != nil { t.Fatalf("error connecting: %s", err.Error()) } @@ -3583,7 +3583,7 @@ func TestErrorInMultiResult(t *testing.T) { // https://github.com/go-sql-driver/mysql/issues/1361 var db *sql.DB if _, err := ParseDSN(dsn); err != errInvalidDSNUnsafeCollation { - db, err = sql.Open("mysql", dsn) + db, err = sql.Open(driverNameTest, dsn) if err != nil { t.Fatalf("error connecting: %s", err.Error()) } diff --git a/go.mod b/go.mod index 1eae3a7aa..a34d5cfb5 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,8 @@ -module github.com/go-sql-driver/mysql +// This is Block's tracking fork of github.com/go-sql-driver/mysql. The module +// path differs from upstream deliberately: a `replace` directive is not +// inherited across module boundaries, so consumers of a library built on this +// fork would silently link upstream instead. See README.md. +module github.com/block/mysql go 1.25.0 diff --git a/utils.go b/utils.go index 2dccb7d53..ad9643b4e 100644 --- a/utils.go +++ b/utils.go @@ -53,7 +53,7 @@ var ( // RootCAs: rootCertPool, // Certificates: clientCert, // }) -// db, err := sql.Open("mysql", "user@tcp(localhost:3306)/test?tls=custom") +// db, err := sql.Open("block-mysql", "user@tcp(localhost:3306)/test?tls=custom") func RegisterTLSConfig(key string, config *tls.Config) error { if _, isBool := readBool(key); isBool || strings.ToLower(key) == "skip-verify" || strings.ToLower(key) == "preferred" { return fmt.Errorf("key '%s' is reserved", key) From 5d3e441166d0cae81cd86977a87499114fbef264 Mon Sep 17 00:00:00 2001 From: Morgan Tocker Date: Sun, 6 Sep 2026 12:10:39 -0600 Subject: [PATCH 2/5] README: soften the framing around upstream State plainly that we depend on these features and keep a tracking fork until upstream carries them, rather than characterising upstream's responsiveness or roadmap. Co-Authored-By: Claude Opus 5 --- README.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 3c0f1a328..e7e3c6c47 100644 --- a/README.md +++ b/README.md @@ -2,17 +2,20 @@ **A tracking fork of [go-sql-driver/mysql](https://github.com/go-sql-driver/mysql).** -Upstream is merged forward regularly and the delta is kept deliberately small: -this fork carries a short list of additive capabilities that upstream has not -adopted, and nothing else. The upstream README follows below the separator, -edited only where it names the import path or driver name. +Block depends on a small number of additive capabilities that aren't in +upstream yet. This fork exists to carry them until they are, and nothing more: +upstream is merged forward regularly and the delta is kept deliberately small, +so the fork can be retired if and when upstream adopts them. + +The upstream README follows below the separator, edited only where it names the +import path or driver name. ## What this fork adds | Capability | What it is | Upstream status | | --- | --- | --- | -| [`QueryResultContext`](unified.go) | Executes arbitrary SQL and returns the response in the shape the server chose — exactly one of `driver.Rows` or `driver.Result`. Callers handling SQL they did not write (a proxy, a REPL) otherwise have to classify statements up front to pick between `QueryContext` and `ExecContext`, and a misclassification either discards a resultset or loses the OK-packet metadata. | Proposed as [go-sql-driver/mysql#1793](https://github.com/go-sql-driver/mysql/issues/1793); no maintainer response. Merged here as [#1](https://github.com/block/mysql/pull/1). | -| [`Warnings()`](warnings.go) | Exposes the warning count from the OK/EOF packet that terminated the last statement — the same number MySQL reports as `@@warning_count`. Warnings themselves live in per-connection state that only `SHOW WARNINGS` can read, so the count is what makes surfacing them affordable: it says whether that round trip would return anything. | Not proposed upstream. Merged here as [#2](https://github.com/block/mysql/pull/2). | +| [`QueryResultContext`](unified.go) | Executes arbitrary SQL and returns the response in the shape the server chose — exactly one of `driver.Rows` or `driver.Result`. Callers handling SQL they did not write (a proxy, a REPL) otherwise have to classify statements up front to pick between `QueryContext` and `ExecContext`, and a misclassification either discards a resultset or loses the OK-packet metadata. | Raised upstream as [go-sql-driver/mysql#1793](https://github.com/go-sql-driver/mysql/issues/1793), still open. Merged here as [#1](https://github.com/block/mysql/pull/1). | +| [`Warnings()`](warnings.go) | Exposes the warning count from the OK/EOF packet that terminated the last statement — the same number MySQL reports as `@@warning_count`. Warnings themselves live in per-connection state that only `SHOW WARNINGS` can read, so the count is what makes surfacing them affordable: it says whether that round trip would return anything. | Not yet raised upstream. Merged here as [#2](https://github.com/block/mysql/pull/2). | Both are reached through `(*sql.Conn).Raw` and a structural interface assertion, so a consumer can depend on the *capability* without a compile-time From 55975b9fa7f73c5c0b8c084531697ae427335102 Mon Sep 17 00:00:00 2001 From: Morgan Tocker Date: Sun, 6 Sep 2026 12:45:33 -0600 Subject: [PATCH 3/5] ci: narrow the matrix to what this fork supports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Linux with MySQL LTS (9.7, 8.4, 8.0), plus Go 1.26 and 1.25 against the newest MySQL. Drops the macOS and Windows runners and the four MariaDB versions: Block deploys none of them, so the jobs cost CI time without telling us anything we act on. 25 test jobs become 5. It also removes exposure to a Windows-runner TCP dial flake ("connectex: A connection attempt failed...") that hits a different matrix cell each run. That flake is not ours — it reproduces on this fork's master without any of these changes, and on upstream go-sql-driver's own CI. This is a deliberate divergence in an upstream-owned file, so the README now lists CI alongside the module path as the second and last place the fork edits upstream, and states the narrower support scope explicitly. --- .github/workflows/test.yml | 14 +++++++------- README.md | 24 ++++++++++++++++++------ 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 75825d821..f348d685e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -34,14 +34,12 @@ jobs: '1.26', '1.25', ] - mysql = [ # LTS versions + # MySQL LTS versions. Upstream also covers MariaDB; this fork does + # not, because Block does not deploy against it. + mysql = [ '9.7', '8.4', '8.0', - 'mariadb-12.3', - 'mariadb-11.8', - 'mariadb-11.4', - 'mariadb-10.11', ] includes = [] @@ -50,8 +48,10 @@ jobs: includes.append({'os': 'ubuntu-latest', 'go': v, 'mysql': mysql[0]}) matrix = { - # OS vs MySQL versions - 'os': [ 'ubuntu-latest', 'macos-latest', 'windows-latest' ], + # MySQL versions. Upstream also runs macos-latest and + # windows-latest; this fork is Linux-only, which additionally + # avoids a Windows-runner TCP dial flake upstream sees too. + 'os': [ 'ubuntu-latest' ], 'go': [ go[0] ], 'mysql': mysql, diff --git a/README.md b/README.md index e7e3c6c47..da224fdb3 100644 --- a/README.md +++ b/README.md @@ -65,12 +65,24 @@ git fetch upstream git merge upstream/master ``` -Edits to upstream files are confined to the module path and driver name -(`go.mod`, `driver.go`, plus doc comments and test call sites that spell either -one out); the capabilities above live in files upstream does not have. That -keeps merges near-mechanical, and keeping it that way is a maintenance -requirement rather than a preference: anything that changes upstream's connect, -TLS, or packet paths belongs in a wrapper package, not here. +Edits to upstream files are confined to two things: the module path and driver +name (`go.mod`, `driver.go`, plus doc comments and test call sites that spell +either one out), and the CI matrix (see below). The capabilities above live in +files upstream does not have. That keeps merges near-mechanical, and keeping it +that way is a maintenance requirement rather than a preference: anything that +changes upstream's connect, TLS, or packet paths belongs in a wrapper package, +not here. + +## Supported platforms + +Narrower than upstream, and deliberately so — CI covers **Linux with MySQL LTS +(9.7, 8.4, 8.0)**, plus the two previous Go releases against the newest MySQL. + +Upstream additionally tests macOS and Windows runners and four MariaDB +versions. Block deploys none of those, so the fork drops them: 5 CI jobs rather +than 25, and no exposure to the Windows-runner TCP dial flake that upstream's +own CI also hits. Nothing about the driver is Linux- or MySQL-specific — the +platforms are merely untested here, so treat upstream as the authority on them. ## License From 6346a1ec80d223800a0d20846fd95a913ee6d802 Mon Sep 17 00:00:00 2001 From: Morgan Tocker Date: Sun, 6 Sep 2026 12:57:15 -0600 Subject: [PATCH 4/5] README: state the merge-cost guidance without foreclosing features The previous wording ruled connect/TLS/packet-path changes out of the fork entirely. The actual constraint is merge cost, not subject matter, so say that: additions are cheapest as new files or new methods. Leaves room for features that need a different shape. Co-Authored-By: Claude Opus 5 --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index da224fdb3..2626c3045 100644 --- a/README.md +++ b/README.md @@ -68,10 +68,9 @@ git merge upstream/master Edits to upstream files are confined to two things: the module path and driver name (`go.mod`, `driver.go`, plus doc comments and test call sites that spell either one out), and the CI matrix (see below). The capabilities above live in -files upstream does not have. That keeps merges near-mechanical, and keeping it -that way is a maintenance requirement rather than a preference: anything that -changes upstream's connect, TLS, or packet paths belongs in a wrapper package, -not here. +files upstream does not have, which is what keeps merges near-mechanical. +Additions are cheapest when they follow the same shape: new files, or new +methods on existing types, in preference to reworking an upstream code path. ## Supported platforms From e3ae89dee83178d946782df4d8fa0ebbec229b53 Mon Sep 17 00:00:00 2001 From: Morgan Tocker Date: Sun, 6 Sep 2026 14:14:52 -0600 Subject: [PATCH 5/5] Address review: pin the fork's identity, finish the README repointing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Four items from the review on #3: 1. "Linking both drivers" documented the errors.As type-identity hazard but not the one that mirrors this PR's own thesis: with both drivers linked, a call site still saying sql.Open("mysql", ...) resolves to upstream and keeps working, until something reaches for QueryResultContext or Warnings() through (*sql.Conn).Raw. Everything else in the both-linked surface fails loudly (the registries are package-level globals and name the cause on use), so the one silent case is worth naming. 2. Nothing pinned the two lines this PR consists of. Both mutations — the driver name back to "mysql", the module path back to upstream's — build clean and pass the full suite, and they are exactly the two places every `git merge upstream/master` has a conflict to resolve. fork_test.go asserts both: debug.ReadBuildInfo().Main.Path reads the real go.mod rather than a copy, and sql.Drivers() reads what init actually registered. Verified it kills both mutations. 3. The LOAD DATA LOCAL INFILE section still had `import "github.com/go-sql-driver/mysql"` — the one copy-pasteable import left on the old path, in the section whose premise is needing the package directly. Following it registers a local file in upstream's fileRegister while connections come from block-mysql. Its godoc link now points at the fork, which documents the fork's additions too; the remaining upstream links are provenance and stay. 4. "5 CI jobs rather than 25" was wrong. Ran the workflow's matrix generator at both revisions: 21 base combinations + 2 appended include entries = 23 test jobs before, 3 + 2 = 5 after. --- README.md | 25 ++++++++++++++++++------ fork_test.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 6 deletions(-) create mode 100644 fork_test.go diff --git a/README.md b/README.md index 2626c3045..7908710d4 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,17 @@ silently returns false rather than failing loudly. Be deliberate about which package each error-inspection site imports, and prefer moving code you control onto one of the two. +The other silent case is `sql.Open`. Registries in this package are +package-level globals, so a `RegisterTLSConfig`/`RegisterLocalFile`/ +`RegisterDialContext` call made against the wrong import path errors on use with +a message that names the cause — a migration chore, not a trap. A call site that +still says `sql.Open("mysql", …)`, however, resolves to whatever upstream's +`init` registered, connects, and behaves correctly until something reaches for +`QueryResultContext` or `Warnings()` through `(*sql.Conn).Raw` and the structural +assertion fails. Note the asymmetry: with upstream *not* in the dependency graph +the same mistake is benign, failing immediately with `sql: unknown driver +"mysql"`. Grep for the literal when both are linked. + ## Staying current ```bash @@ -78,10 +89,12 @@ Narrower than upstream, and deliberately so — CI covers **Linux with MySQL LTS (9.7, 8.4, 8.0)**, plus the two previous Go releases against the newest MySQL. Upstream additionally tests macOS and Windows runners and four MariaDB -versions. Block deploys none of those, so the fork drops them: 5 CI jobs rather -than 25, and no exposure to the Windows-runner TCP dial flake that upstream's -own CI also hits. Nothing about the driver is Linux- or MySQL-specific — the -platforms are merely untested here, so treat upstream as the authority on them. +versions. Block deploys none of those, so the fork drops them: 21 matrix +combinations become 3 (5 test jobs rather than 23, counting the two appended +older-Go entries), and no exposure to the Windows-runner TCP dial flake that +upstream's own CI also hits. Nothing about the driver is Linux- or +MySQL-specific — the platforms are merely untested here, so treat upstream as +the authority on them. ## License @@ -652,14 +665,14 @@ See [context support in the database/sql package](https://golang.org/doc/go1.8#d ### `LOAD DATA LOCAL INFILE` support For this feature you need direct access to the package. Therefore you must change the import path (no `_`): ```go -import "github.com/go-sql-driver/mysql" +import "github.com/block/mysql" ``` Files must be explicitly allowed by registering them with `mysql.RegisterLocalFile(filepath)` (recommended) or the allowlist check must be deactivated by using the DSN parameter `allowAllFiles=true` ([*Might be insecure!*](https://dev.mysql.com/doc/refman/8.0/en/load-data.html#load-data-local)). To use a `io.Reader` a handler function must be registered with `mysql.RegisterReaderHandler(name, handler)` which returns a `io.Reader` or `io.ReadCloser`. The Reader is available with the filepath `Reader::` then. Choose different names for different handlers and `DeregisterReaderHandler` when you don't need it anymore. -See the [godoc of Go-MySQL-Driver](https://godoc.org/github.com/go-sql-driver/mysql "golang mysql driver documentation") for details. +See the [godoc of this fork](https://pkg.go.dev/github.com/block/mysql "golang mysql driver documentation") for details. ### `time.Time` support diff --git a/fork_test.go b/fork_test.go new file mode 100644 index 000000000..c75897e08 --- /dev/null +++ b/fork_test.go @@ -0,0 +1,54 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2026 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +package mysql + +import ( + "database/sql" + rtdebug "runtime/debug" // aliased: const.go declares a package-level `debug` + "slices" + "testing" +) + +// forkModulePath and forkDriverName are the two values that make this a fork +// rather than a vendored copy. See README.md. +const ( + forkModulePath = "github.com/block/mysql" + forkDriverName = "block-mysql" +) + +// TestForkIdentity pins the module path and the registered driver name. +// +// Neither is observable from any other test: no file in the package imports its +// own module path, and every test opens `driverNameTest`, which defaults to +// whatever `driverName` holds — so reverting either value builds clean and +// passes the suite. That matters because these are exactly the two lines the +// documented `git merge upstream/master` workflow puts a conflict on every +// time, and reverting either is silent: the module path reintroduces the +// substitutability problem the fork exists to prevent (`replace` is not +// inherited across module boundaries), and the driver name reintroduces the +// duplicate-`sql.Register` panic for consumers who link both drivers. +func TestForkIdentity(t *testing.T) { + // Main.Path reads the real go.mod of the module under test, not a copy of + // the string kept somewhere in the package. + bi, ok := rtdebug.ReadBuildInfo() + if !ok { + t.Fatal("runtime/debug.ReadBuildInfo() failed; cannot verify the module path") + } + if bi.Main.Path != forkModulePath { + t.Errorf("module path is %q, want %q — a fork of go-sql-driver/mysql needs its own module path, "+ + "or downstream modules silently link upstream instead (a `replace` is main-module-only)", + bi.Main.Path, forkModulePath) + } + + if !slices.Contains(sql.Drivers(), forkDriverName) { + t.Errorf("registered drivers are %q, want one named %q — under upstream's name, any binary that also "+ + "links go-sql-driver panics in init on the duplicate sql.Register", + sql.Drivers(), forkDriverName) + } +}