From 502b3a1fd167f3aee0412f34b95fa6217688554a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20Eeden?= Date: Sat, 6 Dec 2025 13:32:12 +0100 Subject: [PATCH] mysql,client: add log for caps we can't set --- client/auth.go | 13 +++++++++ client/conn.go | 69 ++------------------------------------------- client/conn_test.go | 7 +++++ mysql/const.go | 35 +++++++++++++++++++++++ 4 files changed, 58 insertions(+), 66 deletions(-) diff --git a/client/auth.go b/client/auth.go index 1d2e45768..251899e0e 100644 --- a/client/auth.go +++ b/client/auth.go @@ -5,6 +5,7 @@ import ( "crypto/tls" "encoding/binary" "fmt" + "log/slog" "github.com/go-mysql-org/go-mysql/mysql" "github.com/go-mysql-org/go-mysql/packet" @@ -220,6 +221,18 @@ func (c *Conn) writeAuthHandshake() error { c.ccaps&mysql.CLIENT_COMPRESS | c.ccaps&mysql.CLIENT_ZSTD_COMPRESSION_ALGORITHM | c.ccaps&mysql.CLIENT_LOCAL_FILES + // Loop through the capability flags and see if there is any that was in `c.ccaps` (set by `SetCapability()` ) + // but that is not in `capability`. This happens when a user of this library tries to set a flag + // that we don't support. + for i := 0; i < 32; i++ { + capabilityNumber := uint32(1 << i) + if capname, ok := mysql.CapNames[capabilityNumber]; ok { + if (c.ccaps&capabilityNumber > 0) && (capability&capabilityNumber == 0) { + slog.Debug("capability specified but not set", "capability", capname) + } + } + } + capability &^= c.clientExplicitOffCaps // To enable TLS / SSL diff --git a/client/conn.go b/client/conn.go index d864fb970..367133853 100644 --- a/client/conn.go +++ b/client/conn.go @@ -581,72 +581,9 @@ func (c *Conn) CapabilityString() string { field := uint32(1 << bits.TrailingZeros32(capability)) capability ^= field - switch field { - case mysql.CLIENT_LONG_PASSWORD: - caps = append(caps, "CLIENT_LONG_PASSWORD") - case mysql.CLIENT_FOUND_ROWS: - caps = append(caps, "CLIENT_FOUND_ROWS") - case mysql.CLIENT_LONG_FLAG: - caps = append(caps, "CLIENT_LONG_FLAG") - case mysql.CLIENT_CONNECT_WITH_DB: - caps = append(caps, "CLIENT_CONNECT_WITH_DB") - case mysql.CLIENT_NO_SCHEMA: - caps = append(caps, "CLIENT_NO_SCHEMA") - case mysql.CLIENT_COMPRESS: - caps = append(caps, "CLIENT_COMPRESS") - case mysql.CLIENT_ODBC: - caps = append(caps, "CLIENT_ODBC") - case mysql.CLIENT_LOCAL_FILES: - caps = append(caps, "CLIENT_LOCAL_FILES") - case mysql.CLIENT_IGNORE_SPACE: - caps = append(caps, "CLIENT_IGNORE_SPACE") - case mysql.CLIENT_PROTOCOL_41: - caps = append(caps, "CLIENT_PROTOCOL_41") - case mysql.CLIENT_INTERACTIVE: - caps = append(caps, "CLIENT_INTERACTIVE") - case mysql.CLIENT_SSL: - caps = append(caps, "CLIENT_SSL") - case mysql.CLIENT_IGNORE_SIGPIPE: - caps = append(caps, "CLIENT_IGNORE_SIGPIPE") - case mysql.CLIENT_TRANSACTIONS: - caps = append(caps, "CLIENT_TRANSACTIONS") - case mysql.CLIENT_RESERVED: - caps = append(caps, "CLIENT_RESERVED") - case mysql.CLIENT_SECURE_CONNECTION: - caps = append(caps, "CLIENT_SECURE_CONNECTION") - case mysql.CLIENT_MULTI_STATEMENTS: - caps = append(caps, "CLIENT_MULTI_STATEMENTS") - case mysql.CLIENT_MULTI_RESULTS: - caps = append(caps, "CLIENT_MULTI_RESULTS") - case mysql.CLIENT_PS_MULTI_RESULTS: - caps = append(caps, "CLIENT_PS_MULTI_RESULTS") - case mysql.CLIENT_PLUGIN_AUTH: - caps = append(caps, "CLIENT_PLUGIN_AUTH") - case mysql.CLIENT_CONNECT_ATTRS: - caps = append(caps, "CLIENT_CONNECT_ATTRS") - case mysql.CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA: - caps = append(caps, "CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA") - case mysql.CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS: - caps = append(caps, "CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS") - case mysql.CLIENT_SESSION_TRACK: - caps = append(caps, "CLIENT_SESSION_TRACK") - case mysql.CLIENT_DEPRECATE_EOF: - caps = append(caps, "CLIENT_DEPRECATE_EOF") - case mysql.CLIENT_OPTIONAL_RESULTSET_METADATA: - caps = append(caps, "CLIENT_OPTIONAL_RESULTSET_METADATA") - case mysql.CLIENT_ZSTD_COMPRESSION_ALGORITHM: - caps = append(caps, "CLIENT_ZSTD_COMPRESSION_ALGORITHM") - case mysql.CLIENT_QUERY_ATTRIBUTES: - caps = append(caps, "CLIENT_QUERY_ATTRIBUTES") - case mysql.MULTI_FACTOR_AUTHENTICATION: - caps = append(caps, "MULTI_FACTOR_AUTHENTICATION") - case mysql.CLIENT_CAPABILITY_EXTENSION: - caps = append(caps, "CLIENT_CAPABILITY_EXTENSION") - case mysql.CLIENT_SSL_VERIFY_SERVER_CERT: - caps = append(caps, "CLIENT_SSL_VERIFY_SERVER_CERT") - case mysql.CLIENT_REMEMBER_OPTIONS: - caps = append(caps, "CLIENT_REMEMBER_OPTIONS") - default: + if capname, ok := mysql.CapNames[field]; ok { + caps = append(caps, capname) + } else { caps = append(caps, fmt.Sprintf("(%d)", field)) } } diff --git a/client/conn_test.go b/client/conn_test.go index 472558800..c0384fd41 100644 --- a/client/conn_test.go +++ b/client/conn_test.go @@ -237,3 +237,10 @@ func (s *connTestSuite) TestUseDB() { err = s.c.UseDB("test") require.NoError(s.T(), err) } + +func TestCapabilityString(t *testing.T) { + conn := Conn{ + capability: mysql.CLIENT_PROTOCOL_41 | mysql.CLIENT_DEPRECATE_EOF, + } + require.Equal(t, "CLIENT_PROTOCOL_41|CLIENT_DEPRECATE_EOF", conn.CapabilityString()) +} diff --git a/mysql/const.go b/mysql/const.go index 2883a06b9..d8f859687 100644 --- a/mysql/const.go +++ b/mysql/const.go @@ -122,6 +122,41 @@ const ( CLIENT_REMEMBER_OPTIONS ) +var CapNames = map[uint32]string{ + CLIENT_LONG_PASSWORD: "CLIENT_LONG_PASSWORD", + CLIENT_FOUND_ROWS: "CLIENT_FOUND_ROWS", + CLIENT_LONG_FLAG: "CLIENT_LONG_FLAG", + CLIENT_CONNECT_WITH_DB: "CLIENT_CONNECT_WITH_DB", + CLIENT_NO_SCHEMA: "CLIENT_NO_SCHEMA", + CLIENT_COMPRESS: "CLIENT_COMPRESS", + CLIENT_ODBC: "CLIENT_ODBC", + CLIENT_LOCAL_FILES: "CLIENT_LOCAL_FILES", + CLIENT_IGNORE_SPACE: "CLIENT_IGNORE_SPACE", + CLIENT_PROTOCOL_41: "CLIENT_PROTOCOL_41", + CLIENT_INTERACTIVE: "CLIENT_INTERACTIVE", + CLIENT_SSL: "CLIENT_SSL", + CLIENT_IGNORE_SIGPIPE: "CLIENT_IGNORE_SIGPIPE", + CLIENT_TRANSACTIONS: "CLIENT_TRANSACTIONS", + CLIENT_RESERVED: "CLIENT_RESERVED", + CLIENT_SECURE_CONNECTION: "CLIENT_SECURE_CONNECTION", + CLIENT_MULTI_STATEMENTS: "CLIENT_MULTI_STATEMENTS", + CLIENT_MULTI_RESULTS: "CLIENT_MULTI_RESULTS", + CLIENT_PS_MULTI_RESULTS: "CLIENT_PS_MULTI_RESULTS", + CLIENT_PLUGIN_AUTH: "CLIENT_PLUGIN_AUTH", + CLIENT_CONNECT_ATTRS: "CLIENT_CONNECT_ATTRS", + CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA: "CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA", + CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS: "CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS", + CLIENT_SESSION_TRACK: "CLIENT_SESSION_TRACK", + CLIENT_DEPRECATE_EOF: "CLIENT_DEPRECATE_EOF", + CLIENT_OPTIONAL_RESULTSET_METADATA: "CLIENT_OPTIONAL_RESULTSET_METADATA", + CLIENT_ZSTD_COMPRESSION_ALGORITHM: "CLIENT_ZSTD_COMPRESSION_ALGORITHM", + CLIENT_QUERY_ATTRIBUTES: "CLIENT_QUERY_ATTRIBUTES", + MULTI_FACTOR_AUTHENTICATION: "MULTI_FACTOR_AUTHENTICATION", + CLIENT_CAPABILITY_EXTENSION: "CLIENT_CAPABILITY_EXTENSION", + CLIENT_SSL_VERIFY_SERVER_CERT: "CLIENT_SSL_VERIFY_SERVER_CERT", + CLIENT_REMEMBER_OPTIONS: "CLIENT_REMEMBER_OPTIONS", +} + const ( MYSQL_TYPE_DECIMAL byte = iota MYSQL_TYPE_TINY