mirror of
https://github.com/zebrajr/server.git
synced 2025-12-06 12:20:40 +01:00
MDEV-23639 Auto-create does not work under LOCK TABLES or inside triggers
Don't do tdc_remove_table() for OT_ADD_HISTORY_PARTITION because it is not possible in locked tables mode. LTM_LOCK_TABLES mode (and LTM_PRELOCKED_UNDER_LOCK_TABLES) works out of the box as fast_alter_partition_table() can reopen tables via locked_tables_list. In LTM_PRELOCKED we reopen and relock table manually.
This commit is contained in:
parent
404428733b
commit
41a170c60a
|
|
@ -1506,16 +1506,14 @@ affected rows: 1
|
|||
info: Rows matched: 1 Changed: 1 Inserted: 1 Warnings: 0
|
||||
update t1 set x= x + 1;
|
||||
affected rows: 1
|
||||
info: Rows matched: 1 Changed: 1 Inserted: 1 Warnings: 1
|
||||
Warnings:
|
||||
Warning 4114 Versioned table `test`.`t1`: last HISTORY partition (`p1`) is out of LIMIT, need more HISTORY partitions
|
||||
info: Rows matched: 1 Changed: 1 Inserted: 1 Warnings: 0
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`x` int(11) DEFAULT NULL
|
||||
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
|
||||
PARTITION BY SYSTEM_TIME LIMIT 1 AUTO
|
||||
PARTITIONS 3
|
||||
PARTITIONS 4
|
||||
affected rows: 1
|
||||
unlock tables;
|
||||
affected rows: 0
|
||||
|
|
@ -1525,7 +1523,7 @@ t1 CREATE TABLE `t1` (
|
|||
`x` int(11) DEFAULT NULL
|
||||
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
|
||||
PARTITION BY SYSTEM_TIME LIMIT 1 AUTO
|
||||
PARTITIONS 3
|
||||
PARTITIONS 4
|
||||
affected rows: 1
|
||||
# Overflow prevention under LOCK TABLES
|
||||
create or replace table t1 (x int)
|
||||
|
|
@ -2115,3 +2113,167 @@ t CREATE TABLE `t` (
|
|||
PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 02:00:00' AUTO
|
||||
PARTITIONS 6
|
||||
drop table t;
|
||||
#
|
||||
# MDEV-23639 Auto-create does not work under LOCK TABLES or inside triggers
|
||||
#
|
||||
set timestamp= unix_timestamp('2000-01-01 00:00:00');
|
||||
create or replace table t1 (x int) with system versioning
|
||||
partition by system_time interval 1 hour auto
|
||||
partitions 3;
|
||||
create table t2 (x int);
|
||||
create table t3 (x int);
|
||||
insert into t3 values (3);
|
||||
create trigger tr after insert on t2 for each row update t1 set x= x + 11;
|
||||
create or replace procedure sp() update t1 set x= x + 5;
|
||||
create or replace procedure sp2() insert into t2 values (5);
|
||||
prepare ps from 'update t1 set x= x + 6';
|
||||
prepare ps2 from 'insert into t2 values (6)';
|
||||
insert into t1 values (1);
|
||||
set timestamp= unix_timestamp('2000-01-01 02:00:00');
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`x` int(11) DEFAULT NULL
|
||||
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
|
||||
PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
|
||||
PARTITIONS 3
|
||||
insert into t2 values (2);
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`x` int(11) DEFAULT NULL
|
||||
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
|
||||
PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
|
||||
PARTITIONS 4
|
||||
set timestamp= unix_timestamp('2000-01-01 03:00:00');
|
||||
call sp;
|
||||
call sp;
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`x` int(11) DEFAULT NULL
|
||||
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
|
||||
PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
|
||||
PARTITIONS 5
|
||||
set timestamp= unix_timestamp('2000-01-01 04:00:00');
|
||||
call sp2;
|
||||
call sp2;
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`x` int(11) DEFAULT NULL
|
||||
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
|
||||
PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
|
||||
PARTITIONS 6
|
||||
set timestamp= unix_timestamp('2000-01-01 05:00:00');
|
||||
execute ps;
|
||||
execute ps;
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`x` int(11) DEFAULT NULL
|
||||
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
|
||||
PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
|
||||
PARTITIONS 7
|
||||
set timestamp= unix_timestamp('2000-01-01 06:00:00');
|
||||
execute ps2;
|
||||
execute ps2;
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`x` int(11) DEFAULT NULL
|
||||
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
|
||||
PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
|
||||
PARTITIONS 8
|
||||
set timestamp= unix_timestamp('2000-01-01 08:00:00');
|
||||
lock tables t1 write, t2 write;
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`x` int(11) DEFAULT NULL
|
||||
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
|
||||
PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
|
||||
PARTITIONS 10
|
||||
set timestamp= unix_timestamp('2000-01-01 09:00:00');
|
||||
update t1 set x= x + 1;
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`x` int(11) DEFAULT NULL
|
||||
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
|
||||
PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
|
||||
PARTITIONS 11
|
||||
set timestamp= unix_timestamp('2000-01-01 10:00:00');
|
||||
update t1 set x= x + 2;
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`x` int(11) DEFAULT NULL
|
||||
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
|
||||
PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
|
||||
PARTITIONS 12
|
||||
update t2 set x= x + 1;
|
||||
set timestamp= unix_timestamp('2000-01-01 11:00:00');
|
||||
insert into t2 values (4);
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`x` int(11) DEFAULT NULL
|
||||
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
|
||||
PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
|
||||
PARTITIONS 13
|
||||
update t3 set x= x + 1;
|
||||
ERROR HY000: Table 't3' was not locked with LOCK TABLES
|
||||
set timestamp= unix_timestamp('2000-01-01 12:00:00');
|
||||
call sp;
|
||||
call sp;
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`x` int(11) DEFAULT NULL
|
||||
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
|
||||
PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
|
||||
PARTITIONS 14
|
||||
set timestamp= unix_timestamp('2000-01-01 13:00:00');
|
||||
call sp2;
|
||||
call sp2;
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`x` int(11) DEFAULT NULL
|
||||
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
|
||||
PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
|
||||
PARTITIONS 15
|
||||
set timestamp= unix_timestamp('2000-01-01 14:00:00');
|
||||
execute ps;
|
||||
execute ps;
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`x` int(11) DEFAULT NULL
|
||||
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
|
||||
PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
|
||||
PARTITIONS 16
|
||||
set timestamp= unix_timestamp('2000-01-01 15:00:00');
|
||||
execute ps2;
|
||||
execute ps2;
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`x` int(11) DEFAULT NULL
|
||||
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
|
||||
PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
|
||||
PARTITIONS 17
|
||||
unlock tables;
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`x` int(11) DEFAULT NULL
|
||||
) ENGINE=DEFAULT_ENGINE DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
|
||||
PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR STARTS TIMESTAMP'2000-01-01 00:00:00' AUTO
|
||||
PARTITIONS 17
|
||||
drop tables t1, t2, t3;
|
||||
drop procedure sp;
|
||||
drop procedure sp2;
|
||||
drop prepare ps;
|
||||
drop prepare ps2;
|
||||
|
|
|
|||
|
|
@ -1552,4 +1552,97 @@ show create table t;
|
|||
# Cleanup
|
||||
drop table t;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-23639 Auto-create does not work under LOCK TABLES or inside triggers
|
||||
--echo #
|
||||
set timestamp= unix_timestamp('2000-01-01 00:00:00');
|
||||
create or replace table t1 (x int) with system versioning
|
||||
partition by system_time interval 1 hour auto
|
||||
partitions 3;
|
||||
|
||||
create table t2 (x int);
|
||||
create table t3 (x int);
|
||||
insert into t3 values (3);
|
||||
|
||||
create trigger tr after insert on t2 for each row update t1 set x= x + 11;
|
||||
create or replace procedure sp() update t1 set x= x + 5;
|
||||
create or replace procedure sp2() insert into t2 values (5);
|
||||
prepare ps from 'update t1 set x= x + 6';
|
||||
prepare ps2 from 'insert into t2 values (6)';
|
||||
|
||||
insert into t1 values (1);
|
||||
set timestamp= unix_timestamp('2000-01-01 02:00:00');
|
||||
--replace_result $default_engine DEFAULT_ENGINE
|
||||
show create table t1;
|
||||
insert into t2 values (2);
|
||||
--replace_result $default_engine DEFAULT_ENGINE
|
||||
show create table t1;
|
||||
|
||||
set timestamp= unix_timestamp('2000-01-01 03:00:00');
|
||||
call sp; call sp;
|
||||
--replace_result $default_engine DEFAULT_ENGINE
|
||||
show create table t1;
|
||||
set timestamp= unix_timestamp('2000-01-01 04:00:00');
|
||||
call sp2; call sp2;
|
||||
--replace_result $default_engine DEFAULT_ENGINE
|
||||
show create table t1;
|
||||
|
||||
set timestamp= unix_timestamp('2000-01-01 05:00:00');
|
||||
execute ps; execute ps;
|
||||
--replace_result $default_engine DEFAULT_ENGINE
|
||||
show create table t1;
|
||||
set timestamp= unix_timestamp('2000-01-01 06:00:00');
|
||||
execute ps2; execute ps2;
|
||||
--replace_result $default_engine DEFAULT_ENGINE
|
||||
show create table t1;
|
||||
|
||||
set timestamp= unix_timestamp('2000-01-01 08:00:00');
|
||||
lock tables t1 write, t2 write;
|
||||
--replace_result $default_engine DEFAULT_ENGINE
|
||||
show create table t1;
|
||||
set timestamp= unix_timestamp('2000-01-01 09:00:00');
|
||||
update t1 set x= x + 1;
|
||||
--replace_result $default_engine DEFAULT_ENGINE
|
||||
show create table t1;
|
||||
set timestamp= unix_timestamp('2000-01-01 10:00:00');
|
||||
update t1 set x= x + 2;
|
||||
--replace_result $default_engine DEFAULT_ENGINE
|
||||
show create table t1;
|
||||
update t2 set x= x + 1;
|
||||
set timestamp= unix_timestamp('2000-01-01 11:00:00');
|
||||
insert into t2 values (4);
|
||||
--replace_result $default_engine DEFAULT_ENGINE
|
||||
show create table t1;
|
||||
--error ER_TABLE_NOT_LOCKED
|
||||
update t3 set x= x + 1;
|
||||
|
||||
set timestamp= unix_timestamp('2000-01-01 12:00:00');
|
||||
call sp; call sp;
|
||||
--replace_result $default_engine DEFAULT_ENGINE
|
||||
show create table t1;
|
||||
set timestamp= unix_timestamp('2000-01-01 13:00:00');
|
||||
call sp2; call sp2;
|
||||
--replace_result $default_engine DEFAULT_ENGINE
|
||||
show create table t1;
|
||||
|
||||
set timestamp= unix_timestamp('2000-01-01 14:00:00');
|
||||
execute ps; execute ps;
|
||||
--replace_result $default_engine DEFAULT_ENGINE
|
||||
show create table t1;
|
||||
set timestamp= unix_timestamp('2000-01-01 15:00:00');
|
||||
execute ps2; execute ps2;
|
||||
--replace_result $default_engine DEFAULT_ENGINE
|
||||
show create table t1;
|
||||
|
||||
unlock tables;
|
||||
--replace_result $default_engine DEFAULT_ENGINE
|
||||
show create table t1;
|
||||
|
||||
# Cleanup
|
||||
drop tables t1, t2, t3;
|
||||
drop procedure sp;
|
||||
drop procedure sp2;
|
||||
drop prepare ps;
|
||||
drop prepare ps2;
|
||||
|
||||
--source suite/versioning/common_finish.inc
|
||||
|
|
|
|||
32
sql/lock.cc
32
sql/lock.cc
|
|
@ -654,7 +654,7 @@ bool mysql_lock_abort_for_thread(THD *thd, TABLE *table)
|
|||
a and b are freed with my_free()
|
||||
*/
|
||||
|
||||
MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
|
||||
MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a, MYSQL_LOCK *b, THD *thd)
|
||||
{
|
||||
MYSQL_LOCK *sql_lock;
|
||||
TABLE **table, **end_table;
|
||||
|
|
@ -662,16 +662,28 @@ MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
|
|||
DBUG_PRINT("enter", ("a->lock_count: %u b->lock_count: %u",
|
||||
a->lock_count, b->lock_count));
|
||||
|
||||
if (!(sql_lock= (MYSQL_LOCK*)
|
||||
my_malloc(key_memory_MYSQL_LOCK, sizeof(*sql_lock) +
|
||||
sizeof(THR_LOCK_DATA*)*((a->lock_count+b->lock_count)*2) +
|
||||
sizeof(TABLE*)*(a->table_count+b->table_count),MYF(MY_WME))))
|
||||
DBUG_RETURN(0); // Fatal error
|
||||
const size_t lock_size= sizeof(*sql_lock) +
|
||||
sizeof(THR_LOCK_DATA *) * ((a->lock_count + b->lock_count) * 2) +
|
||||
sizeof(TABLE *) * (a->table_count + b->table_count);
|
||||
if (thd)
|
||||
{
|
||||
sql_lock= (MYSQL_LOCK *) thd->alloc(lock_size);
|
||||
if (!sql_lock)
|
||||
DBUG_RETURN(0);
|
||||
sql_lock->flags= GET_LOCK_ON_THD;
|
||||
}
|
||||
else
|
||||
{
|
||||
sql_lock= (MYSQL_LOCK *)
|
||||
my_malloc(key_memory_MYSQL_LOCK, lock_size, MYF(MY_WME));
|
||||
if (!sql_lock)
|
||||
DBUG_RETURN(0);
|
||||
sql_lock->flags= 0;
|
||||
}
|
||||
sql_lock->lock_count=a->lock_count+b->lock_count;
|
||||
sql_lock->table_count=a->table_count+b->table_count;
|
||||
sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
|
||||
sql_lock->table=(TABLE**) (sql_lock->locks+sql_lock->lock_count*2);
|
||||
sql_lock->flags= 0;
|
||||
memcpy(sql_lock->locks,a->locks,a->lock_count*sizeof(*a->locks));
|
||||
memcpy(sql_lock->locks+a->lock_count,b->locks,
|
||||
b->lock_count*sizeof(*b->locks));
|
||||
|
|
@ -705,8 +717,10 @@ MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
|
|||
a->lock_count, b->lock_count);
|
||||
|
||||
/* Delete old, not needed locks */
|
||||
my_free(a);
|
||||
my_free(b);
|
||||
if (!(a->flags & GET_LOCK_ON_THD))
|
||||
my_free(a);
|
||||
if (!(b->flags & GET_LOCK_ON_THD))
|
||||
my_free(b);
|
||||
DBUG_RETURN(sql_lock);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ int mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock);
|
|||
int mysql_unlock_some_tables(THD *thd, TABLE **table,uint count, uint flag);
|
||||
int mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table);
|
||||
bool mysql_lock_abort_for_thread(THD *thd, TABLE *table);
|
||||
MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b);
|
||||
MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a, MYSQL_LOCK *b, THD *thd= NULL);
|
||||
/* Lock based on name */
|
||||
bool lock_schema_name(THD *thd, const char *db);
|
||||
/* Lock based on stored routine name */
|
||||
|
|
|
|||
|
|
@ -910,15 +910,6 @@ bool partition_info::vers_set_hist_part(THD *thd, uint *create_count)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
When hist_part is almost full LOCK TABLES may overflow the partition as we
|
||||
can't add new partitions under LOCK TABLES. Reserve one more for this case.
|
||||
*/
|
||||
if (auto_hist && *create_count == 0 &&
|
||||
thd->lex->sql_command == SQLCOM_LOCK_TABLES &&
|
||||
vers_info->hist_part->id + 1 == vers_info->now_part->id)
|
||||
++*create_count;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
281
sql/sql_base.cc
281
sql/sql_base.cc
|
|
@ -63,6 +63,9 @@
|
|||
#include "wsrep_trans_observer.h"
|
||||
#endif /* WITH_WSREP */
|
||||
|
||||
static bool
|
||||
open_tables_check_upgradable_mdl(THD *thd, TABLE_LIST *tables_start,
|
||||
TABLE_LIST *tables_end, uint flags);
|
||||
|
||||
bool
|
||||
No_such_table_error_handler::handle_condition(THD *,
|
||||
|
|
@ -1622,26 +1625,48 @@ bool is_locked_view(THD *thd, TABLE_LIST *t)
|
|||
}
|
||||
|
||||
|
||||
bool TABLE::vers_need_hist_part(const THD *thd, const TABLE_LIST *table_list) const
|
||||
{
|
||||
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||
if (part_info && part_info->part_type == VERSIONING_PARTITION &&
|
||||
!table_list->vers_conditions.delete_history &&
|
||||
!thd->stmt_arena->is_stmt_prepare() &&
|
||||
table_list->lock_type >= TL_WRITE_ALLOW_WRITE &&
|
||||
table_list->mdl_request.type >= MDL_SHARED_WRITE &&
|
||||
table_list->mdl_request.type < MDL_EXCLUSIVE)
|
||||
/**
|
||||
Switch part_info->hist_part and request partition creation if needed.
|
||||
|
||||
@retval true Error or partition creation was requested.
|
||||
@retval false No error
|
||||
*/
|
||||
bool TABLE::vers_switch_partition(THD *thd, TABLE_LIST *table_list,
|
||||
Open_table_context *ot_ctx)
|
||||
{
|
||||
if (!part_info || part_info->part_type != VERSIONING_PARTITION ||
|
||||
table_list->vers_conditions.delete_history ||
|
||||
thd->stmt_arena->is_stmt_prepare() ||
|
||||
table_list->lock_type < TL_WRITE_ALLOW_WRITE ||
|
||||
table_list->mdl_request.type < MDL_SHARED_WRITE ||
|
||||
table_list->mdl_request.type == MDL_EXCLUSIVE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
NOTE: we need this condition of prelocking_placeholder because we cannot do
|
||||
auto-create after the transaction is started. Auto-create does
|
||||
close_tables_for_reopen() and that is not possible under started transaction.
|
||||
Also the transaction may not be cancelled at that moment: f.ex. trigger
|
||||
after insert is run when some data is already written.
|
||||
|
||||
We must do auto-creation for PRELOCK_ROUTINE tables at the initial
|
||||
open_tables() no matter what initiating sql_command is.
|
||||
*/
|
||||
if (table_list->prelocking_placeholder != TABLE_LIST::PRELOCK_ROUTINE)
|
||||
{
|
||||
switch (thd->lex->sql_command)
|
||||
{
|
||||
case SQLCOM_INSERT:
|
||||
if (thd->lex->duplicates != DUP_UPDATE)
|
||||
break;
|
||||
return true;
|
||||
return false;
|
||||
break;
|
||||
case SQLCOM_LOAD:
|
||||
if (thd->lex->duplicates != DUP_REPLACE)
|
||||
break;
|
||||
return true;
|
||||
return false;
|
||||
break;
|
||||
case SQLCOM_LOCK_TABLES:
|
||||
case SQLCOM_DELETE:
|
||||
case SQLCOM_UPDATE:
|
||||
|
|
@ -1649,35 +1674,87 @@ bool TABLE::vers_need_hist_part(const THD *thd, const TABLE_LIST *table_list) co
|
|||
case SQLCOM_REPLACE_SELECT:
|
||||
case SQLCOM_DELETE_MULTI:
|
||||
case SQLCOM_UPDATE_MULTI:
|
||||
return true;
|
||||
default:;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
TODO: make row events set thd->lex->sql_command appropriately.
|
||||
default:
|
||||
/*
|
||||
TODO: make row events set thd->lex->sql_command appropriately.
|
||||
|
||||
Sergei Golubchik: f.ex. currently row events increment
|
||||
thd->status_var.com_stat[] each event for its own SQLCOM_xxx, it won't be
|
||||
needed if they'll just set thd->lex->sql_command.
|
||||
*/
|
||||
if (thd->rgi_slave && thd->rgi_slave->current_event &&
|
||||
thd->lex->sql_command == SQLCOM_END)
|
||||
{
|
||||
switch (thd->rgi_slave->current_event->get_type_code())
|
||||
{
|
||||
case UPDATE_ROWS_EVENT:
|
||||
case UPDATE_ROWS_EVENT_V1:
|
||||
case DELETE_ROWS_EVENT:
|
||||
case DELETE_ROWS_EVENT_V1:
|
||||
return true;
|
||||
default:;
|
||||
Sergei Golubchik: f.ex. currently row events increment
|
||||
thd->status_var.com_stat[] each event for its own SQLCOM_xxx, it won't be
|
||||
needed if they'll just set thd->lex->sql_command.
|
||||
*/
|
||||
if (thd->rgi_slave && thd->rgi_slave->current_event &&
|
||||
thd->lex->sql_command == SQLCOM_END)
|
||||
{
|
||||
switch (thd->rgi_slave->current_event->get_type_code())
|
||||
{
|
||||
case UPDATE_ROWS_EVENT:
|
||||
case UPDATE_ROWS_EVENT_V1:
|
||||
case DELETE_ROWS_EVENT:
|
||||
case DELETE_ROWS_EVENT_V1:
|
||||
break;
|
||||
default:;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TABLE *table= this;
|
||||
|
||||
/*
|
||||
NOTE: The semantics of vers_set_hist_part() is double: even when we
|
||||
don't need auto-create, we need to update part_info->hist_part.
|
||||
*/
|
||||
uint *create_count= table_list->vers_skip_create ?
|
||||
NULL : &ot_ctx->vers_create_count;
|
||||
table_list->vers_skip_create= true;
|
||||
if (table->part_info->vers_set_hist_part(thd, create_count))
|
||||
{
|
||||
MYSQL_UNBIND_TABLE(table->file);
|
||||
tc_release_table(table);
|
||||
return true;
|
||||
}
|
||||
if (ot_ctx->vers_create_count)
|
||||
{
|
||||
Open_table_context::enum_open_table_action action;
|
||||
TABLE_LIST *table_arg;
|
||||
mysql_mutex_lock(&table->s->LOCK_share);
|
||||
if (!table->s->vers_skip_auto_create)
|
||||
{
|
||||
table->s->vers_skip_auto_create= true;
|
||||
action= Open_table_context::OT_ADD_HISTORY_PARTITION;
|
||||
table_arg= table_list;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
NOTE: this may repeat multiple times until creating thread acquires
|
||||
MDL_EXCLUSIVE. Since auto-creation is rare operation this is acceptable.
|
||||
We could suspend this thread on cond-var but we must first exit
|
||||
MDL_SHARED_WRITE first and we cannot store cond-var into TABLE_SHARE
|
||||
because it is already released and there is no guarantee that it will
|
||||
be same instance if we acquire it again.
|
||||
*/
|
||||
table_list->vers_skip_create= false;
|
||||
ot_ctx->vers_create_count= 0;
|
||||
action= Open_table_context::OT_REOPEN_TABLES;
|
||||
table_arg= NULL;
|
||||
}
|
||||
mysql_mutex_unlock(&table->s->LOCK_share);
|
||||
if (!thd->locked_tables_mode)
|
||||
{
|
||||
MYSQL_UNBIND_TABLE(table->file);
|
||||
tc_release_table(table);
|
||||
}
|
||||
ot_ctx->request_backoff_action(action, table_arg);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif /* WITH_PARTITION_STORAGE_ENGINE */
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -1832,14 +1909,8 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
|
|||
DBUG_PRINT("info",("Using locked table"));
|
||||
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||
part_names_error= set_partitions_as_used(table_list, table);
|
||||
if (table->vers_need_hist_part(thd, table_list))
|
||||
{
|
||||
/*
|
||||
New partitions are not auto-created under LOCK TABLES (TODO: fix it)
|
||||
but rotation can still happen.
|
||||
*/
|
||||
(void) table->part_info->vers_set_hist_part(thd, NULL);
|
||||
}
|
||||
if (table->vers_switch_partition(thd, table_list, ot_ctx))
|
||||
DBUG_RETURN(true);
|
||||
#endif
|
||||
goto reset;
|
||||
}
|
||||
|
|
@ -2095,54 +2166,10 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
|
|||
tc_add_table(thd, table);
|
||||
}
|
||||
|
||||
if (table->vers_need_hist_part(thd, table_list))
|
||||
{
|
||||
/*
|
||||
NOTE: The semantics of vers_set_hist_part() is double: even when we
|
||||
don't need auto-create, we need to update part_info->hist_part.
|
||||
*/
|
||||
uint *create_count= table_list->vers_skip_create ?
|
||||
NULL : &ot_ctx->vers_create_count;
|
||||
table_list->vers_skip_create= true;
|
||||
if (table->part_info->vers_set_hist_part(thd, create_count))
|
||||
{
|
||||
MYSQL_UNBIND_TABLE(table->file);
|
||||
tc_release_table(table);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
if (ot_ctx->vers_create_count)
|
||||
{
|
||||
Open_table_context::enum_open_table_action action;
|
||||
TABLE_LIST *table_arg;
|
||||
mysql_mutex_lock(&table->s->LOCK_share);
|
||||
if (!table->s->vers_skip_auto_create)
|
||||
{
|
||||
table->s->vers_skip_auto_create= true;
|
||||
action= Open_table_context::OT_ADD_HISTORY_PARTITION;
|
||||
table_arg= table_list;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
NOTE: this may repeat multiple times until creating thread acquires
|
||||
MDL_EXCLUSIVE. Since auto-creation is rare operation this is acceptable.
|
||||
We could suspend this thread on cond-var but we must first exit
|
||||
MDL_SHARED_WRITE first and we cannot store cond-var into TABLE_SHARE
|
||||
because it is already released and there is no guarantee that it will
|
||||
be same instance if we acquire it again.
|
||||
*/
|
||||
table_list->vers_skip_create= false;
|
||||
ot_ctx->vers_create_count= 0;
|
||||
action= Open_table_context::OT_REOPEN_TABLES;
|
||||
table_arg= NULL;
|
||||
}
|
||||
mysql_mutex_unlock(&table->s->LOCK_share);
|
||||
MYSQL_UNBIND_TABLE(table->file);
|
||||
tc_release_table(table);
|
||||
ot_ctx->request_backoff_action(action, table_arg);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
}
|
||||
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||
if (table->vers_switch_partition(thd, table_list, ot_ctx))
|
||||
DBUG_RETURN(true);
|
||||
#endif /* WITH_PARTITION_STORAGE_ENGINE */
|
||||
|
||||
if (!(flags & MYSQL_OPEN_HAS_MDL_LOCK) &&
|
||||
table->s->table_category < TABLE_CATEGORY_INFORMATION)
|
||||
|
|
@ -3291,8 +3318,14 @@ Open_table_context::recover_from_failed_open()
|
|||
case OT_DISCOVER:
|
||||
case OT_REPAIR:
|
||||
case OT_ADD_HISTORY_PARTITION:
|
||||
result= lock_table_names(m_thd, m_thd->lex->create_info, m_failed_table,
|
||||
NULL, get_timeout(), 0);
|
||||
if (!m_thd->locked_tables_mode)
|
||||
result= lock_table_names(m_thd, m_thd->lex->create_info, m_failed_table,
|
||||
NULL, get_timeout(), 0);
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(!result);
|
||||
DBUG_ASSERT(m_action == OT_ADD_HISTORY_PARTITION);
|
||||
}
|
||||
/*
|
||||
We are now under MDL_EXCLUSIVE mode. Other threads have no table share
|
||||
acquired: they are blocked either at open_table_get_mdl_lock() in
|
||||
|
|
@ -3320,8 +3353,13 @@ Open_table_context::recover_from_failed_open()
|
|||
break;
|
||||
}
|
||||
|
||||
tdc_remove_table(m_thd, m_failed_table->db.str,
|
||||
m_failed_table->table_name.str);
|
||||
/*
|
||||
We don't need to remove share under OT_ADD_HISTORY_PARTITION.
|
||||
Moreover fast_alter_partition_table() works with TABLE instance.
|
||||
*/
|
||||
if (m_action != OT_ADD_HISTORY_PARTITION)
|
||||
tdc_remove_table(m_thd, m_failed_table->db.str,
|
||||
m_failed_table->table_name.str);
|
||||
|
||||
switch (m_action)
|
||||
{
|
||||
|
|
@ -3361,12 +3399,56 @@ Open_table_context::recover_from_failed_open()
|
|||
}
|
||||
|
||||
DBUG_ASSERT(vers_create_count);
|
||||
TABLE_LIST *tl= m_failed_table;
|
||||
result= vers_create_partitions(m_thd, tl, vers_create_count);
|
||||
result= vers_create_partitions(m_thd, m_failed_table, vers_create_count);
|
||||
vers_create_count= 0;
|
||||
if (!m_thd->transaction->stmt.is_empty())
|
||||
trans_commit_stmt(m_thd);
|
||||
close_tables_for_reopen(m_thd, &tl, start_of_statement_svp());
|
||||
vers_create_count= 0;
|
||||
DBUG_ASSERT(!result ||
|
||||
!m_thd->locked_tables_mode ||
|
||||
m_thd->lock->lock_count);
|
||||
if (result)
|
||||
break;
|
||||
if (!m_thd->locked_tables_mode)
|
||||
{
|
||||
/*
|
||||
alter_partition_lock_handling() does mysql_lock_remove() but
|
||||
does not clear thd->lock completely.
|
||||
*/
|
||||
DBUG_ASSERT(m_thd->lock->lock_count == 0);
|
||||
if (!(m_thd->lock->flags & GET_LOCK_ON_THD))
|
||||
my_free(m_thd->lock);
|
||||
m_thd->lock= NULL;
|
||||
}
|
||||
else if (m_thd->locked_tables_mode == LTM_PRELOCKED)
|
||||
{
|
||||
MYSQL_LOCK *lock;
|
||||
MYSQL_LOCK *merged_lock;
|
||||
|
||||
/*
|
||||
In LTM_LOCK_TABLES table was reopened via locked_tables_list,
|
||||
but not in prelocked environment where we have to reopen
|
||||
the table manually.
|
||||
*/
|
||||
Open_table_context ot_ctx(m_thd, MYSQL_OPEN_REOPEN);
|
||||
if (open_table(m_thd, m_failed_table, &ot_ctx))
|
||||
{
|
||||
result= true;
|
||||
break;
|
||||
}
|
||||
TABLE *table= m_failed_table->table;
|
||||
table->reginfo.lock_type= m_thd->update_lock_default;
|
||||
m_thd->in_lock_tables= 1;
|
||||
lock= mysql_lock_tables(m_thd, &table, 1,
|
||||
MYSQL_OPEN_REOPEN | MYSQL_LOCK_USE_MALLOC);
|
||||
m_thd->in_lock_tables= 0;
|
||||
if (lock == NULL ||
|
||||
!(merged_lock= mysql_lock_merge(m_thd->lock, lock, m_thd)))
|
||||
{
|
||||
result= true;
|
||||
break;
|
||||
}
|
||||
m_thd->lock= merged_lock;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OT_BACKOFF_AND_RETRY:
|
||||
|
|
@ -5309,9 +5391,6 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
|
|||
if (table_list->table)
|
||||
DBUG_RETURN(table_list->table);
|
||||
|
||||
/* should not be used in a prelocked_mode context, see NOTE above */
|
||||
DBUG_ASSERT(thd->locked_tables_mode < LTM_PRELOCKED);
|
||||
|
||||
THD_STAGE_INFO(thd, stage_opening_tables);
|
||||
thd->current_tablenr= 0;
|
||||
/* open_ltable can be used only for BASIC TABLEs */
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ class derived_handler;
|
|||
class Pushdown_derived;
|
||||
struct Name_resolution_context;
|
||||
class Table_function_json_table;
|
||||
class Open_table_context;
|
||||
|
||||
/*
|
||||
Used to identify NESTED_JOIN structures within a join (applicable only to
|
||||
|
|
@ -1768,7 +1769,10 @@ struct TABLE
|
|||
|
||||
ulonglong vers_start_id() const;
|
||||
ulonglong vers_end_id() const;
|
||||
bool vers_need_hist_part(const THD *thd, const TABLE_LIST *table_list) const;
|
||||
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||
bool vers_switch_partition(THD *thd, TABLE_LIST *table_list,
|
||||
Open_table_context *ot_ctx);
|
||||
#endif
|
||||
|
||||
int update_generated_fields();
|
||||
int period_make_insert(Item *src, Field *dst);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user