Commit 9d07b052 authored by Vladislav Vaintroub's avatar Vladislav Vaintroub

MDEV-31608 - Connector/NET fails to connect since 10.10

Connector/NET does not expect collation IDs returned by "show collations"
to be NULL, runs into an exception.

The fix is to determine connector/net using its connection attributes,
then make sure "show collations" does not output NULL IDs.

The patch introduces new old_mode NO_NULL_COLLATION_IDs, that is
automatically set, once MySQL Connector/NET connection is determined.

A test was added, that uses MySql.Data from powershell - only works
if MySql.Data is installed into GAC (i.e with C/NET MSI package)
parent 6d0bcfc4
$assembly = [system.reflection.Assembly]::LoadWithPartialName("MySql.Data")
if ($assembly -eq $null)
{
"Can't load assembly MySql.Data"
exit 100
}
try
{
$connectionString =[string]::Format("server=127.0.0.1;uid=root;port={0};Connection Reset=true;",$Env:MASTER_MYPORT)
$connection = [MySql.Data.MySqlClient.MySqlConnection]@{ConnectionString=$connectionString}
$connection.Open()
# Test ExecuteReader()
$command = New-Object MySql.Data.MySqlClient.MySqlCommand
$command.Connection = $connection
$command.CommandText = "SELECT @@old_mode"
$reader = $command.ExecuteReader()
$reader.GetName(0)
while ($reader.Read())
{
$reader.GetValue(0)
}
# Test connection reset
$connection.Close()
$connection.Open()
# Test ExecuteNonQuery()
$command.CommandText="do 1";
$affected_rows = $command.ExecuteNonQuery()
if ($affected_rows -ne 0)
{
"Expected affected rows 0, actual $affected_rows"
exit 1
}
# Test Prepared Statement
$command.CommandText = "SELECT @var";
[void]$command.Parameters.AddWithValue("@var", 1);
$command.Prepare();
$out = $command.ExecuteScalar();
if ($out -ne 1)
{
"Expected output 1, actual $out"
exit 1
}
$connection.Close()
}
catch
{
# Dump exception
$_
$inner = $PSItem.Exception.InnerException
if ($inner -ne $null)
{
$PSItem.Exception.InnerException.Message
$PSItem.Exception.InnerException.StackTrace
}
}
@@old_mode
UTF8_IS_UTF8MB3,NO_NULL_COLLATION_IDS
--source include/windows.inc
let $sys_errno=0;
# Error 100 is returned by the powershell script
# if MySql.Data is not installed
--error 0,100
--exec powershell -NoLogo -NoProfile -File main\mysql_connector_net.ps1
if ($sys_errno != 0)
{
--skip Connector/NET is not installed
}
@@ -180,6 +180,7 @@
--- main/mysqld--help.result 2023-11-30 02:21:51.951132200 +0100
+++ main/mysqld--help,win.reject 2023-11-30 02:35:44.404612300 +0100
@@ -191,6 +191,7 @@
--console Write error output on screen; don't remove the console
window on windows.
--core-file Write core on crashes
......@@ -6,7 +8,7 @@
-h, --datadir=name Path to the database root directory
--date-format=name The DATE format (ignored)
--datetime-format=name
@@ -650,6 +651,7 @@
@@ -696,6 +697,7 @@
Use MySQL-5.6 (instead of MariaDB-5.3) format for TIME,
DATETIME, TIMESTAMP columns.
(Defaults to on; use --skip-mysql56-temporal-format to disable.)
......@@ -14,7 +16,7 @@
--net-buffer-length=#
Buffer length for TCP/IP and socket communication
--net-read-timeout=#
@@ -1327,6 +1328,10 @@
@@ -1351,6 +1353,10 @@
Alias for log_slow_query_file. Log slow queries to given
log file. Defaults logging to 'hostname'-slow.log. Must
be enabled to activate other slow log options
......@@ -25,7 +27,7 @@
--socket=name Socket file to use for connection
--sort-buffer-size=#
Each thread that needs to do a sort allocates a buffer of
@@ -1351,6 +1356,7 @@
@@ -1376,6 +1382,7 @@
deleting or updating every row in a table.
--stack-trace Print a symbolic stack trace on failure
(Defaults to on; use --skip-stack-trace to disable.)
......@@ -33,7 +35,7 @@
--standard-compliant-cte
Allow only CTEs compliant to SQL standard
(Defaults to on; use --skip-standard-compliant-cte to disable.)
@@ -1426,6 +1432,11 @@
@@ -1454,6 +1461,11 @@
--thread-pool-max-threads=#
Maximum allowed number of worker threads in the thread
pool
......@@ -45,7 +47,7 @@
--thread-pool-oversubscribe=#
How many additional active worker threads in a group are
allowed.
@@ -1464,8 +1475,8 @@
@@ -1493,8 +1505,8 @@
automatically convert it to an on-disk MyISAM or Aria
table.
-t, --tmpdir=name Path for temporary files. Several paths may be specified,
......@@ -56,7 +58,7 @@
--transaction-alloc-block-size=#
Allocation block size for transactions to be stored in
binary log
@@ -1685,6 +1696,7 @@
@@ -1716,6 +1728,7 @@
myisam-stats-method NULLS_UNEQUAL
myisam-use-mmap FALSE
mysql56-temporal-format TRUE
......@@ -64,7 +66,7 @@
net-buffer-length 16384
net-read-timeout 30
net-retry-count 10
@@ -1841,6 +1853,7 @@
@@ -1874,6 +1887,7 @@
slave-type-conversions
slow-launch-time 2
slow-query-log FALSE
......@@ -72,7 +74,7 @@
sort-buffer-size 2097152
sql-mode STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
sql-safe-updates FALSE
@@ -1867,6 +1880,8 @@
@@ -1901,6 +1915,8 @@
thread-pool-exact-stats FALSE
thread-pool-idle-timeout 60
thread-pool-max-threads 65536
......
......@@ -721,7 +721,8 @@ The following specify which files/extra groups are read (specified before remain
MySQL versions. Any combination of:
NO_DUP_KEY_WARNINGS_WITH_IGNORE, NO_PROGRESS_INFO,
ZERO_DATE_TIME_CAST, UTF8_IS_UTF8MB3,
IGNORE_INDEX_ONLY_FOR_JOIN, COMPAT_5_1_CHECKSUM
IGNORE_INDEX_ONLY_FOR_JOIN, COMPAT_5_1_CHECKSUM,
NO_NULL_COLLATION_IDS
Use 'ALL' to set all combinations.
--old-passwords Use old password encryption method (needed for 4.0 and
older clients)
......
......@@ -257,3 +257,13 @@ Warning 1264 Out of range value for column 'a' at row 2
DROP TABLE t1;
SET @@time_zone=DEFAULT;
SET TIMESTAMP=DEFAULT;
#
# MDEV-31608 - Connector/NET fails to connect since 10.10
#
select count(*) > 0 from information_schema.collations where id IS NULL;
count(*) > 0
1
SET old_mode=no_null_collation_ids;
select count(*) > 0 from information_schema.collations where id IS NULL;
count(*) > 0
0
......@@ -169,3 +169,11 @@ DROP TABLE t1;
SET @@time_zone=DEFAULT;
SET TIMESTAMP=DEFAULT;
--echo #
--echo # MDEV-31608 - Connector/NET fails to connect since 10.10
--echo #
select count(*) > 0 from information_schema.collations where id IS NULL;
SET old_mode=no_null_collation_ids;
select count(*) > 0 from information_schema.collations where id IS NULL;
......@@ -114,8 +114,8 @@ SET @@global.old_mode = 4;
SELECT @@global.old_mode;
@@global.old_mode
ZERO_DATE_TIME_CAST
SET @@global.old_mode = 64;
ERROR 42000: Variable 'old_mode' can't be set to the value of '64'
SET @@global.old_mode = 128;
ERROR 42000: Variable 'old_mode' can't be set to the value of '128'
SELECT @@global.old_mode;
@@global.old_mode
ZERO_DATE_TIME_CAST
......
......@@ -2299,7 +2299,7 @@ VARIABLE_COMMENT Used to emulate old behavior from earlier MariaDB or MySQL vers
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST NO_DUP_KEY_WARNINGS_WITH_IGNORE,NO_PROGRESS_INFO,ZERO_DATE_TIME_CAST,UTF8_IS_UTF8MB3,IGNORE_INDEX_ONLY_FOR_JOIN,COMPAT_5_1_CHECKSUM
ENUM_VALUE_LIST NO_DUP_KEY_WARNINGS_WITH_IGNORE,NO_PROGRESS_INFO,ZERO_DATE_TIME_CAST,UTF8_IS_UTF8MB3,IGNORE_INDEX_ONLY_FOR_JOIN,COMPAT_5_1_CHECKSUM,NO_NULL_COLLATION_IDS
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME OLD_PASSWORDS
......
......@@ -2469,7 +2469,7 @@ VARIABLE_COMMENT Used to emulate old behavior from earlier MariaDB or MySQL vers
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST NO_DUP_KEY_WARNINGS_WITH_IGNORE,NO_PROGRESS_INFO,ZERO_DATE_TIME_CAST,UTF8_IS_UTF8MB3,IGNORE_INDEX_ONLY_FOR_JOIN,COMPAT_5_1_CHECKSUM
ENUM_VALUE_LIST NO_DUP_KEY_WARNINGS_WITH_IGNORE,NO_PROGRESS_INFO,ZERO_DATE_TIME_CAST,UTF8_IS_UTF8MB3,IGNORE_INDEX_ONLY_FOR_JOIN,COMPAT_5_1_CHECKSUM,NO_NULL_COLLATION_IDS
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME OLD_PASSWORDS
......
......@@ -172,7 +172,7 @@ SET @@global.old_mode = 4;
SELECT @@global.old_mode;
--Error ER_WRONG_VALUE_FOR_VAR
SET @@global.old_mode = 64;
SET @@global.old_mode = 128;
SELECT @@global.old_mode;
# use of decimal values
......
......@@ -13576,8 +13576,37 @@ static bool find_mpvio_user(MPVIO_EXT *mpvio)
DBUG_RETURN(0);
}
/**
Determine if the client is MySQL Connector/NET.
Checks whether the given connection attributes blob corresponds to
MySQL Connector/NET by examining the "_client_name" attribute, which is
expected to be the first attribute in the blob.
@param connection_attrs - The connection attributes blob.
@param length - The length of the blob.
@return true if the client is MySQL Connector/NET, false otherwise.
*/
static inline bool is_connector_net_client(const char *connection_attrs,
size_t length)
{
constexpr LEX_CSTRING prefix=
{STRING_WITH_LEN("\x0c_client_name\x13mysql-connector-net")};
if (length < prefix.length)
return false;
/* Optimization to avoid following memcmp in common cases.*/
if (connection_attrs[prefix.length - 1] != prefix.str[prefix.length - 1])
return false;
return !memcmp(connection_attrs, prefix.str, prefix.length);
}
static bool
read_client_connect_attrs(char **ptr, char *end, CHARSET_INFO *from_cs)
read_client_connect_attrs(char **ptr, char *end, THD* thd)
{
ulonglong length;
char *ptr_save= *ptr;
......@@ -13600,10 +13629,14 @@ read_client_connect_attrs(char **ptr, char *end, CHARSET_INFO *from_cs)
if (length > 65535)
return true;
if (PSI_CALL_set_thread_connect_attrs(*ptr, (uint)length, from_cs) &&
if (PSI_CALL_set_thread_connect_attrs(*ptr, (uint)length, thd->charset()) &&
current_thd->variables.log_warnings)
sql_print_warning("Connection attributes of length %llu were truncated",
length);
/* Connector/Net crashes, when "show collations" returns NULL IDs*/
if (is_connector_net_client(*ptr, length))
thd->variables.old_behavior |= OLD_MODE_NO_NULL_COLLATION_IDS;
return false;
}
......@@ -13737,7 +13770,7 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
}
if ((thd->client_capabilities & CLIENT_CONNECT_ATTRS) &&
read_client_connect_attrs(&next_field, end, thd->charset()))
read_client_connect_attrs(&next_field, end, thd))
{
my_message(ER_UNKNOWN_COM_ERROR, ER_THD(thd, ER_UNKNOWN_COM_ERROR),
MYF(0));
......@@ -13987,7 +14020,7 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
if ((thd->client_capabilities & CLIENT_CONNECT_ATTRS) &&
read_client_connect_attrs(&next_field, ((char *)net->read_pos) + pkt_len,
mpvio->auth_info.thd->charset()))
mpvio->auth_info.thd))
return packet_error;
/*
......
......@@ -201,6 +201,7 @@ enum enum_binlog_row_image {
#define OLD_MODE_UTF8_IS_UTF8MB3 (1 << 3)
#define OLD_MODE_IGNORE_INDEX_ONLY_FOR_JOIN (1 << 4)
#define OLD_MODE_COMPAT_5_1_CHECKSUM (1 << 5)
#define OLD_MODE_NO_NULL_COLLATION_IDS (1 << 6)
extern char internal_table_name[2];
extern char empty_c_string[1];
......
......@@ -6398,7 +6398,8 @@ int fill_schema_collation(THD *thd, TABLE_LIST *tables, COND *cond)
tmp_cl->get_collation_name(MY_COLLATION_NAME_MODE_CONTEXT);
LEX_CSTRING full_collation_name=
tmp_cl->get_collation_name(MY_COLLATION_NAME_MODE_FULL);
bool is_context= cmp(context_collation_name, full_collation_name);
bool is_context= cmp(context_collation_name, full_collation_name) &&
!(thd->variables.old_behavior & OLD_MODE_NO_NULL_COLLATION_IDS);
/*
Some collations are applicable to multiple character sets.
Display them only once, with the short name (without the
......
......@@ -3886,6 +3886,7 @@ static const char *old_mode_names[]=
"UTF8_IS_UTF8MB3",
"IGNORE_INDEX_ONLY_FOR_JOIN",
"COMPAT_5_1_CHECKSUM",
"NO_NULL_COLLATION_IDS",
0
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment