Merge branch '10.6' into 10.11
This commit is contained in:
commit
20b818f45e
@ -1787,11 +1787,6 @@ uint xb_client_options_count = array_elements(xb_client_options);
|
||||
static const char *dbug_option;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_URING
|
||||
extern const char *io_uring_may_be_unsafe;
|
||||
bool innodb_use_native_aio_default();
|
||||
#endif
|
||||
|
||||
static my_bool innodb_log_checkpoint_now;
|
||||
|
||||
struct my_option xb_server_options[] =
|
||||
@ -1929,12 +1924,7 @@ struct my_option xb_server_options[] =
|
||||
"Use native AIO if supported on this platform.",
|
||||
(G_PTR*) &srv_use_native_aio,
|
||||
(G_PTR*) &srv_use_native_aio, 0, GET_BOOL, NO_ARG,
|
||||
#ifdef HAVE_URING
|
||||
innodb_use_native_aio_default(),
|
||||
#else
|
||||
TRUE,
|
||||
#endif
|
||||
0, 0, 0, 0, 0},
|
||||
TRUE, 0, 0, 0, 0, 0},
|
||||
{"innodb_page_size", OPT_INNODB_PAGE_SIZE,
|
||||
"The universal page size of the database.",
|
||||
(G_PTR*) &innobase_page_size, (G_PTR*) &innobase_page_size, 0,
|
||||
@ -2539,12 +2529,8 @@ static bool innodb_init_param()
|
||||
msg("InnoDB: Using Linux native AIO");
|
||||
}
|
||||
#elif defined(HAVE_URING)
|
||||
if (!srv_use_native_aio) {
|
||||
} else if (io_uring_may_be_unsafe) {
|
||||
msg("InnoDB: Using liburing on this kernel %s may cause hangs;"
|
||||
" see https://jira.mariadb.org/browse/MDEV-26674",
|
||||
io_uring_may_be_unsafe);
|
||||
} else {
|
||||
|
||||
if (srv_use_native_aio) {
|
||||
msg("InnoDB: Using liburing");
|
||||
}
|
||||
#else
|
||||
|
@ -38,6 +38,8 @@ static inline void *my_get_stack_pointer(void *default_stack)
|
||||
#if defined(__GNUC__) || defined(__clang__) /* GCC and Clang compilers */
|
||||
#if defined(__i386__) /* Intel x86 (32-bit) */
|
||||
__asm__ volatile ("movl %%esp, %0" : "=r" (stack_ptr));
|
||||
#elif defined(__x86_64__) && defined (__ILP32__) /* Intel x86-64 (64-bit), X32 ABI */
|
||||
__asm__ volatile ("movl %%esp, %0" : "=r" (stack_ptr));
|
||||
#elif defined(__x86_64__) /* Intel x86-64 (64-bit) */
|
||||
__asm__ volatile ("movq %%rsp, %0" : "=r" (stack_ptr));
|
||||
#elif defined(__powerpc__) /* PowerPC (32-bit) */
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit a7ad25b01bd7716d24181657abd4fb203a883371
|
||||
Subproject commit 55abb3203826a7b3593f0728d6d077d4e0f19259
|
@ -1,5 +1,5 @@
|
||||
--source include/not_msan.inc
|
||||
--source include/not_valgrind_build.inc
|
||||
--source include/not_valgrind.inc
|
||||
|
||||
--echo # MDEV-20699 do not cache SP in SHOW CREATE
|
||||
--echo # Warmup round, this might allocate some memory for session variable
|
||||
|
@ -1982,6 +1982,52 @@ connection default;
|
||||
DROP VIEW v1;
|
||||
DROP USER foo;
|
||||
DROP USER FOO;
|
||||
#
|
||||
# MDEV-36380: User has unauthorized access to a sequence through
|
||||
# a view with security invoker
|
||||
#
|
||||
create database db;
|
||||
use db;
|
||||
create sequence s;
|
||||
create sql security invoker view vin as select nextval(s);
|
||||
create sql security definer view vdn as select nextval(s);
|
||||
create sql security invoker view vil as select lastval(s);
|
||||
create sql security definer view vdl as select lastval(s);
|
||||
create sql security invoker view vis as select setval(s,20);
|
||||
create sql security definer view vds as select setval(s,30);
|
||||
create user u@localhost;
|
||||
grant select on db.vin to u@localhost;
|
||||
grant select on db.vdn to u@localhost;
|
||||
grant select on db.vil to u@localhost;
|
||||
grant select on db.vdl to u@localhost;
|
||||
grant select on db.vis to u@localhost;
|
||||
grant select on db.vds to u@localhost;
|
||||
connect con1,localhost,u,,db;
|
||||
select nextval(s);
|
||||
ERROR 42000: SELECT, INSERT command denied to user 'u'@'localhost' for table `db`.`s`
|
||||
select * from vin;
|
||||
ERROR HY000: View 'db.vin' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
select * from vdn;
|
||||
nextval(s)
|
||||
1
|
||||
select lastval(s);
|
||||
ERROR 42000: SELECT command denied to user 'u'@'localhost' for table `db`.`s`
|
||||
select * from vil;
|
||||
ERROR HY000: View 'db.vil' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
select * from vdl;
|
||||
lastval(s)
|
||||
1
|
||||
select setval(s,10);
|
||||
ERROR 42000: INSERT command denied to user 'u'@'localhost' for table `db`.`s`
|
||||
select * from vis;
|
||||
ERROR HY000: View 'db.vis' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
select * from vds;
|
||||
setval(s,30)
|
||||
30
|
||||
disconnect con1;
|
||||
connection default;
|
||||
drop database db;
|
||||
drop user u@localhost;
|
||||
# End of 10.5 tests
|
||||
# Check that a user without access to the schema 'foo' cannot query
|
||||
# a JSON_TABLE view in that schema.
|
||||
|
@ -2237,6 +2237,53 @@ DROP VIEW v1;
|
||||
DROP USER foo;
|
||||
DROP USER FOO;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-36380: User has unauthorized access to a sequence through
|
||||
--echo # a view with security invoker
|
||||
--echo #
|
||||
create database db;
|
||||
use db;
|
||||
create sequence s;
|
||||
create sql security invoker view vin as select nextval(s);
|
||||
create sql security definer view vdn as select nextval(s);
|
||||
create sql security invoker view vil as select lastval(s);
|
||||
create sql security definer view vdl as select lastval(s);
|
||||
create sql security invoker view vis as select setval(s,20);
|
||||
create sql security definer view vds as select setval(s,30);
|
||||
create user u@localhost;
|
||||
grant select on db.vin to u@localhost;
|
||||
grant select on db.vdn to u@localhost;
|
||||
grant select on db.vil to u@localhost;
|
||||
grant select on db.vdl to u@localhost;
|
||||
grant select on db.vis to u@localhost;
|
||||
grant select on db.vds to u@localhost;
|
||||
|
||||
--connect (con1,localhost,u,,db)
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
select nextval(s);
|
||||
--error ER_VIEW_INVALID
|
||||
select * from vin;
|
||||
--disable_ps2_protocol
|
||||
select * from vdn;
|
||||
--enable_ps2_protocol
|
||||
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
select lastval(s);
|
||||
--error ER_VIEW_INVALID
|
||||
select * from vil;
|
||||
select * from vdl;
|
||||
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
select setval(s,10);
|
||||
--error ER_VIEW_INVALID
|
||||
select * from vis;
|
||||
select * from vds;
|
||||
|
||||
--disconnect con1
|
||||
--connection default
|
||||
drop database db;
|
||||
drop user u@localhost;
|
||||
|
||||
--echo # End of 10.5 tests
|
||||
|
||||
--echo # Check that a user without access to the schema 'foo' cannot query
|
||||
|
@ -86,6 +86,8 @@ delete from t where a =13;
|
||||
DROP INDEX idx1 ON t;
|
||||
DROP INDEX idx2 ON t;
|
||||
DROP TABLE t;
|
||||
# restart
|
||||
set default_storage_engine=innodb;
|
||||
/* Test large BLOB data */
|
||||
CREATE TABLE `t` (
|
||||
`a` BLOB,
|
||||
|
@ -1,6 +1,6 @@
|
||||
--source include/have_innodb.inc
|
||||
--source include/have_partition.inc
|
||||
--source include/big_test.inc
|
||||
--source include/not_embedded.inc
|
||||
|
||||
call mtr.add_suppression("\\[Warning\\] InnoDB: Compute virtual");
|
||||
|
||||
@ -66,6 +66,41 @@ DROP INDEX idx1 ON t;
|
||||
DROP INDEX idx2 ON t;
|
||||
DROP TABLE t;
|
||||
|
||||
let MYSQLD_DATADIR=`select @@datadir`;
|
||||
let PAGE_SIZE=`select @@innodb_page_size`;
|
||||
--source include/shutdown_mysqld.inc
|
||||
perl;
|
||||
do "$ENV{MTR_SUITE_DIR}/../innodb/include/crc32.pl";
|
||||
my $file = "$ENV{MYSQLD_DATADIR}/ibdata1";
|
||||
open(FILE, "+<$file") || die "Unable to open $file";
|
||||
binmode FILE;
|
||||
my $ps= $ENV{PAGE_SIZE};
|
||||
my $page;
|
||||
die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps;
|
||||
my $full_crc32 = unpack("N",substr($page,54,4)) & 0x10; # FIL_SPACE_FLAGS
|
||||
sysseek(FILE, 7*$ps, 0) || die "Unable to seek $file\n";
|
||||
die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps;
|
||||
substr($page,54,4)=pack("N",0xc001cafe); # 32 MSB of 64-bit DICT_HDR_INDEX_ID
|
||||
my $polynomial = 0x82f63b78; # CRC-32C
|
||||
if ($full_crc32)
|
||||
{
|
||||
my $ck = mycrc32(substr($page, 0, $ps-4), 0, $polynomial);
|
||||
substr($page, $ps-4, 4) = pack("N", $ck);
|
||||
}
|
||||
else
|
||||
{
|
||||
my $ck= pack("N",mycrc32(substr($page, 4, 22), 0, $polynomial) ^
|
||||
mycrc32(substr($page, 38, $ps - 38 - 8), 0, $polynomial));
|
||||
substr($page,0,4)=$ck;
|
||||
substr($page,$ps-8,4)=$ck;
|
||||
}
|
||||
sysseek(FILE, 7*$ps, 0) || die "Unable to rewind $file\n";
|
||||
syswrite(FILE, $page, $ps)==$ps || die "Unable to write $file\n";
|
||||
close(FILE) || die "Unable to close $file";
|
||||
EOF
|
||||
--source include/start_mysqld.inc
|
||||
set default_storage_engine=innodb;
|
||||
|
||||
/* Test large BLOB data */
|
||||
CREATE TABLE `t` (
|
||||
`a` BLOB,
|
||||
|
@ -20,6 +20,9 @@ set global server_audit_file_path=null;
|
||||
set global server_audit_incl_users=null;
|
||||
set global server_audit_file_path='server_audit.log';
|
||||
set global server_audit_output_type=file;
|
||||
set global server_audit_file_path=REPEAT(REPEAT('new_file_name', 50), 50);
|
||||
Warnings:
|
||||
Warning 1 server_audit_file_path can't exceed FN_LEN characters.
|
||||
set global server_audit_logging=on;
|
||||
set global server_audit_incl_users= repeat("'root',", 10000);
|
||||
ERROR 42000: Variable 'server_audit_incl_users' can't be set to the value of ''root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','...'
|
||||
|
@ -20,6 +20,10 @@ set global server_audit_file_path=null;
|
||||
set global server_audit_incl_users=null;
|
||||
set global server_audit_file_path='server_audit.log';
|
||||
set global server_audit_output_type=file;
|
||||
|
||||
--replace_regex /[1-9][0-9][0-9]+/FN_LEN/
|
||||
set global server_audit_file_path=REPEAT(REPEAT('new_file_name', 50), 50);
|
||||
|
||||
set global server_audit_logging=on;
|
||||
|
||||
--error ER_WRONG_VALUE_FOR_VAR
|
||||
|
@ -0,0 +1,41 @@
|
||||
# Set up Semi-Sync with rpl_semi_sync_master_wait_no_slave=0
|
||||
include/master-slave.inc
|
||||
[connection master]
|
||||
SET @@GLOBAL.rpl_semi_sync_master_enabled= 1;
|
||||
SET @@GLOBAL.rpl_semi_sync_master_wait_no_slave= 0;
|
||||
connection slave;
|
||||
SET @@GLOBAL.rpl_semi_sync_slave_enabled= 1;
|
||||
include/start_slave.inc
|
||||
connection master;
|
||||
connection slave;
|
||||
connection master;
|
||||
SELECT ID INTO @binlog_dump_tid
|
||||
FROM information_schema.PROCESSLIST WHERE COMMAND = 'Binlog Dump';
|
||||
# Control State
|
||||
SELECT STATE FROM information_schema.PROCESSLIST WHERE ID = @binlog_dump_tid;
|
||||
STATE
|
||||
Master has sent all binlog to slave; waiting for more updates
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_master_clients';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_clients 1
|
||||
# Disable Semi-Sync while the dump thread is still connected to its slave
|
||||
SET @@GLOBAL.rpl_semi_sync_master_enabled = 0;
|
||||
SELECT STATE FROM information_schema.PROCESSLIST WHERE ID = @binlog_dump_tid;
|
||||
STATE
|
||||
Master has sent all binlog to slave; waiting for more updates
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_master_clients';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_clients 1
|
||||
# Disconnect the slave and wait until the master's dump thread is gone
|
||||
connection slave;
|
||||
STOP SLAVE;
|
||||
connection master;
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_master_clients';
|
||||
Variable_name Value
|
||||
Rpl_semi_sync_master_clients 0
|
||||
# Cleanup
|
||||
SET @@GLOBAL.rpl_semi_sync_master_enabled= 0;
|
||||
SET @@GLOBAL.rpl_semi_sync_master_wait_no_slave= 1;
|
||||
connection slave;
|
||||
SET @@GLOBAL.rpl_semi_sync_slave_enabled= 0;
|
||||
include/rpl_end.inc
|
@ -0,0 +1,68 @@
|
||||
# MDEV-36359: Master crashes when reverting to async after Semi-Sync disabled.
|
||||
#
|
||||
# Assert behavior of turning Semi-Sync off on
|
||||
# the master when still connected to a slave
|
||||
|
||||
--source include/have_binlog_format_mixed.inc # format-agnostic
|
||||
|
||||
--echo # Set up Semi-Sync with rpl_semi_sync_master_wait_no_slave=0
|
||||
--let $rpl_skip_start_slave= 1
|
||||
--source include/master-slave.inc
|
||||
|
||||
--let $orig_master_enabled=`SELECT @@GLOBAL.rpl_semi_sync_master_enabled`
|
||||
SET @@GLOBAL.rpl_semi_sync_master_enabled= 1;
|
||||
--let $orig_wait_no_slave=`SELECT @@GLOBAL.rpl_semi_sync_master_wait_no_slave`
|
||||
SET @@GLOBAL.rpl_semi_sync_master_wait_no_slave= 0;
|
||||
|
||||
--connection slave
|
||||
--let $orig_slave_enabled=`SELECT @@GLOBAL.rpl_semi_sync_slave_enabled`
|
||||
SET @@GLOBAL.rpl_semi_sync_slave_enabled= 1;
|
||||
--source include/start_slave.inc
|
||||
|
||||
--connection master
|
||||
# Make sure Semi-Sync is active
|
||||
--let $status_var= Rpl_semi_sync_master_status
|
||||
--let $status_var_value= ON
|
||||
--source include/wait_for_status_var.inc
|
||||
|
||||
--sync_slave_with_master
|
||||
--connection master
|
||||
|
||||
--disable_cursor_protocol
|
||||
SELECT ID INTO @binlog_dump_tid
|
||||
FROM information_schema.PROCESSLIST WHERE COMMAND = 'Binlog Dump';
|
||||
--enable_cursor_protocol
|
||||
|
||||
--echo # Control State
|
||||
SELECT STATE FROM information_schema.PROCESSLIST WHERE ID = @binlog_dump_tid;
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_master_clients';
|
||||
|
||||
--echo # Disable Semi-Sync while the dump thread is still connected to its slave
|
||||
SET @@GLOBAL.rpl_semi_sync_master_enabled = 0;
|
||||
--let $status_var_value= OFF
|
||||
--source include/wait_for_status_var.inc
|
||||
|
||||
SELECT STATE FROM information_schema.PROCESSLIST WHERE ID = @binlog_dump_tid;
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_master_clients';
|
||||
|
||||
--echo # Disconnect the slave and wait until the master's dump thread is gone
|
||||
--connection slave
|
||||
STOP SLAVE;
|
||||
# Starting with MDEV-13073,
|
||||
# Semi-Sync STOP SLAVE also terminates its dump thread on the master.
|
||||
--connection master
|
||||
|
||||
# MDEV-36359: The disconnection would crash the master and leave the wait with
|
||||
# error 2013 'Lost connection to server during query'
|
||||
--let $wait_condition= SELECT COUNT(*)=0 FROM information_schema.PROCESSLIST WHERE ID = @binlog_dump_tid
|
||||
--source include/wait_condition.inc
|
||||
SHOW STATUS LIKE 'Rpl_semi_sync_master_clients';
|
||||
|
||||
--echo # Cleanup
|
||||
--eval SET @@GLOBAL.rpl_semi_sync_master_enabled= $orig_master_enabled
|
||||
--eval SET @@GLOBAL.rpl_semi_sync_master_wait_no_slave= $orig_wait_no_slave
|
||||
--connection slave
|
||||
--eval SET @@GLOBAL.rpl_semi_sync_slave_enabled= $orig_slave_enabled
|
||||
|
||||
--let $rpl_only_running_threads= 1
|
||||
--source include/rpl_end.inc
|
@ -47,14 +47,57 @@ next_not_cached_value minimum_value maximum_value start_value increment cache_si
|
||||
11 1 9223372036854775806 1 1 1000 0 0
|
||||
connection only_alter;
|
||||
select next value for s1;
|
||||
ERROR 42000: INSERT command denied to user 'only_alter'@'localhost' for table `mysqltest_1`.`s1`
|
||||
ERROR 42000: SELECT, INSERT command denied to user 'only_alter'@'localhost' for table `mysqltest_1`.`s1`
|
||||
alter sequence s1 restart= 11;
|
||||
select * from s1;
|
||||
ERROR 42000: SELECT command denied to user 'only_alter'@'localhost' for table `mysqltest_1`.`s1`
|
||||
connection default;
|
||||
drop database mysqltest_1;
|
||||
drop user 'normal'@'%';
|
||||
drop user 'read_only'@'%';
|
||||
drop user 'read_write'@'%';
|
||||
drop user 'alter'@'%';
|
||||
drop user 'only_alter'@'%';
|
||||
drop sequence s1;
|
||||
#
|
||||
# MDEV-36413 User without any privileges to a sequence can read from
|
||||
# it and modify it via column default
|
||||
#
|
||||
create sequence s1;
|
||||
create sequence s2;
|
||||
select * from s2;
|
||||
next_not_cached_value minimum_value maximum_value start_value increment cache_size cycle_option cycle_count
|
||||
1 1 9223372036854775806 1 1 1000 0 0
|
||||
create table t2 (a int not null default(nextval(s1)));
|
||||
insert into t2 values();
|
||||
create user u;
|
||||
grant create, insert, select, drop on mysqltest_1.t1 to u;
|
||||
grant insert, select on mysqltest_1.s1 to u;
|
||||
grant select on mysqltest_1.t2 to u;
|
||||
connect con1,localhost,u,,mysqltest_1;
|
||||
select nextval(s2);
|
||||
ERROR 42000: SELECT, INSERT command denied to user 'u'@'localhost' for table `mysqltest_1`.`s2`
|
||||
show create sequence s2;
|
||||
ERROR 42000: SHOW command denied to user 'u'@'localhost' for table `mysqltest_1`.`s2`
|
||||
create table t1 (a int not null default(nextval(s1)));
|
||||
drop table t1;
|
||||
create table t1 (a int not null default(nextval(s1))) select a from t2;
|
||||
insert into t1 values();
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
2
|
||||
drop table t1;
|
||||
create table t1 (a int not null default(nextval(s1))) select a from (select t2.a from t2,t2 as t3 where t2.a=t3.a) as t4;
|
||||
drop table t1;
|
||||
create table t1 (a int not null default(nextval(s2)));
|
||||
ERROR 42000: SELECT, INSERT command denied to user 'u'@'localhost' for table `mysqltest_1`.`s2`
|
||||
create table t1 (a int not null default(nextval(s1)),
|
||||
b int not null default(nextval(s2)));
|
||||
ERROR 42000: SELECT, INSERT command denied to user 'u'@'localhost' for table `mysqltest_1`.`s2`
|
||||
disconnect con1;
|
||||
connection default;
|
||||
drop user u;
|
||||
drop database mysqltest_1;
|
||||
#
|
||||
# End of 10.11 tests
|
||||
#
|
||||
|
@ -60,10 +60,58 @@ select * from s1;
|
||||
#
|
||||
|
||||
connection default;
|
||||
drop database mysqltest_1;
|
||||
drop user 'normal'@'%';
|
||||
drop user 'read_only'@'%';
|
||||
drop user 'read_write'@'%';
|
||||
drop user 'alter'@'%';
|
||||
drop user 'only_alter'@'%';
|
||||
drop sequence s1;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-36413 User without any privileges to a sequence can read from
|
||||
--echo # it and modify it via column default
|
||||
--echo #
|
||||
|
||||
create sequence s1;
|
||||
create sequence s2;
|
||||
select * from s2;
|
||||
create table t2 (a int not null default(nextval(s1)));
|
||||
insert into t2 values();
|
||||
|
||||
create user u;
|
||||
grant create, insert, select, drop on mysqltest_1.t1 to u;
|
||||
grant insert, select on mysqltest_1.s1 to u;
|
||||
grant select on mysqltest_1.t2 to u;
|
||||
|
||||
--connect(con1,localhost,u,,mysqltest_1)
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
select nextval(s2);
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
show create sequence s2;
|
||||
|
||||
create table t1 (a int not null default(nextval(s1)));
|
||||
drop table t1;
|
||||
create table t1 (a int not null default(nextval(s1))) select a from t2;
|
||||
insert into t1 values();
|
||||
select * from t1;
|
||||
drop table t1;
|
||||
create table t1 (a int not null default(nextval(s1))) select a from (select t2.a from t2,t2 as t3 where t2.a=t3.a) as t4;
|
||||
drop table t1;
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
create table t1 (a int not null default(nextval(s2)));
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
create table t1 (a int not null default(nextval(s1)),
|
||||
b int not null default(nextval(s2)));
|
||||
--disconnect con1
|
||||
--connection default
|
||||
drop user u;
|
||||
|
||||
#
|
||||
# Cleanup
|
||||
#
|
||||
|
||||
drop database mysqltest_1;
|
||||
|
||||
--echo #
|
||||
--echo # End of 10.11 tests
|
||||
--echo #
|
||||
|
@ -174,7 +174,7 @@ create sequence s_db.s2;
|
||||
drop sequence s_db.s2;
|
||||
connection m_normal_2;
|
||||
select next value for s_db.s1;
|
||||
ERROR 42000: INSERT command denied to user 'normal_2'@'localhost' for table `s_db`.`s1`
|
||||
ERROR 42000: SELECT, INSERT command denied to user 'normal_2'@'localhost' for table `s_db`.`s1`
|
||||
create sequence s_db.s2;
|
||||
ERROR 42000: CREATE command denied to user 'normal_2'@'localhost' for table `s_db`.`s2`
|
||||
connection m_normal_1;
|
||||
|
@ -285,7 +285,7 @@ create sequence s_db.s2;
|
||||
drop sequence s_db.s2;
|
||||
connection m_normal_2;
|
||||
select NEXT VALUE for s_db.s1;
|
||||
ERROR 42000: INSERT command denied to user 'normal_2'@'localhost' for table `s_db`.`s1`
|
||||
ERROR 42000: SELECT, INSERT command denied to user 'normal_2'@'localhost' for table `s_db`.`s1`
|
||||
create sequence s_db.s2;
|
||||
ERROR 42000: CREATE command denied to user 'normal_2'@'localhost' for table `s_db`.`s2`
|
||||
connection m_normal_1;
|
||||
|
@ -1,5 +1,4 @@
|
||||
--source include/have_sequence.inc
|
||||
--source include/have_innodb.inc
|
||||
|
||||
#
|
||||
# Test sequences with views
|
||||
|
@ -2855,6 +2855,18 @@ static void update_file_path(MYSQL_THD thd,
|
||||
{
|
||||
char *new_name= (*(char **) save) ? *(char **) save : empty_str;
|
||||
|
||||
if (strlen(new_name) + 4 > FN_REFLEN)
|
||||
{
|
||||
error_header();
|
||||
fprintf(stderr,
|
||||
"server_audit_file_path can't exceed %d characters.\n",
|
||||
FN_REFLEN - 4);
|
||||
fprintf(stderr, "Log filename remains unchanged '%s'.\n", file_path);
|
||||
CLIENT_ERROR(1, "server_audit_file_path can't exceed %d characters.",
|
||||
MYF(ME_WARNING), FN_REFLEN - 4);
|
||||
return;
|
||||
}
|
||||
|
||||
ADD_ATOMIC(internal_stop_logging, 1);
|
||||
error_header();
|
||||
fprintf(stderr, "Log file name was changed to '%s'.\n", new_name);
|
||||
|
@ -11075,8 +11075,8 @@ void dummy_error_processor(THD *thd, void *data)
|
||||
{}
|
||||
|
||||
/**
|
||||
Wrapper of hide_view_error call for Name_resolution_context error
|
||||
processor.
|
||||
Wrapper of replace_view_error_with_generic call for Name_resolution_context
|
||||
error processor.
|
||||
|
||||
@note
|
||||
hide view underlying tables details in error messages
|
||||
@ -11084,7 +11084,7 @@ void dummy_error_processor(THD *thd, void *data)
|
||||
|
||||
void view_error_processor(THD *thd, void *data)
|
||||
{
|
||||
((TABLE_LIST *)data)->hide_view_error(thd);
|
||||
((TABLE_LIST *)data)->replace_view_error_with_generic(thd);
|
||||
}
|
||||
|
||||
|
||||
|
@ -7068,6 +7068,16 @@ longlong Item_func_cursor_rowcount::val_int()
|
||||
/*****************************************************************************
|
||||
SEQUENCE functions
|
||||
*****************************************************************************/
|
||||
bool Item_func_nextval::check_access_and_fix_fields(THD *thd, Item **ref,
|
||||
privilege_t want_access)
|
||||
{
|
||||
table_list->sequence= false;
|
||||
bool error= check_single_table_access(thd, want_access, table_list, false);
|
||||
table_list->sequence= true;
|
||||
if (error && table_list->belong_to_view)
|
||||
table_list->replace_view_error_with_generic(thd);
|
||||
return error || Item_longlong_func::fix_fields(thd, ref);
|
||||
}
|
||||
|
||||
longlong Item_func_nextval::val_int()
|
||||
{
|
||||
|
@ -4234,6 +4234,7 @@ class Item_func_nextval :public Item_longlong_func
|
||||
protected:
|
||||
TABLE_LIST *table_list;
|
||||
TABLE *table;
|
||||
bool check_access_and_fix_fields(THD *, Item **ref, privilege_t);
|
||||
public:
|
||||
Item_func_nextval(THD *thd, TABLE_LIST *table_list_arg):
|
||||
Item_longlong_func(thd), table_list(table_list_arg) {}
|
||||
@ -4243,6 +4244,8 @@ public:
|
||||
static LEX_CSTRING name= {STRING_WITH_LEN("nextval") };
|
||||
return name;
|
||||
}
|
||||
bool fix_fields(THD *thd, Item **ref) override
|
||||
{ return check_access_and_fix_fields(thd, ref, INSERT_ACL | SELECT_ACL); }
|
||||
bool fix_length_and_dec(THD *thd) override
|
||||
{
|
||||
unsigned_flag= 0;
|
||||
@ -4284,6 +4287,8 @@ class Item_func_lastval :public Item_func_nextval
|
||||
public:
|
||||
Item_func_lastval(THD *thd, TABLE_LIST *table_list_arg):
|
||||
Item_func_nextval(thd, table_list_arg) {}
|
||||
bool fix_fields(THD *thd, Item **ref) override
|
||||
{ return check_access_and_fix_fields(thd, ref, SELECT_ACL); }
|
||||
longlong val_int() override;
|
||||
LEX_CSTRING func_name_cstring() const override
|
||||
{
|
||||
@ -4308,6 +4313,8 @@ public:
|
||||
: Item_func_nextval(thd, table_list_arg),
|
||||
nextval(nextval_arg), round(round_arg), is_used(is_used_arg)
|
||||
{}
|
||||
bool fix_fields(THD *thd, Item **ref) override
|
||||
{ return check_access_and_fix_fields(thd, ref, INSERT_ACL); }
|
||||
longlong val_int() override;
|
||||
LEX_CSTRING func_name_cstring() const override
|
||||
{
|
||||
|
@ -124,8 +124,8 @@ handle_queued_pos_update(THD *thd, rpl_parallel_thread::queued_event *qev)
|
||||
else if (cmp == 0
|
||||
&& rli->group_master_log_pos < qev->future_event_master_log_pos)
|
||||
rli->group_master_log_pos= qev->future_event_master_log_pos;
|
||||
mysql_mutex_unlock(&rli->data_lock);
|
||||
mysql_cond_broadcast(&rli->data_cond);
|
||||
mysql_mutex_unlock(&rli->data_lock);
|
||||
}
|
||||
|
||||
|
||||
|
@ -565,12 +565,14 @@ void Repl_semi_sync_master::remove_slave()
|
||||
{
|
||||
lock();
|
||||
DBUG_ASSERT(rpl_semi_sync_master_clients > 0);
|
||||
if (!(--rpl_semi_sync_master_clients) && !rpl_semi_sync_master_wait_no_slave)
|
||||
if (!(--rpl_semi_sync_master_clients) && !rpl_semi_sync_master_wait_no_slave
|
||||
&& get_master_enabled())
|
||||
{
|
||||
/*
|
||||
Signal transactions waiting in commit_trx() that they do not have to
|
||||
wait anymore.
|
||||
*/
|
||||
DBUG_ASSERT(m_active_tranxs);
|
||||
m_active_tranxs->clear_active_tranx_nodes(NULL, 0,
|
||||
signal_waiting_transaction);
|
||||
}
|
||||
|
@ -5980,9 +5980,9 @@ err_during_init:
|
||||
rli->relay_log.description_event_for_exec= 0;
|
||||
rli->reset_inuse_relaylog();
|
||||
/* Wake up master_pos_wait() */
|
||||
mysql_mutex_unlock(&rli->data_lock);
|
||||
DBUG_PRINT("info",("Signaling possibly waiting master_pos_wait() functions"));
|
||||
mysql_cond_broadcast(&rli->data_cond);
|
||||
mysql_mutex_unlock(&rli->data_lock);
|
||||
rli->ignore_log_space_limit= 0; /* don't need any lock */
|
||||
/* we die so won't remember charset - re-update them on next thread start */
|
||||
thd->system_thread_info.rpl_sql_info->cached_charset_invalidate();
|
||||
|
@ -8433,19 +8433,13 @@ bool check_grant(THD *thd, privilege_t want_access, TABLE_LIST *tables,
|
||||
|
||||
/*
|
||||
If sequence is used as part of NEXT VALUE, PREVIOUS VALUE or SELECT,
|
||||
we need to modify the requested access rights depending on how the
|
||||
sequence is used.
|
||||
the privilege will be checked in ::fix_fields().
|
||||
Direct SELECT of a sequence table doesn't set t_ref->sequence, so
|
||||
privileges will be checked normally, as for any table.
|
||||
*/
|
||||
if (t_ref->sequence &&
|
||||
!(want_access & ~(SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL)))
|
||||
{
|
||||
/*
|
||||
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_FIRST_WRITE) ?
|
||||
INSERT_ACL : SELECT_ACL);
|
||||
}
|
||||
continue;
|
||||
|
||||
const ACL_internal_table_access *access=
|
||||
get_cached_table_access(&t_ref->grant.m_internal,
|
||||
|
@ -8394,7 +8394,7 @@ bool setup_tables_and_check_access(THD *thd, Name_resolution_context *context,
|
||||
if (table_list->belong_to_view && !table_list->view &&
|
||||
check_single_table_access(thd, access, table_list, FALSE))
|
||||
{
|
||||
tables->hide_view_error(thd);
|
||||
tables->replace_view_error_with_generic(thd);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
access= want_access;
|
||||
|
@ -7296,18 +7296,9 @@ check_table_access(THD *thd, privilege_t requirements, TABLE_LIST *tables,
|
||||
DBUG_PRINT("info", ("derived: %d view: %d", table_ref->derived != 0,
|
||||
table_ref->view != 0));
|
||||
|
||||
if (table_ref->is_anonymous_derived_table())
|
||||
if (table_ref->is_anonymous_derived_table() || table_ref->sequence)
|
||||
continue;
|
||||
|
||||
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_FIRST_WRITE) ?
|
||||
INSERT_ACL : SELECT_ACL);
|
||||
}
|
||||
|
||||
if (check_access(thd, want_access, table_ref->get_db_name().str,
|
||||
&table_ref->grant.privilege,
|
||||
&table_ref->grant.m_internal,
|
||||
|
@ -618,7 +618,7 @@ bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables)
|
||||
if (table_list->belong_to_view &&
|
||||
check_single_table_access(thd, PRIV_LOCK_TABLES, table_list, FALSE))
|
||||
{
|
||||
table_list->hide_view_error(thd);
|
||||
table_list->replace_view_error_with_generic(thd);
|
||||
goto error_reset_bits;
|
||||
}
|
||||
if (table_list->is_view_or_derived())
|
||||
|
@ -1704,7 +1704,7 @@ static bool multi_update_check_table_access(THD *thd, TABLE_LIST *table,
|
||||
if (multi_update_check_table_access(thd, tbl, tables_for_update,
|
||||
&updated))
|
||||
{
|
||||
tbl->hide_view_error(thd);
|
||||
tbl->replace_view_error_with_generic(thd);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -341,7 +341,7 @@ bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view,
|
||||
{
|
||||
if (check_single_table_access(thd, SELECT_ACL, tbl, FALSE))
|
||||
{
|
||||
tbl->hide_view_error(thd);
|
||||
tbl->replace_view_error_with_generic(thd);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
@ -6360,9 +6360,9 @@ bool TABLE_LIST::prep_check_option(THD *thd, uint8 check_opt_type)
|
||||
@pre This method can be called only if there is an error.
|
||||
*/
|
||||
|
||||
void TABLE_LIST::hide_view_error(THD *thd)
|
||||
void TABLE_LIST::replace_view_error_with_generic(THD *thd)
|
||||
{
|
||||
if ((thd->killed && !thd->is_error())|| thd->get_internal_handler())
|
||||
if ((thd->killed && !thd->is_error()) || thd->get_internal_handler())
|
||||
return;
|
||||
/* Hide "Unknown column" or "Unknown function" error */
|
||||
DBUG_ASSERT(thd->is_error());
|
||||
|
@ -2830,7 +2830,7 @@ struct TABLE_LIST
|
||||
bool check_single_table(TABLE_LIST **table, table_map map,
|
||||
TABLE_LIST *view);
|
||||
bool set_insert_values(MEM_ROOT *mem_root);
|
||||
void hide_view_error(THD *thd);
|
||||
void replace_view_error_with_generic(THD *thd);
|
||||
TABLE_LIST *find_underlying_table(TABLE *table);
|
||||
TABLE_LIST *first_leaf_for_name_resolution();
|
||||
TABLE_LIST *last_leaf_for_name_resolution();
|
||||
|
@ -155,11 +155,6 @@ void close_thread_tables(THD* thd);
|
||||
#include "wsrep_sst.h"
|
||||
#endif /* WITH_WSREP */
|
||||
|
||||
#ifdef HAVE_URING
|
||||
/** The Linux kernel version if io_uring() is considered unsafe */
|
||||
const char *io_uring_may_be_unsafe;
|
||||
#endif
|
||||
|
||||
#define INSIDE_HA_INNOBASE_CC
|
||||
|
||||
#define EQ_CURRENT_THD(thd) ((thd) == current_thd)
|
||||
@ -4065,13 +4060,6 @@ static int innodb_init_params()
|
||||
cases, we ignore the setting of innodb_use_native_aio. */
|
||||
srv_use_native_aio= FALSE;
|
||||
#endif
|
||||
#ifdef HAVE_URING
|
||||
if (srv_use_native_aio && io_uring_may_be_unsafe)
|
||||
sql_print_warning("innodb_use_native_aio may cause "
|
||||
"hangs with this kernel %s; see "
|
||||
"https://jira.mariadb.org/browse/MDEV-26674",
|
||||
io_uring_may_be_unsafe);
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
switch (srv_file_flush_method) {
|
||||
@ -19666,37 +19654,10 @@ static MYSQL_SYSVAR_LONG(autoinc_lock_mode, innobase_autoinc_lock_mode,
|
||||
AUTOINC_OLD_STYLE_LOCKING, /* Minimum value */
|
||||
AUTOINC_NO_LOCKING, 0); /* Maximum value */
|
||||
|
||||
#ifdef HAVE_URING
|
||||
# include <sys/utsname.h>
|
||||
static utsname uname_for_io_uring;
|
||||
#else
|
||||
static
|
||||
#endif
|
||||
bool innodb_use_native_aio_default()
|
||||
{
|
||||
#ifdef HAVE_URING
|
||||
utsname &u= uname_for_io_uring;
|
||||
if (!uname(&u) && u.release[0] == '5' && u.release[1] == '.' &&
|
||||
u.release[2] == '1' && u.release[3] >= '1' && u.release[3] <= '5' &&
|
||||
u.release[4] == '.')
|
||||
{
|
||||
if (u.release[3] == '5') {
|
||||
const char *s= strstr(u.version, "5.15.");
|
||||
if (s || (s= strstr(u.release, "5.15.")))
|
||||
if ((s[5] >= '3' || s[6] >= '0'))
|
||||
return true; /* 5.15.3 and later should be fine */
|
||||
}
|
||||
io_uring_may_be_unsafe= u.release;
|
||||
return false; /* working around io_uring hangs (MDEV-26674) */
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
static MYSQL_SYSVAR_BOOL(use_native_aio, srv_use_native_aio,
|
||||
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
|
||||
"Use native AIO if supported on this platform.",
|
||||
NULL, NULL, innodb_use_native_aio_default());
|
||||
NULL, NULL, TRUE);
|
||||
|
||||
#ifdef HAVE_LIBNUMA
|
||||
static MYSQL_SYSVAR_BOOL(numa_interleave, srv_numa_interleave,
|
||||
|
@ -152,7 +152,9 @@ trx_undo_log_v_idx(
|
||||
ulint n_idx = 0;
|
||||
for (const auto& v_index : vcol->v_indexes) {
|
||||
n_idx++;
|
||||
/* FIXME: index->id is 64 bits! */
|
||||
if (uint32_t hi= uint32_t(v_index.index->id >> 32)) {
|
||||
size += 1 + mach_get_compressed_size(hi);
|
||||
}
|
||||
size += mach_get_compressed_size(uint32_t(v_index.index->id));
|
||||
size += mach_get_compressed_size(v_index.nth_field);
|
||||
}
|
||||
@ -179,10 +181,14 @@ trx_undo_log_v_idx(
|
||||
ptr += mach_write_compressed(ptr, n_idx);
|
||||
|
||||
for (const auto& v_index : vcol->v_indexes) {
|
||||
ptr += mach_write_compressed(
|
||||
/* FIXME: index->id is 64 bits! */
|
||||
ptr, uint32_t(v_index.index->id));
|
||||
|
||||
/* This is compatible with
|
||||
ptr += mach_u64_write_much_compressed(ptr, v_index.index-id)
|
||||
(the added "if" statement is fixing an old regression). */
|
||||
if (uint32_t hi= uint32_t(v_index.index->id >> 32)) {
|
||||
*ptr++ = 0xff;
|
||||
ptr += mach_write_compressed(ptr, hi);
|
||||
}
|
||||
ptr += mach_write_compressed(ptr, uint32_t(v_index.index->id));
|
||||
ptr += mach_write_compressed(ptr, v_index.nth_field);
|
||||
}
|
||||
|
||||
@ -221,7 +227,15 @@ trx_undo_read_v_idx_low(
|
||||
dict_index_t* clust_index = dict_table_get_first_index(table);
|
||||
|
||||
for (ulint i = 0; i < num_idx; i++) {
|
||||
index_id_t id = mach_read_next_compressed(&ptr);
|
||||
index_id_t id = 0;
|
||||
/* This is like mach_u64_read_much_compressed(),
|
||||
but advancing ptr to the next field. */
|
||||
if (*ptr == 0xff) {
|
||||
ptr++;
|
||||
id = mach_read_next_compressed(&ptr);
|
||||
id <<= 32;
|
||||
}
|
||||
id |= mach_read_next_compressed(&ptr);
|
||||
ulint pos = mach_read_next_compressed(&ptr);
|
||||
dict_index_t* index = dict_table_get_next_index(clust_index);
|
||||
|
||||
|
@ -4150,10 +4150,6 @@ int ha_spider::rnd_init(
|
||||
}
|
||||
}
|
||||
pushed_pos = NULL;
|
||||
/*
|
||||
if (wide_handler->external_lock_type == F_WRLCK)
|
||||
check_and_start_bulk_update(SPD_BU_START_BY_INDEX_OR_RND_INIT);
|
||||
*/
|
||||
rnd_scan_and_first = scan;
|
||||
if (
|
||||
scan &&
|
||||
|
@ -1039,8 +1039,11 @@ if ($USE_CHILD_GROUP2)
|
||||
}
|
||||
}
|
||||
--connection master_1
|
||||
# MDEV-36357
|
||||
--disable_view_protocol
|
||||
SELECT a.a, a.b, date_format(a.c, '%Y-%m-%d %H:%i:%s') FROM tb_l a WHERE
|
||||
EXISTS (SELECT * FROM ta_l b WHERE b.b = a.b) ORDER BY a.a;
|
||||
--enable_view_protocol
|
||||
if ($USE_CHILD_GROUP2)
|
||||
{
|
||||
if (!$OUTPUT_CHILD_GROUP2)
|
||||
|
@ -3039,6 +3039,10 @@ int spider_db_store_result(
|
||||
db_conn = conn->db_conn;
|
||||
if (!result_list->current)
|
||||
{
|
||||
/*
|
||||
Point ->current and ->bgs_current to ->first (create ->first
|
||||
if needed)
|
||||
*/
|
||||
if (!result_list->first)
|
||||
{
|
||||
if (!(result_list->first = (SPIDER_RESULT *)
|
||||
@ -3063,11 +3067,15 @@ int spider_db_store_result(
|
||||
}
|
||||
result_list->bgs_current = result_list->current;
|
||||
current = (SPIDER_RESULT*) result_list->current;
|
||||
} else {
|
||||
} else { /* result_list->current != NULL */
|
||||
if (
|
||||
result_list->bgs_phase > 0 ||
|
||||
result_list->quick_phase > 0
|
||||
) {
|
||||
/*
|
||||
Advance bgs_current to the next result. Create a new result
|
||||
if needed
|
||||
*/
|
||||
if (result_list->bgs_current == result_list->last)
|
||||
{
|
||||
if (!(result_list->last = (SPIDER_RESULT *)
|
||||
@ -3110,6 +3118,10 @@ int spider_db_store_result(
|
||||
}
|
||||
current = (SPIDER_RESULT*) result_list->bgs_current;
|
||||
} else {
|
||||
/*
|
||||
Advance current to the next result. Create a new result if
|
||||
needed
|
||||
*/
|
||||
if (result_list->current == result_list->last)
|
||||
{
|
||||
if (!(result_list->last = (SPIDER_RESULT *)
|
||||
|
@ -1688,7 +1688,7 @@ typedef struct st_spider_result
|
||||
st_spider_result *next;
|
||||
SPIDER_POSITION *first_position; /* for quick mode */
|
||||
int pos_page_size; /* for quick mode */
|
||||
longlong record_num;
|
||||
longlong record_num; /* number of rows */
|
||||
bool finish_flg;
|
||||
bool use_position;
|
||||
bool first_pos_use_position;
|
||||
@ -1731,7 +1731,7 @@ typedef struct st_spider_result_list
|
||||
bool sorted;
|
||||
bool desc_flg;
|
||||
longlong current_row_num;
|
||||
longlong record_num;
|
||||
longlong record_num; /* number of rows */
|
||||
bool finish_flg;
|
||||
longlong limit_num;
|
||||
longlong internal_offset;
|
||||
|
@ -34,9 +34,9 @@ class aio_uring final : public tpool::aio
|
||||
public:
|
||||
aio_uring(tpool::thread_pool *tpool, int max_aio) : tpool_(tpool)
|
||||
{
|
||||
if (io_uring_queue_init(max_aio, &uring_, 0) != 0)
|
||||
if (const auto e= io_uring_queue_init(max_aio, &uring_, 0))
|
||||
{
|
||||
switch (const auto e= errno) {
|
||||
switch (-e) {
|
||||
case ENOMEM:
|
||||
my_printf_error(ER_UNKNOWN_ERROR,
|
||||
"io_uring_queue_init() failed with ENOMEM:"
|
||||
@ -57,6 +57,12 @@ public:
|
||||
"(newer than 5.1 required)",
|
||||
ME_ERROR_LOG | ME_WARNING);
|
||||
break;
|
||||
case EPERM:
|
||||
my_printf_error(ER_UNKNOWN_ERROR,
|
||||
"io_uring_queue_init() failed with EPERM:"
|
||||
" sysctl kernel.io_uring_disabled has the value 2, or 1 and the user of the process is not a member of sysctl kernel.io_uring_group. (see man 2 io_uring_setup).",
|
||||
ME_ERROR_LOG | ME_WARNING);
|
||||
break;
|
||||
default:
|
||||
my_printf_error(ER_UNKNOWN_ERROR,
|
||||
"io_uring_queue_init() failed with errno %d",
|
||||
|
@ -218,7 +218,6 @@ class thread_pool_generic : public thread_pool
|
||||
|
||||
/** Overall number of enqueues*/
|
||||
unsigned long long m_tasks_enqueued;
|
||||
unsigned long long m_group_enqueued;
|
||||
/** Overall number of dequeued tasks. */
|
||||
unsigned long long m_tasks_dequeued;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user