Skip to content

Commit a8b7ed4

Browse files
Remove strict mode (go-sql-driver#676)
* Remove strict mode Fixes go-sql-driver#556 go-sql-driver#602 go-sql-driver#635 Closes go-sql-driver#609 * dsn: panic in case of strict mode
1 parent 7785c74 commit a8b7ed4

8 files changed

+7
-202
lines changed

README.md

+2-14
Original file line numberDiff line numberDiff line change
@@ -294,20 +294,6 @@ supposed to happen, setting this on some MySQL providers (such as AWS Aurora)
294294
is safer for failovers.
295295

296296

297-
##### `strict`
298-
299-
```
300-
Type: bool
301-
Valid Values: true, false
302-
Default: false
303-
```
304-
305-
`strict=true` enables a driver-side strict mode in which MySQL warnings are treated as errors. This mode should not be used in production as it may lead to data corruption in certain situations.
306-
307-
A server-side strict mode, which is safe for production use, can be set via the [`sql_mode`](https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html) system variable.
308-
309-
By default MySQL also treats notes as warnings. Use [`sql_notes=false`](http://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_sql_notes) to ignore notes.
310-
311297
##### `timeout`
312298

313299
```
@@ -317,6 +303,7 @@ Default: OS default
317303

318304
Timeout for establishing connections, aka dial timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*.
319305

306+
320307
##### `tls`
321308

322309
```
@@ -327,6 +314,7 @@ Default: false
327314

328315
`tls=true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side). Use a custom value registered with [`mysql.RegisterTLSConfig`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig).
329316

317+
330318
##### `writeTimeout`
331319

332320
```

benchmark_test.go

+1-5
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,7 @@ func initDB(b *testing.B, queries ...string) *sql.DB {
4848
db := tb.checkDB(sql.Open("mysql", dsn))
4949
for _, query := range queries {
5050
if _, err := db.Exec(query); err != nil {
51-
if w, ok := err.(MySQLWarnings); ok {
52-
b.Logf("warning on %q: %v", query, w)
53-
} else {
54-
b.Fatalf("error on %q: %v", query, err)
55-
}
51+
b.Fatalf("error on %q: %v", query, err)
5652
}
5753
}
5854
return db

connection.go

-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ type mysqlConn struct {
4040
status statusFlag
4141
sequence uint8
4242
parseTime bool
43-
strict bool
4443

4544
// for context support (Go 1.8+)
4645
watching bool

driver.go

-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
6464
return nil, err
6565
}
6666
mc.parseTime = mc.cfg.ParseTime
67-
mc.strict = mc.cfg.Strict
6867

6968
// Connect to Server
7069
if dial, ok := dials[mc.cfg.Net]; ok {

driver_test.go

+3-79
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func init() {
6363
addr = env("MYSQL_TEST_ADDR", "localhost:3306")
6464
dbname = env("MYSQL_TEST_DBNAME", "gotest")
6565
netAddr = fmt.Sprintf("%s(%s)", prot, addr)
66-
dsn = fmt.Sprintf("%s:%s@%s/%s?timeout=30s&strict=true", user, pass, netAddr, dbname)
66+
dsn = fmt.Sprintf("%s:%s@%s/%s?timeout=30s", user, pass, netAddr, dbname)
6767
c, err := net.Dial(prot, addr)
6868
if err == nil {
6969
available = true
@@ -1170,82 +1170,6 @@ func TestFoundRows(t *testing.T) {
11701170
})
11711171
}
11721172

1173-
func TestStrict(t *testing.T) {
1174-
// ALLOW_INVALID_DATES to get rid of stricter modes - we want to test for warnings, not errors
1175-
relaxedDsn := dsn + "&sql_mode='ALLOW_INVALID_DATES,NO_AUTO_CREATE_USER'"
1176-
// make sure the MySQL version is recent enough with a separate connection
1177-
// before running the test
1178-
conn, err := MySQLDriver{}.Open(relaxedDsn)
1179-
if conn != nil {
1180-
conn.Close()
1181-
}
1182-
// Error 1231: Variable 'sql_mode' can't be set to the value of
1183-
// 'ALLOW_INVALID_DATES' => skip test, MySQL server version is too old
1184-
maybeSkip(t, err, 1231)
1185-
runTests(t, relaxedDsn, func(dbt *DBTest) {
1186-
dbt.mustExec("CREATE TABLE test (a TINYINT NOT NULL, b CHAR(4))")
1187-
1188-
var queries = [...]struct {
1189-
in string
1190-
codes []string
1191-
}{
1192-
{"DROP TABLE IF EXISTS no_such_table", []string{"1051"}},
1193-
{"INSERT INTO test VALUES(10,'mysql'),(NULL,'test'),(300,'Open Source')", []string{"1265", "1048", "1264", "1265"}},
1194-
}
1195-
var err error
1196-
1197-
var checkWarnings = func(err error, mode string, idx int) {
1198-
if err == nil {
1199-
dbt.Errorf("expected STRICT error on query [%s] %s", mode, queries[idx].in)
1200-
}
1201-
1202-
if warnings, ok := err.(MySQLWarnings); ok {
1203-
var codes = make([]string, len(warnings))
1204-
for i := range warnings {
1205-
codes[i] = warnings[i].Code
1206-
}
1207-
if len(codes) != len(queries[idx].codes) {
1208-
dbt.Errorf("unexpected STRICT error count on query [%s] %s: Wanted %v, Got %v", mode, queries[idx].in, queries[idx].codes, codes)
1209-
}
1210-
1211-
for i := range warnings {
1212-
if codes[i] != queries[idx].codes[i] {
1213-
dbt.Errorf("unexpected STRICT error codes on query [%s] %s: Wanted %v, Got %v", mode, queries[idx].in, queries[idx].codes, codes)
1214-
return
1215-
}
1216-
}
1217-
1218-
} else {
1219-
dbt.Errorf("unexpected error on query [%s] %s: %s", mode, queries[idx].in, err.Error())
1220-
}
1221-
}
1222-
1223-
// text protocol
1224-
for i := range queries {
1225-
_, err = dbt.db.Exec(queries[i].in)
1226-
checkWarnings(err, "text", i)
1227-
}
1228-
1229-
var stmt *sql.Stmt
1230-
1231-
// binary protocol
1232-
for i := range queries {
1233-
stmt, err = dbt.db.Prepare(queries[i].in)
1234-
if err != nil {
1235-
dbt.Errorf("error on preparing query %s: %s", queries[i].in, err.Error())
1236-
}
1237-
1238-
_, err = stmt.Exec()
1239-
checkWarnings(err, "binary", i)
1240-
1241-
err = stmt.Close()
1242-
if err != nil {
1243-
dbt.Errorf("error on closing stmt for query %s: %s", queries[i].in, err.Error())
1244-
}
1245-
}
1246-
})
1247-
}
1248-
12491173
func TestTLS(t *testing.T) {
12501174
tlsTest := func(dbt *DBTest) {
12511175
if err := dbt.db.Ping(); err != nil {
@@ -1762,7 +1686,7 @@ func TestCustomDial(t *testing.T) {
17621686
return net.Dial(prot, addr)
17631687
})
17641688

1765-
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@mydial(%s)/%s?timeout=30s&strict=true", user, pass, addr, dbname))
1689+
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@mydial(%s)/%s?timeout=30s", user, pass, addr, dbname))
17661690
if err != nil {
17671691
t.Fatalf("error connecting: %s", err.Error())
17681692
}
@@ -1859,7 +1783,7 @@ func TestUnixSocketAuthFail(t *testing.T) {
18591783
}
18601784
}
18611785
t.Logf("socket: %s", socket)
1862-
badDSN := fmt.Sprintf("%s:%s@unix(%s)/%s?timeout=30s&strict=true", user, badPass, socket, dbname)
1786+
badDSN := fmt.Sprintf("%s:%s@unix(%s)/%s?timeout=30s", user, badPass, socket, dbname)
18631787
db, err := sql.Open("mysql", badDSN)
18641788
if err != nil {
18651789
t.Fatalf("error connecting: %s", err.Error())

dsn.go

+1-15
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ type Config struct {
5555
MultiStatements bool // Allow multiple statements in one query
5656
ParseTime bool // Parse time values to time.Time
5757
RejectReadOnly bool // Reject read-only connections
58-
Strict bool // Return warnings as errors
5958
}
6059

6160
// FormatDSN formats the given Config into a DSN string which can be passed to
@@ -206,15 +205,6 @@ func (cfg *Config) FormatDSN() string {
206205
}
207206
}
208207

209-
if cfg.Strict {
210-
if hasParam {
211-
buf.WriteString("&strict=true")
212-
} else {
213-
hasParam = true
214-
buf.WriteString("?strict=true")
215-
}
216-
}
217-
218208
if cfg.Timeout > 0 {
219209
if hasParam {
220210
buf.WriteString("&timeout=")
@@ -502,11 +492,7 @@ func parseDSNParams(cfg *Config, params string) (err error) {
502492

503493
// Strict mode
504494
case "strict":
505-
var isBool bool
506-
cfg.Strict, isBool = readBool(value)
507-
if !isBool {
508-
return errors.New("invalid bool value: " + value)
509-
}
495+
panic("strict mode has been removed. See https://github.com/go-sql-driver/mysql/wiki/strict-mode")
510496

511497
// Dial Timeout
512498
case "timeout":

errors.go

-73
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,8 @@
99
package mysql
1010

1111
import (
12-
"database/sql/driver"
1312
"errors"
1413
"fmt"
15-
"io"
1614
"log"
1715
"os"
1816
)
@@ -65,74 +63,3 @@ type MySQLError struct {
6563
func (me *MySQLError) Error() string {
6664
return fmt.Sprintf("Error %d: %s", me.Number, me.Message)
6765
}
68-
69-
// MySQLWarnings is an error type which represents a group of one or more MySQL
70-
// warnings
71-
type MySQLWarnings []MySQLWarning
72-
73-
func (mws MySQLWarnings) Error() string {
74-
var msg string
75-
for i, warning := range mws {
76-
if i > 0 {
77-
msg += "\r\n"
78-
}
79-
msg += fmt.Sprintf(
80-
"%s %s: %s",
81-
warning.Level,
82-
warning.Code,
83-
warning.Message,
84-
)
85-
}
86-
return msg
87-
}
88-
89-
// MySQLWarning is an error type which represents a single MySQL warning.
90-
// Warnings are returned in groups only. See MySQLWarnings
91-
type MySQLWarning struct {
92-
Level string
93-
Code string
94-
Message string
95-
}
96-
97-
func (mc *mysqlConn) getWarnings() (err error) {
98-
rows, err := mc.Query("SHOW WARNINGS", nil)
99-
if err != nil {
100-
return
101-
}
102-
103-
var warnings = MySQLWarnings{}
104-
var values = make([]driver.Value, 3)
105-
106-
for {
107-
err = rows.Next(values)
108-
switch err {
109-
case nil:
110-
warning := MySQLWarning{}
111-
112-
if raw, ok := values[0].([]byte); ok {
113-
warning.Level = string(raw)
114-
} else {
115-
warning.Level = fmt.Sprintf("%s", values[0])
116-
}
117-
if raw, ok := values[1].([]byte); ok {
118-
warning.Code = string(raw)
119-
} else {
120-
warning.Code = fmt.Sprintf("%s", values[1])
121-
}
122-
if raw, ok := values[2].([]byte); ok {
123-
warning.Message = string(raw)
124-
} else {
125-
warning.Message = fmt.Sprintf("%s", values[0])
126-
}
127-
128-
warnings = append(warnings, warning)
129-
130-
case io.EOF:
131-
return warnings
132-
133-
default:
134-
rows.Close()
135-
return
136-
}
137-
}
138-
}

packets.go

-14
Original file line numberDiff line numberDiff line change
@@ -624,14 +624,7 @@ func (mc *mysqlConn) handleOkPacket(data []byte) error {
624624
}
625625

626626
// warning count [2 bytes]
627-
if !mc.strict {
628-
return nil
629-
}
630627

631-
pos := 1 + n + m + 2
632-
if binary.LittleEndian.Uint16(data[pos:pos+2]) > 0 {
633-
return mc.getWarnings()
634-
}
635628
return nil
636629
}
637630

@@ -843,14 +836,7 @@ func (stmt *mysqlStmt) readPrepareResultPacket() (uint16, error) {
843836
// Reserved [8 bit]
844837

845838
// Warning count [16 bit uint]
846-
if !stmt.mc.strict {
847-
return columnCount, nil
848-
}
849839

850-
// Check for warnings count > 0, only available in MySQL > 4.1
851-
if len(data) >= 12 && binary.LittleEndian.Uint16(data[10:12]) > 0 {
852-
return columnCount, stmt.mc.getWarnings()
853-
}
854840
return columnCount, nil
855841
}
856842
return 0, err

0 commit comments

Comments
 (0)