diff --git a/include/my_base.h b/include/my_base.h index 1d59262f680..44889c4ca96 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -49,6 +49,7 @@ #define HA_OPEN_MERGE_TABLE 2048U #define HA_OPEN_FOR_CREATE 4096U #define HA_OPEN_FOR_DROP (1U << 13) /* Open part of drop */ +#define HA_OPEN_GLOBAL_TMP_TABLE (1U << 14) /* TMP table used by repliction */ /* Allow opening even if table is incompatible as this is for ALTER TABLE which @@ -369,6 +370,12 @@ enum ha_base_keytype { #define HA_CREATE_INTERNAL_TABLE 256U #define HA_PRESERVE_INSERT_ORDER 512U #define HA_CREATE_NO_ROLLBACK 1024U +/* + A temporary table that can be used by different threads, eg. replication + threads. This flag ensure that memory is not allocated with THREAD_SPECIFIC, + as we do for other temporary tables. +*/ +#define HA_CREATE_GLOBAL_TMP_TABLE 2048U /* Flags used by start_bulk_insert */ diff --git a/mysql-test/main/ctype_collate.result b/mysql-test/main/ctype_collate.result index eafe7ff3d7b..7b713df799e 100644 --- a/mysql-test/main/ctype_collate.result +++ b/mysql-test/main/ctype_collate.result @@ -780,3 +780,27 @@ string # # End of 10.2 tests # +# +# MDEV-33318 ORDER BY COLLATE improperly applied to non-character columns +# +set names utf8; +create table t1 (ts datetime); +insert t1 values ('2024-01-26 21:37:54'), ('2024-01-26 21:37:54'), +('2024-01-26 21:37:54'), ('2024-01-26 21:37:54'), +('2024-01-26 21:37:58'), ('2024-01-26 21:37:58'), +('2024-01-26 21:37:58'), ('2024-01-26 21:38:02'), +('2024-01-26 21:38:02'), ('2024-01-26 21:38:02'); +select * from t1 order by ts collate utf8_bin; +ts +2024-01-26 21:37:54 +2024-01-26 21:37:54 +2024-01-26 21:37:54 +2024-01-26 21:37:54 +2024-01-26 21:37:58 +2024-01-26 21:37:58 +2024-01-26 21:37:58 +2024-01-26 21:38:02 +2024-01-26 21:38:02 +2024-01-26 21:38:02 +drop table t1; +# End of 10.6 tests diff --git a/mysql-test/main/ctype_collate.test b/mysql-test/main/ctype_collate.test index 2366b130e7c..96ad216dd20 100644 --- a/mysql-test/main/ctype_collate.test +++ b/mysql-test/main/ctype_collate.test @@ -357,3 +357,18 @@ SELECT COLUMN_GET(COLUMN_CREATE(0, 'string'),0 AS CHAR CHARACTER SET latin1 COLL --echo # --echo # End of 10.2 tests --echo # + +--echo # +--echo # MDEV-33318 ORDER BY COLLATE improperly applied to non-character columns +--echo # +set names utf8; +create table t1 (ts datetime); +insert t1 values ('2024-01-26 21:37:54'), ('2024-01-26 21:37:54'), + ('2024-01-26 21:37:54'), ('2024-01-26 21:37:54'), + ('2024-01-26 21:37:58'), ('2024-01-26 21:37:58'), + ('2024-01-26 21:37:58'), ('2024-01-26 21:38:02'), + ('2024-01-26 21:38:02'), ('2024-01-26 21:38:02'); +select * from t1 order by ts collate utf8_bin; +drop table t1; + +--echo # End of 10.6 tests diff --git a/mysql-test/main/func_json.result b/mysql-test/main/func_json.result index ead4aa3eafa..31b74981e1b 100644 --- a/mysql-test/main/func_json.result +++ b/mysql-test/main/func_json.result @@ -272,7 +272,7 @@ create table t1 as select json_object('id', 87, 'name', 'carrot') as f; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `f` varchar(32) DEFAULT NULL + `f` varchar(46) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci select * from t1; f diff --git a/mysql-test/main/func_json.test b/mysql-test/main/func_json.test index b3659f64307..0d9f2518575 100644 --- a/mysql-test/main/func_json.test +++ b/mysql-test/main/func_json.test @@ -87,15 +87,12 @@ select json_extract('[10, 20, [30, 40], 1, 10]', '$[1]') as exp; select json_extract('[10, 20, [30, 40], 1, 10]', '$[1]', '$[25]') as exp; select json_extract( '[{"a": [3, 4]}, {"b": 2}]', '$[0].a', '$[1].a') as exp; -#enable after MDEV-32454 fix ---disable_view_protocol select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.b.k1', 'word') as exp; select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.d[3]', 3) as exp; select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.a[2]', 2) as exp; select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.b.c', 'word') as exp; select json_set('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.c', '[true, false]') as exp; ---enable_view_protocol select json_replace('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.c', '[true, false]') as exp; select json_replace('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.b', '[true, false]') as exp; @@ -137,14 +134,11 @@ select json_merge('a','b'); select json_merge('{"a":"b"}','{"c":"d"}'); SELECT JSON_MERGE('[1, 2]', '{"id": 47}'); -#enable after MDEV-32454 fix ---disable_view_protocol select json_type('{"k1":123, "k2":345}'); select json_type('[123, "k2", 345]'); select json_type("true"); select json_type('123'); select json_type('123.12'); ---enable_view_protocol select json_keys('{"a":{"c":1, "d":2}, "b":2}'); select json_keys('{"a":{"c":1, "d":2}, "b":2}', "$.a"); @@ -173,11 +167,8 @@ select json_search( json_col, 'all', 'foot' ) as ex from t1; drop table t1; -#enable after MDEV-32454 fix ---disable_view_protocol select json_unquote('"abc"'); select json_unquote('abc'); ---enable_view_protocol # # MDEV-13703 Illegal mix of collations for operation 'json_object' on using JSON_UNQUOTE as an argument. # @@ -188,13 +179,9 @@ select json_object('foo', json_unquote(json_object('bar', c)),'qux', c) as fld f drop table t1; -#enable after MDEV-32454 fix ---disable_view_protocol select json_object("a", json_object("b", "abcd")); select json_object("a", '{"b": "abcd"}'); select json_object("a", json_compact('{"b": "abcd"}')); ---enable_view_protocol - select json_compact(NULL); select json_depth(json_compact(NULL)); @@ -270,11 +257,8 @@ select json_merge('{"a":{"u":12, "x":"b"}}', '{"a":{"x":"c"}}') as ex ; select json_merge('{"a":{"u":12, "x":"b", "r":1}}', '{"a":{"x":"c", "r":2}}') as ex ; select json_compact('{"a":1, "b":[1,2,3], "c":{"aa":"v1", "bb": "v2"}}') as ex; -#enable after MDEV-32454 fix ---disable_view_protocol select json_loose('{"a":1, "b":[1,2,3], "c":{"aa":"v1", "bb": "v2"}}') as ex; select json_detailed('{"a":1, "b":[1,2,3], "c":{"aa":"v1", "bb": "v2"}}') as ex; ---enable_view_protocol # # MDEV-11856 json_search doesn't search for values with double quotes character (") @@ -469,12 +453,9 @@ drop table t1; --echo # MDEV-16750 JSON_SET mishandles unicode every second pair of arguments. --echo # -#enable after MDEV-32454 fix ---disable_view_protocol SELECT JSON_SET('{}', '$.a', _utf8 0xC3B6) as exp; SELECT JSON_SET('{}', '$.a', _utf8 0xC3B6, '$.b', _utf8 0xC3B6) as exp; SELECT JSON_SET('{}', '$.a', _utf8 X'C3B6', '$.x', 1, '$.b', _utf8 X'C3B6') as exp; ---enable_view_protocol --echo # --echo # MDEV-17121 JSON_ARRAY_APPEND diff --git a/mysql-test/main/func_regexp.result b/mysql-test/main/func_regexp.result index b883c8188df..e0a4702c095 100644 --- a/mysql-test/main/func_regexp.result +++ b/mysql-test/main/func_regexp.result @@ -110,7 +110,7 @@ R2 R3 deallocate prepare stmt1; drop table t1; -End of 4.1 tests +# End of 4.1 tests SELECT 1 REGEXP NULL; 1 REGEXP NULL NULL @@ -126,7 +126,7 @@ NULL SELECT "ABC" REGEXP BINARY NULL; "ABC" REGEXP BINARY NULL NULL -End of 5.0 tests +# End of 5.0 tests CREATE TABLE t1(a INT, b CHAR(4)); INSERT INTO t1 VALUES (1, '6.1'), (1, '7.0'), (1, '8.0'); PREPARE stmt1 FROM "SELECT a FROM t1 WHERE a=1 AND '7.0' REGEXP b LIMIT 1"; @@ -144,7 +144,7 @@ a 1 DEALLOCATE PREPARE stmt1; DROP TABLE t1; -End of 5.1 tests +# End of 5.1 tests SELECT ' ' REGEXP '[[:blank:]]'; ' ' REGEXP '[[:blank:]]' 1 @@ -163,3 +163,19 @@ SELECT '\t' REGEXP '[[:space:]]'; SELECT REGEXP_INSTR('111222333',2); REGEXP_INSTR('111222333',2) 4 +# End of 10.3 tests +# +# MDEV-33344 REGEXP empty string inconsistent +# +create table t1 (x char(5)); +insert t1 values (''), ('x'); +select 'foo' regexp x from t1 order by x asc; +'foo' regexp x +1 +0 +select 'foo' regexp x from t1 order by x desc; +'foo' regexp x +0 +1 +drop table t1; +# End of 10.5 tests diff --git a/mysql-test/main/func_regexp.test b/mysql-test/main/func_regexp.test index 6d5186269a5..b9e2ef197d6 100644 --- a/mysql-test/main/func_regexp.test +++ b/mysql-test/main/func_regexp.test @@ -55,7 +55,7 @@ execute stmt1 using @a; deallocate prepare stmt1; drop table t1; ---echo End of 4.1 tests +--echo # End of 4.1 tests # @@ -74,7 +74,7 @@ SELECT NULL REGEXP BINARY NULL; SELECT 'A' REGEXP BINARY NULL; SELECT "ABC" REGEXP BINARY NULL; ---echo End of 5.0 tests +--echo # End of 5.0 tests # @@ -91,7 +91,7 @@ DEALLOCATE PREPARE stmt1; DROP TABLE t1; ---echo End of 5.1 tests +--echo # End of 5.1 tests # # MDEV-5820 MySQL Bug #54805 definitions in regex/my_regex.h conflict with /usr/include/regex.h @@ -110,3 +110,15 @@ SELECT '\t' REGEXP '[[:space:]]'; --echo # SELECT REGEXP_INSTR('111222333',2); +--echo # End of 10.3 tests + +--echo # +--echo # MDEV-33344 REGEXP empty string inconsistent +--echo # +create table t1 (x char(5)); +insert t1 values (''), ('x'); +select 'foo' regexp x from t1 order by x asc; +select 'foo' regexp x from t1 order by x desc; +drop table t1; + +--echo # End of 10.5 tests diff --git a/mysql-test/main/ps.result b/mysql-test/main/ps.result index 2100d63e294..e437b63761b 100644 --- a/mysql-test/main/ps.result +++ b/mysql-test/main/ps.result @@ -5930,5 +5930,55 @@ a b 2 30 DROP TABLE t1, t2; # +# MDEV-33549: Incorrect handling of UPDATE in PS mode in case a table's colum declared as NOT NULL +# +CREATE TABLE t1 (a INT, b INT DEFAULT NULL); +INSERT INTO t1 VALUES (20, 30); +EXECUTE IMMEDIATE 'UPDATE t1 SET b=?' USING DEFAULT; +SELECT * FROM t1; +a b +20 NULL +# Run twice the same update in PS mode to check +# that no memory relating issues taken place. +PREPARE stmt FROM 'UPDATE t1 SET b=?'; +EXECUTE stmt USING DEFAULT; +EXECUTE stmt USING DEFAULT; +# Clean up +DEALLOCATE PREPARE stmt; +DROP TABLE t1; +# The same test for multi-table update +CREATE TABLE t1 (a INT, b INT DEFAULT NULL); +CREATE TABLE t2 (a INT, c INT DEFAULT NULL); +INSERT INTO t1 VALUES (20, 30); +INSERT INTO t2 VALUES (20, 30); +EXECUTE IMMEDIATE 'UPDATE t1,t2 SET b=? WHERE t1.a=t2.a' USING DEFAULT; +SELECT * FROM t1; +a b +20 NULL +# Run twice the same multi-table update in PS mode to check +# that no memory relating issues taken place. +PREPARE stmt FROM 'UPDATE t1,t2 SET b=? WHERE t1.a=t2.a'; +EXECUTE stmt USING DEFAULT; +EXECUTE stmt USING DEFAULT; +DEALLOCATE PREPARE stmt; +# Clean up +DROP TABLE t1; +# This time checks that a default value for table's column +# represented by a function call is handled correctly on UPDATE in PS mode +CREATE TABLE t1 (a INT, b INT DEFAULT MOD(a, 3)); +INSERT INTO t1 VALUES (20, 30); +EXECUTE IMMEDIATE 'UPDATE t1, t2 SET b=? WHERE t1.a=t2.a' USING DEFAULT; +SELECT * FROM t1; +a b +20 2 +# Run twice the same multi-table update in PS mode to check +# that no memory relating issues taken place. +PREPARE stmt FROM 'UPDATE t1, t2 SET b=? WHERE t1.a=t2.a'; +EXECUTE stmt USING DEFAULT; +EXECUTE stmt USING DEFAULT; +# Clean up +DEALLOCATE PREPARE stmt; +DROP TABLE t1, t2; +# # End of 10.4 tests # diff --git a/mysql-test/main/ps.test b/mysql-test/main/ps.test index 30df8dcec32..a360d0efd0f 100644 --- a/mysql-test/main/ps.test +++ b/mysql-test/main/ps.test @@ -5367,6 +5367,60 @@ SELECT * FROM t2; # Cleanup DROP TABLE t1, t2; +--echo # +--echo # MDEV-33549: Incorrect handling of UPDATE in PS mode in case a table's colum declared as NOT NULL +--echo # + +CREATE TABLE t1 (a INT, b INT DEFAULT NULL); +INSERT INTO t1 VALUES (20, 30); +EXECUTE IMMEDIATE 'UPDATE t1 SET b=?' USING DEFAULT; +SELECT * FROM t1; + +--echo # Run twice the same update in PS mode to check +--echo # that no memory relating issues taken place. +PREPARE stmt FROM 'UPDATE t1 SET b=?'; +EXECUTE stmt USING DEFAULT; +EXECUTE stmt USING DEFAULT; + +--echo # Clean up +DEALLOCATE PREPARE stmt; +DROP TABLE t1; + +--echo # The same test for multi-table update +CREATE TABLE t1 (a INT, b INT DEFAULT NULL); +CREATE TABLE t2 (a INT, c INT DEFAULT NULL); + +INSERT INTO t1 VALUES (20, 30); +INSERT INTO t2 VALUES (20, 30); + +EXECUTE IMMEDIATE 'UPDATE t1,t2 SET b=? WHERE t1.a=t2.a' USING DEFAULT; +SELECT * FROM t1; +--echo # Run twice the same multi-table update in PS mode to check +--echo # that no memory relating issues taken place. +PREPARE stmt FROM 'UPDATE t1,t2 SET b=? WHERE t1.a=t2.a'; +EXECUTE stmt USING DEFAULT; +EXECUTE stmt USING DEFAULT; +DEALLOCATE PREPARE stmt; +--echo # Clean up +DROP TABLE t1; + +--echo # This time checks that a default value for table's column +--echo # represented by a function call is handled correctly on UPDATE in PS mode +CREATE TABLE t1 (a INT, b INT DEFAULT MOD(a, 3)); +INSERT INTO t1 VALUES (20, 30); +EXECUTE IMMEDIATE 'UPDATE t1, t2 SET b=? WHERE t1.a=t2.a' USING DEFAULT; +SELECT * FROM t1; + +--echo # Run twice the same multi-table update in PS mode to check +--echo # that no memory relating issues taken place. +PREPARE stmt FROM 'UPDATE t1, t2 SET b=? WHERE t1.a=t2.a'; +EXECUTE stmt USING DEFAULT; +EXECUTE stmt USING DEFAULT; + +--echo # Clean up +DEALLOCATE PREPARE stmt; +DROP TABLE t1, t2; + --echo # --echo # End of 10.4 tests --echo # diff --git a/mysql-test/main/type_json.result b/mysql-test/main/type_json.result index 431a7f138f6..91686704ebd 100644 --- a/mysql-test/main/type_json.result +++ b/mysql-test/main/type_json.result @@ -155,7 +155,7 @@ DROP TABLE t1; # SELECT json_object('a', (SELECT json_objectagg(b, c) FROM (SELECT 'b','c') d)) AS j FROM DUAL; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def j 250 (format=json) 9437283 16 Y 0 39 33 +def j 250 (format=json) 9437310 16 Y 0 39 33 j {"a": {"b":"c"}} # diff --git a/mysql-test/suite/encryption/t/encrypt_and_grep.test b/mysql-test/suite/encryption/t/encrypt_and_grep.test index 687f14e8a55..12593837cf0 100644 --- a/mysql-test/suite/encryption/t/encrypt_and_grep.test +++ b/mysql-test/suite/encryption/t/encrypt_and_grep.test @@ -24,8 +24,9 @@ insert t2 values (repeat('tempsecret', 12)); insert t3 values (repeat('dummysecret', 12)); --echo # Wait max 10 min for key encryption threads to encrypt all spaces +--let $tables_count= `select count(*) + @@global.innodb_undo_tablespaces from information_schema.tables where engine = 'InnoDB'` --let $wait_timeout= 600 ---let $wait_condition=SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 +--let $wait_condition=SELECT COUNT(*) = $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 --source include/wait_condition.inc --sorted_result @@ -95,8 +96,9 @@ UNLOCK TABLES; SET GLOBAL innodb_encrypt_tables = on; --echo # Wait max 10 min for key encryption threads to encrypt all spaces +--let $tables_count= `select count(*) + @@global.innodb_undo_tablespaces from information_schema.tables where engine = 'InnoDB'` --let $wait_timeout= 600 ---let $wait_condition=SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +--let $wait_condition=SELECT COUNT(*) = $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 --source include/wait_condition.inc --sorted_result diff --git a/mysql-test/suite/innodb/r/instant_alter_crash.result b/mysql-test/suite/innodb/r/instant_alter_crash.result index e423afe10a8..565f7e4b34e 100644 --- a/mysql-test/suite/innodb/r/instant_alter_crash.result +++ b/mysql-test/suite/innodb/r/instant_alter_crash.result @@ -202,27 +202,3 @@ Table Op Msg_type Msg_text test.t2 check status OK DROP TABLE t1,t2; db.opt -# -# MDEV-26198 Assertion `0' failed in row_log_table_apply_op during -# ADD PRIMARY KEY or OPTIMIZE TABLE -# -CREATE TABLE t1(f1 year default null, f2 year default null, -f3 text, f4 year default null, f5 year default null, -f6 year default null, f7 year default null, -f8 year default null)ENGINE=InnoDB ROW_FORMAT=REDUNDANT; -INSERT INTO t1 VALUES(1, 1, 1, 1, 1, 1, 1, 1); -ALTER TABLE t1 ADD COLUMN f9 year default null, ALGORITHM=INPLACE; -set DEBUG_SYNC="row_log_table_apply1_before SIGNAL con1_insert WAIT_FOR con1_finish"; -ALTER TABLE t1 ROW_FORMAT=REDUNDANT, ADD COLUMN f10 YEAR DEFAULT NULL, ALGORITHM=INPLACE; -connect con1,localhost,root,,,; -SET DEBUG_SYNC="now WAIT_FOR con1_insert"; -INSERT IGNORE INTO t1 (f3) VALUES ( 'b' ); -INSERT IGNORE INTO t1 (f3) VALUES ( 'l' ); -SET DEBUG_SYNC="now SIGNAL con1_finish"; -connection default; -disconnect con1; -SET DEBUG_SYNC=RESET; -CHECK TABLE t1; -Table Op Msg_type Msg_text -test.t1 check status OK -DROP TABLE t1; diff --git a/mysql-test/suite/innodb/r/instant_alter_debug,redundant.rdiff b/mysql-test/suite/innodb/r/instant_alter_debug,redundant.rdiff index f442e406ce4..cf72c37bde8 100644 --- a/mysql-test/suite/innodb/r/instant_alter_debug,redundant.rdiff +++ b/mysql-test/suite/innodb/r/instant_alter_debug,redundant.rdiff @@ -2,7 +2,7 @@ FROM information_schema.global_status WHERE variable_name = 'innodb_instant_alter_column'; instants --35 -+36 +-37 ++38 SET GLOBAL innodb_stats_persistent = @save_stats_persistent; # End of 10.6 tests diff --git a/mysql-test/suite/innodb/r/instant_alter_debug.result b/mysql-test/suite/innodb/r/instant_alter_debug.result index 0473b9c3204..53da7b6f5dc 100644 --- a/mysql-test/suite/innodb/r/instant_alter_debug.result +++ b/mysql-test/suite/innodb/r/instant_alter_debug.result @@ -479,10 +479,59 @@ SET DEBUG_SYNC="now WAIT_FOR try_insert"; INSERT INTO t1 VALUES(1, 2); ERROR HY000: Lock wait timeout exceeded; try restarting transaction SET DEBUG_SYNC="now SIGNAL alter_progress"; -disconnect con1; connection default; DROP TABLE t1; +# +# MDEV-26198 Assertion `0' failed in row_log_table_apply_op during +# ADD PRIMARY KEY or OPTIMIZE TABLE +# +CREATE TABLE t1(f1 year default null, f2 year default null, +f3 text, f4 year default null, f5 year default null, +f6 year default null, f7 year default null, +f8 year default null)ENGINE=InnoDB; +INSERT INTO t1 VALUES(1, 1, 1, 1, 1, 1, 1, 1); +ALTER TABLE t1 ADD COLUMN f9 year default null, ALGORITHM=INPLACE; +set DEBUG_SYNC="row_log_table_apply1_before SIGNAL con1_insert WAIT_FOR con1_finish"; +ALTER TABLE t1 ADD COLUMN f10 YEAR DEFAULT NULL, FORCE, ALGORITHM=INPLACE; +connection con1; +SET DEBUG_SYNC="now WAIT_FOR con1_insert"; +INSERT IGNORE INTO t1 (f3) VALUES ( 'b' ); +INSERT IGNORE INTO t1 (f3) VALUES ( 'l' ); +SET DEBUG_SYNC="now SIGNAL con1_finish"; +connection default; +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; +# +# MDEV-19044 Alter table corrupts while applying the +# modification log +# +CREATE TABLE t1 ( +f1 INT, +f2 INT, +f3 char(19) CHARACTER SET utf8mb3, +f4 VARCHAR(500), +f5 TEXT)ENGINE=InnoDB; +INSERT INTO t1 VALUES(3, 1, REPEAT('a', 2), REPEAT("b", 20),'a'); +ALTER TABLE t1 ADD COLUMN f6 INT NOT NULL, ALGORITHM=INSTANT; +INSERT INTO t1 VALUES(1, 2, REPEAT('InnoDB', 2), +REPEAT("MariaDB", 20), REPEAT('a', 8000), 12); +INSERT INTO t1 VALUES(1, 2, REPEAT('MYSQL', 2), +REPEAT("MariaDB", 20), REPEAT('a', 8000), 12); +SET DEBUG_SYNC='innodb_inplace_alter_table_enter SIGNAL con1_begin WAIT_FOR con1_update'; +ALTER TABLE t1 MODIFY COLUMN f2 INT NOT NULL, FORCE, ALGORITHM=INPLACE; +connection con1; +SET DEBUG_SYNC='now WAIT_FOR con1_begin'; +UPDATE t1 SET f2=204 order by f1 limit 2; +SET DEBUG_SYNC='now SIGNAL con1_update'; +connection default; +disconnect con1; SET DEBUG_SYNC=reset; +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; # End of 10.4 tests # # MDEV-22867 Assertion instant.n_core_fields == n_core_fields @@ -527,6 +576,6 @@ SELECT variable_value-@old_instant instants FROM information_schema.global_status WHERE variable_name = 'innodb_instant_alter_column'; instants -35 +37 SET GLOBAL innodb_stats_persistent = @save_stats_persistent; # End of 10.6 tests diff --git a/mysql-test/suite/innodb/t/instant_alter_crash.test b/mysql-test/suite/innodb/t/instant_alter_crash.test index f51f61e3c04..76b85b771f7 100644 --- a/mysql-test/suite/innodb/t/instant_alter_crash.test +++ b/mysql-test/suite/innodb/t/instant_alter_crash.test @@ -230,29 +230,3 @@ CHECK TABLE t2; DROP TABLE t1,t2; --list_files $MYSQLD_DATADIR/test - ---echo # ---echo # MDEV-26198 Assertion `0' failed in row_log_table_apply_op during ---echo # ADD PRIMARY KEY or OPTIMIZE TABLE ---echo # -CREATE TABLE t1(f1 year default null, f2 year default null, - f3 text, f4 year default null, f5 year default null, - f6 year default null, f7 year default null, - f8 year default null)ENGINE=InnoDB ROW_FORMAT=REDUNDANT; -INSERT INTO t1 VALUES(1, 1, 1, 1, 1, 1, 1, 1); -ALTER TABLE t1 ADD COLUMN f9 year default null, ALGORITHM=INPLACE; -set DEBUG_SYNC="row_log_table_apply1_before SIGNAL con1_insert WAIT_FOR con1_finish"; -send ALTER TABLE t1 ROW_FORMAT=REDUNDANT, ADD COLUMN f10 YEAR DEFAULT NULL, ALGORITHM=INPLACE; - -connect(con1,localhost,root,,,); -SET DEBUG_SYNC="now WAIT_FOR con1_insert"; -INSERT IGNORE INTO t1 (f3) VALUES ( 'b' ); -INSERT IGNORE INTO t1 (f3) VALUES ( 'l' ); -SET DEBUG_SYNC="now SIGNAL con1_finish"; - -connection default; -reap; -disconnect con1; -SET DEBUG_SYNC=RESET; -CHECK TABLE t1; -DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/instant_alter_debug.test b/mysql-test/suite/innodb/t/instant_alter_debug.test index ab30eb0c7c9..dd11e09629c 100644 --- a/mysql-test/suite/innodb/t/instant_alter_debug.test +++ b/mysql-test/suite/innodb/t/instant_alter_debug.test @@ -551,11 +551,62 @@ SET DEBUG_SYNC="now WAIT_FOR try_insert"; --error ER_LOCK_WAIT_TIMEOUT INSERT INTO t1 VALUES(1, 2); SET DEBUG_SYNC="now SIGNAL alter_progress"; -disconnect con1; connection default; reap; DROP TABLE t1; + +--echo # +--echo # MDEV-26198 Assertion `0' failed in row_log_table_apply_op during +--echo # ADD PRIMARY KEY or OPTIMIZE TABLE +--echo # +CREATE TABLE t1(f1 year default null, f2 year default null, + f3 text, f4 year default null, f5 year default null, + f6 year default null, f7 year default null, + f8 year default null)ENGINE=InnoDB; +INSERT INTO t1 VALUES(1, 1, 1, 1, 1, 1, 1, 1); +ALTER TABLE t1 ADD COLUMN f9 year default null, ALGORITHM=INPLACE; +set DEBUG_SYNC="row_log_table_apply1_before SIGNAL con1_insert WAIT_FOR con1_finish"; +send ALTER TABLE t1 ADD COLUMN f10 YEAR DEFAULT NULL, FORCE, ALGORITHM=INPLACE; + +connection con1; +SET DEBUG_SYNC="now WAIT_FOR con1_insert"; +INSERT IGNORE INTO t1 (f3) VALUES ( 'b' ); +INSERT IGNORE INTO t1 (f3) VALUES ( 'l' ); +SET DEBUG_SYNC="now SIGNAL con1_finish"; + +connection default; +reap; +CHECK TABLE t1; +DROP TABLE t1; + +--echo # +--echo # MDEV-19044 Alter table corrupts while applying the +--echo # modification log +--echo # +CREATE TABLE t1 ( + f1 INT, + f2 INT, + f3 char(19) CHARACTER SET utf8mb3, + f4 VARCHAR(500), + f5 TEXT)ENGINE=InnoDB; +INSERT INTO t1 VALUES(3, 1, REPEAT('a', 2), REPEAT("b", 20),'a'); +ALTER TABLE t1 ADD COLUMN f6 INT NOT NULL, ALGORITHM=INSTANT; +INSERT INTO t1 VALUES(1, 2, REPEAT('InnoDB', 2), + REPEAT("MariaDB", 20), REPEAT('a', 8000), 12); +INSERT INTO t1 VALUES(1, 2, REPEAT('MYSQL', 2), + REPEAT("MariaDB", 20), REPEAT('a', 8000), 12); +SET DEBUG_SYNC='innodb_inplace_alter_table_enter SIGNAL con1_begin WAIT_FOR con1_update'; +send ALTER TABLE t1 MODIFY COLUMN f2 INT NOT NULL, FORCE, ALGORITHM=INPLACE; +connection con1; +SET DEBUG_SYNC='now WAIT_FOR con1_begin'; +UPDATE t1 SET f2=204 order by f1 limit 2; +SET DEBUG_SYNC='now SIGNAL con1_update'; +connection default; +reap; +disconnect con1; SET DEBUG_SYNC=reset; +CHECK TABLE t1; +DROP TABLE t1; --echo # End of 10.4 tests diff --git a/mysql-test/suite/innodb_fts/r/foreign_key_update.result b/mysql-test/suite/innodb_fts/r/foreign_key_update.result index f2d47da78c5..87c21c0bfc5 100644 --- a/mysql-test/suite/innodb_fts/r/foreign_key_update.result +++ b/mysql-test/suite/innodb_fts/r/foreign_key_update.result @@ -32,3 +32,15 @@ database database DROP TABLE t1_fk; DROP TABLE t1; +# +# MDEV-32346 Assertion failure sym_node->table != NULL +# in pars_retrieve_table_def on UPDATE +# +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t2 (a INT, b TEXT, FOREIGN KEY(a) REFERENCES t1(a), +FULLTEXT (b))ENGINE=InnoDB; +INSERT INTO t1 SET a=1; +ALTER TABLE t2 DISCARD TABLESPACE; +UPDATE t1 SET a=2; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`)) +DROP TABLE t2,t1; diff --git a/mysql-test/suite/innodb_fts/t/foreign_key_update.test b/mysql-test/suite/innodb_fts/t/foreign_key_update.test index 1f74e640088..8a64ac33d69 100644 --- a/mysql-test/suite/innodb_fts/t/foreign_key_update.test +++ b/mysql-test/suite/innodb_fts/t/foreign_key_update.test @@ -32,3 +32,16 @@ SELECT * FROM t1_fk WHERE MATCH(a) AGAINST('database'); DROP TABLE t1_fk; DROP TABLE t1; + +--echo # +--echo # MDEV-32346 Assertion failure sym_node->table != NULL +--echo # in pars_retrieve_table_def on UPDATE +--echo # +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t2 (a INT, b TEXT, FOREIGN KEY(a) REFERENCES t1(a), + FULLTEXT (b))ENGINE=InnoDB; +INSERT INTO t1 SET a=1; +ALTER TABLE t2 DISCARD TABLESPACE; +--error ER_ROW_IS_REFERENCED_2 +UPDATE t1 SET a=2; +DROP TABLE t2,t1; diff --git a/mysql-test/suite/json/r/json_no_table.result b/mysql-test/suite/json/r/json_no_table.result index 6784fe6da32..10dd5d4b4ca 100644 --- a/mysql-test/suite/json/r/json_no_table.result +++ b/mysql-test/suite/json/r/json_no_table.result @@ -3338,7 +3338,7 @@ OBJECT CREATE VIEW v1 AS SELECT JSON_TYPE(JSON_OBJECT()); SELECT * FROM v1; JSON_TYPE(JSON_OBJECT()) -OBJE +OBJECT drop view v1; # # Bug#21198333 SIG 6 IN ITEM_CACHE_JSON::CACHE_VALUE AT SQL/ITEM.CC:9470 diff --git a/mysql-test/suite/rpl/r/rpl_parallel_temptable.result b/mysql-test/suite/rpl/r/rpl_parallel_temptable.result index 1a1c12f836d..c0ccdd3d4ff 100644 --- a/mysql-test/suite/rpl/r/rpl_parallel_temptable.result +++ b/mysql-test/suite/rpl/r/rpl_parallel_temptable.result @@ -203,6 +203,24 @@ a b include/stop_slave.inc SET GLOBAL slave_parallel_mode=@old_mode; include/start_slave.inc +*** MDEV33426: Memory allocation accounting incorrect for replicated temptable +connection server_1; +CREATE TEMPORARY TABLE t5 (a int) ENGINE=Aria; +CREATE TEMPORARY TABLE t6 (a int) ENGINE=Heap; +INSERT INTO t5 VALUES (1); +INSERT INTO t6 VALUES (2); +connection server_2; +include/stop_slave.inc +connection server_1; +INSERT INTO t1 SELECT a+40, 5 FROM t5; +INSERT INTO t1 SELECT a+40, 6 FROM t6; +DROP TABLE t5, t6; +connection server_2; +include/start_slave.inc +SELECT * FROM t1 WHERE a>=40 ORDER BY a; +a b +41 5 +42 6 connection server_2; include/stop_slave.inc SET GLOBAL slave_parallel_threads=@old_parallel_threads; diff --git a/mysql-test/suite/rpl/t/rpl_parallel_temptable.test b/mysql-test/suite/rpl/t/rpl_parallel_temptable.test index edb854842e1..eb5f88a1c15 100644 --- a/mysql-test/suite/rpl/t/rpl_parallel_temptable.test +++ b/mysql-test/suite/rpl/t/rpl_parallel_temptable.test @@ -265,6 +265,30 @@ SET GLOBAL slave_parallel_mode=@old_mode; --source include/start_slave.inc +--echo *** MDEV33426: Memory allocation accounting incorrect for replicated temptable +--connection server_1 +CREATE TEMPORARY TABLE t5 (a int) ENGINE=Aria; +CREATE TEMPORARY TABLE t6 (a int) ENGINE=Heap; +INSERT INTO t5 VALUES (1); +INSERT INTO t6 VALUES (2); +--save_master_pos + +--connection server_2 +--sync_with_master +--source include/stop_slave.inc + +--connection server_1 +INSERT INTO t1 SELECT a+40, 5 FROM t5; +INSERT INTO t1 SELECT a+40, 6 FROM t6; +DROP TABLE t5, t6; + +--save_master_pos + +--connection server_2 +--source include/start_slave.inc +--sync_with_master +SELECT * FROM t1 WHERE a>=40 ORDER BY a; + # Clean up. --connection server_2 diff --git a/mysys/lf_alloc-pin.c b/mysys/lf_alloc-pin.c index fc3f320a623..4dc41645530 100644 --- a/mysys/lf_alloc-pin.c +++ b/mysys/lf_alloc-pin.c @@ -291,7 +291,7 @@ static int harvest_pins(LF_PINS *el, struct st_harvester *hv) { for (i= 0; i < LF_PINBOX_PINS; i++) { - void *p= el->pin[i]; + void *p= my_atomic_loadptr((void **)&el->pin[i]); if (p) *hv->granary++= p; } @@ -316,7 +316,7 @@ static int match_pins(LF_PINS *el, void *addr) LF_PINS *el_end= el+LF_DYNARRAY_LEVEL_LENGTH; for (; el < el_end; el++) for (i= 0; i < LF_PINBOX_PINS; i++) - if (el->pin[i] == addr) + if (my_atomic_loadptr((void **)&el->pin[i]) == addr) return 1; return 0; } @@ -501,7 +501,8 @@ void *lf_alloc_new(LF_PINS *pins) { node= allocator->top; lf_pin(pins, 0, node); - } while (node != allocator->top && LF_BACKOFF()); + } while (node != my_atomic_loadptr((void **)(char *)&allocator->top) + && LF_BACKOFF()); if (!node) { node= (void *)my_malloc(key_memory_lf_node, allocator->element_size, diff --git a/sql/handler.cc b/sql/handler.cc index 4f78f3b6ec5..2b432161e7b 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3390,6 +3390,17 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode, DBUG_ASSERT(alloc_root_inited(&table->mem_root)); set_partitions_to_open(partitions_to_open); + internal_tmp_table= MY_TEST(test_if_locked & HA_OPEN_INTERNAL_TABLE); + + if (!internal_tmp_table && (test_if_locked & HA_OPEN_TMP_TABLE) && + current_thd->slave_thread) + { + /* + This is a temporary table used by replication that is not attached + to a THD. Mark it as a global temporary table. + */ + test_if_locked|= HA_OPEN_GLOBAL_TMP_TABLE; + } if (unlikely((error=open(name,mode,test_if_locked)))) { @@ -3435,7 +3446,6 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode, cached_table_flags= table_flags(); } reset_statistics(); - internal_tmp_table= MY_TEST(test_if_locked & HA_OPEN_INTERNAL_TABLE); DBUG_RETURN(error); } @@ -5529,6 +5539,9 @@ handler::ha_create(const char *name, TABLE *form, HA_CREATE_INFO *info_arg) { DBUG_ASSERT(m_lock_type == F_UNLCK); mark_trx_read_write(); + if ((info_arg->options & HA_LEX_CREATE_TMP_TABLE) && + current_thd->slave_thread) + info_arg->options|= HA_LEX_CREATE_GLOBAL_TMP_TABLE; int error= create(name, form, info_arg); if (!error && !(info_arg->options & (HA_LEX_CREATE_TMP_TABLE | HA_CREATE_TMP_ALTER))) diff --git a/sql/handler.h b/sql/handler.h index be0794a73a9..bbdf6b047d8 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -495,6 +495,12 @@ enum chf_create_flags { #define HA_LEX_CREATE_SEQUENCE 16U #define HA_VERSIONED_TABLE 32U #define HA_SKIP_KEY_SORT 64U +/* + A temporary table that can be used by different threads, eg. replication + threads. This flag ensure that memory is not allocated with THREAD_SPECIFIC, + as we do for other temporary tables. +*/ +#define HA_LEX_CREATE_GLOBAL_TMP_TABLE 128U #define HA_MAX_REC_LENGTH 65535 diff --git a/sql/item.cc b/sql/item.cc index 650a3c78c49..e974fc084c2 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -27,6 +27,7 @@ #include "sp_rcontext.h" #include "sp_head.h" #include "sql_trigger.h" +#include "sql_parse.h" #include "sql_select.h" #include "sql_show.h" // append_identifier #include "sql_view.h" // VIEW_ANY_SQL @@ -494,7 +495,10 @@ void Item::print_parenthesised(String *str, enum_query_type query_type, bool need_parens= precedence() < parent_prec; if (need_parens) str->append('('); - print(str, query_type); + if (check_stack_overrun(current_thd, STACK_MIN_SIZE, NULL)) + str->append(STRING_WITH_LEN("")); + else + print(str, query_type); if (need_parens) str->append(')'); } @@ -5156,9 +5160,19 @@ bool Item_param::assign_default(Field *field) } if (m_default_field->default_value) - m_default_field->set_default(); - - return field_conv(field, m_default_field); + { + return m_default_field->default_value->expr->save_in_field(field, 0); + } + else if (m_default_field->is_null()) + { + field->set_null(); + return false; + } + else + { + field->set_notnull(); + return field_conv(field, m_default_field); + } } diff --git a/sql/item.h b/sql/item.h index b7a3947231c..b6eee551110 100644 --- a/sql/item.h +++ b/sql/item.h @@ -4150,6 +4150,12 @@ public: Item_param(THD *thd, const LEX_CSTRING *name_arg, uint pos_in_query_arg, uint len_in_query_arg); + void cleanup() override + { + m_default_field= NULL; + Item::cleanup(); + } + Type type() const override { // Don't pretend to be a constant unless value for this item is set. diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index f8fd28aebb5..a2b7efb8ce8 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -6142,8 +6142,8 @@ bool Regexp_processor_pcre::compile(String *pattern, bool send_error) if (!stringcmp(pattern, &m_prev_pattern)) return false; cleanup(); - m_prev_pattern.copy(*pattern); } + m_prev_pattern.copy(*pattern); if (!(pattern= convert_if_needed(pattern, &pattern_converter))) return true; diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index c4157cbf61d..b2f67122a5f 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -20,20 +20,14 @@ #include "item.h" #include "sql_parse.h" // For check_stack_overrun -/* - Allocating memory and *also* using it (reading and - writing from it) because some build instructions cause - compiler to optimize out stack_used_up. Since alloca() - here depends on stack_used_up, it doesnt get executed - correctly and causes json_debug_nonembedded to fail - ( --error ER_STACK_OVERRUN_NEED_MORE does not occur). -*/ -#define ALLOCATE_MEM_ON_STACK(A) do \ - { \ - uchar *array= (uchar*)alloca(A); \ - bzero(array, A); \ - my_checksum(0, array, A); \ - } while(0) +#ifndef DBUG_OFF +static int dbug_json_check_min_stack_requirement() +{ + my_error(ER_STACK_OVERRUN_NEED_MORE, MYF(ME_FATAL), + my_thread_stack_size, my_thread_stack_size, STACK_MIN_SIZE); + return 1; +} +#endif /* Compare ASCII string against the string with the specified @@ -151,11 +145,8 @@ int json_path_parts_compare( int res, res2; DBUG_EXECUTE_IF("json_check_min_stack_requirement", - { - long arbitrary_var; - long stack_used_up= (available_stack_size(current_thd->thread_stack, &arbitrary_var)); - ALLOCATE_MEM_ON_STACK(my_thread_stack_size-stack_used_up-STACK_MIN_SIZE); - }); + return dbug_json_check_min_stack_requirement();); + if (check_stack_overrun(current_thd, STACK_MIN_SIZE , NULL)) return 1; @@ -759,7 +750,7 @@ bool Item_func_json_unquote::fix_length_and_dec() { collation.set(&my_charset_utf8mb3_general_ci, DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); - max_length= args[0]->max_length; + max_length= args[0]->max_char_length() * collation.collation->mbmaxlen; set_maybe_null(); return FALSE; } @@ -1206,11 +1197,7 @@ static int check_contains(json_engine_t *js, json_engine_t *value) json_engine_t loc_js; bool set_js; DBUG_EXECUTE_IF("json_check_min_stack_requirement", - { - long arbitrary_var; - long stack_used_up= (available_stack_size(current_thd->thread_stack, &arbitrary_var)); - ALLOCATE_MEM_ON_STACK(my_thread_stack_size-stack_used_up-STACK_MIN_SIZE); - }); + return dbug_json_check_min_stack_requirement();); if (check_stack_overrun(current_thd, STACK_MIN_SIZE , NULL)) return 1; @@ -1796,7 +1783,23 @@ bool Item_func_json_array::fix_length_and_dec() return TRUE; for (n_arg=0 ; n_arg < arg_count ; n_arg++) - char_length+= static_cast(args[n_arg]->max_char_length()) + 4; + { + ulonglong arg_length; + Item *arg= args[n_arg]; + + if (arg->result_type() == STRING_RESULT && + !Type_handler_json_common::is_json_type_handler(arg->type_handler())) + arg_length= arg->max_char_length() * 2; /*escaping possible */ + else if (arg->type_handler()->is_bool_type()) + arg_length= 5; + else + arg_length= arg->max_char_length(); + + if (arg_length < 4) + arg_length= 4; /* can be 'null' */ + + char_length+= arg_length + 4; + } fix_char_length_ulonglong(char_length); tmp_val.set_charset(collation.collation); @@ -2184,13 +2187,8 @@ err_return: static int do_merge(String *str, json_engine_t *je1, json_engine_t *je2) { - DBUG_EXECUTE_IF("json_check_min_stack_requirement", - { - long arbitrary_var; - long stack_used_up= (available_stack_size(current_thd->thread_stack, &arbitrary_var)); - ALLOCATE_MEM_ON_STACK(my_thread_stack_size-stack_used_up-STACK_MIN_SIZE); - }); + return dbug_json_check_min_stack_requirement();); if (check_stack_overrun(current_thd, STACK_MIN_SIZE , NULL)) return 1; @@ -2529,11 +2527,7 @@ static int do_merge_patch(String *str, json_engine_t *je1, json_engine_t *je2, bool *empty_result) { DBUG_EXECUTE_IF("json_check_min_stack_requirement", - { - long arbitrary_var; - long stack_used_up= (available_stack_size(current_thd->thread_stack, &arbitrary_var)); - ALLOCATE_MEM_ON_STACK(my_thread_stack_size-stack_used_up-STACK_MIN_SIZE); - }); + return dbug_json_check_min_stack_requirement();); if (check_stack_overrun(current_thd, STACK_MIN_SIZE , NULL)) return 1; @@ -2950,7 +2944,7 @@ longlong Item_func_json_depth::val_int() bool Item_func_json_type::fix_length_and_dec() { collation.set(&my_charset_utf8mb3_general_ci); - max_length= 12; + max_length= 12 * collation.collation->mbmaxlen; set_maybe_null(); return FALSE; } @@ -3016,8 +3010,12 @@ bool Item_func_json_insert::fix_length_and_dec() for (n_arg= 1; n_arg < arg_count; n_arg+= 2) { paths[n_arg/2].set_constant_flag(args[n_arg]->const_item()); - char_length+= - static_cast(args[n_arg+1]->max_char_length()) + 4; + /* + In the resulting JSON we can insert the property + name from the path, and the value itself. + */ + char_length+= args[n_arg/2]->max_char_length() + 6; + char_length+= args[n_arg/2+1]->max_char_length() + 4; } fix_char_length_ulonglong(char_length); @@ -3831,7 +3829,20 @@ bool Item_func_json_format::fix_length_and_dec() { decimals= 0; collation.set(args[0]->collation); - max_length= args[0]->max_length; + switch (fmt) + { + case COMPACT: + max_length= args[0]->max_length; + break; + case LOOSE: + max_length= args[0]->max_length * 2; + break; + case DETAILED: + max_length= MAX_BLOB_WIDTH; + break; + default: + DBUG_ASSERT(0); + }; set_maybe_null(); return FALSE; } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 02ec84d7e2e..1b56beaf5a9 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -3618,7 +3618,9 @@ bool Item_func_set_collation::fix_length_and_dec() } collation.set(m_set_collation, DERIVATION_EXPLICIT, args[0]->collation.repertoire); - max_length= args[0]->max_length; + ulonglong max_char_length= (ulonglong) args[0]->max_char_length(); + fix_char_length_ulonglong(max_char_length * collation.collation->mbmaxlen); + return FALSE; } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index bc534c2bd1f..fe44f657a13 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3125,7 +3125,6 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) sigset_t set; int sig; my_thread_init(); // Init new thread - DBUG_ENTER("signal_hand"); signal_thread_in_use= 1; /* @@ -3179,7 +3178,6 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) { DBUG_PRINT("quit",("signal_handler: calling my_thread_end()")); my_thread_end(); - DBUG_LEAVE; // Must match DBUG_ENTER() signal_thread_in_use= 0; pthread_exit(0); // Safety return 0; // Avoid compiler warnings @@ -3697,20 +3695,35 @@ static void my_malloc_size_cb_func(long long size, my_bool is_thread_specific) thd->status_var.local_memory_used > (int64)thd->variables.max_mem_used && likely(!thd->killed) && !thd->get_stmt_da()->is_set()) { - /* Ensure we don't get called here again */ - char buf[50], *buf2; - thd->set_killed(KILL_QUERY); - my_snprintf(buf, sizeof(buf), "--max-session-mem-used=%llu", - thd->variables.max_mem_used); - if ((buf2= (char*) thd->alloc(256))) - { - my_snprintf(buf2, 256, ER_THD(thd, ER_OPTION_PREVENTS_STATEMENT), buf); - thd->set_killed(KILL_QUERY, ER_OPTION_PREVENTS_STATEMENT, buf2); - } - else - { - thd->set_killed(KILL_QUERY, ER_OPTION_PREVENTS_STATEMENT, - "--max-session-mem-used"); + /* + Ensure we don't get called here again. + + It is not safe to wait for LOCK_thd_kill here, as we could be called + from almost any context. For example while LOCK_plugin is being held; + but THD::awake() locks LOCK_thd_kill and LOCK_plugin in the opposite + order (MDEV-33443). + + So ignore the max_mem_used limit in the unlikely case we cannot obtain + LOCK_thd_kill here (the limit will be enforced on the next allocation). + */ + if (!mysql_mutex_trylock(&thd->LOCK_thd_kill)) { + char buf[50], *buf2; + thd->set_killed_no_mutex(KILL_QUERY); + my_snprintf(buf, sizeof(buf), "--max-session-mem-used=%llu", + thd->variables.max_mem_used); + if ((buf2= (char*) thd->alloc(256))) + { + my_snprintf(buf2, 256, + ER_THD(thd, ER_OPTION_PREVENTS_STATEMENT), buf); + thd->set_killed_no_mutex(KILL_QUERY, + ER_OPTION_PREVENTS_STATEMENT, buf2); + } + else + { + thd->set_killed_no_mutex(KILL_QUERY, ER_OPTION_PREVENTS_STATEMENT, + "--max-session-mem-used"); + } + mysql_mutex_unlock(&thd->LOCK_thd_kill); } } DBUG_ASSERT((longlong) thd->status_var.local_memory_used >= 0 || diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index f3959ceeb80..93bf17d856f 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2899,6 +2899,7 @@ bool acl_reload(THD *thd) } acl_cache->clear(0); + mysql_mutex_record_order(&acl_cache->lock, &LOCK_status); mysql_mutex_lock(&acl_cache->lock); old_acl_hosts= acl_hosts; @@ -13219,8 +13220,27 @@ static bool send_server_handshake_packet(MPVIO_EXT *mpvio, *end++= 0; int2store(end, thd->client_capabilities); + + CHARSET_INFO *handshake_cs= default_charset_info; + if (handshake_cs->number > 0xFF) + { + /* + A workaround for a 2-byte collation ID: translate it into + the ID of the primary collation of this character set. + */ + CHARSET_INFO *cs= get_charset_by_csname(handshake_cs->cs_name.str, + MY_CS_PRIMARY, MYF(MY_WME)); + /* + cs should not normally be NULL, however it may be possible + with a dynamic character set incorrectly defined in Index.xml. + For safety let's fallback to latin1 in case cs is NULL. + */ + handshake_cs= cs ? cs : &my_charset_latin1; + } + /* write server characteristics: up to 16 bytes allowed */ - end[2]= (char) default_charset_info->number; + end[2]= (char) handshake_cs->number; + int2store(end+3, mpvio->auth_info.thd->server_status); int2store(end+5, thd->client_capabilities >> 16); end[7]= data_len; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d3bb496d58a..f5e4eea9270 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -18472,6 +18472,12 @@ Item_cond::remove_eq_conds(THD *thd, Item::cond_result *cond_value, bool and_level= functype() == Item_func::COND_AND_FUNC; List *cond_arg_list= argument_list(); + if (check_stack_overrun(thd, STACK_MIN_SIZE, NULL)) + { + *cond_value= Item::COND_FALSE; + return (COND*) 0; // Fatal error flag is set! + } + if (and_level) { /* diff --git a/sql/temporary_tables.cc b/sql/temporary_tables.cc index cf9cb8e0402..a28b5f96935 100644 --- a/sql/temporary_tables.cc +++ b/sql/temporary_tables.cc @@ -1119,11 +1119,16 @@ TABLE *THD::open_temporary_table(TMP_TABLE_SHARE *share, DBUG_RETURN(NULL); /* Out of memory */ } + uint flags= ha_open_options | (open_options & HA_OPEN_FOR_CREATE); + /* + In replication, temporary tables are not confined to a single + thread/THD. + */ + if (slave_thread) + flags|= HA_OPEN_GLOBAL_TMP_TABLE; if (open_table_from_share(this, share, &alias, (uint) HA_OPEN_KEYFILE, - EXTRA_RECORD, - (ha_open_options | - (open_options & HA_OPEN_FOR_CREATE)), + EXTRA_RECORD, flags, table, false)) { my_free(table); diff --git a/sql/wsrep_client_service.h b/sql/wsrep_client_service.h index 253d2f43ac3..b74c52b038f 100644 --- a/sql/wsrep_client_service.h +++ b/sql/wsrep_client_service.h @@ -57,6 +57,10 @@ public: { return false; } + bool is_prepared_xa() + { + return false; + } bool is_xa_rollback() { return false; diff --git a/storage/innobase/rem/rem0rec.cc b/storage/innobase/rem/rem0rec.cc index a862edd786a..47be5e447f5 100644 --- a/storage/innobase/rem/rem0rec.cc +++ b/storage/innobase/rem/rem0rec.cc @@ -427,7 +427,7 @@ start: } if (!field->fixed_len - || (format == REC_LEAF_TEMP + || (format <= REC_LEAF_TEMP_INSTANT && !dict_col_get_fixed_size(col, true))) { /* Variable-length field: read the length */ len = *lens--; diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 637a877f25c..6a518cddadf 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1591,7 +1591,8 @@ init_fts_doc_id_for_ref( for (dict_foreign_t* foreign : table->referenced_set) { ut_ad(foreign->foreign_table); - if (foreign->foreign_table->fts) { + if (foreign->foreign_table->space + && foreign->foreign_table->fts) { fts_init_doc_id(foreign->foreign_table); } diff --git a/storage/innobase/trx/trx0rseg.cc b/storage/innobase/trx/trx0rseg.cc index e40afa6d4a0..26d09f5fbbe 100644 --- a/storage/innobase/trx/trx0rseg.cc +++ b/storage/innobase/trx/trx0rseg.cc @@ -209,6 +209,11 @@ bool trx_rseg_read_wsrep_checkpoint(const buf_block_t *rseg_header, XID &xid) @return whether the WSREP XID is present */ static bool trx_rseg_init_wsrep_xid(const page_t* page, XID& xid) { + if (memcmp(TRX_SYS + TRX_SYS_WSREP_XID_INFO + page, + field_ref_zero, TRX_SYS_WSREP_XID_LEN) == 0) { + return false; + } + if (mach_read_from_4(TRX_SYS + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_MAGIC_N_FLD + page) @@ -561,10 +566,6 @@ static void trx_rseg_init_binlog_info(const page_t* page) + TRX_SYS + page); trx_sys.recovered_binlog_is_legacy_pos= true; } - -#ifdef WITH_WSREP - trx_rseg_init_wsrep_xid(page, trx_sys.recovered_wsrep_xid); -#endif } /** Initialize or recover the rollback segments at startup. */ @@ -596,7 +597,11 @@ dberr_t trx_rseg_array_init() + sys->page.frame); trx_rseg_init_binlog_info(sys->page.frame); #ifdef WITH_WSREP - wsrep_sys_xid.set(&trx_sys.recovered_wsrep_xid); + if (trx_rseg_init_wsrep_xid( + sys->page.frame, trx_sys.recovered_wsrep_xid)) { + wsrep_sys_xid.set( + &trx_sys.recovered_wsrep_xid); + } #endif } @@ -647,7 +652,7 @@ dberr_t trx_rseg_array_init() } #ifdef WITH_WSREP - if (!wsrep_sys_xid.is_null()) { + if (srv_operation == SRV_OPERATION_NORMAL && !wsrep_sys_xid.is_null()) { /* Upgrade from a version prior to 10.3.5, where WSREP XID was stored in TRX_SYS page. If no rollback segment has a WSREP XID set, diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 642ba26304e..48eb9ccfb50 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -3343,6 +3343,8 @@ int ha_maria::create(const char *name, TABLE *table_arg, if (ha_create_info->tmp_table()) { create_flags|= HA_CREATE_TMP_TABLE | HA_CREATE_DELAY_KEY_WRITE; + if (ha_create_info->options & HA_LEX_CREATE_GLOBAL_TMP_TABLE) + create_flags|= HA_CREATE_GLOBAL_TMP_TABLE; create_info.transactional= 0; } if (ha_create_info->options & HA_CREATE_KEEP_FILES) diff --git a/storage/maria/ma_bitmap.c b/storage/maria/ma_bitmap.c index 23135ff00a9..c813eab07dc 100644 --- a/storage/maria/ma_bitmap.c +++ b/storage/maria/ma_bitmap.c @@ -232,7 +232,7 @@ my_bool _ma_bitmap_init(MARIA_SHARE *share, File file, uint max_page_size; MARIA_FILE_BITMAP *bitmap= &share->bitmap; uint size= share->block_size; - myf flag= MY_WME | (share->temporary ? MY_THREAD_SPECIFIC : 0); + myf flag= MY_WME | share->malloc_flag; pgcache_page_no_t first_bitmap_with_space; #ifndef DBUG_OFF /* We want to have a copy of the bitmap to be able to print differences */ diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c index 543ddcca176..561cc324ed1 100644 --- a/storage/maria/ma_blockrec.c +++ b/storage/maria/ma_blockrec.c @@ -488,7 +488,7 @@ my_bool _ma_init_block_record(MARIA_HA *info) { MARIA_ROW *row= &info->cur_row, *new_row= &info->new_row; MARIA_SHARE *share= info->s; - myf flag= MY_WME | (share->temporary ? MY_THREAD_SPECIFIC : 0); + myf flag= MY_WME | share->malloc_flag; uint default_extents; DBUG_ENTER("_ma_init_block_record"); @@ -2654,7 +2654,6 @@ static my_bool write_block_record(MARIA_HA *info, LSN lsn; my_off_t position; uint save_my_errno; - myf myflag= MY_WME | (share->temporary ? MY_THREAD_SPECIFIC : 0); DBUG_ENTER("write_block_record"); head_block= bitmap_blocks->block; @@ -2721,7 +2720,7 @@ static my_bool write_block_record(MARIA_HA *info, for every data segment we want to store. */ if (_ma_alloc_buffer(&info->rec_buff, &info->rec_buff_size, - row->head_length, myflag)) + row->head_length, MY_WME | share->malloc_flag)) DBUG_RETURN(1); tmp_data_used= 0; /* Either 0 or last used uchar in 'data' */ @@ -4750,7 +4749,7 @@ int _ma_read_block_record2(MARIA_HA *info, uchar *record, MARIA_EXTENT_CURSOR extent; MARIA_COLUMNDEF *column, *end_column; MARIA_ROW *cur_row= &info->cur_row; - myf myflag= MY_WME | (share->temporary ? MY_THREAD_SPECIFIC : 0); + myf myflag= MY_WME | share->malloc_flag; DBUG_ENTER("_ma_read_block_record2"); start_of_data= data; @@ -5089,7 +5088,6 @@ static my_bool read_row_extent_info(MARIA_HA *info, uchar *buff, uint flag, row_extents, row_extents_size; uint field_lengths __attribute__ ((unused)); uchar *extents, *end; - myf myflag= MY_WME | (share->temporary ? MY_THREAD_SPECIFIC : 0); DBUG_ENTER("read_row_extent_info"); if (!(data= get_record_position(share, buff, @@ -5113,7 +5111,7 @@ static my_bool read_row_extent_info(MARIA_HA *info, uchar *buff, if (info->cur_row.extents_buffer_length < row_extents_size && _ma_alloc_buffer(&info->cur_row.extents, &info->cur_row.extents_buffer_length, - row_extents_size, myflag)) + row_extents_size, MY_WME | share->malloc_flag)) DBUG_RETURN(1); memcpy(info->cur_row.extents, data, ROW_EXTENT_SIZE); data+= ROW_EXTENT_SIZE; @@ -5283,7 +5281,7 @@ my_bool _ma_cmp_block_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def, my_bool _ma_scan_init_block_record(MARIA_HA *info) { MARIA_SHARE *share= info->s; - myf flag= MY_WME | (share->temporary ? MY_THREAD_SPECIFIC : 0); + myf flag= MY_WME | share->malloc_flag; DBUG_ENTER("_ma_scan_init_block_record"); DBUG_ASSERT(info->dfile.file == share->bitmap.file.file); diff --git a/storage/maria/ma_check.c b/storage/maria/ma_check.c index 1f6aa2ee98c..1f5f494ca65 100644 --- a/storage/maria/ma_check.c +++ b/storage/maria/ma_check.c @@ -1305,7 +1305,6 @@ static int check_dynamic_record(HA_CHECK *param, MARIA_HA *info, int extend, ulong UNINIT_VAR(left_length); uint b_type; char llbuff[22],llbuff2[22],llbuff3[22]; - myf myflag= MY_WME | (share->temporary ? MY_THREAD_SPECIFIC : 0); DBUG_ENTER("check_dynamic_record"); pos= 0; @@ -1413,7 +1412,8 @@ static int check_dynamic_record(HA_CHECK *param, MARIA_HA *info, int extend, { if (_ma_alloc_buffer(&info->rec_buff, &info->rec_buff_size, block_info.rec_len + - share->base.extra_rec_buff_size, myflag)) + share->base.extra_rec_buff_size, + MY_WME | share->malloc_flag)) { _ma_check_print_error(param, diff --git a/storage/maria/ma_create.c b/storage/maria/ma_create.c index 7fd739d13a8..9ce48ae9e7f 100644 --- a/storage/maria/ma_create.c +++ b/storage/maria/ma_create.c @@ -101,7 +101,7 @@ int maria_create(const char *name, enum data_file_type datafile_type, DBUG_ASSERT(maria_inited); - if (flags & HA_CREATE_TMP_TABLE) + if ((flags & HA_CREATE_TMP_TABLE) && !(flags & HA_CREATE_GLOBAL_TMP_TABLE)) common_flag|= MY_THREAD_SPECIFIC; if (!ci) diff --git a/storage/maria/ma_dynrec.c b/storage/maria/ma_dynrec.c index 33f238d9754..fed1bf411f4 100644 --- a/storage/maria/ma_dynrec.c +++ b/storage/maria/ma_dynrec.c @@ -1488,7 +1488,6 @@ int _ma_read_dynamic_record(MARIA_HA *info, uchar *buf, uchar *UNINIT_VAR(to); uint UNINIT_VAR(left_length); MARIA_SHARE *share= info->s; - myf flag= MY_WME | (share->temporary ? MY_THREAD_SPECIFIC : 0); DBUG_ENTER("_ma_read_dynamic_record"); if (filepos == HA_OFFSET_ERROR) @@ -1525,7 +1524,8 @@ int _ma_read_dynamic_record(MARIA_HA *info, uchar *buf, { if (_ma_alloc_buffer(&info->rec_buff, &info->rec_buff_size, block_info.rec_len + - share->base.extra_rec_buff_size, flag)) + share->base.extra_rec_buff_size, + MY_WME | share->malloc_flag)) goto err; } to= info->rec_buff; @@ -1784,7 +1784,6 @@ int _ma_read_rnd_dynamic_record(MARIA_HA *info, uchar *UNINIT_VAR(to); MARIA_BLOCK_INFO block_info; MARIA_SHARE *share= info->s; - myf flag= MY_WME | (share->temporary ? MY_THREAD_SPECIFIC : 0); DBUG_ENTER("_ma_read_rnd_dynamic_record"); #ifdef MARIA_EXTERNAL_LOCKING @@ -1875,7 +1874,8 @@ int _ma_read_rnd_dynamic_record(MARIA_HA *info, { if (_ma_alloc_buffer(&info->rec_buff, &info->rec_buff_size, block_info.rec_len + - share->base.extra_rec_buff_size, flag)) + share->base.extra_rec_buff_size, + MY_WME | share->malloc_flag)) goto err; } to= info->rec_buff; diff --git a/storage/maria/ma_extra.c b/storage/maria/ma_extra.c index 425cb421e22..49b731af5fc 100644 --- a/storage/maria/ma_extra.c +++ b/storage/maria/ma_extra.c @@ -542,7 +542,7 @@ int maria_reset(MARIA_HA *info) { int error= 0; MARIA_SHARE *share= info->s; - myf flag= MY_WME | (share->temporary ? MY_THREAD_SPECIFIC : 0); + myf flag= MY_WME | share->malloc_flag; DBUG_ENTER("maria_reset"); /* Free buffers and reset the following flags: diff --git a/storage/maria/ma_open.c b/storage/maria/ma_open.c index f844b3890df..6d9ae62ca8e 100644 --- a/storage/maria/ma_open.c +++ b/storage/maria/ma_open.c @@ -94,7 +94,7 @@ static MARIA_HA *maria_clone_internal(MARIA_SHARE *share, uint errpos; MARIA_HA info,*m_info; my_bitmap_map *changed_fields_bitmap; - myf flag= MY_WME | (share->temporary ? MY_THREAD_SPECIFIC : 0); + myf flag= MY_WME | share->malloc_flag; DBUG_ENTER("maria_clone_internal"); errpos= 0; @@ -267,7 +267,9 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags, uint i,j,len,errpos,head_length,base_pos,keys, realpath_err, key_parts,base_key_parts,unique_key_parts,fulltext_keys,uniques; uint internal_table= MY_TEST(open_flags & HA_OPEN_INTERNAL_TABLE); - myf common_flag= open_flags & HA_OPEN_TMP_TABLE ? MY_THREAD_SPECIFIC : 0; + myf common_flag= (((open_flags & HA_OPEN_TMP_TABLE) && + !(open_flags & HA_OPEN_GLOBAL_TMP_TABLE)) ? + MY_THREAD_SPECIFIC : 0); uint file_version; size_t info_length; char name_buff[FN_REFLEN], org_name[FN_REFLEN], index_name[FN_REFLEN], @@ -987,9 +989,10 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags, if (open_flags & HA_OPEN_TMP_TABLE || share->options & HA_OPTION_TMP_TABLE) { - common_flag|= MY_THREAD_SPECIFIC; share->options|= HA_OPTION_TMP_TABLE; share->temporary= share->delay_key_write= 1; + share->malloc_flag= + (open_flags & HA_OPEN_GLOBAL_TMP_TABLE) ? 0 : MY_THREAD_SPECIFIC; share->write_flag=MYF(MY_NABP); share->w_locks++; /* We don't have to update status */ share->tot_locks++; @@ -2046,9 +2049,8 @@ void _ma_set_index_pagecache_callbacks(PAGECACHE_FILE *file, int _ma_open_datafile(MARIA_HA *info, MARIA_SHARE *share) { - myf flags= (share->mode & O_NOFOLLOW) ? MY_NOSYMLINKS | MY_WME : MY_WME; - if (share->temporary) - flags|= MY_THREAD_SPECIFIC; + myf flags= ((share->mode & O_NOFOLLOW) ? MY_NOSYMLINKS | MY_WME : MY_WME) | + share->malloc_flag; DEBUG_SYNC_C("mi_open_datafile"); info->dfile.file= share->bitmap.file.file= mysql_file_open(key_file_dfile, share->data_file_name.str, diff --git a/storage/maria/ma_packrec.c b/storage/maria/ma_packrec.c index 19783423ab5..57926ee49a7 100644 --- a/storage/maria/ma_packrec.c +++ b/storage/maria/ma_packrec.c @@ -1417,7 +1417,6 @@ uint _ma_pack_get_block_info(MARIA_HA *maria, MARIA_BIT_BUFF *bit_buff, uchar *header= info->header; uint head_length,UNINIT_VAR(ref_length); MARIA_SHARE *share= maria->s; - myf flag= MY_WME | (share->temporary ? MY_THREAD_SPECIFIC : 0); if (file >= 0) { @@ -1444,7 +1443,8 @@ uint _ma_pack_get_block_info(MARIA_HA *maria, MARIA_BIT_BUFF *bit_buff, */ if (_ma_alloc_buffer(rec_buff_p, rec_buff_size_p, info->rec_len + info->blob_len + - share->base.extra_rec_buff_size, flag)) + share->base.extra_rec_buff_size, + MY_WME | share->malloc_flag)) return BLOCK_FATAL_ERROR; /* not enough memory */ bit_buff->blob_pos= *rec_buff_p + info->rec_len; bit_buff->blob_end= bit_buff->blob_pos + info->blob_len; @@ -1586,7 +1586,6 @@ _ma_mempack_get_block_info(MARIA_HA *maria, uchar *header) { MARIA_SHARE *share= maria->s; - myf flag= MY_WME | (share->temporary ? MY_THREAD_SPECIFIC : 0); header+= read_pack_length((uint) share->pack.version, header, &info->rec_len); @@ -1596,7 +1595,8 @@ _ma_mempack_get_block_info(MARIA_HA *maria, &info->blob_len); /* _ma_alloc_rec_buff sets my_errno on error */ if (_ma_alloc_buffer(rec_buff_p, rec_buff_size_p, - info->blob_len + share->base.extra_rec_buff_size, flag)) + info->blob_len + share->base.extra_rec_buff_size, + MY_WME | share->malloc_flag)) return 0; /* not enough memory */ bit_buff->blob_pos= *rec_buff_p; bit_buff->blob_end= *rec_buff_p + info->blob_len; diff --git a/storage/maria/maria_def.h b/storage/maria/maria_def.h index 91e1b10a7ed..f3303884200 100644 --- a/storage/maria/maria_def.h +++ b/storage/maria/maria_def.h @@ -754,6 +754,11 @@ typedef struct st_maria_share ulong max_pack_length; ulong state_diff_length; uint rec_reflength; /* rec_reflength in use now */ + /* + Extra flag to use for my_malloc(); set to MY_THREAD_SPECIFIC for temporary + tables whose memory allocation should be accounted to the current THD. + */ + uint malloc_flag; uint keypage_header; uint32 ftkeys; /* Number of distinct full-text keys + 1 */