Skip to content

Strict mode not actually strict #376

Closed
@phemmer

Description

@phemmer

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions