diff options
-rw-r--r-- | mysql-test/suite/sql_sequence/gtid.result | 50 | ||||
-rw-r--r-- | mysql-test/suite/sql_sequence/gtid.test | 38 | ||||
-rw-r--r-- | mysql-test/suite/sql_sequence/other.result | 35 | ||||
-rw-r--r-- | mysql-test/suite/sql_sequence/other.test | 27 | ||||
-rw-r--r-- | mysql-test/suite/sql_sequence/replication.result | 2 | ||||
-rw-r--r-- | sql/ha_sequence.h | 2 | ||||
-rw-r--r-- | sql/sql_acl.cc | 12 | ||||
-rw-r--r-- | sql/sql_parse.cc | 9 | ||||
-rw-r--r-- | sql/sql_sequence.cc | 8 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 5 |
10 files changed, 181 insertions, 7 deletions
diff --git a/mysql-test/suite/sql_sequence/gtid.result b/mysql-test/suite/sql_sequence/gtid.result index 366f201d338..ce8e8b7bb80 100644 --- a/mysql-test/suite/sql_sequence/gtid.result +++ b/mysql-test/suite/sql_sequence/gtid.result @@ -6,9 +6,11 @@ grant all on s_db.* to normal_1@'%' identified by 'pass'; grant all on test.* to normal_2@'%' identified by 'pass'; grant all on s_db.* to normal_3@'%' identified by 'pass'; grant all on test.* to normal_4@'%' identified by 'pass'; +grant select on test.* to normal_5@'%' identified by 'pass'; connection slave; connect m_normal_1, 127.0.0.1, normal_1, pass, s_db, $MASTER_MYPORT; connect m_normal_2, 127.0.0.1, normal_2, pass, test, $MASTER_MYPORT; +connect m_normal_3, 127.0.0.1, normal_5, pass, test, $MASTER_MYPORT; connect s_normal_3, 127.0.0.1, normal_3, pass, s_db, $SLAVE_MYPORT; connect s_normal_4, 127.0.0.1, normal_4, pass, test, $SLAVE_MYPORT; connection slave; @@ -171,7 +173,7 @@ create sequence s_db.s2; drop sequence s_db.s2; connection m_normal_2; select next value for s_db.s1; -ERROR 42000: SELECT command denied to user 'normal_2'@'localhost' for table 's1' +ERROR 42000: INSERT command denied to user 'normal_2'@'localhost' for table 's1' create sequence s_db.s2; ERROR 42000: CREATE command denied to user 'normal_2'@'localhost' for table 's2' connection m_normal_1; @@ -771,6 +773,51 @@ next value for s1 drop function f1; drop table t1; drop sequence s1; +############## +Test GRANT +############## +connection m_normal_2; +create table t1 (a int); +create sequence s1; +select next value for s1; +next value for s1 +1 +insert into t1 values (1); +connection m_normal_3; +select * from t1; +a +1 +select * from s1; +next_value min_value max_value start increment cache cycle round +1001 1 9223372036854775806 1 1 1000 0 0 +select previous value for s1; +previous value for s1 +NULL +insert into t1 values (2); +ERROR 42000: INSERT command denied to user 'normal_5'@'localhost' for table 't1' +select next value for s1; +ERROR 42000: INSERT command denied to user 'normal_5'@'localhost' for table 's1' +do setval(s1,1000,0); +ERROR 42000: INSERT command denied to user 'normal_5'@'localhost' for table 's1' +connection master; +grant insert on test.* to normal_5@'%' identified by 'pass'; +disconnect m_normal_3; +connect m_normal_3, 127.0.0.1, normal_5, pass, test, $MASTER_MYPORT; +insert into t1 values (2); +select t1.*, (next value for s1) from t1; +a (next value for s1) +1 2 +2 3 +do setval(s1,10000,0); +select * from s1; +next_value min_value max_value start increment cache cycle round +10000 1 9223372036854775806 1 1 1000 0 0 +connection m_normal_2; +drop table t1; +drop sequence s1; +# +# Cleanup +# connection master; use s_db; drop database s_db; @@ -778,4 +825,5 @@ drop user normal_1@'%'; drop user normal_2@'%'; drop user normal_3@'%'; drop user normal_4@'%'; +drop user normal_5@'%'; include/rpl_end.inc diff --git a/mysql-test/suite/sql_sequence/gtid.test b/mysql-test/suite/sql_sequence/gtid.test index 50492cbb329..98760119b53 100644 --- a/mysql-test/suite/sql_sequence/gtid.test +++ b/mysql-test/suite/sql_sequence/gtid.test @@ -12,11 +12,13 @@ grant all on s_db.* to normal_1@'%' identified by 'pass'; grant all on test.* to normal_2@'%' identified by 'pass'; grant all on s_db.* to normal_3@'%' identified by 'pass'; grant all on test.* to normal_4@'%' identified by 'pass'; +grant select on test.* to normal_5@'%' identified by 'pass'; --sync_slave_with_master connect(m_normal_1, 127.0.0.1, normal_1, pass, s_db, $MASTER_MYPORT); connect(m_normal_2, 127.0.0.1, normal_2, pass, test, $MASTER_MYPORT); +connect(m_normal_3, 127.0.0.1, normal_5, pass, test, $MASTER_MYPORT); connect(s_normal_3, 127.0.0.1, normal_3, pass, s_db, $SLAVE_MYPORT); connect(s_normal_4, 127.0.0.1, normal_4, pass, test, $SLAVE_MYPORT); @@ -655,6 +657,41 @@ drop function f1; drop table t1; drop sequence s1; +--echo ############## +--echo Test GRANT +--echo ############## + +connection m_normal_2; +create table t1 (a int); +create sequence s1; +select next value for s1; +insert into t1 values (1); +connection m_normal_3; +select * from t1; +select * from s1; +select previous value for s1; +--error ER_TABLEACCESS_DENIED_ERROR +insert into t1 values (2); +--error ER_TABLEACCESS_DENIED_ERROR +select next value for s1; +--error ER_TABLEACCESS_DENIED_ERROR +do setval(s1,1000,0); +connection master; +grant insert on test.* to normal_5@'%' identified by 'pass'; +disconnect m_normal_3; +connect(m_normal_3, 127.0.0.1, normal_5, pass, test, $MASTER_MYPORT); +insert into t1 values (2); +select t1.*, (next value for s1) from t1; +do setval(s1,10000,0); +select * from s1; +connection m_normal_2; +drop table t1; +drop sequence s1; + +--echo # +--echo # Cleanup +--echo # + connection master; use s_db; drop database s_db; @@ -662,5 +699,6 @@ drop user normal_1@'%'; drop user normal_2@'%'; drop user normal_3@'%'; drop user normal_4@'%'; +drop user normal_5@'%'; --source include/rpl_end.inc diff --git a/mysql-test/suite/sql_sequence/other.result b/mysql-test/suite/sql_sequence/other.result index e991a595e91..ea72e264b34 100644 --- a/mysql-test/suite/sql_sequence/other.result +++ b/mysql-test/suite/sql_sequence/other.result @@ -113,3 +113,38 @@ LOCK TABLES s1 WRITE; insert into s1 values (1,1,9223372036854775806, 1, 1, 1000, 0, 0); UNLOCK TABLES; drop table s1; +# +# Many sequence calls with innodb +# +create sequence s1 cache=1000 engine=innodb; +start transaction; +select count(nextval(s1)) from seq_1_to_2000; +count(nextval(s1)) +2000 +commit; +select * from s1; +next_value min_value max_value start increment cache cycle round +2001 1 9223372036854775806 1 1 1000 0 0 +drop sequence s1; +create sequence s1 cache=1000 engine=innodb; +start transaction; +select count(nextval(s1)) from seq_1_to_2000; +count(nextval(s1)) +2000 +connect addconroot, localhost, root,,; +connection addconroot; +start transaction; +select count(nextval(s1)) from seq_1_to_2000; +count(nextval(s1)) +2000 +select * from s1; +next_value min_value max_value start increment cache cycle round +4001 1 9223372036854775806 1 1 1000 0 0 +commit; +disconnect addconroot; +connection default; +select * from s1; +next_value min_value max_value start increment cache cycle round +4001 1 9223372036854775806 1 1 1000 0 0 +commit; +drop sequence s1; diff --git a/mysql-test/suite/sql_sequence/other.test b/mysql-test/suite/sql_sequence/other.test index 3716b53311a..0caeb342bc9 100644 --- a/mysql-test/suite/sql_sequence/other.test +++ b/mysql-test/suite/sql_sequence/other.test @@ -90,3 +90,30 @@ LOCK TABLES s1 WRITE; insert into s1 values (1,1,9223372036854775806, 1, 1, 1000, 0, 0); UNLOCK TABLES; drop table s1; + +--echo # +--echo # Many sequence calls with innodb +--echo # + +create sequence s1 cache=1000 engine=innodb; +start transaction; +select count(nextval(s1)) from seq_1_to_2000; +commit; +select * from s1; +drop sequence s1; + +create sequence s1 cache=1000 engine=innodb; +start transaction; +select count(nextval(s1)) from seq_1_to_2000; + +connect (addconroot, localhost, root,,); +connection addconroot; +start transaction; +select count(nextval(s1)) from seq_1_to_2000; +select * from s1; +commit; +disconnect addconroot; +connection default; +select * from s1; +commit; +drop sequence s1; diff --git a/mysql-test/suite/sql_sequence/replication.result b/mysql-test/suite/sql_sequence/replication.result index 4c1508bad93..12355851f7b 100644 --- a/mysql-test/suite/sql_sequence/replication.result +++ b/mysql-test/suite/sql_sequence/replication.result @@ -286,7 +286,7 @@ create sequence s_db.s2; drop sequence s_db.s2; connection m_normal_2; select NEXT VALUE for s_db.s1; -ERROR 42000: SELECT command denied to user 'normal_2'@'localhost' for table 's1' +ERROR 42000: INSERT command denied to user 'normal_2'@'localhost' for table 's1' create sequence s_db.s2; ERROR 42000: CREATE command denied to user 'normal_2'@'localhost' for table 's2' connection m_normal_1; diff --git a/sql/ha_sequence.h b/sql/ha_sequence.h index 8ab452a9372..fd9da05b591 100644 --- a/sql/ha_sequence.h +++ b/sql/ha_sequence.h @@ -152,6 +152,8 @@ public: { return file->check_and_repair(thd); } bool is_crashed() const { return file->is_crashed(); } + void column_bitmaps_signal() + { return file->column_bitmaps_signal(); } /* New methods */ void register_original_handler(handler *file_arg) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 5608e0dfc49..d63a2f2bc51 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -7524,7 +7524,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table(); Security_context *sctx= thd->security_ctx; uint i; - ulong orig_want_access= want_access; + ulong original_want_access= want_access; bool locked= 0; GRANT_TABLE *grant_table; GRANT_TABLE *grant_table_role= NULL; @@ -7558,6 +7558,16 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, TABLE_LIST *const t_ref= tl->correspondent_table ? tl->correspondent_table : tl; sctx= t_ref->security_ctx ? t_ref->security_ctx : thd->security_ctx; + ulong orig_want_access= original_want_access; + + if (t_ref->sequence) + { + /* We want to have either SELECT or INSERT rights to sequences depending + on how they are accessed + */ + orig_want_access= ((t_ref->lock_type == TL_WRITE_ALLOW_WRITE) ? + INSERT_ACL : SELECT_ACL); + } const ACL_internal_table_access *access= get_cached_table_access(&t_ref->grant.m_internal, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 42bf6a5b97c..7169b5dd068 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7045,6 +7045,15 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables, thd->security_ctx= sctx; + if (table_ref->sequence) + { + /* We want to have either SELECT or INSERT rights to sequences depending + on how they are accessed + */ + want_access= ((table_ref->lock_type == TL_WRITE_ALLOW_WRITE) ? + INSERT_ACL : SELECT_ACL); + } + if (check_access(thd, want_access, table_ref->get_db_name(), &table_ref->grant.privilege, &table_ref->grant.m_internal, diff --git a/sql/sql_sequence.cc b/sql/sql_sequence.cc index 1b591f10c9f..35792bfe72e 100644 --- a/sql/sql_sequence.cc +++ b/sql/sql_sequence.cc @@ -576,7 +576,7 @@ int sequence_definition::write_initial_sequence(TABLE *table) int sequence_definition::write(TABLE *table, bool all_fields) { int error; - MY_BITMAP *save_rpl_write_set, *save_write_set; + MY_BITMAP *save_rpl_write_set, *save_write_set, *save_read_set; DBUG_ASSERT(((ha_sequence*) table->file)->is_locked()); save_rpl_write_set= table->rpl_write_set; @@ -593,12 +593,16 @@ int sequence_definition::write(TABLE *table, bool all_fields) /* Update table */ save_write_set= table->write_set; - table->write_set= &table->s->all_set; + save_read_set= table->read_set; + table->read_set= table->write_set= &table->s->all_set; + table->file->column_bitmaps_signal(); store_fields(table); if ((error= table->file->ha_write_row(table->record[0]))) table->file->print_error(error, MYF(0)); table->rpl_write_set= save_rpl_write_set; + table->read_set= save_read_set; table->write_set= save_write_set; + table->file->column_bitmaps_signal(); return error; } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index c2ccd0fab36..c69075eac2c 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -8129,10 +8129,11 @@ ha_innobase::build_template( ibool fetch_primary_key_cols = FALSE; ulint i; - if (m_prebuilt->select_lock_type == LOCK_X) { + if (m_prebuilt->select_lock_type == LOCK_X || m_prebuilt->table->no_rollback()) { /* We always retrieve the whole clustered index record if we use exclusive row level locks, for example, if the read is - done in an UPDATE statement. */ + done in an UPDATE statement or if we are using a no rollback + table */ whole_row = true; } else if (!whole_row) { |