summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/go-sql-driver/mysql/driver_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/go-sql-driver/mysql/driver_test.go')
-rw-r--r--vendor/github.com/go-sql-driver/mysql/driver_test.go308
1 files changed, 212 insertions, 96 deletions
diff --git a/vendor/github.com/go-sql-driver/mysql/driver_test.go b/vendor/github.com/go-sql-driver/mysql/driver_test.go
index 78e68f5d0..7877aa979 100644
--- a/vendor/github.com/go-sql-driver/mysql/driver_test.go
+++ b/vendor/github.com/go-sql-driver/mysql/driver_test.go
@@ -27,6 +27,12 @@ import (
"time"
)
+// Ensure that all the driver interfaces are implemented
+var (
+ _ driver.Rows = &binaryRows{}
+ _ driver.Rows = &textRows{}
+)
+
var (
user string
pass string
@@ -63,7 +69,7 @@ func init() {
addr = env("MYSQL_TEST_ADDR", "localhost:3306")
dbname = env("MYSQL_TEST_DBNAME", "gotest")
netAddr = fmt.Sprintf("%s(%s)", prot, addr)
- dsn = fmt.Sprintf("%s:%s@%s/%s?timeout=30s&strict=true", user, pass, netAddr, dbname)
+ dsn = fmt.Sprintf("%s:%s@%s/%s?timeout=30s", user, pass, netAddr, dbname)
c, err := net.Dial(prot, addr)
if err == nil {
available = true
@@ -171,6 +177,17 @@ func (dbt *DBTest) mustQuery(query string, args ...interface{}) (rows *sql.Rows)
return rows
}
+func maybeSkip(t *testing.T, err error, skipErrno uint16) {
+ mySQLErr, ok := err.(*MySQLError)
+ if !ok {
+ return
+ }
+
+ if mySQLErr.Number == skipErrno {
+ t.Skipf("skipping test for error: %v", err)
+ }
+}
+
func TestEmptyQuery(t *testing.T) {
runTests(t, dsn, func(dbt *DBTest) {
// just a comment, no query
@@ -482,6 +499,85 @@ func TestString(t *testing.T) {
})
}
+type testValuer struct {
+ value string
+}
+
+func (tv testValuer) Value() (driver.Value, error) {
+ return tv.value, nil
+}
+
+func TestValuer(t *testing.T) {
+ runTests(t, dsn, func(dbt *DBTest) {
+ in := testValuer{"a_value"}
+ var out string
+ var rows *sql.Rows
+
+ dbt.mustExec("CREATE TABLE test (value VARCHAR(255)) CHARACTER SET utf8")
+ dbt.mustExec("INSERT INTO test VALUES (?)", in)
+ rows = dbt.mustQuery("SELECT value FROM test")
+ if rows.Next() {
+ rows.Scan(&out)
+ if in.value != out {
+ dbt.Errorf("Valuer: %v != %s", in, out)
+ }
+ } else {
+ dbt.Errorf("Valuer: no data")
+ }
+
+ dbt.mustExec("DROP TABLE IF EXISTS test")
+ })
+}
+
+type testValuerWithValidation struct {
+ value string
+}
+
+func (tv testValuerWithValidation) Value() (driver.Value, error) {
+ if len(tv.value) == 0 {
+ return nil, fmt.Errorf("Invalid string valuer. Value must not be empty")
+ }
+
+ return tv.value, nil
+}
+
+func TestValuerWithValidation(t *testing.T) {
+ runTests(t, dsn, func(dbt *DBTest) {
+ in := testValuerWithValidation{"a_value"}
+ var out string
+ var rows *sql.Rows
+
+ dbt.mustExec("CREATE TABLE testValuer (value VARCHAR(255)) CHARACTER SET utf8")
+ dbt.mustExec("INSERT INTO testValuer VALUES (?)", in)
+
+ rows = dbt.mustQuery("SELECT value FROM testValuer")
+ defer rows.Close()
+
+ if rows.Next() {
+ rows.Scan(&out)
+ if in.value != out {
+ dbt.Errorf("Valuer: %v != %s", in, out)
+ }
+ } else {
+ dbt.Errorf("Valuer: no data")
+ }
+
+ if _, err := dbt.db.Exec("INSERT INTO testValuer VALUES (?)", testValuerWithValidation{""}); err == nil {
+ dbt.Errorf("Failed to check valuer error")
+ }
+
+ if _, err := dbt.db.Exec("INSERT INTO testValuer VALUES (?)", nil); err != nil {
+ dbt.Errorf("Failed to check nil")
+ }
+
+ if _, err := dbt.db.Exec("INSERT INTO testValuer VALUES (?)", map[string]bool{}); err == nil {
+ dbt.Errorf("Failed to check not valuer")
+ }
+
+ dbt.mustExec("DROP TABLE IF EXISTS testValuer")
+ })
+}
+
type timeTests struct {
dbtype string
tlayout string
@@ -684,7 +780,7 @@ func TestDateTime(t *testing.T) {
for _, setup := range setups.tests {
allowBinTime := true
if setup.s == "" {
- // fill time string whereever Go can reliable produce it
+ // fill time string wherever Go can reliable produce it
setup.s = setup.t.Format(setups.tlayout)
} else if setup.s[0] == '!' {
// skip tests using setup.t as source in queries
@@ -856,14 +952,14 @@ func TestNULL(t *testing.T) {
dbt.Fatal(err)
}
if b != nil {
- dbt.Error("non-nil []byte wich should be nil")
+ dbt.Error("non-nil []byte which should be nil")
}
// Read non-nil
if err = nonNullStmt.QueryRow().Scan(&b); err != nil {
dbt.Fatal(err)
}
if b == nil {
- dbt.Error("nil []byte wich should be non-nil")
+ dbt.Error("nil []byte which should be non-nil")
}
// Insert nil
b = nil
@@ -953,7 +1049,7 @@ func TestUint64(t *testing.T) {
}
func TestLongData(t *testing.T) {
- runTests(t, dsn, func(dbt *DBTest) {
+ runTests(t, dsn+"&maxAllowedPacket=0", func(dbt *DBTest) {
var maxAllowedPacketSize int
err := dbt.db.QueryRow("select @@max_allowed_packet").Scan(&maxAllowedPacketSize)
if err != nil {
@@ -1054,22 +1150,36 @@ func TestLoadData(t *testing.T) {
dbt.Fatalf("rows count mismatch. Got %d, want 4", i)
}
}
+
+ dbt.db.Exec("DROP TABLE IF EXISTS test")
+ dbt.mustExec("CREATE TABLE test (id INT NOT NULL PRIMARY KEY, value TEXT NOT NULL) CHARACTER SET utf8")
+
+ // Local File
file, err := ioutil.TempFile("", "gotest")
defer os.Remove(file.Name())
if err != nil {
dbt.Fatal(err)
}
- file.WriteString("1\ta string\n2\ta string containing a \\t\n3\ta string containing a \\n\n4\ta string containing both \\t\\n\n")
- file.Close()
+ RegisterLocalFile(file.Name())
- dbt.db.Exec("DROP TABLE IF EXISTS test")
- dbt.mustExec("CREATE TABLE test (id INT NOT NULL PRIMARY KEY, value TEXT NOT NULL) CHARACTER SET utf8")
+ // Try first with empty file
+ dbt.mustExec(fmt.Sprintf("LOAD DATA LOCAL INFILE %q INTO TABLE test", file.Name()))
+ var count int
+ err = dbt.db.QueryRow("SELECT COUNT(*) FROM test").Scan(&count)
+ if err != nil {
+ dbt.Fatal(err.Error())
+ }
+ if count != 0 {
+ dbt.Fatalf("unexpected row count: got %d, want 0", count)
+ }
- // Local File
- RegisterLocalFile(file.Name())
+ // Then fille File with data and try to load it
+ file.WriteString("1\ta string\n2\ta string containing a \\t\n3\ta string containing a \\n\n4\ta string containing both \\t\\n\n")
+ file.Close()
dbt.mustExec(fmt.Sprintf("LOAD DATA LOCAL INFILE %q INTO TABLE test", file.Name()))
verifyLoadDataResult()
- // negative test
+
+ // Try with non-existing file
_, err = dbt.db.Exec("LOAD DATA LOCAL INFILE 'doesnotexist' INTO TABLE test")
if err == nil {
dbt.Fatal("load non-existent file didn't fail")
@@ -1145,84 +1255,6 @@ func TestFoundRows(t *testing.T) {
})
}
-func TestStrict(t *testing.T) {
- // ALLOW_INVALID_DATES to get rid of stricter modes - we want to test for warnings, not errors
- relaxedDsn := dsn + "&sql_mode='ALLOW_INVALID_DATES,NO_AUTO_CREATE_USER'"
- // make sure the MySQL version is recent enough with a separate connection
- // before running the test
- conn, err := MySQLDriver{}.Open(relaxedDsn)
- if conn != nil {
- conn.Close()
- }
- if me, ok := err.(*MySQLError); ok && me.Number == 1231 {
- // Error 1231: Variable 'sql_mode' can't be set to the value of 'ALLOW_INVALID_DATES'
- // => skip test, MySQL server version is too old
- return
- }
- runTests(t, relaxedDsn, func(dbt *DBTest) {
- dbt.mustExec("CREATE TABLE test (a TINYINT NOT NULL, b CHAR(4))")
-
- var queries = [...]struct {
- in string
- codes []string
- }{
- {"DROP TABLE IF EXISTS no_such_table", []string{"1051"}},
- {"INSERT INTO test VALUES(10,'mysql'),(NULL,'test'),(300,'Open Source')", []string{"1265", "1048", "1264", "1265"}},
- }
- var err error
-
- var checkWarnings = func(err error, mode string, idx int) {
- if err == nil {
- dbt.Errorf("expected STRICT error on query [%s] %s", mode, queries[idx].in)
- }
-
- if warnings, ok := err.(MySQLWarnings); ok {
- var codes = make([]string, len(warnings))
- for i := range warnings {
- codes[i] = warnings[i].Code
- }
- if len(codes) != len(queries[idx].codes) {
- dbt.Errorf("unexpected STRICT error count on query [%s] %s: Wanted %v, Got %v", mode, queries[idx].in, queries[idx].codes, codes)
- }
-
- for i := range warnings {
- if codes[i] != queries[idx].codes[i] {
- dbt.Errorf("unexpected STRICT error codes on query [%s] %s: Wanted %v, Got %v", mode, queries[idx].in, queries[idx].codes, codes)
- return
- }
- }
-
- } else {
- dbt.Errorf("unexpected error on query [%s] %s: %s", mode, queries[idx].in, err.Error())
- }
- }
-
- // text protocol
- for i := range queries {
- _, err = dbt.db.Exec(queries[i].in)
- checkWarnings(err, "text", i)
- }
-
- var stmt *sql.Stmt
-
- // binary protocol
- for i := range queries {
- stmt, err = dbt.db.Prepare(queries[i].in)
- if err != nil {
- dbt.Errorf("error on preparing query %s: %s", queries[i].in, err.Error())
- }
-
- _, err = stmt.Exec()
- checkWarnings(err, "binary", i)
-
- err = stmt.Close()
- if err != nil {
- dbt.Errorf("error on closing stmt for query %s: %s", queries[i].in, err.Error())
- }
- }
- })
-}
-
func TestTLS(t *testing.T) {
tlsTest := func(dbt *DBTest) {
if err := dbt.db.Ping(); err != nil {
@@ -1422,7 +1454,6 @@ func TestTimezoneConversion(t *testing.T) {
// Regression test for timezone handling
tzTest := func(dbt *DBTest) {
-
// Create table
dbt.mustExec("CREATE TABLE test (ts TIMESTAMP)")
@@ -1638,8 +1669,9 @@ func TestStmtMultiRows(t *testing.T) {
// Regression test for
// * more than 32 NULL parameters (issue 209)
// * more parameters than fit into the buffer (issue 201)
+// * parameters * 64 > max_allowed_packet (issue 734)
func TestPreparedManyCols(t *testing.T) {
- const numParams = defaultBufSize
+ numParams := 65535
runTests(t, dsn, func(dbt *DBTest) {
query := "SELECT ?" + strings.Repeat(",?", numParams-1)
stmt, err := dbt.db.Prepare(query)
@@ -1647,15 +1679,25 @@ func TestPreparedManyCols(t *testing.T) {
dbt.Fatal(err)
}
defer stmt.Close()
+
// create more parameters than fit into the buffer
// which will take nil-values
params := make([]interface{}, numParams)
rows, err := stmt.Query(params...)
if err != nil {
- stmt.Close()
dbt.Fatal(err)
}
- defer rows.Close()
+ rows.Close()
+
+ // Create 0byte string which we can't send via STMT_LONG_DATA.
+ for i := 0; i < numParams; i++ {
+ params[i] = ""
+ }
+ rows, err = stmt.Query(params...)
+ if err != nil {
+ dbt.Fatal(err)
+ }
+ rows.Close()
})
}
@@ -1739,7 +1781,7 @@ func TestCustomDial(t *testing.T) {
return net.Dial(prot, addr)
})
- db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@mydial(%s)/%s?timeout=30s&strict=true", user, pass, addr, dbname))
+ db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@mydial(%s)/%s?timeout=30s", user, pass, addr, dbname))
if err != nil {
t.Fatalf("error connecting: %s", err.Error())
}
@@ -1836,7 +1878,7 @@ func TestUnixSocketAuthFail(t *testing.T) {
}
}
t.Logf("socket: %s", socket)
- badDSN := fmt.Sprintf("%s:%s@unix(%s)/%s?timeout=30s&strict=true", user, badPass, socket, dbname)
+ badDSN := fmt.Sprintf("%s:%s@unix(%s)/%s?timeout=30s", user, badPass, socket, dbname)
db, err := sql.Open("mysql", badDSN)
if err != nil {
t.Fatalf("error connecting: %s", err.Error())
@@ -1902,3 +1944,77 @@ func TestInterruptBySignal(t *testing.T) {
}
})
}
+
+func TestColumnsReusesSlice(t *testing.T) {
+ rows := mysqlRows{
+ rs: resultSet{
+ columns: []mysqlField{
+ {
+ tableName: "test",
+ name: "A",
+ },
+ {
+ tableName: "test",
+ name: "B",
+ },
+ },
+ },
+ }
+
+ allocs := testing.AllocsPerRun(1, func() {
+ cols := rows.Columns()
+
+ if len(cols) != 2 {
+ t.Fatalf("expected 2 columns, got %d", len(cols))
+ }
+ })
+
+ if allocs != 0 {
+ t.Fatalf("expected 0 allocations, got %d", int(allocs))
+ }
+
+ if rows.rs.columnNames == nil {
+ t.Fatalf("expected columnNames to be set, got nil")
+ }
+}
+
+func TestRejectReadOnly(t *testing.T) {
+ runTests(t, dsn, func(dbt *DBTest) {
+ // Create Table
+ dbt.mustExec("CREATE TABLE test (value BOOL)")
+ // Set the session to read-only. We didn't set the `rejectReadOnly`
+ // option, so any writes after this should fail.
+ _, err := dbt.db.Exec("SET SESSION TRANSACTION READ ONLY")
+ // Error 1193: Unknown system variable 'TRANSACTION' => skip test,
+ // MySQL server version is too old
+ maybeSkip(t, err, 1193)
+ if _, err := dbt.db.Exec("DROP TABLE test"); err == nil {
+ t.Fatalf("writing to DB in read-only session without " +
+ "rejectReadOnly did not error")
+ }
+ // Set the session back to read-write so runTests() can properly clean
+ // up the table `test`.
+ dbt.mustExec("SET SESSION TRANSACTION READ WRITE")
+ })
+
+ // Enable the `rejectReadOnly` option.
+ runTests(t, dsn+"&rejectReadOnly=true", func(dbt *DBTest) {
+ // Create Table
+ dbt.mustExec("CREATE TABLE test (value BOOL)")
+ // Set the session to read only. Any writes after this should error on
+ // a driver.ErrBadConn, and cause `database/sql` to initiate a new
+ // connection.
+ dbt.mustExec("SET SESSION TRANSACTION READ ONLY")
+ // This would error, but `database/sql` should automatically retry on a
+ // new connection which is not read-only, and eventually succeed.
+ dbt.mustExec("DROP TABLE test")
+ })
+}
+
+func TestPing(t *testing.T) {
+ runTests(t, dsn, func(dbt *DBTest) {
+ if err := dbt.db.Ping(); err != nil {
+ dbt.fail("Ping", "Ping", err)
+ }
+ })
+}