Skip to content

Commit 21f614e

Browse files
committed
Verify server response cap flags to fail earlier
1 parent 89bdedf commit 21f614e

File tree

5 files changed

+38
-24
lines changed

5 files changed

+38
-24
lines changed

connection.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ func (mc *mysqlConn) readIgnoreColumns(rows *textRows, resLen int) (*textRows, e
417417
rows.rs.columnNames = make([]string, resLen)
418418
return rows, nil
419419
}
420-
return nil, ErrOptionalResultSet
420+
return nil, ErrOptionalResultSetPkt
421421
}
422422

423423
// Gets the value of the given MySQL System Variable

connector.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ func (c *connector) Connect(ctx context.Context) (driver.Conn, error) {
143143
mc.resultSetMetadata = resultSetMetadataFull
144144
default:
145145
mc.Close()
146-
return nil, ErrOptionalResultSet
146+
return nil, ErrOptionalResultSetPkt
147147
}
148148
}
149149

driver_test.go

+11-6
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ func (dbt *DBTest) mustQuery(query string, args ...interface{}) (rows *sql.Rows)
202202
func maybeSkip(t *testing.T, err error, skipErrno uint16) {
203203
mySQLErr, ok := err.(*MySQLError)
204204
if !ok {
205+
errLog.Print("non match")
205206
return
206207
}
207208

@@ -1348,9 +1349,11 @@ func TestFoundRows(t *testing.T) {
13481349
func TestOptionalResultSetMetadata(t *testing.T) {
13491350
runTests(t, dsn+"&resultSetMetadata=none", func(dbt *DBTest) {
13501351
_, err := dbt.db.Exec("CREATE TABLE test (id INT NOT NULL ,data INT NOT NULL)")
1351-
// Error 1193: Unknown system variable 'resultset_metadata' => skip test,
1352-
// MySQL server version is too old
1353-
maybeSkip(t, err, 1193)
1352+
if err == ErrNoOptionalResultSet {
1353+
t.Skip("server does not support resultset metadata")
1354+
} else {
1355+
dbt.Fatal(err)
1356+
}
13541357
dbt.mustExec("INSERT INTO test (id, data) VALUES (0, 0),(0, 0),(1, 0),(1, 0),(1, 1)")
13551358

13561359
row := dbt.db.QueryRow("SELECT id, data FROM test WHERE id = 1")
@@ -1366,9 +1369,11 @@ func TestOptionalResultSetMetadata(t *testing.T) {
13661369
})
13671370
runTests(t, dsn+"&resultSetMetadata=full", func(dbt *DBTest) {
13681371
_, err := dbt.db.Exec("CREATE TABLE test (id INT NOT NULL ,data INT NOT NULL)")
1369-
// Error 1193: Unknown system variable 'resultset_metadata' => skip test,
1370-
// MySQL server version is too old
1371-
maybeSkip(t, err, 1193)
1372+
if err == ErrNoOptionalResultSet {
1373+
t.Skip("server does not support resultset metadata")
1374+
} else {
1375+
dbt.Fatal(err)
1376+
}
13721377
dbt.mustExec("INSERT INTO test (id, data) VALUES (0, 0),(0, 0),(1, 0),(1, 0),(1, 1)")
13731378

13741379
row := dbt.db.QueryRow("SELECT id, data FROM test WHERE id = 1")

errors.go

+14-13
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,20 @@ import (
1717

1818
// Various errors the driver might return. Can change between driver versions.
1919
var (
20-
ErrInvalidConn = errors.New("invalid connection")
21-
ErrMalformPkt = errors.New("malformed packet")
22-
ErrNoTLS = errors.New("TLS requested but server does not support TLS")
23-
ErrCleartextPassword = errors.New("this user requires clear text authentication. If you still want to use it, please add 'allowCleartextPasswords=1' to your DSN")
24-
ErrNativePassword = errors.New("this user requires mysql native password authentication")
25-
ErrOldPassword = errors.New("this user requires old password authentication. If you still want to use it, please add 'allowOldPasswords=1' to your DSN. See also https://github.com/go-sql-driver/mysql/wiki/old_passwords")
26-
ErrUnknownPlugin = errors.New("this authentication plugin is not supported")
27-
ErrOldProtocol = errors.New("MySQL server does not support required protocol 41+")
28-
ErrPktSync = errors.New("commands out of sync. You can't run this command now")
29-
ErrPktSyncMul = errors.New("commands out of sync. Did you run multiple statements at once?")
30-
ErrPktTooLarge = errors.New("packet for query is too large. Try adjusting the 'max_allowed_packet' variable on the server")
31-
ErrBusyBuffer = errors.New("busy buffer")
32-
ErrOptionalResultSet = errors.New("malformed optional resultset metadata packets")
20+
ErrInvalidConn = errors.New("invalid connection")
21+
ErrMalformPkt = errors.New("malformed packet")
22+
ErrNoTLS = errors.New("TLS requested but server does not support TLS")
23+
ErrCleartextPassword = errors.New("this user requires clear text authentication. If you still want to use it, please add 'allowCleartextPasswords=1' to your DSN")
24+
ErrNativePassword = errors.New("this user requires mysql native password authentication")
25+
ErrOldPassword = errors.New("this user requires old password authentication. If you still want to use it, please add 'allowOldPasswords=1' to your DSN. See also https://github.com/go-sql-driver/mysql/wiki/old_passwords")
26+
ErrUnknownPlugin = errors.New("this authentication plugin is not supported")
27+
ErrOldProtocol = errors.New("MySQL server does not support required protocol 41+")
28+
ErrPktSync = errors.New("commands out of sync. You can't run this command now")
29+
ErrPktSyncMul = errors.New("commands out of sync. Did you run multiple statements at once?")
30+
ErrPktTooLarge = errors.New("packet for query is too large. Try adjusting the 'max_allowed_packet' variable on the server")
31+
ErrBusyBuffer = errors.New("busy buffer")
32+
ErrNoOptionalResultSet = errors.New("requested optional resultset metadata but server does not support")
33+
ErrOptionalResultSetPkt = errors.New("malformed optional resultset metadata packets")
3334

3435
// errBadConnNoWrite is used for connection errors where nothing was sent to the database yet.
3536
// If this happens first in a function starting a database interaction, it should be replaced by driver.ErrBadConn

packets.go

+11-3
Original file line numberDiff line numberDiff line change
@@ -235,10 +235,18 @@ func (mc *mysqlConn) readHandshakePacket() (data []byte, plugin string, err erro
235235
if len(data) > pos {
236236
// character set [1 byte]
237237
// status flags [2 bytes]
238+
pos += 1 + 2
238239
// capability flags (upper 2 bytes) [2 bytes]
240+
upperFlags := clientFlag(binary.LittleEndian.Uint16(data[pos : pos+2]))
241+
mc.flags |= upperFlags << 16
242+
pos += 2
243+
if mc.flags&clientOptionalResultSetMetadata == 0 && mc.cfg.ResultSetMetadata != "" {
244+
return nil, "", ErrNoOptionalResultSet
245+
}
246+
239247
// length of auth-plugin-data [1 byte]
240248
// reserved (all [00]) [10 bytes]
241-
pos += 1 + 2 + 2 + 1 + 10
249+
pos += 1 + 10
242250

243251
// second part of the password cipher [mininum 13 bytes],
244252
// where len=MAX(13, length of auth-plugin-data - 8)
@@ -562,10 +570,10 @@ func (mc *mysqlConn) readResultSetHeaderPacket() (int, error) {
562570
// Sniff one extra byte for resultset metadata if we set capability
563571
// CLIENT_OPTIONAL_RESULTSET_METADTA
564572
// https://dev.mysql.com/worklog/task/?id=8134
565-
if len(data) == 2 {
573+
if len(data) == 2 && mc.flags&clientOptionalResultSetMetadata != 0 {
566574
// ResultSet metadata flag check
567575
if mc.resultSetMetadata != data[1] {
568-
return 0, ErrOptionalResultSet
576+
return 0, ErrOptionalResultSetPkt
569577
}
570578
return int(num), nil
571579
}

0 commit comments

Comments
 (0)