Closed
Description
The strict
parameter is not using the MySQL strict mode, just returning errors when mysql throws a warning. This is extremely dangerous behavior that can lead to data corruption.
MySQL has a strict mode that should be used for this: https://dev.mysql.com/doc/refman/5.6/en/sql-mode.html#sql-mode-strict
For example:
package main
import (
"database/sql"
"fmt"
"os"
"time"
_ "github.com/go-sql-driver/mysql"
)
/*
CREATE DATABASE test;
use test;
CREATE TABLE test (
id BIGINT NOT NULL PRIMARY KEY,
value VARCHAR(4)
);
*/
func main() {
db, err := sql.Open("mysql", "root:root@tcp(localhost:3306)/test?strict=true")
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
// show some stuff to confirm we aren't using any STRICT modes
row := db.QueryRow("show variables like 'sql_mode'")
var varname string
var sql_mode string
err = row.Scan(&varname, &sql_mode)
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
fmt.Printf("sql_mode=%q\n", sql_mode)
row = db.QueryRow("select @@GLOBAL.sql_mode")
err = row.Scan(&sql_mode)
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
fmt.Printf("@@GLOBAL.sql_mode=%q\n", sql_mode)
// now perform the test
id := time.Now().UnixNano()
value := "1234567890"
_, err = db.Exec("insert into test (id, value) values (?,?)", id, value)
fmt.Printf("Insert error: %v\n", err)
row = db.QueryRow("select value from test where id=?", id)
err = row.Scan(&value)
fmt.Printf("Select error: %v\n", err)
fmt.Printf("Selected value: %q\n", value)
}
Which results in:
sql_mode="NO_ENGINE_SUBSTITUTION"
@@GLOBAL.sql_mode="NO_ENGINE_SUBSTITUTION"
Insert error: Warning 1265: Data truncated for column 'value' at row 1
Select error: <nil>
Selected value: "1234"
As you can see, the INSERT
threw an error, but the insert was actually performed. I now have this row in my database that I'm not expecting to be there.
If this had been an UPDATE
, I could have overwritten valid data with now invalid, truncated, data.