From 888663ce12647c5aefee5e18accd80843d726741 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 3 Jun 2025 10:32:22 +0200 Subject: [PATCH 001/172] MDEV-36280 ALTER TABLE with DEFAULT NEXTVAL(sequence) fails due to insufficient grants Defer privilege checking until fix_fields. This way ALTER will behave consistently with CREATE, and require the same privileges to sequence column (SELECT/INSERT) --- mysql-test/suite/sql_sequence/grant.result | 13 +++++++++++++ mysql-test/suite/sql_sequence/grant.test | 16 ++++++++++++++++ sql/sql_acl.cc | 14 +++++++++++--- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/sql_sequence/grant.result b/mysql-test/suite/sql_sequence/grant.result index fc3421efcb6..d631772c740 100644 --- a/mysql-test/suite/sql_sequence/grant.result +++ b/mysql-test/suite/sql_sequence/grant.result @@ -97,6 +97,19 @@ ERROR 42000: SELECT, INSERT command denied to user 'u'@'localhost' for table `my disconnect con1; connection default; drop user u; +create user u_alter; +create table t1 (id int); +grant alter on t1 to u_alter; +connect con_alter,localhost,u_alter,,mysqltest_1; +alter table t1 modify id int default nextval(s1); +ERROR 42000: SELECT, INSERT command denied to user 'u_alter'@'localhost' for table `mysqltest_1`.`s1` +connection default; +grant insert, select on s1 to u_alter; +connection con_alter; +alter table t1 modify id int default nextval(s1); +disconnect con_alter; +connection default; +drop user u_alter; drop database mysqltest_1; # # End of 10.11 tests diff --git a/mysql-test/suite/sql_sequence/grant.test b/mysql-test/suite/sql_sequence/grant.test index c205bd34223..8c56de16525 100644 --- a/mysql-test/suite/sql_sequence/grant.test +++ b/mysql-test/suite/sql_sequence/grant.test @@ -106,6 +106,22 @@ create table t1 (a int not null default(nextval(s1)), --connection default drop user u; +# ALTER for table with DEFAULT NEXTVAL(seq) column needs INSERT/SELECT on seq +# just like CREATE does in the example above +create user u_alter; +create table t1 (id int); +grant alter on t1 to u_alter; +--connect(con_alter,localhost,u_alter,,mysqltest_1) +--error ER_TABLEACCESS_DENIED_ERROR +alter table t1 modify id int default nextval(s1); +--connection default +grant insert, select on s1 to u_alter; +--connection con_alter +alter table t1 modify id int default nextval(s1); +--disconnect con_alter +--connection default +drop user u_alter; + # # Cleanup # diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index b61f18c41cc..422ea6b008b 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -8347,9 +8347,17 @@ bool check_grant(THD *thd, privilege_t want_access, TABLE_LIST *tables, Direct SELECT of a sequence table doesn't set t_ref->sequence, so privileges will be checked normally, as for any table. */ - if (t_ref->sequence && - !(want_access & ~(SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL))) - continue; + if (t_ref->sequence) + { + if (!(want_access & ~(SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL))) + continue; + /* + If it is ALTER..SET DEFAULT= nextval(sequence), also defer checks + until ::fix_fields(). + */ + if (tl != tables && want_access == ALTER_ACL) + continue; + } const ACL_internal_table_access *access= get_cached_table_access(&t_ref->grant.m_internal, From 39bb34b9c536b8fd750643ff2a688def4d903190 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Sun, 1 Jun 2025 11:57:21 +1000 Subject: [PATCH 002/172] MDEV-36765: JSON Histogram cannot handle >1 byte characters When json_escape changed[1] to return a -1 in the case of a character that didn't match the character set, json_unescape_to_string assumed the -1 meant out of memory and just looped with more memory. Problem 1 - json_escape needs to return a different code so that the different between charset incompatibility and out of memory needs to occur. This enables json_escape_to_string to handle the it correctly (ignore and fail seems the best option). Problem 2 - JSON histograms need to support character with where the column json min/maximum value aren't a character set represented by a single byte. Problem 2 was previously hidden as ? was a result of the conversion. As JSON histograms can relate to columns when have an explict character set, use that and fall back to bin which was the previous default for non-string columns. Replaces -1/-2 constants and handling with JSON_ERROR_ILLEGAL_SYMBOL / JSON_ERROR_OUT_OF_SPACE defines. [1] regression from: f699010c0fc570786f6fe271f4dc3b2c84f8521d --- mysql-test/main/statistics_json.result | 18 ++++++++++++++++++ mysql-test/main/statistics_json.test | 14 ++++++++++++++ sql/opt_histogram_json.cc | 19 +++++++++++++++---- strings/json_lib.c | 6 +++--- 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/mysql-test/main/statistics_json.result b/mysql-test/main/statistics_json.result index 7a6ed6d2f25..cd885877c40 100644 --- a/mysql-test/main/statistics_json.result +++ b/mysql-test/main/statistics_json.result @@ -7796,3 +7796,21 @@ EXPLAIN } } drop table t1; +# +# MDEV-36765 JSON Histogram cannot handle >1 byte characters +# +CREATE TABLE t1 (f varchar(50)) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +INSERT INTO t1 VALUES (UNHEX('E983A8E996800AE983A8E99680')); +SET STATEMENT histogram_type=JSON_HB FOR ANALYZE TABLE t1 PERSISTENT FOR ALL; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +SELECT min_value, max_value, hist_type +FROM mysql.column_stats WHERE db_name = 'test' AND table_name = 't1'; +min_value max_value hist_type +部門 +部門 部門 +部門 JSON_HB +DROP TABLE t1; +DELETE FROM mysql.column_stats; +# End of 10.11 tests diff --git a/mysql-test/main/statistics_json.test b/mysql-test/main/statistics_json.test index 5263a98fff7..dc6037cca6a 100644 --- a/mysql-test/main/statistics_json.test +++ b/mysql-test/main/statistics_json.test @@ -481,3 +481,17 @@ explain format=json select * from t1 where a > 'y'; drop table t1; +--echo # +--echo # MDEV-36765 JSON Histogram cannot handle >1 byte characters +--echo # + +CREATE TABLE t1 (f varchar(50)) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +INSERT INTO t1 VALUES (UNHEX('E983A8E996800AE983A8E99680')); +SET STATEMENT histogram_type=JSON_HB FOR ANALYZE TABLE t1 PERSISTENT FOR ALL; +SELECT min_value, max_value, hist_type +FROM mysql.column_stats WHERE db_name = 'test' AND table_name = 't1'; + +DROP TABLE t1; +DELETE FROM mysql.column_stats; + +--echo # End of 10.11 tests diff --git a/sql/opt_histogram_json.cc b/sql/opt_histogram_json.cc index 1aec9e53917..358169a4cf4 100644 --- a/sql/opt_histogram_json.cc +++ b/sql/opt_histogram_json.cc @@ -52,10 +52,17 @@ static bool json_unescape_to_string(const char *val, int val_len, String* out) out->length(res); return false; // Ok } + if (res == JSON_ERROR_ILLEGAL_SYMBOL) + return true; // Invalid character // We get here if the unescaped string didn't fit into memory. - if (out->alloc(out->alloced_length()*2)) - return true; + if (res == JSON_ERROR_OUT_OF_SPACE) + { + if (out->alloc(out->alloced_length()*2)) + return true; + } + else + return true; // unknown error } } @@ -493,7 +500,7 @@ bool read_bucket_endpoint(json_engine_t *je, Field *field, String *out, const char* je_value= (const char*)je->value; if (je->value_type == JSON_VALUE_STRING && je->value_escaped) { - StringBuffer<128> unescape_buf; + StringBuffer<128> unescape_buf(field->charset() ? field->charset() : &my_charset_bin); if (json_unescape_to_string(je_value, je->value_len, &unescape_buf)) { *err= "Un-escape error"; @@ -600,10 +607,14 @@ int Histogram_json_hb::parse_bucket(json_engine_t *je, Field *field, bool have_start= false; bool have_size= false; bool have_ndv= false; + CHARSET_INFO *cs; + + if (!(cs= field->charset())) + cs= &my_charset_bin; double size_d; longlong ndv_ll= 0; - StringBuffer<128> value_buf; + StringBuffer<128> value_buf(cs); int rc; while (!(rc= json_scan_next(je)) && je->state != JST_OBJ_END) diff --git a/strings/json_lib.c b/strings/json_lib.c index b6b92c3ffb2..35efc8f669f 100644 --- a/strings/json_lib.c +++ b/strings/json_lib.c @@ -1656,13 +1656,13 @@ int json_unescape(CHARSET_INFO *json_cs, } if (c_len == MY_CS_ILUNI) { - return -1; + return JSON_ERROR_ILLEGAL_SYMBOL; } /* Result buffer is too small. */ - return -1; + return JSON_ERROR_OUT_OF_SPACE; } - return s.error==JE_EOS ? (int)(res - res_b) : -1; + return s.error==JE_EOS ? (int)(res - res_b) : JSON_ERROR_OUT_OF_SPACE; } From 0dd758e5f99f340bd47fbaa218b5986832a8b1dc Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Tue, 3 Jun 2025 12:48:36 +1000 Subject: [PATCH 003/172] MDEV-36765, followup 1: acl: handle json_unescape errors without crashing json_unescape can return negative numbers, and with so we should free the buffer allocated. Also handle the NULL value in unsafe_str by not de-referencing NULL. --- sql/sql_acl.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 116ae220cc5..ecd074fe5ac 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1665,7 +1665,7 @@ class User_table_json: public User_table set_int_value("version_id", (longlong) MYSQL_VERSION_ID); } const char *unsafe_str(const char *s) const - { return s[0] ? s : NULL; } + { return s ? (s[0] ? s : NULL) : NULL; } SSL_type get_ssl_type () const override { return (SSL_type)get_int_value("ssl_type"); } @@ -1764,6 +1764,8 @@ class User_table_json: public User_table if (get_value(key, JSV_STRING, &value_start, &value_len)) return ""; char *ptr= (char*)alloca(value_len); + if (!ptr) + return NULL; int len= json_unescape(m_table->field[2]->charset(), (const uchar*)value_start, (const uchar*)value_start + value_len, From 2b24ed87f0028180e692ba391132f55284377c02 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Tue, 3 Jun 2025 12:56:06 +1000 Subject: [PATCH 004/172] MDEV-36765: followup 2: st_append_json: handle json_unescape error Now pushes the OUTOFMEMORY error and ER_JSON_BAD_CHAR as a warning if these resulted in those errors. callers only expected a bool so the prototype was changed. Json_engine_scan::check_and_get_value_scalar failed to handle the error condition so set the *error if an error occured and return the correct value. --- sql/item_func.h | 4 ++-- sql/item_jsonfunc.cc | 32 +++++++++++++++++++++++++------- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/sql/item_func.h b/sql/item_func.h index 19ae314248d..57fd501d854 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -35,8 +35,8 @@ extern "C" /* Bug in BSDI include file */ #include -extern int st_append_json(String *s, - CHARSET_INFO *json_cs, const uchar *js, uint js_len); +extern bool st_append_json(String *s, + CHARSET_INFO *json_cs, const uchar *js, uint js_len); class Item_func :public Item_func_or_sum { void sync_with_sum_func_and_with_field(List &list); diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 998bc9d8262..46d54458a09 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -98,20 +98,34 @@ append_simple(String *s, const uchar *a, size_t a_len) Appends JSON string to the String object taking charsets in consideration. */ -int st_append_json(String *s, +bool st_append_json(String *s, CHARSET_INFO *json_cs, const uchar *js, uint js_len) { int str_len= js_len * s->charset()->mbmaxlen; - if (!s->reserve(str_len, 1024) && - (str_len= json_unescape(json_cs, js, js + js_len, + if (s->reserve(str_len, 1024)) + { + my_error(ER_OUTOFMEMORY, MYF(0), str_len); + return false; + } + + if ((str_len= json_unescape(json_cs, js, js + js_len, s->charset(), (uchar *) s->end(), (uchar *) s->end() + str_len)) > 0) { s->length(s->length() + str_len); - return 0; + return false; + } + if (current_thd) + { + if (str_len == JSON_ERROR_OUT_OF_SPACE) + my_error(ER_OUTOFMEMORY, MYF(0), str_len); + else if (str_len == JSON_ERROR_ILLEGAL_SYMBOL) + push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, + ER_JSON_BAD_CHR, ER_THD(current_thd, ER_JSON_BAD_CHR), + 0, "st_append_json", 0); } - return str_len; + return true; } @@ -791,8 +805,12 @@ bool Json_engine_scan::check_and_get_value_scalar(String *res, int *error) js_len= value_len; } - - return st_append_json(res, json_cs, js, js_len); + if (st_append_json(res, json_cs, js, js_len)) + { + *error= 1; + return true; + } + return false; } From 12c10712a7a20a2d884ba35f1f3816efad729dd7 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Tue, 3 Jun 2025 13:01:06 +1000 Subject: [PATCH 005/172] MDEV-36765: followup 3: json_unquote/compare_json_str_basic handle errors from json_unescape Using report_json_error was incorrect as errors in the je have already been handled earlier in the json function. The errors related to json_unescape are handled with consistently with other functions. --- sql/item_jsonfunc.cc | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 46d54458a09..2416bf839ea 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -907,7 +907,7 @@ error: String *Item_func_json_unquote::val_str(String *str) { json_engine_t je; - int c_len; + int c_len= JSON_ERROR_OUT_OF_SPACE; String *js; if (!(js= read_json(&je))) @@ -930,7 +930,15 @@ String *Item_func_json_unquote::val_str(String *str) return str; error: - report_json_error(js, &je, 0); + if (current_thd) + { + if (c_len == JSON_ERROR_OUT_OF_SPACE) + my_error(ER_OUTOFMEMORY, MYF(0), je.value_len); + else if (c_len == JSON_ERROR_ILLEGAL_SYMBOL) + push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, + ER_JSON_BAD_CHR, ER_THD(current_thd, ER_JSON_BAD_CHR), + 0, "unquote", 0); + } return js; } @@ -4195,9 +4203,14 @@ int Arg_comparator::compare_json_str_basic(Item *j, Item *s) (uchar *) (value2.ptr() + je.value_len))) < 0) { if (current_thd) - push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, - ER_JSON_BAD_CHR, ER_THD(current_thd, ER_JSON_BAD_CHR), - 0, "comparison", (int)((const char *) je.s.c_str - js->ptr())); + { + if (c_len == JSON_ERROR_OUT_OF_SPACE) + my_error(ER_OUTOFMEMORY, MYF(0), je.value_len); + else if (c_len == JSON_ERROR_ILLEGAL_SYMBOL) + push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, + ER_JSON_BAD_CHR, ER_THD(current_thd, ER_JSON_BAD_CHR), + 0, "comparison", (int)((const char *) je.s.c_str - js->ptr())); + } goto error; } @@ -4254,10 +4267,15 @@ int Arg_comparator::compare_e_json_str_basic(Item *j, Item *s) (uchar *) (value1.ptr() + value_len))) < 0) { if (current_thd) - push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, - ER_JSON_BAD_CHR, ER_THD(current_thd, ER_JSON_BAD_CHR), - 0, "equality comparison", 0); - return 1; + { + if (c_len == JSON_ERROR_OUT_OF_SPACE) + my_error(ER_OUTOFMEMORY, MYF(0), value_len); + else if (c_len == JSON_ERROR_ILLEGAL_SYMBOL) + push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, + ER_JSON_BAD_CHR, ER_THD(current_thd, ER_JSON_BAD_CHR), + 0, "equality comparison", 0); + } + return 1; } value1.length(c_len); res1= &value1; From cce76e72252eccf77599284ee53689d45241cf93 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Mon, 9 Jun 2025 16:40:27 +0300 Subject: [PATCH 006/172] MDEV-36765: followup 4: Fixups to previous fixes - Add a testcase showing JSON_HB histograms handle multi-byte characters correctly. - Make Item_func_json_unquote::val_str() handle situation where it is reading non-UTF8 "JSON" and transcoding it into UTF-8. (the JSON spec only allows UTF8 but MariaDB's implementation supports non-UTF8 as well) - Make Item_func_json_search::compare_json_value_wild() handle json_unescape()'s return values in the same way its done in other places. - Coding style fixes. --- mysql-test/main/statistics_json.result | 215 ++++++++++++++++++++++++- mysql-test/main/statistics_json.test | 39 ++++- sql/item_jsonfunc.cc | 35 +++- 3 files changed, 284 insertions(+), 5 deletions(-) diff --git a/mysql-test/main/statistics_json.result b/mysql-test/main/statistics_json.result index cd885877c40..d5059bfb811 100644 --- a/mysql-test/main/statistics_json.result +++ b/mysql-test/main/statistics_json.result @@ -7812,5 +7812,218 @@ min_value max_value hist_type 部門 部門 部門 JSON_HB DROP TABLE t1; -DELETE FROM mysql.column_stats; +create table t1 ( +col1 varchar(10) charset utf8 +); +set names utf8; +select hex('б'), collation('б'); +hex('б') collation('б') +D0B1 utf8mb3_general_ci +insert into t1 values +('а'),('б'),('в'),('г'),('д'),('е'),('ж'),('з'),('и'),('й'); +analyze table t1 persistent for all; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +select hex(col1) from t1; +hex(col1) +D0B0 +D0B1 +D0B2 +D0B3 +D0B4 +D0B5 +D0B6 +D0B7 +D0B8 +D0B9 +select json_detailed(json_extract(histogram, '$**.histogram_hb')) +from mysql.column_stats where db_name=database() and table_name='t1'; +json_detailed(json_extract(histogram, '$**.histogram_hb')) +[ + [ + { + "start": "а", + "size": 0.1, + "ndv": 1 + }, + { + "start": "б", + "size": 0.1, + "ndv": 1 + }, + { + "start": "в", + "size": 0.1, + "ndv": 1 + }, + { + "start": "г", + "size": 0.1, + "ndv": 1 + }, + { + "start": "д", + "size": 0.1, + "ndv": 1 + }, + { + "start": "е", + "size": 0.1, + "ndv": 1 + }, + { + "start": "ж", + "size": 0.1, + "ndv": 1 + }, + { + "start": "з", + "size": 0.1, + "ndv": 1 + }, + { + "start": "и", + "size": 0.1, + "ndv": 1 + }, + { + "start": "й", + "end": "й", + "size": 0.1, + "ndv": 1 + } + ] +] +explain extended select * from t1 where col1 < 'а'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 10 10.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`col1` AS `col1` from `test`.`t1` where `test`.`t1`.`col1` < 'а' +explain extended select * from t1 where col1 < 'в'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 10 20.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`col1` AS `col1` from `test`.`t1` where `test`.`t1`.`col1` < 'в' +explain extended select * from t1 where col1 < 'д'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 10 40.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`col1` AS `col1` from `test`.`t1` where `test`.`t1`.`col1` < 'д' +explain extended select * from t1 where col1 < 'ж'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 10 60.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`col1` AS `col1` from `test`.`t1` where `test`.`t1`.`col1` < 'ж' +explain extended select * from t1 where col1 < 'й'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 10 90.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`col1` AS `col1` from `test`.`t1` where `test`.`t1`.`col1` < 'й' +delete from t1; +insert into t1 values +('"а'),('"б'),('"в'),('"г'),('"д'),('"е'),('"ж'),('"з'),('"и'),('"й'); +analyze table t1 persistent for all; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +select json_detailed(json_extract(histogram, '$**.histogram_hb')) +from mysql.column_stats where db_name=database() and table_name='t1'; +json_detailed(json_extract(histogram, '$**.histogram_hb')) +[ + [ + { + "start": "\"а", + "size": 0.1, + "ndv": 1 + }, + { + "start": "\"б", + "size": 0.1, + "ndv": 1 + }, + { + "start": "\"в", + "size": 0.1, + "ndv": 1 + }, + { + "start": "\"г", + "size": 0.1, + "ndv": 1 + }, + { + "start": "\"д", + "size": 0.1, + "ndv": 1 + }, + { + "start": "\"е", + "size": 0.1, + "ndv": 1 + }, + { + "start": "\"ж", + "size": 0.1, + "ndv": 1 + }, + { + "start": "\"з", + "size": 0.1, + "ndv": 1 + }, + { + "start": "\"и", + "size": 0.1, + "ndv": 1 + }, + { + "start": "\"й", + "end": "\"й", + "size": 0.1, + "ndv": 1 + } + ] +] +select hex(col1) from t1; +hex(col1) +22D0B9 +22D0B8 +22D0B7 +22D0B6 +22D0B5 +22D0B4 +22D0B3 +22D0B2 +22D0B1 +22D0B0 +explain extended select * from t1 where col1 < '"а'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 10 10.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`col1` AS `col1` from `test`.`t1` where `test`.`t1`.`col1` < '"а' +explain extended select * from t1 where col1 < '"в'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 10 20.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`col1` AS `col1` from `test`.`t1` where `test`.`t1`.`col1` < '"в' +explain extended select * from t1 where col1 < '"д'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 10 40.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`col1` AS `col1` from `test`.`t1` where `test`.`t1`.`col1` < '"д' +explain extended select * from t1 where col1 < '"ж'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 10 60.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`col1` AS `col1` from `test`.`t1` where `test`.`t1`.`col1` < '"ж' +explain extended select * from t1 where col1 < '"й'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 10 90.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`col1` AS `col1` from `test`.`t1` where `test`.`t1`.`col1` < '"й' +drop table t1; +select JSON_UNQUOTE(CONVERT('"ФФ"' using cp1251)); +JSON_UNQUOTE(CONVERT('"ФФ"' using cp1251)) +ФФ # End of 10.11 tests diff --git a/mysql-test/main/statistics_json.test b/mysql-test/main/statistics_json.test index dc6037cca6a..44c7edf0c1c 100644 --- a/mysql-test/main/statistics_json.test +++ b/mysql-test/main/statistics_json.test @@ -492,6 +492,43 @@ SELECT min_value, max_value, hist_type FROM mysql.column_stats WHERE db_name = 'test' AND table_name = 't1'; DROP TABLE t1; -DELETE FROM mysql.column_stats; + +create table t1 ( + col1 varchar(10) charset utf8 +); +set names utf8; +select hex('б'), collation('б'); +insert into t1 values +('а'),('б'),('в'),('г'),('д'),('е'),('ж'),('з'),('и'),('й'); + +analyze table t1 persistent for all; +select hex(col1) from t1; +select json_detailed(json_extract(histogram, '$**.histogram_hb')) +from mysql.column_stats where db_name=database() and table_name='t1'; + +explain extended select * from t1 where col1 < 'а'; +explain extended select * from t1 where col1 < 'в'; +explain extended select * from t1 where col1 < 'д'; +explain extended select * from t1 where col1 < 'ж'; +explain extended select * from t1 where col1 < 'й'; + +delete from t1; +insert into t1 values +('"а'),('"б'),('"в'),('"г'),('"д'),('"е'),('"ж'),('"з'),('"и'),('"й'); + +analyze table t1 persistent for all; +select json_detailed(json_extract(histogram, '$**.histogram_hb')) +from mysql.column_stats where db_name=database() and table_name='t1'; +select hex(col1) from t1; +explain extended select * from t1 where col1 < '"а'; +explain extended select * from t1 where col1 < '"в'; +explain extended select * from t1 where col1 < '"д'; +explain extended select * from t1 where col1 < '"ж'; +explain extended select * from t1 where col1 < '"й'; + +drop table t1; + +# JSON_UNQUOTE was touched by this patch also +select JSON_UNQUOTE(CONVERT('"ФФ"' using cp1251)); --echo # End of 10.11 tests diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 2416bf839ea..3c556d97cb2 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -916,14 +916,25 @@ String *Item_func_json_unquote::val_str(String *str) if (unlikely(je.s.error) || je.value_type != JSON_VALUE_STRING) return js; + int buf_len= je.value_len; + if (js->charset()->cset != my_charset_utf8mb4_bin.cset) + { + /* + json_unquote() will be transcoding between charsets. We don't know + how much buffer space we'll need. Assume that each byte in the source + will require mbmaxlen bytes in the output. + */ + buf_len *= my_charset_utf8mb4_bin.mbmaxlen; + } + str->length(0); str->set_charset(&my_charset_utf8mb4_bin); - if (str->realloc_with_extra_if_needed(je.value_len) || + if (str->realloc_with_extra_if_needed(buf_len) || (c_len= json_unescape(js->charset(), je.value, je.value + je.value_len, &my_charset_utf8mb4_bin, - (uchar *) str->ptr(), (uchar *) (str->ptr() + je.value_len))) < 0) + (uchar *) str->ptr(), (uchar *) (str->ptr() + buf_len))) < 0) goto error; str->length(c_len); @@ -933,7 +944,7 @@ error: if (current_thd) { if (c_len == JSON_ERROR_OUT_OF_SPACE) - my_error(ER_OUTOFMEMORY, MYF(0), je.value_len); + my_error(ER_OUTOFMEMORY, MYF(0), buf_len); else if (c_len == JSON_ERROR_ILLEGAL_SYMBOL) push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, ER_JSON_BAD_CHR, ER_THD(current_thd, ER_JSON_BAD_CHR), @@ -3937,7 +3948,21 @@ int Item_func_json_search::compare_json_value_wild(json_engine_t *je, (uchar *) (esc_value.ptr() + esc_value.alloced_length())); if (esc_len <= 0) + { + if (current_thd) + { + if (esc_len == JSON_ERROR_OUT_OF_SPACE) + my_error(ER_OUTOFMEMORY, MYF(0), je->value_len); + else if (esc_len == JSON_ERROR_ILLEGAL_SYMBOL) + { + push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, + ER_JSON_BAD_CHR, ER_THD(current_thd, ER_JSON_BAD_CHR), + 0, "comparison", + (int)(je->s.c_str - je->value)); + } + } return 0; + } return collation.collation->wildcmp( esc_value.ptr(), esc_value.ptr() + esc_len, @@ -4207,9 +4232,11 @@ int Arg_comparator::compare_json_str_basic(Item *j, Item *s) if (c_len == JSON_ERROR_OUT_OF_SPACE) my_error(ER_OUTOFMEMORY, MYF(0), je.value_len); else if (c_len == JSON_ERROR_ILLEGAL_SYMBOL) + { push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, ER_JSON_BAD_CHR, ER_THD(current_thd, ER_JSON_BAD_CHR), 0, "comparison", (int)((const char *) je.s.c_str - js->ptr())); + } } goto error; } @@ -4271,9 +4298,11 @@ int Arg_comparator::compare_e_json_str_basic(Item *j, Item *s) if (c_len == JSON_ERROR_OUT_OF_SPACE) my_error(ER_OUTOFMEMORY, MYF(0), value_len); else if (c_len == JSON_ERROR_ILLEGAL_SYMBOL) + { push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, ER_JSON_BAD_CHR, ER_THD(current_thd, ER_JSON_BAD_CHR), 0, "equality comparison", 0); + } } return 1; } From 5a6732983d88c282c3e8e8c2dbf8ee6af86f2ad6 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Mon, 9 Jun 2025 21:54:32 +0300 Subject: [PATCH 007/172] MDEV-36461, followup: fix opt_trace.test for --view-protocol --- mysql-test/main/opt_trace.result | 4 ++-- mysql-test/main/opt_trace.test | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/main/opt_trace.result b/mysql-test/main/opt_trace.result index 93a5508327b..029f795b4fa 100644 --- a/mysql-test/main/opt_trace.result +++ b/mysql-test/main/opt_trace.result @@ -11069,9 +11069,9 @@ SUBQ a 985 1 985 2 # The trace must be empty: -select json_detailed(json_extract(trace, '$**.range-checked-for-each-record')) +select json_detailed(json_extract(trace, '$**.range-checked-for-each-record')) as TRACE from information_schema.optimizer_trace; -json_detailed(json_extract(trace, '$**.range-checked-for-each-record')) +TRACE NULL # The trace must be empty: select json_detailed(json_extract(trace, '$**.join_execution')) diff --git a/mysql-test/main/opt_trace.test b/mysql-test/main/opt_trace.test index 55fe4edf328..fa51cfbb603 100644 --- a/mysql-test/main/opt_trace.test +++ b/mysql-test/main/opt_trace.test @@ -1242,7 +1242,7 @@ select from t3; --echo # The trace must be empty: -select json_detailed(json_extract(trace, '$**.range-checked-for-each-record')) +select json_detailed(json_extract(trace, '$**.range-checked-for-each-record')) as TRACE from information_schema.optimizer_trace; --echo # The trace must be empty: select json_detailed(json_extract(trace, '$**.join_execution')) From 5729d89cd511b1a894661518137ee714cf7aecf2 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 4 Jun 2025 09:46:06 +0200 Subject: [PATCH 008/172] MDEV-36938 Fix MSI install failure when ADDLOCAL omits required runtime Since 10.11.12 (commit 8363d05f4df8b5c787), executables are built with the dynamic C runtime (/MD), introducing a dependency on vcruntime140.dll. VC++ runtime is typically installed via the VCCRT feature, which is included by default as part of the hidden/default ALWAYSINSTALL feature set. However, when users specify the ADDLOCAL property, it overrides the default selection and may omit critical features like VCCRT. This leads to installation failures. Fix: Add a custom action that ensures mandatory features (e.g., VCCRT) are appended to the ADDLOCAL property at install time. This guarantees essential runtime components are always installed, even when a custom feature set is selected. --- win/packaging/create_msi.cmake | 5 +++++ win/packaging/extra.wxs.in | 15 +++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/win/packaging/create_msi.cmake b/win/packaging/create_msi.cmake index 57262e10d7d..20b139cf5d1 100644 --- a/win/packaging/create_msi.cmake +++ b/win/packaging/create_msi.cmake @@ -357,6 +357,11 @@ SET(CPACK_WIX_INCLUDES ) ENDFOREACH() +LIST(LENGTH WIX_FEATURE_AlwaysInstall_COMPONENTS len) +IF (len LESS_EQUAL 0) + MESSAGE(FATAL_ERROR "AlwaysInstall_COMPONENTS is empty") +ENDIF() +LIST(JOIN WIX_FEATURE_AlwaysInstall_COMPONENTS "," MANDATORY_FEATURES) CONFIGURE_FILE(${SRCDIR}/mysql_server.wxs.in ${CMAKE_CURRENT_BINARY_DIR}/mysql_server.wxs) diff --git a/win/packaging/extra.wxs.in b/win/packaging/extra.wxs.in index 056a7ec43ab..584f1e6921b 100644 --- a/win/packaging/extra.wxs.in +++ b/win/packaging/extra.wxs.in @@ -63,6 +63,21 @@ + + + + ADDLOCAL + + + ADDLOCAL + - + diff --git a/win/packaging/heidisql.cmake b/win/packaging/heidisql.cmake index 157e5517594..0deffe78178 100644 --- a/win/packaging/heidisql.cmake +++ b/win/packaging/heidisql.cmake @@ -1,4 +1,4 @@ -SET(HEIDISQL_BASE_NAME "HeidiSQL_12.10_32_Portable") +SET(HEIDISQL_BASE_NAME "HeidiSQL_12.10_64_Portable") SET(HEIDISQL_ZIP "${HEIDISQL_BASE_NAME}.zip") SET(HEIDISQL_URL "https://www.heidisql.com/downloads/releases/${HEIDISQL_ZIP}") SET(HEIDISQL_DOWNLOAD_DIR ${THIRD_PARTY_DOWNLOAD_LOCATION}/${HEIDISQL_BASE_NAME}) diff --git a/win/packaging/heidisql.wxi.in b/win/packaging/heidisql.wxi.in index 45bd6c4b218..e4089be7204 100644 --- a/win/packaging/heidisql.wxi.in +++ b/win/packaging/heidisql.wxi.in @@ -1,6 +1,15 @@ - + + + + - + - + patching t1.TRG... +connection default; +CREATE TABLE patch (a blob); +LOAD DATA LOCAL INFILE '$MYSQLD_DATADIR/mysqltest_db1/t1.TRG' INTO TABLE patch; +SELECT SUBSTRING_INDEX(a,'definers=',1) INTO OUTFILE +'$MYSQLD_DATADIR/mysqltest_db1/t1.TRG' +FROM patch; +DROP TABLE patch; +connection wl2818_definer_con; CREATE TRIGGER wl2818_trg2 AFTER INSERT ON t1 FOR EACH ROW diff --git a/mysql-test/main/trigger-compat.test b/mysql-test/main/trigger-compat.test index a8ad20073d6..f927a744c0a 100644 --- a/mysql-test/main/trigger-compat.test +++ b/mysql-test/main/trigger-compat.test @@ -61,23 +61,17 @@ CREATE TRIGGER wl2818_trg1 BEFORE INSERT ON t1 FOR EACH ROW INSERT INTO t2 VALUE # portable and we have to load the file into a table, exclude the definers line, # then load the data to an outfile to accomplish the same effect ---disable_query_log --connection default CREATE TABLE patch (a blob); let $MYSQLD_DATADIR = `select @@datadir`; -eval LOAD DATA LOCAL INFILE '$MYSQLD_DATADIR/mysqltest_db1/t1.TRG' INTO TABLE patch; +evalp LOAD DATA LOCAL INFILE '$MYSQLD_DATADIR/mysqltest_db1/t1.TRG' INTO TABLE patch; # remove original t1.TRG file so SELECT INTO OUTFILE won't fail --remove_file $MYSQLD_DATADIR/mysqltest_db1/t1.TRG ---disable_cursor_protocol ---disable_ps2_protocol -eval SELECT SUBSTRING_INDEX(a,'definers=',1) INTO OUTFILE +evalp SELECT SUBSTRING_INDEX(a,'definers=',1) INTO OUTFILE '$MYSQLD_DATADIR/mysqltest_db1/t1.TRG' FROM patch; ---enable_ps2_protocol ---enable_cursor_protocol DROP TABLE patch; --connection wl2818_definer_con ---enable_query_log # # Create a new trigger. diff --git a/mysql-test/main/type_timestamp.test b/mysql-test/main/type_timestamp.test index e4de6f7845f..a70d2f50c63 100644 --- a/mysql-test/main/type_timestamp.test +++ b/mysql-test/main/type_timestamp.test @@ -742,11 +742,7 @@ FLUSH TABLES; # 0xFF - record flags # 0x77777777 - TIMESTAMP integer part # 0xFFFFFF - TIMESTAMP bad fractional part ---disable_cursor_protocol ---disable_ps2_protocol --eval SELECT CONCAT(0xFF,0x77777777,0xFFFFFF) INTO OUTFILE '$MYSQLD_DATADIR/test/t1.MYD' FIELDS TERMINATED BY '' ESCAPED BY '' LINES TERMINATED BY '' ---enable_ps2_protocol ---enable_cursor_protocol --eval SELECT HEX(LOAD_FILE('$MYSQLD_DATADIR/test/t1.MYD')) AS MYD --enable_query_log SELECT a, CAST(a AS DATETIME) AS dt0, CAST(a AS DATETIME(6)) AS dt6 FROM t1; diff --git a/mysql-test/main/union.test b/mysql-test/main/union.test index 20be464ecac..4a0e0e0a72d 100644 --- a/mysql-test/main/union.test +++ b/mysql-test/main/union.test @@ -1113,11 +1113,9 @@ DROP TABLE t1; -- echo # Bug#32858: Error: "Incorrect usage of UNION and INTO" does not take -- echo # subselects into account -- echo # ---disable_ps2_protocol CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1); ---disable_cursor_protocol -- echo # Tests fix in parser rule select_derived_union. SELECT a INTO @v FROM ( SELECT a FROM t1 @@ -1159,11 +1157,9 @@ SELECT a INTO DUMPFILE 'union.out.file8' FROM t1 UNION SELECT a FROM t1; SELECT ( SELECT a UNION SELECT a ) INTO @v FROM t1; SELECT ( SELECT a UNION SELECT a ) INTO OUTFILE 'union.out.file3' FROM t1; SELECT ( SELECT a UNION SELECT a ) INTO DUMPFILE 'union.out.file4' FROM t1; ---enable_cursor_protocol DROP TABLE t1; remove_files_wildcard $MYSQLTEST_VARDIR/mysqld.1/data/test union.out.fil*; ---enable_ps2_protocol --echo # --echo # Bug #49734: Crash on EXPLAIN EXTENDED UNION ... ORDER BY diff --git a/mysql-test/suite/binlog/include/database.test b/mysql-test/suite/binlog/include/database.test index a55cd7c5002..097a501cc34 100644 --- a/mysql-test/suite/binlog/include/database.test +++ b/mysql-test/suite/binlog/include/database.test @@ -44,11 +44,7 @@ CREATE TABLE t2(c1 INT); let $prefix= `SELECT UUID()`; --echo # Create a file in the database directory --replace_result $prefix FAKE_FILE ---disable_cursor_protocol ---disable_ps2_protocol eval SELECT 'hello' INTO OUTFILE 'fake_file.$prefix'; ---enable_ps2_protocol ---enable_cursor_protocol --echo --echo # 'DROP DATABASE' will fail if there is any other file in the the diff --git a/mysql-test/suite/binlog_encryption/rpl_loadfile.result b/mysql-test/suite/binlog_encryption/rpl_loadfile.result index 19a11e99250..2f94847a3b3 100644 --- a/mysql-test/suite/binlog_encryption/rpl_loadfile.result +++ b/mysql-test/suite/binlog_encryption/rpl_loadfile.result @@ -229,7 +229,6 @@ connection slave; include/rpl_reset.inc connection master; SELECT repeat('x',20) INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/bug_39701.data'; -DROP TABLE IF EXISTS t1; CREATE TABLE t1 (t text); CREATE PROCEDURE p(file varchar(4096)) BEGIN diff --git a/mysql-test/suite/engines/funcs/r/rpl_drop_db.result b/mysql-test/suite/engines/funcs/r/rpl_drop_db.result index 3712527afe4..fbe1cc1dea5 100644 --- a/mysql-test/suite/engines/funcs/r/rpl_drop_db.result +++ b/mysql-test/suite/engines/funcs/r/rpl_drop_db.result @@ -1,7 +1,6 @@ include/master-slave.inc [connection master] connection master; -drop database if exists mysqltest1; create database mysqltest1; create table mysqltest1.t1 (n int); insert into mysqltest1.t1 values (1); diff --git a/mysql-test/suite/engines/funcs/t/ld_null.test b/mysql-test/suite/engines/funcs/t/ld_null.test index e01c473baf3..50cbce78044 100644 --- a/mysql-test/suite/engines/funcs/t/ld_null.test +++ b/mysql-test/suite/engines/funcs/t/ld_null.test @@ -3,9 +3,7 @@ DROP TABLE IF EXISTS t1; --enable_warnings CREATE TABLE t1 (c1 INTEGER NOT NULL PRIMARY KEY, c2 VARCHAR(10), c3 DATETIME); LOAD DATA LOCAL INFILE 'suite/engines/funcs/t/load_null.inc' INTO TABLE t1 FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n'; ---disable_cursor_protocol eval SELECT * INTO OUTFILE '../../tmp/t1.dat' FROM t1; ---enable_cursor_protocol SELECT * FROM t1 ORDER BY c1; TRUNCATE TABLE t1; --disable_query_log @@ -17,9 +15,7 @@ DROP TABLE t1; CREATE TABLE t1 (c1 INTEGER NOT NULL PRIMARY KEY, c2 VARCHAR(10), c3 DATETIME); LOAD DATA LOCAL INFILE 'suite/engines/funcs/t/load_null2.inc' INTO TABLE t1 FIELDS TERMINATED BY ',' ESCAPED BY '\'' LINES TERMINATED BY '\n'; --disable_query_log ---disable_cursor_protocol eval SELECT * INTO OUTFILE '$MYSQLTEST_VARDIR/tmp/t1-2.dat' FIELDS ESCAPED BY '\'' FROM t1; ---enable_cursor_protocol --enable_query_log SELECT * FROM t1 ORDER BY c1; TRUNCATE TABLE t1; diff --git a/mysql-test/suite/federated/federatedx_create_handlers.test b/mysql-test/suite/federated/federatedx_create_handlers.test index ce72667b071..4d6a43377b8 100644 --- a/mysql-test/suite/federated/federatedx_create_handlers.test +++ b/mysql-test/suite/federated/federatedx_create_handlers.test @@ -165,13 +165,9 @@ insert into federated.t4 select * from federated.t1; --sorted_result select * from federated.t4; ---disable_cursor_protocol select name into @var from federated.t1 where id=3 limit 1 ; select @var; ---disable_ps2_protocol select name into outfile 'tmp.txt' from federated.t1; ---enable_ps2_protocol ---enable_cursor_protocol let $path=`select concat(@@datadir, 'test/tmp.txt')`; remove_file $path; diff --git a/mysql-test/suite/funcs_1/r/row_count_func.result b/mysql-test/suite/funcs_1/r/row_count_func.result index ffc0e8e3b77..d78e807732a 100644 --- a/mysql-test/suite/funcs_1/r/row_count_func.result +++ b/mysql-test/suite/funcs_1/r/row_count_func.result @@ -3,7 +3,6 @@ # -- Test case for Bug#21818. # -- -DROP TABLE IF EXISTS t1; CREATE TABLE t1(a INT); INSERT INTO t1 VALUES (1), (2), (3); diff --git a/mysql-test/suite/funcs_1/t/is_basics_mixed.test b/mysql-test/suite/funcs_1/t/is_basics_mixed.test index 9f52d7644f4..0fea9dd351c 100644 --- a/mysql-test/suite/funcs_1/t/is_basics_mixed.test +++ b/mysql-test/suite/funcs_1/t/is_basics_mixed.test @@ -176,11 +176,9 @@ SELECT 1 AS my_col FROM information_schema.tables WHERE table_name = 't1_third'; # # SELECT INTO USER VARIABLE ---disable_cursor_protocol SELECT table_name,table_schema INTO @table_name,@table_schema FROM information_schema.tables WHERE table_schema = 'db_datadict' ORDER BY table_name LIMIT 1; ---enable_cursor_protocol SELECT @table_name,@table_schema; # # SELECT INTO OUTFILE @@ -188,16 +186,12 @@ let $OUTFILE = $MYSQLTEST_VARDIR/tmp/datadict.out; --error 0,1 remove_file $OUTFILE; --replace_result $OUTFILE ---disable_cursor_protocol ---disable_ps2_protocol eval SELECT table_name,table_schema INTO OUTFILE '$OUTFILE' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n' FROM information_schema.tables WHERE table_schema = 'db_datadict' ORDER BY table_name; ---enable_ps2_protocol ---enable_cursor_protocol cat_file $OUTFILE; remove_file $OUTFILE; # diff --git a/mysql-test/suite/funcs_1/t/row_count_func.test b/mysql-test/suite/funcs_1/t/row_count_func.test index 4c3466f7a13..351aee61044 100644 --- a/mysql-test/suite/funcs_1/t/row_count_func.test +++ b/mysql-test/suite/funcs_1/t/row_count_func.test @@ -4,10 +4,6 @@ --echo # -- --echo ---disable_warnings -DROP TABLE IF EXISTS t1; ---enable_warnings - CREATE TABLE t1(a INT); INSERT INTO t1 VALUES (1), (2), (3); @@ -18,11 +14,7 @@ INSERT INTO t1 VALUES (1), (2), (3); --enable_info --echo SELECT * FROM t1 INTO OUTFILE "MYSQL_TMP_DIR/bug21818.txt"; --disable_query_log # to avoid $MYSQL_TMP_DIR in query log ---disable_cursor_protocol ---disable_ps2_protocol --eval SELECT * FROM t1 INTO OUTFILE "$MYSQL_TMP_DIR/bug21818.txt" ---enable_ps2_protocol ---enable_cursor_protocol --enable_query_log --disable_info @@ -34,11 +26,9 @@ SELECT ROW_COUNT(); --echo --echo # -- Check 2. ---disable_cursor_protocol --enable_info SELECT a FROM t1 LIMIT 1 INTO @a; --disable_info ---enable_cursor_protocol --echo --disable_ps2_protocol diff --git a/mysql-test/suite/gcol/inc/gcol_ins_upd.inc b/mysql-test/suite/gcol/inc/gcol_ins_upd.inc index 7b6538a3085..68c0a0e30c9 100644 --- a/mysql-test/suite/gcol/inc/gcol_ins_upd.inc +++ b/mysql-test/suite/gcol/inc/gcol_ins_upd.inc @@ -626,11 +626,7 @@ CREATE TABLE t1 ( ); INSERT IGNORE INTO t1 (b) VALUES (b'101110001110100'),(b'011101'); ---disable_cursor_protocol ---disable_ps2_protocol SELECT pk, b INTO OUTFILE 'load.data' FROM t1; ---enable_ps2_protocol ---enable_cursor_protocol --error ER_DATA_TOO_LONG LOAD DATA INFILE 'load.data' REPLACE INTO TABLE t1 (pk, b); diff --git a/mysql-test/suite/gcol/inc/gcol_keys.inc b/mysql-test/suite/gcol/inc/gcol_keys.inc index 9349824aed7..e5ac0afd92a 100644 --- a/mysql-test/suite/gcol/inc/gcol_keys.inc +++ b/mysql-test/suite/gcol/inc/gcol_keys.inc @@ -776,11 +776,7 @@ CREATE TABLE t1 ( ); INSERT IGNORE INTO t1 (b) VALUES (b'101110001110100'),(b'011101'); ---disable_cursor_protocol ---disable_ps2_protocol SELECT pk, b INTO OUTFILE 'load.data' FROM t1; ---enable_ps2_protocol ---enable_cursor_protocol --error ER_DATA_TOO_LONG LOAD DATA INFILE 'load.data' REPLACE INTO TABLE t1 (pk, b); diff --git a/mysql-test/suite/gcol/t/gcol_bugfixes.test b/mysql-test/suite/gcol/t/gcol_bugfixes.test index 7ec4b3d4e35..c4beb69058a 100644 --- a/mysql-test/suite/gcol/t/gcol_bugfixes.test +++ b/mysql-test/suite/gcol/t/gcol_bugfixes.test @@ -674,11 +674,7 @@ DROP TABLE t1; CREATE TABLE t1 (id INT PRIMARY KEY, a VARCHAR(2333), va VARCHAR(171) AS (a)) ENGINE=InnoDB; INSERT INTO t1 (id,a) VALUES (1,REPEAT('x',200)); ---disable_cursor_protocol ---disable_ps2_protocol SELECT id, va INTO OUTFILE 'load_t1' FROM t1; ---enable_ps2_protocol ---enable_cursor_protocol --error ER_DATA_TOO_LONG LOAD DATA INFILE 'load_t1' REPLACE INTO TABLE t1 (id,va); SELECT * FROM t1; @@ -691,11 +687,7 @@ DROP TABLE t1; CREATE TABLE t1 (id BIGINT PRIMARY KEY, a VARCHAR(2333), va VARCHAR(171) AS (a)) ENGINE=InnoDB; INSERT INTO t1 (id,a) VALUES (1,REPEAT('x',200)); ---disable_cursor_protocol ---disable_ps2_protocol SELECT id, va INTO OUTFILE 'load_t1' FROM t1; ---enable_ps2_protocol ---enable_cursor_protocol --error ER_DATA_TOO_LONG LOAD DATA INFILE 'load_t1' REPLACE INTO TABLE t1 (id,va); SELECT * FROM t1; @@ -715,11 +707,7 @@ CREATE TABLE t1 (id INT PRIMARY KEY, ts TIMESTAMP DEFAULT '1971-01-01 00:00:00', c VARBINARY(8) DEFAULT '', vc VARCHAR(3) AS (c) STORED); INSERT IGNORE INTO t1 (id,c) VALUES (1,'foobar'); ---disable_cursor_protocol ---disable_ps2_protocol SELECT id, ts, vc INTO OUTFILE 'load_t1' FROM t1; ---enable_ps2_protocol ---enable_cursor_protocol --error 0,ER_DATA_TOO_LONG LOAD DATA INFILE 'load_t1' REPLACE INTO TABLE t1 (id, ts, vc); INSERT IGNORE INTO t1 (id) VALUES (2); diff --git a/mysql-test/suite/innodb/t/insert_into_empty.test b/mysql-test/suite/innodb/t/insert_into_empty.test index e31b680ebe8..c2f0e8b5a5e 100644 --- a/mysql-test/suite/innodb/t/insert_into_empty.test +++ b/mysql-test/suite/innodb/t/insert_into_empty.test @@ -560,11 +560,7 @@ DROP TABLE t; --echo # CREATE TABLE t (id INT) ENGINE=InnoDB; --replace_result $MYSQLTEST_VARDIR VARDIR ---disable_cursor_protocol ---disable_ps2_protocol eval select 1 into outfile "$MYSQLTEST_VARDIR/tmp/t.outfile"; ---enable_ps2_protocol ---enable_cursor_protocol BEGIN; --replace_result $MYSQLTEST_VARDIR VARDIR eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/t.outfile' INTO TABLE t; diff --git a/mysql-test/suite/innodb/t/instant_alter_bugs.test b/mysql-test/suite/innodb/t/instant_alter_bugs.test index dcdcd07700e..59666dfce9f 100644 --- a/mysql-test/suite/innodb/t/instant_alter_bugs.test +++ b/mysql-test/suite/innodb/t/instant_alter_bugs.test @@ -129,11 +129,7 @@ INSERT INTO t1 (f1,f2,f3,f4,f5,f6,f7,f8) VALUES INSERT INTO t1 (f1,f2,f3,f4,f5,f6,f7,f8) VALUES ('impact', 'b', 'h', 185, 'fj', 7, 7, 3); ALTER TABLE t1 ADD COLUMN filler VARCHAR(255) DEFAULT ''; ---disable_cursor_protocol ---disable_ps2_protocol SELECT * INTO OUTFILE 'load.data' FROM t1; ---enable_ps2_protocol ---enable_cursor_protocol UPDATE IGNORE t1 SET pk = 0; LOAD DATA INFILE 'load.data' REPLACE INTO TABLE t1; HANDLER t1 OPEN AS h; diff --git a/mysql-test/suite/innodb/t/temp_table_savepoint.test b/mysql-test/suite/innodb/t/temp_table_savepoint.test index 185fb252e93..ffac771ded9 100644 --- a/mysql-test/suite/innodb/t/temp_table_savepoint.test +++ b/mysql-test/suite/innodb/t/temp_table_savepoint.test @@ -141,12 +141,7 @@ update ignore t5 set c1 = 20 where c1 = 140 ; select count(*) from t5 where c1 = 140; --replace_result $MYSQLTEST_VARDIR VARDIR ---disable_cursor_protocol ---disable_ps2_protocol eval select * into outfile "$MYSQLTEST_VARDIR/tmp/t5.outfile" from t5; ---enable_ps2_protocol ---enable_cursor_protocol - create temporary table temp_1 engine = innodb as select * from t5 where 1=2; select count(*) from temp_1; diff --git a/mysql-test/suite/period/t/overlaps.test b/mysql-test/suite/period/t/overlaps.test index aca1a9150de..402d8efedac 100644 --- a/mysql-test/suite/period/t/overlaps.test +++ b/mysql-test/suite/period/t/overlaps.test @@ -253,22 +253,14 @@ insert into t values (1, '2020-03-03', '2020-03-10') on duplicate key update x = 2; select * from t; ---disable_cursor_protocol ---disable_ps2_protocol select * into outfile 'tmp_t.txt' from t; ---enable_ps2_protocol ---enable_cursor_protocol load data infile 'tmp_t.txt' into table t; --error ER_NOT_SUPPORTED_YET load data infile 'tmp_t.txt' replace into table t; remove_file $MYSQLD_DATADIR/test/tmp_t.txt; insert into t values (1, '2020-03-01', '2020-03-05'); ---disable_cursor_protocol ---disable_ps2_protocol select * into outfile 'tmp_t.txt' from t; ---enable_ps2_protocol ---enable_cursor_protocol --error ER_DUP_ENTRY load data infile 'tmp_t.txt' into table t; diff --git a/mysql-test/suite/rpl/r/rpl_drop_db.result b/mysql-test/suite/rpl/r/rpl_drop_db.result index 3712527afe4..fbe1cc1dea5 100644 --- a/mysql-test/suite/rpl/r/rpl_drop_db.result +++ b/mysql-test/suite/rpl/r/rpl_drop_db.result @@ -1,7 +1,6 @@ include/master-slave.inc [connection master] connection master; -drop database if exists mysqltest1; create database mysqltest1; create table mysqltest1.t1 (n int); insert into mysqltest1.t1 values (1); diff --git a/mysql-test/suite/rpl/r/rpl_loaddata_map.result b/mysql-test/suite/rpl/r/rpl_loaddata_map.result index cc67c8d4660..65553c405c4 100644 --- a/mysql-test/suite/rpl/r/rpl_loaddata_map.result +++ b/mysql-test/suite/rpl/r/rpl_loaddata_map.result @@ -1,6 +1,11 @@ include/master-slave.inc [connection master] ==== Create a big file ==== +SET @@sql_log_bin= 0; +create table t1 (id int not null primary key auto_increment); +select * into outfile '$MYSQLTEST_VARDIR/tmp/bug30435_5k.txt' from t1; +DROP TABLE t1; +SET @@sql_log_bin= 1; ==== Load our big file into a table ==== create table t2 (id int not null primary key auto_increment); select @@session.read_buffer_size - @@session.max_allowed_packet > 0 ; diff --git a/mysql-test/suite/rpl/r/rpl_loadfile.result b/mysql-test/suite/rpl/r/rpl_loadfile.result index 2afe510ddeb..3c9cabeb497 100644 --- a/mysql-test/suite/rpl/r/rpl_loadfile.result +++ b/mysql-test/suite/rpl/r/rpl_loadfile.result @@ -229,7 +229,6 @@ connection slave; include/rpl_reset.inc connection master; SELECT repeat('x',20) INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/bug_39701.data'; -DROP TABLE IF EXISTS t1; CREATE TABLE t1 (t text); CREATE PROCEDURE p(file varchar(4096)) BEGIN diff --git a/mysql-test/suite/rpl/t/rpl_binlog_errors.test b/mysql-test/suite/rpl/t/rpl_binlog_errors.test index 25f426d4911..ab95c9b4ee3 100644 --- a/mysql-test/suite/rpl/t/rpl_binlog_errors.test +++ b/mysql-test/suite/rpl/t/rpl_binlog_errors.test @@ -58,11 +58,7 @@ SET @old_debug= @@global.debug_dbug; -- let $load_file= $MYSQLTEST_VARDIR/tmp/bug_46166.data -- let $MYSQLD_DATADIR= `select @@datadir` -- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR ---disable_cursor_protocol ---disable_ps2_protocol -- eval SELECT repeat('x',8192) INTO OUTFILE '$load_file' ---enable_ps2_protocol ---enable_cursor_protocol ### ACTION: create a small file (< 4096 bytes) that will be later used ### in LOAD DATA INFILE to check for absence of binlog errors @@ -71,11 +67,7 @@ SET @old_debug= @@global.debug_dbug; -- let $load_file2= $MYSQLTEST_VARDIR/tmp/bug_46166-2.data -- let $MYSQLD_DATADIR= `select @@datadir` -- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR ---disable_cursor_protocol ---disable_ps2_protocol -- eval SELECT repeat('x',10) INTO OUTFILE '$load_file2' ---enable_ps2_protocol ---enable_cursor_protocol RESET MASTER; diff --git a/mysql-test/suite/rpl/t/rpl_drop_db.test b/mysql-test/suite/rpl/t/rpl_drop_db.test index ef918842d4e..676794e090c 100644 --- a/mysql-test/suite/rpl/t/rpl_drop_db.test +++ b/mysql-test/suite/rpl/t/rpl_drop_db.test @@ -4,19 +4,12 @@ -- source include/master-slave.inc connection master; ---disable_warnings -drop database if exists mysqltest1; ---enable_warnings create database mysqltest1; create table mysqltest1.t1 (n int); insert into mysqltest1.t1 values (1); ---disable_cursor_protocol --enable_prepare_warnings ---disable_ps2_protocol select * from mysqltest1.t1 into outfile 'mysqltest1/f1.txt'; --disable_prepare_warnings ---enable_ps2_protocol ---enable_cursor_protocol create table mysqltest1.t2 (n int); create table mysqltest1.t3 (n int); --replace_result \\ / 66 39 93 39 17 39 247 39 41 39 "File exists" "Directory not empty" diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_local.test b/mysql-test/suite/rpl/t/rpl_loaddata_local.test index 975bd110739..bdeacc522c9 100644 --- a/mysql-test/suite/rpl/t/rpl_loaddata_local.test +++ b/mysql-test/suite/rpl/t/rpl_loaddata_local.test @@ -27,11 +27,7 @@ set SQL_LOG_BIN=1; enable_query_log; let $MYSQLD_DATADIR= `select @@datadir`; --replace_result $MYSQLD_DATADIR MYSQLD_DATADIR ---disable_cursor_protocol ---disable_ps2_protocol eval select * into outfile '$MYSQLD_DATADIR/rpl_loaddatalocal.select_outfile' from t1; ---enable_ps2_protocol ---enable_cursor_protocol #This will generate a 20KB file, now test LOAD DATA LOCAL truncate table t1; --replace_result $MYSQLD_DATADIR MYSQLD_DATADIR @@ -54,11 +50,7 @@ connection master; create table t1(a int); insert into t1 values (1), (2), (2), (3); --replace_result $MYSQLD_DATADIR MYSQLD_DATADIR ---disable_cursor_protocol ---disable_ps2_protocol eval select * into outfile '$MYSQLD_DATADIR/rpl_loaddatalocal.select_outfile' from t1; ---enable_ps2_protocol ---enable_cursor_protocol drop table t1; create table t1(a int primary key); --replace_result $MYSQLD_DATADIR MYSQLD_DATADIR @@ -87,11 +79,7 @@ SET sql_mode='ignore_space'; CREATE TABLE t1(a int); insert into t1 values (1), (2), (3), (4); --replace_result $MYSQLD_DATADIR MYSQLD_DATADIR ---disable_cursor_protocol ---disable_ps2_protocol eval select * into outfile '$MYSQLD_DATADIR/rpl_loaddatalocal.select_outfile' from t1; ---enable_ps2_protocol ---enable_cursor_protocol truncate table t1; --replace_result $MYSQLD_DATADIR MYSQLD_DATADIR eval load data local infile '$MYSQLD_DATADIR/rpl_loaddatalocal.select_outfile' into table t1; @@ -125,11 +113,7 @@ CREATE TABLE t1(a int); INSERT INTO t1 VALUES (1), (2), (3), (4); --replace_result $MYSQLD_DATADIR MYSQLD_DATADIR ---disable_cursor_protocol ---disable_ps2_protocol eval SELECT * INTO OUTFILE '$MYSQLD_DATADIR/bug43746.sql' FROM t1; ---enable_ps2_protocol ---enable_cursor_protocol TRUNCATE TABLE t1; --replace_result $MYSQLD_DATADIR MYSQLD_DATADIR @@ -177,11 +161,7 @@ sync_slave_with_master; connection master; --replace_result $MYSQLD_DATADIR MYSQLD_DATADIR ---disable_cursor_protocol ---disable_ps2_protocol eval SELECT * INTO OUTFILE '$MYSQLD_DATADIR/bug59267.sql' FROM t1; ---enable_ps2_protocol ---enable_cursor_protocol TRUNCATE TABLE t1; --replace_result $MYSQLD_DATADIR MYSQLD_DATADIR @@ -226,11 +206,7 @@ CREATE VIEW v1 AS SELECT * FROM t2 WHERE f1 IN (SELECT f1 FROM t3 WHERE (t3.f2 IS NULL)); --replace_result $MYSQLD_DATADIR MYSQLD_DATADIR ---disable_cursor_protocol ---disable_ps2_protocol eval SELECT 1 INTO OUTFILE '$MYSQLD_DATADIR/bug60580.csv' FROM DUAL; ---enable_ps2_protocol ---enable_cursor_protocol --replace_result $MYSQLD_DATADIR MYSQLD_DATADIR eval LOAD DATA LOCAL INFILE '$MYSQLD_DATADIR/bug60580.csv' INTO TABLE t1 (@f1) SET f2 = (SELECT f1 FROM v1 WHERE f1=@f1); diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_map.test b/mysql-test/suite/rpl/t/rpl_loaddata_map.test index 24477fa0230..4ba4af5f2fb 100644 --- a/mysql-test/suite/rpl/t/rpl_loaddata_map.test +++ b/mysql-test/suite/rpl/t/rpl_loaddata_map.test @@ -26,26 +26,22 @@ source include/master-slave.inc; # just an auxiliary construction anyways, it is not needed on the # slave. ---disable_query_log SET @@sql_log_bin= 0; -let $rows= 5000; create table t1 (id int not null primary key auto_increment); +--disable_query_log +let $rows= 5000; while($rows) { eval insert into t1 values (null); dec $rows; } ---disable_cursor_protocol ---disable_ps2_protocol -eval select * into outfile '$MYSQLTEST_VARDIR/tmp/bug30435_5k.txt' from t1; ---enable_ps2_protocol ---enable_cursor_protocol +--enable_query_log +evalp select * into outfile '$MYSQLTEST_VARDIR/tmp/bug30435_5k.txt' from t1; DROP TABLE t1; SET @@sql_log_bin= 1; ---enable_query_log --echo ==== Load our big file into a table ==== diff --git a/mysql-test/suite/rpl/t/rpl_loadfile.test b/mysql-test/suite/rpl/t/rpl_loadfile.test index edb72dc9925..eb6d65f4686 100644 --- a/mysql-test/suite/rpl/t/rpl_loadfile.test +++ b/mysql-test/suite/rpl/t/rpl_loadfile.test @@ -69,15 +69,7 @@ connection master; let $file= $MYSQLTEST_VARDIR/tmp/bug_39701.data; --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR ---disable_cursor_protocol ---disable_ps2_protocol --eval SELECT repeat('x',20) INTO OUTFILE '$file' ---enable_ps2_protocol ---enable_cursor_protocol - -disable_warnings; -DROP TABLE IF EXISTS t1; -enable_warnings; CREATE TABLE t1 (t text); DELIMITER |; diff --git a/mysql-test/suite/rpl/t/rpl_misc_functions.test b/mysql-test/suite/rpl/t/rpl_misc_functions.test index be55a208c3e..974fd9a16d1 100644 --- a/mysql-test/suite/rpl/t/rpl_misc_functions.test +++ b/mysql-test/suite/rpl/t/rpl_misc_functions.test @@ -26,11 +26,7 @@ insert into t1 values(3, 0, 0, 0, password('does_this_work?')); --disable_warnings insert into t1 values(4, connection_id(), rand()*1000, rand()*1000, password('does_this_still_work?')); --enable_warnings ---disable_cursor_protocol ---disable_ps2_protocol select * into outfile 'rpl_misc_functions.outfile' from t1; ---enable_ps2_protocol ---enable_cursor_protocol let $MYSQLD_DATADIR= `select @@datadir`; sync_slave_with_master; create temporary table t2 like t1; @@ -95,12 +91,8 @@ INSERT INTO t1 (col_a) VALUES (test_replication_sf()); --enable_prepare_warnings # Dump table on slave ---disable_cursor_protocol ---disable_ps2_protocol select * from t1 into outfile "../../tmp/t1_slave.txt"; --disable_prepare_warnings ---enable_ps2_protocol ---enable_cursor_protocol # Load data from slave into temp table on master connection master; diff --git a/mysql-test/suite/sys_vars/t/secure_file_priv.test b/mysql-test/suite/sys_vars/t/secure_file_priv.test index 395bdaed343..bbbf01aae89 100644 --- a/mysql-test/suite/sys_vars/t/secure_file_priv.test +++ b/mysql-test/suite/sys_vars/t/secure_file_priv.test @@ -26,9 +26,7 @@ my $protected_file= dirname($ENV{MYSQLTEST_VARDIR}).'/bug50373.txt'; # test runs). unlink $protected_file; open(FILE, ">", "$ENV{MYSQL_TMP_DIR}/bug50373.inc") or die; -print FILE "--disable_ps2_protocol\n"; print FILE "SELECT * FROM t1 INTO OUTFILE '".$protected_file."';\n"; -print FILE "--enable_ps2_protocol\n"; print FILE "DELETE FROM t1;\n"; print FILE "LOAD DATA INFILE '".$protected_file."' INTO TABLE t1;\n"; print FILE "SELECT * FROM t1;\n"; diff --git a/mysql-test/suite/vcol/t/load_data.test b/mysql-test/suite/vcol/t/load_data.test index be247d106b9..f4b3b60397e 100644 --- a/mysql-test/suite/vcol/t/load_data.test +++ b/mysql-test/suite/vcol/t/load_data.test @@ -5,11 +5,7 @@ create table t1 ( c1 varchar(10), c2 varchar(10), c3 int ); insert into t1 values ("a" , "b", 1), ("a" , "b", 2); create table t2 like t1 ; alter table t2 add column c4 bigint unsigned as (CONV(LEFT(MD5(concat(c1,c2,c3)), 16), 16, 10)) persistent unique key; ---disable_cursor_protocol ---disable_ps2_protocol select * into outfile 't1.csv' from t1; ---enable_ps2_protocol ---enable_cursor_protocol load data infile 't1.csv' ignore into table t2 ; select * from t2; insert into t2 (c1,c2,c3) values ("a" , "b", 4); diff --git a/mysql-test/suite/vcol/t/vcol_keys_myisam.test b/mysql-test/suite/vcol/t/vcol_keys_myisam.test index e9207d3bcdd..223da482423 100644 --- a/mysql-test/suite/vcol/t/vcol_keys_myisam.test +++ b/mysql-test/suite/vcol/t/vcol_keys_myisam.test @@ -281,11 +281,7 @@ drop table t1; CREATE TABLE t1 (i INT, d1 DATE, d2 DATE NOT NULL, t TIMESTAMP, KEY(t)) ENGINE=MyISAM; INSERT INTO t1 VALUES (1,'2023-03-16','2023-03-15','2012-12-12 12:12:12'); ALTER TABLE t1 MODIFY t FLOAT AS (i) PERSISTENT; ---disable_cursor_protocol ---disable_ps2_protocol SELECT i, d1, d2 INTO OUTFILE 'load_t1' FROM t1; ---enable_ps2_protocol ---enable_cursor_protocol DELETE FROM t1; LOAD DATA INFILE 'load_t1' INTO TABLE t1 (i,d1,d2); SELECT * FROM t1 WHERE d2 < d1; diff --git a/mysql-test/suite/versioning/t/foreign.test b/mysql-test/suite/versioning/t/foreign.test index 58db815d8f1..1b8bb83f064 100644 --- a/mysql-test/suite/versioning/t/foreign.test +++ b/mysql-test/suite/versioning/t/foreign.test @@ -400,27 +400,15 @@ INSERT INTO t2 VALUES (1,'against'),(2,'q'); SET SQL_MODE= ''; SET timestamp = 2; ---disable_cursor_protocol ---disable_ps2_protocol SELECT * INTO OUTFILE 't1.data' FROM t1; ---enable_ps2_protocol ---enable_cursor_protocol SET timestamp = 3; UPDATE t1 SET f13 = 'q'; SET timestamp = 4; LOAD DATA INFILE 't1.data' REPLACE INTO TABLE t1; ---disable_cursor_protocol ---disable_ps2_protocol SELECT * INTO OUTFILE 't1.data.2' FROM t1; ---enable_ps2_protocol ---enable_cursor_protocol SET timestamp = 5; LOAD DATA INFILE 't1.data.2' REPLACE INTO TABLE t1; ---disable_cursor_protocol ---disable_ps2_protocol SELECT * INTO OUTFILE 't2.data' FROM t2; ---enable_ps2_protocol ---enable_cursor_protocol SET timestamp = 6; LOAD DATA INFILE 't2.data' REPLACE INTO TABLE t2; SET FOREIGN_KEY_CHECKS = OFF; @@ -563,11 +551,7 @@ delete from t0; --error ER_ROW_IS_REFERENCED_2 replace t0 values (1); ---disable_cursor_protocol ---disable_ps2_protocol select * into outfile 'load_t0' from t0 ; ---enable_ps2_protocol ---enable_cursor_protocol --error ER_ROW_IS_REFERENCED_2 load data infile 'load_t0' replace into table t0; diff --git a/mysql-test/suite/versioning/t/insert.test b/mysql-test/suite/versioning/t/insert.test index 7c1b4fed361..7b197cabf7c 100644 --- a/mysql-test/suite/versioning/t/insert.test +++ b/mysql-test/suite/versioning/t/insert.test @@ -192,11 +192,7 @@ replace into t3 values (0, '1980-01-01 00:00:00', '1981-01-01 00:00:00'); --echo # LOAD DATA --let DATAFILE= $MYSQLTEST_VARDIR/tmp/test_versioning_t3.data --replace_result $DATAFILE DATAFILE ---disable_cursor_protocol ---disable_ps2_protocol eval select x, row_start, row_end into outfile '$DATAFILE' from t1 for system_time all; ---enable_ps2_protocol ---enable_cursor_protocol create or replace table t2 like t1; --replace_result $default_engine DEFAULT_ENGINE show create table t2; @@ -253,11 +249,7 @@ set sql_mode='STRICT_ALL_TABLES'; create or replace table t1 (a int) with system versioning; set system_versioning_insert_history= on; insert into t1 (a,row_start,row_end) values (1,'2022-01-01','2023-01-01'),(1,'2022-01-01','2023-01-01'); ---disable_cursor_protocol ---disable_ps2_protocol select a,row_start,row_end into outfile 'mdev29813.txt' from t1 for system_time all; ---enable_ps2_protocol ---enable_cursor_protocol create or replace table t1 (a int primary key) with system versioning; load data infile 'mdev29813.txt' ignore into table t1 (a,row_start,row_end); diff --git a/mysql-test/suite/versioning/t/partition.test b/mysql-test/suite/versioning/t/partition.test index ed1f66dadc7..74a86ddaac8 100644 --- a/mysql-test/suite/versioning/t/partition.test +++ b/mysql-test/suite/versioning/t/partition.test @@ -1019,16 +1019,12 @@ create or replace table t1 ( insert into t1 () values (),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(); ---disable_cursor_protocol ---disable_ps2_protocol select * into outfile 'MDEV-17891.data' from t1; ---enable_ps2_protocol load data infile 'MDEV-17891.data' replace into table t1; --error ER_RECORD_FILE_FULL load data infile 'MDEV-17891.data' replace into table t1; --error ER_RECORD_FILE_FULL load data infile 'MDEV-17891.data' replace into table t1; ---enable_cursor_protocol # Cleanup --remove_file $datadir/test/MDEV-17891.data @@ -1369,11 +1365,7 @@ partition by system_time limit 100 ( partition pn current); insert into t1 select seq from seq_0_to_49; ---disable_cursor_protocol ---disable_ps2_protocol select x into outfile 'MDEV-20077.data' from t1; ---enable_ps2_protocol ---enable_cursor_protocol load data infile 'MDEV-20077.data' replace into table t1 (x); load data infile 'MDEV-20077.data' replace into table t1 (x); @@ -2212,11 +2204,7 @@ create or replace table t1 (x int primary key) with system versioning partition by system_time interval 1 hour auto; insert t1 values (1), (2), (3); ---disable_cursor_protocol ---disable_ps2_protocol select x into outfile 'MDEV-17554.data' from t1; ---enable_ps2_protocol ---enable_cursor_protocol set timestamp= unix_timestamp('2000-01-01 01:00:00'); load data infile 'MDEV-17554.data' replace into table t1 (x); diff --git a/mysql-test/suite/versioning/t/replace.test b/mysql-test/suite/versioning/t/replace.test index c10b6aa443d..abae4f3d3cb 100644 --- a/mysql-test/suite/versioning/t/replace.test +++ b/mysql-test/suite/versioning/t/replace.test @@ -93,11 +93,7 @@ if ($default_engine == MEMORY) create table t1 (a int, b int, c int, vc int as (c), unique(a), unique(b)) with system versioning; insert ignore into t1 (a,b,c) values (1,2,3); ---disable_cursor_protocol ---disable_ps2_protocol select a, b, c into outfile '15330.data' from t1; ---enable_ps2_protocol ---enable_cursor_protocol load data infile '15330.data' ignore into table t1 (a,b,c); load data infile '15330.data' replace into table t1 (a,b,c); --let $datadir=`select @@datadir` diff --git a/mysql-test/suite/versioning/t/rpl.test b/mysql-test/suite/versioning/t/rpl.test index 76e537085e4..9fe3750a18c 100644 --- a/mysql-test/suite/versioning/t/rpl.test +++ b/mysql-test/suite/versioning/t/rpl.test @@ -414,11 +414,7 @@ select row_start = '1980-01-01 00:00:00', row_end = '1980-01-01 00:00:01' from t connection master; --let DATAFILE= $MYSQLTEST_VARDIR/tmp/test_versioning_t3.data --replace_result $DATAFILE DATAFILE ---disable_cursor_protocol ---disable_ps2_protocol eval select x, row_start, row_end into outfile '$DATAFILE' from t1 for system_time all; ---enable_ps2_protocol ---enable_cursor_protocol create or replace table t3 like t1; set @@system_versioning_insert_history= 1; --replace_result $DATAFILE DATAFILE From b1daecfc45145ce9e259a893ffed01e77af7217b Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 13 Jul 2025 09:36:08 +0200 Subject: [PATCH 126/172] MDEV-30190 Password check plugin prevents changing grants for CURRENT_USER CURRENT_USER should not initialize $$->auth, just like explicitly specified user name doesn't. --- .../plugins/r/simple_password_check.result | 18 +++++++++++++++++- .../suite/plugins/t/simple_password_check.test | 15 ++++++++++++++- sql/sql_yacc.yy | 1 - 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/plugins/r/simple_password_check.result b/mysql-test/suite/plugins/r/simple_password_check.result index 0826b7f6637..8046761d708 100644 --- a/mysql-test/suite/plugins/r/simple_password_check.result +++ b/mysql-test/suite/plugins/r/simple_password_check.result @@ -261,6 +261,22 @@ install soname "simple_password_check"; MARIADB-ADMIN: unable to change password; error: 'The MariaDB server is running with the --strict-password-validation option so it cannot execute this statement' # All done uninstall plugin simple_password_check; -# # End of 10.4 tests # +# MDEV-30190 Password check plugin prevents changing grants for CURRENT_USER +# +select priv into @old_priv from mysql.global_priv where user='root' and host='localhost'; +install soname "simple_password_check"; +grant all on db1.* to current_user; +select current_user; +current_user +root@localhost +show grants; +Grants for root@localhost +GRANT ALL PRIVILEGES ON *.* TO `root`@`localhost` WITH GRANT OPTION +GRANT ALL PRIVILEGES ON `db1`.* TO `root`@`localhost` +GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION +revoke all on db1.* from current_user; +uninstall plugin simple_password_check; +update mysql.global_priv set priv=@old_priv where user='root' and host='localhost'; +# End of 10.11 tests diff --git a/mysql-test/suite/plugins/t/simple_password_check.test b/mysql-test/suite/plugins/t/simple_password_check.test index 442585e89d4..5b55512591e 100644 --- a/mysql-test/suite/plugins/t/simple_password_check.test +++ b/mysql-test/suite/plugins/t/simple_password_check.test @@ -165,6 +165,19 @@ install soname "simple_password_check"; --echo # All done uninstall plugin simple_password_check; ---echo # --echo # End of 10.4 tests + --echo # +--echo # MDEV-30190 Password check plugin prevents changing grants for CURRENT_USER +--echo # +select priv into @old_priv from mysql.global_priv where user='root' and host='localhost'; +install soname "simple_password_check"; +grant all on db1.* to current_user; +select current_user; +show grants; +revoke all on db1.* from current_user; +uninstall plugin simple_password_check; +#cleanup +update mysql.global_priv set priv=@old_priv where user='root' and host='localhost'; + +--echo # End of 10.11 tests diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index b2b8aca2eb6..ed1942ff70b 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -15505,7 +15505,6 @@ user_maybe_role: if (unlikely(!($$=(LEX_USER*)thd->calloc(sizeof(LEX_USER))))) MYSQL_YYABORT; $$->user= current_user; - $$->auth= new (thd->mem_root) USER_AUTH(); } ; From c05b1fe2c22599ac0ab91b45b57d8c70e2ea5a1c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 13 Jul 2025 09:46:40 +0200 Subject: [PATCH 127/172] MDEV-21654 binary library file pam_mariadb_mtr.so installed among test data files lintian complains: arch-dependent-file-in-usr-share arch-independent-package-contains-binary-or-object --- debian/mariadb-test-data.lintian-overrides | 3 --- plugin/auth_pam/testing/CMakeLists.txt | 8 +++++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/debian/mariadb-test-data.lintian-overrides b/debian/mariadb-test-data.lintian-overrides index 99e72007c16..cbd77e02830 100644 --- a/debian/mariadb-test-data.lintian-overrides +++ b/debian/mariadb-test-data.lintian-overrides @@ -1,6 +1,3 @@ -# These should be moved, see https://jira.mariadb.org/browse/MDEV-21654 -arch-dependent-file-in-usr-share [usr/share/mysql/mysql-test/suite/plugins/pam/pam_mariadb_mtr.so] -arch-independent-package-contains-binary-or-object [usr/share/mysql/mysql-test/suite/plugins/pam/pam_mariadb_mtr.so] # Mainly for support for *BSD family. Not right way to do but this is test package and not for production incorrect-path-for-interpreter /usr/bin/env perl != /usr/bin/perl [usr/share/mysql/mysql-test/std_data/checkDBI_DBD-MariaDB.pl] incorrect-path-for-interpreter /usr/bin/env perl != /usr/bin/perl [usr/share/mysql/mysql-test/suite/engines/rr_trx/run_stress_tx_rr.pl] diff --git a/plugin/auth_pam/testing/CMakeLists.txt b/plugin/auth_pam/testing/CMakeLists.txt index 151823b9419..9217e23ce02 100644 --- a/plugin/auth_pam/testing/CMakeLists.txt +++ b/plugin/auth_pam/testing/CMakeLists.txt @@ -10,6 +10,8 @@ IF(CMAKE_C_COMPILER_ID MATCHES "Clang") PROPERTY COMPILE_FLAGS "-Wno-incompatible-pointer-types-discards-qualifiers") ENDIF() -SET(dest DESTINATION "${INSTALL_MYSQLTESTDIR}/suite/plugins/pam" COMPONENT Test) -INSTALL(TARGETS pam_mariadb_mtr ${dest}) -INSTALL(FILES mariadb_mtr.conf RENAME mariadb_mtr ${dest}) +IF (NOT DEB) # avoid arch-dependent-file-in-usr-share error + SET(dest DESTINATION "${INSTALL_MYSQLTESTDIR}/suite/plugins/pam" COMPONENT Test) + INSTALL(TARGETS pam_mariadb_mtr ${dest}) + INSTALL(FILES mariadb_mtr.conf RENAME mariadb_mtr ${dest}) +ENDIF() From 552c477950356b6cf788e31160d0880aa85ffc87 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Thu, 19 Sep 2024 09:31:54 +0200 Subject: [PATCH 128/172] MDEV-34926: mysql-install-db suggests a deprecated procedure Fixed to recommended command name. --- scripts/mysql_install_db.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh index 18fd532e919..3350d69c44d 100644 --- a/scripts/mysql_install_db.sh +++ b/scripts/mysql_install_db.sh @@ -667,7 +667,7 @@ then echo echo "Two all-privilege accounts were created." echo "One is root@localhost, it has no password, but you need to" - echo "be system 'root' user to connect. Use, for example, sudo mysql" + echo "be system 'root' user to connect. Use, for example, sudo mariadb" echo "The second is $auth_root_socket_user@localhost, it has no password either, but" echo "you need to be the system '$auth_root_socket_user' user to connect." echo "After connecting you can set the password, if you would need to be" From 67745e4dbf6c4bfef9ad2e7a564af3d17aef004f Mon Sep 17 00:00:00 2001 From: Rex Date: Thu, 2 Feb 2023 06:29:05 +1200 Subject: [PATCH 129/172] MDEV-30334 Optimizer trace produces invalid JSON with WHERE subquery Simple code rearrangement to stop it displaying an unsigned int in a String. --- mysql-test/main/opt_trace.result | 17 +++++++++++++++++ mysql-test/main/opt_trace.test | 17 +++++++++++++++++ sql/sql_select.cc | 5 ++++- 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/opt_trace.result b/mysql-test/main/opt_trace.result index 029f795b4fa..866f21e7b1b 100644 --- a/mysql-test/main/opt_trace.result +++ b/mysql-test/main/opt_trace.result @@ -10374,6 +10374,23 @@ exp1 exp2 ] 1 DROP TABLE t1; # +# MDEV-30334 Optimizer trace produces invalid JSON with WHERE subquery +# Simple code rearrangement to stop it displaying an unsigned int in a String. +# +SET optimizer_trace= 'enabled=on'; +CREATE TABLE t1 (id INT PRIMARY KEY); +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (a INT); +INSERT INTO t2 VALUES (3),(4); +SELECT * FROM t1 WHERE id < ( SELECT SUM(a) FROM t2 ); +id +1 +2 +SELECT JSON_VALID(trace) FROM information_schema.optimizer_trace; +JSON_VALID(trace) +1 +DROP TABLE t1, t2; +# # End of 10.4 tests # set optimizer_trace='enabled=on'; diff --git a/mysql-test/main/opt_trace.test b/mysql-test/main/opt_trace.test index fa51cfbb603..d3de3883d23 100644 --- a/mysql-test/main/opt_trace.test +++ b/mysql-test/main/opt_trace.test @@ -883,6 +883,23 @@ SELECT b, a FROM t1 WHERE b <> 'p' OR a = 4 GROUP BY b, a HAVING a <= 7; SELECT DROP TABLE t1; --enable_view_protocol +--echo # +--echo # MDEV-30334 Optimizer trace produces invalid JSON with WHERE subquery +--echo # Simple code rearrangement to stop it displaying an unsigned int in a String. +--echo # + +SET optimizer_trace= 'enabled=on'; + +CREATE TABLE t1 (id INT PRIMARY KEY); +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (a INT); +INSERT INTO t2 VALUES (3),(4); + +SELECT * FROM t1 WHERE id < ( SELECT SUM(a) FROM t2 ); +SELECT JSON_VALID(trace) FROM information_schema.optimizer_trace; + +DROP TABLE t1, t2; + --echo # --echo # End of 10.4 tests --echo # diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b96ebf237af..e66a98b71d2 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -30812,6 +30812,8 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) } } str->append(STRING_WITH_LEN(" */ ")); + if (join && join->cleaned) // if this join has been cleaned + return; // the select_number printed above is all we have } if (sel_type == SELECT_CMD || @@ -30826,10 +30828,11 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) because temporary tables they pointed on could be freed. */ str->append('#'); - str->append(select_number); + str->append_ulonglong(select_number); return; } + /* First add options */ if (options & SELECT_STRAIGHT_JOIN) str->append(STRING_WITH_LEN("straight_join ")); From 9a51709dba2ecd2d3585cd8732db5cca5f55317d Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 9 Jul 2025 15:45:35 +0300 Subject: [PATCH 130/172] MDEV-29001 DROP DEFAULT makes SHOW CREATE non-idempotent DROP DEFAULT adds DEFAULT NULL in case of nullable column. In case of NOT NULL column it drops default expression if any exists. --- mysql-test/main/alter_table.result | 36 ++++++++ mysql-test/main/alter_table.test | 24 +++++ .../main/column_compression_parts.result | 2 +- mysql-test/main/column_compression_parts.test | 1 - .../funcs/r/ta_set_drop_default.result | 88 +++++-------------- mysql-test/suite/innodb/r/innodb-alter.result | 2 +- .../suite/innodb/r/innodb-wl5980-alter.result | 2 +- sql/sql_table.cc | 3 +- .../mysql-test/rocksdb/r/alter_table.result | 18 ++-- 9 files changed, 96 insertions(+), 80 deletions(-) diff --git a/mysql-test/main/alter_table.result b/mysql-test/main/alter_table.result index c033ae26dad..0dda2d8b5b4 100644 --- a/mysql-test/main/alter_table.result +++ b/mysql-test/main/alter_table.result @@ -3131,6 +3131,42 @@ alter table t1 drop constraint t1_fk_t2_id, drop t2_id, drop t2_id; ERROR 42000: Can't DROP COLUMN `t2_id`; check that it exists drop table t1, t2; # +# MDEV-29001 DROP DEFAULT makes SHOW CREATE non-idempotent +# +SET @save_sql_mode=@@sql_mode; +SET sql_mode=strict_all_tables; +create table t1 ( +a int, +b int default 0, +c int not null, +d int not null default 1); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT 0, + `c` int(11) NOT NULL, + `d` int(11) NOT NULL DEFAULT 1 +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +alter table t1 +alter a drop default, +alter b drop default, +alter c drop default, +alter d drop default; +SHOW create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + `c` int(11) NOT NULL, + `d` int(11) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +insert t1 values (default, default, default, default); +ERROR HY000: Field 'c' doesn't have a default value +insert t1 values (default, default, 0, 0); +drop table t1; +set sql_mode= @save_sql_mode; +# # End of 10.6 tests # # diff --git a/mysql-test/main/alter_table.test b/mysql-test/main/alter_table.test index dd496352deb..5165d034da8 100644 --- a/mysql-test/main/alter_table.test +++ b/mysql-test/main/alter_table.test @@ -2417,6 +2417,30 @@ create table t1(id int primary key, t2_id int, constraint t1_fk_t2_id foreign ke alter table t1 drop constraint t1_fk_t2_id, drop t2_id, drop t2_id; drop table t1, t2; +--echo # +--echo # MDEV-29001 DROP DEFAULT makes SHOW CREATE non-idempotent +--echo # +SET @save_sql_mode=@@sql_mode; +SET sql_mode=strict_all_tables; +create table t1 ( + a int, + b int default 0, + c int not null, + d int not null default 1); +show create table t1; +alter table t1 + alter a drop default, + alter b drop default, + alter c drop default, + alter d drop default; +SHOW create table t1; +--error ER_NO_DEFAULT_FOR_FIELD +insert t1 values (default, default, default, default); +insert t1 values (default, default, 0, 0); + +drop table t1; +set sql_mode= @save_sql_mode; + --echo # --echo # End of 10.6 tests --echo # diff --git a/mysql-test/main/column_compression_parts.result b/mysql-test/main/column_compression_parts.result index e960ff71927..57f65957591 100644 --- a/mysql-test/main/column_compression_parts.result +++ b/mysql-test/main/column_compression_parts.result @@ -127,7 +127,6 @@ ALTER TABLE t1 MODIFY COLUMN a VARCHAR(1000); ALTER TABLE t1 ALTER COLUMN a DROP DEFAULT; INSERT INTO t1 VALUES (REPEAT('b',100),11); INSERT INTO t1 VALUES (default,10); -ERROR HY000: Field 'a' doesn't have a default value ALTER TABLE t1 MODIFY COLUMN a VARCHAR(1000) COMPRESSED; SHOW CREATE TABLE t1; Table Create Table @@ -139,6 +138,7 @@ t1 CREATE TABLE `t1` ( (PARTITION `p0` VALUES LESS THAN (100,'sss') ENGINE = MyISAM) SELECT * from t1 ORDER BY id; a id +NULL 10 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 11 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 23 zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz 24 diff --git a/mysql-test/main/column_compression_parts.test b/mysql-test/main/column_compression_parts.test index 4c77a7308f7..607603ffbde 100644 --- a/mysql-test/main/column_compression_parts.test +++ b/mysql-test/main/column_compression_parts.test @@ -72,7 +72,6 @@ ALTER TABLE t1 ALTER COLUMN a DROP DEFAULT; ALTER TABLE t1 MODIFY COLUMN a VARCHAR(1000); ALTER TABLE t1 ALTER COLUMN a DROP DEFAULT; INSERT INTO t1 VALUES (REPEAT('b',100),11); ---error ER_NO_DEFAULT_FOR_FIELD INSERT INTO t1 VALUES (default,10); ALTER TABLE t1 MODIFY COLUMN a VARCHAR(1000) COMPRESSED; diff --git a/mysql-test/suite/engines/funcs/r/ta_set_drop_default.result b/mysql-test/suite/engines/funcs/r/ta_set_drop_default.result index 1647669eb40..dc4597e8b44 100644 --- a/mysql-test/suite/engines/funcs/r/ta_set_drop_default.result +++ b/mysql-test/suite/engines/funcs/r/ta_set_drop_default.result @@ -24,8 +24,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ALTER TABLE t1 ALTER c2 DROP DEFAULT; INSERT IGNORE INTO t1(c1) VALUES(2); -Warnings: -Warning 1364 Field 'c2' doesn't have a default value SELECT * FROM t1 ORDER BY c1; c1 c2 1 10 @@ -34,7 +32,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` tinyint(4) NOT NULL, - `c2` tinyint(4), + `c2` tinyint(4) DEFAULT NULL, PRIMARY KEY (`c1`) ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; @@ -65,8 +63,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ALTER TABLE t1 ALTER c2 DROP DEFAULT; INSERT IGNORE INTO t1(c1) VALUES(2); -Warnings: -Warning 1364 Field 'c2' doesn't have a default value SELECT * FROM t1 ORDER BY c1; c1 c2 1 10 @@ -75,7 +71,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` smallint(6) NOT NULL, - `c2` smallint(6), + `c2` smallint(6) DEFAULT NULL, PRIMARY KEY (`c1`) ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; @@ -106,8 +102,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ALTER TABLE t1 ALTER c2 DROP DEFAULT; INSERT IGNORE INTO t1(c1) VALUES(2); -Warnings: -Warning 1364 Field 'c2' doesn't have a default value SELECT * FROM t1 ORDER BY c1; c1 c2 1 10 @@ -116,7 +110,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` mediumint(9) NOT NULL, - `c2` mediumint(9), + `c2` mediumint(9) DEFAULT NULL, PRIMARY KEY (`c1`) ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; @@ -147,8 +141,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ALTER TABLE t1 ALTER c2 DROP DEFAULT; INSERT IGNORE INTO t1(c1) VALUES(2); -Warnings: -Warning 1364 Field 'c2' doesn't have a default value SELECT * FROM t1 ORDER BY c1; c1 c2 1 10 @@ -157,7 +149,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` int(11) NOT NULL, - `c2` int(11), + `c2` int(11) DEFAULT NULL, PRIMARY KEY (`c1`) ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; @@ -188,8 +180,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ALTER TABLE t1 ALTER c2 DROP DEFAULT; INSERT IGNORE INTO t1(c1) VALUES(2); -Warnings: -Warning 1364 Field 'c2' doesn't have a default value SELECT * FROM t1 ORDER BY c1; c1 c2 1 10 @@ -198,7 +188,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` int(11) NOT NULL, - `c2` int(11), + `c2` int(11) DEFAULT NULL, PRIMARY KEY (`c1`) ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; @@ -229,8 +219,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ALTER TABLE t1 ALTER c2 DROP DEFAULT; INSERT IGNORE INTO t1(c1) VALUES(2); -Warnings: -Warning 1364 Field 'c2' doesn't have a default value SELECT * FROM t1 ORDER BY c1; c1 c2 1 10 @@ -239,7 +227,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` bigint(20) NOT NULL, - `c2` bigint(20), + `c2` bigint(20) DEFAULT NULL, PRIMARY KEY (`c1`) ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; @@ -270,8 +258,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ALTER TABLE t1 ALTER c2 DROP DEFAULT; INSERT IGNORE INTO t1(c1) VALUES(2); -Warnings: -Warning 1364 Field 'c2' doesn't have a default value SELECT * FROM t1 ORDER BY c1; c1 c2 1 10 @@ -280,7 +266,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` double NOT NULL, - `c2` double, + `c2` double DEFAULT NULL, PRIMARY KEY (`c1`) ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; @@ -311,8 +297,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ALTER TABLE t1 ALTER c2 DROP DEFAULT; INSERT IGNORE INTO t1(c1) VALUES(2); -Warnings: -Warning 1364 Field 'c2' doesn't have a default value SELECT * FROM t1 ORDER BY c1; c1 c2 1 10 @@ -321,7 +305,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` double NOT NULL, - `c2` double, + `c2` double DEFAULT NULL, PRIMARY KEY (`c1`) ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; @@ -352,8 +336,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ALTER TABLE t1 ALTER c2 DROP DEFAULT; INSERT IGNORE INTO t1(c1) VALUES(2); -Warnings: -Warning 1364 Field 'c2' doesn't have a default value SELECT * FROM t1 ORDER BY c1; c1 c2 1 10 @@ -362,7 +344,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` float NOT NULL, - `c2` float, + `c2` float DEFAULT NULL, PRIMARY KEY (`c1`) ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; @@ -393,8 +375,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ALTER TABLE t1 ALTER c2 DROP DEFAULT; INSERT IGNORE INTO t1(c1) VALUES(2); -Warnings: -Warning 1364 Field 'c2' doesn't have a default value SELECT * FROM t1 ORDER BY c1; c1 c2 1 10 @@ -403,7 +383,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` decimal(10,0) NOT NULL, - `c2` decimal(10,0), + `c2` decimal(10,0) DEFAULT NULL, PRIMARY KEY (`c1`) ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; @@ -434,8 +414,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ALTER TABLE t1 ALTER c2 DROP DEFAULT; INSERT IGNORE INTO t1(c1) VALUES(2); -Warnings: -Warning 1364 Field 'c2' doesn't have a default value SELECT * FROM t1 ORDER BY c1; c1 c2 1 10 @@ -444,7 +422,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` decimal(10,0) NOT NULL, - `c2` decimal(10,0), + `c2` decimal(10,0) DEFAULT NULL, PRIMARY KEY (`c1`) ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; @@ -475,8 +453,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ALTER TABLE t1 ALTER COLUMN c2 DROP DEFAULT; INSERT IGNORE INTO t1(c1) VALUES(2); -Warnings: -Warning 1364 Field 'c2' doesn't have a default value SELECT * FROM t1 ORDER BY c1; c1 c2 1 10 @@ -485,7 +461,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` tinyint(4) NOT NULL, - `c2` tinyint(4), + `c2` tinyint(4) DEFAULT NULL, PRIMARY KEY (`c1`) ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; @@ -516,8 +492,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ALTER TABLE t1 ALTER COLUMN c2 DROP DEFAULT; INSERT IGNORE INTO t1(c1) VALUES(2); -Warnings: -Warning 1364 Field 'c2' doesn't have a default value SELECT * FROM t1 ORDER BY c1; c1 c2 1 10 @@ -526,7 +500,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` smallint(6) NOT NULL, - `c2` smallint(6), + `c2` smallint(6) DEFAULT NULL, PRIMARY KEY (`c1`) ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; @@ -557,8 +531,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ALTER TABLE t1 ALTER COLUMN c2 DROP DEFAULT; INSERT IGNORE INTO t1(c1) VALUES(2); -Warnings: -Warning 1364 Field 'c2' doesn't have a default value SELECT * FROM t1 ORDER BY c1; c1 c2 1 10 @@ -567,7 +539,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` mediumint(9) NOT NULL, - `c2` mediumint(9), + `c2` mediumint(9) DEFAULT NULL, PRIMARY KEY (`c1`) ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; @@ -598,8 +570,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ALTER TABLE t1 ALTER COLUMN c2 DROP DEFAULT; INSERT IGNORE INTO t1(c1) VALUES(2); -Warnings: -Warning 1364 Field 'c2' doesn't have a default value SELECT * FROM t1 ORDER BY c1; c1 c2 1 10 @@ -608,7 +578,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` int(11) NOT NULL, - `c2` int(11), + `c2` int(11) DEFAULT NULL, PRIMARY KEY (`c1`) ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; @@ -639,8 +609,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ALTER TABLE t1 ALTER COLUMN c2 DROP DEFAULT; INSERT IGNORE INTO t1(c1) VALUES(2); -Warnings: -Warning 1364 Field 'c2' doesn't have a default value SELECT * FROM t1 ORDER BY c1; c1 c2 1 10 @@ -649,7 +617,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` int(11) NOT NULL, - `c2` int(11), + `c2` int(11) DEFAULT NULL, PRIMARY KEY (`c1`) ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; @@ -680,8 +648,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ALTER TABLE t1 ALTER COLUMN c2 DROP DEFAULT; INSERT IGNORE INTO t1(c1) VALUES(2); -Warnings: -Warning 1364 Field 'c2' doesn't have a default value SELECT * FROM t1 ORDER BY c1; c1 c2 1 10 @@ -690,7 +656,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` bigint(20) NOT NULL, - `c2` bigint(20), + `c2` bigint(20) DEFAULT NULL, PRIMARY KEY (`c1`) ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; @@ -721,8 +687,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ALTER TABLE t1 ALTER COLUMN c2 DROP DEFAULT; INSERT IGNORE INTO t1(c1) VALUES(2); -Warnings: -Warning 1364 Field 'c2' doesn't have a default value SELECT * FROM t1 ORDER BY c1; c1 c2 1 10 @@ -731,7 +695,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` double NOT NULL, - `c2` double, + `c2` double DEFAULT NULL, PRIMARY KEY (`c1`) ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; @@ -762,8 +726,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ALTER TABLE t1 ALTER COLUMN c2 DROP DEFAULT; INSERT IGNORE INTO t1(c1) VALUES(2); -Warnings: -Warning 1364 Field 'c2' doesn't have a default value SELECT * FROM t1 ORDER BY c1; c1 c2 1 10 @@ -772,7 +734,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` double NOT NULL, - `c2` double, + `c2` double DEFAULT NULL, PRIMARY KEY (`c1`) ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; @@ -803,8 +765,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ALTER TABLE t1 ALTER COLUMN c2 DROP DEFAULT; INSERT IGNORE INTO t1(c1) VALUES(2); -Warnings: -Warning 1364 Field 'c2' doesn't have a default value SELECT * FROM t1 ORDER BY c1; c1 c2 1 10 @@ -813,7 +773,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` float NOT NULL, - `c2` float, + `c2` float DEFAULT NULL, PRIMARY KEY (`c1`) ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; @@ -844,8 +804,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ALTER TABLE t1 ALTER COLUMN c2 DROP DEFAULT; INSERT IGNORE INTO t1(c1) VALUES(2); -Warnings: -Warning 1364 Field 'c2' doesn't have a default value SELECT * FROM t1 ORDER BY c1; c1 c2 1 10 @@ -854,7 +812,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` decimal(10,0) NOT NULL, - `c2` decimal(10,0), + `c2` decimal(10,0) DEFAULT NULL, PRIMARY KEY (`c1`) ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; @@ -885,8 +843,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ALTER TABLE t1 ALTER COLUMN c2 DROP DEFAULT; INSERT IGNORE INTO t1(c1) VALUES(2); -Warnings: -Warning 1364 Field 'c2' doesn't have a default value SELECT * FROM t1 ORDER BY c1; c1 c2 1 10 @@ -895,7 +851,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` decimal(10,0) NOT NULL, - `c2` decimal(10,0), + `c2` decimal(10,0) DEFAULT NULL, PRIMARY KEY (`c1`) ) ENGINE=ENGINE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; diff --git a/mysql-test/suite/innodb/r/innodb-alter.result b/mysql-test/suite/innodb/r/innodb-alter.result index edeebac5f94..baa8ec04bb5 100644 --- a/mysql-test/suite/innodb/r/innodb-alter.result +++ b/mysql-test/suite/innodb/r/innodb-alter.result @@ -52,7 +52,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` int(11) NOT NULL, - `c2` int(11), + `c2` int(11) DEFAULT NULL, `ct` text DEFAULT NULL, PRIMARY KEY (`c1`), KEY `c2` (`c2`) diff --git a/mysql-test/suite/innodb/r/innodb-wl5980-alter.result b/mysql-test/suite/innodb/r/innodb-wl5980-alter.result index 4d6ac474da8..9deda1473cc 100644 --- a/mysql-test/suite/innodb/r/innodb-wl5980-alter.result +++ b/mysql-test/suite/innodb/r/innodb-wl5980-alter.result @@ -59,7 +59,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` int(11) NOT NULL, - `c2` int(11), + `c2` int(11) DEFAULT NULL, `ct` text DEFAULT NULL, PRIMARY KEY (`c1`), KEY `c2` (`c2`) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index c13d49150fb..505926b67ce 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -8658,7 +8658,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, } else { - if ((def->default_value= alter->default_value)) + if ((def->default_value= alter->default_value) || + !(def->flags & NOT_NULL_FLAG)) def->flags&= ~NO_DEFAULT_VALUE_FLAG; else def->flags|= NO_DEFAULT_VALUE_FLAG; diff --git a/storage/rocksdb/mysql-test/rocksdb/r/alter_table.result b/storage/rocksdb/mysql-test/rocksdb/r/alter_table.result index 4ba9834a279..e2ad074f46e 100644 --- a/storage/rocksdb/mysql-test/rocksdb/r/alter_table.result +++ b/storage/rocksdb/mysql-test/rocksdb/r/alter_table.result @@ -26,7 +26,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `pk` int(11) NOT NULL, - `a` int(11), + `a` int(11) DEFAULT NULL, `c` char(8) DEFAULT NULL, `b` int(11) DEFAULT NULL, PRIMARY KEY (`pk`) @@ -37,7 +37,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `b1` char(8) DEFAULT NULL, `pk` int(11) NOT NULL, - `a` int(11), + `a` int(11) DEFAULT NULL, `c` char(8) DEFAULT NULL, PRIMARY KEY (`pk`) ) ENGINE=ROCKSDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci @@ -46,7 +46,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `pk` int(11) NOT NULL, - `a` int(11), + `a` int(11) DEFAULT NULL, `c` char(8) DEFAULT NULL, `b` int(11) DEFAULT NULL, PRIMARY KEY (`pk`) @@ -56,7 +56,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `pk` int(11) NOT NULL, - `a` int(11), + `a` int(11) DEFAULT NULL, `c` char(8) DEFAULT NULL, `b` char(8) DEFAULT NULL, PRIMARY KEY (`pk`) @@ -66,7 +66,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `pk` int(11) NOT NULL, - `a` int(11), + `a` int(11) DEFAULT NULL, `c` char(8) DEFAULT NULL, `b` int(11) DEFAULT NULL, PRIMARY KEY (`pk`) @@ -77,7 +77,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `b` char(8) DEFAULT NULL, `pk` int(11) NOT NULL, - `a` int(11), + `a` int(11) DEFAULT NULL, `c` char(8) DEFAULT NULL, PRIMARY KEY (`pk`) ) ENGINE=ROCKSDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci @@ -86,7 +86,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `pk` int(11) NOT NULL, - `a` int(11), + `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, `c` char(8) DEFAULT NULL, PRIMARY KEY (`pk`) @@ -96,7 +96,7 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `pk` int(11) NOT NULL, - `a` int(11), + `a` int(11) DEFAULT NULL, `c` char(8) DEFAULT NULL, PRIMARY KEY (`pk`) ) ENGINE=ROCKSDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci @@ -107,7 +107,7 @@ SHOW CREATE TABLE t2; Table Create Table t2 CREATE TABLE `t2` ( `pk` int(11) NOT NULL, - `a` int(11), + `a` int(11) DEFAULT NULL, `c` char(8) DEFAULT NULL, PRIMARY KEY (`pk`) ) ENGINE=ROCKSDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci From db3e1edac37ab1cf5c5322dc8613234c88aef9e9 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 16 Jul 2025 13:23:16 +0200 Subject: [PATCH 131/172] MDEV-36814 MariaDB 10.11.9 Signal 11 crash on second Stored Procedure call don't reset thd->lex->current_select, it's not a leftover from previous parsing, it's set in reinit_stmt_before_use() --- mysql-test/main/sp-bugs2.result | 17 +++++++++++++++++ mysql-test/main/sp-bugs2.test | 20 ++++++++++++++++++++ sql/sql_parse.cc | 5 ----- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/mysql-test/main/sp-bugs2.result b/mysql-test/main/sp-bugs2.result index dc56bc4f90b..0a8df79a903 100644 --- a/mysql-test/main/sp-bugs2.result +++ b/mysql-test/main/sp-bugs2.result @@ -42,4 +42,21 @@ t1test(1) wrbyviwb drop function t1test; drop table t1; +# +# MDEV-36814 MariaDB 10.11.9 Signal 11 crash on second Stored Procedure call +# +set names utf8; +create table t1 (a varchar(1000)); +create procedure p1(in p_a varchar(1000)) insert into t1 values (p_a);// +create procedure p2(in s varchar(10)) +begin +if s = '1' then set @startDate = now(); end if; +if s = '2' then set @startDate = '2025-05-23'; end if; +call p1(concat(s, @startDate, ' and ')); +end;// +call p2('1'); +call p2('2'); +drop table t1; +drop procedure p1; +drop procedure p2; # End of 10.11 tests diff --git a/mysql-test/main/sp-bugs2.test b/mysql-test/main/sp-bugs2.test index 9ef35de0899..01c6106c0ca 100644 --- a/mysql-test/main/sp-bugs2.test +++ b/mysql-test/main/sp-bugs2.test @@ -47,4 +47,24 @@ select t1test(1); drop function t1test; drop table t1; +--echo # +--echo # MDEV-36814 MariaDB 10.11.9 Signal 11 crash on second Stored Procedure call +--echo # +set names utf8; +create table t1 (a varchar(1000)); +--delimiter // +create procedure p1(in p_a varchar(1000)) insert into t1 values (p_a);// +create procedure p2(in s varchar(10)) +begin + if s = '1' then set @startDate = now(); end if; + if s = '2' then set @startDate = '2025-05-23'; end if; + call p1(concat(s, @startDate, ' and ')); +end;// +--delimiter ; +call p2('1'); +call p2('2'); +drop table t1; +drop procedure p1; +drop procedure p2; + --echo # End of 10.11 tests diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 62f0bc8fcc8..3657f8127d2 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3072,11 +3072,6 @@ static bool do_execute_sp(THD *thd, sp_head *sp) ha_rows select_limit= thd->variables.select_limit; thd->variables.select_limit= HA_POS_ERROR; - /* - Reset current_select as it may point to random data as a - result of previous parsing. - */ - thd->lex->current_select= NULL; thd->lex->in_sum_func= 0; // For Item_field::fix_fields() /* From aedc65fe10d1e5fd0a66da0aa5b1a23670ce5ef6 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 8 Jul 2025 14:01:50 +0300 Subject: [PATCH 132/172] MDEV-30364 Assertion MDL_EXCLUSIVE on DISCARD TABLESPACE in LOCK TABLE mode In locked_tables_mode when table is opened without MYSQL_OPEN_GET_NEW_TABLE flag it is taken from pre-opened and locked tables. In that case we upgrade its MDL ticket to MDL_EXCLUSIVE before the operation and downgrade after operation. --- mysql-test/main/debug_sync.result | 27 +++++++++++++++++++++ mysql-test/main/debug_sync.test | 40 +++++++++++++++++++++++++++++++ sql/sql_table.cc | 21 +++++++++++++++- 3 files changed, 87 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/debug_sync.result b/mysql-test/main/debug_sync.result index 4c1711a6d6b..6bc2a5cbe24 100644 --- a/mysql-test/main/debug_sync.result +++ b/mysql-test/main/debug_sync.result @@ -320,3 +320,30 @@ SHOW VARIABLES LIKE 'DEBUG_SYNC'; Variable_name Value debug_sync ON - current signals: 's2,s7,s1,s5' SET DEBUG_SYNC= 'RESET'; +# +# MDEV-30364 Assertion MDL_EXCLUSIVE on DISCARD TABLESPACE in LOCK TABLE mode +# +create table t (c int) engine=innodb; +connect con1,localhost,root; +set debug_sync='get_schema_column WAIT_FOR go'; +select column_name from information_schema.columns +where table_schema='test' and table_name='t'; +connection default; +lock table t write; +alter table t discard tablespace; +connect con2,localhost,root; +disconnect con2; +connection default; +ERROR 70100: Query execution was interrupted +set debug_sync='now SIGNAL go'; +connection con1; +column_name +c +disconnect con1; +connection default; +unlock tables; +drop table t; +set debug_sync= 'reset'; +# +# End of 10.6 tests +# diff --git a/mysql-test/main/debug_sync.test b/mysql-test/main/debug_sync.test index 0c5bee3e220..1c8638832c1 100644 --- a/mysql-test/main/debug_sync.test +++ b/mysql-test/main/debug_sync.test @@ -18,6 +18,7 @@ # We need the Debug Sync Facility. # --source include/have_debug_sync.inc +--source include/have_innodb.inc # # We are checking privileges, which the embedded server cannot do. @@ -448,3 +449,42 @@ SHOW VARIABLES LIKE 'DEBUG_SYNC'; # SET DEBUG_SYNC= 'RESET'; +--echo # +--echo # MDEV-30364 Assertion MDL_EXCLUSIVE on DISCARD TABLESPACE in LOCK TABLE mode +--echo # +create table t (c int) engine=innodb; +--connect con1,localhost,root +set debug_sync='get_schema_column WAIT_FOR go'; +send select column_name from information_schema.columns +where table_schema='test' and table_name='t'; + +--connection default +let $wait_condition=select 1 from information_schema.processlist where state like 'debug sync point%'; +--source include/wait_condition.inc +let $connid=`select connection_id()`; +lock table t write; +send alter table t discard tablespace; + +--connect con2,localhost,root +--disable_query_log +--eval kill query $connid +--enable_query_log +--disconnect con2 + +--connection default +--error ER_QUERY_INTERRUPTED +reap; +set debug_sync='now SIGNAL go'; + +--connection con1 +reap; +--disconnect con1 + +--connection default +unlock tables; +drop table t; +set debug_sync= 'reset'; + +--echo # +--echo # End of 10.6 tests +--echo # diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 505926b67ce..7a3a25d3ce0 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5946,6 +5946,8 @@ int mysql_discard_or_import_tablespace(THD *thd, { Alter_table_prelocking_strategy alter_prelocking_strategy; int error; + TABLE *table; + enum_mdl_type mdl_downgrade= MDL_NOT_INITIALIZED; DBUG_ENTER("mysql_discard_or_import_tablespace"); mysql_audit_alter_table(thd, table_list); @@ -5978,7 +5980,21 @@ int mysql_discard_or_import_tablespace(THD *thd, DBUG_RETURN(-1); } - error= table_list->table->file->ha_discard_or_import_tablespace(discard); + table= table_list->table; + DBUG_ASSERT(table->mdl_ticket || table->s->tmp_table); + if (table->mdl_ticket && table->mdl_ticket->get_type() < MDL_EXCLUSIVE) + { + DBUG_ASSERT(thd->locked_tables_mode); + mdl_downgrade= table->mdl_ticket->get_type(); + if (thd->mdl_context.upgrade_shared_lock(table->mdl_ticket, MDL_EXCLUSIVE, + thd->variables.lock_wait_timeout)) + { + error= 1; + goto err; + } + } + + error= table->file->ha_discard_or_import_tablespace(discard); THD_STAGE_INFO(thd, stage_end); @@ -6004,6 +6020,9 @@ int mysql_discard_or_import_tablespace(THD *thd, err: thd->tablespace_op=FALSE; + if (mdl_downgrade > MDL_NOT_INITIALIZED) + table->mdl_ticket->downgrade_lock(mdl_downgrade); + if (likely(error == 0)) { my_ok(thd); From a8eeffb0a3912eea760b7280dbffdbbe19f5b0b6 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 16 Jul 2025 23:19:01 +0200 Subject: [PATCH 133/172] MDEV-18030 waiting_threads-t is disabled enabled. updated to use mysql_* pthread wrappers. reduced the number of iterations to finish in mtr-appropriate time --- unittest/mysys/CMakeLists.txt | 8 ++-- unittest/mysys/lf-t.c | 8 ++-- unittest/mysys/thr_template.c | 6 +-- unittest/mysys/waiting_threads-t.c | 77 ++++++++++++++---------------- 4 files changed, 48 insertions(+), 51 deletions(-) diff --git a/unittest/mysys/CMakeLists.txt b/unittest/mysys/CMakeLists.txt index e35f9d72062..927c0e83dc7 100644 --- a/unittest/mysys/CMakeLists.txt +++ b/unittest/mysys/CMakeLists.txt @@ -13,12 +13,12 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA -MY_ADD_TESTS(bitmap base64 my_atomic my_rdtsc lf my_malloc my_getopt dynstring - byte_order - queues stacktrace stack_allocation crc32 LINK_LIBRARIES mysys) +MY_ADD_TESTS(base64 bitmap byte_order crc32 dynstring lf my_atomic my_getopt + my_malloc my_rdtsc queues stack_allocation stacktrace waiting_threads + LINK_LIBRARIES mysys) MY_ADD_TESTS(my_vsnprintf LINK_LIBRARIES strings mysys) -MY_ADD_TESTS(aes LINK_LIBRARIES mysys mysys_ssl) ADD_DEFINITIONS(${SSL_DEFINES}) +MY_ADD_TESTS(aes LINK_LIBRARIES mysys mysys_ssl) INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIRS}) MY_ADD_TESTS(ma_dyncol LINK_LIBRARIES mysys) diff --git a/unittest/mysys/lf-t.c b/unittest/mysys/lf-t.c index 088ecadd8e0..8f6594bf98e 100644 --- a/unittest/mysys/lf-t.c +++ b/unittest/mysys/lf-t.c @@ -91,7 +91,7 @@ pthread_handler_t test_lf_alloc(void *arg) lf_alloc_free(pins, node2); } lf_alloc_put_pins(pins); - pthread_mutex_lock(&mutex); + mysql_mutex_lock(&mutex); bad+= y; if (--N == 0) @@ -102,7 +102,7 @@ pthread_handler_t test_lf_alloc(void *arg) bad|= lf_allocator.mallocs - lf_alloc_pool_count(&lf_allocator); #endif } - pthread_mutex_unlock(&mutex); + mysql_mutex_unlock(&mutex); if (with_my_thread_init) my_thread_end(); @@ -157,7 +157,7 @@ pthread_handler_t test_lf_hash(void *arg) } } lf_hash_put_pins(pins); - pthread_mutex_lock(&mutex); + mysql_mutex_lock(&mutex); bad+= sum; inserts+= ins; @@ -168,7 +168,7 @@ pthread_handler_t test_lf_hash(void *arg) lf_hash.size, inserts, scans); bad|= lf_hash.count; } - pthread_mutex_unlock(&mutex); + mysql_mutex_unlock(&mutex); if (with_my_thread_init) my_thread_end(); return 0; diff --git a/unittest/mysys/thr_template.c b/unittest/mysys/thr_template.c index 1e715484687..a0113edcb0a 100644 --- a/unittest/mysys/thr_template.c +++ b/unittest/mysys/thr_template.c @@ -19,7 +19,7 @@ #include volatile uint32 bad; -pthread_mutex_t mutex; +mysql_mutex_t mutex; void do_tests(); @@ -57,7 +57,7 @@ int main(int argc __attribute__((unused)), char **argv) if (argv[1] && *argv[1]) DBUG_SET_INITIAL(argv[1]); - pthread_mutex_init(&mutex, 0); + mysql_mutex_init(PSI_NOT_INSTRUMENTED, &mutex, 0); #define CYCLES 30000 #define THREADS 30 @@ -66,7 +66,7 @@ int main(int argc __attribute__((unused)), char **argv) do_tests(); - pthread_mutex_destroy(&mutex); + mysql_mutex_destroy(&mutex); my_end(0); return exit_status(); } diff --git a/unittest/mysys/waiting_threads-t.c b/unittest/mysys/waiting_threads-t.c index 82623157159..9e97bc62c2e 100644 --- a/unittest/mysys/waiting_threads-t.c +++ b/unittest/mysys/waiting_threads-t.c @@ -16,15 +16,16 @@ #include "thr_template.c" #include #include +#include struct test_wt_thd { WT_THD thd; - pthread_mutex_t lock; + mysql_mutex_t lock; } thds[THREADS]; uint i, cnt; -pthread_mutex_t lock; -pthread_cond_t thread_sync; +mysql_mutex_t lock; +mysql_cond_t thread_sync; ulong wt_timeout_short=100, wt_deadlock_search_depth_short=4; ulong wt_timeout_long=10000, wt_deadlock_search_depth_long=15; @@ -49,7 +50,7 @@ pthread_handler_t test_wt(void *arg) my_thread_init(); - pthread_mutex_lock(&mutex); + mysql_mutex_lock(&mutex); id= cnt++; wt_thd_lazy_init(& thds[id].thd, & wt_deadlock_search_depth_short, & wt_timeout_short, @@ -57,11 +58,11 @@ pthread_handler_t test_wt(void *arg) /* now, wait for everybody to be ready to run */ if (cnt >= THREADS) - pthread_cond_broadcast(&thread_sync); + mysql_cond_broadcast(&thread_sync); else while (cnt < THREADS) - pthread_cond_wait(&thread_sync, &mutex); - pthread_mutex_unlock(&mutex); + mysql_cond_wait(&thread_sync, &mutex); + mysql_mutex_unlock(&mutex); my_rnd_init(&rand, (ulong)(intptr)&m, id); if (kill_strategy == YOUNGEST) @@ -72,7 +73,7 @@ pthread_handler_t test_wt(void *arg) for (m= *(int *)arg; m ; m--) { WT_RESOURCE_ID resid; - int blockers[THREADS/10], j, k; + int blockers[THREADS/10]={0}, j, k; resid.value= id; resid.type= &restype; @@ -94,25 +95,25 @@ retry: if (kill_strategy == RANDOM) thds[id].thd.weight= rnd(); - pthread_mutex_lock(& thds[i].lock); + mysql_mutex_lock(& thds[i].lock); res= wt_thd_will_wait_for(& thds[id].thd, & thds[i].thd, &resid); - pthread_mutex_unlock(& thds[i].lock); + mysql_mutex_unlock(& thds[i].lock); } if (!res) { - pthread_mutex_lock(&lock); + mysql_mutex_lock(&lock); res= wt_thd_cond_timedwait(& thds[id].thd, &lock); - pthread_mutex_unlock(&lock); + mysql_mutex_unlock(&lock); } if (res) { - pthread_mutex_lock(& thds[id].lock); - pthread_mutex_lock(&lock); + mysql_mutex_lock(& thds[id].lock); + mysql_mutex_lock(&lock); wt_thd_release_all(& thds[id].thd); - pthread_mutex_unlock(&lock); - pthread_mutex_unlock(& thds[id].lock); + mysql_mutex_unlock(&lock); + mysql_mutex_unlock(& thds[id].lock); if (kill_strategy == LOCKS) thds[id].thd.weight= 0; if (kill_strategy == YOUNGEST) @@ -122,21 +123,21 @@ retry: thds[id].thd.weight++; } - pthread_mutex_lock(&mutex); + mysql_mutex_lock(&mutex); /* wait for everybody to finish */ if (!--cnt) - pthread_cond_broadcast(&thread_sync); + mysql_cond_broadcast(&thread_sync); else while (cnt) - pthread_cond_wait(&thread_sync, &mutex); + mysql_cond_wait(&thread_sync, &mutex); - pthread_mutex_lock(& thds[id].lock); - pthread_mutex_lock(&lock); + mysql_mutex_lock(& thds[id].lock); + mysql_mutex_lock(&lock); wt_thd_release_all(& thds[id].thd); - pthread_mutex_unlock(&lock); - pthread_mutex_unlock(& thds[id].lock); + mysql_mutex_unlock(&lock); + mysql_mutex_unlock(& thds[id].lock); wt_thd_destroy(& thds[id].thd); - pthread_mutex_unlock(&mutex); + mysql_mutex_unlock(&mutex); DBUG_PRINT("wt", ("exiting")); my_thread_end(); @@ -152,7 +153,8 @@ void do_one_test() reset(wt_wait_stats); wt_success_stats=0; cnt=0; - test_concurrently("waiting_threads", test_wt, THREADS, CYCLES); + test_concurrently("waiting_threads", test_wt, THREADS, + CYCLES/(skip_big_tests?500:10)); sum=sum0=0; for (cnt=0; cnt < WT_CYCLE_STATS; cnt++) @@ -179,21 +181,16 @@ void do_one_test() void do_tests() { DBUG_ENTER("do_tests"); - if (skip_big_tests) - { - skip(1, "Big test skipped"); - return; - } plan(13); compile_time_assert(THREADS >= 4); DBUG_PRINT("wt", ("================= initialization ===================")); - pthread_cond_init(&thread_sync, 0); - pthread_mutex_init(&lock, 0); + mysql_cond_init(PSI_NOT_INSTRUMENTED, &thread_sync, 0); + mysql_mutex_init(PSI_NOT_INSTRUMENTED, &lock, 0); wt_init(); for (cnt=0; cnt < THREADS; cnt++) - pthread_mutex_init(& thds[cnt].lock, 0); + mysql_mutex_init(PSI_NOT_INSTRUMENTED, & thds[cnt].lock, 0); { WT_RESOURCE_ID resid[4]; for (i=0; i < array_elements(resid); i++) @@ -218,16 +215,16 @@ void do_tests() ok_wait(0,2,0); ok_wait(0,3,0); - pthread_mutex_lock(&lock); + mysql_mutex_lock(&lock); bad= wt_thd_cond_timedwait(& thds[0].thd, &lock); - pthread_mutex_unlock(&lock); + mysql_mutex_unlock(&lock); ok(bad == WT_TIMEOUT, "timeout test returned %d", bad); ok_wait(0,1,0); ok_wait(1,2,1); ok_deadlock(2,0,2); - pthread_mutex_lock(&lock); + mysql_mutex_lock(&lock); ok(wt_thd_cond_timedwait(& thds[0].thd, &lock) == WT_TIMEOUT, "as always"); ok(wt_thd_cond_timedwait(& thds[1].thd, &lock) == WT_TIMEOUT, "as always"); wt_thd_release_all(& thds[0].thd); @@ -240,7 +237,7 @@ void do_tests() wt_thd_release_all(& thds[i].thd); wt_thd_destroy(& thds[i].thd); } - pthread_mutex_unlock(&lock); + mysql_mutex_unlock(&lock); } wt_deadlock_search_depth_short=6; @@ -277,10 +274,10 @@ void do_tests() DBUG_PRINT("wt", ("================= cleanup ===================")); for (cnt=0; cnt < THREADS; cnt++) - pthread_mutex_destroy(& thds[cnt].lock); + mysql_mutex_destroy(& thds[cnt].lock); wt_end(); - pthread_mutex_destroy(&lock); - pthread_cond_destroy(&thread_sync); + mysql_mutex_destroy(&lock); + mysql_cond_destroy(&thread_sync); DBUG_VOID_RETURN; } From cedfe8eca49506c6b4d2d6868f1014c72caaab36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 17 Jul 2025 12:24:25 +0300 Subject: [PATCH 134/172] MDEV-37250 buf_pool_t::shrink() assertion failure buf_pool_t::shrink(): When relocating a dirty page of the temporary tablespace, reset the oldest_modification() on the discarded block, like we do for persistent pages in buf_flush_relocate_on_flush_list(). buf_pool_t::resize(): Add debug assertions to catch this error earlier. This bug does not seem to affect non-debug builds. Reviewed by: Thirunarayanan Balathandayuthapani --- ...innodb_buffer_pool_shrink_temporary.result | 17 ++++++++++++++++ .../t/innodb_buffer_pool_shrink_temporary.opt | 1 + .../innodb_buffer_pool_shrink_temporary.test | 20 +++++++++++++++++++ storage/innobase/buf/buf0buf.cc | 8 +++++++- 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/innodb/r/innodb_buffer_pool_shrink_temporary.result create mode 100644 mysql-test/suite/innodb/t/innodb_buffer_pool_shrink_temporary.opt create mode 100644 mysql-test/suite/innodb/t/innodb_buffer_pool_shrink_temporary.test diff --git a/mysql-test/suite/innodb/r/innodb_buffer_pool_shrink_temporary.result b/mysql-test/suite/innodb/r/innodb_buffer_pool_shrink_temporary.result new file mode 100644 index 00000000000..bfaf8df7a2e --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_buffer_pool_shrink_temporary.result @@ -0,0 +1,17 @@ +call mtr.add_suppression("innodb_buffer_pool_size change aborted"); +SET @b=REPEAT('0',1048576); +CREATE TEMPORARY TABLE t (c MEDIUMTEXT) ENGINE=InnoDB; +INSERT INTO t VALUES +(@b),(@b),(@b),(@b),(@b),(@b),(@b),(@b),(@b),(@b),(@b); +SET STATEMENT max_statement_time=0.000001 FOR +SET GLOBAL innodb_buffer_pool_size=6291456; +SET STATEMENT max_statement_time=0.000001 FOR +SET GLOBAL innodb_buffer_pool_size=6291456; +SET STATEMENT max_statement_time=0.000001 FOR +SET GLOBAL innodb_buffer_pool_size=6291456; +SET GLOBAL innodb_buffer_pool_size=6291456; +SET GLOBAL innodb_buffer_pool_size=16777216; +CHECKSUM TABLE t; +Table Checksum +test.t 4050893687 +DROP TEMPORARY TABLE t; diff --git a/mysql-test/suite/innodb/t/innodb_buffer_pool_shrink_temporary.opt b/mysql-test/suite/innodb/t/innodb_buffer_pool_shrink_temporary.opt new file mode 100644 index 00000000000..d8ba7cf7b0f --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_buffer_pool_shrink_temporary.opt @@ -0,0 +1 @@ +--innodb-buffer-pool-size=16m diff --git a/mysql-test/suite/innodb/t/innodb_buffer_pool_shrink_temporary.test b/mysql-test/suite/innodb/t/innodb_buffer_pool_shrink_temporary.test new file mode 100644 index 00000000000..cf2ea4ad175 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_buffer_pool_shrink_temporary.test @@ -0,0 +1,20 @@ +--source include/have_innodb.inc +call mtr.add_suppression("innodb_buffer_pool_size change aborted"); +SET @b=REPEAT('0',1048576); +CREATE TEMPORARY TABLE t (c MEDIUMTEXT) ENGINE=InnoDB; +INSERT INTO t VALUES +(@b),(@b),(@b),(@b),(@b),(@b),(@b),(@b),(@b),(@b),(@b); +--error 0,ER_WRONG_USAGE +SET STATEMENT max_statement_time=0.000001 FOR +SET GLOBAL innodb_buffer_pool_size=6291456; +--error 0,ER_WRONG_USAGE +SET STATEMENT max_statement_time=0.000001 FOR +SET GLOBAL innodb_buffer_pool_size=6291456; +--error 0,ER_WRONG_USAGE +SET STATEMENT max_statement_time=0.000001 FOR +SET GLOBAL innodb_buffer_pool_size=6291456; +--error 0,ER_WRONG_USAGE +SET GLOBAL innodb_buffer_pool_size=6291456; +SET GLOBAL innodb_buffer_pool_size=16777216; +CHECKSUM TABLE t; +DROP TEMPORARY TABLE t; diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 614e095f53a..4b245bd14de 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -1760,6 +1760,11 @@ ATTRIBUTE_COLD buf_pool_t::shrink_status buf_pool_t::shrink(size_t size) buf_flush_relocate_on_flush_list(b, &block->page); mysql_mutex_unlock(&flush_list_mutex); } + else + { + ut_d(if (auto om= b->oldest_modification()) ut_ad(om == 2)); + b->oldest_modification_.store(0, std::memory_order_relaxed); + } } /* relocate LRU list */ @@ -2091,10 +2096,11 @@ ATTRIBUTE_COLD void buf_pool_t::resize(size_t size, THD *thd) noexcept while (buf_page_t *b= UT_LIST_GET_FIRST(withdrawn)) { + ut_ad(!b->oldest_modification()); + ut_ad(b->state() == buf_page_t::NOT_USED); UT_LIST_REMOVE(withdrawn, b); UT_LIST_ADD_LAST(free, b); ut_d(b->in_free_list= true); - ut_ad(b->state() == buf_page_t::NOT_USED); b->lock.init(); } From 1681b6c330dfd62810030ee1522f28e26b5999fa Mon Sep 17 00:00:00 2001 From: Julius Goryavsky Date: Thu, 17 Jul 2025 15:42:59 +0200 Subject: [PATCH 135/172] MDEV-37257: unstable tests temporarily added to 'disabled' list --- mysql-test/suite/galera/disabled.def | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/suite/galera/disabled.def b/mysql-test/suite/galera/disabled.def index 23bf40c409a..438b1e63cfd 100644 --- a/mysql-test/suite/galera/disabled.def +++ b/mysql-test/suite/galera/disabled.def @@ -14,3 +14,5 @@ galera_wan : MDEV-35940 Unallowed state transition: donor -> synced in galera_wa galera_vote_rejoin_ddl : MDEV-35940 Unallowed state transition: donor -> synced in galera_wan MW-329 : MDEV-35951 Complete freeze during MW-329 test galera_vote_rejoin_dml : MDEV-35964 Assertion `ist_seqno >= cc_seqno' failed in galera_vote_rejoin_dml +galera_var_notify_cmd : MDEV-37257 WSREP: Notification command failed: 1 (Operation not permitted) +galera_var_notify_ssl_ipv6 : MDEV-37257 WSREP: Notification command failed: 1 (Operation not permitted) From 008145b968518f1ccf22558ee15fbc146f1b204b Mon Sep 17 00:00:00 2001 From: Julius Goryavsky Date: Thu, 17 Jul 2025 17:21:02 +0200 Subject: [PATCH 136/172] galera: changes for transition to galera library 26.4.23 --- mysql-test/include/galera_variables_ok.inc | 2 +- mysql-test/suite/wsrep/r/variables.result | 2 -- mysql-test/suite/wsrep/r/variables_debug.result | 3 +++ mysql-test/suite/wsrep/t/variables.test | 2 +- mysql-test/suite/wsrep/t/variables_debug.test | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/mysql-test/include/galera_variables_ok.inc b/mysql-test/include/galera_variables_ok.inc index 4d9c71e47d8..9bd31bb32b2 100644 --- a/mysql-test/include/galera_variables_ok.inc +++ b/mysql-test/include/galera_variables_ok.inc @@ -5,7 +5,7 @@ if (!$_galera_variables_delta) { --let $galera_variables_delta=0 } ---let $galera_variables_expected=`SELECT 49 + $galera_variables_delta` +--let $galera_variables_expected=`SELECT 51 + $galera_variables_delta` --let $galera_variables_count=`SELECT COUNT(*) FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'wsrep%'` diff --git a/mysql-test/suite/wsrep/r/variables.result b/mysql-test/suite/wsrep/r/variables.result index c8150a2f0b0..592e5ef1b73 100644 --- a/mysql-test/suite/wsrep/r/variables.result +++ b/mysql-test/suite/wsrep/r/variables.result @@ -108,8 +108,6 @@ WSREP_FORCED_BINLOG_FORMAT WSREP_GTID_DOMAIN_ID WSREP_GTID_MODE WSREP_GTID_SEQ_NO -WSREP_MODE -WSREP_STRICT_DDL WSREP_IGNORE_APPLY_ERRORS WSREP_LOAD_DATA_SPLITTING WSREP_LOG_CONFLICTS diff --git a/mysql-test/suite/wsrep/r/variables_debug.result b/mysql-test/suite/wsrep/r/variables_debug.result index 36f9b4ec256..18a323054d6 100644 --- a/mysql-test/suite/wsrep/r/variables_debug.result +++ b/mysql-test/suite/wsrep/r/variables_debug.result @@ -108,11 +108,13 @@ WSREP_DRUPAL_282555_WORKAROUND WSREP_FORCED_BINLOG_FORMAT WSREP_GTID_DOMAIN_ID WSREP_GTID_MODE +WSREP_GTID_SEQ_NO WSREP_IGNORE_APPLY_ERRORS WSREP_LOAD_DATA_SPLITTING WSREP_LOG_CONFLICTS WSREP_MAX_WS_ROWS WSREP_MAX_WS_SIZE +WSREP_MODE WSREP_MYSQL_REPLICATION_BUNDLE WSREP_NODE_ADDRESS WSREP_NODE_INCOMING_ADDRESS @@ -138,6 +140,7 @@ WSREP_SST_DONOR_REJECTS_QUERIES WSREP_SST_METHOD WSREP_SST_RECEIVE_ADDRESS WSREP_START_POSITION +WSREP_STRICT_DDL WSREP_SYNC_WAIT WSREP_TRX_FRAGMENT_SIZE WSREP_TRX_FRAGMENT_UNIT diff --git a/mysql-test/suite/wsrep/t/variables.test b/mysql-test/suite/wsrep/t/variables.test index 762d783a09c..c82d0ae02c2 100644 --- a/mysql-test/suite/wsrep/t/variables.test +++ b/mysql-test/suite/wsrep/t/variables.test @@ -3,7 +3,7 @@ --source include/have_innodb.inc --source include/galera_no_debug_sync.inc ---let $galera_version=26.4.21 +--let $galera_version=26.4.23 source include/check_galera_version.inc; source include/galera_variables_ok.inc; diff --git a/mysql-test/suite/wsrep/t/variables_debug.test b/mysql-test/suite/wsrep/t/variables_debug.test index e55dbd4fa1f..e50cee28a15 100644 --- a/mysql-test/suite/wsrep/t/variables_debug.test +++ b/mysql-test/suite/wsrep/t/variables_debug.test @@ -5,7 +5,7 @@ --source include/have_debug_sync.inc --source include/galera_have_debug_sync.inc ---let $galera_version=26.4.21 +--let $galera_version=26.4.23 source include/check_galera_version.inc; source include/galera_variables_ok_debug.inc; From 733c58a71e74f48d4a0aa8cc3ff0318a352794ef Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 17 Jul 2025 13:30:17 +0200 Subject: [PATCH 137/172] MDEV-37232 - fix embedded build on Windows --- include/my_service_manager.h | 2 +- sql/mysqld.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/my_service_manager.h b/include/my_service_manager.h index 498fc762048..f2dcf30c33b 100644 --- a/include/my_service_manager.h +++ b/include/my_service_manager.h @@ -43,7 +43,7 @@ #define SD_LISTEN_FDS_START (0) #define sd_notify(X, Y) #define sd_notifyf(E, F, ...) -#ifdef _WIN32 +#if defined (_WIN32) && !defined(EMBEDDED_LIBRARY) #define service_manager_extend_timeout(I, F, ...) \ mysqld_win_extend_service_timeout(I) #else diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 2b8cb0a6a48..d7e1bd67a75 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2860,7 +2860,7 @@ void unlink_thd(THD *thd) } -#if defined(_WIN32) +#if defined(_WIN32) && !defined(EMBEDDED_LIBRARY) /* If server is started as service, the service routine will set the callback function. From 55e0c34f4f00ca70ad8d6f0522efa94bb81f74fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 18 Jul 2025 10:06:33 +0300 Subject: [PATCH 138/172] MDEV-37263 Hang or crash when shrinking innodb_buffer_pool_size buf_pool_t::shrink(): If we run out of pages to evict from buf_pool.LRU, abort the operation. Also, do not leak the spare block that we may have allocated. --- .../innodb/r/innodb_buffer_pool_shrink.result | 11 +++++++++++ .../suite/innodb/t/innodb_buffer_pool_shrink.test | 14 ++++++++++++++ storage/innobase/buf/buf0buf.cc | 6 ++++++ 3 files changed, 31 insertions(+) create mode 100644 mysql-test/suite/innodb/r/innodb_buffer_pool_shrink.result create mode 100644 mysql-test/suite/innodb/t/innodb_buffer_pool_shrink.test diff --git a/mysql-test/suite/innodb/r/innodb_buffer_pool_shrink.result b/mysql-test/suite/innodb/r/innodb_buffer_pool_shrink.result new file mode 100644 index 00000000000..187dcfbd587 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_buffer_pool_shrink.result @@ -0,0 +1,11 @@ +call mtr.add_suppression("innodb_buffer_pool_size change aborted"); +CREATE TABLE t (c INT) ENGINE=InnoDB PARTITION BY HASH(c) PARTITIONS 512; +BEGIN; +SELECT * FROM t LOCK IN SHARE MODE; +c +SET @save_size = @@GLOBAL.innodb_buffer_pool_size; +SET GLOBAL innodb_buffer_pool_size=6291456; +COMMIT; +SET GLOBAL innodb_buffer_pool_size=6291456; +SET GLOBAL innodb_buffer_pool_size = @save_size; +DROP TABLE t; diff --git a/mysql-test/suite/innodb/t/innodb_buffer_pool_shrink.test b/mysql-test/suite/innodb/t/innodb_buffer_pool_shrink.test new file mode 100644 index 00000000000..886e31955c6 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_buffer_pool_shrink.test @@ -0,0 +1,14 @@ +--source include/have_innodb.inc +--source include/have_partition.inc +call mtr.add_suppression("innodb_buffer_pool_size change aborted"); +CREATE TABLE t (c INT) ENGINE=InnoDB PARTITION BY HASH(c) PARTITIONS 512; +BEGIN; +SELECT * FROM t LOCK IN SHARE MODE; +SET @save_size = @@GLOBAL.innodb_buffer_pool_size; +--error 0,ER_WRONG_USAGE +SET GLOBAL innodb_buffer_pool_size=6291456; +COMMIT; +--error 0,ER_WRONG_USAGE +SET GLOBAL innodb_buffer_pool_size=6291456; +SET GLOBAL innodb_buffer_pool_size = @save_size; +DROP TABLE t; diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 4b245bd14de..d2a3170b13c 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -1823,6 +1823,12 @@ ATTRIBUTE_COLD buf_pool_t::shrink_status buf_pool_t::shrink(size_t size) goto next; } + if (block) + buf_LRU_block_free_non_file_page(block); + + if (!UT_LIST_GET_LEN(LRU) && n_blocks_to_withdraw) + return SHRINK_ABORT; + if (UT_LIST_GET_LEN(free) + UT_LIST_GET_LEN(LRU) < usable_size() / 20) return SHRINK_ABORT; From 9412cd0e62c3fcdcaed371ff0e5917d5c3300837 Mon Sep 17 00:00:00 2001 From: Raghunandan Bhat Date: Fri, 18 Jul 2025 18:59:25 +0530 Subject: [PATCH 139/172] MDEV-35330: Assertion `marked_for_read()` failed in VSec9::VSec9 | Item_func_from_unixtime::get_date Problem: When a parameter in a prepared UPDATE statement uses DEFAULT value for a column (e.g., `EXECUTE IMMEDIATE 'UPDATE t SET b=?' USING DEFAULT`), and that column's default is derived from an expression or a function referencing another column (e.g., `FROM_UNIXTIME(a)`), the server fails to correctly mark the dependent column (`a`) for reading. This happened because the server failed to associate the `Item_param` (representing the `?` parameter) with its target field (`b`), leaving `Item_param::m_associated_field` uninitialized. This prevented the correct code path for evaluating the `DEFAULT` value, leading to the dependent column not being marked for read. When the column's value was later accessed, an assertion failed, causing a crash. Fix: In the prepare stage of the UPDATE statement, associate each value with the target field, causing the server to take the correct code path (`Item_param::assign_default`) for evaluating DEFAULT values and marking dependent column for reading beforehand. Only tests are included as it is a duplicate of MDEV-36870. --- mysql-test/main/ps.result | 52 +++++++++++++++++++++++++++++++++++++++ mysql-test/main/ps.test | 51 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/mysql-test/main/ps.result b/mysql-test/main/ps.result index 775ada34653..691f4ba4a04 100644 --- a/mysql-test/main/ps.result +++ b/mysql-test/main/ps.result @@ -5995,3 +5995,55 @@ DROP VIEW t1; # # End of 10.4 tests # +# +# MDEV-35330: Assertion `marked_for_read()` failed in VSec9::VSec9 | Item_func_from_unixtime::get_date +# +CREATE TABLE t (a INT,b TIMESTAMP DEFAULT FROM_UNIXTIME(a)); +INSERT INTO t VALUES (1,'2025-07-18 18:37:10'); +SELECT * FROM t; +a b +1 2025-07-18 18:37:10 +EXECUTE IMMEDIATE 'UPDATE t SET b=?' USING DEFAULT; +SELECT * FROM t; +a b +1 1970-01-01 09:00:01 +DROP TABLE t; +CREATE TABLE t (a INT, b INT DEFAULT (a+5)); +INSERT INTO t values (1,2), (2,DEFAULT); +EXECUTE IMMEDIATE 'INSERT INTO t VALUES (3,4), (4,?)' USING DEFAULT; +SELECT * FROM t; +a b +1 2 +2 7 +3 4 +4 9 +EXECUTE IMMEDIATE 'UPDATE t SET b=?' USING DEFAULT; +SELECT * FROM t; +a b +1 6 +2 7 +3 8 +4 9 +DROP TABLE t; +CREATE TABLE t (a INT,b TIMESTAMP DEFAULT FROM_UNIXTIME(a)); +INSERT INTO t VALUES (1,'2025-07-18 18:37:10'); +SELECT * FROM t; +a b +1 2025-07-18 18:37:10 +PREPARE s FROM 'UPDATE t SET b=?'; +EXECUTE s USING DEFAULT; +SELECT * FROM t; +a b +1 1970-01-01 09:00:01 +DROP TABLE t; +CREATE TABLE t (a INT, b TIMESTAMP DEFAULT FROM_UNIXTIME(a), c INT DEFAULT (a+5)); +INSERT INTO t VALUES (1,'2025-07-18 18:37:10',3); +SELECT * FROM t; +a b c +1 2025-07-18 18:37:10 3 +EXECUTE IMMEDIATE 'UPDATE t SET b=?, c=?' USING DEFAULT, DEFAULT; +SELECT * FROM t; +a b c +1 1970-01-01 09:00:01 6 +DROP TABLE t; +# End of 10.6 tests diff --git a/mysql-test/main/ps.test b/mysql-test/main/ps.test index ff1e9e9f13e..54666d64012 100644 --- a/mysql-test/main/ps.test +++ b/mysql-test/main/ps.test @@ -5447,3 +5447,54 @@ DROP VIEW t1; --echo # --echo # End of 10.4 tests --echo # + +--echo # +--echo # MDEV-35330: Assertion `marked_for_read()` failed in VSec9::VSec9 | Item_func_from_unixtime::get_date +--echo # + +CREATE TABLE t (a INT,b TIMESTAMP DEFAULT FROM_UNIXTIME(a)); +INSERT INTO t VALUES (1,'2025-07-18 18:37:10'); + +SELECT * FROM t; + +EXECUTE IMMEDIATE 'UPDATE t SET b=?' USING DEFAULT; + +SELECT * FROM t; + +DROP TABLE t; + +CREATE TABLE t (a INT, b INT DEFAULT (a+5)); +INSERT INTO t values (1,2), (2,DEFAULT); +EXECUTE IMMEDIATE 'INSERT INTO t VALUES (3,4), (4,?)' USING DEFAULT; + +SELECT * FROM t; + +EXECUTE IMMEDIATE 'UPDATE t SET b=?' USING DEFAULT; + +SELECT * FROM t; + +DROP TABLE t; + +CREATE TABLE t (a INT,b TIMESTAMP DEFAULT FROM_UNIXTIME(a)); +INSERT INTO t VALUES (1,'2025-07-18 18:37:10'); + +SELECT * FROM t; + +PREPARE s FROM 'UPDATE t SET b=?'; +EXECUTE s USING DEFAULT; + +SELECT * FROM t; + +DROP TABLE t; + +CREATE TABLE t (a INT, b TIMESTAMP DEFAULT FROM_UNIXTIME(a), c INT DEFAULT (a+5)); +INSERT INTO t VALUES (1,'2025-07-18 18:37:10',3); + +SELECT * FROM t; + +EXECUTE IMMEDIATE 'UPDATE t SET b=?, c=?' USING DEFAULT, DEFAULT; + +SELECT * FROM t; + +DROP TABLE t; +--echo # End of 10.6 tests From a7d8c979526e502a8c231a06ea1c789fe251c950 Mon Sep 17 00:00:00 2001 From: Rex Johnston Date: Mon, 14 Jul 2025 13:31:50 +1100 Subject: [PATCH 140/172] MDEV-37230 Incorrect handling of NULL join conditions when using split-materialized During the optimization phase, when determining whether or not to materialize a derived table all at once or in groups (split materialization), all key equalities that reference the derived table have their cond Items pushed into JOIN::spl_opt_info->inj_cond_list. From there they are filtered (tables in join prefix) and injected into the JOIN conditions (in JOIN::inject_best_splitting_cond()), where they might be removed because they are involved ref access and they aren't needed. These pushed items conditions were always Item_func_eq, whether or or the key usage specifies null safe equality (<=>) or not. The fix is to create an Item_func_equal condition when the key equality is specified using <=>. approved by Sergei Petrunia (sergey@mariadb.com) PR#4198 --- mysql-test/main/derived_split_innodb.result | 240 +++++++++++++++++++- mysql-test/main/derived_split_innodb.test | 62 +++++ sql/opt_split.cc | 10 +- 3 files changed, 309 insertions(+), 3 deletions(-) diff --git a/mysql-test/main/derived_split_innodb.result b/mysql-test/main/derived_split_innodb.result index fc8f6551d49..2fbe27ea2f7 100644 --- a/mysql-test/main/derived_split_innodb.result +++ b/mysql-test/main/derived_split_innodb.result @@ -989,7 +989,7 @@ explain $query; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 range t2_IDX t2_IDX 4 NULL 1 Using index condition 1 PRIMARY ref key0 key0 10 test.t2.a,test.t2.b 1 Using where -2 LATERAL DERIVED t1 ref t1_IDX t1_IDX 9 test.t2.a,test.t2.b 1 +2 LATERAL DERIVED t1 ref t1_IDX t1_IDX 9 test.t2.a,test.t2.b 1 Using index condition $query; a b name total_amt 1 NULL A 10 @@ -998,4 +998,242 @@ set statement optimizer_switch='split_materialized=off' for $query; a b name total_amt 1 NULL A 10 DROP TABLE t1,t2; +# +# MDEV-37230 Incorrect handling of NULL join conditions when using +# split-materialized +# +create table t1 +( +a int not null, +b int, +c int, +d int, +amount decimal, +key t1_ix1 (a,b) +) engine=innodb; +insert into t1 values (0, NULL, 0, NULL, 10.0000), (1, 1, 1, 1, 10.0000), +(2, 2, 2, 2, 20.0000), (3, 3, 3, 3, 30.0000), (4, 4, 4, 4, 40.0000), +(5, 5, 5, 5, NULL), (6, 6, 6, 6, NULL), (7, 7, 7, 7, 70.0000), +(8, 8, 8, 8, 80.0000); +create table t2 +( +a int NOT NULL, +b int, +name varchar(50), +key t2_ix1 (a,b) +) engine=innodb; +insert into t2 values (0, NULL, 'a'), (1, NULL, 'A'), (2, 2, 'B'), (3,3, 'C'), +(4,4, 'D'), (5,5, NULL), (6,6, NULL), (7,7, 'E'), (8,8, 'F'), (9,9, 'G'), +(10,10,'H'), (11,11, NULL), (12,12, NULL); +create table t3 +( +a int not null, +b int, +description varchar(50), +key t3_ix1 (a,b) +); +insert into t3 values (1, 1, 'bar'),(2,2,'buz'),(0,NULL, 'gold'); +insert into t3 select seq, seq, 'junk' from seq_3_to_13; +analyze table t1, t2, t3; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +test.t2 analyze status Engine-independent statistics collected +test.t2 analyze status OK +test.t3 analyze status Engine-independent statistics collected +test.t3 analyze status OK +set optimizer_switch='default'; +set statement optimizer_switch='split_materialized=on' for explain format=json select * from t1 +join t2 on t1.a = t2.a and t1.b <=> t2.b +join +( +select a, b, description from t3 group by a, b +) dt on dt.a = t1.a and dt.b <=> t1.b and dt.b <=> t2.b +where dt.a < 1; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "cost": "REPLACED", + "nested_loop": [ + { + "table": { + "table_name": "t1", + "access_type": "range", + "possible_keys": ["t1_ix1"], + "key": "t1_ix1", + "key_length": "4", + "used_key_parts": ["a"], + "loops": 1, + "rows": 1, + "cost": "REPLACED", + "filtered": 100, + "index_condition": "t1.a < 1" + } + }, + { + "table": { + "table_name": "t2", + "access_type": "ref", + "possible_keys": ["t2_ix1"], + "key": "t2_ix1", + "key_length": "9", + "used_key_parts": ["a", "b"], + "ref": ["test.t1.a", "test.t1.b"], + "loops": 1, + "rows": 1, + "cost": "REPLACED", + "filtered": 100, + "index_condition": "t1.b <=> t2.b" + } + }, + { + "table": { + "table_name": "", + "access_type": "ref", + "possible_keys": ["key0"], + "key": "key0", + "key_length": "9", + "used_key_parts": ["a", "b"], + "ref": ["test.t1.a", "test.t1.b"], + "loops": 1, + "rows": 1, + "cost": "REPLACED", + "filtered": 100, + "attached_condition": "dt.b <=> t1.b and dt.b <=> t2.b", + "materialized": { + "lateral": 1, + "query_block": { + "select_id": 3, + "cost": "REPLACED", + "nested_loop": [ + { + "table": { + "table_name": "t3", + "access_type": "ref", + "possible_keys": ["t3_ix1"], + "key": "t3_ix1", + "key_length": "9", + "used_key_parts": ["a", "b"], + "ref": ["test.t1.a", "test.t1.b"], + "loops": 1, + "rows": 1, + "cost": "REPLACED", + "filtered": 100, + "index_condition": "t3.a < 1 and t3.b <=> t1.b and t3.b <=> t2.b and t3.a = t2.a" + } + } + ] + } + } + } + } + ] + } +} +set statement optimizer_switch='split_materialized=on' for select * from t1 +join t2 on t1.a = t2.a and t1.b <=> t2.b +join +( +select a, b, description from t3 group by a, b +) dt on dt.a = t1.a and dt.b <=> t1.b and dt.b <=> t2.b +where dt.a < 1; +a b c d amount a b name a b description +0 NULL 0 NULL 10 0 NULL a 0 NULL gold +set statement optimizer_switch='split_materialized=off' for explain format=json select * from t1 +join t2 on t1.a = t2.a and t1.b <=> t2.b +join +( +select a, b, description from t3 group by a, b +) dt on dt.a = t1.a and dt.b <=> t1.b and dt.b <=> t2.b +where dt.a < 1; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "cost": "REPLACED", + "nested_loop": [ + { + "table": { + "table_name": "t1", + "access_type": "range", + "possible_keys": ["t1_ix1"], + "key": "t1_ix1", + "key_length": "4", + "used_key_parts": ["a"], + "loops": 1, + "rows": 1, + "cost": "REPLACED", + "filtered": 100, + "index_condition": "t1.a < 1" + } + }, + { + "table": { + "table_name": "t2", + "access_type": "ref", + "possible_keys": ["t2_ix1"], + "key": "t2_ix1", + "key_length": "9", + "used_key_parts": ["a", "b"], + "ref": ["test.t1.a", "test.t1.b"], + "loops": 1, + "rows": 1, + "cost": "REPLACED", + "filtered": 100, + "index_condition": "t1.b <=> t2.b" + } + }, + { + "table": { + "table_name": "", + "access_type": "ref", + "possible_keys": ["key0"], + "key": "key0", + "key_length": "9", + "used_key_parts": ["a", "b"], + "ref": ["test.t1.a", "test.t1.b"], + "loops": 1, + "rows": 1, + "cost": "REPLACED", + "filtered": 100, + "attached_condition": "dt.b <=> t1.b and dt.b <=> t2.b", + "materialized": { + "query_block": { + "select_id": 3, + "cost": "REPLACED", + "nested_loop": [ + { + "table": { + "table_name": "t3", + "access_type": "range", + "possible_keys": ["t3_ix1"], + "key": "t3_ix1", + "key_length": "4", + "used_key_parts": ["a"], + "loops": 1, + "rows": 1, + "cost": "REPLACED", + "filtered": 100, + "index_condition": "t3.a < 1" + } + } + ] + } + } + } + } + ] + } +} +set statement optimizer_switch='split_materialized=off' for select * from t1 +join t2 on t1.a = t2.a and t1.b <=> t2.b +join +( +select a, b, description from t3 group by a, b +) dt on dt.a = t1.a and dt.b <=> t1.b and dt.b <=> t2.b +where dt.a < 1; +a b c d amount a b name a b description +0 NULL 0 NULL 10 0 NULL a 0 NULL gold +drop table t1, t2, t3; SET GLOBAL innodb_stats_persistent=@save_innodb_stats_persistent; diff --git a/mysql-test/main/derived_split_innodb.test b/mysql-test/main/derived_split_innodb.test index b5a985a0453..1d30f9e6bb8 100644 --- a/mysql-test/main/derived_split_innodb.test +++ b/mysql-test/main/derived_split_innodb.test @@ -603,5 +603,67 @@ evalp set statement optimizer_switch='split_materialized=off' for $query; DROP TABLE t1,t2; +--echo # +--echo # MDEV-37230 Incorrect handling of NULL join conditions when using +--echo # split-materialized +--echo # + +create table t1 +( + a int not null, + b int, + c int, + d int, + amount decimal, + key t1_ix1 (a,b) +) engine=innodb; + +insert into t1 values (0, NULL, 0, NULL, 10.0000), (1, 1, 1, 1, 10.0000), +(2, 2, 2, 2, 20.0000), (3, 3, 3, 3, 30.0000), (4, 4, 4, 4, 40.0000), +(5, 5, 5, 5, NULL), (6, 6, 6, 6, NULL), (7, 7, 7, 7, 70.0000), +(8, 8, 8, 8, 80.0000); + +create table t2 +( + a int NOT NULL, + b int, + name varchar(50), + key t2_ix1 (a,b) +) engine=innodb; + +insert into t2 values (0, NULL, 'a'), (1, NULL, 'A'), (2, 2, 'B'), (3,3, 'C'), +(4,4, 'D'), (5,5, NULL), (6,6, NULL), (7,7, 'E'), (8,8, 'F'), (9,9, 'G'), +(10,10,'H'), (11,11, NULL), (12,12, NULL); + +create table t3 +( + a int not null, + b int, + description varchar(50), + key t3_ix1 (a,b) +); +insert into t3 values (1, 1, 'bar'),(2,2,'buz'),(0,NULL, 'gold'); +insert into t3 select seq, seq, 'junk' from seq_3_to_13; + +let $q= +select * from t1 +join t2 on t1.a = t2.a and t1.b <=> t2.b +join +( + select a, b, description from t3 group by a, b +) dt on dt.a = t1.a and dt.b <=> t1.b and dt.b <=> t2.b +where dt.a < 1; + +analyze table t1, t2, t3; +set optimizer_switch='default'; +--source include/analyze-format.inc +eval set statement optimizer_switch='split_materialized=on' for explain format=json $q; +eval set statement optimizer_switch='split_materialized=on' for $q; +--source include/analyze-format.inc +eval set statement optimizer_switch='split_materialized=off' for explain format=json $q; +eval set statement optimizer_switch='split_materialized=off' for $q; + +drop table t1, t2, t3; + # End of 11.4 tests; SET GLOBAL innodb_stats_persistent=@save_innodb_stats_persistent; diff --git a/sql/opt_split.cc b/sql/opt_split.cc index 1fc69b65714..29fa13d6a66 100644 --- a/sql/opt_split.cc +++ b/sql/opt_split.cc @@ -605,13 +605,19 @@ void TABLE::add_splitting_info_for_key_field(KEY_FIELD *key_field) THD *thd= in_use; Item *left_item= spl_field->producing_item->build_clone(thd); Item *right_item= key_field->val->build_clone(thd); - Item_func_eq *eq_item= 0; + Item_bool_func *eq_item= 0; if (left_item && right_item) { right_item->walk(&Item::set_fields_as_dependent_processor, false, join->select_lex); right_item->update_used_tables(); - eq_item= new (thd->mem_root) Item_func_eq(thd, left_item, right_item); + + // Item_func::EQUAL_FUNC is null-safe, others can use Item_func_eq() + if (key_field->cond->type() == Item::FUNC_ITEM && + ((Item_func*)key_field->cond)->functype() == Item_func::EQUAL_FUNC) + eq_item= new (thd->mem_root) Item_func_equal(thd, left_item, right_item); + else + eq_item= new (thd->mem_root) Item_func_eq(thd, left_item, right_item); } if (!eq_item) return; From 3a2e1f87a1fa01bfe5ada183ec38412aa96726ce Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 20 Jul 2025 12:06:42 +0200 Subject: [PATCH 141/172] MDEV-37268 ER_NOT_KEYFILE or assertion failure upon REPLACE into table with unique hash under READ-COMMITTED followup for 9703c90712f3 (MDEV-37199 UNIQUE KEY USING HASH accepting duplicate records) don't forget to rnd_init()/rnd_end() around rnd_pos() --- sql/handler.cc | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/sql/handler.cc b/sql/handler.cc index 959fedae959..e58ddff3aa5 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -7774,16 +7774,19 @@ int handler::ha_write_row(const uchar *buf) { if (lookup_handler != this) // INSERT IGNORE or REPLACE or ODKU { + int olderror= error; + if ((error= rnd_init(0))) + goto err; position(buf); - int e= rnd_pos(lookup_buffer, ref); - if (!e) - { - increment_statistics(&SSV::ha_delete_count); - TABLE_IO_WAIT(tracker, PSI_TABLE_DELETE_ROW, MAX_KEY, e, - { e= delete_row(buf);}) - } - if (e) - error= e; + if ((error= rnd_pos(lookup_buffer, ref))) + goto err; + + increment_statistics(&SSV::ha_delete_count); + TABLE_IO_WAIT(tracker, PSI_TABLE_DELETE_ROW, MAX_KEY, error, + { error= delete_row(buf);}) + rnd_end(); + if (!error) + error= olderror; } goto err; } From 774039e410d1ff4ff54d810157fd9071c48648be Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 20 Jul 2025 12:33:01 +0200 Subject: [PATCH 142/172] MDEV-37268 ER_DUP_ENTRY upon REPLACE into table with unique hash under READ-COMMITTED followup for 9703c90712f3 (MDEV-37199 UNIQUE KEY USING HASH accepting duplicate records) when looking for long unique duplicates and the new row is already inserted, we cannot simply "skip one conflict" we must skip exactly the new row and find a conflict which isn't a new row - otherwise table->file->dup_ref can be set incorrectly and REPLACE won't work. --- mysql-test/main/long_unique_innodb.result | 13 +++++++++++++ mysql-test/main/long_unique_innodb.test | 14 ++++++++++++++ sql/handler.cc | 11 +++++++---- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/mysql-test/main/long_unique_innodb.result b/mysql-test/main/long_unique_innodb.result index 8ed45ce6b10..58267e9c4eb 100644 --- a/mysql-test/main/long_unique_innodb.result +++ b/mysql-test/main/long_unique_innodb.result @@ -134,3 +134,16 @@ disconnect con2; # MDEV-20131 Assertion `!pk->has_virtual()' failed create table t1 (a text, primary key(a(1871))) engine=innodb; ERROR 42000: Specified key was too long; max key length is 1536 bytes +# End of 10.4 tests +# +# MDEV-37268 ER_NOT_KEYFILE or assertion failure upon REPLACE into table with unique hash under READ-COMMITTED +# +create table t1 (id int not null primary key, f varchar(100), unique(f) using hash) engine=innodb; +insert t1 values (1,'x'); +set transaction isolation level read committed; +replace t1 values (2,'x'); +select * from t1; +id f +2 x +drop table t1; +# End of 10.6 tests diff --git a/mysql-test/main/long_unique_innodb.test b/mysql-test/main/long_unique_innodb.test index dd2d9f94de3..3253bd927eb 100644 --- a/mysql-test/main/long_unique_innodb.test +++ b/mysql-test/main/long_unique_innodb.test @@ -143,3 +143,17 @@ disconnect con2; --error ER_TOO_LONG_KEY create table t1 (a text, primary key(a(1871))) engine=innodb; + +--echo # End of 10.4 tests + +--echo # +--echo # MDEV-37268 ER_NOT_KEYFILE or assertion failure upon REPLACE into table with unique hash under READ-COMMITTED +--echo # +create table t1 (id int not null primary key, f varchar(100), unique(f) using hash) engine=innodb; +insert t1 values (1,'x'); +set transaction isolation level read committed; +replace t1 values (2,'x'); +select * from t1; +drop table t1; + +--echo # End of 10.6 tests diff --git a/sql/handler.cc b/sql/handler.cc index e58ddff3aa5..1ae75ff94d3 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -7414,7 +7414,7 @@ int handler::check_duplicate_long_entry_key(const uchar *new_rec, uint key_no) { int result; /* Skip just written row in the case of HA_CHECK_UNIQUE_AFTER_WRITE */ - bool lax= (ha_table_flags() & HA_CHECK_UNIQUE_AFTER_WRITE) > 0; + bool skip_self= ha_table_flags() & HA_CHECK_UNIQUE_AFTER_WRITE; KEY *key_info= table->key_info + key_no; uchar ptr[HA_HASH_KEY_LENGTH_WITH_NULL]; DBUG_ENTER("handler::check_duplicate_long_entry_key"); @@ -7426,6 +7426,9 @@ int handler::check_duplicate_long_entry_key(const uchar *new_rec, uint key_no) if (key_info->key_part->field->is_real_null()) DBUG_RETURN(0); + if (skip_self) + position(table->record[0]); + key_copy(ptr, new_rec, key_info, key_info->key_length, false); result= lookup_handler->ha_index_init(key_no, 0); @@ -7454,14 +7457,14 @@ int handler::check_duplicate_long_entry_key(const uchar *new_rec, uint key_no) { if (!long_unique_fields_differ(key_info, lookup_buffer)) { - if (lax) + lookup_handler->position(table->record[0]); + if (skip_self && !memcmp(ref, lookup_handler->ref, ref_length)) { - lax= false; + skip_self= false; // cannot happen twice, so let's save a memcpy continue; } result= HA_ERR_FOUND_DUPP_KEY; table->file->lookup_errkey= key_no; - lookup_handler->position(table->record[0]); memcpy(table->file->dup_ref, lookup_handler->ref, ref_length); goto end; } From b96b5a6ccf6a2f7679cd3bb880af945da85073dd Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 20 Jul 2025 16:08:51 +0200 Subject: [PATCH 143/172] cleanup: ha_partition::m_rec0 it makes no sense to safe this->table->record[0] in this->m_rec0, just use table->record[0] (also, future-proof, if table->record[0] changes) --- sql/ha_partition.cc | 24 +++++++++++------------- sql/ha_partition.h | 1 - 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 1c796a78416..3c3c51f92eb 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -409,7 +409,6 @@ void ha_partition::init_handler_variables() m_top_entry= NO_CURRENT_PART_ID; m_rec_length= 0; m_last_part= 0; - m_rec0= 0; m_err_rec= NULL; m_curr_key_info[0]= NULL; m_curr_key_info[1]= NULL; @@ -2199,7 +2198,7 @@ int ha_partition::copy_partitions(ulonglong * const copied, goto init_error; while (TRUE) { - if ((result= file->ha_rnd_next(m_rec0))) + if ((result= file->ha_rnd_next(table->record[0]))) { if (result != HA_ERR_END_OF_FILE) goto error; @@ -2225,7 +2224,7 @@ int ha_partition::copy_partitions(ulonglong * const copied, /* Copy record to new handler */ (*copied)++; DBUG_ASSERT(!m_new_file[new_part]->row_logging); - result= m_new_file[new_part]->ha_write_row(m_rec0); + result= m_new_file[new_part]->ha_write_row(table->record[0]); if (result) goto error; } @@ -3803,7 +3802,6 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) DBUG_RETURN(HA_ERR_INITIALIZATION); } m_start_key.length= 0; - m_rec0= table->record[0]; m_rec_length= table_share->reclength; if (!m_part_ids_sorted_by_num_of_records) { @@ -4719,15 +4717,15 @@ int ha_partition::update_row(const uchar *old_data, const uchar *new_data) */ { Abort_on_warning_instant_set old_abort_on_warning(thd, 0); - error= get_part_for_buf(old_data, m_rec0, m_part_info, &old_part_id); + error= get_part_for_buf(old_data, table->record[0], m_part_info, &old_part_id); } DBUG_ASSERT(!error); DBUG_ASSERT(old_part_id == m_last_part); DBUG_ASSERT(bitmap_is_set(&(m_part_info->read_partitions), old_part_id)); #endif - if (unlikely((error= get_part_for_buf(new_data, m_rec0, m_part_info, - &new_part_id)))) + if (unlikely((error= get_part_for_buf(new_data, table->record[0], + m_part_info, &new_part_id)))) goto exit; if (unlikely(!bitmap_is_set(&(m_part_info->lock_partitions), new_part_id))) { @@ -5555,7 +5553,7 @@ int ha_partition::rnd_pos_by_record(uchar *record) { DBUG_ENTER("ha_partition::rnd_pos_by_record"); - if (unlikely(get_part_for_buf(record, m_rec0, m_part_info, &m_last_part))) + if (unlikely(get_part_for_buf(record, table->record[0], m_part_info, &m_last_part))) DBUG_RETURN(1); int err= m_file[m_last_part]->rnd_pos_by_record(record); @@ -6339,7 +6337,7 @@ int ha_partition::read_range_first(const key_range *start_key, m_start_key.key= NULL; m_index_scan_type= partition_read_range; - error= common_index_read(m_rec0, MY_TEST(start_key)); + error= common_index_read(table->record[0], MY_TEST(start_key)); DBUG_RETURN(error); } @@ -10338,7 +10336,7 @@ void ha_partition::print_error(int error, myf errflag) str.append('('); str.append_ulonglong(m_last_part); str.append(STRING_WITH_LEN(" != ")); - if (get_part_for_buf(m_err_rec, m_rec0, m_part_info, &part_id)) + if (get_part_for_buf(m_err_rec, table->record[0], m_part_info, &part_id)) str.append('?'); else str.append_ulonglong(part_id); @@ -11323,7 +11321,7 @@ int ha_partition::check_misplaced_rows(uint read_part_id, bool do_repair) while (true) { - if ((result= m_file[read_part_id]->ha_rnd_next(m_rec0))) + if ((result= m_file[read_part_id]->ha_rnd_next(table->record[0]))) { if (result != HA_ERR_END_OF_FILE) break; @@ -11369,7 +11367,7 @@ int ha_partition::check_misplaced_rows(uint read_part_id, bool do_repair) Insert row into correct partition. Notice that there are no commit for every N row, so the repair will be one large transaction! */ - if ((result= m_file[correct_part_id]->ha_write_row(m_rec0))) + if ((result= m_file[correct_part_id]->ha_write_row(table->record[0]))) { /* We have failed to insert a row, it might have been a duplicate! @@ -11413,7 +11411,7 @@ int ha_partition::check_misplaced_rows(uint read_part_id, bool do_repair) } /* Delete row from wrong partition. */ - if ((result= m_file[read_part_id]->ha_delete_row(m_rec0))) + if ((result= m_file[read_part_id]->ha_delete_row(table->record[0]))) { if (m_file[correct_part_id]->has_transactions_and_rollback()) break; diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 0bad10b91bf..d03428bd625 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -322,7 +322,6 @@ private: and if clustered pk, [0]= current index, [1]= pk, [2]= NULL */ KEY *m_curr_key_info[3]; // Current index - uchar *m_rec0; // table->record[0] const uchar *m_err_rec; // record which gave error QUEUE m_queue; // Prio queue used by sorted read From 2b11a0e9918ac6b04d821fdbe4192475f516946a Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 20 Jul 2025 13:00:23 +0200 Subject: [PATCH 144/172] MDEV-37268 assert upon UPDATE or partitioned table with unique hash under READ-COMMITTED followup for 9703c90712f3 (MDEV-37199 UNIQUE KEY USING HASH accepting duplicate records) maintain the invariant, that handler::ha_update_row() is always invoked as handler::ha_update_row(record[0], record[1]) --- sql/handler.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sql/handler.cc b/sql/handler.cc index 1ae75ff94d3..4ca785d1c32 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -7863,9 +7863,13 @@ int handler::ha_update_row(const uchar *old_data, const uchar *new_data) return HA_ERR_UNSUPPORTED; } } + table->move_fields(table->field, table->record[1], table->record[0]); + std::swap(table->record[0], table->record[1]); increment_statistics(&SSV::ha_update_count); TABLE_IO_WAIT(tracker, PSI_TABLE_UPDATE_ROW, MAX_KEY, e, { e= update_row(new_data, old_data);}) + table->move_fields(table->field, table->record[1], table->record[0]); + std::swap(table->record[0], table->record[1]); } return e ? e : error; } From 5622f3f5e8ceac675dca0cfe63e6310b343239ac Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 20 Jul 2025 13:04:52 +0200 Subject: [PATCH 145/172] MDEV-37268 HA_ERR_KEY_NOT_FOUND upon UPDATE or partitioned table with unique hash under READ-COMMITTED followup for 9703c90712f3 (MDEV-37199 UNIQUE KEY USING HASH accepting duplicate records) ha_partition can return HA_ERR_KEY_NOT_FOUND even in the middle of the index scan --- mysql-test/main/long_unique_innodb.result | 9 +++++++++ mysql-test/main/long_unique_innodb.test | 7 +++++++ sql/handler.cc | 8 ++------ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/mysql-test/main/long_unique_innodb.result b/mysql-test/main/long_unique_innodb.result index 58267e9c4eb..2af8a860115 100644 --- a/mysql-test/main/long_unique_innodb.result +++ b/mysql-test/main/long_unique_innodb.result @@ -146,4 +146,13 @@ select * from t1; id f 2 x drop table t1; +create table t1 (id int, f longtext, primary key (id), unique(f)) engine=innodb partition by key (id) partitions 9; +insert t1 (id) values (1),(2); +set transaction isolation level read committed; +update ignore t1 set f = 'x'; +select * from t1; +id f +1 x +2 NULL +drop table t1; # End of 10.6 tests diff --git a/mysql-test/main/long_unique_innodb.test b/mysql-test/main/long_unique_innodb.test index 3253bd927eb..95bcc5c74fd 100644 --- a/mysql-test/main/long_unique_innodb.test +++ b/mysql-test/main/long_unique_innodb.test @@ -1,4 +1,5 @@ --source include/have_innodb.inc +--source include/have_partition.inc # # MDEV-371 Unique indexes for blobs @@ -156,4 +157,10 @@ replace t1 values (2,'x'); select * from t1; drop table t1; +create table t1 (id int, f longtext, primary key (id), unique(f)) engine=innodb partition by key (id) partitions 9; +insert t1 (id) values (1),(2); +set transaction isolation level read committed; +update ignore t1 set f = 'x'; +select * from t1; +drop table t1; --echo # End of 10.6 tests diff --git a/sql/handler.cc b/sql/handler.cc index 4ca785d1c32..393e4cc12d5 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -7440,11 +7440,7 @@ int handler::check_duplicate_long_entry_key(const uchar *new_rec, uint key_no) result= lookup_handler->ha_index_read_map(table->record[0], ptr, HA_WHOLE_KEY, HA_READ_KEY_EXACT); if (result) - { - if (result == HA_ERR_KEY_NOT_FOUND) - result= 0; goto end; - } // restore pointers after swap_values in TABLE::update_virtual_fields() for (Field **vf= table->vfield; *vf; vf++) @@ -7472,10 +7468,10 @@ int handler::check_duplicate_long_entry_key(const uchar *new_rec, uint key_no) while (!(result= lookup_handler->ha_index_next_same(table->record[0], ptr, key_info->key_length))); - if (result == HA_ERR_END_OF_FILE) +end: + if (result == HA_ERR_END_OF_FILE || result == HA_ERR_KEY_NOT_FOUND) result= 0; -end: restore_record(table, file->lookup_buffer); table->restore_blob_values(blob_storage); lookup_handler->ha_index_end(); From 687c8be813429f03267ecfcc1de8f9215b060b4f Mon Sep 17 00:00:00 2001 From: Rex Johnston Date: Mon, 21 Jul 2025 14:44:49 +1100 Subject: [PATCH 146/172] MDEV-19269 Pushdown into IN subquery is not made on the second execution of stmt Item_in_subselect::is_jtbm_const_tab left initialized from previous execution of prepared statement. approved by Dave Gosselin (dave.gosselin@mariadb.com) PR#4215 --- mysql-test/main/having_cond_pushdown.result | 146 ++++++++++++++++++++ mysql-test/main/having_cond_pushdown.test | 28 ++++ sql/item_subselect.h | 1 + 3 files changed, 175 insertions(+) diff --git a/mysql-test/main/having_cond_pushdown.result b/mysql-test/main/having_cond_pushdown.result index 3257f684617..059819840fa 100644 --- a/mysql-test/main/having_cond_pushdown.result +++ b/mysql-test/main/having_cond_pushdown.result @@ -5826,3 +5826,149 @@ SELECT LOAD_FILE('') AS f, a FROM t1 GROUP BY f, a HAVING f = a; f a DROP TABLE t1; End of 10.5 tests +# +# MDEV-19269 Pushdown into IN subquery is not made on the second +# execution of stmt +# +create table t1 (a int, b int); +create table t2 (x int, y int); +insert into t1 values (1,1),(2,2); +insert into t2 values (1,1),(2,2),(2,3); +prepare stmt from " +EXPLAIN FORMAT=JSON +SELECT * FROM t1 +WHERE a = b + AND (a,b) IN (SELECT t2.x, COUNT(t2.y) FROM t2 WHERE @a=1 GROUP BY t2.x);"; +set @a=2; +execute stmt; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "message": "Impossible WHERE noticed after reading const tables" + }, + "subqueries": [ + { + "materialization": { + "query_block": { + "select_id": 2, + "table": { + "message": "Impossible WHERE" + } + } + } + } + ] + } +} +set @a=1; +# we expect to see having_condition in both the below statements +execute stmt; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "nested_loop": [ + { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 2, + "filtered": 100, + "attached_condition": "t1.b = t1.a and t1.a is not null and t1.a is not null" + } + }, + { + "table": { + "table_name": "", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "12", + "used_key_parts": ["x", "COUNT(t2.y)"], + "ref": ["test.t1.a", "test.t1.a"], + "rows": 1, + "filtered": 100, + "attached_condition": "t1.a = ``.`COUNT(t2.y)`", + "materialized": { + "unique": 1, + "materialization": { + "query_block": { + "select_id": 2, + "having_condition": "`COUNT(t2.y)` = t2.x", + "temporary_table": { + "nested_loop": [ + { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 3, + "filtered": 100 + } + } + ] + } + } + } + } + } + } + ] + } +} +execute stmt; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "nested_loop": [ + { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 2, + "filtered": 100, + "attached_condition": "t1.b = t1.a and t1.a is not null and t1.a is not null" + } + }, + { + "table": { + "table_name": "", + "access_type": "eq_ref", + "possible_keys": ["distinct_key"], + "key": "distinct_key", + "key_length": "12", + "used_key_parts": ["x", "COUNT(t2.y)"], + "ref": ["test.t1.a", "test.t1.a"], + "rows": 1, + "filtered": 100, + "attached_condition": "t1.a = ``.`COUNT(t2.y)`", + "materialized": { + "unique": 1, + "materialization": { + "query_block": { + "select_id": 2, + "having_condition": "`COUNT(t2.y)` = t2.x", + "temporary_table": { + "nested_loop": [ + { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 3, + "filtered": 100 + } + } + ] + } + } + } + } + } + } + ] + } +} +drop table t1, t2; +End of 10.11 tests diff --git a/mysql-test/main/having_cond_pushdown.test b/mysql-test/main/having_cond_pushdown.test index 190fb8a493f..272508d0620 100644 --- a/mysql-test/main/having_cond_pushdown.test +++ b/mysql-test/main/having_cond_pushdown.test @@ -1601,3 +1601,31 @@ SELECT LOAD_FILE('') AS f, a FROM t1 GROUP BY f, a HAVING f = a; DROP TABLE t1; --echo End of 10.5 tests + +--echo # +--echo # MDEV-19269 Pushdown into IN subquery is not made on the second +--echo # execution of stmt +--echo # + +create table t1 (a int, b int); +create table t2 (x int, y int); + +insert into t1 values (1,1),(2,2); +insert into t2 values (1,1),(2,2),(2,3); + +prepare stmt from " +EXPLAIN FORMAT=JSON +SELECT * FROM t1 +WHERE a = b + AND (a,b) IN (SELECT t2.x, COUNT(t2.y) FROM t2 WHERE @a=1 GROUP BY t2.x);"; + +set @a=2; +execute stmt; +set @a=1; +--echo # we expect to see having_condition in both the below statements +execute stmt; +execute stmt; + +drop table t1, t2; + +--echo End of 10.11 tests diff --git a/sql/item_subselect.h b/sql/item_subselect.h index e6e8d4b6271..1e71bf6fddb 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -639,6 +639,7 @@ public: value= 0; null_value= 0; was_null= 0; + is_jtbm_const_tab= 0; } bool select_transformer(JOIN *join) override; bool create_in_to_exists_cond(JOIN *join_arg); From 76c79d4fd8c4280e8174023fe57d2a574a8706d1 Mon Sep 17 00:00:00 2001 From: ParadoxV5 Date: Thu, 17 Jul 2025 19:52:27 -0600 Subject: [PATCH 147/172] =?UTF-8?q?MDEV-37060:=20Don=E2=80=99t=20check=20E?= =?UTF-8?q?ncrpyted=20Server=20IDs=20in=20`mariadb-binlog`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MSAN found that `mariadb-binlog --force-read` checks encrypted events too for whether `--do-server-ids`/`ignore-server-ids` includes any of their (uninitialized) Server IDs. This fix extends the condition to stop skipping `UNKNOWN_EVENT`s by Server ID in addition to `ROTATE_EVENT`s. An alternative solution is to zero-initialize the `server_id` field of `Unknown_log_event` or even its supertype, `Log_event`. Though to avoid hiding `use-of-uninitialized-value` mistakes in the future, leaving unset fields uninitialized is more assured; not to mention the potential of ID 0 still in use. Reviewed-by: Brandon Nesterenko Acked-by: Daniel Black --- client/mysqlbinlog.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index b2ecadc4aed..5dc2d89a15e 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -1201,9 +1201,16 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, binlog, even if they have a server_id. Also, we have to read the format_description event so that we can parse subsequent events. + Don't skip Unknown events either since we don't know their `server_id`s. */ - if (ev_type != ROTATE_EVENT && is_server_id_excluded(ev->server_id)) - goto end; + switch (ev_type) { + case ROTATE_EVENT: + case UNKNOWN_EVENT: + break; + default: + if (is_server_id_excluded(ev->server_id)) + goto end; + } } if ((ev->when >= stop_datetime) || (pos >= stop_position_mot)) From 33e845595de1dacb0d3b8ee989e31c774349af41 Mon Sep 17 00:00:00 2001 From: ParadoxV5 Date: Tue, 15 Jul 2025 20:40:27 -0600 Subject: [PATCH 148/172] MDEV-36839: Revert MDEV-7409 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MDEV-6247 added PROCESSLIST states for when a Replication SQL thread processes Row events, including a WSRep variant that dynamically includes the Galera Sequence Number. MDEV-7409 further expanded on it by adding the table name to the states. However, PROCESSLIST __cannot__ support generated states. Because it loads the state texts asynchronously, only permanently static strings are safe. Even thread-local memory can become invalid when the thread terminates, which can happen in the middle of generating a PROCESSLIST. To prioritize memory safety, this commit reverts both variants to static strings as the non-WSRep variant was before MDEV-7409. * __Fully__ revert MDEV-7409 (d9898c9a71) * Remove the WSRep override from MDEV-6247 * Remove `THD::wsrep_info` and its compiler flag `WSREP_PROC_INFO` as they are now unused This commit also includes small optimizations from MDEV-36839’s previous draft, #4133. Reviewed-by: Brandon Nesterenko --- cmake/wsrep.cmake | 2 - config.h.cmake | 1 - mysql-test/suite/rpl/r/rpl_rbr_monitor.result | 43 ------ mysql-test/suite/rpl/t/rpl_rbr_monitor.test | 76 ----------- sql/log_event_server.cc | 123 ++---------------- sql/sql_class.cc | 1 - sql/sql_class.h | 1 - 7 files changed, 9 insertions(+), 238 deletions(-) delete mode 100644 mysql-test/suite/rpl/r/rpl_rbr_monitor.result delete mode 100644 mysql-test/suite/rpl/t/rpl_rbr_monitor.test diff --git a/cmake/wsrep.cmake b/cmake/wsrep.cmake index a01a1d68f64..95df72400c7 100644 --- a/cmake/wsrep.cmake +++ b/cmake/wsrep.cmake @@ -49,8 +49,6 @@ Then restart the build. SET(WSREP_VERSION "${WSREP_API_VERSION}.${WSREP_PATCH_VERSION}" CACHE INTERNAL "WSREP version") - SET(WSREP_PROC_INFO ${WITH_WSREP}) - SET(WSREP_PATCH_VERSION "wsrep_${WSREP_VERSION}") if (NOT WITH_WSREP_ALL) SET(WSREP_LIB_WITH_UNIT_TESTS OFF CACHE BOOL diff --git a/config.h.cmake b/config.h.cmake index 751bca8528e..90d1ed86a87 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -549,7 +549,6 @@ this is the case with Microsoft Windows VirtualFree(MEM_DECOMMIT) */ #ifndef EMBEDDED_LIBRARY #cmakedefine WSREP_INTERFACE_VERSION "@WSREP_INTERFACE_VERSION@" #cmakedefine WITH_WSREP 1 -#cmakedefine WSREP_PROC_INFO 1 #endif #if !defined(__STDC_FORMAT_MACROS) diff --git a/mysql-test/suite/rpl/r/rpl_rbr_monitor.result b/mysql-test/suite/rpl/r/rpl_rbr_monitor.result deleted file mode 100644 index e8ac6277233..00000000000 --- a/mysql-test/suite/rpl/r/rpl_rbr_monitor.result +++ /dev/null @@ -1,43 +0,0 @@ -include/master-slave.inc -[connection master] -connection master; -create table t1(a int primary key) engine=innodb; -connection slave; -connection slave1; -begin; -insert into t1(a) values(1); -connection master; -select * from t1; -a -insert into t1(a) values(1); -#monitoring write rows -connection slave; -#monitoring update rows -connection slave1; -rollback; -begin; -select a from t1 for update; -a -1 -connection master; -update t1 set a = a + 1 ; -connection slave; -#monitoring delete rows -connection slave1; -rollback; -begin; -select * from t1 for update; -a -2 -connection master; -delete from t1; -connection slave; -select * from t1; -a -2 -connection slave1; -rollback; -connection master; -drop table t1; -connection slave; -include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_rbr_monitor.test b/mysql-test/suite/rpl/t/rpl_rbr_monitor.test deleted file mode 100644 index 2bc1f9cd482..00000000000 --- a/mysql-test/suite/rpl/t/rpl_rbr_monitor.test +++ /dev/null @@ -1,76 +0,0 @@ -# -# Mdev-7409 On RBR, extend the PROCESSLIST info to include at least the name of -# the recently used table -# This testcase create Write_rows_log_event , Update_rows_log_event and -# Delete_rows_log_event which is blocked on slave and we will check whether -# whether processinfo includes table name or not. ---source include/have_innodb.inc ---source include/have_binlog_format_row.inc ---source include/master-slave.inc ---enable_connect_log - ---connection master -create table t1(a int primary key) engine=innodb; - ---sync_slave_with_master ---connection slave1 -begin; -insert into t1(a) values(1); ---connection master -select * from t1; - -insert into t1(a) values(1); ---save_master_pos - ---echo #monitoring write rows ---connection slave - - -let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST - WHERE DB = 'test' AND STATE LIKE "Write_rows_log_event::write_row(%) on table %"; ---source include/wait_condition.inc - - ---echo #monitoring update rows ---connection slave1 -rollback; ---sync_with_master -begin; -select a from t1 for update; - ---connection master -update t1 set a = a + 1 ; ---save_master_pos - ---connection slave -let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST - WHERE DB = 'test' AND STATE LIKE "Update_rows_log_event::find_row(%) on table %"; ---source include/wait_condition.inc - ---echo #monitoring delete rows ---connection slave1 -rollback; ---sync_with_master -begin; -select * from t1 for update; - ---connection master -delete from t1; ---save_master_pos - ---connection slave -select * from t1; -let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST - WHERE DB = 'test' AND STATE LIKE "Delete_rows_log_event::find_row(%) on table %"; ---source include/wait_condition.inc - -#CleanUp ---connection slave1 -rollback; ---sync_with_master - ---connection master -drop table t1; ---sync_slave_with_master - ---source include/rpl_end.inc diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc index d0130349e43..b1058dd0b6b 100644 --- a/sql/log_event_server.cc +++ b/sql/log_event_server.cc @@ -6212,6 +6212,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi) table->in_use= thd; error= do_exec_row(rgi); + THD_STAGE_INFO(thd, stage_executing); if (unlikely(error)) DBUG_PRINT("info", ("error: %s", HA_ERR(error))); @@ -8084,36 +8085,10 @@ int Rows_log_event::update_sequence() int Write_rows_log_event::do_exec_row(rpl_group_info *rgi) { - DBUG_ASSERT(m_table != NULL); - const char *tmp= thd->get_proc_info(); - char *message, msg[128]; - const LEX_CSTRING &table_name= m_table->s->table_name; - const char quote_char= - get_quote_char_for_identifier(thd, table_name.str, table_name.length); - my_snprintf(msg, sizeof msg, - "Write_rows_log_event::write_row() on table %c%.*s%c", - quote_char, int(table_name.length), table_name.str, quote_char); - message= msg; int error; - -#ifdef WSREP_PROC_INFO - my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, - "Write_rows_log_event::write_row(%lld) on table %c%.*s%c", - (long long) wsrep_thd_trx_seqno(thd), quote_char, - int(table_name.length), table_name.str, quote_char); - message= thd->wsrep_info; -#endif /* WSREP_PROC_INFO */ - - thd_proc_info(thd, message); + thd_proc_info(thd, "Write_rows_log_event::write_row()"); error= write_row(rgi, slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT); - thd_proc_info(thd, tmp); - - if (unlikely(error) && unlikely(!thd->is_error())) - { - DBUG_ASSERT(0); - my_error(ER_UNKNOWN_ERROR, MYF(0)); - } - + DBUG_ASSERT(!error || thd->is_error()); return error; } @@ -8725,46 +8700,15 @@ Delete_rows_log_event::do_after_row_operations(const Slave_reporting_capability int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi) { int error; - const char *tmp= thd->get_proc_info(); - char *message, msg[128]; - const LEX_CSTRING &table_name= m_table->s->table_name; - const char quote_char= - get_quote_char_for_identifier(thd, table_name.str, table_name.length); - my_snprintf(msg, sizeof msg, - "Delete_rows_log_event::find_row() on table %c%.*s%c", - quote_char, int(table_name.length), table_name.str, quote_char); - message= msg; - const bool invoke_triggers= (m_table->triggers && do_invoke_trigger()); - DBUG_ASSERT(m_table != NULL); + const bool invoke_triggers= m_table->triggers && do_invoke_trigger(); -#ifdef WSREP_PROC_INFO - my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, - "Delete_rows_log_event::find_row(%lld) on table %c%.*s%c", - (long long) wsrep_thd_trx_seqno(thd), quote_char, - int(table_name.length), table_name.str, - quote_char); - message= thd->wsrep_info; -#endif /* WSREP_PROC_INFO */ - - thd_proc_info(thd, message); + thd_proc_info(thd, "Delete_rows_log_event::find_row()"); if (likely(!(error= find_row(rgi)))) { /* Delete the record found, located in record[0] */ - my_snprintf(msg, sizeof msg, - "Delete_rows_log_event::ha_delete_row() on table %c%.*s%c", - quote_char, int(table_name.length), table_name.str, - quote_char); - message= msg; -#ifdef WSREP_PROC_INFO - snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, - "Delete_rows_log_event::ha_delete_row(%lld) on table %c%.*s%c", - (long long) wsrep_thd_trx_seqno(thd), quote_char, - int(table_name.length), table_name.str, quote_char); - message= thd->wsrep_info; -#endif - thd_proc_info(thd, message); + thd_proc_info(thd, "Delete_rows_log_event::ha_delete_row()"); if (invoke_triggers && unlikely(process_triggers(TRG_EVENT_DELETE, TRG_ACTION_BEFORE, FALSE))) @@ -8791,7 +8735,6 @@ int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi) error= HA_ERR_GENERIC; // in case if error is not set yet m_table->file->ha_index_or_rnd_end(); } - thd_proc_info(thd, tmp); return error; } @@ -8885,28 +8828,7 @@ int Update_rows_log_event::do_exec_row(rpl_group_info *rgi) { const bool invoke_triggers= (m_table->triggers && do_invoke_trigger()); - const char *tmp= thd->get_proc_info(); - DBUG_ASSERT(m_table != NULL); - char *message, msg[128]; - const LEX_CSTRING &table_name= m_table->s->table_name; - const char quote_char= - get_quote_char_for_identifier(thd, table_name.str, table_name.length); - my_snprintf(msg, sizeof msg, - "Update_rows_log_event::find_row() on table %c%.*s%c", - quote_char, int(table_name.length), table_name.str, quote_char); - message= msg; - -#ifdef WSREP_PROC_INFO - my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, - "Update_rows_log_event::find_row(%lld) on table %c%.*s%c", - (long long) wsrep_thd_trx_seqno(thd), quote_char, - int(table_name.length), table_name.str, - quote_char); - message= thd->wsrep_info; -#endif /* WSREP_PROC_INFO */ - - thd_proc_info(thd, message); - + thd_proc_info(thd, "Update_rows_log_event::find_row()"); int error= find_row(rgi); if (unlikely(error)) { @@ -8916,7 +8838,6 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) */ if ((m_curr_row= m_curr_row_end)) unpack_current_row(rgi, &m_cols_ai); - thd_proc_info(thd, tmp); return error; } @@ -8939,20 +8860,8 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) store_record(m_table,record[1]); m_curr_row= m_curr_row_end; - my_snprintf(msg, sizeof msg, - "Update_rows_log_event::unpack_current_row() on table %c%.*s%c", - quote_char, int(table_name.length), table_name.str, quote_char); - message= msg; -#ifdef WSREP_PROC_INFO - my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, - "Update_rows_log_event::unpack_current_row(%lld) on table %c%.*s%c", - (long long) wsrep_thd_trx_seqno(thd), quote_char, - int(table_name.length), table_name.str, quote_char); - message= thd->wsrep_info; -#endif /* WSREP_PROC_INFO */ - /* this also updates m_curr_row_end */ - thd_proc_info(thd, message); + thd_proc_info(thd, "Update_rows_log_event::unpack_current_row()"); if (unlikely((error= unpack_current_row(rgi, &m_cols_ai)))) goto err; if (m_table->s->long_unique_table) @@ -8972,19 +8881,7 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) DBUG_DUMP("new values", m_table->record[0], m_table->s->reclength); #endif - my_snprintf(msg, sizeof msg, - "Update_rows_log_event::ha_update_row() on table %c%.*s%c", - quote_char, int(table_name.length), table_name.str, quote_char); - message= msg; -#ifdef WSREP_PROC_INFO - my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, - "Update_rows_log_event::ha_update_row(%lld) on table %c%.*s%c", - (long long) wsrep_thd_trx_seqno(thd), quote_char, - int(table_name.length), table_name.str, quote_char); - message= thd->wsrep_info; -#endif /* WSREP_PROC_INFO */ - - thd_proc_info(thd, message); + thd_proc_info(thd, "Update_rows_log_event::ha_update_row()"); if (invoke_triggers && unlikely(process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_BEFORE, TRUE))) { @@ -9016,9 +8913,7 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) unlikely(process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_AFTER, TRUE))) error= HA_ERR_GENERIC; // in case if error is not set yet - err: - thd_proc_info(thd, tmp); m_table->file->ha_index_or_rnd_end(); return error; } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 2d99fa1c81f..1d51d793872 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -915,7 +915,6 @@ THD::THD(my_thread_id id, bool is_wsrep_applier) #ifdef WITH_WSREP mysql_cond_init(key_COND_wsrep_thd, &COND_wsrep_thd, NULL); - wsrep_info[sizeof(wsrep_info) - 1] = '\0'; /* make sure it is 0-terminated */ #endif /* Call to init() below requires fully initialized Open_tables_state. */ reset_open_tables_state(); diff --git a/sql/sql_class.h b/sql/sql_class.h index 3268e6f0c50..4edc4a081b3 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -5553,7 +5553,6 @@ public: uint32 wsrep_rand; rpl_group_info *wsrep_rgi; bool wsrep_converted_lock_session; - char wsrep_info[128]; /* string for dynamic proc info */ ulong wsrep_retry_counter; // of autocommit bool wsrep_PA_safe; char* wsrep_retry_query; From 5f51a3a6ebeeb592faa56cb5d214b5b5b2c60795 Mon Sep 17 00:00:00 2001 From: Brandon Nesterenko Date: Tue, 8 Jul 2025 15:53:18 -0600 Subject: [PATCH 149/172] MDEV-36906: RBR crashes upon DML after CONVERT PARTITION MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MDEV-33658 part 1’s refactoring ecaedbe299fe11372c36319f9b732b81e9f54883 introduced a new function init_key_info which (in part) aims to calculate the total key length; however, it doesn’t account for the key already having been initialized (as happens when called via ALTER TABLE .. CONVERT PARTITION .. TO TABLE). This leads to crashes when this key is later iterated over, because the iterator will try to iterate over additional key parts which don’t exist because the length reports as longer than the actual memory owned. The crash reported by MDEV-36906 highlights this in function key_copy. To explain how the keys already have been initialized, init_key_info is called multiple times. That is, init_key_info is called from mysql_prepare_create_table, which prepares a table and its key structures for table creation, which is in turn called by mysql_write_frm when using flags MFRM_WRITE_SHADOW and MFRM_WRITE_CONVERTED_TO. The ALTER TABLE .. CONVERT PARTITION .. TO TABLE use case (see function fast_alter_partition_table), calls mysql_write_frm multiple times with both of these flags set (first with MFRM_WRITE_CONVERTED_TO and then with MFRM_WRITE_SHADOW). Raising it up a level, mysql_prepare_create_table doesn't need to be called again after it has already been invoked when just writing frms. Init_key_info is the only place in that function which leads to side effects, but the rest is redundant and can be skipped on the second call (i.e. when writing the shadow). The patch fixes this by skipping the call to mysql_prepare_create_table in mysql_write_frm in the MFRM_WRITE_SHADOW block when it has already been called previously. To track whether or not it has been previously called, we add a new flag for the mysql_write_frm function, MFRM_ALTER_INFO_PREPARED, which is hard-coded into the function call on the later invocation. Test case based on work by Elena Stepanova Reviewed By: ============ Sergei Golubchik Nikita Malyavin --- .../rpl/r/rpl_alter_convert_partition.result | 80 ++++++++++++ .../rpl/t/rpl_alter_convert_partition.test | 117 ++++++++++++++++++ sql/sql_partition.cc | 2 +- sql/sql_table.cc | 46 +++++-- sql/sql_table.h | 2 + 5 files changed, 239 insertions(+), 8 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_alter_convert_partition.result create mode 100644 mysql-test/suite/rpl/t/rpl_alter_convert_partition.test diff --git a/mysql-test/suite/rpl/r/rpl_alter_convert_partition.result b/mysql-test/suite/rpl/r/rpl_alter_convert_partition.result new file mode 100644 index 00000000000..a6b42d11e66 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_alter_convert_partition.result @@ -0,0 +1,80 @@ +include/master-slave.inc +[connection master] +# +# Ensure initial CREATE TABLE with partitioned data is replicated +# correctly +connection master; +create table t (a int, b int, key(a)) engine=innodb partition by range (b) (partition p1 values less than (10), partition pn values less than (maxvalue)); +insert into t values (1,5),(2,100); +include/save_master_gtid.inc +connection slave; +include/sync_with_master_gtid.inc +include/diff_tables.inc [master:test.t,slave:test.t] +# +# Ensure ALTER TABLE .. CONVERT PARTITION .. TO TABLE replicates +# correctly +connection master; +alter table t convert partition p1 to table offspring; +include/save_master_gtid.inc +connection slave; +include/sync_with_master_gtid.inc +include/diff_tables.inc [master:test.t,slave:test.t] +include/diff_tables.inc [master:test.offspring,slave:test.offspring] +# +# Ensure data can be inserted into existing table after +# ALTER TABLE .. CONVERT PARTITION .. TO TABLE +connection master; +insert into t values (3, 6); +include/save_master_gtid.inc +connection slave; +include/sync_with_master_gtid.inc +include/diff_tables.inc [master:test.t,slave:test.t] +# +# Ensure data can be inserted into offspring table after +# ALTER TABLE .. CONVERT PARTITION .. TO TABLE +connection master; +insert into offspring values (4, 101); +include/save_master_gtid.inc +connection slave; +include/sync_with_master_gtid.inc +include/diff_tables.inc [master:test.offspring,slave:test.offspring] +# +# Ensure data can be updated in existing table after +# ALTER TABLE .. CONVERT PARTITION .. TO TABLE +connection master; +update t set b=b+1 where a=3; +include/save_master_gtid.inc +connection slave; +include/sync_with_master_gtid.inc +include/diff_tables.inc [master:test.t,slave:test.t] +# +# Ensure data can be updated in offspring table after +# ALTER TABLE .. CONVERT PARTITION .. TO TABLE +connection master; +update offspring set b=b+1 where a=4; +include/save_master_gtid.inc +connection slave; +include/sync_with_master_gtid.inc +include/diff_tables.inc [master:test.offspring,slave:test.offspring] +# +# Ensure data can be deleted in existing table after +# ALTER TABLE .. CONVERT PARTITION .. TO TABLE +connection master; +delete from t; +include/save_master_gtid.inc +connection slave; +include/sync_with_master_gtid.inc +include/diff_tables.inc [master:test.t,slave:test.t] +# +# Ensure data can be deleted in offspring table after +# ALTER TABLE .. CONVERT PARTITION .. TO TABLE +connection master; +delete from offspring; +include/save_master_gtid.inc +connection slave; +include/sync_with_master_gtid.inc +include/diff_tables.inc [master:test.offspring,slave:test.offspring] +connection master; +drop table t, offspring; +include/rpl_end.inc +# End of rpl_alter_convert_partition diff --git a/mysql-test/suite/rpl/t/rpl_alter_convert_partition.test b/mysql-test/suite/rpl/t/rpl_alter_convert_partition.test new file mode 100644 index 00000000000..ef5aa3ed9cb --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_alter_convert_partition.test @@ -0,0 +1,117 @@ +# +# This test ensures that ALTER TABLE ... CONVERT PARTITION ... TO TABLE +# works with replication. I.e., the partitioning is done correctly, and +# after partitioning, both tables can be updated correctly. +# +# References: +# MDEV-36906: RBR crashes upon DML after CONVERT PARTITION +# + +--source include/have_innodb.inc +--source include/have_partition.inc +--source include/master-slave.inc + + +--echo # +--echo # Ensure initial CREATE TABLE with partitioned data is replicated +--echo # correctly +--connection master +create table t (a int, b int, key(a)) engine=innodb partition by range (b) (partition p1 values less than (10), partition pn values less than (maxvalue)); +insert into t values (1,5),(2,100); +--source include/save_master_gtid.inc +--connection slave +--source include/sync_with_master_gtid.inc +--let $diff_tables=master:test.t,slave:test.t + +--source include/diff_tables.inc + +--echo # +--echo # Ensure ALTER TABLE .. CONVERT PARTITION .. TO TABLE replicates +--echo # correctly +--connection master +alter table t convert partition p1 to table offspring; +--source include/save_master_gtid.inc +--connection slave +--source include/sync_with_master_gtid.inc +--let $diff_tables=master:test.t,slave:test.t +--source include/diff_tables.inc +--let $diff_tables=master:test.offspring,slave:test.offspring +--source include/diff_tables.inc + + +--echo # +--echo # Ensure data can be inserted into existing table after +--echo # ALTER TABLE .. CONVERT PARTITION .. TO TABLE +--connection master +insert into t values (3, 6); +--source include/save_master_gtid.inc +--connection slave +--source include/sync_with_master_gtid.inc +--let $diff_tables=master:test.t,slave:test.t +--source include/diff_tables.inc + + +--echo # +--echo # Ensure data can be inserted into offspring table after +--echo # ALTER TABLE .. CONVERT PARTITION .. TO TABLE +--connection master +insert into offspring values (4, 101); +--source include/save_master_gtid.inc +--connection slave +--source include/sync_with_master_gtid.inc +--let $diff_tables=master:test.offspring,slave:test.offspring +--source include/diff_tables.inc + + +--echo # +--echo # Ensure data can be updated in existing table after +--echo # ALTER TABLE .. CONVERT PARTITION .. TO TABLE +--connection master +update t set b=b+1 where a=3; +--source include/save_master_gtid.inc +--connection slave +--source include/sync_with_master_gtid.inc +--let $diff_tables=master:test.t,slave:test.t +--source include/diff_tables.inc + + +--echo # +--echo # Ensure data can be updated in offspring table after +--echo # ALTER TABLE .. CONVERT PARTITION .. TO TABLE +--connection master +update offspring set b=b+1 where a=4; +--source include/save_master_gtid.inc +--connection slave +--source include/sync_with_master_gtid.inc +--let $diff_tables=master:test.offspring,slave:test.offspring +--source include/diff_tables.inc + + +--echo # +--echo # Ensure data can be deleted in existing table after +--echo # ALTER TABLE .. CONVERT PARTITION .. TO TABLE +--connection master +delete from t; +--source include/save_master_gtid.inc +--connection slave +--source include/sync_with_master_gtid.inc +--let $diff_tables=master:test.t,slave:test.t +--source include/diff_tables.inc + + +--echo # +--echo # Ensure data can be deleted in offspring table after +--echo # ALTER TABLE .. CONVERT PARTITION .. TO TABLE +--connection master +delete from offspring; +--source include/save_master_gtid.inc +--connection slave +--source include/sync_with_master_gtid.inc +--let $diff_tables=master:test.offspring,slave:test.offspring +--source include/diff_tables.inc + + +--connection master +drop table t, offspring; +--source include/rpl_end.inc +--echo # End of rpl_alter_convert_partition diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index ba7e7207ebb..da2f37d7b7f 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -7626,7 +7626,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT("convert_partition_1") || write_log_drop_shadow_frm(lpt) || ERROR_INJECT("convert_partition_2") || - mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || + mysql_write_frm(lpt, WFRM_WRITE_SHADOW|WFRM_ALTER_INFO_PREPARED) || ERROR_INJECT("convert_partition_3") || wait_while_table_is_used(thd, table, HA_EXTRA_NOT_USED) || ERROR_INJECT("convert_partition_4") || diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 7a3a25d3ce0..f60463a5cf8 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -721,16 +721,30 @@ uint build_table_shadow_filename(char *buff, size_t bufflen, lpt Struct carrying many parameters needed for this method flags Flags as defined below - WFRM_INITIAL_WRITE If set we need to prepare table before - creating the frm file - WFRM_INSTALL_SHADOW If set we should install the new frm - WFRM_KEEP_SHARE If set we know that the share is to be + WFRM_WRITE_SHADOW If set, we need to prepare the table before + creating the frm file. Note it is possible that + mysql_write_frm was already called with + WFRM_WRITE_CONVERTED_TO, which would have + already called mysql_prepare_create_table, in + which case, we can skip that specific step in + the preparation. + WFRM_INSTALL_SHADOW If set, we should install the new frm + WFRM_KEEP_SHARE If set, we know that the share is to be retained and thus we should ensure share object is correct, if not set we don't set the new partition syntax string since we know the share object is destroyed. - WFRM_PACK_FRM If set we should pack the frm file and delete - the frm file + WFRM_WRITE_CONVERTED_TO Similar to WFRM_WRITE_SHADOW but for + ALTER TABLE ... CONVERT PARTITION .. TO TABLE, + i.e., we need to prepare the table before + creating the frm file. Though in this case, + mysql_write_frm will be called again with + WFRM_WRITE_SHADOW, where the + prepare_create_table step will be skipped. + WFRM_BACKUP_ORIGINAL If set, will back up the existing frm file + before creating the new frm file. + WFRM_ALTER_INFO_PREPARED If set, the prepare_create_table step should be + skipped when WFRM_WRITE_SHADOW is set. RETURN VALUES TRUE Error @@ -775,7 +789,15 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) strxmov(shadow_frm_name, shadow_path, reg_ext, NullS); if (flags & WFRM_WRITE_SHADOW) { - if (mysql_prepare_create_table(lpt->thd, lpt->create_info, lpt->alter_info, + /* + It is possible mysql_prepare_create_table was already called in our + create/alter_info context and we don't need to call it again. That is, if + in the context of `ALTER TABLE ... CONVERT PARTITION .. TO TABLE` then + mysql_prepare_create_table would have already been called through a prior + invocation of mysql_write_frm with flag MFRM_WRITE_CONVERTED_TO. + */ + if (!(flags & WFRM_ALTER_INFO_PREPARED) && + mysql_prepare_create_table(lpt->thd, lpt->create_info, lpt->alter_info, &lpt->db_options, lpt->table->file, &lpt->key_info_buffer, &lpt->key_count, C_ALTER_TABLE)) @@ -850,6 +872,11 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) ERROR_INJECT("create_before_create_frm")) DBUG_RETURN(TRUE); + /* + For WFRM_WRITE_CONVERTED_TO, we always need to call + mysql_prepare_create_table + */ + DBUG_ASSERT(!(flags & WFRM_ALTER_INFO_PREPARED)); if (mysql_prepare_create_table(thd, create_info, lpt->alter_info, &lpt->db_options, file, &lpt->key_info_buffer, &lpt->key_count, @@ -3004,6 +3031,11 @@ my_bool init_key_info(THD *thd, Alter_info *alter_info, for (Key &key: alter_info->key_list) { + /* + Ensure we aren't re-initializing keys that were already initialized. + */ + DBUG_ASSERT(!key.length); + if (key.type == Key::FOREIGN_KEY) continue; diff --git a/sql/sql_table.h b/sql/sql_table.h index 3a9a58ddc05..69982d7b4e9 100644 --- a/sql/sql_table.h +++ b/sql/sql_table.h @@ -55,11 +55,13 @@ enum enum_explain_filename_mode /* depends on errmsg.txt Database `db`, Table `t` ... */ #define EXPLAIN_FILENAME_MAX_EXTRA_LENGTH 63 +/* See mysql_write_frm function comment for explanations of these flags */ #define WFRM_WRITE_SHADOW 1 #define WFRM_INSTALL_SHADOW 2 #define WFRM_KEEP_SHARE 4 #define WFRM_WRITE_CONVERTED_TO 8 #define WFRM_BACKUP_ORIGINAL 16 +#define WFRM_ALTER_INFO_PREPARED 32 /* Flags for conversion functions. */ static const uint FN_FROM_IS_TMP= 1 << 0; From d6cb7255e9800434587b8ef3c684a205dbd8c35f Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Sat, 12 Jul 2025 19:28:23 +0300 Subject: [PATCH 150/172] MDEV-30711: Crash in add_keyuses_for_splitting() when joining with a derived table Split-Materialized optimization in add_keyuses_for_splitting() pushes "derived_split_table.field=right_expr" down into the derived_split_table. This requires that right_expr's attributes are updated. Typically it has references to tables in the parent select, those become references to outside in the child select. This was done with the right_expr->walk(&Item::set_fields_as_dependent_processor, ...) call. The function was implemented for Item_field objects. However it was not implemented for Item_direct_view_ref objects. If an Item_direct_view_ref object didn't have an Item_field inside (e.g. view column referred to a constant) this would mean that used_tables() attribute would not be updated and right_expr will end up with wrong used_tables(), which could eventually cause a crash as it looked like a reference to non-existant table. Fixed by adding Item_direct_view_ref::set_fields_as_dependent_processor() with the same logic as in Item_field. --- mysql-test/main/derived_split_innodb.result | 33 +++++++++++++++++++++ mysql-test/main/derived_split_innodb.test | 30 +++++++++++++++++++ sql/item.h | 13 ++++++++ sql/opt_split.cc | 5 ++++ 4 files changed, 81 insertions(+) diff --git a/mysql-test/main/derived_split_innodb.result b/mysql-test/main/derived_split_innodb.result index 6346b44dcc6..685c663af2f 100644 --- a/mysql-test/main/derived_split_innodb.result +++ b/mysql-test/main/derived_split_innodb.result @@ -935,4 +935,37 @@ cnt 6 DROP TABLE t1; # End of 10.4 tests +# +# MDEV-30711: Crash in add_keyuses_for_splitting() when joining with a derived table +# +create table t1 (a int); +insert into t1 values (1),(2); +create table t2 (a int, index(a)); +insert into t2 values (1),(3); +create view v1 as +select +nullif(tbl2.COL1,123) as COL10 +from +t1 left join +(select 1 as COL1, a from t2) tbl2 on t1.a=tbl2.a; +create table t10 (grp_id int, a int, index(grp_id)); +insert into t10 select A.seq, B.seq from seq_1_to_100 A, seq_1_to_100 B; +analyze table t10; +Table Op Msg_type Msg_text +test.t10 analyze status Engine-independent statistics collected +test.t10 analyze status Table is already up to date +explain +select * from +v1, +(select grp_id, count(*) from t10 group by grp_id) T +where +T.grp_id=v1.COL10; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 +1 PRIMARY t2 ref a a 5 test.t1.a 2 Using where; Using index +1 PRIMARY ref key0 key0 5 func 10 Using where +2 DERIVED t10 index grp_id grp_id 5 NULL 10000 Using index; Using temporary; Using filesort +drop table t1,t2, t10; +drop view v1; +# End of 10.11 tests SET GLOBAL innodb_stats_persistent=@save_innodb_stats_persistent; diff --git a/mysql-test/main/derived_split_innodb.test b/mysql-test/main/derived_split_innodb.test index 67db02f7483..9a58fd94db8 100644 --- a/mysql-test/main/derived_split_innodb.test +++ b/mysql-test/main/derived_split_innodb.test @@ -549,4 +549,34 @@ DROP TABLE t1; --echo # End of 10.4 tests +--echo # +--echo # MDEV-30711: Crash in add_keyuses_for_splitting() when joining with a derived table +--echo # +create table t1 (a int); +insert into t1 values (1),(2); +create table t2 (a int, index(a)); +insert into t2 values (1),(3); + +create view v1 as +select + nullif(tbl2.COL1,123) as COL10 +from + t1 left join + (select 1 as COL1, a from t2) tbl2 on t1.a=tbl2.a; + +create table t10 (grp_id int, a int, index(grp_id)); +insert into t10 select A.seq, B.seq from seq_1_to_100 A, seq_1_to_100 B; +analyze table t10; + +explain +select * from + v1, + (select grp_id, count(*) from t10 group by grp_id) T +where + T.grp_id=v1.COL10; + +drop table t1,t2, t10; +drop view v1; + +--echo # End of 10.11 tests SET GLOBAL innodb_stats_persistent=@save_innodb_stats_persistent; diff --git a/sql/item.h b/sql/item.h index 1e822113e53..0938c5dda78 100644 --- a/sql/item.h +++ b/sql/item.h @@ -6504,6 +6504,19 @@ public: { return get_item_copy(thd, this); } Item *field_transformer_for_having_pushdown(THD *, uchar *) override { return this; } + /* + Do the same thing as Item_field: if we were referring to a local view, + now we refer to somewhere outside of our SELECT. + */ + bool set_fields_as_dependent_processor(void *arg) override + { + if (!(used_tables() & OUTER_REF_TABLE_BIT)) + { + depended_from= (st_select_lex *) arg; + item_equal= NULL; + } + return 0; + } }; diff --git a/sql/opt_split.cc b/sql/opt_split.cc index c174f1b4368..a54ba525a3b 100644 --- a/sql/opt_split.cc +++ b/sql/opt_split.cc @@ -610,6 +610,11 @@ void TABLE::add_splitting_info_for_key_field(KEY_FIELD *key_field) right_item->walk(&Item::set_fields_as_dependent_processor, false, join->select_lex); right_item->update_used_tables(); + /* + We've just pushed right_item down into the child select. It may only + have references to outside. + */ + DBUG_ASSERT(!(right_item->used_tables() & ~PSEUDO_TABLE_BITS)); eq_item= new (thd->mem_root) Item_func_eq(thd, left_item, right_item); } if (!eq_item) From 288db5fa5f73aa0f75f776dee19a3ba74c39d2a1 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 18 Jul 2025 20:32:45 +0200 Subject: [PATCH 151/172] MDEV-24981 LOAD INDEX may cause rollback of prepared XA transaction XAER_RMFAIL means the admin statement was not allowed, it's not a per-table message, so must fail the whole statement. And must not rollback, obviously, it's not allowed after prepare. Also, remove duplicate XAER_RMFAIL in open_tables(), check_has_uncommitted_xa() already issues it. --- mysql-test/main/xa.result | 23 +++++++++++++++++++++-- mysql-test/main/xa.test | 22 ++++++++++++++++------ sql/sql_admin.cc | 3 +++ sql/sql_base.cc | 3 --- 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/mysql-test/main/xa.result b/mysql-test/main/xa.result index f0544fe50dd..cacd484707f 100644 --- a/mysql-test/main/xa.result +++ b/mysql-test/main/xa.result @@ -1,5 +1,4 @@ call mtr.add_suppression("Deadlock found when trying to get lock; try restarting transaction"); -drop table if exists t1, t2; create table t1 (a int) engine=innodb; xa start 'test1'; insert t1 values (10); @@ -595,6 +594,26 @@ formatID gtrid_length bqual_length data xa rollback '4'; ERROR XA100: XA_RBROLLBACK: Transaction branch was rolled back set @@global.read_only=@sav_read_only; -# # End of 10.5 tests # +# MDEV-24981 LOAD INDEX may cause rollback of prepared XA transaction +# +create table t1 (f1 integer primary key) engine=innodb; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` int(11) NOT NULL, + PRIMARY KEY (`f1`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +xa start 'a'; +insert into t1 values (1); +xa end 'a'; +xa prepare 'a'; +load index into cache t1 key(primary); +ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the PREPARED state +xa commit 'a'; +select count(*) from t1; +count(*) +1 +drop table t1; +# End of 10.11 tests diff --git a/mysql-test/main/xa.test b/mysql-test/main/xa.test index c77f11761d8..12ff85476f8 100644 --- a/mysql-test/main/xa.test +++ b/mysql-test/main/xa.test @@ -1,7 +1,7 @@ # # WL#1756 # --- source include/have_innodb.inc +--source include/have_innodb.inc --source include/not_embedded.inc # Save the initial number of concurrent sessions @@ -12,10 +12,6 @@ call mtr.add_suppression("Deadlock found when trying to get lock; try restarting call mtr.add_suppression("InnoDB: Transaction was aborted due to "); --enable_query_log - ---disable_warnings -drop table if exists t1, t2; ---enable_warnings create table t1 (a int) engine=innodb; xa start 'test1'; insert t1 values (10); @@ -752,7 +748,21 @@ xa rollback '4'; set @@global.read_only=@sav_read_only; +--echo # End of 10.5 tests --echo # ---echo # End of 10.5 tests +--echo # MDEV-24981 LOAD INDEX may cause rollback of prepared XA transaction --echo # +create table t1 (f1 integer primary key) engine=innodb; +show create table t1; +xa start 'a'; +insert into t1 values (1); +xa end 'a'; +xa prepare 'a'; +--error ER_XAER_RMFAIL +load index into cache t1 key(primary); +xa commit 'a'; +select count(*) from t1; +drop table t1; + +--echo # End of 10.11 tests diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index 3b6a73f95c5..bb318355422 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -565,6 +565,9 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, Disable_wsrep_on_guard wsrep_on_guard(thd, disable_wsrep_on); #endif /* WITH_WSREP */ + if (thd->transaction->xid_state.check_has_uncommitted_xa()) + DBUG_RETURN(TRUE); + fill_check_table_metadata_fields(thd, &field_list); if (protocol->send_result_set_metadata(&field_list, diff --git a/sql/sql_base.cc b/sql/sql_base.cc index dcf2c35365b..ad514b73742 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4598,10 +4598,7 @@ bool open_tables(THD *thd, const DDL_options_st &options, if (!table->schema_table) { if (thd->transaction->xid_state.check_has_uncommitted_xa()) - { - thd->transaction->xid_state.er_xaer_rmfail(); DBUG_RETURN(true); - } else break; } From 6521b4112bb6eec61985fdd07968dd499a8cb727 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 20 Jul 2025 10:32:37 +0200 Subject: [PATCH 152/172] MDEV-37281 incorrect isolation level in update with unique using hash or without overlap in 11.4 multi_update::prepare() is called both for single and multi update. as it's invoked before lock_tables(), it cannot do prepare_for_insert(), which calls external_lock() and only can be used on an already locked table --- mysql-test/main/update_innodb.result | 18 ++++++++++++++++++ mysql-test/main/update_innodb.test | 20 +++++++++++++++++++- sql/sql_update.cc | 4 ++-- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/mysql-test/main/update_innodb.result b/mysql-test/main/update_innodb.result index fbcbf78d865..e06594f7e28 100644 --- a/mysql-test/main/update_innodb.result +++ b/mysql-test/main/update_innodb.result @@ -251,3 +251,21 @@ update orders, customer, nation set orders.o_comment = "+++" where o_orderDATE o_custkey = c_custkey and c_nationkey = n_nationkey and n_name='PERU'; DROP DATABASE dbt3_s001; set default_storage_engine=@save_default_storage_engine; +use test; +# +# MDEV-37281 incorrect isolation level in update with unique using hash or without overlap +# +create table t1 (id int, e varchar(100), a int, unique (e) using hash) engine=innodb; +insert t1 values(10, '2000-01-01', 0); +insert t1 values(20, '2000-01-02', 1); +insert t1 values(30, '2000-01-03', 2); +set transaction isolation level read committed; +start transaction; +update t1 set a=10 where a=0; +connect con1,localhost,root; +set transaction isolation level read committed; +update t1 set a=20 where a=1; +connection default; +drop table t1; +disconnect con1; +# End of 11.4.tests diff --git a/mysql-test/main/update_innodb.test b/mysql-test/main/update_innodb.test index ad728fb8e28..c1d2fb33e22 100644 --- a/mysql-test/main/update_innodb.test +++ b/mysql-test/main/update_innodb.test @@ -193,7 +193,6 @@ let $c1= c_nationkey = n_nationkey and n_name='PERU'; - explain update orders, customer, nation set orders.o_comment = "+++" where o_orderDATE between '1992-01-01' and '1992-06-30' and o_custkey = c_custkey and c_nationkey = n_nationkey and n_name='PERU'; @@ -208,4 +207,23 @@ update orders, customer, nation set orders.o_comment = "+++" where o_orderDATE DROP DATABASE dbt3_s001; set default_storage_engine=@save_default_storage_engine; +use test; +--echo # +--echo # MDEV-37281 incorrect isolation level in update with unique using hash or without overlap +--echo # +create table t1 (id int, e varchar(100), a int, unique (e) using hash) engine=innodb; +insert t1 values(10, '2000-01-01', 0); +insert t1 values(20, '2000-01-02', 1); +insert t1 values(30, '2000-01-03', 2); +set transaction isolation level read committed; +start transaction; +update t1 set a=10 where a=0; +--connect con1,localhost,root +set transaction isolation level read committed; +update t1 set a=20 where a=1; +--connection default +drop table t1; +--disconnect con1 + +--echo # End of 11.4.tests diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 35bdaaeba08..b6d66da13d4 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1842,8 +1842,6 @@ int multi_update::prepare(List ¬_used_values, { table->read_set= &table->def_read_set; bitmap_union(table->read_set, &table->tmp_set); - if (!(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_PREPARE)) - table->file->prepare_for_insert(1); } } if (unlikely(error)) @@ -2076,6 +2074,8 @@ multi_update::initialize_tables(JOIN *join) ORDER group; TMP_TABLE_PARAM *tmp_param; + table->file->prepare_for_insert(1); + if (ignore) table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); if (table == main_table) // First table in join From 3109d994ebf867d6f3efc65a0e4c41195b8239f9 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Mon, 16 Jun 2025 14:52:32 +0300 Subject: [PATCH 153/172] MDEV-36323: Split Materialized code: last_refills is never set in 11.0+ SplM_opt_info::last_refills is never set, so remove it. It was used in In JOIN_TAB::choose_best_splitting(), use local variable "refills" there, instead. The logic in the function is that we compute startup_cost= refills * spl_plan->cost; only when we have a splitting query plan which implies "refills" was set accordingly. Also - Added a comment about what "refills" is. - Updated derived_cond_pushdown.result: the change makes the Split-Materialized plans more expensive, so the join order changes from t3, to , t3 --- mysql-test/main/derived_cond_pushdown.result | 2 +- sql/opt_split.cc | 22 ++++++++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/mysql-test/main/derived_cond_pushdown.result b/mysql-test/main/derived_cond_pushdown.result index 36f8beb8187..1fa1eea5dd3 100644 --- a/mysql-test/main/derived_cond_pushdown.result +++ b/mysql-test/main/derived_cond_pushdown.result @@ -22725,8 +22725,8 @@ where dt.a=t1.a and t3.a < 3 from t1 limit 5; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 1000 +2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 Using where 2 DEPENDENT SUBQUERY ref key0 key0 5 test.t1.a 1 -2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join) 3 LATERAL DERIVED t2 ref a a 5 test.t1.a 10 select a, diff --git a/sql/opt_split.cc b/sql/opt_split.cc index 29fa13d6a66..2c1197ba0fa 100644 --- a/sql/opt_split.cc +++ b/sql/opt_split.cc @@ -291,7 +291,6 @@ public: double unsplit_oper_cost; /* Cardinality of T when nothing is pushed */ double unsplit_card; - double last_refills; SplM_plan_info *find_plan(TABLE *table, uint key, uint parts); }; @@ -1056,6 +1055,25 @@ SplM_plan_info * JOIN_TAB::choose_best_splitting(uint idx, if (best_table) { *spl_pd_boundary= this->table->map; + /* + Compute "refills" - how many times we'll need to refill the split- + materialized temp. table. Split-materialized table has references to + preceding table(s). Suppose the join prefix is (t1, t2, t3) and + split-materialized refers to table t2: + + t1 t2 t3 + ^ | + +------------ + + + If we do not use join buffer for table t3, then we'll need to refill + the split-materialized table partial_join_cardinality({t1, t2}) times. + (this assumes that fanout of table t3 is greater than 1, which is + typically true). + If table t3 uses join buffer, then every time we get a record combination + of {t1.row,t2.row,t3.row} the t2.row may be different and so we will need + to refill every time, that is, + partial_join_cardinality(t1,t3,t3) times. + */ if (!best_param_tables) refills= 1; else @@ -1176,7 +1194,7 @@ SplM_plan_info * JOIN_TAB::choose_best_splitting(uint idx, The best plan that employs splitting is cheaper than the plan without splitting */ - startup_cost= spl_opt_info->last_refills * spl_plan->cost; + startup_cost= refills * spl_plan->cost; records= (ha_rows) (spl_opt_info->unsplit_card * spl_plan->split_sel); if (unlikely(thd->trace_started()) && ! already_printed) { From 18f85c8c681db74b35d3e042a998e4bccb1d6d98 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 24 Jul 2025 00:11:33 +0200 Subject: [PATCH 154/172] MDEV-37302 Assertion failure in Table_triggers_list::add_tables_and_routines_for_triggers upon attempt to insert DEFAULT into non-insertable view Only do trigger prelocking for tables that are doing to be modified (with a write lock). A table can cause prelocking if its DEFAULT value is used (because DEFAULT can be NEXTVAL), even if the table itself is only used for reads. Don't process triggers for such a table --- mysql-test/suite/sql_sequence/default.result | 10 ++++++++++ mysql-test/suite/sql_sequence/default.test | 11 +++++++++++ sql/sql_base.cc | 2 +- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/sql_sequence/default.result b/mysql-test/suite/sql_sequence/default.result index fb8fed00a9a..fe9c6af1795 100644 --- a/mysql-test/suite/sql_sequence/default.result +++ b/mysql-test/suite/sql_sequence/default.result @@ -303,4 +303,14 @@ execute stmt using default; deallocate prepare stmt; drop table t1; drop sequence s1; +# +# MDEV-37302 Assertion failure in Table_triggers_list::add_tables_and_routines_for_triggers upon attempt to insert DEFAULT into non-insertable view +# +create table t1 (f int); +create algorithm=temptable view v1 as select * from t1; +create trigger tr before update on t1 for each row set @a=1; +insert v1 values (default); +ERROR HY000: The target table v1 of the INSERT is not insertable-into +drop view v1; +drop table t1; # End of 10.6 tests diff --git a/mysql-test/suite/sql_sequence/default.test b/mysql-test/suite/sql_sequence/default.test index d7bc978ed9e..5cbfe237cd3 100644 --- a/mysql-test/suite/sql_sequence/default.test +++ b/mysql-test/suite/sql_sequence/default.test @@ -229,4 +229,15 @@ deallocate prepare stmt; drop table t1; drop sequence s1; +--echo # +--echo # MDEV-37302 Assertion failure in Table_triggers_list::add_tables_and_routines_for_triggers upon attempt to insert DEFAULT into non-insertable view +--echo # +create table t1 (f int); +create algorithm=temptable view v1 as select * from t1; +create trigger tr before update on t1 for each row set @a=1; +--error ER_NON_INSERTABLE_TABLE +insert v1 values (default); +drop view v1; +drop table t1; + --echo # End of 10.6 tests diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 1a4fa315c3c..501d13f201c 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4897,7 +4897,7 @@ bool DML_prelocking_strategy::handle_table(THD *thd, DBUG_ASSERT(table_list->lock_type >= TL_FIRST_WRITE || thd->lex->default_used); - if (table_list->trg_event_map) + if (table_list->trg_event_map && table_list->lock_type >= TL_FIRST_WRITE) { if (table->triggers) { From fb2f324f855080ce169e3896c7d375227bcc964f Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 25 Jul 2025 12:26:50 +0200 Subject: [PATCH 155/172] MDEV-37310 Non-debug failing assertion node->pcur->rel_pos == BTR_PCUR_ON upon violating long unique under READ-COMMITTED let's disallow UPDATE IGNORE in READ COMMITTED with the table has UNIQUE constraint that is USING HASH or is WITHOUT OVERLAPS This rarely-used combination should not block a release, with be fixed in MDEV-37233 --- mysql-test/main/long_unique_innodb.result | 16 ++++++++++- mysql-test/main/long_unique_innodb.test | 13 +++++++++ .../main/long_unique_innodb_debug.result | 5 ++-- mysql-test/main/long_unique_innodb_debug.test | 1 + mysql-test/suite/period/r/innodb_debug.result | 3 +- mysql-test/suite/period/t/innodb_debug.test | 1 + sql/handler.cc | 28 ++++--------------- 7 files changed, 40 insertions(+), 27 deletions(-) diff --git a/mysql-test/main/long_unique_innodb.result b/mysql-test/main/long_unique_innodb.result index 2af8a860115..fd2b3daf8e5 100644 --- a/mysql-test/main/long_unique_innodb.result +++ b/mysql-test/main/long_unique_innodb.result @@ -150,9 +150,23 @@ create table t1 (id int, f longtext, primary key (id), unique(f)) engine=innodb insert t1 (id) values (1),(2); set transaction isolation level read committed; update ignore t1 set f = 'x'; +ERROR 42000: UPDATE IGNORE in READ COMMITTED isolation mode of a table with a UNIQUE constraint USING HASH is not currently supported select * from t1; id f -1 x +1 NULL 2 NULL drop table t1; +# +# MDEV-37310 Non-debug failing assertion node->pcur->rel_pos == BTR_PCUR_ON upon violating long unique under READ-COMMITTED +# +create table t1 (id int, f blob, unique(id,f)) engine=innodb partition by key(id) partitions 2; +insert t1 values (1,'foo'),(2,'foo'); +set transaction isolation level read committed; +update ignore t1 set id = 2; +ERROR 42000: UPDATE IGNORE in READ COMMITTED isolation mode of a table with a UNIQUE constraint USING HASH is not currently supported +select * from t1; +id f +1 foo +2 foo +drop table t1; # End of 10.6 tests diff --git a/mysql-test/main/long_unique_innodb.test b/mysql-test/main/long_unique_innodb.test index 95bcc5c74fd..cbe2d7431fe 100644 --- a/mysql-test/main/long_unique_innodb.test +++ b/mysql-test/main/long_unique_innodb.test @@ -160,7 +160,20 @@ drop table t1; create table t1 (id int, f longtext, primary key (id), unique(f)) engine=innodb partition by key (id) partitions 9; insert t1 (id) values (1),(2); set transaction isolation level read committed; +--error ER_NOT_SUPPORTED_YET update ignore t1 set f = 'x'; select * from t1; drop table t1; + +--echo # +--echo # MDEV-37310 Non-debug failing assertion node->pcur->rel_pos == BTR_PCUR_ON upon violating long unique under READ-COMMITTED +--echo # +create table t1 (id int, f blob, unique(id,f)) engine=innodb partition by key(id) partitions 2; +insert t1 values (1,'foo'),(2,'foo'); +set transaction isolation level read committed; +--error ER_NOT_SUPPORTED_YET +update ignore t1 set id = 2; +select * from t1; +drop table t1; + --echo # End of 10.6 tests diff --git a/mysql-test/main/long_unique_innodb_debug.result b/mysql-test/main/long_unique_innodb_debug.result index 65409309b5f..497f2af39bf 100644 --- a/mysql-test/main/long_unique_innodb_debug.result +++ b/mysql-test/main/long_unique_innodb_debug.result @@ -166,6 +166,7 @@ set transaction isolation level read committed; update t1 set col2='a' where col1=15; set debug_sync="now SIGNAL do_insert"; connection con1; +ERROR 42000: UPDATE IGNORE in READ COMMITTED isolation mode of a table with a UNIQUE constraint USING HASH is not currently supported connection default; select * from t1; col1 col2 @@ -173,7 +174,7 @@ commit; select * from t1; col1 col2 5 b -9 e +9 d 15 a disconnect con1; disconnect con2; @@ -237,7 +238,7 @@ set transaction isolation level read committed; update t1 set col2='a' where col1=15; set debug_sync="now SIGNAL do_insert"; connection con1; -ERROR 42000: UPDATE IGNORE that modifies a primary key of a table with a UNIQUE constraint USING HASH is not currently supported +ERROR 42000: UPDATE IGNORE in READ COMMITTED isolation mode of a table with a UNIQUE constraint USING HASH is not currently supported connection default; select * from t1; col1 col2 diff --git a/mysql-test/main/long_unique_innodb_debug.test b/mysql-test/main/long_unique_innodb_debug.test index 5f750d9cf3c..d1a0673b54a 100644 --- a/mysql-test/main/long_unique_innodb_debug.test +++ b/mysql-test/main/long_unique_innodb_debug.test @@ -162,6 +162,7 @@ set transaction isolation level read committed; update t1 set col2='a' where col1=15; set debug_sync="now SIGNAL do_insert"; --connection con1 +--error ER_NOT_SUPPORTED_YET --reap --connection default select * from t1; diff --git a/mysql-test/suite/period/r/innodb_debug.result b/mysql-test/suite/period/r/innodb_debug.result index fe9adb4d4c3..eafc2230fdb 100644 --- a/mysql-test/suite/period/r/innodb_debug.result +++ b/mysql-test/suite/period/r/innodb_debug.result @@ -128,6 +128,7 @@ set transaction isolation level read committed; update t1 set s=date'2010-10-10' where e=date'2010-12-12'; set debug_sync="now SIGNAL do_insert"; connection con1; +ERROR 42000: UPDATE IGNORE in READ COMMITTED isolation mode of a table with a UNIQUE constraint WITHOUT OVERLAPS is not currently supported connection default; select * from t1; id s e @@ -199,7 +200,7 @@ set transaction isolation level read committed; update t1 set s=date'2010-10-10' where e=date'2010-12-12'; set debug_sync="now SIGNAL do_insert"; connection con1; -ERROR 42000: UPDATE IGNORE that modifies a primary key of a table with a UNIQUE constraint WITHOUT OVERLAPS is not currently supported +ERROR 42000: UPDATE IGNORE in READ COMMITTED isolation mode of a table with a UNIQUE constraint WITHOUT OVERLAPS is not currently supported connection default; select * from t1; id s e diff --git a/mysql-test/suite/period/t/innodb_debug.test b/mysql-test/suite/period/t/innodb_debug.test index 6ae92ab600f..46ff13cb5fb 100644 --- a/mysql-test/suite/period/t/innodb_debug.test +++ b/mysql-test/suite/period/t/innodb_debug.test @@ -125,6 +125,7 @@ set transaction isolation level read committed; update t1 set s=date'2010-10-10' where e=date'2010-12-12'; set debug_sync="now SIGNAL do_insert"; --connection con1 +--error ER_NOT_SUPPORTED_YET --reap --connection default select * from t1; diff --git a/sql/handler.cc b/sql/handler.cc index 393e4cc12d5..09f438bc204 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -7843,29 +7843,11 @@ int handler::ha_update_row(const uchar *old_data, const uchar *new_data) int e= 0; if (ha_thd()->lex->ignore) { - /* hack: modifying PK is not supported for now, see MDEV-37233 */ - if (table->s->primary_key != MAX_KEY) - { - KEY *key= table->key_info + table->s->primary_key; - KEY_PART_INFO *kp= key->key_part; - KEY_PART_INFO *end= kp + key->user_defined_key_parts; - for (; kp < end; kp++) - if (bitmap_is_set(table->write_set, kp->fieldnr-1)) - { - my_printf_error(ER_NOT_SUPPORTED_YET, "UPDATE IGNORE that " - "modifies a primary key of a table with a UNIQUE constraint " - "%s is not currently supported", MYF(0), - table->s->long_unique_table ? "USING HASH" : "WITHOUT OVERLAPS"); - return HA_ERR_UNSUPPORTED; - } - } - table->move_fields(table->field, table->record[1], table->record[0]); - std::swap(table->record[0], table->record[1]); - increment_statistics(&SSV::ha_update_count); - TABLE_IO_WAIT(tracker, PSI_TABLE_UPDATE_ROW, MAX_KEY, e, - { e= update_row(new_data, old_data);}) - table->move_fields(table->field, table->record[1], table->record[0]); - std::swap(table->record[0], table->record[1]); + my_printf_error(ER_NOT_SUPPORTED_YET, "UPDATE IGNORE in READ " + "COMMITTED isolation mode of a table with a UNIQUE constraint " + "%s is not currently supported", MYF(0), + table->s->long_unique_table ? "USING HASH" : "WITHOUT OVERLAPS"); + return HA_ERR_UNSUPPORTED; } return e ? e : error; } From a3c3db76930724f7e9a495a67633cfe8f91d0dc1 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 14 Jul 2025 16:38:24 +0200 Subject: [PATCH 156/172] update WolfSSL to 5.8.0-stable --- extra/wolfssl/wolfssl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/wolfssl/wolfssl b/extra/wolfssl/wolfssl index 239b85c8043..b077c81eb63 160000 --- a/extra/wolfssl/wolfssl +++ b/extra/wolfssl/wolfssl @@ -1 +1 @@ -Subproject commit 239b85c80438bf60d9a5b9e0ebe9ff097a760d0d +Subproject commit b077c81eb635392e694ccedbab8b644297ec0285 From 145afe7d7934ece196fdf47e71359af4856a6500 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 14 Jul 2025 21:58:59 +0200 Subject: [PATCH 157/172] Workaround WolfSSL issue #9004 to fix the build on Windows. --- extra/wolfssl/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extra/wolfssl/CMakeLists.txt b/extra/wolfssl/CMakeLists.txt index 38203a07911..f5b5c8bb5e8 100644 --- a/extra/wolfssl/CMakeLists.txt +++ b/extra/wolfssl/CMakeLists.txt @@ -134,6 +134,8 @@ if(MSVC) remove_definitions(-DHAVE_CONFIG_H) target_compile_definitions(wolfssl PRIVATE WOLFSSL_HAVE_MIN WOLFSSL_HAVE_MAX) + # Workaround https://github.com/wolfSSL/wolfssl/issues/9004 + target_compile_definitions(wolfssl PRIVATE WOLFSSL_NO_SOCK SOCKET_INVALID=-1) endif() CONFIGURE_FILE(user_settings.h.in user_settings.h) From a99dfa26d394647e0316881b0eac3faa3a6c6dee Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 14 Jul 2025 17:09:11 +0200 Subject: [PATCH 158/172] HeidiSQL 12.11 --- win/packaging/heidisql.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win/packaging/heidisql.cmake b/win/packaging/heidisql.cmake index 157e5517594..79755e63371 100644 --- a/win/packaging/heidisql.cmake +++ b/win/packaging/heidisql.cmake @@ -1,4 +1,4 @@ -SET(HEIDISQL_BASE_NAME "HeidiSQL_12.10_32_Portable") +SET(HEIDISQL_BASE_NAME "HeidiSQL_12.11_32_Portable") SET(HEIDISQL_ZIP "${HEIDISQL_BASE_NAME}.zip") SET(HEIDISQL_URL "https://www.heidisql.com/downloads/releases/${HEIDISQL_ZIP}") SET(HEIDISQL_DOWNLOAD_DIR ${THIRD_PARTY_DOWNLOAD_LOCATION}/${HEIDISQL_BASE_NAME}) From a0759bf017df167dca767e43649adf4b3d1321e7 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 16 Jul 2025 12:50:24 +0200 Subject: [PATCH 159/172] Connector/C 3.3.17 --- libmariadb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmariadb b/libmariadb index 55abb320382..77bdf5a5725 160000 --- a/libmariadb +++ b/libmariadb @@ -1 +1 @@ -Subproject commit 55abb3203826a7b3593f0728d6d077d4e0f19259 +Subproject commit 77bdf5a5725ec13c9067723ee2d3e1c5787e8c71 From b0a2b921cc7af1ca64492864317b0ea42c717e9a Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 14 Jul 2025 17:13:35 +0200 Subject: [PATCH 160/172] ColumnStore 6.4.11-1 --- storage/columnstore/columnstore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/columnstore/columnstore b/storage/columnstore/columnstore index ef0647b74ac..5ba808d542e 160000 --- a/storage/columnstore/columnstore +++ b/storage/columnstore/columnstore @@ -1 +1 @@ -Subproject commit ef0647b74ac41263cfdc25d3d4b5169c9e8df7ec +Subproject commit 5ba808d542e8552a4b3a868fce9e119623f366d7 From 17358074486eeefa95dc955b4fc21bbe1da407d9 Mon Sep 17 00:00:00 2001 From: Justin Jose Date: Thu, 27 Feb 2025 08:44:14 +0530 Subject: [PATCH 161/172] Bug#37117875 Binlog record error when delimiter is set to other symbols Description: ------------ When the delimiter is set to a non-default symbol and the SQL statement contains an unquoted semicolon (;) within a MySQL-specific comment, the SQL executes successfully in the source database. However, the binlog record becomes incomplete, leading to a syntax error in the replica database. Analysis: ------------ When the delimiter is set to a non-default symbol and an SQL statement contains an unquoted semicolon within a MySQL-specific comment, the client transmits the entire SQL statement, including the MySQL-specific comment, up to the delimiter to the server. During parsing, the server interprets the semicolon as the end of the command while processing the comment, resulting in the execution of a partial statement. The truncated statement is then recorded in the binary log and propagated to the replica, leading to an error. Fix: ------------ When the delimiter is set to a non-default symbol, treat MySQL-specific comments containing unquoted semicolons as syntax errors and return a parser error. Change-Id: I00d6b4ced89e79a7350c94218bf2527553054aed --- sql/sql_lex.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 7923c137b77..3741184d8cb 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2019, Oracle and/or its affiliates. - Copyright (c) 2009, 2022, MariaDB Corporation. +/* Copyright (c) 2000, 2025, Oracle and/or its affiliates. + Copyright (c) 2009, 2025, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2564,6 +2564,8 @@ int Lex_input_stream::lex_one_token(YYSTYPE *yylval, THD *thd) state=MY_LEX_CHAR; break; case MY_LEX_END: + /* Unclosed special comments result in a syntax error */ + if (in_comment == DISCARD_COMMENT) return (ABORT_SYM); next_state= MY_LEX_END; return(0); // We found end of input last time From 5fa5ee3edb219e9a9db55f2667f8fda954b82084 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 24 Jul 2025 15:46:45 +0200 Subject: [PATCH 162/172] Bug#37117875 test case --- .../suite/rpl/r/rpl_conditional_comments.result | 14 ++++++++++++++ .../suite/rpl/t/rpl_conditional_comments.test | 12 ++++++++++++ 2 files changed, 26 insertions(+) diff --git a/mysql-test/suite/rpl/r/rpl_conditional_comments.result b/mysql-test/suite/rpl/r/rpl_conditional_comments.result index 036824d60aa..8bfccb9c6a8 100644 --- a/mysql-test/suite/rpl/r/rpl_conditional_comments.result +++ b/mysql-test/suite/rpl/r/rpl_conditional_comments.result @@ -88,5 +88,19 @@ c1 3 20 connection master; +insert t1 values /*! (100);insert t1 values */ (200) // +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'insert t1 values */ (200)' at line 1 +select * from t1; +c1 +62 +3 +20 +connection slave; +select * from t1; +c1 +62 +3 +20 +connection master; DROP TABLE t1; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_conditional_comments.test b/mysql-test/suite/rpl/t/rpl_conditional_comments.test index 6e4ec8745f4..343ea0d3d13 100644 --- a/mysql-test/suite/rpl/t/rpl_conditional_comments.test +++ b/mysql-test/suite/rpl/t/rpl_conditional_comments.test @@ -80,5 +80,17 @@ sync_slave_with_master; select * from t1; connection master; +# +# Bug#37117875 Binlog record error when delimiter is set to other symbols +# +delimiter //; +--error ER_PARSE_ERROR +insert t1 values /*! (100);insert t1 values */ (200) // +delimiter ;// +select * from t1; +sync_slave_with_master; +select * from t1; +connection master; + DROP TABLE t1; --source include/rpl_end.inc From 29775c03c147ae72b0a61378d3da729dbad346a2 Mon Sep 17 00:00:00 2001 From: Ayush Gupta Date: Tue, 20 May 2025 06:53:03 +0200 Subject: [PATCH 163/172] Bug#34422267 - Contribution by Tencent: comment mistake in get_best_ror_intersect Description: The function get_best_ror_intersect is responsible for selecting the optimal combination of ROR scans that minimize cost while improving selectivity. It iteratively adds scans to a selected set (S), ensuring that each addition results in improved selectivity. If selectivity improves, the function then evaluates whether the cost is minimized. The comment contained some inaccuracies: - Incorrect Selectivity Condition: A missing parentheses caused the condition to be misinterpreted, leading to incorrect logic. The function intends to check whether adding a scan improves selectivity before including it in the set. - Loop Condition Issue: The condition for continuing the loop did not properly reduce R in the comment which meant it was an infinite loop. Fix: The comment of the function is fixed addressing the issues. The set should include the scan before comparing the selectivity with the initial set and thus the selectivity condition in the comment is fixed by properly enclosing the expression in parentheses to reflect the intended logic. Ensured that R is properly reduced in each iteration to maintain correctness. Change-Id: Ie197af8211a5ef05a5118a33b8b543d354475780 --- sql/opt_range.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 0a3d71abe93..3b0b0de1fad 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -7132,21 +7132,24 @@ static bool ror_intersect_add(ROR_INTERSECT_INFO *info, order R by (E(#records_matched) * key_record_length). S= first(R); -- set of scans that will be used for ROR-intersection - R= R-first(S); + R= R - S; min_cost= cost(S); min_scan= make_scan(S); while (R is not empty) { - firstR= R - first(R); - if (!selectivity(S + firstR < selectivity(S))) + firstR= first(R); + if (!selectivity(S + firstR) < selectivity(S)) + { + R= R - firstR; continue; - + } S= S + first(R); if (cost(S) < min_cost) { min_cost= cost(S); min_scan= make_scan(S); } + R= R - firstR; -- Remove the processed scan from R } return min_scan; } From f49a5beb30e832d3d3a987b12cc18ddd0f7c702f Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 25 Jul 2025 19:15:09 +0200 Subject: [PATCH 164/172] mariadb-backup: read --tables-file in the text mode on Windows --- extra/mariabackup/xtrabackup.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 60f81861a35..a65f8c2cf0b 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -4416,7 +4416,7 @@ xb_load_list_file( FILE* fp; /* read and store the filenames */ - fp = fopen(filename, "r"); + fp = fopen(filename, "rt"); if (!fp) { die("Can't open %s", filename); From 633417308f163141a822398fcf8e7f281bcda38b Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 26 Jul 2025 10:26:16 +0200 Subject: [PATCH 165/172] MDEV-37312 ASAN errors or assertion failure upon attempt to UPDATE FOR PORTION violating long unique under READ COMMITTED in case of a long unique conflict ha_write_row() used delete_row() to remove the newly inserted row, and it used rnd_pos() to position the cursor before deletion. This rnd_pos() was freeing and reallocating blobs in record[0]. So when the code for FOR PORTION OF did store_record(record[2]); ha_write_row() restore_record(record[2]); it ended up with blob pointers to a freed memory. Let's use lookup_handler for deletion. --- mysql-test/suite/period/r/long_unique.result | 17 ++++++++++++++++ mysql-test/suite/period/t/long_unique.test | 21 ++++++++++++++++++++ sql/handler.cc | 13 ++++++------ 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/mysql-test/suite/period/r/long_unique.result b/mysql-test/suite/period/r/long_unique.result index 5c5f4297fb9..fa7817fb562 100644 --- a/mysql-test/suite/period/r/long_unique.result +++ b/mysql-test/suite/period/r/long_unique.result @@ -15,3 +15,20 @@ INSERT INTO t1 VALUES (1,'foo','2022-01-01', '2025-01-01'); DELETE FROM t1 FOR PORTION OF app FROM '2023-01-01' TO '2024-01-01'; ERROR 23000: Duplicate entry 'foo' for key 'b' DROP TABLE t1; +# End of 10.5 tests +# +# MDEV-37312 ASAN errors or assertion failure upon attempt to UPDATE FOR PORTION violating long unique under READ COMMITTED +# +create table t1 (a int, f text unique, s datetime, e datetime, period for p(s,e)) engine=innodb; +insert into t1 values (1,'foo','1900-01-01','2000-01-01'),(2,'bar','1900-01-01','2000-01-01'); +set transaction isolation level read committed; +update t1 for portion of p from '1980-01-01' to '1980-01-02' set a = 1; +ERROR 23000: Duplicate entry 'foo' for key 'f' +drop table t1; +create table t1 (a int, f text unique, s datetime, e datetime, period for p(s,e)) engine=innodb partition by hash (a); +insert into t1 values (1,'foo','1900-01-01','2000-01-01'),(2,'bar','1900-01-01','2000-01-01'); +set transaction isolation level read committed; +update t1 for portion of p from '1980-01-01' to '1980-01-02' set a = 1; +ERROR 23000: Duplicate entry 'foo' for key 'f' +drop table t1; +# End of 10.6 tests diff --git a/mysql-test/suite/period/t/long_unique.test b/mysql-test/suite/period/t/long_unique.test index c2dcd3f6c3f..bca2f15ebae 100644 --- a/mysql-test/suite/period/t/long_unique.test +++ b/mysql-test/suite/period/t/long_unique.test @@ -1,3 +1,4 @@ +--source include/have_innodb.inc --source include/have_partition.inc --echo # @@ -21,3 +22,23 @@ INSERT INTO t1 VALUES (1,'foo','2022-01-01', '2025-01-01'); DELETE FROM t1 FOR PORTION OF app FROM '2023-01-01' TO '2024-01-01'; DROP TABLE t1; +--echo # End of 10.5 tests + +--echo # +--echo # MDEV-37312 ASAN errors or assertion failure upon attempt to UPDATE FOR PORTION violating long unique under READ COMMITTED +--echo # +create table t1 (a int, f text unique, s datetime, e datetime, period for p(s,e)) engine=innodb; +insert into t1 values (1,'foo','1900-01-01','2000-01-01'),(2,'bar','1900-01-01','2000-01-01'); +set transaction isolation level read committed; +--error ER_DUP_ENTRY +update t1 for portion of p from '1980-01-01' to '1980-01-02' set a = 1; +drop table t1; + +create table t1 (a int, f text unique, s datetime, e datetime, period for p(s,e)) engine=innodb partition by hash (a); +insert into t1 values (1,'foo','1900-01-01','2000-01-01'),(2,'bar','1900-01-01','2000-01-01'); +set transaction isolation level read committed; +--error ER_DUP_ENTRY +update t1 for portion of p from '1980-01-01' to '1980-01-02' set a = 1; +drop table t1; + +--echo # End of 10.6 tests diff --git a/sql/handler.cc b/sql/handler.cc index 09f438bc204..5d7138490fd 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3367,7 +3367,7 @@ int handler::create_lookup_handler() if (!(tmp= clone(table->s->normalized_path.str, table->in_use->mem_root))) return 1; lookup_handler= tmp; - return lookup_handler->ha_external_lock(table->in_use, F_RDLCK); + return lookup_handler->ha_external_lock(table->in_use, F_WRLCK); } LEX_CSTRING *handler::engine_name() @@ -7774,16 +7774,16 @@ int handler::ha_write_row(const uchar *buf) if (lookup_handler != this) // INSERT IGNORE or REPLACE or ODKU { int olderror= error; - if ((error= rnd_init(0))) + if ((error= lookup_handler->rnd_init(0))) goto err; position(buf); - if ((error= rnd_pos(lookup_buffer, ref))) + if ((error= lookup_handler->rnd_pos(lookup_buffer, ref))) goto err; increment_statistics(&SSV::ha_delete_count); TABLE_IO_WAIT(tracker, PSI_TABLE_DELETE_ROW, MAX_KEY, error, - { error= delete_row(buf);}) - rnd_end(); + { error= lookup_handler->delete_row(buf);}) + lookup_handler->rnd_end(); if (!error) error= olderror; } @@ -7916,8 +7916,7 @@ int handler::ha_delete_row(const uchar *buf) /* Normally table->record[0] is used, but sometimes table->record[1] is used. */ - DBUG_ASSERT(buf == table->record[0] || - buf == table->record[1]); + DBUG_ASSERT(buf == table->record[0] || buf == table->record[1]); MYSQL_DELETE_ROW_START(table_share->db.str, table_share->table_name.str); mark_trx_read_write(); From 03dd699ffefc5804276664f5b2b2fa87cec6c4db Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 27 Jul 2025 00:16:14 +0200 Subject: [PATCH 166/172] MDEV-37315 Assertion `!xid_state.xid_cache_element' failed in trans_xa_rollback trying to commit a "hanging" prepared XA transaction is currently not allowed within an another active XA transaction. it should equally be not allowed if a current XA transaction is in the rollback-only state. --- mysql-test/main/xa.result | 69 +++++++++++++++++++++++++++++++++++++++ mysql-test/main/xa.test | 69 +++++++++++++++++++++++++++++++++++++++ sql/xa.cc | 4 +-- 3 files changed, 140 insertions(+), 2 deletions(-) diff --git a/mysql-test/main/xa.result b/mysql-test/main/xa.result index cacd484707f..18ec4bf761b 100644 --- a/mysql-test/main/xa.result +++ b/mysql-test/main/xa.result @@ -616,4 +616,73 @@ select count(*) from t1; count(*) 1 drop table t1; +# +# MDEV-37315 Assertion `!xid_state.xid_cache_element' failed in trans_xa_rollback +# +create table t1 (a int) engine=innodb; +create table t2 (b int) engine=innodb; +create table t3 (c int) engine=innodb; +insert t1 values (1); +insert t2 values (2); +connect con1,localhost,root; +xa start 'r:foo'; +insert t3 values (3); +xa end 'r:foo'; +xa prepare 'r:foo'; +disconnect con1; +connection default; +xa recover; +formatID gtrid_length bqual_length data +1 5 0 r:foo +xa start 'r:bar'; +select * from t1 for update; +a +1 +connect con2,localhost,root; +xa start 'r:baz'; +update t2 set b=12; +update t1 set a=13; +connection default; +xa rollback 'r:foo'; +ERROR XAE09: XAER_OUTSIDE: Some work is done outside global transaction +select * from t2 for update; +Got one of the listed errors +xa rollback 'r:foo'; +ERROR XAE09: XAER_OUTSIDE: Some work is done outside global transaction +connection con2; +disconnect con2; +connection default; +xa rollback 'r:bar'; +xa rollback 'r:foo'; +connect con1,localhost,root; +xa start 'c:foo'; +insert t3 values (103); +xa end 'c:foo'; +xa prepare 'c:foo'; +disconnect con1; +connection default; +xa recover; +formatID gtrid_length bqual_length data +1 5 0 c:foo +xa start 'c:bar'; +select * from t1 for update; +a +1 +connect con2,localhost,root; +xa start 'c:baz'; +update t2 set b=102; +update t1 set a=103; +connection default; +xa commit 'c:foo'; +ERROR XAE09: XAER_OUTSIDE: Some work is done outside global transaction +select * from t2 for update; +Got one of the listed errors +xa commit 'c:foo'; +ERROR XAE09: XAER_OUTSIDE: Some work is done outside global transaction +connection con2; +disconnect con2; +connection default; +xa rollback 'c:bar'; +xa commit 'c:foo'; +drop table t1,t2,t3; # End of 10.11 tests diff --git a/mysql-test/main/xa.test b/mysql-test/main/xa.test index 12ff85476f8..104509b6cc6 100644 --- a/mysql-test/main/xa.test +++ b/mysql-test/main/xa.test @@ -765,4 +765,73 @@ xa commit 'a'; select count(*) from t1; drop table t1; +--echo # +--echo # MDEV-37315 Assertion `!xid_state.xid_cache_element' failed in trans_xa_rollback +--echo # +create table t1 (a int) engine=innodb; +create table t2 (b int) engine=innodb; +create table t3 (c int) engine=innodb; +insert t1 values (1); +insert t2 values (2); + +connect con1,localhost,root; +xa start 'r:foo'; +insert t3 values (3); +xa end 'r:foo'; +xa prepare 'r:foo'; +disconnect con1; +connection default; +xa recover; + +xa start 'r:bar'; +select * from t1 for update; +connect con2,localhost,root; +xa start 'r:baz'; +update t2 set b=12; +send update t1 set a=13; +connection default; +--error ER_XAER_OUTSIDE +xa rollback 'r:foo'; +--error ER_LOCK_DEADLOCK,ER_XAER_RMFAIL +select * from t2 for update; +--error ER_XAER_OUTSIDE +xa rollback 'r:foo'; +connection con2; +reap; +disconnect con2; +connection default; +xa rollback 'r:bar'; +xa rollback 'r:foo'; + +connect con1,localhost,root; +xa start 'c:foo'; +insert t3 values (103); +xa end 'c:foo'; +xa prepare 'c:foo'; +disconnect con1; +connection default; +xa recover; + +xa start 'c:bar'; +select * from t1 for update; +connect con2,localhost,root; +xa start 'c:baz'; +update t2 set b=102; +send update t1 set a=103; +connection default; +--error ER_XAER_OUTSIDE +xa commit 'c:foo'; +--error ER_LOCK_DEADLOCK,ER_XAER_RMFAIL +select * from t2 for update; +--error ER_XAER_OUTSIDE +xa commit 'c:foo'; +connection con2; +reap; +disconnect con2; +connection default; +xa rollback 'c:bar'; +xa commit 'c:foo'; + +drop table t1,t2,t3; + --echo # End of 10.11 tests diff --git a/sql/xa.cc b/sql/xa.cc index 5ab37451721..48cbf65c53a 100644 --- a/sql/xa.cc +++ b/sql/xa.cc @@ -625,7 +625,7 @@ bool trans_xa_commit(THD *thd) if (!xid_state.is_explicit_XA() || !xid_state.xid_cache_element->xid.eq(thd->lex->xid)) { - if (thd->in_multi_stmt_transaction_mode()) + if (thd->in_multi_stmt_transaction_mode() || xid_state.xid_cache_element) { /* Not allow to commit from inside an not-"native" to xid @@ -799,7 +799,7 @@ bool trans_xa_rollback(THD *thd) if (!xid_state.is_explicit_XA() || !xid_state.xid_cache_element->xid.eq(thd->lex->xid)) { - if (thd->in_multi_stmt_transaction_mode()) + if (thd->in_multi_stmt_transaction_mode() || xid_state.xid_cache_element) { my_error(ER_XAER_OUTSIDE, MYF(0)); DBUG_RETURN(TRUE); From 57dd23dad82d69639a589b8e1c7115823915401c Mon Sep 17 00:00:00 2001 From: drrtuy Date: Wed, 16 Jul 2025 14:08:11 +0000 Subject: [PATCH 167/172] New getter to read Engine Independent JSON histogram buckets directly This would allow Columnstore to leverage EI data in its cost-based and rewrite optimizer parts --- sql/opt_histogram_json.h | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/sql/opt_histogram_json.h b/sql/opt_histogram_json.h index 248467928fd..a3e21a08aa7 100644 --- a/sql/opt_histogram_json.h +++ b/sql/opt_histogram_json.h @@ -16,6 +16,20 @@ #include "sql_statistics.h" +struct Histogram_bucket +{ + // The left endpoint in KeyTupleFormat. The endpoint is inclusive, this + // value is in this bucket. + std::string start_value; + + // Cumulative fraction: The fraction of table rows that fall into this + // and preceding buckets. + double cum_fract; + + // Number of distinct values in the bucket. + longlong ndv; +}; + /* An equi-height histogram which stores real values for bucket bounds. @@ -71,21 +85,7 @@ class Histogram_json_hb final : public Histogram_base /* Collection-time only: collected histogram in the JSON form. */ std::string json_text; - struct Bucket - { - // The left endpoint in KeyTupleFormat. The endpoint is inclusive, this - // value is in this bucket. - std::string start_value; - - // Cumulative fraction: The fraction of table rows that fall into this - // and preceding buckets. - double cum_fract; - - // Number of distinct values in the bucket. - longlong ndv; - }; - - std::vector buckets; + std::vector buckets; std::string last_bucket_end_endp; @@ -129,6 +129,16 @@ public: double range_selectivity(Field *field, key_range *min_endp, key_range *max_endp, double avg_sel) override; + const std::vector& get_json_histogram() const + { + return buckets; + } + + const std::string& get_last_bucket_end_endp() const + { + return last_bucket_end_endp; + } + void set_json_text(ulonglong sz, const char *json_text_arg, size_t json_text_len) { From 2b89bf7b1ad9ec9e0225e89f27caf9960253e9c1 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 23 Jul 2025 17:40:10 +0200 Subject: [PATCH 168/172] make main.desc_index_min_max more stable InnoDB row format estimations are approximate, cannot be part of the result file --- mysql-test/main/desc_index_min_max.result | 6 ++---- mysql-test/main/desc_index_min_max.test | 7 +++---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/mysql-test/main/desc_index_min_max.result b/mysql-test/main/desc_index_min_max.result index 5698ddbe3f6..3b6e59cc7fd 100644 --- a/mysql-test/main/desc_index_min_max.result +++ b/mysql-test/main/desc_index_min_max.result @@ -113,13 +113,13 @@ min(a) 2 explain select max(200 - a) from t1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL a 5 NULL 100 Using index +1 SIMPLE t1 index NULL a 5 NULL # Using index select max(200 - a) from t1; max(200 - a) 198 explain select min(200 - a) from t1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL a 5 NULL 100 Using index +1 SIMPLE t1 index NULL a 5 NULL # Using index select min(200 - a) from t1; min(200 - a) 0 @@ -174,6 +174,4 @@ SELECT MAX(a) FROM t1 WHERE a <= 0.6789; MAX(a) 0.6789 drop table t1; -# # end of test 11.4 -# diff --git a/mysql-test/main/desc_index_min_max.test b/mysql-test/main/desc_index_min_max.test index 7df261cd749..99128e1584e 100644 --- a/mysql-test/main/desc_index_min_max.test +++ b/mysql-test/main/desc_index_min_max.test @@ -102,13 +102,13 @@ eval $query; # double reversion let $query= select max(200 - a) from t1; -replace_result 101 100; +replace_column 9 #; eval explain $query; eval $query; let $query= select min(200 - a) from t1; -replace_result 101 100; +replace_column 9 #; eval explain $query; eval $query; @@ -162,6 +162,5 @@ eval $query; # Cleanup drop table t1; ---echo # + --echo # end of test 11.4 ---echo # From 0ef4b1ab7fdbd1b57422053eb2fcc898abd14187 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 22 Jul 2025 23:08:29 +0200 Subject: [PATCH 169/172] Connector/C 3.4.7 --- libmariadb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmariadb b/libmariadb index b5a2c9f3c27..b790c6c149c 160000 --- a/libmariadb +++ b/libmariadb @@ -1 +1 @@ -Subproject commit b5a2c9f3c275861447ca21ee1f01560135ec6c2f +Subproject commit b790c6c149c9119fb73c416e993af1c7ef256b34 From ca91bf5d2a2f2ea884fe7e32ee87608e0f413e5d Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 17 Jul 2025 17:23:56 +0200 Subject: [PATCH 170/172] Update ColumnStore 23.10.5-1 --- storage/columnstore/columnstore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/columnstore/columnstore b/storage/columnstore/columnstore index 9763b126517..f33e9ce86c7 160000 --- a/storage/columnstore/columnstore +++ b/storage/columnstore/columnstore @@ -1 +1 @@ -Subproject commit 9763b126517c8efb716e767fd5ba4eb2b5b405fc +Subproject commit f33e9ce86c73f606dbef2d50cac8b92e393344ef From fe8047caf26d20e98ea7f6ec1dce3924e696703f Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 28 Jul 2025 15:45:51 +0200 Subject: [PATCH 171/172] MDEV-37320 ASAN errors in Field::is_null / Item_param::assign_default don't construct a "default value field" by moving field's ptr/null_ptr. Field can have its null_ptr moved to extra_null_bitmap for BEFORE triggers. Perhaps there can be other reasons for null_ptr and ptr not to be at the right offset to each other. Instead, use pointers from TABLE_SHARE::field, which always point to default values. Except when there's no TABLE_SHARE::field, which can happen for TEMPTABLE views, for example, but these views are not updatable anyway. Add an assert to Field::move_field_offset() to ensure it's only used for appropriately set ptr/null_ptr pairs. --- mysql-test/main/default.result | 14 +++++++++----- mysql-test/main/default.test | 17 ++++++++++++----- sql/field.h | 7 +++++++ sql/item.cc | 9 ++++++++- 4 files changed, 36 insertions(+), 11 deletions(-) diff --git a/mysql-test/main/default.result b/mysql-test/main/default.result index 335f7e7d607..29a05e3ad88 100644 --- a/mysql-test/main/default.result +++ b/mysql-test/main/default.result @@ -3432,10 +3432,8 @@ DEFAULT(a) CASE a WHEN 0 THEN 1 ELSE 2 END NULL 2 DROP TABLE t; DROP VIEW v; -# # End of 10.2 test # -# # MDEV-22703 DEFAULT() on a BLOB column can overwrite the default # record, which can cause crashes when accessing already released # memory. @@ -3450,10 +3448,8 @@ length(DEFAULT(h)) 25 INSERT INTO t1 () VALUES (); drop table t1; -# # End of 10.3 test # -# # MDEV-26423: MariaDB server crash in Create_tmp_table::finalize # CREATE TABLE t1 (pk text DEFAULT length(uuid())); @@ -3483,6 +3479,14 @@ column_name column_default has_default is_nullable a NULL 1 YES drop view v1; drop table t1; -# # End of 10.4 test # +# MDEV-37320 ASAN errors in Field::is_null / Item_param::assign_default +# +create table t1 (f01 timestamp, f03 timestamp); +insert into t1 () values (); +create trigger tr before insert on t1 for each row set @a=1; +prepare stmt from "update t1 set f03 = ?"; +execute stmt using default; +drop table t1; +# End of 10.6 test diff --git a/mysql-test/main/default.test b/mysql-test/main/default.test index 13f611246c9..5b37f7047fa 100644 --- a/mysql-test/main/default.test +++ b/mysql-test/main/default.test @@ -2137,9 +2137,8 @@ CREATE ALGORITHM=TEMPTABLE VIEW v AS SELECT * FROM t; SELECT DISTINCT DEFAULT(a), CASE a WHEN 0 THEN 1 ELSE 2 END FROM v GROUP BY a WITH ROLLUP; DROP TABLE t; DROP VIEW v; ---echo # + --echo # End of 10.2 test ---echo # --echo # --echo # MDEV-22703 DEFAULT() on a BLOB column can overwrite the default @@ -2157,9 +2156,7 @@ SELECT length(DEFAULT(h)) FROM t1; INSERT INTO t1 () VALUES (); drop table t1; ---echo # --echo # End of 10.3 test ---echo # --echo # --echo # MDEV-26423: MariaDB server crash in Create_tmp_table::finalize @@ -2183,6 +2180,16 @@ select column_name, column_default, column_default is not null as 'has_default', drop view v1; drop table t1; ---echo # --echo # End of 10.4 test + --echo # +--echo # MDEV-37320 ASAN errors in Field::is_null / Item_param::assign_default +--echo # +create table t1 (f01 timestamp, f03 timestamp); +insert into t1 () values (); +create trigger tr before insert on t1 for each row set @a=1; +prepare stmt from "update t1 set f03 = ?"; +execute stmt using default; +drop table t1; + +--echo # End of 10.6 test diff --git a/sql/field.h b/sql/field.h index 59dcd229b52..d68e72c0925 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1537,7 +1537,14 @@ public: { ptr=ADD_TO_PTR(ptr,ptr_diff, uchar*); if (null_ptr) + { null_ptr=ADD_TO_PTR(null_ptr,ptr_diff,uchar*); + if (table) + { + DBUG_ASSERT(null_ptr < ptr); + DBUG_ASSERT(ptr - null_ptr <= (int)table->s->rec_buff_length); + } + } } void get_image(uchar *buff, uint length, CHARSET_INFO *cs) const { get_image(buff, length, ptr, cs); } diff --git a/sql/item.cc b/sql/item.cc index 4a47b268f52..051c13adc3b 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5231,10 +5231,17 @@ static Field *make_default_field(THD *thd, Field *field_arg) def_field->default_value->expr->update_used_tables(); def_field->move_field(newptr + 1, def_field->maybe_null() ? newptr : 0, 1); } - else + else if (field_arg->table && field_arg->table->s->field) + { + Field *def_val= field_arg->table->s->field[field_arg->field_index]; + def_field->move_field(def_val->ptr, def_val->null_ptr, def_val->null_bit); + } + else /* e.g. non-updatable view */ + { def_field->move_field_offset((my_ptrdiff_t) (def_field->table->s->default_values - def_field->table->record[0])); + } return def_field; } From cbcb080a1fdb94dba0cdaa7ae0441cde286ccab4 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 28 Jul 2025 16:44:59 +0200 Subject: [PATCH 172/172] MDEV-37328 Assertion failure in make_empty_rec upon CONVERT PARTITION ALTER TABLE ... CONVERT invokes build_frm_image() three times on the same data structures. The latter should not increment create_info->null_bits on every invocation. --- mysql-test/suite/parts/r/alter_table.result | 11 +++++++++++ mysql-test/suite/parts/t/alter_table.test | 12 ++++++++++++ sql/unireg.cc | 5 ++--- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/parts/r/alter_table.result b/mysql-test/suite/parts/r/alter_table.result index 82d200e1dca..784d1dee53a 100644 --- a/mysql-test/suite/parts/r/alter_table.result +++ b/mysql-test/suite/parts/r/alter_table.result @@ -383,4 +383,15 @@ disconnect con1; connection default; drop user u@localhost; drop database db; +# +# MDEV-37328 Assertion failure in make_empty_rec upon CONVERT PARTITION +# +create table t (f1 int, f2 int, f3 int, f4 int, f5 int, f6 int, f7 int) engine=myisam +partition by list (f3) ( +partition p0 values in (null,0), +partition p1 values in (1,2,3), +partition p2 default +); +alter table t convert partition p0 to table tp; +drop table if exists tp, t; # End of 10.11 tests diff --git a/mysql-test/suite/parts/t/alter_table.test b/mysql-test/suite/parts/t/alter_table.test index 810d5cd2cd6..c5f4bb48a64 100644 --- a/mysql-test/suite/parts/t/alter_table.test +++ b/mysql-test/suite/parts/t/alter_table.test @@ -347,4 +347,16 @@ alter table t1 convert table tp to partition p2 values less than (1000); drop user u@localhost; drop database db; +--echo # +--echo # MDEV-37328 Assertion failure in make_empty_rec upon CONVERT PARTITION +--echo # +create table t (f1 int, f2 int, f3 int, f4 int, f5 int, f6 int, f7 int) engine=myisam + partition by list (f3) ( + partition p0 values in (null,0), + partition p1 values in (1,2,3), + partition p2 default +); +alter table t convert partition p0 to table tp; +drop table if exists tp, t; + --echo # End of 10.11 tests diff --git a/sql/unireg.cc b/sql/unireg.cc index e2cf96f3b9a..28a7deb4da3 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -288,9 +288,8 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table, DBUG_ENTER("build_frm_image"); /* If fixed row records, we need one bit to check for deleted rows */ - if (!(create_info->table_options & HA_OPTION_PACK_RECORD)) - create_info->null_bits++; - data_offset= (create_info->null_bits + 7) / 8; + bool need_deleted_bit= !(create_info->table_options & HA_OPTION_PACK_RECORD); + data_offset= (create_info->null_bits + need_deleted_bit + 7) / 8; error= pack_vcols(thd, &vcols, create_fields, create_info->check_constraint_list);