MDEV-12930 Testing SEQUENCE object
Fixed the following things from the above MDEV: - Ensure the user has INSERT privilege when generating new sequence values with NEXT VALUE FOR or SETVAL() - Fixed bug in InnoDB when generating several sequence values in one statement - Ensure that read_set is up to date before calling ha_sequence::ha_write_row() - This is only a potential bug with storage engines that trusts the column maps completely
This commit is contained in:
parent
d5d8fa6e04
commit
959891662d
@ -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 test.* to normal_2@'%' identified by 'pass';
|
||||||
grant all on s_db.* to normal_3@'%' 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 all on test.* to normal_4@'%' identified by 'pass';
|
||||||
|
grant select on test.* to normal_5@'%' identified by 'pass';
|
||||||
connection slave;
|
connection slave;
|
||||||
connect m_normal_1, 127.0.0.1, normal_1, pass, s_db, $MASTER_MYPORT;
|
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_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_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;
|
connect s_normal_4, 127.0.0.1, normal_4, pass, test, $SLAVE_MYPORT;
|
||||||
connection slave;
|
connection slave;
|
||||||
@ -171,7 +173,7 @@ create sequence s_db.s2;
|
|||||||
drop sequence s_db.s2;
|
drop sequence s_db.s2;
|
||||||
connection m_normal_2;
|
connection m_normal_2;
|
||||||
select next value for s_db.s1;
|
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;
|
create sequence s_db.s2;
|
||||||
ERROR 42000: CREATE command denied to user 'normal_2'@'localhost' for table 's2'
|
ERROR 42000: CREATE command denied to user 'normal_2'@'localhost' for table 's2'
|
||||||
connection m_normal_1;
|
connection m_normal_1;
|
||||||
@ -771,6 +773,51 @@ next value for s1
|
|||||||
drop function f1;
|
drop function f1;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
drop sequence s1;
|
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;
|
connection master;
|
||||||
use s_db;
|
use s_db;
|
||||||
drop database s_db;
|
drop database s_db;
|
||||||
@ -778,4 +825,5 @@ drop user normal_1@'%';
|
|||||||
drop user normal_2@'%';
|
drop user normal_2@'%';
|
||||||
drop user normal_3@'%';
|
drop user normal_3@'%';
|
||||||
drop user normal_4@'%';
|
drop user normal_4@'%';
|
||||||
|
drop user normal_5@'%';
|
||||||
include/rpl_end.inc
|
include/rpl_end.inc
|
||||||
|
@ -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 test.* to normal_2@'%' identified by 'pass';
|
||||||
grant all on s_db.* to normal_3@'%' 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 all on test.* to normal_4@'%' identified by 'pass';
|
||||||
|
grant select on test.* to normal_5@'%' identified by 'pass';
|
||||||
|
|
||||||
--sync_slave_with_master
|
--sync_slave_with_master
|
||||||
|
|
||||||
connect(m_normal_1, 127.0.0.1, normal_1, pass, s_db, $MASTER_MYPORT);
|
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_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_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);
|
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 table t1;
|
||||||
drop sequence s1;
|
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;
|
connection master;
|
||||||
use s_db;
|
use s_db;
|
||||||
drop database s_db;
|
drop database s_db;
|
||||||
@ -662,5 +699,6 @@ drop user normal_1@'%';
|
|||||||
drop user normal_2@'%';
|
drop user normal_2@'%';
|
||||||
drop user normal_3@'%';
|
drop user normal_3@'%';
|
||||||
drop user normal_4@'%';
|
drop user normal_4@'%';
|
||||||
|
drop user normal_5@'%';
|
||||||
|
|
||||||
--source include/rpl_end.inc
|
--source include/rpl_end.inc
|
||||||
|
@ -113,3 +113,38 @@ LOCK TABLES s1 WRITE;
|
|||||||
insert into s1 values (1,1,9223372036854775806, 1, 1, 1000, 0, 0);
|
insert into s1 values (1,1,9223372036854775806, 1, 1, 1000, 0, 0);
|
||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
drop table s1;
|
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;
|
||||||
|
@ -90,3 +90,30 @@ LOCK TABLES s1 WRITE;
|
|||||||
insert into s1 values (1,1,9223372036854775806, 1, 1, 1000, 0, 0);
|
insert into s1 values (1,1,9223372036854775806, 1, 1, 1000, 0, 0);
|
||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
drop table s1;
|
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;
|
||||||
|
@ -286,7 +286,7 @@ create sequence s_db.s2;
|
|||||||
drop sequence s_db.s2;
|
drop sequence s_db.s2;
|
||||||
connection m_normal_2;
|
connection m_normal_2;
|
||||||
select NEXT VALUE for s_db.s1;
|
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;
|
create sequence s_db.s2;
|
||||||
ERROR 42000: CREATE command denied to user 'normal_2'@'localhost' for table 's2'
|
ERROR 42000: CREATE command denied to user 'normal_2'@'localhost' for table 's2'
|
||||||
connection m_normal_1;
|
connection m_normal_1;
|
||||||
|
@ -152,6 +152,8 @@ public:
|
|||||||
{ return file->check_and_repair(thd); }
|
{ return file->check_and_repair(thd); }
|
||||||
bool is_crashed() const
|
bool is_crashed() const
|
||||||
{ return file->is_crashed(); }
|
{ return file->is_crashed(); }
|
||||||
|
void column_bitmaps_signal()
|
||||||
|
{ return file->column_bitmaps_signal(); }
|
||||||
|
|
||||||
/* New methods */
|
/* New methods */
|
||||||
void register_original_handler(handler *file_arg)
|
void register_original_handler(handler *file_arg)
|
||||||
|
@ -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();
|
TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
|
||||||
Security_context *sctx= thd->security_ctx;
|
Security_context *sctx= thd->security_ctx;
|
||||||
uint i;
|
uint i;
|
||||||
ulong orig_want_access= want_access;
|
ulong original_want_access= want_access;
|
||||||
bool locked= 0;
|
bool locked= 0;
|
||||||
GRANT_TABLE *grant_table;
|
GRANT_TABLE *grant_table;
|
||||||
GRANT_TABLE *grant_table_role= NULL;
|
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=
|
TABLE_LIST *const t_ref=
|
||||||
tl->correspondent_table ? tl->correspondent_table : tl;
|
tl->correspondent_table ? tl->correspondent_table : tl;
|
||||||
sctx= t_ref->security_ctx ? t_ref->security_ctx : thd->security_ctx;
|
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=
|
const ACL_internal_table_access *access=
|
||||||
get_cached_table_access(&t_ref->grant.m_internal,
|
get_cached_table_access(&t_ref->grant.m_internal,
|
||||||
|
@ -7045,6 +7045,15 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
|
|||||||
|
|
||||||
thd->security_ctx= sctx;
|
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(),
|
if (check_access(thd, want_access, table_ref->get_db_name(),
|
||||||
&table_ref->grant.privilege,
|
&table_ref->grant.privilege,
|
||||||
&table_ref->grant.m_internal,
|
&table_ref->grant.m_internal,
|
||||||
|
@ -576,7 +576,7 @@ int sequence_definition::write_initial_sequence(TABLE *table)
|
|||||||
int sequence_definition::write(TABLE *table, bool all_fields)
|
int sequence_definition::write(TABLE *table, bool all_fields)
|
||||||
{
|
{
|
||||||
int error;
|
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());
|
DBUG_ASSERT(((ha_sequence*) table->file)->is_locked());
|
||||||
|
|
||||||
save_rpl_write_set= table->rpl_write_set;
|
save_rpl_write_set= table->rpl_write_set;
|
||||||
@ -593,12 +593,16 @@ int sequence_definition::write(TABLE *table, bool all_fields)
|
|||||||
|
|
||||||
/* Update table */
|
/* Update table */
|
||||||
save_write_set= table->write_set;
|
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);
|
store_fields(table);
|
||||||
if ((error= table->file->ha_write_row(table->record[0])))
|
if ((error= table->file->ha_write_row(table->record[0])))
|
||||||
table->file->print_error(error, MYF(0));
|
table->file->print_error(error, MYF(0));
|
||||||
table->rpl_write_set= save_rpl_write_set;
|
table->rpl_write_set= save_rpl_write_set;
|
||||||
|
table->read_set= save_read_set;
|
||||||
table->write_set= save_write_set;
|
table->write_set= save_write_set;
|
||||||
|
table->file->column_bitmaps_signal();
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8129,10 +8129,11 @@ ha_innobase::build_template(
|
|||||||
ibool fetch_primary_key_cols = FALSE;
|
ibool fetch_primary_key_cols = FALSE;
|
||||||
ulint i;
|
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
|
/* We always retrieve the whole clustered index record if we
|
||||||
use exclusive row level locks, for example, if the read is
|
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;
|
whole_row = true;
|
||||||
} else if (!whole_row) {
|
} else if (!whole_row) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user