From 7c02e8717de59af16e0f24a2334d10b426909c3a Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 2 Jul 2021 15:13:37 +0200 Subject: [PATCH 01/35] MDEV-26081 set role crashes when a hostname cannot be resolved host can be NULL --- mysql-test/r/skip_name_resolve.result | 22 +++++++++++++++- .../suite/roles/set_default_role_for.result | 4 +-- .../roles/set_default_role_invalid.result | 6 ++--- .../suite/roles/set_role-recursive.result | 2 +- mysql-test/t/skip_name_resolve.test | 26 ++++++++++++++++++- sql/sql_acl.cc | 9 +++---- 6 files changed, 55 insertions(+), 14 deletions(-) diff --git a/mysql-test/r/skip_name_resolve.result b/mysql-test/r/skip_name_resolve.result index 1362e482717..7159a1509b8 100644 --- a/mysql-test/r/skip_name_resolve.result +++ b/mysql-test/r/skip_name_resolve.result @@ -39,4 +39,24 @@ SET @@LOCAL.skip_name_resolve=0; ERROR HY000: Variable 'skip_name_resolve' is a read only variable SET @@GLOBAL.skip_name_resolve=0; ERROR HY000: Variable 'skip_name_resolve' is a read only variable -End of 5.1 tests +# +# End of 5.1 tests +# +# +# MDEV-26081 set role crashes when a hostname cannot be resolved +# +create user u1@`%`; +create role r1; +create role r2; +grant r2 to r1; +grant r1 to u1@`%`; +connect u1,127.0.0.1,u1,,,$MASTER_MYPORT; +set role r2; +ERROR OP000: User `u1`@`%` has not been granted role `r2` +disconnect u1; +connection default; +drop user u1@`%`; +drop role r1, r2; +# +# End of 10.2 tests +# diff --git a/mysql-test/suite/roles/set_default_role_for.result b/mysql-test/suite/roles/set_default_role_for.result index 62c31373486..2f6ad0a9f7f 100644 --- a/mysql-test/suite/roles/set_default_role_for.result +++ b/mysql-test/suite/roles/set_default_role_for.result @@ -14,7 +14,7 @@ set default role role_a for user_a@localhost; set default role invalid_role for user_a@localhost; ERROR OP000: Invalid role specification `invalid_role` set default role role_b for user_a@localhost; -ERROR OP000: User `user_a@localhost` has not been granted role `role_b` +ERROR OP000: User `root`@`localhost` has not been granted role `role_b` set default role role_b for user_b@localhost; show grants; Grants for user_a@localhost @@ -37,7 +37,7 @@ user host default_role user_a localhost role_a user_b localhost role_b set default role role_b for current_user; -ERROR OP000: User `user_a@localhost` has not been granted role `role_b` +ERROR OP000: User `user_a`@`localhost` has not been granted role `role_b` show grants; Grants for user_b@localhost GRANT role_b TO 'user_b'@'localhost' diff --git a/mysql-test/suite/roles/set_default_role_invalid.result b/mysql-test/suite/roles/set_default_role_invalid.result index 53ee464e2c1..c98e6e7d2a9 100644 --- a/mysql-test/suite/roles/set_default_role_invalid.result +++ b/mysql-test/suite/roles/set_default_role_invalid.result @@ -48,7 +48,7 @@ CREATE USER b; CREATE ROLE r1; CREATE ROLE r2; SET DEFAULT ROLE r1 FOR a; -ERROR OP000: User `a@%` has not been granted role `r1` +ERROR OP000: User `root`@`localhost` has not been granted role `r1` GRANT r1 TO b; GRANT r2 TO b; SET DEFAULT ROLE r1 FOR b; @@ -100,7 +100,7 @@ GRANT USAGE ON *.* TO 'b'@'%' GRANT SELECT, UPDATE ON `mysql`.* TO 'b'@'%' SET DEFAULT ROLE r2 FOR 'b'@'%' SET DEFAULT ROLE r1 FOR a; -ERROR OP000: User `a@%` has not been granted role `r1` +ERROR OP000: User `b`@`%` has not been granted role `r1` SET DEFAULT ROLE invalid_role; ERROR OP000: Invalid role specification `invalid_role` SET DEFAULT ROLE invalid_role FOR a; @@ -117,7 +117,7 @@ SET DEFAULT ROLE None; # Change user b (session 3: role granted to user a) SET DEFAULT ROLE r1 FOR a; SET DEFAULT ROLE r2 FOR a; -ERROR OP000: User `a@%` has not been granted role `r2` +ERROR OP000: User `b`@`%` has not been granted role `r2` SET DEFAULT ROLE invalid_role; ERROR OP000: Invalid role specification `invalid_role` SET DEFAULT ROLE invalid_role FOR a; diff --git a/mysql-test/suite/roles/set_role-recursive.result b/mysql-test/suite/roles/set_role-recursive.result index b0d79377183..fc5322a692e 100644 --- a/mysql-test/suite/roles/set_role-recursive.result +++ b/mysql-test/suite/roles/set_role-recursive.result @@ -66,7 +66,7 @@ Grants for test_user@localhost GRANT USAGE ON *.* TO 'test_user'@'localhost' GRANT test_role1 TO 'test_user'@'localhost' set role test_role2; -ERROR OP000: User `test_user@localhost` has not been granted role `test_role2` +ERROR OP000: User `test_user`@`localhost` has not been granted role `test_role2` select current_user(), current_role(); current_user() current_role() test_user@localhost NULL diff --git a/mysql-test/t/skip_name_resolve.test b/mysql-test/t/skip_name_resolve.test index b0c5118f970..0ff19092b82 100644 --- a/mysql-test/t/skip_name_resolve.test +++ b/mysql-test/t/skip_name_resolve.test @@ -50,4 +50,28 @@ SET @@LOCAL.skip_name_resolve=0; --error ER_INCORRECT_GLOBAL_LOCAL_VAR SET @@GLOBAL.skip_name_resolve=0; ---echo End of 5.1 tests +--echo # +--echo # End of 5.1 tests +--echo # + +--echo # +--echo # MDEV-26081 set role crashes when a hostname cannot be resolved +--echo # + +create user u1@`%`; +create role r1; +create role r2; +grant r2 to r1; +grant r1 to u1@`%`; + +connect u1,127.0.0.1,u1,,,$MASTER_MYPORT; +error ER_INVALID_ROLE; +set role r2; +disconnect u1; +connection default; +drop user u1@`%`; +drop role r1, r2; + +--echo # +--echo # End of 10.2 tests +--echo # diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 2b59a82277e..2d91254435a 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2732,7 +2732,6 @@ end: my_error(ER_INVALID_ROLE, MYF(0), rolename); break; case 1: - StringBuffer<1024> c_usr; LEX_CSTRING role_lex; /* First, check if current user can see mysql database. */ bool read_access= !check_access(thd, SELECT_ACL, "mysql", NULL, NULL, 1, 1); @@ -2753,11 +2752,9 @@ end: NULL) == -1)) { /* Role is not granted but current user can see the role */ - c_usr.append(user, strlen(user)); - c_usr.append('@'); - c_usr.append(host, strlen(host)); - my_printf_error(ER_INVALID_ROLE, "User %`s has not been granted role %`s", - MYF(0), c_usr.c_ptr(), rolename); + my_printf_error(ER_INVALID_ROLE, "User %`s@%`s has not been granted role %`s", + MYF(0), thd->security_ctx->priv_user, + thd->security_ctx->priv_host, rolename); } else { From cdb29960d2ed4dd8c51c3ee1f95c1ab0ff953142 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Thu, 20 May 2021 18:03:35 +0300 Subject: [PATCH 02/35] MDEV-17783: AddressSanitizer: stack-buffer-overflow in table_cond_selectivity A less-intrusive fix: don't have table_cond_selectivity() assume that there are less than MAX_REF_PARTS hash-join KEYUSEs. If there are more than that, switch to using an array. Allocate the array on the heap: we can't allocate it on MEM_ROOT as table_cond_selectivity() is called many times during the optimization. (Variant 2, with review input addressed) --- mysql-test/r/selectivity_innodb.result | 29 ++++++++++++++++++++++ mysql-test/t/selectivity_innodb.test | 34 ++++++++++++++++++++++++++ sql/sql_select.cc | 31 +++++++++++++++++++++-- 3 files changed, 92 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/selectivity_innodb.result b/mysql-test/r/selectivity_innodb.result index 5452919aa6d..23e0fcc9387 100644 --- a/mysql-test/r/selectivity_innodb.result +++ b/mysql-test/r/selectivity_innodb.result @@ -2103,6 +2103,35 @@ drop view v1; # # End of 10.1 tests # +# +# MDEV-17783: AddressSanitizer: stack-buffer-overflow in table_cond_selectivity +# +set +@tmp_jcl=@@join_cache_level, +@tmp_sel=@@optimizer_use_condition_selectivity; +set +join_cache_level=3, +optimizer_use_condition_selectivity=2; +CREATE TABLE t1 ( +c1 int, c2 int, c3 int, c4 int, c5 int, c6 int, c7 int, c8 int, c9 int, c10 int, +c11 int, c12 int, c13 int, c14 int, c15 int, c16 int, c17 int, c18 int, c19 int, +c20 int, c21 int, c22 int, c23 int, c24 int, c25 int, c26 int, c27 int, c28 int, +c29 int, c30 int, c31 int, c32 int, c33 int, c34 int +) ENGINE=InnoDB; +SELECT * FROM t1 +WHERE +(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, +c11, c12, c13, c14, c15, c16, c17, c18, c19, +c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, +c30, c31, c32, c33, c34) IN (SELECT * FROM t1) ; +c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 c31 c32 c33 c34 +set +join_cache_level=@tmp_jcl, +optimizer_use_condition_selectivity=@tmp_sel; +drop table t1; +# +# End of 10.1 tests +# set use_stat_tables= @tmp_ust; set optimizer_use_condition_selectivity= @tmp_oucs; set @@global.histogram_size=@save_histogram_size; diff --git a/mysql-test/t/selectivity_innodb.test b/mysql-test/t/selectivity_innodb.test index 6c457e2848b..eb05091e43a 100644 --- a/mysql-test/t/selectivity_innodb.test +++ b/mysql-test/t/selectivity_innodb.test @@ -174,6 +174,40 @@ drop view v1; --echo # End of 10.1 tests --echo # +--echo # +--echo # MDEV-17783: AddressSanitizer: stack-buffer-overflow in table_cond_selectivity +--echo # + +set + @tmp_jcl=@@join_cache_level, + @tmp_sel=@@optimizer_use_condition_selectivity; +set + join_cache_level=3, + optimizer_use_condition_selectivity=2; + +CREATE TABLE t1 ( + c1 int, c2 int, c3 int, c4 int, c5 int, c6 int, c7 int, c8 int, c9 int, c10 int, + c11 int, c12 int, c13 int, c14 int, c15 int, c16 int, c17 int, c18 int, c19 int, + c20 int, c21 int, c22 int, c23 int, c24 int, c25 int, c26 int, c27 int, c28 int, + c29 int, c30 int, c31 int, c32 int, c33 int, c34 int +) ENGINE=InnoDB; + +SELECT * FROM t1 +WHERE + (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, + c11, c12, c13, c14, c15, c16, c17, c18, c19, + c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, + c30, c31, c32, c33, c34) IN (SELECT * FROM t1) ; + +set + join_cache_level=@tmp_jcl, + optimizer_use_condition_selectivity=@tmp_sel; +drop table t1; + +--echo # +--echo # End of 10.1 tests +--echo # + set use_stat_tables= @tmp_ust; set optimizer_use_condition_selectivity= @tmp_oucs; set @@global.histogram_size=@save_histogram_size; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index fcdb671941d..362adc9853f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7943,7 +7943,9 @@ static double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s, table_map rem_tables) { - uint16 ref_keyuse_steps[MAX_REF_PARTS - 1]; + uint16 ref_keyuse_steps_buf[MAX_REF_PARTS]; + uint ref_keyuse_size= MAX_REF_PARTS; + uint16 *ref_keyuse_steps= ref_keyuse_steps_buf; Field *field; TABLE *table= s->table; MY_BITMAP *read_set= table->read_set; @@ -8090,6 +8092,29 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s, } if (keyparts > 1) { + /* + Prepare to set ref_keyuse_steps[keyparts-2]: resize the array + if it is not large enough + */ + if (keyparts - 2 >= ref_keyuse_size) + { + uint new_size= MY_MAX(ref_keyuse_size*2, keyparts); + void *new_buf; + if (!(new_buf= my_malloc(sizeof(*ref_keyuse_steps)*new_size, + MYF(0)))) + { + sel= 1.0; // As if no selectivity was computed + goto exit; + } + memcpy(new_buf, ref_keyuse_steps, + sizeof(*ref_keyuse_steps)*ref_keyuse_size); + if (ref_keyuse_steps != ref_keyuse_steps_buf) + my_free(ref_keyuse_steps); + + ref_keyuse_steps= (uint16*)new_buf; + ref_keyuse_size= new_size; + } + ref_keyuse_steps[keyparts-2]= (uint16)(keyuse - prev_ref_keyuse); prev_ref_keyuse= keyuse; } @@ -8144,7 +8169,9 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s, sel*= table_multi_eq_cond_selectivity(join, idx, s, rem_tables, keyparts, ref_keyuse_steps); - +exit: + if (ref_keyuse_steps != ref_keyuse_steps_buf) + my_free(ref_keyuse_steps); return sel; } From d4177a7e090aa78b96b5a308a159236450877250 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Thu, 20 May 2021 18:16:55 +0300 Subject: [PATCH 03/35] MDEV-23937: SIGSEGV in looped best_extension_by_limited_search from greedy_search Add a testcase (fixed by fix for MDEV-17783) --- mysql-test/r/selectivity_no_engine.result | 20 ++++++++++++++++++++ mysql-test/t/selectivity_no_engine.test | 21 +++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/mysql-test/r/selectivity_no_engine.result b/mysql-test/r/selectivity_no_engine.result index 7fc3c6e9909..74a52c9fed8 100644 --- a/mysql-test/r/selectivity_no_engine.result +++ b/mysql-test/r/selectivity_no_engine.result @@ -293,6 +293,26 @@ SELECT * FROM t1 WHERE t1.d = 0 AND t1.p = '1' AND t1.i != '-1' AND t1.n = 'some i n d p set optimizer_use_condition_selectivity= @tmp_mdev8779; DROP TABLE t1; +# +# MDEV-23937: SIGSEGV in looped best_extension_by_limited_search from greedy_search +# (Testcase only) +# +set +@tmp_jcl= @@join_cache_level, +@tmp_ucs= @@optimizer_use_condition_selectivity; +set +join_cache_level=3, +optimizer_use_condition_selectivity=2; +CREATE TABLE t1 AS SELECT * FROM mysql.user; +CREATE TABLE t3 (b VARCHAR (1)); +CREATE TABLE t2 (c2 INT); +INSERT INTO t2 VALUES (1); +EXPLAIN +SELECT * FROM t1 AS a NATURAL JOIN t1 AS b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE a ALL NULL NULL NULL NULL 4 +1 SIMPLE b hash_ALL NULL #hash#$hj 827 test.a.Host,test.a.User,test.a.Password,test.a.Select_priv,test.a.Insert_priv,test.a.Update_priv,test.a.Delete_priv,test.a.Create_priv,test.a.Drop_priv,test.a.Reload_priv,test.a.Shutdown_priv,test.a.Process_priv,test.a.File_priv,test.a.Grant_priv,test.a.References_priv,test.a.Index_priv,test.a.Alter_priv,test.a.Show_db_priv,test.a.Super_priv,test.a.Create_tmp_table_priv,test.a.Lock_tables_priv,test.a.Execute_priv,test.a.Repl_slave_priv,test.a.Repl_client_priv,test.a.Create_view_priv,test.a.Show_view_priv,test.a.Create_routine_priv,test.a.Alter_routine_priv,test.a.Create_user_priv,test.a.Event_priv,test.a.Trigger_priv,test.a.Create_tablespace_priv,test.a.ssl_type,test.a.ssl_cipher,test.a.x509_issuer,test.a.x509_subject,test.a.max_questions,test.a.max_updates,test.a.max_connections,test.a.max_user_connections,test.a.plugin,test.a.authentication_string,test.a.password_expired,test.a.is_role,test.a.default_role,test.a.max_statement_time 4 Using where; Using join buffer (flat, BNLH join) +DROP TABLE t1,t2,t3; # # End of the test file # diff --git a/mysql-test/t/selectivity_no_engine.test b/mysql-test/t/selectivity_no_engine.test index 345b7bd1e8a..b5f52dd167d 100644 --- a/mysql-test/t/selectivity_no_engine.test +++ b/mysql-test/t/selectivity_no_engine.test @@ -228,6 +228,27 @@ SELECT * FROM t1 WHERE t1.d = 0 AND t1.p = '1' AND t1.i != '-1' AND t1.n = 'some set optimizer_use_condition_selectivity= @tmp_mdev8779; DROP TABLE t1; +--echo # +--echo # MDEV-23937: SIGSEGV in looped best_extension_by_limited_search from greedy_search +--echo # (Testcase only) +--echo # +set + @tmp_jcl= @@join_cache_level, + @tmp_ucs= @@optimizer_use_condition_selectivity; +set + join_cache_level=3, + optimizer_use_condition_selectivity=2; + +CREATE TABLE t1 AS SELECT * FROM mysql.user; +CREATE TABLE t3 (b VARCHAR (1)); +CREATE TABLE t2 (c2 INT); +INSERT INTO t2 VALUES (1); + +EXPLAIN +SELECT * FROM t1 AS a NATURAL JOIN t1 AS b; + +DROP TABLE t1,t2,t3; + --echo # --echo # End of the test file --echo # From 99f700a820ef90b5b36ef765fb1532145ab3e907 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Sat, 3 Jul 2021 11:41:49 +0300 Subject: [PATCH 04/35] MDEV-25013: SIGSEGV in best_extension_by_limited_search | SIGSEGV in restore_prev_nj_state Add testcase --- mysql-test/r/selectivity_innodb.result | 22 ++++++++++++++++++++++ mysql-test/t/selectivity_innodb.test | 21 +++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/mysql-test/r/selectivity_innodb.result b/mysql-test/r/selectivity_innodb.result index 23e0fcc9387..bf240af3c47 100644 --- a/mysql-test/r/selectivity_innodb.result +++ b/mysql-test/r/selectivity_innodb.result @@ -2129,6 +2129,28 @@ set join_cache_level=@tmp_jcl, optimizer_use_condition_selectivity=@tmp_sel; drop table t1; +# +# MDEV-25013: SIGSEGV in best_extension_by_limited_search | SIGSEGV in restore_prev_nj_state +# +SET join_cache_level=3; +CREATE TABLE t1 ( +TEXT1 TEXT, TEXT2 TEXT, TEXT3 TEXT, TEXT4 TEXT, TEXT5 TEXT, +TEXT6 TEXT, TEXT7 TEXT, TEXT8 TEXT, TEXT9 TEXT, TEXT10 TEXT, +TEXT11 TEXT, TEXT12 TEXT,TEXT13 TEXT,TEXT14 TEXT,TEXT15 TEXT, +TEXT16 TEXT,TEXT17 TEXT,TEXT18 TEXT,TEXT19 TEXT,TEXT20 TEXT, +TEXT21 TEXT,TEXT22 TEXT,TEXT23 TEXT,TEXT24 TEXT,TEXT25 TEXT, +TEXT26 TEXT,TEXT27 TEXT,TEXT28 TEXT,TEXT29 TEXT,TEXT30 TEXT, +TEXT31 TEXT,TEXT32 TEXT,TEXT33 TEXT,TEXT34 TEXT,TEXT35 TEXT, +TEXT36 TEXT,TEXT37 TEXT,TEXT38 TEXT,TEXT39 TEXT,TEXT40 TEXT, +TEXT41 TEXT,TEXT42 TEXT,TEXT43 TEXT,TEXT44 TEXT,TEXT45 TEXT, +TEXT46 TEXT,TEXT47 TEXT,TEXT48 TEXT,TEXT49 TEXT,TEXT50 TEXT +) ENGINE=InnoDB; +EXPLAIN SELECT 1 FROM t1 NATURAL JOIN t1 AS t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 1 Using where +1 SIMPLE t2 hash_ALL NULL #hash#$hj 150 test.t1.TEXT1,test.t1.TEXT2,test.t1.TEXT3,test.t1.TEXT4,test.t1.TEXT5,test.t1.TEXT6,test.t1.TEXT7,test.t1.TEXT8,test.t1.TEXT9,test.t1.TEXT10,test.t1.TEXT11,test.t1.TEXT12,test.t1.TEXT13,test.t1.TEXT14,test.t1.TEXT15,test.t1.TEXT16,test.t1.TEXT17,test.t1.TEXT18,test.t1.TEXT19,test.t1.TEXT20,test.t1.TEXT21,test.t1.TEXT22,test.t1.TEXT23,test.t1.TEXT24,test.t1.TEXT25,test.t1.TEXT26,test.t1.TEXT27,test.t1.TEXT28,test.t1.TEXT29,test.t1.TEXT30,test.t1.TEXT31,test.t1.TEXT32,test.t1.TEXT33,test.t1.TEXT34,test.t1.TEXT35,test.t1.TEXT36,test.t1.TEXT37,test.t1.TEXT38,test.t1.TEXT39,test.t1.TEXT40,test.t1.TEXT41,test.t1.TEXT42,test.t1.TEXT43,test.t1.TEXT44,test.t1.TEXT45,test.t1.TEXT46,test.t1.TEXT47,test.t1.TEXT48,test.t1.TEXT49,test.t1.TEXT50 1 Using where; Using join buffer (flat, BNLH join) +set join_cache_level=@tmp_jcl; +drop table t1; # # End of 10.1 tests # diff --git a/mysql-test/t/selectivity_innodb.test b/mysql-test/t/selectivity_innodb.test index eb05091e43a..057a36fcf62 100644 --- a/mysql-test/t/selectivity_innodb.test +++ b/mysql-test/t/selectivity_innodb.test @@ -204,6 +204,27 @@ set optimizer_use_condition_selectivity=@tmp_sel; drop table t1; +--echo # +--echo # MDEV-25013: SIGSEGV in best_extension_by_limited_search | SIGSEGV in restore_prev_nj_state +--echo # + +SET join_cache_level=3; +CREATE TABLE t1 ( + TEXT1 TEXT, TEXT2 TEXT, TEXT3 TEXT, TEXT4 TEXT, TEXT5 TEXT, + TEXT6 TEXT, TEXT7 TEXT, TEXT8 TEXT, TEXT9 TEXT, TEXT10 TEXT, + TEXT11 TEXT, TEXT12 TEXT,TEXT13 TEXT,TEXT14 TEXT,TEXT15 TEXT, + TEXT16 TEXT,TEXT17 TEXT,TEXT18 TEXT,TEXT19 TEXT,TEXT20 TEXT, + TEXT21 TEXT,TEXT22 TEXT,TEXT23 TEXT,TEXT24 TEXT,TEXT25 TEXT, + TEXT26 TEXT,TEXT27 TEXT,TEXT28 TEXT,TEXT29 TEXT,TEXT30 TEXT, + TEXT31 TEXT,TEXT32 TEXT,TEXT33 TEXT,TEXT34 TEXT,TEXT35 TEXT, + TEXT36 TEXT,TEXT37 TEXT,TEXT38 TEXT,TEXT39 TEXT,TEXT40 TEXT, + TEXT41 TEXT,TEXT42 TEXT,TEXT43 TEXT,TEXT44 TEXT,TEXT45 TEXT, + TEXT46 TEXT,TEXT47 TEXT,TEXT48 TEXT,TEXT49 TEXT,TEXT50 TEXT +) ENGINE=InnoDB; +EXPLAIN SELECT 1 FROM t1 NATURAL JOIN t1 AS t2; + +set join_cache_level=@tmp_jcl; +drop table t1; --echo # --echo # End of 10.1 tests --echo # From 22e4baaa5d073f46a3b139bbd40d2dba287eb84f Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 5 May 2021 20:14:27 +0300 Subject: [PATCH 05/35] MDEV-25595 DROP part of failed CREATE OR REPLACE is not written into binary log Do log_drop_table() in case of failed mysql_prepare_create_table(). --- mysql-test/extra/binlog_tests/binlog.test | 18 ++++++++++++++ .../suite/binlog/r/binlog_row_binlog.result | 23 ++++++++++++++++++ .../suite/binlog/r/binlog_stm_binlog.result | 24 +++++++++++++++++++ .../suite/rpl/r/create_or_replace_mix.result | 3 +++ .../suite/rpl/r/create_or_replace_row.result | 3 +++ .../rpl/r/create_or_replace_statement.result | 2 ++ sql/sql_insert.cc | 10 ++++++++ 7 files changed, 83 insertions(+) diff --git a/mysql-test/extra/binlog_tests/binlog.test b/mysql-test/extra/binlog_tests/binlog.test index 8fe710e2ac7..f982b87aae7 100644 --- a/mysql-test/extra/binlog_tests/binlog.test +++ b/mysql-test/extra/binlog_tests/binlog.test @@ -408,4 +408,22 @@ SHOW SESSION VARIABLES LIKE "unique_checks"; DROP TABLE t1; disconnect fresh; +connection default; +--echo # +--echo # MDEV-25595 DROP part of failed CREATE OR REPLACE is not written into binary log +--echo # +reset master; +--error ER_DUP_FIELDNAME +create table t as select 1 as b, 2 as b; +create table t (old_table_field int); +--error ER_DUP_FIELDNAME +create or replace table t as select 1 as b, 2 as b; +--error ER_DUP_FIELDNAME +create or replace temporary table t as select 1 as b, 2 as b; +create table t (new_table_field int); + +--source include/show_binlog_events.inc + +# cleanup +drop table t; diff --git a/mysql-test/suite/binlog/r/binlog_row_binlog.result b/mysql-test/suite/binlog/r/binlog_row_binlog.result index 4068a80771c..948ccee58ca 100644 --- a/mysql-test/suite/binlog/r/binlog_row_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_row_binlog.result @@ -1073,3 +1073,26 @@ Variable_name Value unique_checks OFF DROP TABLE t1; disconnect fresh; +connection default; +# +# MDEV-25595 DROP part of failed CREATE OR REPLACE is not written into binary log +# +reset master; +create table t as select 1 as b, 2 as b; +ERROR 42S21: Duplicate column name 'b' +create table t (old_table_field int); +create or replace table t as select 1 as b, 2 as b; +ERROR 42S21: Duplicate column name 'b' +create or replace temporary table t as select 1 as b, 2 as b; +ERROR 42S21: Duplicate column name 'b' +create table t (new_table_field int); +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; create table t (old_table_field int) +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS `test`.`t`/* Generated to handle failed CREATE OR REPLACE */ +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; create table t (new_table_field int) +drop table t; diff --git a/mysql-test/suite/binlog/r/binlog_stm_binlog.result b/mysql-test/suite/binlog/r/binlog_stm_binlog.result index 872ba40e05f..5016ed70242 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_stm_binlog.result @@ -673,3 +673,27 @@ Variable_name Value unique_checks OFF DROP TABLE t1; disconnect fresh; +connection default; +# +# MDEV-25595 DROP part of failed CREATE OR REPLACE is not written into binary log +# +reset master; +create table t as select 1 as b, 2 as b; +ERROR 42S21: Duplicate column name 'b' +create table t (old_table_field int); +create or replace table t as select 1 as b, 2 as b; +ERROR 42S21: Duplicate column name 'b' +create or replace temporary table t as select 1 as b, 2 as b; +ERROR 42S21: Duplicate column name 'b' +create table t (new_table_field int); +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; create table t (old_table_field int) +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS `test`.`t`/* Generated to handle failed CREATE OR REPLACE */ +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # DROP TEMPORARY TABLE IF EXISTS `test`.`t`/* Generated to handle failed CREATE OR REPLACE */ +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; create table t (new_table_field int) +drop table t; diff --git a/mysql-test/suite/rpl/r/create_or_replace_mix.result b/mysql-test/suite/rpl/r/create_or_replace_mix.result index 661278aa7ef..b44b2a5c10f 100644 --- a/mysql-test/suite/rpl/r/create_or_replace_mix.result +++ b/mysql-test/suite/rpl/r/create_or_replace_mix.result @@ -100,6 +100,9 @@ include/show_binlog_events.inc Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Gtid # # GTID #-#-# master-bin.000001 # Query # # use `test`; create table t1 (a int) +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS `test`.`t1`/* Generated to handle failed CREATE OR REPLACE */ +master-bin.000001 # Query # # ROLLBACK drop table if exists t1,t2; Warnings: Note 1051 Unknown table 'test.t1' diff --git a/mysql-test/suite/rpl/r/create_or_replace_row.result b/mysql-test/suite/rpl/r/create_or_replace_row.result index c45daefd671..16f92b5e4b6 100644 --- a/mysql-test/suite/rpl/r/create_or_replace_row.result +++ b/mysql-test/suite/rpl/r/create_or_replace_row.result @@ -128,6 +128,9 @@ include/show_binlog_events.inc Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Gtid # # GTID #-#-# master-bin.000001 # Query # # use `test`; create table t1 (a int) +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS `test`.`t1`/* Generated to handle failed CREATE OR REPLACE */ +master-bin.000001 # Query # # ROLLBACK drop table if exists t1,t2; Warnings: Note 1051 Unknown table 'test.t1' diff --git a/mysql-test/suite/rpl/r/create_or_replace_statement.result b/mysql-test/suite/rpl/r/create_or_replace_statement.result index f95b451e5ec..4d6409b1710 100644 --- a/mysql-test/suite/rpl/r/create_or_replace_statement.result +++ b/mysql-test/suite/rpl/r/create_or_replace_statement.result @@ -103,6 +103,8 @@ include/show_binlog_events.inc Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Gtid # # GTID #-#-# master-bin.000001 # Query # # use `test`; create table t1 (a int) +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS `test`.`t1`/* Generated to handle failed CREATE OR REPLACE */ drop table if exists t1,t2; Warnings: Note 1051 Unknown table 'test.t1' diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 90cf8782d48..51b2c84cfea 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -4386,8 +4386,18 @@ select_create::prepare(List &values, SELECT_LEX_UNIT *u) create_table, alter_info, &values, &extra_lock, hook_ptr))) + { + if (create_info->or_replace()) + { + /* Original table was deleted. We have to log it */ + log_drop_table(thd, create_table->db, create_table->db_length, + create_table->table_name, create_table->table_name_length, + thd->lex->tmp_table()); + } + /* abort() deletes table */ DBUG_RETURN(-1); + } if (create_info->tmp_table()) { From 6a466db00ab5656bfc091f81abf363b00248d1f8 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 5 Jul 2021 22:02:23 +0200 Subject: [PATCH 06/35] MDEV-25857 MTR should report at least last test that was executed in case of shutdown and not-completed * return a success/failure value from mysqld_start() and don't error out / exit in mysqld_start(), the caller will do * pass the correct $mysqld object into check_expected_crash_and_restart() instead of searching for it inside. Search in the caller * so that when a failed restart changes $mysqld->{proc}, mtr would still detect it as a failed mysqld (by updating $proc to match) also: log the server command line into the server error log --- mysql-test/mysql-test-run.pl | 104 ++++++++++++++++------------------- 1 file changed, 47 insertions(+), 57 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 5e46cfe8eff..a91bdc0b751 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2820,7 +2820,9 @@ sub mysql_server_start($) { if (!$opt_embedded_server) { - mysqld_start($mysqld,$extra_opts); + mysqld_start($mysqld, $extra_opts) or + mtr_error("Failed to start mysqld ".$mysqld->name()." with command " + . $ENV{MYSQLD_LAST_CMD}); # Save this test case information, so next can examine it $mysqld->{'started_tinfo'}= $tinfo; @@ -4135,9 +4137,12 @@ sub run_testcase ($$) { # ---------------------------------------------------- # Check if it was an expected crash # ---------------------------------------------------- - my $check_crash = check_expected_crash_and_restart($wait_for_proc); + my @mysqld = grep($wait_for_proc eq $_->{proc}, mysqlds()); + goto SRVDIED unless @mysqld; + my $check_crash = check_expected_crash_and_restart($mysqld[0]); if ($check_crash == 0) # unexpected exit/crash of $wait_for_proc { + $proc= $mysqld[0]->{proc}; goto SRVDIED; } elsif ($check_crash == 1) # $wait_for_proc was started again by check_expected_crash_and_restart() @@ -4695,61 +4700,52 @@ sub check_warnings_post_shutdown { } # -# Loop through our list of processes and look for and entry -# with the provided pid, if found check for the file indicating -# expected crash and restart it. +# Check for the file indicating expected crash and restart it. # sub check_expected_crash_and_restart { - my ($proc)= @_; + my $mysqld = shift; - foreach my $mysqld ( mysqlds() ) + # Check if crash expected by looking at the .expect file + # in var/tmp + my $expect_file= "$opt_vardir/tmp/".$mysqld->name().".expect"; + if ( -f $expect_file ) { - next unless ( $mysqld->{proc} and $mysqld->{proc} eq $proc ); + mtr_verbose("Crash was expected, file '$expect_file' exists"); - # Check if crash expected by looking at the .expect file - # in var/tmp - my $expect_file= "$opt_vardir/tmp/".$mysqld->name().".expect"; - if ( -f $expect_file ) + for (my $waits = 0; $waits < 50; mtr_milli_sleep(100), $waits++) { - mtr_verbose("Crash was expected, file '$expect_file' exists"); - - for (my $waits = 0; $waits < 50; mtr_milli_sleep(100), $waits++) + # Race condition seen on Windows: try again until file not empty + next if -z $expect_file; + # If last line in expect file starts with "wait" + # sleep a little and try again, thus allowing the + # test script to control when the server should start + # up again. Keep trying for up to 5s at a time. + my $last_line= mtr_lastlinesfromfile($expect_file, 1); + if ($last_line =~ /^wait/ ) { - # Race condition seen on Windows: try again until file not empty - next if -z $expect_file; - # If last line in expect file starts with "wait" - # sleep a little and try again, thus allowing the - # test script to control when the server should start - # up again. Keep trying for up to 5s at a time. - my $last_line= mtr_lastlinesfromfile($expect_file, 1); - if ($last_line =~ /^wait/ ) - { - mtr_verbose("Test says wait before restart") if $waits == 0; - next; - } - - # Ignore any partial or unknown command - next unless $last_line =~ /^restart/; - # If last line begins "restart:", the rest of the line is read as - # extra command line options to add to the restarted mysqld. - # Anything other than 'wait' or 'restart:' (with a colon) will - # result in a restart with original mysqld options. - if ($last_line =~ /restart:(.+)/) { - my @rest_opt= split(' ', $1); - $mysqld->{'restart_opts'}= \@rest_opt; - } else { - delete $mysqld->{'restart_opts'}; - } - unlink($expect_file); - - # Start server with same settings as last time - mysqld_start($mysqld, $mysqld->{'started_opts'}); - - return 1; + mtr_verbose("Test says wait before restart") if $waits == 0; + next; } - # Loop ran through: we should keep waiting after a re-check - return 2; + + # Ignore any partial or unknown command + next unless $last_line =~ /^restart/; + # If last line begins "restart:", the rest of the line is read as + # extra command line options to add to the restarted mysqld. + # Anything other than 'wait' or 'restart:' (with a colon) will + # result in a restart with original mysqld options. + if ($last_line =~ /restart:(.+)/) { + my @rest_opt= split(' ', $1); + $mysqld->{'restart_opts'}= \@rest_opt; + } else { + delete $mysqld->{'restart_opts'}; + } + unlink($expect_file); + + # Start server with same settings as last time + return mysqld_start($mysqld, $mysqld->{'started_opts'}); } + # Loop ran through: we should keep waiting after a re-check + return 2; } # Not an expected crash @@ -5106,6 +5102,7 @@ sub mysqld_start ($$) { if ( defined $exe ) { + mtr_tofile($output, "\$ $exe @$args\n"); pre_write_errorlog($output); $mysqld->{'proc'}= My::SafeProcess->new ( @@ -5124,17 +5121,10 @@ sub mysqld_start ($$) { mtr_verbose("Started $mysqld->{proc}"); } - if (!sleep_until_file_created($mysqld->value('pid-file'), - $opt_start_timeout, $mysqld->{'proc'}, $warn_seconds)) - { - my $mname= $mysqld->name(); - mtr_error("Failed to start mysqld $mname with command $exe"); - } - - # Remember options used when starting $mysqld->{'started_opts'}= $extra_opts; - return; + return sleep_until_file_created($mysqld->value('pid-file'), + $opt_start_timeout, $mysqld->{'proc'}, $warn_seconds); } From 1223cfe1d3d72598e788582701989f9bb35695fb Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 5 Jul 2021 21:46:00 +0200 Subject: [PATCH 07/35] MDEV-25802 mtr: race condition if the test quickly restarts twice expect file is always removed before starting a server. So if it exists here, it means the server started successfully, mysqltest continued executing the test, created a new expect file, and shut down the server. All while we were waiting for the server to start. In other words, if the expect file exists, the server did actually start. Even if it isn't running now. This fixes occasional failures of innodb.log_corruption (in 10.6) --- mysql-test/lib/mtr_process.pl | 6 ++++-- mysql-test/mysql-test-run.pl | 11 ++++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index cee9f2b6ed6..c568f8dc48c 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -40,7 +40,7 @@ BEGIN eval 'sub USE_NETPING { $use_netping }'; } -sub sleep_until_file_created ($$$$); +sub sleep_until_file_created ($$$$$); sub mtr_ping_port ($); sub mtr_ping_port ($) { @@ -102,8 +102,9 @@ sub mtr_ping_port ($) { # FIXME check that the pidfile contains the expected pid! -sub sleep_until_file_created ($$$$) { +sub sleep_until_file_created ($$$$$) { my $pidfile= shift; + my $expectfile = shift; my $timeout= shift; my $proc= shift; my $warn_seconds = shift; @@ -122,6 +123,7 @@ sub sleep_until_file_created ($$$$) { # Check if it died after the fork() was successful if ( defined $proc and ! $proc->wait_one(0) ) { + return 1 if -r $expectfile; mtr_warning("Process $proc died after mysql-test-run waited $seconds " . "seconds for $pidfile to be created."); return 0; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index a91bdc0b751..29aaebd44b0 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2845,11 +2845,11 @@ sub mysql_server_start($) { sub mysql_server_wait { my ($mysqld, $tinfo) = @_; + my $expect_file= "$opt_vardir/tmp/".$mysqld->name().".expect"; - if (!sleep_until_file_created($mysqld->value('pid-file'), - $opt_start_timeout, - $mysqld->{'proc'}, - $warn_seconds)) + if (!sleep_until_file_created($mysqld->value('pid-file'), $expect_file, + $opt_start_timeout, $mysqld->{'proc'}, + $warn_seconds)) { $tinfo->{comment}= "Failed to start ".$mysqld->name() . "\n"; return 1; @@ -5123,7 +5123,8 @@ sub mysqld_start ($$) { $mysqld->{'started_opts'}= $extra_opts; - return sleep_until_file_created($mysqld->value('pid-file'), + my $expect_file= "$opt_vardir/tmp/".$mysqld->name().".expect"; + return sleep_until_file_created($mysqld->value('pid-file'), $expect_file, $opt_start_timeout, $mysqld->{'proc'}, $warn_seconds); } From 621fae3cbc79eb4d0277c40993328faa4019e95f Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 6 Jul 2021 11:36:59 +0200 Subject: [PATCH 08/35] MDEV-25802 mtr: race condition if the test quickly restarts twice part II need to tell SafeProcess not to collect the exited mysqld in sleep_until_file_created(), so that it would be found in the later wait_any_timeout() in run_testcase() Removed a strange condition in SafeProcess::wait_one() that treated return value of -1 from waitpid() as "process exists" instead of as "no such child process" (see `perldoc -f waitpid`) --- mysql-test/lib/My/SafeProcess.pm | 18 +++++++++--------- mysql-test/lib/mtr_process.pl | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/mysql-test/lib/My/SafeProcess.pm b/mysql-test/lib/My/SafeProcess.pm index 4f7464daf44..30c8fe54642 100644 --- a/mysql-test/lib/My/SafeProcess.pm +++ b/mysql-test/lib/My/SafeProcess.pm @@ -395,10 +395,10 @@ sub _collect { # 1 Still running # sub wait_one { - my ($self, $timeout)= @_; - croak "usage: \$safe_proc->wait_one([timeout])" unless ref $self; + my ($self, $timeout, $keep)= @_; + croak "usage: \$safe_proc->wait_one([timeout] [, keep])" unless ref $self; - _verbose("wait_one $self, $timeout"); + _verbose("wait_one $self, $timeout, $keep"); if ( ! defined($self->{SAFE_PID}) ) { # No pid => not running @@ -472,16 +472,16 @@ sub wait_one { return 1; } - if ( not $blocking and $retpid == -1 ) { - # still running - _verbose("still running"); - return 1; - } + #if ( not $blocking and $retpid == -1 ) { + # # still running + # _verbose("still running"); + # return 1; + #} #warn "wait_one: expected pid $pid but got $retpid" # unless( $retpid == $pid ); - $self->_collect($exit_code); + $self->_collect($exit_code) unless $keep; return 0; } diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index c568f8dc48c..2ff78c0e10a 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -121,7 +121,7 @@ sub sleep_until_file_created ($$$$$) { my $seconds= ($loop * $sleeptime) / 1000; # Check if it died after the fork() was successful - if ( defined $proc and ! $proc->wait_one(0) ) + if ( defined $proc and ! $proc->wait_one(0, 1) ) { return 1 if -r $expectfile; mtr_warning("Process $proc died after mysql-test-run waited $seconds " . From 83e442fc34e53f214a37f747e25656bf92785bd3 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Tue, 6 Jul 2021 14:38:32 -0700 Subject: [PATCH 09/35] MDEV-26095 Infinite recursion when processing embedded recursive CTE with missing RECURSIVE If a table reference r used inthe specification of a CTE whose definition is contained in the WITH clause where RECURSIVE is omitted then this table reference cannot be considered as a recursive table reference even if it is used in the query that specifies CTE whose name is r. It can be considered only as a reference to an embedding CTE or to a temporary table or to a base table/view. If there is no such object with name r then an error message must be reported. This patch fixes the code that actually in some cases resolved r as a reference to the CTE whose specification contained r if its name was r in spite of the fact that r was not considered as a recursive CTE. This happened in the cases when the definition of r was used in the specification of another CTE. Such wrong name resolution for r led to an infinite recursive invocations of the parser that ultimately crashed the server. This bug is a result of the fix for mdev-13780 that was not quite correct. Approved by Oleksandr Byelkin --- mysql-test/r/cte_nonrecursive.result | 25 +++++++++++++++++++++++++ mysql-test/t/cte_nonrecursive.test | 23 +++++++++++++++++++++++ sql/sql_cte.cc | 4 +++- 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/cte_nonrecursive.result b/mysql-test/r/cte_nonrecursive.result index c1d7fd0a615..5cc5a2503e3 100644 --- a/mysql-test/r/cte_nonrecursive.result +++ b/mysql-test/r/cte_nonrecursive.result @@ -2019,4 +2019,29 @@ drop procedure sp1; drop procedure sp2; drop procedure sp3; drop table t1; +# +# MDEV-26095: missing RECURSIVE for the recursive definition of CTE +# embedded into another CTE definition +# +create table t1 (a int); +insert into t1 values (5), (7); +with cte_e as ( +with recursive cte_r as ( +select a from t1 union select a+1 as a from cte_r r where a < 10 +) select * from cte_r +) select * from cte_e; +a +5 +7 +6 +8 +9 +10 +with cte_e as ( +with cte_r as ( +select a from t1 union select a+1 as a from cte_r r where a < 10 +) select * from cte_r +) select * from cte_e; +ERROR 42S02: Table 'test.cte_r' doesn't exist +drop table t1; # End of 10.2 tests diff --git a/mysql-test/t/cte_nonrecursive.test b/mysql-test/t/cte_nonrecursive.test index cbe4f8b855d..68dbc0cac19 100644 --- a/mysql-test/t/cte_nonrecursive.test +++ b/mysql-test/t/cte_nonrecursive.test @@ -1492,4 +1492,27 @@ drop procedure sp3; drop table t1; +--echo # +--echo # MDEV-26095: missing RECURSIVE for the recursive definition of CTE +--echo # embedded into another CTE definition +--echo # + +create table t1 (a int); +insert into t1 values (5), (7); + +with cte_e as ( + with recursive cte_r as ( + select a from t1 union select a+1 as a from cte_r r where a < 10 + ) select * from cte_r +) select * from cte_e; + +--ERROR ER_NO_SUCH_TABLE +with cte_e as ( + with cte_r as ( + select a from t1 union select a+1 as a from cte_r r where a < 10 + ) select * from cte_r +) select * from cte_e; + +drop table t1; + --echo # End of 10.2 tests diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc index 9dad33d5b71..702db8f96d9 100644 --- a/sql/sql_cte.cc +++ b/sql/sql_cte.cc @@ -1256,6 +1256,7 @@ bool With_element::is_anchor(st_select_lex *sel) With_element *st_select_lex::find_table_def_in_with_clauses(TABLE_LIST *table) { With_element *found= NULL; + With_clause *containing_with_clause= NULL; st_select_lex_unit *master_unit; st_select_lex *outer_sl; for (st_select_lex *sl= this; sl; sl= outer_sl) @@ -1268,6 +1269,7 @@ With_element *st_select_lex::find_table_def_in_with_clauses(TABLE_LIST *table) */ With_clause *attached_with_clause= sl->get_with_clause(); if (attached_with_clause && + attached_with_clause != containing_with_clause && (found= attached_with_clause->find_table_def(table, NULL))) break; master_unit= sl->master_unit(); @@ -1275,7 +1277,7 @@ With_element *st_select_lex::find_table_def_in_with_clauses(TABLE_LIST *table) With_element *with_elem= sl->get_with_element(); if (with_elem) { - With_clause *containing_with_clause= with_elem->get_owner(); + containing_with_clause= with_elem->get_owner(); With_element *barrier= containing_with_clause->with_recursive ? NULL : with_elem; if ((found= containing_with_clause->find_table_def(table, barrier))) From d2dddbff4e6f04ececb2c192f2d8725f128f2ba8 Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Fri, 2 Jul 2021 15:11:25 +0200 Subject: [PATCH 10/35] MDEV-26080: SHOW GRANTS does not quote role names properly for DEFAULT ROLE - Used single quotes, back quotes are used with commit fafb35ee517f309d9e507f6e3908caca5d8cd257 in 10.3 and will be changed. Reviewed by: serg@mariadb.org --- mysql-test/r/grant5.result | 45 +++++-- mysql-test/r/mysql_upgrade.result | 6 +- mysql-test/r/mysqldump-system.result | 24 ++-- mysql-test/suite/roles/admin.result | 44 +++---- .../suite/roles/create_and_drop_role.result | 2 +- .../suite/roles/create_and_grant_role.result | 2 +- mysql-test/suite/roles/definer.result | 2 +- mysql-test/suite/roles/drop_routines.result | 14 +-- .../suite/roles/flush_roles-17898.result | 4 +- mysql-test/suite/roles/grant-5771.result | 4 +- mysql-test/suite/roles/grant_empty.result | 2 +- .../suite/roles/grant_revoke_current.result | 4 +- mysql-test/suite/roles/ip-6401.result | 2 +- .../suite/roles/prepare_stmt_with_role.result | 8 +- .../suite/roles/rebuild_role_grants.result | 6 +- mysql-test/suite/roles/recursive.result | 112 +++++++++--------- mysql-test/suite/roles/recursive_dbug.result | 112 +++++++++--------- mysql-test/suite/roles/revoke_all.result | 50 ++++---- .../roles/role_case_sensitive-10744.result | 6 +- mysql-test/suite/roles/rpl_definer.result | 12 +- mysql-test/suite/roles/set_and_drop.result | 2 +- .../suite/roles/set_default_role_clear.result | 6 +- .../suite/roles/set_default_role_for.result | 10 +- .../roles/set_default_role_invalid.result | 18 +-- .../set_default_role_new_connection.result | 12 +- mysql-test/suite/roles/set_role-13655.result | 6 +- mysql-test/suite/roles/set_role-9614.result | 6 +- .../roles/set_role-database-recursive.result | 10 +- .../suite/roles/set_role-multiple-role.result | 42 +++---- .../suite/roles/set_role-recursive.result | 28 ++--- .../roles/set_role-routine-simple.result | 18 +-- mysql-test/suite/roles/set_role-simple.result | 4 +- .../roles/set_role-table-column-priv.result | 10 +- .../suite/roles/set_role-table-simple.result | 10 +- mysql-test/suite/roles/show_grants.result | 44 +++---- .../suite/roles/show_grants_replicated.result | 2 +- mysql-test/t/grant5.test | 23 ++++ sql/sql_acl.cc | 8 +- 38 files changed, 387 insertions(+), 333 deletions(-) diff --git a/mysql-test/r/grant5.result b/mysql-test/r/grant5.result index a69070e8399..3b16d033f5e 100644 --- a/mysql-test/r/grant5.result +++ b/mysql-test/r/grant5.result @@ -8,7 +8,7 @@ connect conn_1, localhost, test,,; set role foo; show grants for test; Grants for test@% -GRANT foo TO 'test'@'%' +GRANT 'foo' TO 'test'@'%' GRANT USAGE ON *.* TO 'test'@'%' show grants for foo; Grants for foo @@ -45,29 +45,60 @@ GRANT test_role TO test_user; SET DEFAULT ROLE test_role FOR test_user; SHOW GRANTS FOR test_user; Grants for test_user@% -GRANT test_role TO 'test_user'@'%' +GRANT 'test_role' TO 'test_user'@'%' GRANT USAGE ON *.* TO 'test_user'@'%' -SET DEFAULT ROLE test_role FOR 'test_user'@'%' +SET DEFAULT ROLE 'test_role' FOR 'test_user'@'%' SET DEFAULT ROLE NONE for test_user; SHOW GRANTS FOR test_user; Grants for test_user@% -GRANT test_role TO 'test_user'@'%' +GRANT 'test_role' TO 'test_user'@'%' GRANT USAGE ON *.* TO 'test_user'@'%' SET ROLE test_role; SET DEFAULT ROLE test_role; SHOW GRANTS; Grants for root@localhost -GRANT test_role TO 'root'@'localhost' WITH ADMIN OPTION +GRANT 'test_role' TO 'root'@'localhost' WITH ADMIN OPTION GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION GRANT USAGE ON *.* TO 'test_role' -SET DEFAULT ROLE test_role FOR 'root'@'localhost' +SET DEFAULT ROLE 'test_role' FOR 'root'@'localhost' SET DEFAULT ROLE NONE; SHOW GRANTS; Grants for root@localhost -GRANT test_role TO 'root'@'localhost' WITH ADMIN OPTION +GRANT 'test_role' TO 'root'@'localhost' WITH ADMIN OPTION GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION GRANT USAGE ON *.* TO 'test_role' DROP USER test_user; DROP ROLE test_role; +CREATE ROLE 'test-role'; +CREATE USER 'test-user'; +GRANT 'test-role' TO 'test-user'; +SET DEFAULT ROLE 'test-role' FOR 'test-user'; +SHOW GRANTS FOR 'test-user'; +Grants for test-user@% +GRANT 'test-role' TO 'test-user'@'%' +GRANT USAGE ON *.* TO 'test-user'@'%' +SET DEFAULT ROLE 'test-role' FOR 'test-user'@'%' +DROP ROLE 'test-role'; +SHOW GRANTS FOR 'test-user'; +Grants for test-user@% +GRANT USAGE ON *.* TO 'test-user'@'%' +SET DEFAULT ROLE 'test-role' FOR 'test-user'@'%' +SET DEFAULT ROLE NONE FOR 'test-user'; +SHOW GRANTS FOR 'test-user'; +Grants for test-user@% +GRANT USAGE ON *.* TO 'test-user'@'%' +CREATE ROLE `r``o'l"e`; +select user from mysql.user where is_role='Y'; +user +r`o'l"e +GRANT `r``o'l"e` TO 'test-user'; +SET DEFAULT ROLE `r``o'l"e` FOR 'test-user'; +SHOW GRANTS FOR 'test-user'; +Grants for test-user@% +GRANT 'r`o'l"e' TO 'test-user'@'%' +GRANT USAGE ON *.* TO 'test-user'@'%' +SET DEFAULT ROLE 'r`o'l"e' FOR 'test-user'@'%' +DROP ROLE `r``o'l"e`; +DROP USER 'test-user'; diff --git a/mysql-test/r/mysql_upgrade.result b/mysql-test/r/mysql_upgrade.result index 3961c7e8c27..79c15984a12 100644 --- a/mysql-test/r/mysql_upgrade.result +++ b/mysql-test/r/mysql_upgrade.result @@ -840,15 +840,15 @@ CREATE ROLE `aRole`; SET DEFAULT ROLE aRole; SHOW GRANTS; Grants for root@localhost -GRANT aRole TO 'root'@'localhost' WITH ADMIN OPTION +GRANT 'aRole' TO 'root'@'localhost' WITH ADMIN OPTION GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION GRANT USAGE ON *.* TO 'aRole' -SET DEFAULT ROLE aRole FOR 'root'@'localhost' +SET DEFAULT ROLE 'aRole' FOR 'root'@'localhost' SET DEFAULT ROLE NONE; SHOW GRANTS; Grants for root@localhost -GRANT aRole TO 'root'@'localhost' WITH ADMIN OPTION +GRANT 'aRole' TO 'root'@'localhost' WITH ADMIN OPTION GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION GRANT USAGE ON *.* TO 'aRole' diff --git a/mysql-test/r/mysqldump-system.result b/mysql-test/r/mysqldump-system.result index 74cfc4e9882..7746417715f 100644 --- a/mysql-test/r/mysqldump-system.result +++ b/mysql-test/r/mysqldump-system.result @@ -61,17 +61,17 @@ SET ROLE mariadb_dump_import_role; /*!80001 CREATE ROLE 'role_2' */; /*M!100005 CREATE ROLE 'role_2' WITH ADMIN mariadb_dump_import_role */; /*M!100005 GRANT 'role_2' TO 'role_1' WITH ADMIN OPTION */; -GRANT role_1 TO 'root'@'localhost' WITH ADMIN OPTION; +GRANT 'role_1' TO 'root'@'localhost' WITH ADMIN OPTION; GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION; GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION; /*M!100005 SET DEFAULT ROLE NONE FOR 'root'@'localhost' */; /*!80001 ALTER USER 'root'@'localhost' DEFAULT ROLE NONE */; -GRANT role_1 TO 'USER'@'%'; -GRANT role_2 TO 'USER'@'%'; +GRANT 'role_1' TO 'USER'@'%'; +GRANT 'role_2' TO 'USER'@'%'; GRANT USAGE ON *.* TO 'USER'@'%' IDENTIFIED VIA unix_socket; /*M!100005 SET DEFAULT ROLE 'role_2' FOR 'USER'@'%' */; /*!80001 ALTER USER 'USER'@'%' DEFAULT ROLE 'role_2' */; -GRANT role_2 TO 'role_1' WITH ADMIN OPTION; +GRANT 'role_2' TO 'role_1' WITH ADMIN OPTION; GRANT SHOW DATABASES ON *.* TO 'role_1'; GRANT USAGE ON *.* TO 'role_2'; GRANT USAGE ON *.* TO 'role_2'; @@ -196,17 +196,17 @@ SET ROLE mariadb_dump_import_role; /*!80001 CREATE ROLE 'role_2' */; /*M!100103 CREATE OR REPLACE ROLE 'role_2' WITH ADMIN mariadb_dump_import_role */; /*M!100005 GRANT 'role_2' TO 'role_1' WITH ADMIN OPTION */; -GRANT role_1 TO 'root'@'localhost' WITH ADMIN OPTION; +GRANT 'role_1' TO 'root'@'localhost' WITH ADMIN OPTION; GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION; GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION; /*M!100005 SET DEFAULT ROLE NONE FOR 'root'@'localhost' */; /*!80001 ALTER USER 'root'@'localhost' DEFAULT ROLE NONE */; -GRANT role_1 TO 'USER'@'%'; -GRANT role_2 TO 'USER'@'%'; +GRANT 'role_1' TO 'USER'@'%'; +GRANT 'role_2' TO 'USER'@'%'; GRANT USAGE ON *.* TO 'USER'@'%' IDENTIFIED VIA unix_socket; /*M!100005 SET DEFAULT ROLE 'role_2' FOR 'USER'@'%' */; /*!80001 ALTER USER 'USER'@'%' DEFAULT ROLE 'role_2' */; -GRANT role_2 TO 'role_1' WITH ADMIN OPTION; +GRANT 'role_2' TO 'role_1' WITH ADMIN OPTION; GRANT SHOW DATABASES ON *.* TO 'role_1'; GRANT USAGE ON *.* TO 'role_2'; GRANT USAGE ON *.* TO 'role_2'; @@ -317,17 +317,17 @@ SET ROLE mariadb_dump_import_role; /*!80001 CREATE ROLE IF NOT EXISTS 'role_2' */; /*M!100005 CREATE ROLE IF NOT EXISTS 'role_2' WITH ADMIN mariadb_dump_import_role */; /*M!100005 GRANT 'role_2' TO 'role_1' WITH ADMIN OPTION */; -GRANT role_1 TO 'root'@'localhost' WITH ADMIN OPTION; +GRANT 'role_1' TO 'root'@'localhost' WITH ADMIN OPTION; GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION; GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION; /*M!100005 SET DEFAULT ROLE NONE FOR 'root'@'localhost' */; /*!80001 ALTER USER 'root'@'localhost' DEFAULT ROLE NONE */; -GRANT role_1 TO 'USER'@'%'; -GRANT role_2 TO 'USER'@'%'; +GRANT 'role_1' TO 'USER'@'%'; +GRANT 'role_2' TO 'USER'@'%'; GRANT USAGE ON *.* TO 'USER'@'%' IDENTIFIED VIA unix_socket; /*M!100005 SET DEFAULT ROLE 'role_2' FOR 'USER'@'%' */; /*!80001 ALTER USER 'USER'@'%' DEFAULT ROLE 'role_2' */; -GRANT role_2 TO 'role_1' WITH ADMIN OPTION; +GRANT 'role_2' TO 'role_1' WITH ADMIN OPTION; GRANT SHOW DATABASES ON *.* TO 'role_1'; GRANT USAGE ON *.* TO 'role_2'; GRANT USAGE ON *.* TO 'role_2'; diff --git a/mysql-test/suite/roles/admin.result b/mysql-test/suite/roles/admin.result index 87d2888b47c..d5e4e1370db 100644 --- a/mysql-test/suite/roles/admin.result +++ b/mysql-test/suite/roles/admin.result @@ -27,19 +27,19 @@ grant select on *.* to foo@localhost with admin option; 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 'admin option' at line 1 show grants for foo@localhost; Grants for foo@localhost +GRANT 'role1' TO 'foo'@'localhost' WITH ADMIN OPTION +GRANT 'role2' TO 'foo'@'localhost' +GRANT 'role5' TO 'foo'@'localhost' WITH ADMIN OPTION GRANT CREATE USER ON *.* TO 'foo'@'localhost' -GRANT role1 TO 'foo'@'localhost' WITH ADMIN OPTION -GRANT role2 TO 'foo'@'localhost' -GRANT role5 TO 'foo'@'localhost' WITH ADMIN OPTION show grants for role1; Grants for role1 +GRANT 'role2' TO 'role1' +GRANT 'role3' TO 'role1' WITH ADMIN OPTION +GRANT 'role4' TO 'role3' WITH ADMIN OPTION GRANT USAGE ON *.* TO 'role1' GRANT USAGE ON *.* TO 'role2' GRANT USAGE ON *.* TO 'role3' GRANT USAGE ON *.* TO 'role4' -GRANT role2 TO 'role1' -GRANT role3 TO 'role1' WITH ADMIN OPTION -GRANT role4 TO 'role3' WITH ADMIN OPTION show grants for role4; Grants for role4 GRANT USAGE ON *.* TO 'role4' @@ -58,19 +58,19 @@ localhost root role4 Y flush privileges; show grants for foo@localhost; Grants for foo@localhost +GRANT 'role1' TO 'foo'@'localhost' WITH ADMIN OPTION +GRANT 'role2' TO 'foo'@'localhost' +GRANT 'role5' TO 'foo'@'localhost' WITH ADMIN OPTION GRANT CREATE USER ON *.* TO 'foo'@'localhost' -GRANT role1 TO 'foo'@'localhost' WITH ADMIN OPTION -GRANT role2 TO 'foo'@'localhost' -GRANT role5 TO 'foo'@'localhost' WITH ADMIN OPTION show grants for role1; Grants for role1 +GRANT 'role2' TO 'role1' +GRANT 'role3' TO 'role1' WITH ADMIN OPTION +GRANT 'role4' TO 'role3' WITH ADMIN OPTION GRANT USAGE ON *.* TO 'role1' GRANT USAGE ON *.* TO 'role2' GRANT USAGE ON *.* TO 'role3' GRANT USAGE ON *.* TO 'role4' -GRANT role2 TO 'role1' -GRANT role3 TO 'role1' WITH ADMIN OPTION -GRANT role4 TO 'role3' WITH ADMIN OPTION show grants for role4; Grants for role4 GRANT USAGE ON *.* TO 'role4' @@ -89,18 +89,18 @@ revoke admin option for role2 from foo@localhost; revoke admin option for role1 from root@localhost; show grants for foo@localhost; Grants for foo@localhost +GRANT 'role2' TO 'foo'@'localhost' +GRANT 'role5' TO 'foo'@'localhost' WITH ADMIN OPTION GRANT CREATE USER ON *.* TO 'foo'@'localhost' -GRANT role2 TO 'foo'@'localhost' -GRANT role5 TO 'foo'@'localhost' WITH ADMIN OPTION show grants for role1; Grants for role1 +GRANT 'role2' TO 'role1' WITH ADMIN OPTION +GRANT 'role3' TO 'role1' WITH ADMIN OPTION +GRANT 'role4' TO 'role3' GRANT USAGE ON *.* TO 'role1' GRANT USAGE ON *.* TO 'role2' GRANT USAGE ON *.* TO 'role3' GRANT USAGE ON *.* TO 'role4' -GRANT role2 TO 'role1' WITH ADMIN OPTION -GRANT role3 TO 'role1' WITH ADMIN OPTION -GRANT role4 TO 'role3' show grants for role4; Grants for role4 GRANT USAGE ON *.* TO 'role4' @@ -118,18 +118,18 @@ localhost root role4 Y flush privileges; show grants for foo@localhost; Grants for foo@localhost +GRANT 'role2' TO 'foo'@'localhost' +GRANT 'role5' TO 'foo'@'localhost' WITH ADMIN OPTION GRANT CREATE USER ON *.* TO 'foo'@'localhost' -GRANT role2 TO 'foo'@'localhost' -GRANT role5 TO 'foo'@'localhost' WITH ADMIN OPTION show grants for role1; Grants for role1 +GRANT 'role2' TO 'role1' WITH ADMIN OPTION +GRANT 'role3' TO 'role1' WITH ADMIN OPTION +GRANT 'role4' TO 'role3' GRANT USAGE ON *.* TO 'role1' GRANT USAGE ON *.* TO 'role2' GRANT USAGE ON *.* TO 'role3' GRANT USAGE ON *.* TO 'role4' -GRANT role2 TO 'role1' WITH ADMIN OPTION -GRANT role3 TO 'role1' WITH ADMIN OPTION -GRANT role4 TO 'role3' show grants for role4; Grants for role4 GRANT USAGE ON *.* TO 'role4' diff --git a/mysql-test/suite/roles/create_and_drop_role.result b/mysql-test/suite/roles/create_and_drop_role.result index a163ee82f42..b13f6eb4cb8 100644 --- a/mysql-test/suite/roles/create_and_drop_role.result +++ b/mysql-test/suite/roles/create_and_drop_role.result @@ -66,7 +66,7 @@ localhost r1 r2 N localhost root r2 Y SHOW GRANTS FOR r1@localhost; Grants for r1@localhost -GRANT r2 TO 'r1'@'localhost' +GRANT 'r2' TO 'r1'@'localhost' GRANT USAGE ON *.* TO 'r1'@'localhost' DROP USER u1; DROP ROLE r2; diff --git a/mysql-test/suite/roles/create_and_grant_role.result b/mysql-test/suite/roles/create_and_grant_role.result index 883ae44397d..b298b2baeee 100644 --- a/mysql-test/suite/roles/create_and_grant_role.result +++ b/mysql-test/suite/roles/create_and_grant_role.result @@ -13,10 +13,10 @@ Host User Role Admin_option localhost root r1 Y show grants; Grants for root@localhost +GRANT 'r1' TO 'root'@'localhost' WITH ADMIN OPTION GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION GRANT USAGE ON *.* TO 'r1' -GRANT r1 TO 'root'@'localhost' WITH ADMIN OPTION drop role r1; select * from mysql.roles_mapping; Host User Role Admin_option diff --git a/mysql-test/suite/roles/definer.result b/mysql-test/suite/roles/definer.result index 0a83262add1..19d5a026e65 100644 --- a/mysql-test/suite/roles/definer.result +++ b/mysql-test/suite/roles/definer.result @@ -38,7 +38,7 @@ connect c1, localhost, foo,,mysqltest1; connection c1; show grants; Grants for foo@localhost -GRANT role4 TO 'foo'@'localhost' +GRANT 'role4' TO 'foo'@'localhost' GRANT USAGE ON *.* TO 'foo'@'localhost' GRANT CREATE VIEW ON `mysqltest1`.* TO 'foo'@'localhost' select * from test.v1; diff --git a/mysql-test/suite/roles/drop_routines.result b/mysql-test/suite/roles/drop_routines.result index 11eda3a290f..8a5bb4f218c 100644 --- a/mysql-test/suite/roles/drop_routines.result +++ b/mysql-test/suite/roles/drop_routines.result @@ -7,15 +7,15 @@ grant r3 to r2; grant r1 to u1; show grants for u1; Grants for u1@% +GRANT 'r1' TO 'u1'@'%' GRANT USAGE ON *.* TO 'u1'@'%' -GRANT r1 TO 'u1'@'%' show grants for r1; Grants for r1 +GRANT 'r2' TO 'r1' +GRANT 'r3' TO 'r2' GRANT USAGE ON *.* TO 'r1' GRANT USAGE ON *.* TO 'r2' GRANT USAGE ON *.* TO 'r3' -GRANT r2 TO 'r1' -GRANT r3 TO 'r2' grant SELECT on *.* to u1; grant INSERT on mysql.* to r1; grant DELETE on mysql.roles_mapping to r2; @@ -33,6 +33,8 @@ revoke execute on procedure mysql.test_proc from r2; ERROR 42000: There is no such grant defined for user 'r2' on host '' on routine 'test_proc' show grants for r1; Grants for r1 +GRANT 'r2' TO 'r1' +GRANT 'r3' TO 'r2' GRANT DELETE ON `mysql`.`roles_mapping` TO 'r2' GRANT EXECUTE ON FUNCTION `mysql`.`test_func` TO 'r2' GRANT EXECUTE ON PROCEDURE `mysql`.`test_proc` TO 'r3' @@ -41,17 +43,15 @@ GRANT UPDATE ON `mysql`.`user` TO 'r3' GRANT USAGE ON *.* TO 'r1' GRANT USAGE ON *.* TO 'r2' GRANT USAGE ON *.* TO 'r3' -GRANT r2 TO 'r1' -GRANT r3 TO 'r2' show grants for r2; Grants for r2 +GRANT 'r3' TO 'r2' GRANT DELETE ON `mysql`.`roles_mapping` TO 'r2' GRANT EXECUTE ON FUNCTION `mysql`.`test_func` TO 'r2' GRANT EXECUTE ON PROCEDURE `mysql`.`test_proc` TO 'r3' GRANT UPDATE ON `mysql`.`user` TO 'r3' GRANT USAGE ON *.* TO 'r2' GRANT USAGE ON *.* TO 'r3' -GRANT r3 TO 'r2' show grants for r3; Grants for r3 GRANT EXECUTE ON PROCEDURE `mysql`.`test_proc` TO 'r3' @@ -64,11 +64,11 @@ returns CHAR(50) DETERMINISTIC return concat('Test string: ',s); show grants for r2; Grants for r2 +GRANT 'r3' TO 'r2' GRANT DELETE ON `mysql`.`roles_mapping` TO 'r2' GRANT UPDATE ON `mysql`.`user` TO 'r3' GRANT USAGE ON *.* TO 'r2' GRANT USAGE ON *.* TO 'r3' -GRANT r3 TO 'r2' connect u1,localhost,u1,,; select mysql.test_func("none"); ERROR 42000: execute command denied to user 'u1'@'%' for routine 'mysql.test_func' diff --git a/mysql-test/suite/roles/flush_roles-17898.result b/mysql-test/suite/roles/flush_roles-17898.result index ae8fb0a27d2..a1a8f1a5dde 100644 --- a/mysql-test/suite/roles/flush_roles-17898.result +++ b/mysql-test/suite/roles/flush_roles-17898.result @@ -24,11 +24,11 @@ grant select on m_.* to r2; grant r2 to r1; show grants for u1@localhost; Grants for u1@localhost -GRANT r1 TO 'u1'@'localhost' +GRANT 'r1' TO 'u1'@'localhost' GRANT USAGE ON *.* TO 'u1'@'localhost' show grants for r1; Grants for r1 -GRANT r2 TO 'r1' +GRANT 'r2' TO 'r1' GRANT USAGE ON *.* TO 'r1' GRANT USAGE ON *.* TO 'r2' GRANT SELECT ON `test`.* TO 'r2' diff --git a/mysql-test/suite/roles/grant-5771.result b/mysql-test/suite/roles/grant-5771.result index 87797d8b9a4..5b4c98522f0 100644 --- a/mysql-test/suite/roles/grant-5771.result +++ b/mysql-test/suite/roles/grant-5771.result @@ -21,9 +21,9 @@ show tables in mysqltest2; Tables_in_mysqltest2 show grants; Grants for foo@localhost -GRANT r2 TO 'foo'@'localhost' +GRANT 'r2' TO 'foo'@'localhost' GRANT USAGE ON *.* TO 'foo'@'localhost' -GRANT r1 TO 'r2' +GRANT 'r1' TO 'r2' GRANT USAGE ON *.* TO 'r2' GRANT ALL PRIVILEGES ON `mysqltest2`.* TO 'r2' GRANT USAGE ON *.* TO 'r1' diff --git a/mysql-test/suite/roles/grant_empty.result b/mysql-test/suite/roles/grant_empty.result index 3316c755b9f..7ed9c663128 100644 --- a/mysql-test/suite/roles/grant_empty.result +++ b/mysql-test/suite/roles/grant_empty.result @@ -9,7 +9,7 @@ current_user @localhost show grants; Grants for @localhost -GRANT r1 TO ''@'localhost' +GRANT 'r1' TO ''@'localhost' GRANT USAGE ON *.* TO ''@'localhost' connection default; drop role r1; diff --git a/mysql-test/suite/roles/grant_revoke_current.result b/mysql-test/suite/roles/grant_revoke_current.result index 436bec92a8f..c3774923cd3 100644 --- a/mysql-test/suite/roles/grant_revoke_current.result +++ b/mysql-test/suite/roles/grant_revoke_current.result @@ -27,14 +27,14 @@ GRANT USAGE ON *.* TO 'r1' set password=password('foobar'); show grants; Grants for root@localhost -GRANT r1 TO 'root'@'localhost' WITH ADMIN OPTION +GRANT 'r1' TO 'root'@'localhost' WITH ADMIN OPTION GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY PASSWORD '*9B500343BC52E2911172EB52AE5CF4847604C6E5' WITH GRANT OPTION GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION GRANT USAGE ON *.* TO 'r1' grant r1 to current_user() identified by 'barfoo'; show grants; Grants for root@localhost -GRANT r1 TO 'root'@'localhost' WITH ADMIN OPTION +GRANT 'r1' TO 'root'@'localhost' WITH ADMIN OPTION GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY PASSWORD '*343915A8181B5728EADBDC73E1F7E6B0C3998483' WITH GRANT OPTION GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION GRANT USAGE ON *.* TO 'r1' diff --git a/mysql-test/suite/roles/ip-6401.result b/mysql-test/suite/roles/ip-6401.result index 1afd649636e..1b27e82bce1 100644 --- a/mysql-test/suite/roles/ip-6401.result +++ b/mysql-test/suite/roles/ip-6401.result @@ -4,7 +4,7 @@ grant r1 to foo@'127.0.0.1'; connect con1,127.0.0.1,foo,,; show grants; Grants for foo@127.0.0.1 -GRANT r1 TO 'foo'@'127.0.0.1' +GRANT 'r1' TO 'foo'@'127.0.0.1' GRANT USAGE ON *.* TO 'foo'@'127.0.0.1' set role r1; select * from information_schema.enabled_roles; diff --git a/mysql-test/suite/roles/prepare_stmt_with_role.result b/mysql-test/suite/roles/prepare_stmt_with_role.result index 0352502c35c..b2af23c8fbb 100644 --- a/mysql-test/suite/roles/prepare_stmt_with_role.result +++ b/mysql-test/suite/roles/prepare_stmt_with_role.result @@ -17,7 +17,7 @@ user host is_role developers Y SHOW GRANTS; Grants for root@localhost -GRANT developers TO 'root'@'localhost' WITH ADMIN OPTION +GRANT 'developers' TO 'root'@'localhost' WITH ADMIN OPTION GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION # Test reexecution. @@ -40,7 +40,7 @@ Host User Role Admin_option localhost root developers Y SHOW GRANTS FOR test_user; Grants for test_user@% -GRANT developers TO 'test_user'@'%' +GRANT 'developers' TO 'test_user'@'%' GRANT USAGE ON *.* TO 'test_user'@'%' # # Test revoking a role. @@ -56,7 +56,7 @@ GRANT USAGE ON *.* TO 'test_user'@'%' EXECUTE stmtGrantRole; SHOW GRANTS FOR test_user; Grants for test_user@% -GRANT developers TO 'test_user'@'%' +GRANT 'developers' TO 'test_user'@'%' GRANT USAGE ON *.* TO 'test_user'@'%' EXECUTE stmtRevokeRole; SHOW GRANTS FOR test_user; @@ -96,7 +96,7 @@ Host User Role Admin_option localhost root developers Y SHOW GRANTS; Grants for root@localhost -GRANT developers TO 'root'@'localhost' WITH ADMIN OPTION +GRANT 'developers' TO 'root'@'localhost' WITH ADMIN OPTION GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION SHOW GRANTS FOR test_user; diff --git a/mysql-test/suite/roles/rebuild_role_grants.result b/mysql-test/suite/roles/rebuild_role_grants.result index 1068be9bc01..72eabe38b93 100644 --- a/mysql-test/suite/roles/rebuild_role_grants.result +++ b/mysql-test/suite/roles/rebuild_role_grants.result @@ -3,13 +3,13 @@ create user u1; grant r1 to u1; show grants for u1; Grants for u1@% +GRANT 'r1' TO 'u1'@'%' GRANT USAGE ON *.* TO 'u1'@'%' -GRANT r1 TO 'u1'@'%' create user u2; show grants for u1; Grants for u1@% +GRANT 'r1' TO 'u1'@'%' GRANT USAGE ON *.* TO 'u1'@'%' -GRANT r1 TO 'u1'@'%' show grants for u2; Grants for u2@% GRANT USAGE ON *.* TO 'u2'@'%' @@ -30,8 +30,8 @@ grant r1 to u1; grant r1 to u1; show grants for u1; Grants for u1@% +GRANT 'r1' TO 'u1'@'%' GRANT USAGE ON *.* TO 'u1'@'%' -GRANT r1 TO 'u1'@'%' select * from mysql.roles_mapping; Host User Role Admin_option % u1 r1 N diff --git a/mysql-test/suite/roles/recursive.result b/mysql-test/suite/roles/recursive.result index 897577ba2ff..18fb573ecc0 100644 --- a/mysql-test/suite/roles/recursive.result +++ b/mysql-test/suite/roles/recursive.result @@ -26,8 +26,8 @@ ERROR HY000: Cannot grant role 'role10' to: 'role2' connect foo, localhost, foo; show grants; Grants for foo@localhost +GRANT 'role10' TO 'foo'@'localhost' GRANT USAGE ON *.* TO 'foo'@'localhost' -GRANT role10 TO 'foo'@'localhost' select * from information_schema.applicable_roles; GRANTEE ROLE_NAME IS_GRANTABLE IS_DEFAULT foo@localhost role10 NO NO @@ -56,6 +56,17 @@ count(*) 22 show grants; Grants for foo@localhost +GRANT 'role1' TO 'role2' +GRANT 'role10' TO 'foo'@'localhost' +GRANT 'role2' TO 'role4' +GRANT 'role2' TO 'role5' +GRANT 'role3' TO 'role5' +GRANT 'role4' TO 'role6' +GRANT 'role5' TO 'role6' +GRANT 'role5' TO 'role7' +GRANT 'role6' TO 'role9' +GRANT 'role7' TO 'role9' +GRANT 'role9' TO 'role10' GRANT SELECT ON *.* TO 'role1' GRANT USAGE ON *.* TO 'foo'@'localhost' GRANT USAGE ON *.* TO 'role10' @@ -66,17 +77,6 @@ GRANT USAGE ON *.* TO 'role5' GRANT USAGE ON *.* TO 'role6' GRANT USAGE ON *.* TO 'role7' GRANT USAGE ON *.* TO 'role9' -GRANT role1 TO 'role2' -GRANT role10 TO 'foo'@'localhost' -GRANT role2 TO 'role4' -GRANT role2 TO 'role5' -GRANT role3 TO 'role5' -GRANT role4 TO 'role6' -GRANT role5 TO 'role6' -GRANT role5 TO 'role7' -GRANT role6 TO 'role9' -GRANT role7 TO 'role9' -GRANT role9 TO 'role10' select * from information_schema.enabled_roles; ROLE_NAME role1 @@ -114,6 +114,17 @@ count(*) 22 show grants; Grants for foo@localhost +GRANT 'role1' TO 'role2' +GRANT 'role10' TO 'foo'@'localhost' +GRANT 'role2' TO 'role4' +GRANT 'role2' TO 'role5' +GRANT 'role3' TO 'role5' +GRANT 'role4' TO 'role6' +GRANT 'role5' TO 'role6' +GRANT 'role5' TO 'role7' +GRANT 'role6' TO 'role9' +GRANT 'role7' TO 'role9' +GRANT 'role9' TO 'role10' GRANT SELECT ON `mysql`.* TO 'role1' GRANT USAGE ON *.* TO 'foo'@'localhost' GRANT USAGE ON *.* TO 'role1' @@ -125,17 +136,6 @@ GRANT USAGE ON *.* TO 'role5' GRANT USAGE ON *.* TO 'role6' GRANT USAGE ON *.* TO 'role7' GRANT USAGE ON *.* TO 'role9' -GRANT role1 TO 'role2' -GRANT role10 TO 'foo'@'localhost' -GRANT role2 TO 'role4' -GRANT role2 TO 'role5' -GRANT role3 TO 'role5' -GRANT role4 TO 'role6' -GRANT role5 TO 'role6' -GRANT role5 TO 'role7' -GRANT role6 TO 'role9' -GRANT role7 TO 'role9' -GRANT role9 TO 'role10' connection default; revoke select on mysql.* from role1; show status like 'debug%'; @@ -157,6 +157,17 @@ count(*) 22 show grants; Grants for foo@localhost +GRANT 'role1' TO 'role2' +GRANT 'role10' TO 'foo'@'localhost' +GRANT 'role2' TO 'role4' +GRANT 'role2' TO 'role5' +GRANT 'role3' TO 'role5' +GRANT 'role4' TO 'role6' +GRANT 'role5' TO 'role6' +GRANT 'role5' TO 'role7' +GRANT 'role6' TO 'role9' +GRANT 'role7' TO 'role9' +GRANT 'role9' TO 'role10' GRANT SELECT ON `mysql`.`roles_mapping` TO 'role1' GRANT USAGE ON *.* TO 'foo'@'localhost' GRANT USAGE ON *.* TO 'role1' @@ -168,17 +179,6 @@ GRANT USAGE ON *.* TO 'role5' GRANT USAGE ON *.* TO 'role6' GRANT USAGE ON *.* TO 'role7' GRANT USAGE ON *.* TO 'role9' -GRANT role1 TO 'role2' -GRANT role10 TO 'foo'@'localhost' -GRANT role2 TO 'role4' -GRANT role2 TO 'role5' -GRANT role3 TO 'role5' -GRANT role4 TO 'role6' -GRANT role5 TO 'role6' -GRANT role5 TO 'role7' -GRANT role6 TO 'role9' -GRANT role7 TO 'role9' -GRANT role9 TO 'role10' connection default; revoke select on mysql.roles_mapping from role1; show status like 'debug%'; @@ -202,6 +202,17 @@ count(concat(User)) 22 show grants; Grants for foo@localhost +GRANT 'role1' TO 'role2' +GRANT 'role10' TO 'foo'@'localhost' +GRANT 'role2' TO 'role4' +GRANT 'role2' TO 'role5' +GRANT 'role3' TO 'role5' +GRANT 'role4' TO 'role6' +GRANT 'role5' TO 'role6' +GRANT 'role5' TO 'role7' +GRANT 'role6' TO 'role9' +GRANT 'role7' TO 'role9' +GRANT 'role9' TO 'role10' GRANT SELECT (User) ON `mysql`.`roles_mapping` TO 'role1' GRANT USAGE ON *.* TO 'foo'@'localhost' GRANT USAGE ON *.* TO 'role1' @@ -213,17 +224,6 @@ GRANT USAGE ON *.* TO 'role5' GRANT USAGE ON *.* TO 'role6' GRANT USAGE ON *.* TO 'role7' GRANT USAGE ON *.* TO 'role9' -GRANT role1 TO 'role2' -GRANT role10 TO 'foo'@'localhost' -GRANT role2 TO 'role4' -GRANT role2 TO 'role5' -GRANT role3 TO 'role5' -GRANT role4 TO 'role6' -GRANT role5 TO 'role6' -GRANT role5 TO 'role7' -GRANT role6 TO 'role9' -GRANT role7 TO 'role9' -GRANT role9 TO 'role10' connection default; grant select(Host) on mysql.roles_mapping to role3; show status like 'debug%'; @@ -236,6 +236,17 @@ count(concat(User,Host)) 22 show grants; Grants for foo@localhost +GRANT 'role1' TO 'role2' +GRANT 'role10' TO 'foo'@'localhost' +GRANT 'role2' TO 'role4' +GRANT 'role2' TO 'role5' +GRANT 'role3' TO 'role5' +GRANT 'role4' TO 'role6' +GRANT 'role5' TO 'role6' +GRANT 'role5' TO 'role7' +GRANT 'role6' TO 'role9' +GRANT 'role7' TO 'role9' +GRANT 'role9' TO 'role10' GRANT SELECT (Host) ON `mysql`.`roles_mapping` TO 'role3' GRANT SELECT (User) ON `mysql`.`roles_mapping` TO 'role1' GRANT USAGE ON *.* TO 'foo'@'localhost' @@ -248,17 +259,6 @@ GRANT USAGE ON *.* TO 'role5' GRANT USAGE ON *.* TO 'role6' GRANT USAGE ON *.* TO 'role7' GRANT USAGE ON *.* TO 'role9' -GRANT role1 TO 'role2' -GRANT role10 TO 'foo'@'localhost' -GRANT role2 TO 'role4' -GRANT role2 TO 'role5' -GRANT role3 TO 'role5' -GRANT role4 TO 'role6' -GRANT role5 TO 'role6' -GRANT role5 TO 'role7' -GRANT role6 TO 'role9' -GRANT role7 TO 'role9' -GRANT role9 TO 'role10' connection default; revoke select(User) on mysql.roles_mapping from role1; show status like 'debug%'; diff --git a/mysql-test/suite/roles/recursive_dbug.result b/mysql-test/suite/roles/recursive_dbug.result index cec461be4a2..a5772a6354c 100644 --- a/mysql-test/suite/roles/recursive_dbug.result +++ b/mysql-test/suite/roles/recursive_dbug.result @@ -30,8 +30,8 @@ ERROR HY000: Cannot grant role 'role10' to: 'role2' connect foo, localhost, foo; show grants; Grants for foo@localhost +GRANT 'role10' TO 'foo'@'localhost' GRANT USAGE ON *.* TO 'foo'@'localhost' -GRANT role10 TO 'foo'@'localhost' select * from information_schema.applicable_roles; GRANTEE ROLE_NAME IS_GRANTABLE IS_DEFAULT foo@localhost role10 NO NO @@ -70,6 +70,17 @@ count(*) 22 show grants; Grants for foo@localhost +GRANT 'role1' TO 'role2' +GRANT 'role10' TO 'foo'@'localhost' +GRANT 'role2' TO 'role4' +GRANT 'role2' TO 'role5' +GRANT 'role3' TO 'role5' +GRANT 'role4' TO 'role6' +GRANT 'role5' TO 'role6' +GRANT 'role5' TO 'role7' +GRANT 'role6' TO 'role9' +GRANT 'role7' TO 'role9' +GRANT 'role9' TO 'role10' GRANT SELECT ON *.* TO 'role1' GRANT USAGE ON *.* TO 'foo'@'localhost' GRANT USAGE ON *.* TO 'role10' @@ -80,17 +91,6 @@ GRANT USAGE ON *.* TO 'role5' GRANT USAGE ON *.* TO 'role6' GRANT USAGE ON *.* TO 'role7' GRANT USAGE ON *.* TO 'role9' -GRANT role1 TO 'role2' -GRANT role10 TO 'foo'@'localhost' -GRANT role2 TO 'role4' -GRANT role2 TO 'role5' -GRANT role3 TO 'role5' -GRANT role4 TO 'role6' -GRANT role5 TO 'role6' -GRANT role5 TO 'role7' -GRANT role6 TO 'role9' -GRANT role7 TO 'role9' -GRANT role9 TO 'role10' select * from information_schema.enabled_roles; ROLE_NAME role1 @@ -138,6 +138,17 @@ count(*) 22 show grants; Grants for foo@localhost +GRANT 'role1' TO 'role2' +GRANT 'role10' TO 'foo'@'localhost' +GRANT 'role2' TO 'role4' +GRANT 'role2' TO 'role5' +GRANT 'role3' TO 'role5' +GRANT 'role4' TO 'role6' +GRANT 'role5' TO 'role6' +GRANT 'role5' TO 'role7' +GRANT 'role6' TO 'role9' +GRANT 'role7' TO 'role9' +GRANT 'role9' TO 'role10' GRANT SELECT ON `mysql`.* TO 'role1' GRANT USAGE ON *.* TO 'foo'@'localhost' GRANT USAGE ON *.* TO 'role1' @@ -149,17 +160,6 @@ GRANT USAGE ON *.* TO 'role5' GRANT USAGE ON *.* TO 'role6' GRANT USAGE ON *.* TO 'role7' GRANT USAGE ON *.* TO 'role9' -GRANT role1 TO 'role2' -GRANT role10 TO 'foo'@'localhost' -GRANT role2 TO 'role4' -GRANT role2 TO 'role5' -GRANT role3 TO 'role5' -GRANT role4 TO 'role6' -GRANT role5 TO 'role6' -GRANT role5 TO 'role7' -GRANT role6 TO 'role9' -GRANT role7 TO 'role9' -GRANT role9 TO 'role10' connection default; revoke select on mysql.* from role1; show status like 'debug%'; @@ -191,6 +191,17 @@ count(*) 22 show grants; Grants for foo@localhost +GRANT 'role1' TO 'role2' +GRANT 'role10' TO 'foo'@'localhost' +GRANT 'role2' TO 'role4' +GRANT 'role2' TO 'role5' +GRANT 'role3' TO 'role5' +GRANT 'role4' TO 'role6' +GRANT 'role5' TO 'role6' +GRANT 'role5' TO 'role7' +GRANT 'role6' TO 'role9' +GRANT 'role7' TO 'role9' +GRANT 'role9' TO 'role10' GRANT SELECT ON `mysql`.`roles_mapping` TO 'role1' GRANT USAGE ON *.* TO 'foo'@'localhost' GRANT USAGE ON *.* TO 'role1' @@ -202,17 +213,6 @@ GRANT USAGE ON *.* TO 'role5' GRANT USAGE ON *.* TO 'role6' GRANT USAGE ON *.* TO 'role7' GRANT USAGE ON *.* TO 'role9' -GRANT role1 TO 'role2' -GRANT role10 TO 'foo'@'localhost' -GRANT role2 TO 'role4' -GRANT role2 TO 'role5' -GRANT role3 TO 'role5' -GRANT role4 TO 'role6' -GRANT role5 TO 'role6' -GRANT role5 TO 'role7' -GRANT role6 TO 'role9' -GRANT role7 TO 'role9' -GRANT role9 TO 'role10' connection default; revoke select on mysql.roles_mapping from role1; show status like 'debug%'; @@ -246,6 +246,17 @@ count(concat(User)) 22 show grants; Grants for foo@localhost +GRANT 'role1' TO 'role2' +GRANT 'role10' TO 'foo'@'localhost' +GRANT 'role2' TO 'role4' +GRANT 'role2' TO 'role5' +GRANT 'role3' TO 'role5' +GRANT 'role4' TO 'role6' +GRANT 'role5' TO 'role6' +GRANT 'role5' TO 'role7' +GRANT 'role6' TO 'role9' +GRANT 'role7' TO 'role9' +GRANT 'role9' TO 'role10' GRANT SELECT (User) ON `mysql`.`roles_mapping` TO 'role1' GRANT USAGE ON *.* TO 'foo'@'localhost' GRANT USAGE ON *.* TO 'role1' @@ -257,17 +268,6 @@ GRANT USAGE ON *.* TO 'role5' GRANT USAGE ON *.* TO 'role6' GRANT USAGE ON *.* TO 'role7' GRANT USAGE ON *.* TO 'role9' -GRANT role1 TO 'role2' -GRANT role10 TO 'foo'@'localhost' -GRANT role2 TO 'role4' -GRANT role2 TO 'role5' -GRANT role3 TO 'role5' -GRANT role4 TO 'role6' -GRANT role5 TO 'role6' -GRANT role5 TO 'role7' -GRANT role6 TO 'role9' -GRANT role7 TO 'role9' -GRANT role9 TO 'role10' connection default; grant select(Host) on mysql.roles_mapping to role3; show status like 'debug%'; @@ -285,6 +285,17 @@ count(concat(User,Host)) 22 show grants; Grants for foo@localhost +GRANT 'role1' TO 'role2' +GRANT 'role10' TO 'foo'@'localhost' +GRANT 'role2' TO 'role4' +GRANT 'role2' TO 'role5' +GRANT 'role3' TO 'role5' +GRANT 'role4' TO 'role6' +GRANT 'role5' TO 'role6' +GRANT 'role5' TO 'role7' +GRANT 'role6' TO 'role9' +GRANT 'role7' TO 'role9' +GRANT 'role9' TO 'role10' GRANT SELECT (Host) ON `mysql`.`roles_mapping` TO 'role3' GRANT SELECT (User) ON `mysql`.`roles_mapping` TO 'role1' GRANT USAGE ON *.* TO 'foo'@'localhost' @@ -297,17 +308,6 @@ GRANT USAGE ON *.* TO 'role5' GRANT USAGE ON *.* TO 'role6' GRANT USAGE ON *.* TO 'role7' GRANT USAGE ON *.* TO 'role9' -GRANT role1 TO 'role2' -GRANT role10 TO 'foo'@'localhost' -GRANT role2 TO 'role4' -GRANT role2 TO 'role5' -GRANT role3 TO 'role5' -GRANT role4 TO 'role6' -GRANT role5 TO 'role6' -GRANT role5 TO 'role7' -GRANT role6 TO 'role9' -GRANT role7 TO 'role9' -GRANT role9 TO 'role10' connection default; revoke select(User) on mysql.roles_mapping from role1; show status like 'debug%'; diff --git a/mysql-test/suite/roles/revoke_all.result b/mysql-test/suite/roles/revoke_all.result index 7e72b5bc766..b2457e6b5f5 100644 --- a/mysql-test/suite/roles/revoke_all.result +++ b/mysql-test/suite/roles/revoke_all.result @@ -10,18 +10,18 @@ grant r1 to u1; grant r4 to r1; show grants for u1; Grants for u1@% +GRANT 'r1' TO 'u1'@'%' GRANT USAGE ON *.* TO 'u1'@'%' -GRANT r1 TO 'u1'@'%' show grants for r1; Grants for r1 +GRANT 'r2' TO 'r1' +GRANT 'r3' TO 'r2' +GRANT 'r4' TO 'r1' +GRANT 'r4' TO 'r3' GRANT USAGE ON *.* TO 'r1' GRANT USAGE ON *.* TO 'r2' GRANT USAGE ON *.* TO 'r3' GRANT USAGE ON *.* TO 'r4' -GRANT r2 TO 'r1' -GRANT r3 TO 'r2' -GRANT r4 TO 'r1' -GRANT r4 TO 'r3' grant SELECT on *.* to u1; grant INSERT on mysql.* to r1; grant DELETE on mysql.roles_mapping to r2; @@ -38,6 +38,10 @@ grant execute on procedure mysql.test_proc to r3; grant execute on mysql.* to r4; show grants for r1; Grants for r1 +GRANT 'r2' TO 'r1' +GRANT 'r3' TO 'r2' +GRANT 'r4' TO 'r1' +GRANT 'r4' TO 'r3' GRANT DELETE ON `mysql`.`roles_mapping` TO 'r2' GRANT EXECUTE ON FUNCTION `mysql`.`test_func` TO 'r2' GRANT EXECUTE ON PROCEDURE `mysql`.`test_proc` TO 'r3' @@ -48,12 +52,10 @@ GRANT USAGE ON *.* TO 'r1' GRANT USAGE ON *.* TO 'r2' GRANT USAGE ON *.* TO 'r3' GRANT USAGE ON *.* TO 'r4' -GRANT r2 TO 'r1' -GRANT r3 TO 'r2' -GRANT r4 TO 'r1' -GRANT r4 TO 'r3' show grants for r2; Grants for r2 +GRANT 'r3' TO 'r2' +GRANT 'r4' TO 'r3' GRANT DELETE ON `mysql`.`roles_mapping` TO 'r2' GRANT EXECUTE ON FUNCTION `mysql`.`test_func` TO 'r2' GRANT EXECUTE ON PROCEDURE `mysql`.`test_proc` TO 'r3' @@ -62,16 +64,14 @@ GRANT UPDATE ON `mysql`.`user` TO 'r3' GRANT USAGE ON *.* TO 'r2' GRANT USAGE ON *.* TO 'r3' GRANT USAGE ON *.* TO 'r4' -GRANT r3 TO 'r2' -GRANT r4 TO 'r3' show grants for r3; Grants for r3 +GRANT 'r4' TO 'r3' GRANT EXECUTE ON PROCEDURE `mysql`.`test_proc` TO 'r3' GRANT EXECUTE ON `mysql`.* TO 'r4' GRANT UPDATE ON `mysql`.`user` TO 'r3' GRANT USAGE ON *.* TO 'r3' GRANT USAGE ON *.* TO 'r4' -GRANT r4 TO 'r3' show grants for r4; Grants for r4 GRANT EXECUTE ON `mysql`.* TO 'r4' @@ -79,6 +79,10 @@ GRANT USAGE ON *.* TO 'r4' revoke all privileges, grant option from r4; show grants for r1; Grants for r1 +GRANT 'r2' TO 'r1' +GRANT 'r3' TO 'r2' +GRANT 'r4' TO 'r1' +GRANT 'r4' TO 'r3' GRANT DELETE ON `mysql`.`roles_mapping` TO 'r2' GRANT EXECUTE ON FUNCTION `mysql`.`test_func` TO 'r2' GRANT EXECUTE ON PROCEDURE `mysql`.`test_proc` TO 'r3' @@ -88,12 +92,10 @@ GRANT USAGE ON *.* TO 'r1' GRANT USAGE ON *.* TO 'r2' GRANT USAGE ON *.* TO 'r3' GRANT USAGE ON *.* TO 'r4' -GRANT r2 TO 'r1' -GRANT r3 TO 'r2' -GRANT r4 TO 'r1' -GRANT r4 TO 'r3' show grants for r2; Grants for r2 +GRANT 'r3' TO 'r2' +GRANT 'r4' TO 'r3' GRANT DELETE ON `mysql`.`roles_mapping` TO 'r2' GRANT EXECUTE ON FUNCTION `mysql`.`test_func` TO 'r2' GRANT EXECUTE ON PROCEDURE `mysql`.`test_proc` TO 'r3' @@ -101,21 +103,22 @@ GRANT UPDATE ON `mysql`.`user` TO 'r3' GRANT USAGE ON *.* TO 'r2' GRANT USAGE ON *.* TO 'r3' GRANT USAGE ON *.* TO 'r4' -GRANT r3 TO 'r2' -GRANT r4 TO 'r3' show grants for r3; Grants for r3 +GRANT 'r4' TO 'r3' GRANT EXECUTE ON PROCEDURE `mysql`.`test_proc` TO 'r3' GRANT UPDATE ON `mysql`.`user` TO 'r3' GRANT USAGE ON *.* TO 'r3' GRANT USAGE ON *.* TO 'r4' -GRANT r4 TO 'r3' show grants for r4; Grants for r4 GRANT USAGE ON *.* TO 'r4' revoke all privileges, grant option from r3; show grants for r1; Grants for r1 +GRANT 'r2' TO 'r1' +GRANT 'r3' TO 'r2' +GRANT 'r4' TO 'r1' GRANT DELETE ON `mysql`.`roles_mapping` TO 'r2' GRANT EXECUTE ON FUNCTION `mysql`.`test_func` TO 'r2' GRANT INSERT ON `mysql`.* TO 'r1' @@ -123,16 +126,13 @@ GRANT USAGE ON *.* TO 'r1' GRANT USAGE ON *.* TO 'r2' GRANT USAGE ON *.* TO 'r3' GRANT USAGE ON *.* TO 'r4' -GRANT r2 TO 'r1' -GRANT r3 TO 'r2' -GRANT r4 TO 'r1' show grants for r2; Grants for r2 +GRANT 'r3' TO 'r2' GRANT DELETE ON `mysql`.`roles_mapping` TO 'r2' GRANT EXECUTE ON FUNCTION `mysql`.`test_func` TO 'r2' GRANT USAGE ON *.* TO 'r2' GRANT USAGE ON *.* TO 'r3' -GRANT r3 TO 'r2' show grants for r3; Grants for r3 GRANT USAGE ON *.* TO 'r3' @@ -142,12 +142,12 @@ GRANT USAGE ON *.* TO 'r4' revoke all privileges, grant option from r2; show grants for r1; Grants for r1 +GRANT 'r2' TO 'r1' +GRANT 'r4' TO 'r1' GRANT INSERT ON `mysql`.* TO 'r1' GRANT USAGE ON *.* TO 'r1' GRANT USAGE ON *.* TO 'r2' GRANT USAGE ON *.* TO 'r4' -GRANT r2 TO 'r1' -GRANT r4 TO 'r1' show grants for r2; Grants for r2 GRANT USAGE ON *.* TO 'r2' diff --git a/mysql-test/suite/roles/role_case_sensitive-10744.result b/mysql-test/suite/roles/role_case_sensitive-10744.result index b898310e83c..4870300eefc 100644 --- a/mysql-test/suite/roles/role_case_sensitive-10744.result +++ b/mysql-test/suite/roles/role_case_sensitive-10744.result @@ -21,7 +21,7 @@ grant select on secret_db.* to test_role; grant test_role to test_user; show grants for test_user; Grants for test_user@% -GRANT test_role TO 'test_user'@'%' +GRANT 'test_role' TO 'test_user'@'%' GRANT USAGE ON *.* TO 'test_user'@'%' # # Now test the UPPER case role. @@ -30,8 +30,8 @@ grant test_ROLE to test_user; grant insert on secret_db.t1 to test_ROLE; show grants for test_user; Grants for test_user@% -GRANT test_role TO 'test_user'@'%' -GRANT test_ROLE TO 'test_user'@'%' +GRANT 'test_role' TO 'test_user'@'%' +GRANT 'test_ROLE' TO 'test_user'@'%' GRANT USAGE ON *.* TO 'test_user'@'%' connect test_user,localhost,test_user; # diff --git a/mysql-test/suite/roles/rpl_definer.result b/mysql-test/suite/roles/rpl_definer.result index 2d10dc6cd7a..44f0d883ba3 100644 --- a/mysql-test/suite/roles/rpl_definer.result +++ b/mysql-test/suite/roles/rpl_definer.result @@ -7,14 +7,14 @@ grant role2 to role1; set role role1; show grants; Grants for root@localhost +GRANT 'role1' TO 'root'@'localhost' WITH ADMIN OPTION +GRANT 'role2' TO 'role1' +GRANT 'role2' TO 'root'@'localhost' WITH ADMIN OPTION GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION GRANT EXECUTE ON `test`.* TO 'role2' GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION GRANT USAGE ON *.* TO 'role1' GRANT USAGE ON *.* TO 'role2' -GRANT role1 TO 'root'@'localhost' WITH ADMIN OPTION -GRANT role2 TO 'role1' -GRANT role2 TO 'root'@'localhost' WITH ADMIN OPTION create definer=current_user procedure pcu() select current_user; create definer=root@localhost procedure pu() select "root@localhost"; create definer=current_role procedure pcr() select current_role; @@ -39,14 +39,14 @@ connection slave; set role role1; show grants; Grants for root@localhost +GRANT 'role1' TO 'root'@'localhost' WITH ADMIN OPTION +GRANT 'role2' TO 'role1' +GRANT 'role2' TO 'root'@'localhost' WITH ADMIN OPTION GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION GRANT EXECUTE ON `test`.* TO 'role2' GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION GRANT USAGE ON *.* TO 'role1' GRANT USAGE ON *.* TO 'role2' -GRANT role1 TO 'root'@'localhost' WITH ADMIN OPTION -GRANT role2 TO 'role1' -GRANT role2 TO 'root'@'localhost' WITH ADMIN OPTION show create procedure pcu; Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation pcu STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION CREATE DEFINER=`root`@`localhost` PROCEDURE `pcu`() diff --git a/mysql-test/suite/roles/set_and_drop.result b/mysql-test/suite/roles/set_and_drop.result index 2d3e675ebd0..69e2128c170 100644 --- a/mysql-test/suite/roles/set_and_drop.result +++ b/mysql-test/suite/roles/set_and_drop.result @@ -56,7 +56,7 @@ drop role role2; connection foo; show grants; Grants for foo@localhost -GRANT role1 TO 'foo'@'localhost' +GRANT 'role1' TO 'foo'@'localhost' GRANT USAGE ON *.* TO 'foo'@'localhost' GRANT USAGE ON *.* TO 'role1' select * from information_schema.enabled_roles; diff --git a/mysql-test/suite/roles/set_default_role_clear.result b/mysql-test/suite/roles/set_default_role_clear.result index 3cb13f55b4b..3e322a2df9f 100644 --- a/mysql-test/suite/roles/set_default_role_clear.result +++ b/mysql-test/suite/roles/set_default_role_clear.result @@ -4,7 +4,7 @@ grant select on *.* to test_role; grant test_role to test_user@localhost; show grants; Grants for test_user@localhost -GRANT test_role TO 'test_user'@'localhost' +GRANT 'test_role' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' set default role test_role; select user, host, default_role from mysql.user; @@ -14,10 +14,10 @@ user host default_role test_user localhost test_role show grants; Grants for test_user@localhost -GRANT test_role TO 'test_user'@'localhost' +GRANT 'test_role' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' GRANT SELECT ON *.* TO 'test_role' -SET DEFAULT ROLE test_role FOR 'test_user'@'localhost' +SET DEFAULT ROLE 'test_role' FOR 'test_user'@'localhost' select user, host, default_role from mysql.user where user='test_user'; user host default_role test_user localhost test_role diff --git a/mysql-test/suite/roles/set_default_role_for.result b/mysql-test/suite/roles/set_default_role_for.result index 2f6ad0a9f7f..1f0812caeb9 100644 --- a/mysql-test/suite/roles/set_default_role_for.result +++ b/mysql-test/suite/roles/set_default_role_for.result @@ -18,10 +18,10 @@ ERROR OP000: User `root`@`localhost` has not been granted role `role_b` set default role role_b for user_b@localhost; show grants; Grants for user_a@localhost -GRANT role_a TO 'user_a'@'localhost' +GRANT 'role_a' TO 'user_a'@'localhost' GRANT USAGE ON *.* TO 'user_a'@'localhost' GRANT SELECT ON *.* TO 'role_a' -SET DEFAULT ROLE role_a FOR 'user_a'@'localhost' +SET DEFAULT ROLE 'role_a' FOR 'user_a'@'localhost' select user, host, default_role from mysql.user where user like 'user_%'; user host default_role user_a localhost role_a @@ -40,10 +40,10 @@ set default role role_b for current_user; ERROR OP000: User `user_a`@`localhost` has not been granted role `role_b` show grants; Grants for user_b@localhost -GRANT role_b TO 'user_b'@'localhost' +GRANT 'role_b' TO 'user_b'@'localhost' GRANT USAGE ON *.* TO 'user_b'@'localhost' GRANT INSERT, UPDATE ON *.* TO 'role_b' -SET DEFAULT ROLE role_b FOR 'user_b'@'localhost' +SET DEFAULT ROLE 'role_b' FOR 'user_b'@'localhost' select user, host, default_role from mysql.user where user like 'user_%'; ERROR 42000: SELECT command denied to user 'user_b'@'localhost' for table 'user' insert ignore into mysql.user (user, host) values ('someuser', 'somehost'); @@ -55,7 +55,7 @@ Warning 1364 Field 'authentication_string' doesn't have a default value set default role NONE for user_a@localhost; show grants; Grants for user_a@localhost -GRANT role_a TO 'user_a'@'localhost' +GRANT 'role_a' TO 'user_a'@'localhost' GRANT USAGE ON *.* TO 'user_a'@'localhost' GRANT INSERT, UPDATE ON *.* TO 'role_b' select user, host, default_role from mysql.user where user like 'user_%'; diff --git a/mysql-test/suite/roles/set_default_role_invalid.result b/mysql-test/suite/roles/set_default_role_invalid.result index c98e6e7d2a9..b18f0154c91 100644 --- a/mysql-test/suite/roles/set_default_role_invalid.result +++ b/mysql-test/suite/roles/set_default_role_invalid.result @@ -5,7 +5,7 @@ grant select on *.* to test_role; grant test_role to test_user@localhost; show grants; Grants for test_user@localhost -GRANT test_role TO 'test_user'@'localhost' +GRANT 'test_role' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' select user, host, default_role from mysql.user; ERROR 42000: SELECT command denied to user 'test_user'@'localhost' for table 'user' @@ -21,10 +21,10 @@ user host default_role test_user localhost test_role show grants; Grants for test_user@localhost -GRANT test_role TO 'test_user'@'localhost' +GRANT 'test_role' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' GRANT SELECT ON *.* TO 'test_role' -SET DEFAULT ROLE test_role FOR 'test_user'@'localhost' +SET DEFAULT ROLE 'test_role' FOR 'test_user'@'localhost' select user, host, default_role from mysql.user where user='test_user'; user host default_role test_user localhost test_role @@ -68,11 +68,11 @@ GRANT SELECT ON mysql.* TO b; # Change user b (session 1: select_priv) SHOW GRANTS FOR b; Grants for b@% -GRANT r1 TO 'b'@'%' -GRANT r2 TO 'b'@'%' +GRANT 'r1' TO 'b'@'%' +GRANT 'r2' TO 'b'@'%' GRANT USAGE ON *.* TO 'b'@'%' GRANT SELECT ON `mysql`.* TO 'b'@'%' -SET DEFAULT ROLE r2 FOR 'b'@'%' +SET DEFAULT ROLE 'r2' FOR 'b'@'%' SET DEFAULT ROLE r1 FOR a; ERROR 42000: Access denied for user 'b'@'%' to database 'mysql' SELECT CURRENT_ROLE; @@ -94,11 +94,11 @@ GRANT UPDATE ON mysql.* TO b; # Change user b SHOW GRANTS FOR b; Grants for b@% -GRANT r1 TO 'b'@'%' -GRANT r2 TO 'b'@'%' +GRANT 'r1' TO 'b'@'%' +GRANT 'r2' TO 'b'@'%' GRANT USAGE ON *.* TO 'b'@'%' GRANT SELECT, UPDATE ON `mysql`.* TO 'b'@'%' -SET DEFAULT ROLE r2 FOR 'b'@'%' +SET DEFAULT ROLE 'r2' FOR 'b'@'%' SET DEFAULT ROLE r1 FOR a; ERROR OP000: User `b`@`%` has not been granted role `r1` SET DEFAULT ROLE invalid_role; diff --git a/mysql-test/suite/roles/set_default_role_new_connection.result b/mysql-test/suite/roles/set_default_role_new_connection.result index 75e4075ff9e..79ce800ed43 100644 --- a/mysql-test/suite/roles/set_default_role_new_connection.result +++ b/mysql-test/suite/roles/set_default_role_new_connection.result @@ -5,7 +5,7 @@ grant test_role to test_user@localhost; connect c1, localhost, test_user,,; show grants; Grants for test_user@localhost -GRANT test_role TO 'test_user'@'localhost' +GRANT 'test_role' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' select user, host, default_role from mysql.user where user = 'test_user'; ERROR 42000: SELECT command denied to user 'test_user'@'localhost' for table 'user' @@ -20,10 +20,10 @@ test_user localhost test_role connect c1, localhost, test_user,,; show grants; Grants for test_user@localhost -GRANT test_role TO 'test_user'@'localhost' +GRANT 'test_role' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' GRANT SELECT ON *.* TO 'test_role' -SET DEFAULT ROLE test_role FOR 'test_user'@'localhost' +SET DEFAULT ROLE 'test_role' FOR 'test_user'@'localhost' select user, host, default_role from mysql.user where user = 'test_user'; user host default_role test_user localhost test_role @@ -36,7 +36,7 @@ test_user localhost connect c1, localhost, test_user,,; show grants; Grants for test_user@localhost -GRANT test_role TO 'test_user'@'localhost' +GRANT 'test_role' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' select user, host, default_role from mysql.user where user = 'test_user'; ERROR 42000: SELECT command denied to user 'test_user'@'localhost' for table 'user' @@ -49,10 +49,10 @@ set default role test_role for test_user@localhost; connect c1, localhost, test_user,,; show grants; Grants for test_user@localhost -GRANT test_role TO 'test_user'@'localhost' +GRANT 'test_role' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' GRANT SELECT ON *.* TO 'test_role' -SET DEFAULT ROLE test_role FOR 'test_user'@'localhost' +SET DEFAULT ROLE 'test_role' FOR 'test_user'@'localhost' select user, host, default_role from mysql.user where user = 'test_user'; user host default_role test_user localhost test_role diff --git a/mysql-test/suite/roles/set_role-13655.result b/mysql-test/suite/roles/set_role-13655.result index c30e4115953..9d7008ad921 100644 --- a/mysql-test/suite/roles/set_role-13655.result +++ b/mysql-test/suite/roles/set_role-13655.result @@ -18,7 +18,7 @@ create role admin; grant simple to admin; show grants for admin; Grants for admin -GRANT simple TO 'admin' +GRANT 'simple' TO 'admin' GRANT USAGE ON *.* TO 'admin' GRANT USAGE ON *.* TO 'simple' GRANT SELECT, INSERT, UPDATE, DELETE, LOCK TABLES, EXECUTE ON `t`.* TO 'simple' @@ -37,9 +37,9 @@ ERROR 42000: Access denied for user 'foo'@'%' to database 't' set role admin; show grants; Grants for foo@% -GRANT admin TO 'foo'@'%' +GRANT 'admin' TO 'foo'@'%' GRANT USAGE ON *.* TO 'foo'@'%' -GRANT simple TO 'admin' +GRANT 'simple' TO 'admin' GRANT USAGE ON *.* TO 'admin' GRANT ALL PRIVILEGES ON `t`.* TO 'admin' GRANT USAGE ON *.* TO 'simple' diff --git a/mysql-test/suite/roles/set_role-9614.result b/mysql-test/suite/roles/set_role-9614.result index 37f6db070c0..60986c2c133 100644 --- a/mysql-test/suite/roles/set_role-9614.result +++ b/mysql-test/suite/roles/set_role-9614.result @@ -35,11 +35,11 @@ GRANT `client` TO `usertestjohn`@`%`; # SHOW GRANTS FOR `john`@`%`; Grants for john@% -GRANT client TO 'john'@'%' +GRANT 'client' TO 'john'@'%' GRANT USAGE ON *.* TO 'john'@'%' SHOW GRANTS FOR `usertestjohn`@`%`; Grants for usertestjohn@% -GRANT client TO 'usertestjohn'@'%' +GRANT 'client' TO 'usertestjohn'@'%' GRANT USAGE ON *.* TO 'usertestjohn'@'%' SHOW GRANTS FOR `client`; Grants for client @@ -84,7 +84,7 @@ information_schema test show grants; Grants for usertestjohn@% -GRANT client TO 'usertestjohn'@'%' +GRANT 'client' TO 'usertestjohn'@'%' GRANT USAGE ON *.* TO 'usertestjohn'@'%' GRANT USAGE ON *.* TO 'client' GRANT SELECT ON `bug_db`.`t0` TO 'client' diff --git a/mysql-test/suite/roles/set_role-database-recursive.result b/mysql-test/suite/roles/set_role-database-recursive.result index 479e553c3d1..64cf2a2f9af 100644 --- a/mysql-test/suite/roles/set_role-database-recursive.result +++ b/mysql-test/suite/roles/set_role-database-recursive.result @@ -67,6 +67,11 @@ set role test_role1; delete from mysql.user where user='no such user'; show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' +GRANT 'test_role2' TO 'test_role1' +GRANT 'test_role2' TO 'test_user'@'localhost' +GRANT 'test_role3' TO 'test_role2' +GRANT 'test_role4' TO 'test_role3' GRANT DELETE ON `mysql`.* TO 'test_role4' GRANT SELECT ON `mysql`.* TO 'test_role2' GRANT USAGE ON *.* TO 'test_role1' @@ -74,10 +79,5 @@ GRANT USAGE ON *.* TO 'test_role2' GRANT USAGE ON *.* TO 'test_role3' GRANT USAGE ON *.* TO 'test_role4' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' -GRANT test_role2 TO 'test_role1' -GRANT test_role2 TO 'test_user'@'localhost' -GRANT test_role3 TO 'test_role2' -GRANT test_role4 TO 'test_role3' drop user test_user@localhost; drop role test_role1, test_role2, test_role3, test_role4; diff --git a/mysql-test/suite/roles/set_role-multiple-role.result b/mysql-test/suite/roles/set_role-multiple-role.result index fca53b4d645..eb359e85f52 100644 --- a/mysql-test/suite/roles/set_role-multiple-role.result +++ b/mysql-test/suite/roles/set_role-multiple-role.result @@ -25,14 +25,14 @@ select * from mysql.roles_mapping; ERROR 42000: SELECT command denied to user 'test_user'@'localhost' for table 'roles_mapping' show grants; Grants for test_user@localhost +GRANT 'r_crt' TO 'test_user'@'localhost' +GRANT 'r_del' TO 'test_user'@'localhost' +GRANT 'r_drp' TO 'test_user'@'localhost' +GRANT 'r_ins' TO 'test_user'@'localhost' +GRANT 'r_rld' TO 'test_user'@'localhost' +GRANT 'r_sel' TO 'test_user'@'localhost' +GRANT 'r_upd' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT r_crt TO 'test_user'@'localhost' -GRANT r_del TO 'test_user'@'localhost' -GRANT r_drp TO 'test_user'@'localhost' -GRANT r_ins TO 'test_user'@'localhost' -GRANT r_rld TO 'test_user'@'localhost' -GRANT r_sel TO 'test_user'@'localhost' -GRANT r_upd TO 'test_user'@'localhost' select current_user(), current_role(); current_user() current_role() test_user@localhost NULL @@ -42,15 +42,15 @@ current_user() current_role() test_user@localhost r_sel show grants; Grants for test_user@localhost +GRANT 'r_crt' TO 'test_user'@'localhost' +GRANT 'r_del' TO 'test_user'@'localhost' +GRANT 'r_drp' TO 'test_user'@'localhost' +GRANT 'r_ins' TO 'test_user'@'localhost' +GRANT 'r_rld' TO 'test_user'@'localhost' +GRANT 'r_sel' TO 'test_user'@'localhost' +GRANT 'r_upd' TO 'test_user'@'localhost' GRANT SELECT ON *.* TO 'r_sel' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT r_crt TO 'test_user'@'localhost' -GRANT r_del TO 'test_user'@'localhost' -GRANT r_drp TO 'test_user'@'localhost' -GRANT r_ins TO 'test_user'@'localhost' -GRANT r_rld TO 'test_user'@'localhost' -GRANT r_sel TO 'test_user'@'localhost' -GRANT r_upd TO 'test_user'@'localhost' select * from mysql.roles_mapping; Host User Role Admin_option localhost root r_crt Y @@ -73,15 +73,15 @@ current_user() current_role() test_user@localhost r_ins show grants; Grants for test_user@localhost +GRANT 'r_crt' TO 'test_user'@'localhost' +GRANT 'r_del' TO 'test_user'@'localhost' +GRANT 'r_drp' TO 'test_user'@'localhost' +GRANT 'r_ins' TO 'test_user'@'localhost' +GRANT 'r_rld' TO 'test_user'@'localhost' +GRANT 'r_sel' TO 'test_user'@'localhost' +GRANT 'r_upd' TO 'test_user'@'localhost' GRANT INSERT ON *.* TO 'r_ins' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT r_crt TO 'test_user'@'localhost' -GRANT r_del TO 'test_user'@'localhost' -GRANT r_drp TO 'test_user'@'localhost' -GRANT r_ins TO 'test_user'@'localhost' -GRANT r_rld TO 'test_user'@'localhost' -GRANT r_sel TO 'test_user'@'localhost' -GRANT r_upd TO 'test_user'@'localhost' select * from mysql.roles_mapping; ERROR 42000: SELECT command denied to user 'test_user'@'localhost' for table 'roles_mapping' insert into mysql.roles_mapping values ('', 'r_sel', 'r_rld', 'N'); diff --git a/mysql-test/suite/roles/set_role-recursive.result b/mysql-test/suite/roles/set_role-recursive.result index fc5322a692e..fb62019c2e4 100644 --- a/mysql-test/suite/roles/set_role-recursive.result +++ b/mysql-test/suite/roles/set_role-recursive.result @@ -25,8 +25,8 @@ select * from mysql.roles_mapping; ERROR 42000: SELECT command denied to user 'test_user'@'localhost' for table 'roles_mapping' show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' select current_user(), current_role(); current_user() current_role() test_user@localhost NULL @@ -36,35 +36,35 @@ current_user() current_role() test_user@localhost test_role1 show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' +GRANT 'test_role2' TO 'test_role1' GRANT SELECT ON *.* TO 'test_role2' GRANT USAGE ON *.* TO 'test_role1' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' -GRANT test_role2 TO 'test_role1' select * from mysql.roles_mapping where Host=''; Host User Role Admin_option test_role1 test_role2 N show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' +GRANT 'test_role2' TO 'test_role1' GRANT SELECT ON *.* TO 'test_role2' GRANT USAGE ON *.* TO 'test_role1' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' -GRANT test_role2 TO 'test_role1' set role none; select current_user(), current_role(); current_user() current_role() test_user@localhost NULL show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' select * from mysql.roles_mapping; ERROR 42000: SELECT command denied to user 'test_user'@'localhost' for table 'roles_mapping' show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' set role test_role2; ERROR OP000: User `test_user`@`localhost` has not been granted role `test_role2` select current_user(), current_role(); @@ -72,43 +72,43 @@ current_user() current_role() test_user@localhost NULL show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' select * from mysql.roles_mapping; ERROR 42000: SELECT command denied to user 'test_user'@'localhost' for table 'roles_mapping' show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' set role test_role1; select current_user(), current_role(); current_user() current_role() test_user@localhost test_role1 show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' +GRANT 'test_role2' TO 'test_role1' GRANT SELECT ON *.* TO 'test_role2' GRANT USAGE ON *.* TO 'test_role1' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' -GRANT test_role2 TO 'test_role1' select * from mysql.roles_mapping where Host=''; Host User Role Admin_option test_role1 test_role2 N show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' +GRANT 'test_role2' TO 'test_role1' GRANT SELECT ON *.* TO 'test_role2' GRANT USAGE ON *.* TO 'test_role1' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' -GRANT test_role2 TO 'test_role1' set role none; select current_user(), current_role(); current_user() current_role() test_user@localhost NULL show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' select * from mysql.roles_mapping; ERROR 42000: SELECT command denied to user 'test_user'@'localhost' for table 'roles_mapping' delete from mysql.user where user='test_role1'; diff --git a/mysql-test/suite/roles/set_role-routine-simple.result b/mysql-test/suite/roles/set_role-routine-simple.result index 3e17a78ad77..b25926af209 100644 --- a/mysql-test/suite/roles/set_role-routine-simple.result +++ b/mysql-test/suite/roles/set_role-routine-simple.result @@ -31,9 +31,9 @@ grant execute on procedure mysql.test_proc to test_role2; grant execute on mysql.* to test_role3; show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' +GRANT 'test_role3' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' -GRANT test_role3 TO 'test_user'@'localhost' use mysql; ERROR 42000: Access denied for user 'test_user'@'localhost' to database 'mysql' select current_user(), current_role(); @@ -53,23 +53,23 @@ test_func('AABBCCDD') Test string: AABBCCDD show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' +GRANT 'test_role2' TO 'test_role1' +GRANT 'test_role3' TO 'test_user'@'localhost' GRANT EXECUTE ON FUNCTION `mysql`.`test_func` TO 'test_role2' GRANT EXECUTE ON PROCEDURE `mysql`.`test_proc` TO 'test_role2' GRANT USAGE ON *.* TO 'test_role1' GRANT USAGE ON *.* TO 'test_role2' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' -GRANT test_role2 TO 'test_role1' -GRANT test_role3 TO 'test_user'@'localhost' set role none; select current_user(), current_role(); current_user() current_role() test_user@localhost NULL show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' +GRANT 'test_role3' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' -GRANT test_role3 TO 'test_user'@'localhost' call test_proc(@a); ERROR 42000: execute command denied to user 'test_user'@'localhost' for routine 'mysql.test_proc' SELECT test_func('AABBCCDD'); @@ -80,11 +80,11 @@ current_user() current_role() test_user@localhost test_role3 show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' +GRANT 'test_role3' TO 'test_user'@'localhost' GRANT EXECUTE ON `mysql`.* TO 'test_role3' GRANT USAGE ON *.* TO 'test_role3' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' -GRANT test_role3 TO 'test_user'@'localhost' call test_proc(@a); SELECT @a; @a diff --git a/mysql-test/suite/roles/set_role-simple.result b/mysql-test/suite/roles/set_role-simple.result index 29b176776e7..0eeba8f6c64 100644 --- a/mysql-test/suite/roles/set_role-simple.result +++ b/mysql-test/suite/roles/set_role-simple.result @@ -17,8 +17,8 @@ select * from mysql.roles_mapping; ERROR 42000: SELECT command denied to user 'test_user'@'localhost' for table 'roles_mapping' show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' select current_user(), current_role(); current_user() current_role() test_user@localhost NULL @@ -28,9 +28,9 @@ current_user() current_role() test_user@localhost test_role1 show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' GRANT SELECT ON *.* TO 'test_role1' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' select * from mysql.roles_mapping; Host User Role Admin_option localhost root test_role1 Y diff --git a/mysql-test/suite/roles/set_role-table-column-priv.result b/mysql-test/suite/roles/set_role-table-column-priv.result index 721bd3039a3..ca1cbd8004f 100644 --- a/mysql-test/suite/roles/set_role-table-column-priv.result +++ b/mysql-test/suite/roles/set_role-table-column-priv.result @@ -19,8 +19,8 @@ select * from mysql.roles_mapping; ERROR 42000: SELECT command denied to user 'test_user'@'localhost' for table 'roles_mapping' show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' select current_user(), current_role(); current_user() current_role() test_user@localhost NULL @@ -30,12 +30,12 @@ current_user() current_role() test_user@localhost test_role1 show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' +GRANT 'test_role2' TO 'test_role1' GRANT SELECT (Role) ON `mysql`.`roles_mapping` TO 'test_role2' GRANT USAGE ON *.* TO 'test_role1' GRANT USAGE ON *.* TO 'test_role2' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' -GRANT test_role2 TO 'test_role1' select * from mysql.roles_mapping; ERROR 42000: SELECT command denied to user 'test_user'@'localhost' for column 'Host' in table 'roles_mapping' select Role from mysql.roles_mapping; @@ -46,12 +46,12 @@ test_role2 test_role2 show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' +GRANT 'test_role2' TO 'test_role1' GRANT SELECT (Role) ON `mysql`.`roles_mapping` TO 'test_role2' GRANT USAGE ON *.* TO 'test_role1' GRANT USAGE ON *.* TO 'test_role2' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' -GRANT test_role2 TO 'test_role1' use mysql; set role none; select current_user(), current_role(); diff --git a/mysql-test/suite/roles/set_role-table-simple.result b/mysql-test/suite/roles/set_role-table-simple.result index f5688dbe62e..57fcb78ea09 100644 --- a/mysql-test/suite/roles/set_role-table-simple.result +++ b/mysql-test/suite/roles/set_role-table-simple.result @@ -19,8 +19,8 @@ select * from mysql.roles_mapping; ERROR 42000: SELECT command denied to user 'test_user'@'localhost' for table 'roles_mapping' show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' select current_user(), current_role(); current_user() current_role() test_user@localhost NULL @@ -30,12 +30,12 @@ current_user() current_role() test_user@localhost test_role1 show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' +GRANT 'test_role2' TO 'test_role1' GRANT SELECT ON `mysql`.`roles_mapping` TO 'test_role2' GRANT USAGE ON *.* TO 'test_role1' GRANT USAGE ON *.* TO 'test_role2' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' -GRANT test_role2 TO 'test_role1' select * from mysql.roles_mapping; Host User Role Admin_option test_role1 test_role2 N @@ -44,12 +44,12 @@ localhost root test_role2 Y localhost test_user test_role1 N show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' +GRANT 'test_role2' TO 'test_role1' GRANT SELECT ON `mysql`.`roles_mapping` TO 'test_role2' GRANT USAGE ON *.* TO 'test_role1' GRANT USAGE ON *.* TO 'test_role2' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' -GRANT test_role2 TO 'test_role1' use mysql; set role none; select current_user(), current_role(); diff --git a/mysql-test/suite/roles/show_grants.result b/mysql-test/suite/roles/show_grants.result index b523211420b..7732daa6d93 100644 --- a/mysql-test/suite/roles/show_grants.result +++ b/mysql-test/suite/roles/show_grants.result @@ -34,9 +34,9 @@ test_user@localhost test_role1 NO NO test_user@localhost test_role2 NO NO show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' +GRANT 'test_role2' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' -GRANT test_role2 TO 'test_user'@'localhost' select current_user(), current_role(); current_user() current_role() test_user@localhost NULL @@ -50,13 +50,13 @@ current_user() current_role() test_user@localhost test_role1 show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' +GRANT 'test_role2' TO 'test_role1' +GRANT 'test_role2' TO 'test_user'@'localhost' GRANT SELECT ON `mysql`.* TO 'test_role2' GRANT USAGE ON *.* TO 'test_role1' GRANT USAGE ON *.* TO 'test_role2' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' -GRANT test_role2 TO 'test_role1' -GRANT test_role2 TO 'test_user'@'localhost' set role none; select * from information_schema.enabled_roles; ROLE_NAME @@ -66,28 +66,28 @@ current_user() current_role() test_user@localhost NULL show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' +GRANT 'test_role2' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' -GRANT test_role2 TO 'test_user'@'localhost' show grants for test_user@localhost; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' +GRANT 'test_role2' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' -GRANT test_role2 TO 'test_user'@'localhost' show grants for test_role1; ERROR 42000: Access denied for user 'test_user'@'localhost' to database 'mysql' show grants for test_role2; ERROR 42000: Access denied for user 'test_user'@'localhost' to database 'mysql' show grants for CURRENT_USER; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' +GRANT 'test_role2' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' -GRANT test_role2 TO 'test_user'@'localhost' show grants for CURRENT_USER(); Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' +GRANT 'test_role2' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' -GRANT test_role2 TO 'test_user'@'localhost' show grants for CURRENT_ROLE; ERROR 42000: There is no such grant defined for user 'test_user' on host 'localhost' show grants for CURRENT_ROLE(); @@ -101,36 +101,36 @@ current_user() current_role() test_user@localhost test_role2 show grants; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' +GRANT 'test_role2' TO 'test_user'@'localhost' GRANT SELECT ON `mysql`.* TO 'test_role2' GRANT USAGE ON *.* TO 'test_role2' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' -GRANT test_role2 TO 'test_user'@'localhost' show grants for test_user@localhost; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' +GRANT 'test_role2' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' -GRANT test_role2 TO 'test_user'@'localhost' show grants for test_role1; Grants for test_role1 +GRANT 'test_role2' TO 'test_role1' GRANT SELECT ON `mysql`.* TO 'test_role2' GRANT USAGE ON *.* TO 'test_role1' GRANT USAGE ON *.* TO 'test_role2' -GRANT test_role2 TO 'test_role1' show grants for test_role2; Grants for test_role2 GRANT SELECT ON `mysql`.* TO 'test_role2' GRANT USAGE ON *.* TO 'test_role2' show grants for CURRENT_USER; Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' +GRANT 'test_role2' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' -GRANT test_role2 TO 'test_user'@'localhost' show grants for CURRENT_USER(); Grants for test_user@localhost +GRANT 'test_role1' TO 'test_user'@'localhost' +GRANT 'test_role2' TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost' -GRANT test_role1 TO 'test_user'@'localhost' -GRANT test_role2 TO 'test_user'@'localhost' show grants for CURRENT_ROLE; Grants for test_role2 GRANT SELECT ON `mysql`.* TO 'test_role2' diff --git a/mysql-test/suite/roles/show_grants_replicated.result b/mysql-test/suite/roles/show_grants_replicated.result index cb9df65dbbd..f26a22c8ee6 100644 --- a/mysql-test/suite/roles/show_grants_replicated.result +++ b/mysql-test/suite/roles/show_grants_replicated.result @@ -44,7 +44,7 @@ GRANT USAGE ON *.* TO 'r1' set role r1; show grants; Grants for root@localhost -GRANT r1 TO 'root'@'localhost' WITH ADMIN OPTION +GRANT 'r1' TO 'root'@'localhost' WITH ADMIN OPTION GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION GRANT USAGE ON *.* TO 'r1' diff --git a/mysql-test/t/grant5.test b/mysql-test/t/grant5.test index 944918e63ec..d8c62691a84 100644 --- a/mysql-test/t/grant5.test +++ b/mysql-test/t/grant5.test @@ -70,6 +70,29 @@ SHOW GRANTS; DROP USER test_user; DROP ROLE test_role; +# +# MDEV-26080 SHOW GRANTS does not quote role names properly for DEFAULT ROLE +# + +CREATE ROLE 'test-role'; +CREATE USER 'test-user'; +GRANT 'test-role' TO 'test-user'; +SET DEFAULT ROLE 'test-role' FOR 'test-user'; +SHOW GRANTS FOR 'test-user'; +DROP ROLE 'test-role'; +SHOW GRANTS FOR 'test-user'; +SET DEFAULT ROLE NONE FOR 'test-user'; +SHOW GRANTS FOR 'test-user'; +CREATE ROLE `r``o'l"e`; +select user from mysql.user where is_role='Y'; +GRANT `r``o'l"e` TO 'test-user'; +SET DEFAULT ROLE `r``o'l"e` FOR 'test-user'; +# it is expected that quotes won't be shown correctly +SHOW GRANTS FOR 'test-user'; +DROP ROLE `r``o'l"e`; +DROP USER 'test-user'; + + # # End of 10.1 tests # diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 2d91254435a..89fecc92e9b 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -8847,9 +8847,9 @@ static bool show_default_role(THD *thd, ACL_USER *acl_entry, { String def_str(buff, buffsize, system_charset_info); def_str.length(0); - def_str.append(STRING_WITH_LEN("SET DEFAULT ROLE ")); + def_str.append(STRING_WITH_LEN("SET DEFAULT ROLE '")); def_str.append(&def_rolename); - def_str.append(" FOR '"); + def_str.append("' FOR '"); def_str.append(&acl_entry->user); DBUG_ASSERT(!(acl_entry->flags & IS_ROLE)); def_str.append(STRING_WITH_LEN("'@'")); @@ -8878,12 +8878,12 @@ static bool show_role_grants(THD *thd, const char *hostname, for (counter= 0; counter < acl_entry->role_grants.elements; counter++) { grant.length(0); - grant.append(STRING_WITH_LEN("GRANT ")); + grant.append(STRING_WITH_LEN("GRANT '")); ACL_ROLE *acl_role= *(dynamic_element(&acl_entry->role_grants, counter, ACL_ROLE**)); grant.append(acl_role->user.str, acl_role->user.length, system_charset_info); - grant.append(STRING_WITH_LEN(" TO '")); + grant.append(STRING_WITH_LEN("' TO '")); grant.append(acl_entry->user.str, acl_entry->user.length, system_charset_info); if (!(acl_entry->flags & IS_ROLE)) From 85063aebda7e4b691c04a90b0c38a6df3873a84e Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Wed, 28 Oct 2020 19:45:54 +0100 Subject: [PATCH 11/35] Update description of mariadb-common package - Commit https://github.com/mariadb/server/commit/438ed0408c69 introduced `mariadb-common` package and added description. Example in description is confusing since files referred to are not installed and not related/owned by the `mariadb-common` package. - Patch is updating real file/directory description section pointing to the real examples owned by the package. - Example: ``` mariadb-client-10.3 install mariadb-client-core-10.3 install mariadb-common install mariadb-server install mariadb-server-10.3 install mariadb-server-core-10.3 install /. /etc /etc/mysql /etc/mysql/mariadb.cnf /etc/mysql/mariadb.conf.d /usr /usr/share /usr/share/doc /usr/share/doc/mariadb-common /usr/share/doc/mariadb-common/changelog.Debian.gz /usr/share/doc/mariadb-common/copyright ``` Closes PR #1690 Reviewed by: otto@kekalainen.net --- debian/control | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/control b/debian/control index c906c1bd505..372abafe205 100644 --- a/debian/control +++ b/debian/control @@ -164,14 +164,14 @@ Description: MariaDB database common files (e.g. /etc/mysql/my.cnf) Package: mariadb-common Architecture: all Depends: mysql-common, ${misc:Depends}, ${shlibs:Depends} -Description: MariaDB database common files (e.g. /etc/mysql/conf.d/mariadb.cnf) +Description: MariaDB database common files (e.g. /etc/mysql/mariadb.conf.d/) MariaDB is a fast, stable and true multi-user, multi-threaded SQL database server. SQL (Structured Query Language) is the most popular database query language in the world. The main goals of MariaDB are speed, robustness and ease of use. . This package includes files needed by all versions of the client library - (e.g. /etc/mysql/conf.d/mariadb.cnf). + (e.g. /etc/mysql/mariadb.conf.d/ or /etc/mysql/mariadb.cnf). Package: mariadb-client-core-10.2 Architecture: any From fb0b28932ce82903f2fcfb690a71bff52355507f Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Thu, 8 Jul 2021 17:47:24 +0530 Subject: [PATCH 12/35] MDEV-25998 encryption.innodb_encryption_filekeys failure in buildbot - Set the innodb_encrypt_tables variable before timeout happens. It will add the pending tablespace to default encrypt list and does the encryption/decryption based on innodb_encrypt_tables. --- .../t/innodb_encryption_filekeys.test | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/mysql-test/suite/encryption/t/innodb_encryption_filekeys.test b/mysql-test/suite/encryption/t/innodb_encryption_filekeys.test index 03447bbcfa6..cd5724638b1 100644 --- a/mysql-test/suite/encryption/t/innodb_encryption_filekeys.test +++ b/mysql-test/suite/encryption/t/innodb_encryption_filekeys.test @@ -48,6 +48,12 @@ while ($cnt) { real_sleep 1; dec $cnt; + if ($cnt == 200) + { + --disable_query_log + set global innodb_encrypt_tables = on; + --enable_query_log + } } } if (!$success) @@ -78,6 +84,12 @@ while ($cnt) { real_sleep 1; dec $cnt; + if ($cnt == 200) + { + --disable_query_log + set global innodb_encrypt_tables = off; + --enable_query_log + } } } if (!$success) @@ -107,6 +119,12 @@ while ($cnt) { real_sleep 1; dec $cnt; + if ($cnt == 200) + { + --disable_query_log + set global innodb_encrypt_tables=on; + --enable_query_log + } } } if (!$success) From b082716892071fdc3c961e9afaa011e0f6beb102 Mon Sep 17 00:00:00 2001 From: Robert Bindar Date: Fri, 2 Jul 2021 09:34:25 +0300 Subject: [PATCH 13/35] MDEV-21206 Can't link zlib library during DBD::mysql installation mysql_config should never return -lzlib as linking flag. Clients trying to link against mariadb that use the output of mysql_config experience linking error because we return -lzlib when we don't ship any libzlib.a in our binary tarballs, bundled zlib static library is already linked. --- cmake/for_clients.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/for_clients.cmake b/cmake/for_clients.cmake index e5916c56ddc..e52e3b34f21 100644 --- a/cmake/for_clients.cmake +++ b/cmake/for_clients.cmake @@ -24,7 +24,7 @@ MACRO(EXTRACT_LINK_LIBRARIES target var) FOREACH(lib ${${target}_LIB_DEPENDS}) # Filter out "general", it is not a library, just CMake hint # Also, remove duplicates - IF(NOT lib STREQUAL "general" AND NOT ${var} MATCHES "-l${lib} ") + IF(NOT lib STREQUAL "general" AND NOT ${var} MATCHES "-l${lib} " AND NOT lib STREQUAL "zlib") IF (lib MATCHES "^\\-") SET(${var} "${${var}} ${lib} ") ELSEIF(lib MATCHES "^/") From 0e9ba176bf2ad4d44e62b8f6e4e1916b39c5bf33 Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Mon, 21 Jun 2021 04:00:16 +0300 Subject: [PATCH 14/35] MDEV-17890 Server crash on DELETE with YEAR field with truncated expr The failing reason was inconsistent truncation rules: the value of virtual column could have been evaluated to '2000' sometimes instead of '0000' for value 'a'. The reason why `c YEAR AS ('aaaa')` was not evaluated same is that len=4 is a special case insidew Field_year::store. The correct fix is: always evaluate a bad value to 0000 instead 2000. The truncated values should be evaluated as usual. $support_virtual_index is finally changed to 1 in gcol.gcol_ins_upd_innodb, which is also enough for testing. The test from original bug report is also added. --- mysql-test/suite/gcol/inc/gcol_ins_upd.inc | 22 +++ mysql-test/suite/gcol/inc/gcol_keys.inc | 2 +- .../suite/gcol/r/gcol_ins_upd_innodb.result | 171 ++++++++++++++++++ .../suite/gcol/r/gcol_ins_upd_myisam.result | 21 ++- .../suite/gcol/r/gcol_keys_innodb.result | 2 +- .../suite/gcol/r/gcol_keys_myisam.result | 2 +- .../suite/gcol/t/gcol_ins_upd_innodb.test | 2 +- sql/field.cc | 10 +- 8 files changed, 225 insertions(+), 7 deletions(-) diff --git a/mysql-test/suite/gcol/inc/gcol_ins_upd.inc b/mysql-test/suite/gcol/inc/gcol_ins_upd.inc index 7fde9c2e852..6bd7974f2af 100644 --- a/mysql-test/suite/gcol/inc/gcol_ins_upd.inc +++ b/mysql-test/suite/gcol/inc/gcol_ins_upd.inc @@ -607,4 +607,26 @@ DELETE FROM t1; DROP TEMPORARY TABLE t1; +--echo # +--echo # Original test case from MDEV-17890 +--echo # + +CREATE TABLE t1 ( + pk BIGINT AUTO_INCREMENT, + b BIT(15), + v BIT(10) AS (b) VIRTUAL, + PRIMARY KEY(pk), + UNIQUE(v) +); + +INSERT IGNORE INTO t1 (b) VALUES (b'101110001110100'),(b'011101'); +SELECT pk, b FROM t1 INTO OUTFILE 'load.data'; +--error ER_DATA_TOO_LONG +LOAD DATA INFILE 'load.data' REPLACE INTO TABLE t1 (pk, b); + +# Cleanup +DROP TABLE t1; +--let $datadir= `SELECT @@datadir` +--remove_file $datadir/test/load.data + } diff --git a/mysql-test/suite/gcol/inc/gcol_keys.inc b/mysql-test/suite/gcol/inc/gcol_keys.inc index e5f7f976120..cf0612b0d0c 100644 --- a/mysql-test/suite/gcol/inc/gcol_keys.inc +++ b/mysql-test/suite/gcol/inc/gcol_keys.inc @@ -812,7 +812,7 @@ DROP TABLE t1; --echo # MDEV-19011 Assertion `file->s->base.reclength < file->s->vreclength' --echo # failed in ha_myisam::setup_vcols_for_repair -CREATE TABLE t1 (a INT GENERATED ALWAYS AS (1) VIRTUAL) ENGINE=MyISAM; +CREATE TABLE t1 (a INT GENERATED ALWAYS AS (1) VIRTUAL); ALTER TABLE t1 ADD KEY (a); DROP TABLE t1; diff --git a/mysql-test/suite/gcol/r/gcol_ins_upd_innodb.result b/mysql-test/suite/gcol/r/gcol_ins_upd_innodb.result index 3024b58da54..99e47c2d168 100644 --- a/mysql-test/suite/gcol/r/gcol_ins_upd_innodb.result +++ b/mysql-test/suite/gcol/r/gcol_ins_upd_innodb.result @@ -435,6 +435,26 @@ UPDATE t1 SET col1 = 2; UPDATE t1 SET col7 = DEFAULT; UPDATE t1 SET col8 = DEFAULT; DROP TABLE t1; +Bug#20797344: WL#8149: ALLOCATED SPACE FOR INDEXED BLOB VGC CAN BE +OVERWRITTEN FOR UPDATE +# +CREATE TABLE t (a varchar(100), b blob, +c blob GENERATED ALWAYS AS (concat(a,b)) VIRTUAL, +d blob GENERATED ALWAYS AS (b) VIRTUAL, +e int(11) GENERATED ALWAYS AS (10) VIRTUAL, +h int(11) NOT NULL, PRIMARY KEY (h), key(c(20))); +INSERT INTO t(a,b,h) VALUES('aaaaaaa','1111111', 11); +INSERT INTO t(a,b,h) VALUES('bbbbbbb','2222222', 22); +SELECT c FROM t; +c +aaaaaaa1111111 +bbbbbbb2222222 +UPDATE t SET a='ccccccc'; +SELECT c FROM t; +c +ccccccc1111111 +ccccccc2222222 +DROP TABLE t; # Bug#21081742: ASSERTION !TABLE || (!TABLE->WRITE_SET || # BITMAP_IS_SET(TABLE->WRITE_SET # @@ -491,6 +511,21 @@ SELECT * FROM t; x y gc 2 1 3 DROP TABLE t; +CREATE TABLE t ( +x INT, y INT, gc INT GENERATED ALWAYS AS (x+1), KEY (x,gc) +); +INSERT INTO t VALUES (); +UPDATE t t1, t t2 SET t1.x = 1, t2.y = 2; +SELECT * FROM t; +x y gc +1 2 2 +SELECT gc FROM t; +gc +2 +CHECK TABLE t; +Table Op Msg_type Msg_text +test.t check status OK +DROP TABLE t; # stored CREATE TABLE C ( col_varchar_nokey VARCHAR(1), @@ -552,6 +587,99 @@ SELECT * from C; col_varchar_nokey col_varchar_key a aa DROP TABLE C; +# virtual, indexed +CREATE TABLE C ( +col_varchar_nokey VARCHAR(1), +col_varchar_key VARCHAR(2) GENERATED ALWAYS AS +(CONCAT(col_varchar_nokey, col_varchar_nokey)) VIRTUAL, +KEY (col_varchar_key, col_varchar_nokey) +); +INSERT INTO C (col_varchar_nokey) VALUES ('c'); +EXPLAIN UPDATE C AS OUTR1, C AS OUTR2 +SET OUTR1.`col_varchar_nokey` = 'f', +OUTR2.`col_varchar_nokey` = "a"; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE OUTR1 ALL NULL NULL NULL NULL 1 +1 SIMPLE OUTR2 ALL NULL NULL NULL NULL 1 +UPDATE C AS OUTR1, C AS OUTR2 +SET OUTR1.`col_varchar_nokey` = 'f', +OUTR2.`col_varchar_nokey` = "a"; +SELECT * from C; +col_varchar_nokey col_varchar_key +a aa +DROP TABLE C; +# +# Bug #21530366 CRASH/ASSERTION, CORRUPTION WITH INDEXES + +# VIRTUAL COLUMNS, BLOB +# +CREATE TABLE t ( +a INTEGER, +b BLOB GENERATED ALWAYS AS (a) VIRTUAL, +INDEX (b(57)) +); +INSERT INTO t (a) VALUES (9); +UPDATE t SET a = 10; +DELETE FROM t WHERE a = 10; +DROP TABLE t; +# Bug#21807818: Generated columns not updated with empty insert list +CREATE TABLE t ( +a BLOB GENERATED ALWAYS AS ('') VIRTUAL, +b TIMESTAMP(4) GENERATED ALWAYS AS ('') VIRTUAL, +KEY (a(183),b) +); +INSERT IGNORE INTO t VALUES(), (), (); +Warnings: +Warning 1265 Data truncated for column 'b' at row 1 +Warning 1265 Data truncated for column 'b' at row 2 +Warning 1265 Data truncated for column 'b' at row 3 +DELETE IGNORE FROM t; +DROP TABLE t; +# +# Bug#22195458:GCOLS: ASSERTION 0 AND CORRUPTION... +# +CREATE TABLE t ( +a INT, +b YEAR GENERATED ALWAYS AS ('a') VIRTUAL, +c YEAR GENERATED ALWAYS AS ('aaaa') VIRTUAL, +b1 YEAR GENERATED ALWAYS AS ('a') STORED, +c1 YEAR GENERATED ALWAYS AS ('aaaa') STORED, +UNIQUE(b), +UNIQUE(b1) +); +INSERT IGNORE INTO t VALUES(); +SELECT b from t; +b +0000 +SELECT b1 from t; +b1 +0000 +SELECT * from t; +a b c b1 c1 +NULL 0000 0000 0000 0000 +DELETE FROM t; +CHECK TABLE t EXTENDED; +Table Op Msg_type Msg_text +test.t check status OK +DROP TABLE t; +# Bug#22195364:GCOLS: FAILING ASSERTION: +# DFIELD_IS_NULL(DFIELD2) || DFIELD2->DATA +CREATE TABLE t ( +a INT, +c BLOB GENERATED ALWAYS AS ('') VIRTUAL, +UNIQUE KEY(c(1),a) +); +INSERT INTO t(a) VALUES(1) ON DUPLICATE KEY UPDATE a=2; +SELECT * FROM t; +a c +1 +INSERT INTO t(a) VALUES(1) ON DUPLICATE KEY UPDATE a=2; +SELECT * FROM t; +a c +2 +SELECT GROUP_CONCAT(c ORDER BY c) FROM t; +GROUP_CONCAT(c ORDER BY c) + +DROP TABLE t; #Bug#21929967:GCOLS:GCOL VALUE CHANGES WHEN SESSION CHANGES SQL_MODE CREATE TABLE t(c1 INT GENERATED ALWAYS AS (1) VIRTUAL, c2 INT GENERATED ALWAYS AS(2) STORED); @@ -593,6 +721,49 @@ i1 i2 5 10 5 10 DROP TABLE t1,t2; +# +# Bug#22070021 GCOL:ASSERTION `!TABLE || (!TABLE->WRITE_SET || +# BITMAP_IS_SET(TABLE->WRITE_SET, +# +CREATE TABLE t1( +c1 INT, +c2 INT GENERATED ALWAYS AS (c1 + c1) VIRTUAL, +KEY(c2) +); +INSERT INTO t1(c1) VALUES(0); +DELETE O1.* FROM t1 AS O1, t1 AS O2; +SELECT * FROM t1; +c1 c2 +DROP TABLE t1; +# +# Bug#21944199 SIMPLE DELETE QUERY CAUSES INNODB: FAILING ASSERTION: 0 +# & DATA CORRUPTION +# +CREATE TEMPORARY TABLE t1 ( +a INTEGER NOT NULL, +b INTEGER GENERATED ALWAYS AS (a+1) VIRTUAL +); +INSERT INTO t1 (a) VALUES (0), (0), (0); +ALTER TABLE t1 ADD INDEX idx (b); +DELETE FROM t1; +DROP TEMPORARY TABLE t1; +# +# Original test case from MDEV-17890 +# +CREATE TABLE t1 ( +pk BIGINT AUTO_INCREMENT, +b BIT(15), +v BIT(10) AS (b) VIRTUAL, +PRIMARY KEY(pk), +UNIQUE(v) +); +INSERT IGNORE INTO t1 (b) VALUES (b'101110001110100'),(b'011101'); +Warnings: +Warning 1264 Out of range value for column 'v' at row 1 +SELECT pk, b FROM t1 INTO OUTFILE 'load.data'; +LOAD DATA INFILE 'load.data' REPLACE INTO TABLE t1 (pk, b); +ERROR 22001: Data too long for column 'v' at row 1 +DROP TABLE t1; DROP VIEW IF EXISTS v1,v2; DROP TABLE IF EXISTS t1,t2,t3; DROP PROCEDURE IF EXISTS p1; diff --git a/mysql-test/suite/gcol/r/gcol_ins_upd_myisam.result b/mysql-test/suite/gcol/r/gcol_ins_upd_myisam.result index c7e5cab4f8c..ce57fc08ac2 100644 --- a/mysql-test/suite/gcol/r/gcol_ins_upd_myisam.result +++ b/mysql-test/suite/gcol/r/gcol_ins_upd_myisam.result @@ -571,13 +571,13 @@ UNIQUE(b1) INSERT IGNORE INTO t VALUES(); SELECT b from t; b -2000 +0000 SELECT b1 from t; b1 0000 SELECT * from t; a b c b1 c1 -NULL 2000 0000 0000 0000 +NULL 0000 0000 0000 0000 DELETE FROM t; CHECK TABLE t EXTENDED; Table Op Msg_type Msg_text @@ -669,6 +669,23 @@ INSERT INTO t1 (a) VALUES (0), (0), (0); ALTER TABLE t1 ADD INDEX idx (b); DELETE FROM t1; DROP TEMPORARY TABLE t1; +# +# Original test case from MDEV-17890 +# +CREATE TABLE t1 ( +pk BIGINT AUTO_INCREMENT, +b BIT(15), +v BIT(10) AS (b) VIRTUAL, +PRIMARY KEY(pk), +UNIQUE(v) +); +INSERT IGNORE INTO t1 (b) VALUES (b'101110001110100'),(b'011101'); +Warnings: +Warning 1264 Out of range value for column 'v' at row 1 +SELECT pk, b FROM t1 INTO OUTFILE 'load.data'; +LOAD DATA INFILE 'load.data' REPLACE INTO TABLE t1 (pk, b); +ERROR 22001: Data too long for column 'v' at row 1 +DROP TABLE t1; DROP VIEW IF EXISTS v1,v2; DROP TABLE IF EXISTS t1,t2,t3; DROP PROCEDURE IF EXISTS p1; diff --git a/mysql-test/suite/gcol/r/gcol_keys_innodb.result b/mysql-test/suite/gcol/r/gcol_keys_innodb.result index 37b350c0c32..2d8b81a0ea1 100644 --- a/mysql-test/suite/gcol/r/gcol_keys_innodb.result +++ b/mysql-test/suite/gcol/r/gcol_keys_innodb.result @@ -879,7 +879,7 @@ ERROR 22003: Out of range value for column 'vi' at row 1 DROP TABLE t1; # MDEV-19011 Assertion `file->s->base.reclength < file->s->vreclength' # failed in ha_myisam::setup_vcols_for_repair -CREATE TABLE t1 (a INT GENERATED ALWAYS AS (1) VIRTUAL) ENGINE=MyISAM; +CREATE TABLE t1 (a INT GENERATED ALWAYS AS (1) VIRTUAL); ALTER TABLE t1 ADD KEY (a); DROP TABLE t1; # diff --git a/mysql-test/suite/gcol/r/gcol_keys_myisam.result b/mysql-test/suite/gcol/r/gcol_keys_myisam.result index 643c4a304a3..17b15826813 100644 --- a/mysql-test/suite/gcol/r/gcol_keys_myisam.result +++ b/mysql-test/suite/gcol/r/gcol_keys_myisam.result @@ -879,7 +879,7 @@ ERROR 22003: Out of range value for column 'vi' at row 1 DROP TABLE t1; # MDEV-19011 Assertion `file->s->base.reclength < file->s->vreclength' # failed in ha_myisam::setup_vcols_for_repair -CREATE TABLE t1 (a INT GENERATED ALWAYS AS (1) VIRTUAL) ENGINE=MyISAM; +CREATE TABLE t1 (a INT GENERATED ALWAYS AS (1) VIRTUAL); ALTER TABLE t1 ADD KEY (a); DROP TABLE t1; DROP VIEW IF EXISTS v1,v2; diff --git a/mysql-test/suite/gcol/t/gcol_ins_upd_innodb.test b/mysql-test/suite/gcol/t/gcol_ins_upd_innodb.test index 23d97a797e0..15a0db29615 100644 --- a/mysql-test/suite/gcol/t/gcol_ins_upd_innodb.test +++ b/mysql-test/suite/gcol/t/gcol_ins_upd_innodb.test @@ -36,7 +36,7 @@ eval SET @@session.default_storage_engine = 'InnoDB'; #------------------------------------------------------------------------------# # Execute the tests to be applied to all storage engines -let $support_virtual_index= 0; +let $support_virtual_index= 1; --source suite/gcol/inc/gcol_ins_upd.inc #------------------------------------------------------------------------------# diff --git a/sql/field.cc b/sql/field.cc index 652228beceb..074de35e0cf 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -6373,6 +6373,7 @@ bool Field_timef::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) int Field_year::store(const char *from, uint len,CHARSET_INFO *cs) { ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED; + THD *thd= get_thd(); char *end; int error; longlong nr= cs->cset->strntoull10rnd(cs, from, len, 0, &end, &error); @@ -6384,7 +6385,14 @@ int Field_year::store(const char *from, uint len,CHARSET_INFO *cs) set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1); return 1; } - if (get_thd()->count_cuted_fields && + + if (!thd->count_cuted_fields && error == MY_ERRNO_EDOM) + { + *ptr= 0; + return 1; + } + + if (thd->count_cuted_fields && (error= check_int(cs, from, len, end, error))) { if (error == 1) /* empty or incorrect string */ From 7d9ba57da4843c05a4d11e63159a961c4eb79a04 Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Mon, 21 Jun 2021 17:48:45 +0300 Subject: [PATCH 15/35] [1/2] MDEV-18166 ASSERT_COLUMN_MARKED_FOR_READ failed on tables with vcols This is a 10.2+ part of a jira task The two bugs regarding virtual column marking have been fixed: 1. UPDATE of a partitioned table, where the optimizer has chosen a secondary index to make a filesort; 2. INSERT into a table with a nonblob field generated from a blob, with binlog enabled and binlog_row_image=noblob. 3. DELETE from a view on a table with virtual column. Generally the assertion happens from update_virtual_fields() call These bugs are root-caused by missing field marking for dependant fields of a virtual column. Therefore a fix is: mark all the fields involved in the vcol expression by calling field->register_field_in_read_map() instead just setting a single bit. 3 was reproducible only on 10.4+, however the problem might has just been invisible in the earlier versions. The fix is applicable to 10.2-10.3 as well. --- mysql-test/suite/gcol/inc/gcol_partition.inc | 16 ++++++++++ mysql-test/suite/gcol/inc/gcol_view.inc | 29 +++++++++++++++++++ .../suite/gcol/r/gcol_partition_innodb.result | 15 ++++++++++ .../suite/gcol/r/gcol_partition_myisam.result | 15 ++++++++++ .../suite/gcol/r/gcol_view_innodb.result | 20 +++++++++++++ .../suite/gcol/r/gcol_view_myisam.result | 20 +++++++++++++ mysql-test/suite/vcol/r/binlog.result | 14 +++++++++ mysql-test/suite/vcol/t/binlog.test | 14 +++++++++ sql/ha_partition.cc | 3 +- sql/sql_base.cc | 2 +- sql/table.cc | 2 +- 11 files changed, 146 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/gcol/inc/gcol_partition.inc b/mysql-test/suite/gcol/inc/gcol_partition.inc index df199e86c68..4e4af4f0023 100644 --- a/mysql-test/suite/gcol/inc/gcol_partition.inc +++ b/mysql-test/suite/gcol/inc/gcol_partition.inc @@ -153,3 +153,19 @@ CHECK TABLE t EXTENDED; FLUSH TABLES; CHECK TABLE t EXTENDED; DROP TABLE t; + +--echo # +--echo # MDEV-18166 ASSERT_COLUMN_MARKED_FOR_READ failed on tables with vcols +--echo # +CREATE TABLE t1 ( + a INT, + b INT, + c BIT(4) NOT NULL DEFAULT b'0', + pk INTEGER AUTO_INCREMENT, + d BIT(4) AS (c) VIRTUAL, + PRIMARY KEY(pk), + KEY (b,d) +) PARTITION BY HASH(pk); +INSERT INTO t1 () VALUES (),(); +UPDATE t1 SET a = 0 WHERE b IS NULL ORDER BY pk; +DROP TABLE t1; diff --git a/mysql-test/suite/gcol/inc/gcol_view.inc b/mysql-test/suite/gcol/inc/gcol_view.inc index 51cb9b5d725..5e5afcb5ab1 100644 --- a/mysql-test/suite/gcol/inc/gcol_view.inc +++ b/mysql-test/suite/gcol/inc/gcol_view.inc @@ -221,3 +221,32 @@ select * from t1; drop view v1; drop table t1; + +--echo # +--echo # MDEV-18166 ASSERT_COLUMN_MARKED_FOR_READ failed on tables with vcols +--echo # + +CREATE TABLE t1 (d DATETIME(3), v DATETIME(2) AS (d)); +CREATE VIEW v1 AS SELECT * FROM t1; + +INSERT INTO t1 (d) VALUES ('2004-04-19 15:37:39.123'), + ('1985-12-24 10:15:08.456'); +DELETE FROM v1 ORDER BY v LIMIT 4; + +# Cleanup +DROP VIEW v1; +DROP TABLE t1; + +--echo # +--echo # [duplicate] MDEV-19306 Assertion `marked_for_read()' failed in +--echo # Field_blob::val_str with virtual columns and views +--echo # + +CREATE TABLE t1 (a BLOB, b TEXT AS (a) VIRTUAL); +CREATE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 (a) VALUES ('foo'),('bar'); +DELETE FROM v1 ORDER BY b LIMIT 2; + +# Cleanup +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/suite/gcol/r/gcol_partition_innodb.result b/mysql-test/suite/gcol/r/gcol_partition_innodb.result index e5a68cdb177..d3f211c9b9a 100644 --- a/mysql-test/suite/gcol/r/gcol_partition_innodb.result +++ b/mysql-test/suite/gcol/r/gcol_partition_innodb.result @@ -89,6 +89,21 @@ Table Op Msg_type Msg_text test.t check status OK DROP TABLE t; # +# MDEV-18166 ASSERT_COLUMN_MARKED_FOR_READ failed on tables with vcols +# +CREATE TABLE t1 ( +a INT, +b INT, +c BIT(4) NOT NULL DEFAULT b'0', +pk INTEGER AUTO_INCREMENT, +d BIT(4) AS (c) VIRTUAL, +PRIMARY KEY(pk), +KEY (b,d) +) PARTITION BY HASH(pk); +INSERT INTO t1 () VALUES (),(); +UPDATE t1 SET a = 0 WHERE b IS NULL ORDER BY pk; +DROP TABLE t1; +# # MDEV-16980 Wrongly set tablename len while opening the # table for purge thread # diff --git a/mysql-test/suite/gcol/r/gcol_partition_myisam.result b/mysql-test/suite/gcol/r/gcol_partition_myisam.result index 81324da6fcd..75e216f903b 100644 --- a/mysql-test/suite/gcol/r/gcol_partition_myisam.result +++ b/mysql-test/suite/gcol/r/gcol_partition_myisam.result @@ -86,6 +86,21 @@ CHECK TABLE t EXTENDED; Table Op Msg_type Msg_text test.t check status OK DROP TABLE t; +# +# MDEV-18166 ASSERT_COLUMN_MARKED_FOR_READ failed on tables with vcols +# +CREATE TABLE t1 ( +a INT, +b INT, +c BIT(4) NOT NULL DEFAULT b'0', +pk INTEGER AUTO_INCREMENT, +d BIT(4) AS (c) VIRTUAL, +PRIMARY KEY(pk), +KEY (b,d) +) PARTITION BY HASH(pk); +INSERT INTO t1 () VALUES (),(); +UPDATE t1 SET a = 0 WHERE b IS NULL ORDER BY pk; +DROP TABLE t1; DROP VIEW IF EXISTS v1,v2; DROP TABLE IF EXISTS t1,t2,t3; DROP PROCEDURE IF EXISTS p1; diff --git a/mysql-test/suite/gcol/r/gcol_view_innodb.result b/mysql-test/suite/gcol/r/gcol_view_innodb.result index ec82c792493..2690c60f634 100644 --- a/mysql-test/suite/gcol/r/gcol_view_innodb.result +++ b/mysql-test/suite/gcol/r/gcol_view_innodb.result @@ -271,6 +271,26 @@ a b c 1 -1 -1 drop view v1; drop table t1; +# +# MDEV-18166 ASSERT_COLUMN_MARKED_FOR_READ failed on tables with vcols +# +CREATE TABLE t1 (d DATETIME(3), v DATETIME(2) AS (d)); +CREATE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 (d) VALUES ('2004-04-19 15:37:39.123'), +('1985-12-24 10:15:08.456'); +DELETE FROM v1 ORDER BY v LIMIT 4; +DROP VIEW v1; +DROP TABLE t1; +# +# [duplicate] MDEV-19306 Assertion `marked_for_read()' failed in +# Field_blob::val_str with virtual columns and views +# +CREATE TABLE t1 (a BLOB, b TEXT AS (a) VIRTUAL); +CREATE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 (a) VALUES ('foo'),('bar'); +DELETE FROM v1 ORDER BY b LIMIT 2; +DROP VIEW v1; +DROP TABLE t1; DROP VIEW IF EXISTS v1,v2; DROP TABLE IF EXISTS t1,t2,t3; DROP PROCEDURE IF EXISTS p1; diff --git a/mysql-test/suite/gcol/r/gcol_view_myisam.result b/mysql-test/suite/gcol/r/gcol_view_myisam.result index 13cb74ebcb5..b2856e36d13 100644 --- a/mysql-test/suite/gcol/r/gcol_view_myisam.result +++ b/mysql-test/suite/gcol/r/gcol_view_myisam.result @@ -271,6 +271,26 @@ a b c 1 -1 -1 drop view v1; drop table t1; +# +# MDEV-18166 ASSERT_COLUMN_MARKED_FOR_READ failed on tables with vcols +# +CREATE TABLE t1 (d DATETIME(3), v DATETIME(2) AS (d)); +CREATE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 (d) VALUES ('2004-04-19 15:37:39.123'), +('1985-12-24 10:15:08.456'); +DELETE FROM v1 ORDER BY v LIMIT 4; +DROP VIEW v1; +DROP TABLE t1; +# +# [duplicate] MDEV-19306 Assertion `marked_for_read()' failed in +# Field_blob::val_str with virtual columns and views +# +CREATE TABLE t1 (a BLOB, b TEXT AS (a) VIRTUAL); +CREATE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 (a) VALUES ('foo'),('bar'); +DELETE FROM v1 ORDER BY b LIMIT 2; +DROP VIEW v1; +DROP TABLE t1; DROP VIEW IF EXISTS v1,v2; DROP TABLE IF EXISTS t1,t2,t3; DROP PROCEDURE IF EXISTS p1; diff --git a/mysql-test/suite/vcol/r/binlog.result b/mysql-test/suite/vcol/r/binlog.result index d4893b7ed3c..463928b97b8 100644 --- a/mysql-test/suite/vcol/r/binlog.result +++ b/mysql-test/suite/vcol/r/binlog.result @@ -80,4 +80,18 @@ Warnings: Warning 1265 Data truncated for column 'b' at row 1 Warning 1265 Data truncated for column 'b' at row 2 DROP TABLE t1; +# +# MDEV-18166 ASSERT_COLUMN_MARKED_FOR_READ failed on tables with vcols +# +SET SESSION binlog_row_image= noblob; +CREATE TEMPORARY TABLE t1 SELECT UUID(); +show create table t1; +Table Create Table +t1 CREATE TEMPORARY TABLE `t1` ( + `UUID()` varchar(36) CHARACTER SET utf8 DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +CREATE TABLE t2 (a INT PRIMARY KEY, b TEXT, c INT GENERATED ALWAYS AS(b)); +INSERT INTO t2 (a,b) VALUES (1,1); +SET SESSION binlog_row_image= default; +DROP TABLE t2; include/rpl_end.inc diff --git a/mysql-test/suite/vcol/t/binlog.test b/mysql-test/suite/vcol/t/binlog.test index aa939086f12..edf0a8957b9 100644 --- a/mysql-test/suite/vcol/t/binlog.test +++ b/mysql-test/suite/vcol/t/binlog.test @@ -66,4 +66,18 @@ UPDATE IGNORE t1 SET a = NULL; DROP TABLE t1; +--echo # +--echo # MDEV-18166 ASSERT_COLUMN_MARKED_FOR_READ failed on tables with vcols +--echo # + +SET SESSION binlog_row_image= noblob; +CREATE TEMPORARY TABLE t1 SELECT UUID(); +show create table t1; +CREATE TABLE t2 (a INT PRIMARY KEY, b TEXT, c INT GENERATED ALWAYS AS(b)); +INSERT INTO t2 (a,b) VALUES (1,1); + +SET SESSION binlog_row_image= default; +DROP TABLE t2; + + --source include/rpl_end.inc diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index ad020acf5c4..6f50d078dff 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -5255,8 +5255,7 @@ int ha_partition::index_init(uint inx, bool sorted) do { for (i= 0; i < (*key_info)->user_defined_key_parts; i++) - bitmap_set_bit(table->read_set, - (*key_info)->key_part[i].field->field_index); + (*key_info)->key_part[i].field->register_field_in_read_map(); } while (*(++key_info)); } for (i= bitmap_get_first_set(&m_part_info->read_partitions); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 11f4cb9890b..3471297ac7d 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -5839,7 +5839,7 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, { TABLE *table= field_to_set->table; if (thd->mark_used_columns == MARK_COLUMNS_READ) - bitmap_set_bit(table->read_set, field_to_set->field_index); + field_to_set->register_field_in_read_map(); else bitmap_set_bit(table->write_set, field_to_set->field_index); } diff --git a/sql/table.cc b/sql/table.cc index 1004f583448..2666523f092 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -6717,7 +6717,7 @@ void TABLE::mark_columns_per_binlog_row_image() if ((my_field->flags & PRI_KEY_FLAG) || (my_field->type() != MYSQL_TYPE_BLOB)) { - bitmap_set_bit(read_set, my_field->field_index); + my_field->register_field_in_read_map(); bitmap_set_bit(rpl_write_set, my_field->field_index); } } From 0f6a5b4390efeac19ff3ad6fd3a8dd32241b343c Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Tue, 22 Jun 2021 18:30:53 +0300 Subject: [PATCH 16/35] [2/2] MDEV-18166 ASSERT_COLUMN_MARKED_FOR_READ failed on tables with vcols Several different test cases were failing under the same reason: the fields in a vcol expression were not marked during marking columns of a key contatining virtual column for read. Fix: make marking columns of a key for read a special case where register_field_in_read_map() is done instead of plain bitmap_set_bit(). Some test cases are only reproducible in 10.4+, but the fix is applicable to 10.2+ --- mysql-test/suite/gcol/inc/gcol_ins_upd.inc | 30 ++++++++++++++ mysql-test/suite/gcol/inc/gcol_view.inc | 17 ++++++++ .../suite/gcol/r/gcol_ins_upd_innodb.result | 27 +++++++++++++ .../suite/gcol/r/gcol_ins_upd_myisam.result | 27 +++++++++++++ .../suite/gcol/r/gcol_view_innodb.result | 12 ++++++ .../suite/gcol/r/gcol_view_myisam.result | 12 ++++++ sql/table.cc | 39 ++++++++++++------- sql/table.h | 1 + 8 files changed, 152 insertions(+), 13 deletions(-) diff --git a/mysql-test/suite/gcol/inc/gcol_ins_upd.inc b/mysql-test/suite/gcol/inc/gcol_ins_upd.inc index 6bd7974f2af..4cfcf371fd7 100644 --- a/mysql-test/suite/gcol/inc/gcol_ins_upd.inc +++ b/mysql-test/suite/gcol/inc/gcol_ins_upd.inc @@ -629,4 +629,34 @@ DROP TABLE t1; --let $datadir= `SELECT @@datadir` --remove_file $datadir/test/load.data + +--echo # +--echo # MDEV-18166 ASSERT_COLUMN_MARKED_FOR_READ failed on tables with vcols +--echo # + +CREATE TABLE t1 ( + id INT NOT NULL AUTO_INCREMENT, + f ENUM('a','b','c'), + v ENUM('a','b','c') AS (f), + KEY(v,id) +) ENGINE=MyISAM; +INSERT INTO t1 (f) VALUES ('a'),('b'); +INSERT IGNORE INTO t1 SELECT * FROM t1; + +# Cleanup +DROP TABLE t1; + + +CREATE TABLE t1 ( + id INT NOT NULL AUTO_INCREMENT, + f ENUM('a','b','c'), + v ENUM('a','b','c') AS (f), + KEY(v,id) +) ENGINE=MyISAM; +INSERT INTO t1 (f) VALUES ('a'),('b'); +INSERT IGNORE INTO t1 SELECT * FROM t1; + +# Cleanup +DROP TABLE t1; + } diff --git a/mysql-test/suite/gcol/inc/gcol_view.inc b/mysql-test/suite/gcol/inc/gcol_view.inc index 5e5afcb5ab1..4aabd2429cd 100644 --- a/mysql-test/suite/gcol/inc/gcol_view.inc +++ b/mysql-test/suite/gcol/inc/gcol_view.inc @@ -250,3 +250,20 @@ DELETE FROM v1 ORDER BY b LIMIT 2; # Cleanup DROP VIEW v1; DROP TABLE t1; +CREATE TABLE t1 (d INT, v TINYINT AS (d)); +CREATE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 (d) VALUES ('2004'),('1985') ; +DELETE FROM v1 ORDER BY v LIMIT 4; + +DROP VIEW v1; +DROP TABLE t1; + + +CREATE TABLE t1 (d VARCHAR(64), v VARCHAR(63) AS (d)); +CREATE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 (d) VALUES ('2004-04-19 15:37:39.123'),('1985-12-24 10:15:08.456') ; +DELETE FROM v1 ORDER BY v LIMIT 4; + +DROP TABLE t1; +DROP VIEW v1; + diff --git a/mysql-test/suite/gcol/r/gcol_ins_upd_innodb.result b/mysql-test/suite/gcol/r/gcol_ins_upd_innodb.result index 99e47c2d168..1d85fc837dc 100644 --- a/mysql-test/suite/gcol/r/gcol_ins_upd_innodb.result +++ b/mysql-test/suite/gcol/r/gcol_ins_upd_innodb.result @@ -764,6 +764,33 @@ SELECT pk, b FROM t1 INTO OUTFILE 'load.data'; LOAD DATA INFILE 'load.data' REPLACE INTO TABLE t1 (pk, b); ERROR 22001: Data too long for column 'v' at row 1 DROP TABLE t1; +# +# MDEV-18166 ASSERT_COLUMN_MARKED_FOR_READ failed on tables with vcols +# +CREATE TABLE t1 ( +id INT NOT NULL AUTO_INCREMENT, +f ENUM('a','b','c'), +v ENUM('a','b','c') AS (f), +KEY(v,id) +) ENGINE=MyISAM; +INSERT INTO t1 (f) VALUES ('a'),('b'); +INSERT IGNORE INTO t1 SELECT * FROM t1; +Warnings: +Warning 1906 The value specified for generated column 'v' in table 't1' has been ignored +Warning 1906 The value specified for generated column 'v' in table 't1' has been ignored +DROP TABLE t1; +CREATE TABLE t1 ( +id INT NOT NULL AUTO_INCREMENT, +f ENUM('a','b','c'), +v ENUM('a','b','c') AS (f), +KEY(v,id) +) ENGINE=MyISAM; +INSERT INTO t1 (f) VALUES ('a'),('b'); +INSERT IGNORE INTO t1 SELECT * FROM t1; +Warnings: +Warning 1906 The value specified for generated column 'v' in table 't1' has been ignored +Warning 1906 The value specified for generated column 'v' in table 't1' has been ignored +DROP TABLE t1; DROP VIEW IF EXISTS v1,v2; DROP TABLE IF EXISTS t1,t2,t3; DROP PROCEDURE IF EXISTS p1; diff --git a/mysql-test/suite/gcol/r/gcol_ins_upd_myisam.result b/mysql-test/suite/gcol/r/gcol_ins_upd_myisam.result index ce57fc08ac2..e10b83cabf5 100644 --- a/mysql-test/suite/gcol/r/gcol_ins_upd_myisam.result +++ b/mysql-test/suite/gcol/r/gcol_ins_upd_myisam.result @@ -686,6 +686,33 @@ SELECT pk, b FROM t1 INTO OUTFILE 'load.data'; LOAD DATA INFILE 'load.data' REPLACE INTO TABLE t1 (pk, b); ERROR 22001: Data too long for column 'v' at row 1 DROP TABLE t1; +# +# MDEV-18166 ASSERT_COLUMN_MARKED_FOR_READ failed on tables with vcols +# +CREATE TABLE t1 ( +id INT NOT NULL AUTO_INCREMENT, +f ENUM('a','b','c'), +v ENUM('a','b','c') AS (f), +KEY(v,id) +) ENGINE=MyISAM; +INSERT INTO t1 (f) VALUES ('a'),('b'); +INSERT IGNORE INTO t1 SELECT * FROM t1; +Warnings: +Warning 1906 The value specified for generated column 'v' in table 't1' has been ignored +Warning 1906 The value specified for generated column 'v' in table 't1' has been ignored +DROP TABLE t1; +CREATE TABLE t1 ( +id INT NOT NULL AUTO_INCREMENT, +f ENUM('a','b','c'), +v ENUM('a','b','c') AS (f), +KEY(v,id) +) ENGINE=MyISAM; +INSERT INTO t1 (f) VALUES ('a'),('b'); +INSERT IGNORE INTO t1 SELECT * FROM t1; +Warnings: +Warning 1906 The value specified for generated column 'v' in table 't1' has been ignored +Warning 1906 The value specified for generated column 'v' in table 't1' has been ignored +DROP TABLE t1; DROP VIEW IF EXISTS v1,v2; DROP TABLE IF EXISTS t1,t2,t3; DROP PROCEDURE IF EXISTS p1; diff --git a/mysql-test/suite/gcol/r/gcol_view_innodb.result b/mysql-test/suite/gcol/r/gcol_view_innodb.result index 2690c60f634..59e299f9d8c 100644 --- a/mysql-test/suite/gcol/r/gcol_view_innodb.result +++ b/mysql-test/suite/gcol/r/gcol_view_innodb.result @@ -291,6 +291,18 @@ INSERT INTO t1 (a) VALUES ('foo'),('bar'); DELETE FROM v1 ORDER BY b LIMIT 2; DROP VIEW v1; DROP TABLE t1; +CREATE TABLE t1 (d INT, v TINYINT AS (d)); +CREATE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 (d) VALUES ('2004'),('1985') ; +DELETE FROM v1 ORDER BY v LIMIT 4; +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 (d VARCHAR(64), v VARCHAR(63) AS (d)); +CREATE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 (d) VALUES ('2004-04-19 15:37:39.123'),('1985-12-24 10:15:08.456') ; +DELETE FROM v1 ORDER BY v LIMIT 4; +DROP TABLE t1; +DROP VIEW v1; DROP VIEW IF EXISTS v1,v2; DROP TABLE IF EXISTS t1,t2,t3; DROP PROCEDURE IF EXISTS p1; diff --git a/mysql-test/suite/gcol/r/gcol_view_myisam.result b/mysql-test/suite/gcol/r/gcol_view_myisam.result index b2856e36d13..17cc2135439 100644 --- a/mysql-test/suite/gcol/r/gcol_view_myisam.result +++ b/mysql-test/suite/gcol/r/gcol_view_myisam.result @@ -291,6 +291,18 @@ INSERT INTO t1 (a) VALUES ('foo'),('bar'); DELETE FROM v1 ORDER BY b LIMIT 2; DROP VIEW v1; DROP TABLE t1; +CREATE TABLE t1 (d INT, v TINYINT AS (d)); +CREATE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 (d) VALUES ('2004'),('1985') ; +DELETE FROM v1 ORDER BY v LIMIT 4; +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 (d VARCHAR(64), v VARCHAR(63) AS (d)); +CREATE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 (d) VALUES ('2004-04-19 15:37:39.123'),('1985-12-24 10:15:08.456') ; +DELETE FROM v1 ORDER BY v LIMIT 4; +DROP TABLE t1; +DROP VIEW v1; DROP VIEW IF EXISTS v1,v2; DROP TABLE IF EXISTS t1,t2,t3; DROP PROCEDURE IF EXISTS p1; diff --git a/sql/table.cc b/sql/table.cc index 2666523f092..4afd2488ea1 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -6329,7 +6329,7 @@ void TABLE::prepare_for_position() if ((file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) && s->primary_key < MAX_KEY) { - mark_columns_used_by_index_no_reset(s->primary_key, read_set); + mark_columns_used_by_index_for_read_no_reset(s->primary_key); /* signal change */ file->column_bitmaps_signal(); } @@ -6385,23 +6385,36 @@ void TABLE::restore_column_maps_after_keyread(MY_BITMAP *backup) DBUG_VOID_RETURN; } +static void mark_index_columns(TABLE *table, uint index, + MY_BITMAP *bitmap, bool read) +{ + KEY_PART_INFO *key_part= table->key_info[index].key_part; + uint key_parts= table->key_info[index].user_defined_key_parts; + for (uint k= 0; k < key_parts; k++) + if (read) + key_part[k].field->register_field_in_read_map(); + else + bitmap_set_bit(bitmap, key_part[k].fieldnr-1); + if (table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX && + table->s->primary_key != MAX_KEY && table->s->primary_key != index) + mark_index_columns(table, table->s->primary_key, bitmap, read); +} /* mark columns used by key, but don't reset other fields */ -void TABLE::mark_columns_used_by_index_no_reset(uint index, MY_BITMAP *bitmap) +inline void TABLE::mark_columns_used_by_index_no_reset(uint index, MY_BITMAP *bitmap) { - KEY_PART_INFO *key_part= key_info[index].key_part; - KEY_PART_INFO *key_part_end= (key_part + key_info[index].user_defined_key_parts); - for (;key_part != key_part_end; key_part++) - bitmap_set_bit(bitmap, key_part->fieldnr-1); - if (file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX && - s->primary_key != MAX_KEY && s->primary_key != index) - mark_columns_used_by_index_no_reset(s->primary_key, bitmap); + mark_index_columns(this, index, bitmap, false); } +inline void TABLE::mark_columns_used_by_index_for_read_no_reset(uint index) +{ + mark_index_columns(this, index, read_set, true); +} + /* Mark auto-increment fields as used fields in both read and write maps @@ -6420,7 +6433,7 @@ void TABLE::mark_auto_increment_column() bitmap_set_bit(read_set, found_next_number_field->field_index); bitmap_set_bit(write_set, found_next_number_field->field_index); if (s->next_number_keypart) - mark_columns_used_by_index_no_reset(s->next_number_index, read_set); + mark_columns_used_by_index_for_read_no_reset(s->next_number_index); file->column_bitmaps_signal(); } @@ -6476,7 +6489,7 @@ void TABLE::mark_columns_needed_for_delete() file->use_hidden_primary_key(); else { - mark_columns_used_by_index_no_reset(s->primary_key, read_set); + mark_columns_used_by_index_for_read_no_reset(s->primary_key); need_signal= true; } } @@ -6566,7 +6579,7 @@ void TABLE::mark_columns_needed_for_update() file->use_hidden_primary_key(); else { - mark_columns_used_by_index_no_reset(s->primary_key, read_set); + mark_columns_used_by_index_for_read_no_reset(s->primary_key); need_signal= true; } } @@ -6729,7 +6742,7 @@ void TABLE::mark_columns_per_binlog_row_image() We don't need to mark the primary key in the rpl_write_set as the binary log will include all columns read anyway. */ - mark_columns_used_by_index_no_reset(s->primary_key, read_set); + mark_columns_used_by_index_for_read_no_reset(s->primary_key); /* Only write columns that have changed */ rpl_write_set= write_set; break; diff --git a/sql/table.h b/sql/table.h index 69bd14b2834..7a5f4c6fe86 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1423,6 +1423,7 @@ public: { return prepare_for_keyread(index, &tmp_set); } void mark_columns_used_by_index(uint index, MY_BITMAP *map); void mark_columns_used_by_index_no_reset(uint index, MY_BITMAP *map); + void mark_columns_used_by_index_for_read_no_reset(uint index); void restore_column_maps_after_keyread(MY_BITMAP *backup); void mark_auto_increment_column(void); void mark_columns_needed_for_update(void); From f64a4f672ab9c5338a700a05650df394a732aac9 Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Mon, 28 Jun 2021 21:31:14 +0300 Subject: [PATCH 17/35] follow-up MDEV-18166: rename marking functions Reformulate mark_columns_used_by_index* function family in a more laconic way: mark_columns_used_by_index -> mark_index_columns mark_columns_used_by_index_for_read_no_reset -> mark_index_columns_for_read mark_columns_used_by_index_no_reset -> mark_index_columns_no_reset static mark_index_columns -> do_mark_index_columns --- sql/key.cc | 2 +- sql/sql_class.cc | 4 ++-- sql/sql_select.cc | 2 +- sql/sql_update.cc | 2 +- sql/table.cc | 32 ++++++++++++++++---------------- sql/table.h | 6 +++--- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/sql/key.cc b/sql/key.cc index 689b1e9c886..d0da75ae61b 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -465,7 +465,7 @@ void key_unpack(String *to, TABLE *table, KEY *key) bool is_key_used(TABLE *table, uint idx, const MY_BITMAP *fields) { - table->mark_columns_used_by_index(idx, &table->tmp_set); + table->mark_index_columns(idx, &table->tmp_set); return bitmap_is_overlapping(&table->tmp_set, fields); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 80ff0aa077c..5ada018e540 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -6681,8 +6681,8 @@ void THD::binlog_prepare_row_images(TABLE *table) { case BINLOG_ROW_IMAGE_MINIMAL: /* MINIMAL: Mark only PK */ - table->mark_columns_used_by_index(table->s->primary_key, - &table->tmp_set); + table->mark_index_columns(table->s->primary_key, + &table->tmp_set); break; case BINLOG_ROW_IMAGE_NOBLOB: /** diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 362adc9853f..e89d06115fc 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1179,7 +1179,7 @@ int JOIN::init_join_caches() if (table->file->keyread_enabled()) { if (!(table->file->index_flags(table->file->keyread, 0, 1) & HA_CLUSTERED_INDEX)) - table->mark_columns_used_by_index(table->file->keyread, table->read_set); + table->mark_index_columns(table->file->keyread, table->read_set); } else if ((tab->read_first_record == join_read_first || tab->read_first_record == join_read_last) && diff --git a/sql/sql_update.cc b/sql/sql_update.cc index b7ef7c2a0db..8af6c8f80a2 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -195,7 +195,7 @@ static void prepare_record_for_error_message(int error, TABLE *table) /* Create unique_map with all fields used by that index. */ my_bitmap_init(&unique_map, unique_map_buf, table->s->fields, FALSE); - table->mark_columns_used_by_index(keynr, &unique_map); + table->mark_index_columns(keynr, &unique_map); /* Subtract read_set and write_set. */ bitmap_subtract(&unique_map, table->read_set); diff --git a/sql/table.cc b/sql/table.cc index 4afd2488ea1..b7cf1274400 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -6329,7 +6329,7 @@ void TABLE::prepare_for_position() if ((file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) && s->primary_key < MAX_KEY) { - mark_columns_used_by_index_for_read_no_reset(s->primary_key); + mark_index_columns_for_read(s->primary_key); /* signal change */ file->column_bitmaps_signal(); } @@ -6345,7 +6345,7 @@ MY_BITMAP *TABLE::prepare_for_keyread(uint index, MY_BITMAP *map) file->ha_start_keyread(index); if (map != read_set || !(file->index_flags(index, 0, 1) & HA_CLUSTERED_INDEX)) { - mark_columns_used_by_index(index, map); + mark_index_columns(index, map); column_bitmaps_set(map); } DBUG_RETURN(backup); @@ -6356,12 +6356,12 @@ MY_BITMAP *TABLE::prepare_for_keyread(uint index, MY_BITMAP *map) Mark that only fields from one key is used. Useful before keyread. */ -void TABLE::mark_columns_used_by_index(uint index, MY_BITMAP *bitmap) +void TABLE::mark_index_columns(uint index, MY_BITMAP *bitmap) { - DBUG_ENTER("TABLE::mark_columns_used_by_index"); + DBUG_ENTER("TABLE::mark_index_columns"); bitmap_clear_all(bitmap); - mark_columns_used_by_index_no_reset(index, bitmap); + mark_index_columns_no_reset(index, bitmap); DBUG_VOID_RETURN; } @@ -6385,8 +6385,8 @@ void TABLE::restore_column_maps_after_keyread(MY_BITMAP *backup) DBUG_VOID_RETURN; } -static void mark_index_columns(TABLE *table, uint index, - MY_BITMAP *bitmap, bool read) +static void do_mark_index_columns(TABLE *table, uint index, + MY_BITMAP *bitmap, bool read) { KEY_PART_INFO *key_part= table->key_info[index].key_part; uint key_parts= table->key_info[index].user_defined_key_parts; @@ -6397,22 +6397,22 @@ static void mark_index_columns(TABLE *table, uint index, bitmap_set_bit(bitmap, key_part[k].fieldnr-1); if (table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX && table->s->primary_key != MAX_KEY && table->s->primary_key != index) - mark_index_columns(table, table->s->primary_key, bitmap, read); + do_mark_index_columns(table, table->s->primary_key, bitmap, read); } /* mark columns used by key, but don't reset other fields */ -inline void TABLE::mark_columns_used_by_index_no_reset(uint index, MY_BITMAP *bitmap) +inline void TABLE::mark_index_columns_no_reset(uint index, MY_BITMAP *bitmap) { - mark_index_columns(this, index, bitmap, false); + do_mark_index_columns(this, index, bitmap, false); } -inline void TABLE::mark_columns_used_by_index_for_read_no_reset(uint index) +inline void TABLE::mark_index_columns_for_read(uint index) { - mark_index_columns(this, index, read_set, true); + do_mark_index_columns(this, index, read_set, true); } /* @@ -6433,7 +6433,7 @@ void TABLE::mark_auto_increment_column() bitmap_set_bit(read_set, found_next_number_field->field_index); bitmap_set_bit(write_set, found_next_number_field->field_index); if (s->next_number_keypart) - mark_columns_used_by_index_for_read_no_reset(s->next_number_index); + mark_index_columns_for_read(s->next_number_index); file->column_bitmaps_signal(); } @@ -6489,7 +6489,7 @@ void TABLE::mark_columns_needed_for_delete() file->use_hidden_primary_key(); else { - mark_columns_used_by_index_for_read_no_reset(s->primary_key); + mark_index_columns_for_read(s->primary_key); need_signal= true; } } @@ -6579,7 +6579,7 @@ void TABLE::mark_columns_needed_for_update() file->use_hidden_primary_key(); else { - mark_columns_used_by_index_for_read_no_reset(s->primary_key); + mark_index_columns_for_read(s->primary_key); need_signal= true; } } @@ -6742,7 +6742,7 @@ void TABLE::mark_columns_per_binlog_row_image() We don't need to mark the primary key in the rpl_write_set as the binary log will include all columns read anyway. */ - mark_columns_used_by_index_for_read_no_reset(s->primary_key); + mark_index_columns_for_read(s->primary_key); /* Only write columns that have changed */ rpl_write_set= write_set; break; diff --git a/sql/table.h b/sql/table.h index 7a5f4c6fe86..38b63d285c6 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1421,9 +1421,9 @@ public: MY_BITMAP *prepare_for_keyread(uint index, MY_BITMAP *map); MY_BITMAP *prepare_for_keyread(uint index) { return prepare_for_keyread(index, &tmp_set); } - void mark_columns_used_by_index(uint index, MY_BITMAP *map); - void mark_columns_used_by_index_no_reset(uint index, MY_BITMAP *map); - void mark_columns_used_by_index_for_read_no_reset(uint index); + void mark_index_columns(uint index, MY_BITMAP *bitmap); + void mark_index_columns_no_reset(uint index, MY_BITMAP *bitmap); + void mark_index_columns_for_read(uint index); void restore_column_maps_after_keyread(MY_BITMAP *backup); void mark_auto_increment_column(void); void mark_columns_needed_for_update(void); From 191cae2d0ddeb475152c475a2227d1c385eaac83 Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Fri, 25 Jun 2021 04:23:27 +0300 Subject: [PATCH 18/35] MDEV-18249 ASSERT_COLUMN_MARKED_FOR_READ failed in ANALYZE TABLE The problem is the same as in MDEV-18166: columns in virtual field expression are not marked for read, while the field itself does. field->register_field_in_read_map() should be called for read-marking all fields. The test is reproduced only in 10.4+, however the fix is applicable to 10.2+. --- mysql-test/suite/gcol/inc/gcol_view.inc | 9 +++++++++ mysql-test/suite/gcol/r/gcol_view_innodb.result | 9 +++++++++ mysql-test/suite/gcol/r/gcol_view_myisam.result | 9 +++++++++ sql/sql_admin.cc | 4 ++-- 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/gcol/inc/gcol_view.inc b/mysql-test/suite/gcol/inc/gcol_view.inc index 4aabd2429cd..6f9ce673199 100644 --- a/mysql-test/suite/gcol/inc/gcol_view.inc +++ b/mysql-test/suite/gcol/inc/gcol_view.inc @@ -267,3 +267,12 @@ DELETE FROM v1 ORDER BY v LIMIT 4; DROP TABLE t1; DROP VIEW v1; + +--echo # +--echo # MDEV-18249 ASSERT_COLUMN_MARKED_FOR_READ failed in ANALYZE TABLE +--echo # + +create table t1 (c varchar(3) not null, v varchar(4) as (c) virtual); +insert into t1 (c) values ('a'),('b'); +analyze table t1 persistent for columns (v) indexes (); + diff --git a/mysql-test/suite/gcol/r/gcol_view_innodb.result b/mysql-test/suite/gcol/r/gcol_view_innodb.result index 59e299f9d8c..03c4a15620a 100644 --- a/mysql-test/suite/gcol/r/gcol_view_innodb.result +++ b/mysql-test/suite/gcol/r/gcol_view_innodb.result @@ -303,6 +303,15 @@ INSERT INTO t1 (d) VALUES ('2004-04-19 15:37:39.123'),('1985-12-24 10:15:08.456' DELETE FROM v1 ORDER BY v LIMIT 4; DROP TABLE t1; DROP VIEW v1; +# +# MDEV-18249 ASSERT_COLUMN_MARKED_FOR_READ failed in ANALYZE TABLE +# +create table t1 (c varchar(3) not null, v varchar(4) as (c) virtual); +insert into t1 (c) values ('a'),('b'); +analyze table t1 persistent for columns (v) indexes (); +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK DROP VIEW IF EXISTS v1,v2; DROP TABLE IF EXISTS t1,t2,t3; DROP PROCEDURE IF EXISTS p1; diff --git a/mysql-test/suite/gcol/r/gcol_view_myisam.result b/mysql-test/suite/gcol/r/gcol_view_myisam.result index 17cc2135439..a030c73401c 100644 --- a/mysql-test/suite/gcol/r/gcol_view_myisam.result +++ b/mysql-test/suite/gcol/r/gcol_view_myisam.result @@ -303,6 +303,15 @@ INSERT INTO t1 (d) VALUES ('2004-04-19 15:37:39.123'),('1985-12-24 10:15:08.456' DELETE FROM v1 ORDER BY v LIMIT 4; DROP TABLE t1; DROP VIEW v1; +# +# MDEV-18249 ASSERT_COLUMN_MARKED_FOR_READ failed in ANALYZE TABLE +# +create table t1 (c varchar(3) not null, v varchar(4) as (c) virtual); +insert into t1 (c) values ('a'),('b'); +analyze table t1 persistent for columns (v) indexes (); +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK DROP VIEW IF EXISTS v1,v2; DROP TABLE IF EXISTS t1,t2,t3; DROP PROCEDURE IF EXISTS p1; diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index 41af1e22de6..7942587cf02 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -838,7 +838,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, enum enum_field_types type= (*field_ptr)->type(); if (type < MYSQL_TYPE_MEDIUM_BLOB || type > MYSQL_TYPE_BLOB) - bitmap_set_bit(tab->read_set, fields); + tab->field[fields]->register_field_in_read_map(); else push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_NO_EIS_FOR_FIELD, @@ -866,7 +866,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, enum enum_field_types type= tab->field[pos]->type(); if (type < MYSQL_TYPE_MEDIUM_BLOB || type > MYSQL_TYPE_BLOB) - bitmap_set_bit(tab->read_set, pos); + tab->field[pos]->register_field_in_read_map(); else push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_NO_EIS_FOR_FIELD, From 165a6dc97a900e922cb90a1fb5b16e8f9d254ec3 Mon Sep 17 00:00:00 2001 From: Alexey Bychko Date: Tue, 13 Jul 2021 14:30:40 +0700 Subject: [PATCH 19/35] MDEV-26119 RPM packages on RHEL-8 require the latest minor changed rpm db query to output only version for libsepol and not release/buildnumber --- support-files/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/support-files/CMakeLists.txt b/support-files/CMakeLists.txt index 038e7163901..810e0127202 100644 --- a/support-files/CMakeLists.txt +++ b/support-files/CMakeLists.txt @@ -88,7 +88,7 @@ IF(UNIX) INSTALL(FILES ${out} DESTINATION ${inst_location}/policy/selinux COMPONENT SupportFiles) ENDFOREACH() IF(RPM) - EXECUTE_PROCESS(COMMAND rpm -q --qf "%{VERSION}-%{RELEASE}" libsepol + EXECUTE_PROCESS(COMMAND rpm -q --qf "%{VERSION}" libsepol OUTPUT_VARIABLE LIBSEPOL_VERSION RESULT_VARIABLE err) IF (NOT err) SET(CPACK_RPM_server_PACKAGE_REQUIRES From 0f6e170c34700a2964556839c676c1b7768f3ffb Mon Sep 17 00:00:00 2001 From: Nayuta Yanagisawa Date: Thu, 8 Jul 2021 04:24:38 +0000 Subject: [PATCH 20/35] MDEV-25985 Spider handle ">=" as ">" in some cases The function spider_db_append_key_where_internal() converts HA_READ_AFTER_KEY to '>'. The conversion seems to be correct for single-column indexes because HA_READ_AFTER_KEY means "read the key after the provided value." However, how about multi-column indexes? Assume that there is a multi-column index on c1 and c2 and we search with the condition 'c1 >= 100 AND c2 > 200'. The key_range.flag corresponds to the search condition could be HA_READ_AFTER_KEY. In such a case, we could not simply convert HA_READ_AFTER_KEY to '>'. The correct conversion is to convert HA_READ_AFTER_KEY to '>' only for the last column in key_part_map and to convert HA_READ_AFTER_KEY to '>=' for the other column. The similar discussion also applies to the conversion from key_range.flag to a sign of inequality. --- .../spider/include/init_master_1.inc | 5 +++ .../spider/r/spider_fixes_part.result | 34 +++++++++++++++ .../spider/t/spider_fixes_part.test | 35 ++++++++++++++++ storage/spider/spd_db_conn.cc | 42 +++++++++++++++---- 4 files changed, 107 insertions(+), 9 deletions(-) diff --git a/storage/spider/mysql-test/spider/include/init_master_1.inc b/storage/spider/mysql-test/spider/include/init_master_1.inc index 2c45d0bd65d..460142b9c7d 100644 --- a/storage/spider/mysql-test/spider/include/init_master_1.inc +++ b/storage/spider/mysql-test/spider/include/init_master_1.inc @@ -152,6 +152,11 @@ let $MASTER_1_COMMENT_TEXT_PK1_1= COMMENT 'tbl "t1", srv "s_2_1"'; let $MASTER_1_COMMENT_TEXT_KEY1_1= COMMENT 'tbl "t1", srv "s_2_1"'; +let $MASTER_1_COMMENT_MDEV_25985= + COMMENT='table "t1"' + PARTITION BY LIST COLUMNS(`a`) ( + PARTITION `pt1` DEFAULT COMMENT = 'srv "s_2_1"' + ); let $MASTER_1_CHECK_DIRECT_UPDATE_STATUS= SHOW STATUS LIKE 'Spider_direct_update'; let $MASTER_1_CHECK_DIRECT_DELETE_STATUS= diff --git a/storage/spider/mysql-test/spider/r/spider_fixes_part.result b/storage/spider/mysql-test/spider/r/spider_fixes_part.result index d2367af9bbd..ad8a87db727 100644 --- a/storage/spider/mysql-test/spider/r/spider_fixes_part.result +++ b/storage/spider/mysql-test/spider/r/spider_fixes_part.result @@ -262,6 +262,40 @@ a b c d e f 56B68DA68D6D4A04A08B453D09AD7B70 821E71E6ABB4404EBAA349BB681089F8 51041110620310 2018-08-02 13:48:28 510411 0 51ECF2C0CD3C48D99C91792E99D3C1A0 017B8A460DBC444682B791305EF75356 51041110620308 2018-08-02 13:48:29 510411 0 093B37A93A534DF883787AF5F6799674 996C7F14989D480589A553717D735E3E 51041110620302 2018-08-02 13:48:30 510411 0 +# +# MDEV-25985 Spider handle ">=" as ">" in some cases +# +connection child2_1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( +a int, +b int, +c int, +PRIMARY KEY (a), +KEY (b,c) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +INSERT INTO t1 VALUES (1, 1, 1), (2, 2, 1); +connection master_1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( +a int, +b int, +c int, +PRIMARY KEY (a), +KEY (b,c) +) ENGINE=Spider DEFAULT CHARSET=utf8 COMMENT='table "t1"' + PARTITION BY LIST COLUMNS(`a`) ( +PARTITION `pt1` DEFAULT COMMENT = 'srv "s_2_1"' + ); +connection master_1; +SELECT * FROM t1 WHERE c > 0 AND b >= 1 AND b <= 2; +a b c +1 1 1 +2 2 1 +SELECT * FROM t1 WHERE c < 3 AND b <= 2; +a b c +1 1 1 +2 2 1 deinit connection master_1; diff --git a/storage/spider/mysql-test/spider/t/spider_fixes_part.test b/storage/spider/mysql-test/spider/t/spider_fixes_part.test index 868e684f959..68594458434 100644 --- a/storage/spider/mysql-test/spider/t/spider_fixes_part.test +++ b/storage/spider/mysql-test/spider/t/spider_fixes_part.test @@ -726,6 +726,41 @@ if ($HAVE_PARTITION) } } + +--echo # +--echo # MDEV-25985 Spider handle ">=" as ">" in some cases +--echo # + +--connection child2_1 +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings +eval CREATE TABLE t1 ( + a int, + b int, + c int, + PRIMARY KEY (a), + KEY (b,c) +) $CHILD2_1_ENGINE $CHILD2_1_CHARSET; + +INSERT INTO t1 VALUES (1, 1, 1), (2, 2, 1); + +--connection master_1 +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings +eval CREATE TABLE t1 ( + a int, + b int, + c int, + PRIMARY KEY (a), + KEY (b,c) +) $MASTER_1_ENGINE $MASTER_1_CHARSET $MASTER_1_COMMENT_MDEV_25985; + +--connection master_1 +SELECT * FROM t1 WHERE c > 0 AND b >= 1 AND b <= 2; +SELECT * FROM t1 WHERE c < 3 AND b <= 2; + --echo --echo deinit --disable_warnings diff --git a/storage/spider/spd_db_conn.cc b/storage/spider/spd_db_conn.cc index 8d4e9acda07..df6c0ceb5f5 100644 --- a/storage/spider/spd_db_conn.cc +++ b/storage/spider/spd_db_conn.cc @@ -1867,12 +1867,20 @@ int spider_db_append_key_where_internal( case HA_READ_AFTER_KEY: if (sql_kind == SPIDER_SQL_KIND_SQL) { + const char* op_str; + uint32 op_len; + if (start_key_part_map == 1) { + op_str = SPIDER_SQL_GT_STR; + op_len = SPIDER_SQL_GT_LEN; + } else { + op_str = SPIDER_SQL_GTEQUAL_STR; + op_len = SPIDER_SQL_GTEQUAL_LEN; + } if (str->reserve(store_length + key_name_length + - /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 + - SPIDER_SQL_GT_LEN)) + /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 + op_len)) DBUG_RETURN(HA_ERR_OUT_OF_MEM); dbton_share->append_column_name(str, field->field_index); - str->q_append(SPIDER_SQL_GT_STR, SPIDER_SQL_GT_LEN); + str->q_append(op_str, op_len); if (spider_dbton[dbton_id].db_util-> append_column_value(spider, str, field, ptr, share->access_charset)) @@ -1927,12 +1935,20 @@ int spider_db_append_key_where_internal( result_list->desc_flg = TRUE; if (sql_kind == SPIDER_SQL_KIND_SQL) { + const char* op_str; + uint32 op_len; + if (start_key_part_map == 1) { + op_str = SPIDER_SQL_LT_STR; + op_len = SPIDER_SQL_LT_LEN; + } else { + op_str = SPIDER_SQL_LTEQUAL_STR; + op_len = SPIDER_SQL_LTEQUAL_LEN; + } if (str->reserve(store_length + key_name_length + - /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 + - SPIDER_SQL_LT_LEN)) + /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 + op_len)) DBUG_RETURN(HA_ERR_OUT_OF_MEM); dbton_share->append_column_name(str, field->field_index); - str->q_append(SPIDER_SQL_LT_STR, SPIDER_SQL_LT_LEN); + str->q_append(op_str, op_len); if (spider_dbton[dbton_id].db_util-> append_column_value(spider, str, field, ptr, share->access_charset)) @@ -2297,12 +2313,20 @@ int spider_db_append_key_where_internal( case HA_READ_BEFORE_KEY: if (sql_kind == SPIDER_SQL_KIND_SQL) { + const char* op_str; + uint32 op_len; + if (end_key_part_map == 1) { + op_str = SPIDER_SQL_LT_STR; + op_len = SPIDER_SQL_LT_LEN; + } else { + op_str = SPIDER_SQL_LTEQUAL_STR; + op_len = SPIDER_SQL_LTEQUAL_LEN; + } if (str->reserve(store_length + key_name_length + - /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 + - SPIDER_SQL_LT_LEN)) + /* SPIDER_SQL_NAME_QUOTE_LEN */ 2 + op_len)) DBUG_RETURN(HA_ERR_OUT_OF_MEM); dbton_share->append_column_name(str, field->field_index); - str->q_append(SPIDER_SQL_LT_STR, SPIDER_SQL_LT_LEN); + str->q_append(op_str, op_len); if (spider_dbton[dbton_id].db_util-> append_column_value(spider, str, field, ptr, share->access_charset)) From da495b1b697d7cde0af8c7900dc9762cc3f7455b Mon Sep 17 00:00:00 2001 From: Oli Sennhauser Date: Thu, 14 Jan 2021 14:35:45 +0100 Subject: [PATCH 21/35] Typo fix in extrabackup.cc and innobackupex.cc Thanks to @shinguz for helping with this. This a backport commit from 10.7 --- extra/mariabackup/innobackupex.cc | 2 +- extra/mariabackup/xtrabackup.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extra/mariabackup/innobackupex.cc b/extra/mariabackup/innobackupex.cc index c4c8ec7f17b..4bbdeead0d6 100644 --- a/extra/mariabackup/innobackupex.cc +++ b/extra/mariabackup/innobackupex.cc @@ -307,7 +307,7 @@ static struct my_option ibx_long_options[] = {"force-non-empty-directories", OPT_FORCE_NON_EMPTY_DIRS, "This " "option, when specified, makes --copy-back or --move-back transfer " "files to non-empty directories. Note that no existing files will be " - "overwritten. If --copy-back or --nove-back has to copy a file from " + "overwritten. If --copy-back or --move-back has to copy a file from " "the backup directory which already exists in the destination " "directory, it will still fail with an error.", (uchar *) &opt_ibx_force_non_empty_dirs, diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index dc6227b6b7b..6f4ad7d9e17 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -1281,7 +1281,7 @@ struct my_option xb_client_options[]= { "This " "option, when specified, makes --copy-back or --move-back transfer " "files to non-empty directories. Note that no existing files will be " - "overwritten. If --copy-back or --nove-back has to copy a file from " + "overwritten. If --copy-back or --move-back has to copy a file from " "the backup directory which already exists in the destination " "directory, it will still fail with an error.", (uchar *) &opt_force_non_empty_dirs, (uchar *) &opt_force_non_empty_dirs, From 6a89f346dea852b267994e6f32e1c163e7688b34 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Thu, 10 Jun 2021 23:54:14 +0300 Subject: [PATCH 22/35] MDEV-25858: Query results are incorrect when indexes are added If test_if_skip_sort_order() decides to use an index to produce required ordering, it should disable "Range Checked for each record" optimization. This is because Range-Checked-for-each-record may decide to use an index (or an index_merge) which will not produce the required ordering. --- mysql-test/r/order_by_innodb.result | 52 +++++++++++++++++++++++++++++ mysql-test/t/order_by_innodb.test | 51 ++++++++++++++++++++++++++++ sql/sql_select.cc | 12 +++++++ 3 files changed, 115 insertions(+) diff --git a/mysql-test/r/order_by_innodb.result b/mysql-test/r/order_by_innodb.result index 9cdf9800cee..14b9b861a14 100644 --- a/mysql-test/r/order_by_innodb.result +++ b/mysql-test/r/order_by_innodb.result @@ -147,4 +147,56 @@ i n 656 eight set optimizer_switch= @save_optimizer_switch; DROP TABLE t1,t2,t3; +# +# MDEV-25858: Query results are incorrect when indexes are added +# +CREATE TABLE t1 (id int NOT NULL PRIMARY KEY) engine=innodb; +insert into t1 values (1),(2),(3); +CREATE TABLE t2 ( +id int NOT NULL PRIMARY KEY, +id2 int NOT NULL, +d1 datetime, +d2 timestamp NOT NULL, +KEY id2 (id2) +) engine=innodb; +insert into t2 values +(1,2,'2019-03-05 00:00:00','2019-03-06 00:00:00'), +(2,3,'2019-03-05 00:00:00','2019-03-06 00:00:00'), +(3,3,'2019-03-06 00:00:00','2019-03-05 00:00:00'); +select +t1.id,t2.id +from +t1 left join +t2 on t2.id2 = t1.id and +t2.id = (select dd.id +from t2 dd +where +dd.id2 = t1.id and +d1 > '2019-02-06 00:00:00' + order by +dd.d1 desc, dd.d2 desc, dd.id desc limit 1 +); +id id +1 NULL +2 1 +3 3 +create index for_latest_sort on t2 (d1 desc, d2 desc, id desc); +select +t1.id,t2.id +from +t1 left join +t2 on t2.id2 = t1.id and +t2.id = (select dd.id +from t2 dd +where +dd.id2 = t1.id and +d1 > '2019-02-06 00:00:00' + order by +dd.d1 desc, dd.d2 desc, dd.id desc limit 1 +); +id id +1 NULL +2 1 +3 3 +drop table t1,t2; # End of 10.2 tests diff --git a/mysql-test/t/order_by_innodb.test b/mysql-test/t/order_by_innodb.test index f4c738263ae..97c043b8dbc 100644 --- a/mysql-test/t/order_by_innodb.test +++ b/mysql-test/t/order_by_innodb.test @@ -135,4 +135,55 @@ set optimizer_switch= @save_optimizer_switch; DROP TABLE t1,t2,t3; +--echo # +--echo # MDEV-25858: Query results are incorrect when indexes are added +--echo # + +CREATE TABLE t1 (id int NOT NULL PRIMARY KEY) engine=innodb; +insert into t1 values (1),(2),(3); + +CREATE TABLE t2 ( + id int NOT NULL PRIMARY KEY, + id2 int NOT NULL, + d1 datetime, + d2 timestamp NOT NULL, + KEY id2 (id2) +) engine=innodb; + +insert into t2 values + (1,2,'2019-03-05 00:00:00','2019-03-06 00:00:00'), + (2,3,'2019-03-05 00:00:00','2019-03-06 00:00:00'), + (3,3,'2019-03-06 00:00:00','2019-03-05 00:00:00'); + +select + t1.id,t2.id +from + t1 left join + t2 on t2.id2 = t1.id and + t2.id = (select dd.id + from t2 dd + where + dd.id2 = t1.id and + d1 > '2019-02-06 00:00:00' + order by + dd.d1 desc, dd.d2 desc, dd.id desc limit 1 + ); + +create index for_latest_sort on t2 (d1 desc, d2 desc, id desc); + +select + t1.id,t2.id +from + t1 left join + t2 on t2.id2 = t1.id and + t2.id = (select dd.id + from t2 dd + where + dd.id2 = t1.id and + d1 > '2019-02-06 00:00:00' + order by + dd.d1 desc, dd.d2 desc, dd.id desc limit 1 + ); +drop table t1,t2; + --echo # End of 10.2 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e89d06115fc..2bb01ee0d0a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -21938,6 +21938,12 @@ check_reverse_order: if (select->quick == save_quick) save_quick= 0; // make_reverse() consumed it select->set_quick(tmp); + /* Cancel "Range checked for each record" */ + if (tab->use_quick == 2) + { + tab->use_quick= 1; + tab->read_first_record= join_init_read_record; + } } else if (tab->type != JT_NEXT && tab->type != JT_REF_OR_NULL && tab->ref.key >= 0 && tab->ref.key_parts <= used_key_parts) @@ -21950,6 +21956,12 @@ check_reverse_order: */ tab->read_first_record= join_read_last_key; tab->read_record.read_record= join_read_prev_same; + /* Cancel "Range checked for each record" */ + if (tab->use_quick == 2) + { + tab->use_quick= 1; + tab->read_first_record= join_init_read_record; + } /* Cancel Pushed Index Condition, as it doesn't work for reverse scans. */ From c47e4aab62c65e1a1d431f9888ba1bc6b9841687 Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Sat, 26 Jun 2021 20:11:56 +0300 Subject: [PATCH 23/35] MDEV-23597 Assertion `marked_for_read()' failed while evaluating DEFAULT The columns that are part of DEFAULT expression were not read-marked in statements like UPDATE...SET b=DEFAULT. The problem is `F(DEFAULT)` expression depends of the left-hand side of an assignment. However, setup_fields accepts only right-hand side value. Neither Item::fix_fields does. Suchwise, b=DEFAULT(b) works fine, because Item_default_field has information on what field it is default of: if (thd->mark_used_columns != MARK_COLUMNS_NONE) def_field->default_value->expr->update_used_tables(); in Item_default_value::fix_fields(). It is not reasonable to pass a left-hand side to Item:fix_fields, because the case is rare, so the rewrite b= F(DEFAULT) -> b= F(DEFAULT(b)) is made instead. Both UPDATE and multi-UPDATE are affected, however any form of INSERT is not: it marks all the fields in DEFAULT expressions for read in TABLE::mark_default_fields_for_write(). --- mysql-test/r/default.result | 4 ++-- mysql-test/suite/gcol/inc/gcol_ins_upd.inc | 22 +++++++++++++++++++ .../suite/gcol/r/gcol_ins_upd_innodb.result | 22 +++++++++++++++++++ .../suite/gcol/r/gcol_ins_upd_myisam.result | 22 +++++++++++++++++++ mysql-test/t/default.test | 2 +- sql/item.cc | 6 +++++ sql/item.h | 22 ++++++++++++++----- sql/sql_base.cc | 12 ++++++++++ sql/sql_base.h | 1 + sql/sql_update.cc | 4 ++++ sql/sql_yacc.yy | 4 ++-- 11 files changed, 111 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/default.result b/mysql-test/r/default.result index 8335b553a8e..369734ae92a 100644 --- a/mysql-test/r/default.result +++ b/mysql-test/r/default.result @@ -3089,8 +3089,8 @@ DROP TABLE t1; # # Collations # -CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET latin1 DEFAULT CONCAT('ö')) CHARACTER SET koi8r COLLATE koi8r_bin; -ERROR 22007: Encountered illegal value 'ö' when converting to koi8r +CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET latin1 DEFAULT CONCAT('�')) CHARACTER SET koi8r COLLATE koi8r_bin; +ERROR 22007: Encountered illegal value '�' when converting to koi8r CREATE OR REPLACE TABLE t1 (a char(2) default concat('A') COLLATE utf8mb4_unicode_ci); SHOW CREATE TABLE t1; Table Create Table diff --git a/mysql-test/suite/gcol/inc/gcol_ins_upd.inc b/mysql-test/suite/gcol/inc/gcol_ins_upd.inc index 4cfcf371fd7..e02a3828ea2 100644 --- a/mysql-test/suite/gcol/inc/gcol_ins_upd.inc +++ b/mysql-test/suite/gcol/inc/gcol_ins_upd.inc @@ -660,3 +660,25 @@ INSERT IGNORE INTO t1 SELECT * FROM t1; DROP TABLE t1; } + +--echo # +--echo # MDEV-23597 Assertion `marked_for_read()' failed while evaluating DEFAULT +--echo # + +CREATE TABLE t1 (a INT UNIQUE, b INT DEFAULT (c+1), c int); +INSERT INTO t1 VALUES (1,1,1); +UPDATE t1 SET b=DEFAULT; +SELECT * from t1; + +REPLACE t1 VALUES(1,1,1); +INSERT INTO t1 VALUES (1,1,1) ON DUPLICATE KEY UPDATE b= DEFAULT; +SELECT * from t1; + +REPLACE t1 VALUES(1,1,1); +CREATE TABLE t2 (a INT, b INT DEFAULT (c+1), c int); +INSERT INTO t2 VALUES (5,5,5); +UPDATE t1 join t2 set t1.b= DEFAULT, t2.b= DEFAULT; +SELECT * from t1, t2; + +DROP TABLE t1, t2; + diff --git a/mysql-test/suite/gcol/r/gcol_ins_upd_innodb.result b/mysql-test/suite/gcol/r/gcol_ins_upd_innodb.result index 1d85fc837dc..143e1b725c4 100644 --- a/mysql-test/suite/gcol/r/gcol_ins_upd_innodb.result +++ b/mysql-test/suite/gcol/r/gcol_ins_upd_innodb.result @@ -791,6 +791,28 @@ Warnings: Warning 1906 The value specified for generated column 'v' in table 't1' has been ignored Warning 1906 The value specified for generated column 'v' in table 't1' has been ignored DROP TABLE t1; +# +# MDEV-23597 Assertion `marked_for_read()' failed while evaluating DEFAULT +# +CREATE TABLE t1 (a INT UNIQUE, b INT DEFAULT (c+1), c int); +INSERT INTO t1 VALUES (1,1,1); +UPDATE t1 SET b=DEFAULT; +SELECT * from t1; +a b c +1 2 1 +REPLACE t1 VALUES(1,1,1); +INSERT INTO t1 VALUES (1,1,1) ON DUPLICATE KEY UPDATE b= DEFAULT; +SELECT * from t1; +a b c +1 2 1 +REPLACE t1 VALUES(1,1,1); +CREATE TABLE t2 (a INT, b INT DEFAULT (c+1), c int); +INSERT INTO t2 VALUES (5,5,5); +UPDATE t1 join t2 set t1.b= DEFAULT, t2.b= DEFAULT; +SELECT * from t1, t2; +a b c a b c +1 2 1 5 6 5 +DROP TABLE t1, t2; DROP VIEW IF EXISTS v1,v2; DROP TABLE IF EXISTS t1,t2,t3; DROP PROCEDURE IF EXISTS p1; diff --git a/mysql-test/suite/gcol/r/gcol_ins_upd_myisam.result b/mysql-test/suite/gcol/r/gcol_ins_upd_myisam.result index e10b83cabf5..2c883b2de35 100644 --- a/mysql-test/suite/gcol/r/gcol_ins_upd_myisam.result +++ b/mysql-test/suite/gcol/r/gcol_ins_upd_myisam.result @@ -713,6 +713,28 @@ Warnings: Warning 1906 The value specified for generated column 'v' in table 't1' has been ignored Warning 1906 The value specified for generated column 'v' in table 't1' has been ignored DROP TABLE t1; +# +# MDEV-23597 Assertion `marked_for_read()' failed while evaluating DEFAULT +# +CREATE TABLE t1 (a INT UNIQUE, b INT DEFAULT (c+1), c int); +INSERT INTO t1 VALUES (1,1,1); +UPDATE t1 SET b=DEFAULT; +SELECT * from t1; +a b c +1 2 1 +REPLACE t1 VALUES(1,1,1); +INSERT INTO t1 VALUES (1,1,1) ON DUPLICATE KEY UPDATE b= DEFAULT; +SELECT * from t1; +a b c +1 2 1 +REPLACE t1 VALUES(1,1,1); +CREATE TABLE t2 (a INT, b INT DEFAULT (c+1), c int); +INSERT INTO t2 VALUES (5,5,5); +UPDATE t1 join t2 set t1.b= DEFAULT, t2.b= DEFAULT; +SELECT * from t1, t2; +a b c a b c +1 2 1 5 6 5 +DROP TABLE t1, t2; DROP VIEW IF EXISTS v1,v2; DROP TABLE IF EXISTS t1,t2,t3; DROP PROCEDURE IF EXISTS p1; diff --git a/mysql-test/t/default.test b/mysql-test/t/default.test index 31cf589c487..aec518d94a6 100644 --- a/mysql-test/t/default.test +++ b/mysql-test/t/default.test @@ -1855,7 +1855,7 @@ DROP TABLE t1; --echo # --error ER_BAD_DATA -CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET latin1 DEFAULT CONCAT('ö')) CHARACTER SET koi8r COLLATE koi8r_bin; +CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET latin1 DEFAULT CONCAT('�')) CHARACTER SET koi8r COLLATE koi8r_bin; CREATE OR REPLACE TABLE t1 (a char(2) default concat('A') COLLATE utf8mb4_unicode_ci); SHOW CREATE TABLE t1; DROP TABLE t1; diff --git a/sql/item.cc b/sql/item.cc index d7a3659a2ce..96e118e6365 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -9003,6 +9003,12 @@ error: return TRUE; } +bool Item_default_value::enchant_default_with_arg_processor(void *proc_arg) +{ + if (!arg) arg= (Item *)proc_arg; + return 0; +} + void Item_default_value::cleanup() { delete cached_field; // Free cached blob data diff --git a/sql/item.h b/sql/item.h index cc1914a7ad4..8be9a7fe417 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1713,6 +1713,7 @@ public: virtual bool limit_index_condition_pushdown_processor(void *arg) { return 0; } virtual bool exists2in_processor(void *arg) { return 0; } virtual bool find_selective_predicates_list_processor(void *arg) { return 0; } + virtual bool enchant_default_with_arg_processor(void *arg) { return 0; } bool cleanup_is_expensive_cache_processor(void *arg) { is_expensive_cache= (int8)(-1); @@ -5449,6 +5450,11 @@ public: class Item_default_value : public Item_field { void calculate(); +protected: + Item_default_value(THD *thd, Name_resolution_context *context_arg, Item *a) + :Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL, + (const char *)NULL), + arg(a), cached_field(NULL) {} public: Item *arg; Field *cached_field; @@ -5456,16 +5462,12 @@ public: :Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL, (const char *)NULL), arg(NULL), cached_field(NULL) {} - Item_default_value(THD *thd, Name_resolution_context *context_arg, Item *a) - :Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL, - (const char *)NULL), - arg(a), cached_field(NULL) {} Item_default_value(THD *thd, Name_resolution_context *context_arg, Field *a) :Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL, (const char *)NULL), arg(NULL),cached_field(NULL) {} enum Type type() const { return DEFAULT_VALUE_ITEM; } - bool vcol_assignment_allowed_value() const { return arg == NULL; } + bool vcol_assignment_allowed_value() const { return true; } bool eq(const Item *item, bool binary_cmp) const; bool fix_fields(THD *, Item **); void cleanup(); @@ -5495,6 +5497,7 @@ public: Item_field *field_for_view_update() { return 0; } bool update_vcol_processor(void *arg) { return 0; } bool check_func_default_processor(void *arg) { return true; } + bool enchant_default_with_arg_processor(void *arg); bool walk(Item_processor processor, bool walk_subquery, void *args) { @@ -5505,6 +5508,15 @@ public: Item *transform(THD *thd, Item_transformer transformer, uchar *args); }; +class Item_default_value_arg: public Item_default_value +{ +public: + Item_default_value_arg(THD *thd, Name_resolution_context *context, Item *a) + :Item_default_value(thd, context, a) {} + + bool vcol_assignment_allowed_value() const { return arg == NULL; } +}; + /** This class is used as bulk parameter INGNORE representation. diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 3471297ac7d..9a66b27a454 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7193,6 +7193,18 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List &fields, DBUG_RETURN(0); } +/** Transforms b= F(DEFAULT) -> b= F(DEFAULT(b)) */ +void setup_defaults(THD *thd, List &fields, List &values) +{ + List_iterator fit(fields); + List_iterator vit(values); + + for (Item *value= vit++, *f_item= fit++; value; value= vit++, f_item= fit++) + { + value->walk(&Item::enchant_default_with_arg_processor, false, f_item); + } +} + /**************************************************************************** ** Check that all given fields exists and fill struct with current data ****************************************************************************/ diff --git a/sql/sql_base.h b/sql/sql_base.h index 5674e8378c5..b3b0a11795d 100644 --- a/sql/sql_base.h +++ b/sql/sql_base.h @@ -172,6 +172,7 @@ bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array, List &item, enum_mark_columns mark_used_columns, List *sum_func_list, List *pre_fix, bool allow_sum_func); +void setup_defaults(THD *thd, List &fields, List &values); void unfix_fields(List &items); bool fill_record(THD * thd, TABLE *table_arg, List &fields, List &values, bool ignore_errors, bool update); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 8af6c8f80a2..0344d8e0082 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -370,6 +370,8 @@ int mysql_update(THD *thd, DBUG_RETURN(1); } + setup_defaults(thd, fields, values); + #ifndef NO_EMBEDDED_ACCESS_CHECKS /* Check values */ table_list->grant.want_privilege= table->grant.want_privilege= @@ -1749,6 +1751,8 @@ int multi_update::prepare(List ¬_used_values, } } + setup_defaults(thd, *fields, *values); + /* We have to check values after setup_tables to get covering_keys right in reference tables diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 25826d2d6b0..ec82c7f9f07 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -9466,8 +9466,8 @@ column_default_non_parenthesized_expr: Item_splocal *il= $3->get_item_splocal(); if (il) my_yyabort_error((ER_WRONG_COLUMN_NAME, MYF(0), il->my_name()->str)); - $$= new (thd->mem_root) Item_default_value(thd, Lex->current_context(), - $3); + $$= new (thd->mem_root) Item_default_value_arg(thd, Lex->current_context(), + $3); if ($$ == NULL) MYSQL_YYABORT; } From bab989ab38a4d1d93f0f783fa0ee5e9f641a8566 Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Mon, 19 Jul 2021 19:25:11 +0700 Subject: [PATCH 24/35] MDEV-26145: Incorrect metadata is sent on running query with union in PS mode Test cases like the following one produce different result sets if it's run with and without th option --ps-protocol. CREATE TABLE t1(a INT); --enable_metadata (SELECT MAX(a) FROM t1) UNION (SELECT MAX(a) FROM t1); --disable_metadata DROP TABLE t1; Result sets differ in metadata for the query (SELECT MAX(a) FROM t1) UNION (SELECT MAX(a) FROM t1); The reason for different content of query metadata is that for queries with union the items being created on JOIN preparing phase is placed into item_list from SELECT_LEX_UNIT whereas for queries without union item_list from SELECT_LEX is used instead. --- mysql-test/r/mysql_client_test.result | 5 ++ mysql-test/t/mysql_client_test.test | 4 ++ sql/sql_prepare.cc | 7 ++- tests/mysql_client_test.c | 66 +++++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/mysql_client_test.result b/mysql-test/r/mysql_client_test.result index 9538475fb86..37a735286da 100644 --- a/mysql-test/r/mysql_client_test.result +++ b/mysql-test/r/mysql_client_test.result @@ -126,6 +126,11 @@ Data: EOF mysql_stmt_next_result(): 0; field_count: 0 # ------------------------------------ +# cat MYSQL_TMP_DIR/test_mdev26145.out.log +# ------------------------------------ +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def MAX(a) MAX(a) 3 11 0 Y 32768 0 63 +# ------------------------------------ SET @@global.general_log= @old_general_log; SET @@global.slow_query_log= @old_slow_query_log; diff --git a/mysql-test/t/mysql_client_test.test b/mysql-test/t/mysql_client_test.test index 8c2f5e2c32b..aa9b1d5a77c 100644 --- a/mysql-test/t/mysql_client_test.test +++ b/mysql-test/t/mysql_client_test.test @@ -35,6 +35,10 @@ echo ok; --echo # ------------------------------------ --cat_file $MYSQL_TMP_DIR/test_wl4435.out.log --echo # ------------------------------------ +--echo # cat MYSQL_TMP_DIR/test_mdev26145.out.log +--echo # ------------------------------------ +--cat_file $MYSQL_TMP_DIR/test_mdev26145.out.log +--echo # ------------------------------------ --echo SET @@global.general_log= @old_general_log; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 922d7c92796..624bcb90cd5 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1674,7 +1674,12 @@ static int mysql_test_select(Prepared_statement *stmt, if (!lex->describe && !thd->lex->analyze_stmt && !stmt->is_sql_prepare()) { /* Make copy of item list, as change_columns may change it */ - List fields(lex->select_lex.item_list); + SELECT_LEX_UNIT* master_unit= unit->first_select()->master_unit(); + bool is_union_op= + master_unit->is_union() || master_unit->fake_select_lex; + + List fields(is_union_op ? unit->item_list : + lex->select_lex.item_list); /* Change columns if a procedure like analyse() */ if (unit->last_procedure && unit->last_procedure->change_columns(thd, fields)) diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 93f23236dbc..1f0334ec2cf 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -19896,6 +19896,71 @@ static void test_ps_params_in_ctes() myquery(rc); } +void display_result_metadata(MYSQL_FIELD *field, + uint num_fields) +{ + MYSQL_FIELD* field_end; + + mct_log("Catalog\tDatabase\tTable\tTable_alias\tColumn\t" + "Column_alias\tType\tLength\tMax length\tIs_null\t" + "Flags\tDecimals\tCharsetnr\n"); + for (field_end= field+num_fields; field < field_end; field++) + { + mct_log("%s\t", field->catalog); + mct_log("%s\t", field->db); + mct_log("%s\t", field->org_table); + mct_log("%s\t", field->table); + mct_log("%s\t", field->org_name); + mct_log("%s\t", field->name); + mct_log("%u\t", field->type); + mct_log("%lu\t", field->length); + mct_log("%lu\t", field->max_length); + mct_log("%s\t", (IS_NOT_NULL(field->flags) ? "N" : "Y")); + mct_log("%u\t", field->flags); + mct_log("%u\t", field->decimals); + mct_log("%u\n", field->charsetnr); + } +} + +static void test_mdev_26145() +{ + MYSQL_STMT *stmt; + MYSQL_RES *result; + MYSQL_FIELD *fields; + int rc, num_fields; + + myheader("test_mdev_26145"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1(a INT)"); + myquery(rc); + + stmt= mysql_simple_prepare( + mysql, "(SELECT MAX(a) FROM t1) UNION (SELECT MAX(a) FROM t1)"); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + result= mysql_stmt_result_metadata(stmt); + DIE_UNLESS(result); + + num_fields= mysql_stmt_field_count(stmt); + fields= mysql_fetch_fields(result); + + mct_start_logging("test_mdev26145"); + display_result_metadata(fields, num_fields); + mct_close_log(); + + mysql_free_result(result); + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1"); + + myquery(rc); +} #ifndef EMBEDDED_LIBRARY #define MDEV19838_MAX_PARAM_COUNT 32 @@ -20047,6 +20112,7 @@ static void test_mdev19838() #endif // EMBEDDED_LIBRARY static struct my_tests_st my_tests[]= { + { "test_mdev_26145", test_mdev_26145 }, { "disable_query_logs", disable_query_logs }, { "test_view_sp_list_fields", test_view_sp_list_fields }, { "client_query", client_query }, From b7886f55eb707c4cf7d8a5d94e79a87909f153e7 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 18 Jul 2021 23:52:50 +0200 Subject: [PATCH 25/35] fix mysqld_safe --help put defaults* options first (and together). list --defaults-group-suffix too --- scripts/mysqld_safe.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index dc2c0db8e40..9f539bf875d 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -73,12 +73,14 @@ usage () { cat < Date: Fri, 16 Jul 2021 22:46:50 -0700 Subject: [PATCH 26/35] MDEV-26135 Assertion failure when executing PS with a hanging recursive CTE The bug affected execution of queries with With clauses containing so-called hanging recursive CTEs in PREPARE mode. A CTE is hanging if it's not used in the query. Preparation of a prepared statement from a query with a hanging CTE caused a leak in the server and execution of this prepared statement led to an assert failure of the server built in the debug mode. This happened because the units specifying recursive CTEs erroneously were not cleaned up if those CTEs were hanging. The patch enforces cleanup of hanging recursive CTEs in the same way as other hanging CTEs. Approved by dmitry.shulga@mariadb.com --- mysql-test/r/cte_recursive.result | 27 +++++++++++++++++++++++++++ mysql-test/t/cte_recursive.test | 21 +++++++++++++++++++++ sql/sql_union.cc | 6 ++++-- 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/cte_recursive.result b/mysql-test/r/cte_recursive.result index 3e926525e99..a4d821ed1a0 100644 --- a/mysql-test/r/cte_recursive.result +++ b/mysql-test/r/cte_recursive.result @@ -4454,5 +4454,32 @@ deallocate prepare stmt; drop table folks; set big_tables=@save_big_tables; # +# MDEV-26135: execution of PS for query with hanging recursive CTE +# +create table t1 (a int); +insert into t1 values (5), (7); +create table t2 (b int); +insert into t2 values (3), (7), (1); +with recursive r as (select a from t1 union select a+1 from r where a < 10) +select * from t2; +b +3 +7 +1 +prepare stmt from "with recursive r as (select a from t1 union select a+1 from r where a < 10) +select * from t2"; +execute stmt; +b +3 +7 +1 +execute stmt; +b +3 +7 +1 +deallocate prepare stmt; +drop table t1,t2; +# # End of 10.2 tests # diff --git a/mysql-test/t/cte_recursive.test b/mysql-test/t/cte_recursive.test index 849e76b0436..49f9c1f4574 100644 --- a/mysql-test/t/cte_recursive.test +++ b/mysql-test/t/cte_recursive.test @@ -2819,6 +2819,27 @@ drop table folks; set big_tables=@save_big_tables; +--echo # +--echo # MDEV-26135: execution of PS for query with hanging recursive CTE +--echo # + +create table t1 (a int); +insert into t1 values (5), (7); +create table t2 (b int); +insert into t2 values (3), (7), (1); + +let $q= +with recursive r as (select a from t1 union select a+1 from r where a < 10) +select * from t2; + +eval $q; +eval prepare stmt from "$q"; +execute stmt; +execute stmt; +deallocate prepare stmt; + +drop table t1,t2; + --echo # --echo # End of 10.2 tests --echo # diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 7baedfb259c..e5648e6989b 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -1382,7 +1382,8 @@ bool st_select_lex_unit::cleanup() { DBUG_RETURN(FALSE); } - if (with_element && with_element->is_recursive && union_result) + if (with_element && with_element->is_recursive && union_result && + with_element->rec_outer_references) { select_union_recursive *result= with_element->rec_result; if (++result->cleanup_count == with_element->rec_outer_references) @@ -1584,7 +1585,8 @@ bool st_select_lex::cleanup() for (SELECT_LEX_UNIT *lex_unit= first_inner_unit(); lex_unit ; lex_unit= lex_unit->next_unit()) { - if (lex_unit->with_element && lex_unit->with_element->is_recursive) + if (lex_unit->with_element && lex_unit->with_element->is_recursive && + lex_unit->with_element->rec_outer_references) continue; error= (bool) ((uint) error | (uint) lex_unit->cleanup()); } From 0151590d8fd2c6492eddf00a6b8dbbb69d378177 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 19 Jul 2021 17:50:09 +0200 Subject: [PATCH 27/35] Update libmariadb --- libmariadb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmariadb b/libmariadb index 802ce584a26..e9f02c9ea6e 160000 --- a/libmariadb +++ b/libmariadb @@ -1 +1 @@ -Subproject commit 802ce584a26fdc0ba67fcf35e277bf3c7440956a +Subproject commit e9f02c9ea6e5a262005324fd0a3231ca39fa5c99 From 6638cf2e9ea49c21a504c9f1b8e6460887930441 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 19 Jul 2021 22:02:10 +0200 Subject: [PATCH 28/35] MDEV-20787 Script dgcov.pl does not work For every file.gcda file, gcov <7.x created file.cc.gcda.gcov. While gcov 7.x and 8.x create file.cc.gcov And sometimes otherfile.h.gcov or otherfile.ic.gcov, for included files. (gcov 9.x+ creates .json.gz files, see MDEV-26102) So, we use `gcov -l` that will create file.cc.gcda##file.cc.gcov, file.cc.gcda##otherfile.h.gcov, etc. And we search and parse all those file.cc.gcda*.gcov files. --- mysql-test/dgcov.pl | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/mysql-test/dgcov.pl b/mysql-test/dgcov.pl index fbc5540e697..734f5c6ed7d 100755 --- a/mysql-test/dgcov.pl +++ b/mysql-test/dgcov.pl @@ -155,32 +155,34 @@ END sub gcov_one_file { return unless /\.gcda$/; unless ($opt_skip_gcov) { - $cmd= "gcov -i '$_' 2>/dev/null >/dev/null"; + $cmd= "gcov -il '$_' 2>/dev/null >/dev/null"; print STDERR ++$file_no,"\r" if not $opt_verbose and -t STDERR; logv "Running: $cmd"; system($cmd)==0 or die "system($cmd): $? $!"; } # now, read the generated file - open FH, '<', "$_.gcov" or die "open(<$_.gcov): $!"; - my $fname; - while () { - chomp; - if (/^function:/) { - next; + for my $gcov_file (<$_*.gcov>) { + open FH, '<', "$gcov_file" or die "open(<$gcov_file): $!"; + my $fname; + while () { + chomp; + if (/^function:/) { + next; + } + if (/^file:/) { + $fname=realpath($'); + next; + } + next if /^lcount:\d+,-\d+/; # whatever that means + unless (/^lcount:(\d+),(\d+)/ and $fname) { + warn "unknown line '$_' in $gcov_file"; + next; + } + $cov{$fname}->{$1}+=$2; } - if (/^file:/) { - $fname=realpath($'); - next; - } - next if /^lcount:\d+,-\d+/; # whatever that means - unless (/^lcount:(\d+),(\d+)/ and $fname) { - warn "unknown line '$_' after running '$cmd'"; - next; - } - $cov{$fname}->{$1}+=$2; + close(FH); } - close(FH); } sub write_coverage { From ce2a2bff0f087257220ac372cc499cf037599a03 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 19 Jul 2021 22:06:42 +0200 Subject: [PATCH 29/35] MDEV-20787 Script dgcov.pl does not work When building with `make` gcov files use full path names, when building with `ninja` gcov files use paths relative to the source root in gcov_one_file() the current directory is somewhere under CMakeFiles/, so if a file exists in the specified location, this location must've been a full path name. --- mysql-test/dgcov.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/dgcov.pl b/mysql-test/dgcov.pl index 734f5c6ed7d..2c00c64d1ff 100755 --- a/mysql-test/dgcov.pl +++ b/mysql-test/dgcov.pl @@ -171,7 +171,7 @@ sub gcov_one_file { next; } if (/^file:/) { - $fname=realpath($'); + $fname=realpath(-f $' ? $' : $root.$'); next; } next if /^lcount:\d+,-\d+/; # whatever that means From 1cfcf32cd092b775cee0a108aad0b4ec70eb8318 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 20 Jul 2021 10:56:49 +0200 Subject: [PATCH 30/35] fix libmariadb compilation, on GCC. --- libmariadb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmariadb b/libmariadb index e9f02c9ea6e..7d3d7c5ff4a 160000 --- a/libmariadb +++ b/libmariadb @@ -1 +1 @@ -Subproject commit e9f02c9ea6e5a262005324fd0a3231ca39fa5c99 +Subproject commit 7d3d7c5ff4a9772cf6c73901757d6e39c6a20e99 From 5f8651ac238d8d6cd3e4a7e3090b4b529f990331 Mon Sep 17 00:00:00 2001 From: Jagdeep Sidhu Date: Tue, 13 Jul 2021 16:05:29 +0000 Subject: [PATCH 31/35] Fix switch case statement in trx_flush_log_if_needed_low() In commit 2e814d4702d71a04388386a9f591d14a35980bfe on MariaDB 10.2 the switch case statement in trx_flush_log_if_needed_low() regressed. Since 10.2 this code was refactored to have switches in descending order, so value of 3 for innodb_flush_log_at_trx_commit is behaving the same as value of 2, that is no FSYNC is being enforced during COMMIT phase. The switch should however not be empty and cases 2 and 3 should not have the identical contents. As per documentation, setting innodb_flush_log_at_trx_commit to 3 should do FSYNC to disk if innodb_flush_log_at_trx_commit is set to 3. This fixes the regression so that the switch statement again does what users expect the setting should do. All new code of the whole pull request, including one or several files that are either new files or modified ones, are contributed under the BSD-new license. I am contributing on behalf of my employer Amazon Web Services, Inc. --- storage/innobase/trx/trx0trx.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index e3df3f397a5..d1b35bd84a3 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -1559,12 +1559,12 @@ trx_flush_log_if_needed_low( bool flush = srv_file_flush_method != SRV_NOSYNC; switch (srv_flush_log_at_trx_commit) { - case 3: case 2: /* Write the log but do not flush it to disk */ flush = false; /* fall through */ case 1: + case 3: /* Write the log and optionally flush it to disk */ log_write_up_to(lsn, flush); return; From 1918bdf32cdbd1f190cc4479f4076ee4a467f25d Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Mon, 21 Jun 2021 14:54:26 +0300 Subject: [PATCH 32/35] MDEV-25361 innochecksum must not report errors for freed pages Store and maintain xdes pages always. And doesn't verify checksums for freed pages. innochecksum can work only with the first space file of multiple ones. Tell about it and abort in case of not the first file. --- extra/innochecksum.cc | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/extra/innochecksum.cc b/extra/innochecksum.cc index 4dca6572434..beda56032b8 100644 --- a/extra/innochecksum.cc +++ b/extra/innochecksum.cc @@ -817,6 +817,16 @@ write_file( return(true); } +// checks using current xdes page whether the page is free +static bool page_is_free(const byte *xdes, page_size_t page_size, + size_t page_no) +{ + const byte *des= + xdes + XDES_ARR_OFFSET + + XDES_SIZE * ((page_no & (page_size.physical() - 1)) / FSP_EXTENT_SIZE); + return xdes_get_bit(des, XDES_FREE_BIT, page_no % FSP_EXTENT_SIZE); +} + /* Parse the page and collect/dump the information about page type @param [in] page buffer page @@ -908,11 +918,7 @@ parse_page( std::map::iterator it; it = index_ids.find(id); per_index_stats &index = (it->second); - const byte* des = xdes + XDES_ARR_OFFSET - + XDES_SIZE * ((page_no & (page_size.physical() - 1)) - / FSP_EXTENT_SIZE); - if (xdes_get_bit(des, XDES_FREE_BIT, - page_no % FSP_EXTENT_SIZE)) { + if (page_is_free(xdes, page_size, page_no)) { index.free_pages++; return; } @@ -1072,7 +1078,6 @@ parse_page( case FIL_PAGE_TYPE_FSP_HDR: page_type.n_fil_page_type_fsp_hdr++; - memcpy(xdes, page, page_size.physical()); if (page_type_dump) { fprintf(file, "#::%llu\t\t|\t\tFile Space " "Header\t\t|\t%s\n", cur_page_num, str); @@ -1081,7 +1086,6 @@ parse_page( case FIL_PAGE_TYPE_XDES: page_type.n_fil_page_type_xdes++; - memcpy(xdes, page, page_size.physical()); if (page_type_dump) { fprintf(file, "#::%llu\t\t|\t\tExtent descriptor " "page\t\t|\t%s\n", cur_page_num, str); @@ -1814,6 +1818,8 @@ int main( printf("page %llu ", cur_page_num); } + memcpy(xdes, buf, physical_page_size); + if (page_type_summary || page_type_dump) { parse_page(buf, xdes, fil_page_type, page_size, is_encrypted); } @@ -1992,6 +1998,7 @@ first_non_zero: /* If no-check is enabled, skip the checksum verification.*/ if (!no_check + && !page_is_free(xdes, page_size, cur_page_num) && !skip_page && (exit_status = verify_checksum( buf, page_size, @@ -2014,6 +2021,10 @@ first_non_zero: printf("page %llu ", cur_page_num); } + if (page_get_page_no(buf) % physical_page_size == 0) { + memcpy(xdes, buf, physical_page_size); + } + if (page_type_summary || page_type_dump) { parse_page(buf, xdes, fil_page_type, page_size, is_encrypted); } From 7da1cfb07a0dfec08b861688640bbbb7779549f6 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Fri, 25 Jun 2021 18:00:47 +0300 Subject: [PATCH 33/35] avoid searching std::map twice in innochecksum --- extra/innochecksum.cc | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/extra/innochecksum.cc b/extra/innochecksum.cc index beda56032b8..3eea1244429 100644 --- a/extra/innochecksum.cc +++ b/extra/innochecksum.cc @@ -912,12 +912,7 @@ parse_page( } /* update per-index statistics */ { - if (index_ids.count(id) == 0) { - index_ids[id] = per_index_stats(); - } - std::map::iterator it; - it = index_ids.find(id); - per_index_stats &index = (it->second); + per_index_stats &index = index_ids[id]; if (page_is_free(xdes, page_size, page_no)) { index.free_pages++; return; From 872422dcbbe3681a794935fb2cae422d9d5f4108 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Tue, 20 Jul 2021 00:07:31 -0700 Subject: [PATCH 34/35] MDEV-26025 Server crashes while executing query with CTE in PS/SP This bug appeared after the patch for bug MDEV-23886. Due to this bug execution of queries with CTEs used the same CTE at least twice via prepared statements or with stored procedures caused crashes of the server. It happened because the select created for any of not the first usage of a CTE erroneously was not included into all_selects_list. This patch corrects the patch applied to fix the bug MDEV-26108. Approved by Oleksandr Byelkin --- mysql-test/r/cte_nonrecursive.result | 42 ++++++++++++++++++++++++++++ mysql-test/t/cte_nonrecursive.test | 27 ++++++++++++++++++ sql/sql_cte.cc | 15 ++++++---- 3 files changed, 79 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/cte_nonrecursive.result b/mysql-test/r/cte_nonrecursive.result index 5cc5a2503e3..2504e55d77c 100644 --- a/mysql-test/r/cte_nonrecursive.result +++ b/mysql-test/r/cte_nonrecursive.result @@ -2044,4 +2044,46 @@ select a from t1 union select a+1 as a from cte_r r where a < 10 ) select * from cte_e; ERROR 42S02: Table 'test.cte_r' doesn't exist drop table t1; +# +# MDEV-26025: query with two usage of a CTE executing via PS /SP +# +create table t1 (a int, b int); +insert into t1 value (1,3), (3,2), (1,3), (4,1); +prepare stmt from "with +cte1 as ( select a,b from t1 where a = 1 AND b = 3 ), +cte2 as ( select a,b from cte1 ), +cte3 as ( select a,b from cte2 ) +select * from cte3, cte2"; +execute stmt; +a b a b +1 3 1 3 +1 3 1 3 +1 3 1 3 +1 3 1 3 +execute stmt; +a b a b +1 3 1 3 +1 3 1 3 +1 3 1 3 +1 3 1 3 +deallocate prepare stmt; +create procedure sp() with +cte1 as ( select a,b from t1 where a = 1 AND b = 3 ), +cte2 as ( select a,b from cte1 ), +cte3 as ( select a,b from cte2 ) +select * from cte3, cte2; +call sp(); +a b a b +1 3 1 3 +1 3 1 3 +1 3 1 3 +1 3 1 3 +call sp(); +a b a b +1 3 1 3 +1 3 1 3 +1 3 1 3 +1 3 1 3 +drop procedure sp; +drop table t1; # End of 10.2 tests diff --git a/mysql-test/t/cte_nonrecursive.test b/mysql-test/t/cte_nonrecursive.test index 68dbc0cac19..c20a0dc1d39 100644 --- a/mysql-test/t/cte_nonrecursive.test +++ b/mysql-test/t/cte_nonrecursive.test @@ -1515,4 +1515,31 @@ with cte_e as ( drop table t1; +--echo # +--echo # MDEV-26025: query with two usage of a CTE executing via PS /SP +--echo # + +create table t1 (a int, b int); +insert into t1 value (1,3), (3,2), (1,3), (4,1); + +let $q= +with + cte1 as ( select a,b from t1 where a = 1 AND b = 3 ), + cte2 as ( select a,b from cte1 ), + cte3 as ( select a,b from cte2 ) +select * from cte3, cte2; + +eval prepare stmt from "$q"; +execute stmt; +execute stmt; +deallocate prepare stmt; + +eval create procedure sp() $q; + +call sp(); +call sp(); + +drop procedure sp; +drop table t1; + --echo # End of 10.2 tests diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc index 702db8f96d9..b720eac2317 100644 --- a/sql/sql_cte.cc +++ b/sql/sql_cte.cc @@ -1012,6 +1012,7 @@ st_select_lex_unit *With_element::clone_parsed_spec(LEX *old_lex, bool parse_status= false; st_select_lex *with_select; + st_select_lex *last_clone_select; char save_end= unparsed_spec.str[unparsed_spec.length]; unparsed_spec.str[unparsed_spec.length]= '\0'; @@ -1099,11 +1100,6 @@ st_select_lex_unit *With_element::clone_parsed_spec(LEX *old_lex, lex->unit.include_down(with_table->select_lex); lex->unit.set_slave(with_select); lex->unit.cloned_from= spec; - old_lex->all_selects_list= - (st_select_lex*) (lex->all_selects_list-> - insert_chain_before( - (st_select_lex_node **) &(old_lex->all_selects_list), - with_select)); /* Now all references to the CTE defined outside of the cloned specification @@ -1119,6 +1115,15 @@ st_select_lex_unit *With_element::clone_parsed_spec(LEX *old_lex, goto err; } + last_clone_select= lex->all_selects_list; + while (last_clone_select->next_select_in_list()) + last_clone_select= last_clone_select->next_select_in_list(); + old_lex->all_selects_list= + (st_select_lex*) (lex->all_selects_list-> + insert_chain_before( + (st_select_lex_node **) &(old_lex->all_selects_list), + last_clone_select)); + lex->sphead= NULL; // in order not to delete lex->sphead lex_end(lex); err: From 4c387945f0f8d5df84ae987c4a4bba7675815c72 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 9 Jul 2021 18:56:34 -0700 Subject: [PATCH 35/35] MDEV-25565 Crash on 2-nd execution of SP/PS for query calculating window functions from view A crash of the server happened when executing a stored procedure whose the only query calculated window functions over a mergeable view specified as a select from non-mergeable view. The crash could be reproduced if the window specifications of the window functions were identical and both contained PARTITION lists and ORDER BY lists. A crash also happened on the second execution of the prepared statement created for such query. If to use derived tables or CTE instead of views the problem still manifests itself crashing the server. When optimizing the window specifications of a window function the server can substitute the partition lists and the order lists for the corresponding lists from another window specification in the case when the lists are identical. This substitution is not permanent and should be rolled back before the second execution. It was not done and this ultimately led to a crash when resolving the column names at the second execution of SP/PS. --- mysql-test/r/win.result | 287 ++++++++++++++++++++++++++++++++++++++++ mysql-test/t/win.test | 147 ++++++++++++++++++++ sql/sql_union.cc | 26 ++++ sql/sql_window.cc | 12 ++ sql/sql_window.h | 5 +- 5 files changed, 476 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/win.result b/mysql-test/r/win.result index 8a31dcc0634..bc017ea70a3 100644 --- a/mysql-test/r/win.result +++ b/mysql-test/r/win.result @@ -3911,5 +3911,292 @@ sum(i) over () IN ( SELECT 1 FROM t1 a) 0 DROP TABLE t1; # +# MDEV-25565: 2-nd call of SP with SELECT from view / derived table / CTE +# returning the result of calculation of 2 window +# functions that use the same window specification +# +create table t1 (a int); +insert into t1 values (3), (7), (1), (7), (1), (1), (3), (1), (5); +create view v2 as select a from t1 group by a; +create view v1 as select * from v2; +create procedure sp1() select v1.a, +sum(v1.a) over (partition by v1.a order by v1.a) as k, +avg(v1.a) over (partition by v1.a order by v1.a) as m +from v1; +call sp1(); +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +call sp1(); +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +prepare stmt from "select v1.a, +sum(v1.a) over (partition by v1.a order by v1.a) as k, +avg(v1.a) over (partition by v1.a order by v1.a) as m +from v1"; +execute stmt; +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +execute stmt; +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +deallocate prepare stmt; +create procedure sp2() select * from +( select dt1.a, +sum(dt1.a) over (partition by dt1.a order by dt1.a) as k, +avg(dt1.a) over (partition by dt1.a order by dt1.a) as m +from (select * from v2) as dt1 +) as dt; +call sp2(); +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +call sp2(); +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +prepare stmt from "select * from +( select dt1.a, +sum(dt1.a) over (partition by dt1.a order by dt1.a) as k, +avg(dt1.a) over (partition by dt1.a order by dt1.a) as m +from (select * from v2) as dt1 +) as dt"; +execute stmt; +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +execute stmt; +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +deallocate prepare stmt; +create procedure sp3() select * from +( select dt1.a, +sum(dt1.a) over (partition by dt1.a order by dt1.a) as k, +avg(dt1.a) over (partition by dt1.a order by dt1.a) as m +from ( select * from (select * from t1 group by a) as dt2 ) as dt1 +) as dt; +call sp3(); +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +call sp3(); +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +prepare stmt from "select * from +( select dt1.a, +sum(dt1.a) over (partition by dt1.a order by dt1.a) as k, +avg(dt1.a) over (partition by dt1.a order by dt1.a) as m +from ( select * from (select * from t1 group by a) as dt2 ) as dt1 +) as dt"; +execute stmt; +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +execute stmt; +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +deallocate prepare stmt; +create procedure sp4() with cte1 as (select * from (select * from t1 group by a) as dt2), +cte as +( select cte1.a, +sum(cte1.a) over (partition by cte1.a order by cte1.a) as k, +avg(cte1.a) over (partition by cte1.a order by cte1.a) as m +from cte1 ) +select * from cte; +call sp4(); +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +call sp4(); +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +prepare stmt from "with cte1 as (select * from (select * from t1 group by a) as dt2), +cte as +( select cte1.a, +sum(cte1.a) over (partition by cte1.a order by cte1.a) as k, +avg(cte1.a) over (partition by cte1.a order by cte1.a) as m +from cte1 ) +select * from cte"; +execute stmt; +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +execute stmt; +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +deallocate prepare stmt; +create procedure sp5() with cte1 as (select * from v2), +cte as +( select cte1.a, +sum(cte1.a) over (partition by cte1.a order by cte1.a) as k, +avg(cte1.a) over (partition by cte1.a order by cte1.a) as m +from cte1 ) +select * from cte; +call sp5(); +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +call sp5(); +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +prepare stmt from "with cte1 as (select * from v2), +cte as +( select cte1.a, +sum(cte1.a) over (partition by cte1.a order by cte1.a) as k, +avg(cte1.a) over (partition by cte1.a order by cte1.a) as m +from cte1 ) +select * from cte"; +execute stmt; +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +execute stmt; +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +deallocate prepare stmt; +create procedure sp6() with +cte1 as (with cte2 as (select * from t1 group by a) select * from cte2), +cte as +( select cte1.a, +sum(cte1.a) over (partition by cte1.a order by cte1.a) as k, +avg(cte1.a) over (partition by cte1.a order by cte1.a) as m +from cte1 ) +select * from cte; +call sp6(); +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +call sp6(); +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +prepare stmt from "with +cte1 as (with cte2 as (select * from t1 group by a) select * from cte2), +cte as +( select cte1.a, +sum(cte1.a) over (partition by cte1.a order by cte1.a) as k, +avg(cte1.a) over (partition by cte1.a order by cte1.a) as m +from cte1 ) +select * from cte"; +execute stmt; +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +execute stmt; +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +deallocate prepare stmt; +create procedure sp7() with +cte2 as (select * from v1), +cte1 as (select * from cte2), +cte as +( select cte1.a, +sum(cte1.a) over (partition by cte1.a order by cte1.a) as k, +avg(cte1.a) over (partition by cte1.a order by cte1.a) as m +from cte1 ) +select * from cte; +call sp7(); +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +call sp7(); +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +prepare stmt from "with +cte2 as (select * from v1), +cte1 as (select * from cte2), +cte as +( select cte1.a, +sum(cte1.a) over (partition by cte1.a order by cte1.a) as k, +avg(cte1.a) over (partition by cte1.a order by cte1.a) as m +from cte1 ) +select * from cte"; +execute stmt; +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +execute stmt; +a k m +1 1 1.0000 +3 3 3.0000 +5 5 5.0000 +7 7 7.0000 +deallocate prepare stmt; +drop procedure sp1; +drop procedure sp2; +drop procedure sp3; +drop procedure sp4; +drop procedure sp5; +drop procedure sp6; +drop procedure sp7; +drop view v1,v2; +drop table t1; +# # End of 10.2 tests # diff --git a/mysql-test/t/win.test b/mysql-test/t/win.test index c07a81f17da..72e789dff3f 100644 --- a/mysql-test/t/win.test +++ b/mysql-test/t/win.test @@ -2556,6 +2556,153 @@ INSERT INTO t1 VALUES (1),(2),(3); SELECT sum(i) over () IN ( SELECT 1 FROM t1 a) FROM t1; DROP TABLE t1; +--echo # +--echo # MDEV-25565: 2-nd call of SP with SELECT from view / derived table / CTE +--echo # returning the result of calculation of 2 window +--echo # functions that use the same window specification +--echo # + +create table t1 (a int); +insert into t1 values (3), (7), (1), (7), (1), (1), (3), (1), (5); + +create view v2 as select a from t1 group by a; +create view v1 as select * from v2; + +let $q1= +select v1.a, + sum(v1.a) over (partition by v1.a order by v1.a) as k, + avg(v1.a) over (partition by v1.a order by v1.a) as m +from v1; + +eval create procedure sp1() $q1; +call sp1(); +call sp1(); + +eval prepare stmt from "$q1"; +execute stmt; +execute stmt; +deallocate prepare stmt; + +let $q2= +select * from + ( select dt1.a, + sum(dt1.a) over (partition by dt1.a order by dt1.a) as k, + avg(dt1.a) over (partition by dt1.a order by dt1.a) as m + from (select * from v2) as dt1 + ) as dt; + +eval create procedure sp2() $q2; +call sp2(); +call sp2(); + +eval prepare stmt from "$q2"; +execute stmt; +execute stmt; +deallocate prepare stmt; + +let $q3= +select * from + ( select dt1.a, + sum(dt1.a) over (partition by dt1.a order by dt1.a) as k, + avg(dt1.a) over (partition by dt1.a order by dt1.a) as m + from ( select * from (select * from t1 group by a) as dt2 ) as dt1 + ) as dt; + +eval create procedure sp3() $q3; +call sp3(); +call sp3(); + +eval prepare stmt from "$q3"; +execute stmt; +execute stmt; +deallocate prepare stmt; + +let $q4= +with cte1 as (select * from (select * from t1 group by a) as dt2), + cte as + ( select cte1.a, + sum(cte1.a) over (partition by cte1.a order by cte1.a) as k, + avg(cte1.a) over (partition by cte1.a order by cte1.a) as m + from cte1 ) +select * from cte; + +eval create procedure sp4() $q4; +call sp4(); +call sp4(); + +eval prepare stmt from "$q4"; +execute stmt; +execute stmt; +deallocate prepare stmt; + +let $q5= +with cte1 as (select * from v2), + cte as + ( select cte1.a, + sum(cte1.a) over (partition by cte1.a order by cte1.a) as k, + avg(cte1.a) over (partition by cte1.a order by cte1.a) as m + from cte1 ) +select * from cte; + +eval create procedure sp5() $q5; +call sp5(); +call sp5(); + +eval prepare stmt from "$q5"; +execute stmt; +execute stmt; +deallocate prepare stmt; + +let $q6= +with +cte1 as (with cte2 as (select * from t1 group by a) select * from cte2), + cte as + ( select cte1.a, + sum(cte1.a) over (partition by cte1.a order by cte1.a) as k, + avg(cte1.a) over (partition by cte1.a order by cte1.a) as m + from cte1 ) +select * from cte; + +eval create procedure sp6() $q6; +call sp6(); +call sp6(); + +eval prepare stmt from "$q6"; +execute stmt; +execute stmt; +deallocate prepare stmt; + +let $q7= +with + cte2 as (select * from v1), + cte1 as (select * from cte2), + cte as + ( select cte1.a, + sum(cte1.a) over (partition by cte1.a order by cte1.a) as k, + avg(cte1.a) over (partition by cte1.a order by cte1.a) as m + from cte1 ) +select * from cte; + +eval create procedure sp7() $q7; +call sp7(); +call sp7(); + +eval prepare stmt from "$q7"; +execute stmt; +execute stmt; +deallocate prepare stmt; + + +drop procedure sp1; +drop procedure sp2; +drop procedure sp3; +drop procedure sp4; +drop procedure sp5; +drop procedure sp6; +drop procedure sp7; +drop view v1,v2; +drop table t1; + --echo # --echo # End of 10.2 tests --echo # diff --git a/sql/sql_union.cc b/sql/sql_union.cc index e5648e6989b..8f7aca2a8ed 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -30,6 +30,7 @@ #include "filesort.h" // filesort_free_buffers #include "sql_view.h" #include "sql_cte.h" +#include "item_windowfunc.h" bool mysql_union(THD *thd, LEX *lex, select_result *result, SELECT_LEX_UNIT *unit, ulong setup_tables_done_option) @@ -1551,6 +1552,29 @@ static void cleanup_order(ORDER *order) } +static void cleanup_window_funcs(List &win_funcs) +{ + List_iterator_fast it(win_funcs); + Item_window_func *win_func; + while ((win_func= it++)) + { + Window_spec *win_spec= win_func->window_spec; + if (!win_spec) + continue; + if (win_spec->save_partition_list) + { + win_spec->partition_list= win_spec->save_partition_list; + win_spec->save_partition_list= NULL; + } + if (win_spec->save_order_list) + { + win_spec->order_list= win_spec->save_order_list; + win_spec->save_order_list= NULL; + } + } +} + + bool st_select_lex::cleanup() { bool error= FALSE; @@ -1559,6 +1583,8 @@ bool st_select_lex::cleanup() cleanup_order(order_list.first); cleanup_order(group_list.first); + cleanup_window_funcs(window_funcs); + if (join) { List_iterator ti(leaf_tables); diff --git a/sql/sql_window.cc b/sql/sql_window.cc index 612c6e692fe..3ef751bc5b9 100644 --- a/sql/sql_window.cc +++ b/sql/sql_window.cc @@ -479,9 +479,15 @@ int compare_window_funcs_by_window_specs(Item_window_func *win_func1, Let's use only one of the lists. */ if (!win_spec1->name() && win_spec2->name()) + { + win_spec1->save_partition_list= win_spec1->partition_list; win_spec1->partition_list= win_spec2->partition_list; + } else + { + win_spec2->save_partition_list= win_spec2->partition_list; win_spec2->partition_list= win_spec1->partition_list; + } cmp= compare_order_lists(win_spec1->order_list, win_spec2->order_list); @@ -494,9 +500,15 @@ int compare_window_funcs_by_window_specs(Item_window_func *win_func1, Let's use only one of the lists. */ if (!win_spec1->name() && win_spec2->name()) + { + win_spec1->save_order_list= win_spec2->order_list; win_spec1->order_list= win_spec2->order_list; + } else + { + win_spec1->save_order_list= win_spec2->order_list; win_spec2->order_list= win_spec1->order_list; + } cmp= compare_window_frames(win_spec1->window_frame, win_spec2->window_frame); diff --git a/sql/sql_window.h b/sql/sql_window.h index e0c1563e5bb..417d0bca12c 100644 --- a/sql/sql_window.h +++ b/sql/sql_window.h @@ -99,8 +99,10 @@ class Window_spec : public Sql_alloc LEX_STRING *window_ref; SQL_I_List *partition_list; + SQL_I_List *save_partition_list; SQL_I_List *order_list; + SQL_I_List *save_order_list; Window_frame *window_frame; @@ -111,7 +113,8 @@ class Window_spec : public Sql_alloc SQL_I_List *ord_list, Window_frame *win_frame) : window_names_are_checked(false), window_ref(win_ref), - partition_list(part_list), order_list(ord_list), + partition_list(part_list), save_partition_list(NULL), + order_list(ord_list), save_order_list(NULL), window_frame(win_frame), referenced_win_spec(NULL) {} virtual char *name() { return NULL; }