Merge 10.2 into 10.3
This commit is contained in:
commit
537f8594a6
@ -1 +1 @@
|
||||
Subproject commit 7de639518ffe56a99ac805654381d17f42796be2
|
||||
Subproject commit 544b6f1d12f0e5b2a141129075ff2d64feb0e4c9
|
@ -3357,18 +3357,26 @@ a b
|
||||
drop table t1;
|
||||
set sql_mode=default;
|
||||
create table t1 (a int default b, b int default 4, t text);
|
||||
insert into t1 (b, t) values (5, '1 column is omitted');
|
||||
insert into t1 values (default, 5, '2 column gets DEFAULT, keyword');
|
||||
insert into t1 values (default(a), 5, '3 column gets DEFAULT(a), expression');
|
||||
insert into t1 values (default(a)+0, 5, '4 also expression DEFAULT(0)+0');
|
||||
insert into t1 values (b, 5, '5 the value of the DEFAULT(a), that is b');
|
||||
insert t1 (b, t) values (5, '1 column is omitted');
|
||||
insert t1 values (default, 5, '2 column gets DEFAULT, keyword');
|
||||
insert t1 values (default(a), 5, '3 column gets DEFAULT(a), expression');
|
||||
insert t1 values (default(a)+0, 5, '4 also expression DEFAULT(0)+0');
|
||||
insert t1 values (b, 5, '5 the value of the DEFAULT(a), that is b');
|
||||
insert t1 (t,b,a) values ('6 reversed, column gets DEFAULT, keyword', 5, default);
|
||||
insert t1 (t,b,a) values ('7 reversed, column gets DEFAULT(a), expression', 5, default(a));
|
||||
insert t1 (t,b,a) values ('8 reversed, also expression DEFAULT(0)+0', 5, default(a)+0);
|
||||
insert t1 (t,b,a) values ('9 reversed, the value of the DEFAULT(a), that is b', 5, b);
|
||||
select * from t1 order by t;
|
||||
a b t
|
||||
5 5 1 column is omitted
|
||||
5 5 2 column gets DEFAULT, keyword
|
||||
4 5 2 column gets DEFAULT, keyword
|
||||
4 5 3 column gets DEFAULT(a), expression
|
||||
4 5 4 also expression DEFAULT(0)+0
|
||||
4 5 5 the value of the DEFAULT(a), that is b
|
||||
5 5 6 reversed, column gets DEFAULT, keyword
|
||||
5 5 7 reversed, column gets DEFAULT(a), expression
|
||||
5 5 8 reversed, also expression DEFAULT(0)+0
|
||||
5 5 9 reversed, the value of the DEFAULT(a), that is b
|
||||
drop table t1;
|
||||
create table t1 (col1 int default(-(default(col1))));
|
||||
ERROR 01000: Expression for field `col1` is referring to uninitialized field `col1`
|
||||
|
@ -2073,11 +2073,16 @@ set sql_mode=default;
|
||||
# MDEV-10201 Bad results for CREATE TABLE t1 (a INT DEFAULT b, b INT DEFAULT 4)
|
||||
#
|
||||
create table t1 (a int default b, b int default 4, t text);
|
||||
insert into t1 (b, t) values (5, '1 column is omitted');
|
||||
insert into t1 values (default, 5, '2 column gets DEFAULT, keyword');
|
||||
insert into t1 values (default(a), 5, '3 column gets DEFAULT(a), expression');
|
||||
insert into t1 values (default(a)+0, 5, '4 also expression DEFAULT(0)+0');
|
||||
insert into t1 values (b, 5, '5 the value of the DEFAULT(a), that is b');
|
||||
insert t1 (b, t) values (5, '1 column is omitted');
|
||||
insert t1 values (default, 5, '2 column gets DEFAULT, keyword');
|
||||
insert t1 values (default(a), 5, '3 column gets DEFAULT(a), expression');
|
||||
insert t1 values (default(a)+0, 5, '4 also expression DEFAULT(0)+0');
|
||||
insert t1 values (b, 5, '5 the value of the DEFAULT(a), that is b');
|
||||
# and the same in a different order
|
||||
insert t1 (t,b,a) values ('6 reversed, column gets DEFAULT, keyword', 5, default);
|
||||
insert t1 (t,b,a) values ('7 reversed, column gets DEFAULT(a), expression', 5, default(a));
|
||||
insert t1 (t,b,a) values ('8 reversed, also expression DEFAULT(0)+0', 5, default(a)+0);
|
||||
insert t1 (t,b,a) values ('9 reversed, the value of the DEFAULT(a), that is b', 5, b);
|
||||
select * from t1 order by t;
|
||||
drop table t1;
|
||||
|
||||
|
@ -3093,3 +3093,55 @@ a b
|
||||
1999-12-01 11:22:33.000000 1999-12-01 11:22:33.000000
|
||||
2001-09-09 04:46:40.000000 2001-09-09 04:46:40.000000
|
||||
DROP TABLE t1;
|
||||
create table t1 (t timestamp, i int, v timestamp as (t) virtual, key(v));
|
||||
insert t1 (t,i) values ('2006-03-01 23:59:59',1);
|
||||
update t1 set i = 2;
|
||||
check table t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
drop table t1;
|
||||
create table t1 (t timestamp, i int);
|
||||
create trigger tr1 before update on t1 for each row set @new:=new.t;
|
||||
insert t1 (t,i) values ('2006-03-01 23:59:59', 1);
|
||||
update t1 set i = 2;
|
||||
select if(@new = t, 'correct', 'wrong') from t1;
|
||||
if(@new = t, 'correct', 'wrong')
|
||||
correct
|
||||
drop table t1;
|
||||
create table t1 (i int, j int as (i));
|
||||
create trigger tr1 before update on t1 for each row set @new:=new.j;
|
||||
insert t1 (i) values (1);
|
||||
update t1, t1 as t2 set t1.i = 2;
|
||||
select if(@new = j, 'correct', 'wrong') from t1;
|
||||
if(@new = j, 'correct', 'wrong')
|
||||
correct
|
||||
drop table t1;
|
||||
create table t1 (a int, b varchar(20) default 'foo');
|
||||
insert t1 values (1,'bla'),(2, 'bar');
|
||||
select * from t1;
|
||||
a b
|
||||
1 bla
|
||||
2 bar
|
||||
update t1 set b=default where a=1;
|
||||
select * from t1;
|
||||
a b
|
||||
1 foo
|
||||
2 bar
|
||||
drop table t1;
|
||||
create table t1 (
|
||||
a int,
|
||||
b timestamp default '2010-10-10 10:10:10' on update now(),
|
||||
c varchar(100) default 'x');
|
||||
insert t1 (a) values (1),(2);
|
||||
select * from t1;
|
||||
a b c
|
||||
1 2010-10-10 10:10:10 x
|
||||
2 2010-10-10 10:10:10 x
|
||||
set timestamp=unix_timestamp('2011-11-11 11-11-11');
|
||||
update t1 set b=default, c=default(b) where a=1;
|
||||
select * from t1;
|
||||
a b c
|
||||
1 2010-10-10 10:10:10 2010-10-10 10:10:10
|
||||
2 2010-10-10 10:10:10 x
|
||||
drop table t1;
|
||||
set timestamp=default;
|
||||
|
@ -19,3 +19,51 @@ let $now=NOW(6);
|
||||
let $timestamp=TIMESTAMP(6);
|
||||
let $datetime=DATETIME(6);
|
||||
source 'include/function_defaults.inc';
|
||||
|
||||
#
|
||||
# MDEV-20403 Assertion `0' or Assertion `btr_validate_index(index, 0)' failed in row_upd_sec_index_entry or error code 126: Index is corrupted upon UPDATE with TIMESTAMP..ON UPDATE
|
||||
#
|
||||
|
||||
# ON UPDATE NOW and indexed virtual columns
|
||||
create table t1 (t timestamp, i int, v timestamp as (t) virtual, key(v));
|
||||
insert t1 (t,i) values ('2006-03-01 23:59:59',1);
|
||||
update t1 set i = 2;
|
||||
check table t1;
|
||||
drop table t1;
|
||||
|
||||
# ON UPDATE NOW and triggers
|
||||
create table t1 (t timestamp, i int);
|
||||
create trigger tr1 before update on t1 for each row set @new:=new.t;
|
||||
insert t1 (t,i) values ('2006-03-01 23:59:59', 1);
|
||||
update t1 set i = 2;
|
||||
select if(@new = t, 'correct', 'wrong') from t1;
|
||||
drop table t1;
|
||||
|
||||
# triggers, virtual columns, multi-update
|
||||
create table t1 (i int, j int as (i));
|
||||
create trigger tr1 before update on t1 for each row set @new:=new.j;
|
||||
insert t1 (i) values (1);
|
||||
update t1, t1 as t2 set t1.i = 2;
|
||||
select if(@new = j, 'correct', 'wrong') from t1;
|
||||
drop table t1;
|
||||
|
||||
# SET xxx=DEFAULT
|
||||
create table t1 (a int, b varchar(20) default 'foo');
|
||||
insert t1 values (1,'bla'),(2, 'bar');
|
||||
select * from t1;
|
||||
update t1 set b=default where a=1;
|
||||
select * from t1;
|
||||
drop table t1;
|
||||
|
||||
# ON UPDATE NOW and SET xxx=DEFAULT
|
||||
create table t1 (
|
||||
a int,
|
||||
b timestamp default '2010-10-10 10:10:10' on update now(),
|
||||
c varchar(100) default 'x');
|
||||
insert t1 (a) values (1),(2);
|
||||
select * from t1;
|
||||
set timestamp=unix_timestamp('2011-11-11 11-11-11');
|
||||
update t1 set b=default, c=default(b) where a=1;
|
||||
select * from t1;
|
||||
drop table t1;
|
||||
set timestamp=default;
|
||||
|
@ -538,7 +538,7 @@ a b
|
||||
insert into t2 values(1);
|
||||
select a,b from t2;
|
||||
a b
|
||||
12 1
|
||||
NULL 1
|
||||
drop table t1,t2;
|
||||
create table t1 (a int invisible, b int, c int);
|
||||
create table t2 (a int, b int, d int);
|
||||
|
@ -33,6 +33,7 @@ galera_var_node_address : MDEV-17151 Galera test failure
|
||||
galera_var_notify_cmd : MDEV-13549 Galera test failures
|
||||
galera_var_slave_threads : MDEV-19746 Galera test failures because of wsrep_slave_threads identification
|
||||
galera_sst_mariabackup_encrypt_with_key : MDEV-19926 Galera SST tests fail
|
||||
galera_wan : MDEV-17259: Test failure on galera.galera_wan
|
||||
galera_var_node_address : MDEV-20485 Galera test failure on galera.galera_var_node_address
|
||||
galera_wan : MDEV-17259 Test failure on galera.galera_wan
|
||||
partition : MDEV-19958 Galera test failure on galera.partition
|
||||
query_cache: MDEV-15805 Test failure on galera.query_cache
|
@ -1,4 +1,5 @@
|
||||
FLUSH TABLES;
|
||||
call mtr.add_suppression("Found 1 prepared XA transactions");
|
||||
#
|
||||
# MDEV-13797 InnoDB may hang if shutdown is initiated soon after startup
|
||||
# while rolling back recovered incomplete transactions
|
||||
@ -8,10 +9,12 @@ BEGIN;
|
||||
COMMIT;
|
||||
connect con$c,localhost,root,,;
|
||||
CREATE TABLE t8 (a SERIAL, b INT UNIQUE, c INT UNIQUE) ENGINE=InnoDB;
|
||||
BEGIN;
|
||||
XA START 'x';
|
||||
INSERT INTO t8 (a) SELECT NULL FROM t;
|
||||
UPDATE t8 SET a=a+100, b=a;
|
||||
DELETE FROM t8;
|
||||
XA END 'x';
|
||||
XA PREPARE 'x';
|
||||
connect con$c,localhost,root,,;
|
||||
CREATE TABLE t7 (a SERIAL, b INT UNIQUE, c INT UNIQUE) ENGINE=InnoDB;
|
||||
BEGIN;
|
||||
@ -63,4 +66,7 @@ connection default;
|
||||
SET GLOBAL innodb_flush_log_at_trx_commit=1;
|
||||
CREATE TABLE u(a SERIAL) ENGINE=INNODB;
|
||||
FLUSH TABLES;
|
||||
XA RECOVER;
|
||||
formatID gtrid_length bqual_length data
|
||||
1 1 0 x
|
||||
DROP TABLE t,u;
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
# Flush any open myisam tables from previous tests
|
||||
FLUSH TABLES;
|
||||
call mtr.add_suppression("Found 1 prepared XA transactions");
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-13797 InnoDB may hang if shutdown is initiated soon after startup
|
||||
@ -23,6 +24,15 @@ dec $c;
|
||||
COMMIT;
|
||||
|
||||
let $c = $trx;
|
||||
connect (con$c,localhost,root,,);
|
||||
eval CREATE TABLE t$c (a SERIAL, b INT UNIQUE, c INT UNIQUE) ENGINE=InnoDB;
|
||||
XA START 'x';
|
||||
eval INSERT INTO t$c (a) SELECT NULL FROM t;
|
||||
eval UPDATE t$c SET a=a+$size, b=a;
|
||||
eval DELETE FROM t$c;
|
||||
XA END 'x';
|
||||
XA PREPARE 'x';
|
||||
dec $c;
|
||||
while ($c)
|
||||
{
|
||||
connect (con$c,localhost,root,,);
|
||||
@ -53,12 +63,17 @@ FLUSH TABLES;
|
||||
|
||||
# Perform a slow shutdown in order to roll back all recovered transactions
|
||||
# and to avoid locking conflicts with the DROP TABLE below.
|
||||
XA RECOVER;
|
||||
--disable_query_log
|
||||
SET GLOBAL innodb_fast_shutdown=0;
|
||||
--source include/restart_mysqld.inc
|
||||
|
||||
--disable_query_log
|
||||
let $c = $trx;
|
||||
disconnect con$c;
|
||||
XA ROLLBACK 'x';
|
||||
eval DROP TABLE t$c;
|
||||
dec $c;
|
||||
while ($c)
|
||||
{
|
||||
disconnect con$c;
|
||||
|
@ -17,5 +17,4 @@ rpl_row_binlog_max_cache_size : MDEV-11092
|
||||
rpl_row_index_choice : MDEV-11666
|
||||
rpl_parallel2 : fails after MDEV-16172
|
||||
rpl_semi_sync_after_sync : fails after MDEV-16172
|
||||
mdev_17588: MDEV-20137
|
||||
rpl_slave_grp_exec: MDEV-10514
|
||||
|
@ -1,18 +1,16 @@
|
||||
include/master-slave.inc
|
||||
[connection master]
|
||||
connection slave;
|
||||
include/stop_slave.inc
|
||||
CHANGE MASTER TO master_use_gtid=slave_pos;
|
||||
include/start_slave.inc
|
||||
connection master;
|
||||
create table t1 (a int) engine=innodb;
|
||||
create table t2 (a int);
|
||||
create table t3 (a int) engine=innodb;
|
||||
include/save_master_gtid.inc
|
||||
connection slave;
|
||||
include/wait_for_slave_sql_error.inc [errno=1286]
|
||||
Last_Error = 'Error 'Unknown storage engine 'innodb'' on query. Default database: 'test'. Query: 'create table t1 (a int) engine=innodb''
|
||||
STOP SLAVE IO_THREAD;
|
||||
include/wait_for_slave_to_stop.inc
|
||||
SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
|
||||
include/start_slave.inc
|
||||
include/sync_with_master_gtid.inc
|
||||
include/wait_for_slave_sql_error_and_skip.inc [errno=1286]
|
||||
# Asserted this: Status should be 'Slave has read all relay log...'
|
||||
show tables;
|
||||
Tables_in_test
|
||||
t2
|
||||
|
@ -1,23 +1,28 @@
|
||||
--source include/master-slave.inc
|
||||
--source include/have_innodb.inc
|
||||
|
||||
--connection slave
|
||||
--source include/stop_slave.inc
|
||||
CHANGE MASTER TO master_use_gtid=slave_pos;
|
||||
--source include/start_slave.inc
|
||||
|
||||
--connection master
|
||||
create table t1 (a int) engine=innodb;
|
||||
create table t2 (a int);
|
||||
create table t3 (a int) engine=innodb;
|
||||
--source include/save_master_gtid.inc
|
||||
--save_master_pos
|
||||
|
||||
--connection slave
|
||||
# Using ER_UNKNOWN_STORAGE_ENGINE wont work
|
||||
let $slave_sql_errno= 1286;
|
||||
--source include/wait_for_slave_sql_error.inc
|
||||
--let $status_items= Last_Error
|
||||
--source include/show_slave_status.inc
|
||||
STOP SLAVE IO_THREAD;
|
||||
source include/wait_for_slave_to_stop.inc;
|
||||
SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
|
||||
--source include/start_slave.inc
|
||||
--source include/sync_with_master_gtid.inc
|
||||
--source include/wait_for_slave_sql_error_and_skip.inc
|
||||
--sync_with_master
|
||||
|
||||
--let $assert_text= Status should be 'Slave has read all relay log...'
|
||||
--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]"
|
||||
#Like "Slave has read all relay log%"
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
show tables;
|
||||
show create table t2;
|
||||
--error ER_NO_SUCH_TABLE
|
||||
|
27
sql/field.cc
27
sql/field.cc
@ -11422,33 +11422,6 @@ key_map Field::get_possible_keys()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Mark the field as having an explicit default value.
|
||||
|
||||
@param value if available, the value that the field is being set to
|
||||
|
||||
@note
|
||||
Fields that have an explicit default value should not be updated
|
||||
automatically via the DEFAULT or ON UPDATE functions. The functions
|
||||
that deal with data change functionality (INSERT/UPDATE/LOAD),
|
||||
determine if there is an explicit value for each field before performing
|
||||
the data change, and call this method to mark the field.
|
||||
|
||||
If the 'value' parameter is NULL, then the field is marked unconditionally
|
||||
as having an explicit value. If 'value' is not NULL, then it can be further
|
||||
analyzed to check if it really should count as a value.
|
||||
*/
|
||||
|
||||
bool Field::set_explicit_default(Item *value)
|
||||
{
|
||||
if (value->type() == Item::DEFAULT_VALUE_ITEM &&
|
||||
!((Item_default_value*)value)->arg)
|
||||
return false;
|
||||
set_has_explicit_value();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Field::validate_value_in_record_with_warn(THD *thd, const uchar *record)
|
||||
{
|
||||
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
|
||||
|
23
sql/field.h
23
sql/field.h
@ -1001,7 +1001,6 @@ public:
|
||||
{
|
||||
bitmap_clear_bit(&table->has_value_set, field_index);
|
||||
}
|
||||
bool set_explicit_default(Item *value);
|
||||
|
||||
virtual my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const
|
||||
{ DBUG_ASSERT(0); return 0; }
|
||||
@ -1010,14 +1009,6 @@ public:
|
||||
return get_timestamp(ptr, sec_part);
|
||||
}
|
||||
|
||||
/**
|
||||
Evaluates the @c UPDATE default function, if one exists, and stores the
|
||||
result in the record buffer. If no such function exists for the column,
|
||||
or the function is not valid for the column's data type, invoking this
|
||||
function has no effect.
|
||||
*/
|
||||
virtual int evaluate_update_default_function() { return 0; }
|
||||
|
||||
virtual bool binary() const { return 1; }
|
||||
virtual bool zero_pack() const { return 1; }
|
||||
virtual enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
|
||||
@ -2686,13 +2677,6 @@ public:
|
||||
void sql_type(String &str) const;
|
||||
bool zero_pack() const { return 0; }
|
||||
int set_time();
|
||||
int evaluate_update_default_function()
|
||||
{
|
||||
int res= 0;
|
||||
if (has_update_default_function())
|
||||
res= set_time();
|
||||
return res;
|
||||
}
|
||||
/* Get TIMESTAMP field value as seconds since begging of Unix Epoch */
|
||||
my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const;
|
||||
my_time_t get_timestamp(ulong *sec_part) const
|
||||
@ -3148,13 +3132,6 @@ public:
|
||||
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
|
||||
{ return Field_datetime::get_TIME(ltime, ptr, fuzzydate); }
|
||||
int set_time();
|
||||
int evaluate_update_default_function()
|
||||
{
|
||||
int res= 0;
|
||||
if (has_update_default_function())
|
||||
res= set_time();
|
||||
return res;
|
||||
}
|
||||
uchar *pack(uchar* to, const uchar *from,
|
||||
uint max_length __attribute__((unused)))
|
||||
{
|
||||
|
@ -802,9 +802,9 @@ struct xid_t {
|
||||
char data[XIDDATASIZE]; // not \0-terminated !
|
||||
|
||||
xid_t() {} /* Remove gcc warning */
|
||||
bool eq(struct xid_t *xid)
|
||||
bool eq(struct xid_t *xid) const
|
||||
{ return !xid->is_null() && eq(xid->gtrid_length, xid->bqual_length, xid->data); }
|
||||
bool eq(long g, long b, const char *d)
|
||||
bool eq(long g, long b, const char *d) const
|
||||
{ return !is_null() && g == gtrid_length && b == bqual_length && !memcmp(d, data, g+b); }
|
||||
void set(struct xid_t *xid)
|
||||
{ memcpy(this, xid, xid->length()); }
|
||||
|
@ -9403,8 +9403,6 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions)
|
||||
return Item_field::save_in_field(field_arg, no_conversions);
|
||||
}
|
||||
|
||||
if (field_arg->default_value && field_arg->default_value->flags)
|
||||
return 0; // defaut fields will be set later, no need to do it twice
|
||||
return field_arg->save_in_field_default_value(context->error_processor ==
|
||||
&view_error_processor);
|
||||
}
|
||||
@ -9651,7 +9649,7 @@ bool Item_trigger_field::set_value(THD *thd, sp_rcontext * /*ctx*/, Item **it)
|
||||
int err_code= item->save_in_field(field, 0);
|
||||
|
||||
field->table->copy_blobs= copy_blobs_saved;
|
||||
field->set_explicit_default(item);
|
||||
field->set_has_explicit_value();
|
||||
|
||||
return err_code < 0;
|
||||
}
|
||||
|
@ -8343,7 +8343,7 @@ fill_record(THD *thd, TABLE *table_arg, List<Item> &fields, List<Item> &values,
|
||||
rfield->move_field_offset((my_ptrdiff_t) (table->record[1] -
|
||||
table->record[0]));
|
||||
}
|
||||
rfield->set_explicit_default(value);
|
||||
rfield->set_has_explicit_value();
|
||||
}
|
||||
|
||||
if (update && thd->variables.sql_mode & MODE_SIMULTANEOUS_ASSIGNMENT)
|
||||
@ -8362,9 +8362,13 @@ fill_record(THD *thd, TABLE *table_arg, List<Item> &fields, List<Item> &values,
|
||||
}
|
||||
}
|
||||
|
||||
if (!update && table_arg->default_field &&
|
||||
table_arg->update_default_fields(0, ignore_errors))
|
||||
goto err;
|
||||
if (update)
|
||||
table_arg->evaluate_update_default_function();
|
||||
else
|
||||
if (table_arg->default_field &&
|
||||
table_arg->update_default_fields(ignore_errors))
|
||||
goto err;
|
||||
|
||||
/* Update virtual fields */
|
||||
if (table_arg->vfield &&
|
||||
table_arg->update_virtual_fields(table_arg->file, VCOL_UPDATE_FOR_WRITE))
|
||||
@ -8554,7 +8558,6 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List<Item> &values,
|
||||
{
|
||||
List_iterator_fast<Item> v(values);
|
||||
List<TABLE> tbl_list;
|
||||
bool all_fields_have_values= true;
|
||||
Item *value;
|
||||
Field *field;
|
||||
bool abort_on_warning_saved= thd->abort_on_warning;
|
||||
@ -8585,10 +8588,7 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List<Item> &values,
|
||||
DBUG_ASSERT(field->table == table);
|
||||
|
||||
if (unlikely(field->invisible))
|
||||
{
|
||||
all_fields_have_values= false;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
value=v++;
|
||||
|
||||
@ -8617,11 +8617,8 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List<Item> &values,
|
||||
else
|
||||
if (value->save_in_field(field, 0) < 0)
|
||||
goto err;
|
||||
all_fields_have_values &= field->set_explicit_default(value);
|
||||
field->set_has_explicit_value();
|
||||
}
|
||||
if (!all_fields_have_values && table->default_field &&
|
||||
table->update_default_fields(0, ignore_errors))
|
||||
goto err;
|
||||
/* Update virtual fields */
|
||||
thd->abort_on_warning= FALSE;
|
||||
if (table->vfield &&
|
||||
|
@ -1835,10 +1835,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
|
||||
be updated as if this is an UPDATE.
|
||||
*/
|
||||
if (different_records && table->default_field)
|
||||
{
|
||||
if (table->update_default_fields(1, info->ignore))
|
||||
goto err;
|
||||
}
|
||||
table->evaluate_update_default_function();
|
||||
|
||||
/* CHECK OPTION for VIEW ... ON DUPLICATE KEY UPDATE ... */
|
||||
res= info->table_list->view_check_option(table->in_use, info->ignore);
|
||||
@ -3856,7 +3853,7 @@ int select_insert::send_data(List<Item> &values)
|
||||
thd->count_cuted_fields= CHECK_FIELD_WARN; // Calculate cuted fields
|
||||
store_values(values);
|
||||
if (table->default_field &&
|
||||
unlikely(table->update_default_fields(0, info.ignore)))
|
||||
unlikely(table->update_default_fields(info.ignore)))
|
||||
DBUG_RETURN(1);
|
||||
thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
|
||||
if (unlikely(thd->is_error()))
|
||||
|
@ -9819,7 +9819,7 @@ do_continue:;
|
||||
thd->count_cuted_fields= CHECK_FIELD_EXPRESSION;
|
||||
altered_table->reset_default_fields();
|
||||
if (altered_table->default_field &&
|
||||
altered_table->update_default_fields(0, 1))
|
||||
altered_table->update_default_fields(true))
|
||||
goto err_new_table_cleanup;
|
||||
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
|
||||
|
||||
@ -10515,7 +10515,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
|
||||
|
||||
prev_insert_id= to->file->next_insert_id;
|
||||
if (to->default_field)
|
||||
to->update_default_fields(0, ignore);
|
||||
to->update_default_fields(ignore);
|
||||
if (to->vfield)
|
||||
to->update_virtual_fields(to->file, VCOL_UPDATE_FOR_WRITE);
|
||||
|
||||
|
@ -69,17 +69,20 @@ bool compare_record(const TABLE *table)
|
||||
{
|
||||
DBUG_ASSERT(records_are_comparable(table));
|
||||
|
||||
if ((table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ) != 0)
|
||||
if (table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ ||
|
||||
table->s->has_update_default_function)
|
||||
{
|
||||
/*
|
||||
Storage engine may not have read all columns of the record. Fields
|
||||
(including NULL bits) not in the write_set may not have been read and
|
||||
can therefore not be compared.
|
||||
Or ON UPDATE DEFAULT NOW() could've changed field values, including
|
||||
NULL bits.
|
||||
*/
|
||||
for (Field **ptr= table->field ; *ptr != NULL; ptr++)
|
||||
{
|
||||
Field *field= *ptr;
|
||||
if (bitmap_is_set(table->write_set, field->field_index))
|
||||
if (field->has_explicit_value() && !field->vcol_info)
|
||||
{
|
||||
if (field->real_maybe_null())
|
||||
{
|
||||
@ -111,8 +114,9 @@ bool compare_record(const TABLE *table)
|
||||
/* Compare updated fields */
|
||||
for (Field **ptr= table->field ; *ptr ; ptr++)
|
||||
{
|
||||
if (bitmap_is_set(table->write_set, (*ptr)->field_index) &&
|
||||
(*ptr)->cmp_binary_offset(table->s->rec_buff_length))
|
||||
Field *field= *ptr;
|
||||
if (field->has_explicit_value() && !field->vcol_info &&
|
||||
field->cmp_binary_offset(table->s->rec_buff_length))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
@ -897,11 +901,6 @@ update_begin:
|
||||
|
||||
if (!can_compare_record || compare_record(table))
|
||||
{
|
||||
if (table->default_field && table->update_default_fields(1, ignore))
|
||||
{
|
||||
error= 1;
|
||||
break;
|
||||
}
|
||||
if ((res= table_list->view_check_option(thd, ignore)) !=
|
||||
VIEW_CHECK_OK)
|
||||
{
|
||||
@ -2379,10 +2378,6 @@ int multi_update::send_data(List<Item> ¬_used_values)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (table->default_field &&
|
||||
unlikely(table->update_default_fields(1, ignore)))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
if ((error= cur_table->view_check_option(thd, ignore)) !=
|
||||
VIEW_CHECK_OK)
|
||||
{
|
||||
@ -2699,6 +2694,10 @@ int multi_update::do_updates()
|
||||
copy_field_ptr->to_field->set_has_explicit_value();
|
||||
}
|
||||
|
||||
table->evaluate_update_default_function();
|
||||
if (table->vfield &&
|
||||
table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_WRITE))
|
||||
goto err2;
|
||||
if (table->triggers &&
|
||||
table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
|
||||
TRG_ACTION_BEFORE, TRUE))
|
||||
@ -2707,12 +2706,6 @@ int multi_update::do_updates()
|
||||
if (!can_compare_record || compare_record(table))
|
||||
{
|
||||
int error;
|
||||
if (table->default_field &&
|
||||
(error= table->update_default_fields(1, ignore)))
|
||||
goto err2;
|
||||
if (table->vfield &&
|
||||
table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_WRITE))
|
||||
goto err2;
|
||||
if ((error= cur_table->view_check_option(thd, ignore)) !=
|
||||
VIEW_CHECK_OK)
|
||||
{
|
||||
|
28
sql/table.cc
28
sql/table.cc
@ -7930,7 +7930,7 @@ int TABLE::update_virtual_field(Field *vf)
|
||||
ignore_errors == 0. If set then an error was generated.
|
||||
*/
|
||||
|
||||
int TABLE::update_default_fields(bool update_command, bool ignore_errors)
|
||||
int TABLE::update_default_fields(bool ignore_errors)
|
||||
{
|
||||
Query_arena backup_arena;
|
||||
Field **field_ptr;
|
||||
@ -7950,14 +7950,9 @@ int TABLE::update_default_fields(bool update_command, bool ignore_errors)
|
||||
*/
|
||||
if (!field->has_explicit_value())
|
||||
{
|
||||
if (!update_command)
|
||||
{
|
||||
if (field->default_value &&
|
||||
(field->default_value->flags || field->flags & BLOB_FLAG))
|
||||
res|= (field->default_value->expr->save_in_field(field, 0) < 0);
|
||||
}
|
||||
else
|
||||
res|= field->evaluate_update_default_function();
|
||||
if (field->default_value &&
|
||||
(field->default_value->flags || field->flags & BLOB_FLAG))
|
||||
res|= (field->default_value->expr->save_in_field(field, 0) < 0);
|
||||
if (!ignore_errors && res)
|
||||
{
|
||||
my_error(ER_CALCULATING_DEFAULT_VALUE, MYF(0), field->field_name.str);
|
||||
@ -7971,6 +7966,21 @@ int TABLE::update_default_fields(bool update_command, bool ignore_errors)
|
||||
}
|
||||
|
||||
|
||||
void TABLE::evaluate_update_default_function()
|
||||
{
|
||||
DBUG_ENTER("TABLE::evaluate_update_default_function");
|
||||
|
||||
if (s->has_update_default_function)
|
||||
for (Field **field_ptr= default_field; *field_ptr ; field_ptr++)
|
||||
{
|
||||
Field *field= (*field_ptr);
|
||||
if (!field->has_explicit_value() && field->has_update_default_function())
|
||||
field->set_time();
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
void TABLE::vers_update_fields()
|
||||
{
|
||||
bitmap_set_bit(write_set, vers_start_field()->field_index);
|
||||
|
@ -1489,7 +1489,8 @@ public:
|
||||
ulong actual_key_flags(KEY *keyinfo);
|
||||
int update_virtual_field(Field *vf);
|
||||
int update_virtual_fields(handler *h, enum_vcol_update_mode update_mode);
|
||||
int update_default_fields(bool update, bool ignore_errors);
|
||||
int update_default_fields(bool ignore_errors);
|
||||
void evaluate_update_default_function();
|
||||
void reset_default_fields();
|
||||
inline ha_rows stat_records() { return used_stat_records; }
|
||||
|
||||
|
@ -482,14 +482,10 @@ lock_rec_unlock(
|
||||
const buf_block_t* block, /*!< in: buffer block containing rec */
|
||||
const rec_t* rec, /*!< in: record */
|
||||
lock_mode lock_mode);/*!< in: LOCK_S or LOCK_X */
|
||||
/*********************************************************************//**
|
||||
Releases a transaction's locks, and releases possible other transactions
|
||||
waiting because of these locks. Change the state of the transaction to
|
||||
TRX_STATE_COMMITTED_IN_MEMORY. */
|
||||
void
|
||||
lock_trx_release_locks(
|
||||
/*===================*/
|
||||
trx_t* trx); /*!< in/out: transaction */
|
||||
|
||||
/** Release the explicit locks of a committing transaction,
|
||||
and release possible other transactions waiting because of these locks. */
|
||||
void lock_trx_release_locks(trx_t* trx);
|
||||
|
||||
/*********************************************************************//**
|
||||
Calculates the fold value of a page file address: used in inserting or
|
||||
|
@ -44,7 +44,8 @@ index record.
|
||||
@param[in] rec secondary index record
|
||||
@param[in] index secondary index
|
||||
@param[in] offsets rec_get_offsets(rec, index)
|
||||
@return the active transaction; trx->release_reference() must be invoked
|
||||
@return the active transaction; state must be rechecked after
|
||||
trx_mutex_enter(), and trx->release_reference() must be invoked
|
||||
@retval NULL if the record was committed */
|
||||
trx_t*
|
||||
row_vers_impl_x_locked(
|
||||
|
@ -514,8 +514,10 @@ class rw_trx_hash_t
|
||||
{
|
||||
ut_ad(!trx->read_only || !trx->rsegs.m_redo.rseg);
|
||||
ut_ad(!trx_is_autocommit_non_locking(trx));
|
||||
/* trx->state can be anything except TRX_STATE_NOT_STARTED */
|
||||
mutex_enter(&trx->mutex);
|
||||
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE) ||
|
||||
trx_state_eq(trx, TRX_STATE_COMMITTED_IN_MEMORY) ||
|
||||
trx_state_eq(trx, TRX_STATE_PREPARED_RECOVERED) ||
|
||||
trx_state_eq(trx, TRX_STATE_PREPARED));
|
||||
mutex_exit(&trx->mutex);
|
||||
@ -940,7 +942,7 @@ public:
|
||||
/**
|
||||
Takes MVCC snapshot.
|
||||
|
||||
To reduce malloc probablility we reserver rw_trx_hash.size() + 32 elements
|
||||
To reduce malloc probablility we reserve rw_trx_hash.size() + 32 elements
|
||||
in ids.
|
||||
|
||||
For details about get_rw_trx_hash_version() != get_max_trx_id() spin
|
||||
|
@ -211,16 +211,13 @@ trx_recover_for_mysql(
|
||||
/*==================*/
|
||||
XID* xid_list, /*!< in/out: prepared transactions */
|
||||
uint len); /*!< in: number of slots in xid_list */
|
||||
/*******************************************************************//**
|
||||
This function is used to find one X/Open XA distributed transaction
|
||||
which is in the prepared state
|
||||
@return trx or NULL; on match, the trx->xid will be invalidated;
|
||||
note that the trx may have been committed, unless the caller is
|
||||
holding lock_sys.mutex */
|
||||
trx_t *
|
||||
trx_get_trx_by_xid(
|
||||
/*===============*/
|
||||
XID* xid); /*!< in: X/Open XA transaction identifier */
|
||||
/** Look up an X/Open distributed transaction in XA PREPARE state.
|
||||
@param[in] xid X/Open XA transaction identifier
|
||||
@return transaction on match (the trx_t::xid will be invalidated);
|
||||
note that the trx may have been committed before the caller acquires
|
||||
trx_t::mutex
|
||||
@retval NULL if no match */
|
||||
trx_t* trx_get_trx_by_xid(const XID* xid);
|
||||
/**********************************************************************//**
|
||||
If required, flushes the log to disk if we called trx_commit_for_mysql()
|
||||
with trx->flush_log_later == TRUE. */
|
||||
@ -467,6 +464,9 @@ Check transaction state */
|
||||
ut_ad(!(t)->read_view.is_open()); \
|
||||
ut_ad((t)->lock.wait_thr == NULL); \
|
||||
ut_ad(UT_LIST_GET_LEN((t)->lock.trx_locks) == 0); \
|
||||
ut_ad((t)->lock.table_locks.empty()); \
|
||||
ut_ad(!(t)->autoinc_locks \
|
||||
|| ib_vector_is_empty((t)->autoinc_locks)); \
|
||||
ut_ad((t)->dict_operation == TRX_DICT_OP_NONE); \
|
||||
} while(0)
|
||||
|
||||
@ -701,8 +701,8 @@ so without holding any mutex. The following are exceptions to this:
|
||||
|
||||
* trx_rollback_resurrected() may access resurrected (connectionless)
|
||||
transactions while the system is already processing new user
|
||||
transactions. The trx_sys.mutex prevents a race condition between it
|
||||
and lock_trx_release_locks() [invoked by trx_commit()].
|
||||
transactions. The trx_sys.mutex and trx->is_recovered prevent
|
||||
a race condition between it and trx_commit().
|
||||
|
||||
* trx_print_low() may access transactions not associated with the current
|
||||
thread. The caller must be holding lock_sys.mutex.
|
||||
@ -713,7 +713,7 @@ must not be modified without holding trx->mutex.
|
||||
* The locking code (in particular, lock_deadlock_recursive() and
|
||||
lock_rec_convert_impl_to_expl()) will access transactions associated
|
||||
to other connections. The locks of transactions are protected by
|
||||
lock_sys.mutex and sometimes by trx->mutex. */
|
||||
lock_sys.mutex (insertions also by trx->mutex). */
|
||||
|
||||
/** Represents an instance of rollback segment along with its state variables.*/
|
||||
struct trx_undo_ptr_t {
|
||||
@ -837,26 +837,19 @@ public:
|
||||
ACTIVE->COMMITTED is possible when the transaction is in
|
||||
rw_trx_hash.
|
||||
|
||||
Transitions to COMMITTED are protected by both lock_sys.mutex
|
||||
and trx->mutex.
|
||||
|
||||
NOTE: Some of these state change constraints are an overkill,
|
||||
currently only required for a consistent view for printing stats.
|
||||
This unnecessarily adds a huge cost for the general case. */
|
||||
|
||||
Transitions to COMMITTED are protected by trx_t::mutex. */
|
||||
trx_state_t state;
|
||||
/** whether this is a recovered transaction that should be
|
||||
rolled back by trx_rollback_or_clean_recovered().
|
||||
Protected by trx_t::mutex for transactions that are in trx_sys. */
|
||||
bool is_recovered;
|
||||
|
||||
ReadView read_view; /*!< consistent read view used in the
|
||||
transaction, or NULL if not yet set */
|
||||
trx_lock_t lock; /*!< Information about the transaction
|
||||
locks and state. Protected by
|
||||
trx->mutex or lock_sys.mutex
|
||||
or both */
|
||||
bool is_recovered; /*!< 0=normal transaction,
|
||||
1=recovered, must be rolled back,
|
||||
protected by trx_sys.mutex when
|
||||
trx is in rw_trx_hash */
|
||||
|
||||
lock_sys.mutex (insertions also
|
||||
by trx_t::mutex). */
|
||||
|
||||
/* These fields are not protected by any mutex. */
|
||||
const char* op_info; /*!< English text describing the
|
||||
@ -1116,6 +1109,12 @@ public:
|
||||
return flush_observer;
|
||||
}
|
||||
|
||||
/** Transition to committed state, to release implicit locks. */
|
||||
inline void commit_state();
|
||||
|
||||
/** Release any explicit locks of a committing transaction. */
|
||||
inline void release_locks();
|
||||
|
||||
|
||||
bool is_referenced()
|
||||
{
|
||||
|
@ -4740,7 +4740,7 @@ lock_trx_table_locks_find(
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
trx_mutex_enter(trx);
|
||||
ut_ad(trx_mutex_own(trx));
|
||||
|
||||
for (lock_list::const_iterator it = trx->lock.table_locks.begin(),
|
||||
end = trx->lock.table_locks.end(); it != end; ++it) {
|
||||
@ -4763,8 +4763,6 @@ lock_trx_table_locks_find(
|
||||
ut_a(lock->un_member.tab_lock.table != NULL);
|
||||
}
|
||||
|
||||
trx_mutex_exit(trx);
|
||||
|
||||
return(found);
|
||||
}
|
||||
|
||||
@ -4785,25 +4783,23 @@ lock_table_queue_validate(
|
||||
lock != NULL;
|
||||
lock = UT_LIST_GET_NEXT(un_member.tab_lock.locks, lock)) {
|
||||
|
||||
/* Transaction state may change from ACTIVE to PREPARED.
|
||||
State change to COMMITTED is not possible while we are
|
||||
holding lock_sys.mutex: it is done by lock_trx_release_locks()
|
||||
under lock_sys.mutex protection.
|
||||
Transaction in NOT_STARTED state cannot hold locks, and
|
||||
lock->trx->state can only move to NOT_STARTED from COMMITTED. */
|
||||
/* lock->trx->state cannot change from or to NOT_STARTED
|
||||
while we are holding the trx_sys.mutex. It may change
|
||||
from ACTIVE or PREPARED to PREPARED or COMMITTED. */
|
||||
trx_mutex_enter(lock->trx);
|
||||
check_trx_state(lock->trx);
|
||||
|
||||
if (!lock_get_wait(lock)) {
|
||||
|
||||
if (lock->trx->state == TRX_STATE_COMMITTED_IN_MEMORY) {
|
||||
} else if (!lock_get_wait(lock)) {
|
||||
ut_a(!lock_table_other_has_incompatible(
|
||||
lock->trx, 0, table,
|
||||
lock_get_mode(lock)));
|
||||
} else {
|
||||
|
||||
ut_a(lock_table_has_to_wait_in_queue(lock));
|
||||
}
|
||||
|
||||
ut_a(lock_trx_table_locks_find(lock->trx, lock));
|
||||
trx_mutex_exit(lock->trx);
|
||||
}
|
||||
|
||||
return(TRUE);
|
||||
@ -4850,42 +4846,41 @@ lock_rec_queue_validate(
|
||||
lock != NULL;
|
||||
lock = lock_rec_get_next_const(heap_no, lock)) {
|
||||
|
||||
ut_ad(!index || lock->index == index);
|
||||
|
||||
trx_mutex_enter(lock->trx);
|
||||
ut_ad(!trx_is_ac_nl_ro(lock->trx));
|
||||
|
||||
if (lock_get_wait(lock)) {
|
||||
ut_a(lock_rec_has_to_wait_in_queue(lock));
|
||||
}
|
||||
|
||||
if (index != NULL) {
|
||||
ut_a(lock->index == index);
|
||||
}
|
||||
ut_ad(trx_state_eq(lock->trx,
|
||||
TRX_STATE_COMMITTED_IN_MEMORY)
|
||||
|| !lock_get_wait(lock)
|
||||
|| lock_rec_has_to_wait_in_queue(lock));
|
||||
trx_mutex_exit(lock->trx);
|
||||
}
|
||||
|
||||
goto func_exit;
|
||||
func_exit:
|
||||
if (!locked_lock_trx_sys) {
|
||||
lock_mutex_exit();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ut_ad(page_rec_is_leaf(rec));
|
||||
ut_ad(lock_mutex_own());
|
||||
|
||||
if (index == NULL) {
|
||||
const trx_id_t impl_trx_id = index && index->is_primary()
|
||||
? lock_clust_rec_some_has_impl(rec, index, offsets)
|
||||
: 0;
|
||||
|
||||
/* Nothing we can do */
|
||||
if (trx_t *impl_trx = impl_trx_id
|
||||
? trx_sys.find(current_trx(), impl_trx_id, false)
|
||||
: 0) {
|
||||
/* impl_trx could have been committed before we
|
||||
acquire its mutex, but not thereafter. */
|
||||
|
||||
} else if (dict_index_is_clust(index)) {
|
||||
/* Unlike the non-debug code, this invariant can only succeed
|
||||
if the check and assertion are covered by the lock mutex. */
|
||||
|
||||
const trx_id_t impl_trx_id = lock_clust_rec_some_has_impl(
|
||||
rec, index, offsets);
|
||||
|
||||
const trx_t *impl_trx = impl_trx_id
|
||||
? trx_sys.find(current_trx(), impl_trx_id, false)
|
||||
: 0;
|
||||
|
||||
ut_ad(lock_mutex_own());
|
||||
/* impl_trx cannot be committed until lock_mutex_exit()
|
||||
because lock_trx_release_locks() acquires lock_sys.mutex */
|
||||
|
||||
if (!impl_trx) {
|
||||
mutex_enter(&impl_trx->mutex);
|
||||
ut_ad(impl_trx->state != TRX_STATE_NOT_STARTED);
|
||||
if (impl_trx->state == TRX_STATE_COMMITTED_IN_MEMORY) {
|
||||
} else if (const lock_t* other_lock
|
||||
= lock_rec_other_has_expl_req(
|
||||
LOCK_S, block, true, heap_no,
|
||||
@ -4927,6 +4922,8 @@ lock_rec_queue_validate(
|
||||
ut_ad(lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP,
|
||||
block, heap_no, impl_trx));
|
||||
}
|
||||
|
||||
mutex_exit(&impl_trx->mutex);
|
||||
}
|
||||
|
||||
for (lock = lock_rec_get_first(lock_sys.rec_hash, block, heap_no);
|
||||
@ -4971,12 +4968,7 @@ lock_rec_queue_validate(
|
||||
ut_ad(innodb_lock_schedule_algorithm == INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS ||
|
||||
lock_queue_validate(lock));
|
||||
|
||||
func_exit:
|
||||
if (!locked_lock_trx_sys) {
|
||||
lock_mutex_exit();
|
||||
}
|
||||
|
||||
return(TRUE);
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
@ -5398,30 +5390,24 @@ lock_rec_convert_impl_to_expl_for_trx(
|
||||
trx_t* trx, /*!< in/out: active transaction */
|
||||
ulint heap_no)/*!< in: rec heap number to lock */
|
||||
{
|
||||
ut_ad(trx->is_referenced());
|
||||
ut_ad(page_rec_is_leaf(rec));
|
||||
ut_ad(!rec_is_metadata(rec, index));
|
||||
|
||||
DEBUG_SYNC_C("before_lock_rec_convert_impl_to_expl_for_trx");
|
||||
|
||||
lock_mutex_enter();
|
||||
|
||||
trx_mutex_enter(trx);
|
||||
ut_ad(trx->is_referenced());
|
||||
ut_ad(!trx_state_eq(trx, TRX_STATE_NOT_STARTED));
|
||||
|
||||
if (!trx_state_eq(trx, TRX_STATE_COMMITTED_IN_MEMORY)
|
||||
&& !lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP,
|
||||
block, heap_no, trx)) {
|
||||
|
||||
ulint type_mode;
|
||||
|
||||
type_mode = (LOCK_REC | LOCK_X | LOCK_REC_NOT_GAP);
|
||||
|
||||
lock_rec_add_to_queue(
|
||||
type_mode, block, heap_no, index, trx, FALSE);
|
||||
lock_rec_add_to_queue(LOCK_REC | LOCK_X | LOCK_REC_NOT_GAP,
|
||||
block, heap_no, index, trx, true);
|
||||
}
|
||||
|
||||
lock_mutex_exit();
|
||||
|
||||
trx_mutex_exit(trx);
|
||||
trx->release_reference();
|
||||
|
||||
DEBUG_SYNC_C("after_lock_rec_convert_impl_to_expl_for_trx");
|
||||
@ -5444,13 +5430,17 @@ static my_bool lock_rec_other_trx_holds_expl_callback(
|
||||
mutex_enter(&element->mutex);
|
||||
if (element->trx)
|
||||
{
|
||||
lock_t *expl_lock= lock_rec_has_expl(LOCK_S | LOCK_REC_NOT_GAP, arg->block,
|
||||
arg->heap_no, element->trx);
|
||||
trx_mutex_enter(element->trx);
|
||||
ut_ad(element->trx->state != TRX_STATE_NOT_STARTED);
|
||||
lock_t *expl_lock= element->trx->state == TRX_STATE_COMMITTED_IN_MEMORY
|
||||
? NULL : lock_rec_has_expl(LOCK_S | LOCK_REC_NOT_GAP, arg->block,
|
||||
arg->heap_no, element->trx);
|
||||
/*
|
||||
An explicit lock is held by trx other than the trx holding the implicit
|
||||
lock.
|
||||
*/
|
||||
ut_ad(!expl_lock || expl_lock->trx == arg->impl_trx);
|
||||
trx_mutex_exit(element->trx);
|
||||
}
|
||||
mutex_exit(&element->mutex);
|
||||
return 0;
|
||||
@ -5480,9 +5470,6 @@ static void lock_rec_other_trx_holds_expl(trx_t *caller_trx, trx_t *trx,
|
||||
ut_ad(!page_rec_is_metadata(rec));
|
||||
lock_mutex_enter();
|
||||
ut_ad(trx->is_referenced());
|
||||
/* Prevent a data race with trx_prepare(), which could change the
|
||||
state from ACTIVE to PREPARED. Other state changes should be
|
||||
blocked by lock_mutex_own() and trx->is_referenced(). */
|
||||
trx_mutex_enter(trx);
|
||||
const trx_state_t state = trx->state;
|
||||
trx_mutex_exit(trx);
|
||||
@ -6248,89 +6235,24 @@ lock_unlock_table_autoinc(
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
Releases a transaction's locks, and releases possible other transactions
|
||||
waiting because of these locks. Change the state of the transaction to
|
||||
TRX_STATE_COMMITTED_IN_MEMORY. */
|
||||
void
|
||||
lock_trx_release_locks(
|
||||
/*===================*/
|
||||
trx_t* trx) /*!< in/out: transaction */
|
||||
/** Release the explicit locks of a committing transaction,
|
||||
and release possible other transactions waiting because of these locks. */
|
||||
void lock_trx_release_locks(trx_t* trx)
|
||||
{
|
||||
check_trx_state(trx);
|
||||
ut_ad(trx_state_eq(trx, TRX_STATE_PREPARED)
|
||||
|| trx_state_eq(trx, TRX_STATE_PREPARED_RECOVERED)
|
||||
|| trx_state_eq(trx, TRX_STATE_ACTIVE));
|
||||
|
||||
bool release_lock = UT_LIST_GET_LEN(trx->lock.trx_locks) > 0;
|
||||
|
||||
/* Don't take lock_sys.mutex if trx didn't acquire any lock. */
|
||||
if (release_lock) {
|
||||
|
||||
/* The transition of trx->state to TRX_STATE_COMMITTED_IN_MEMORY
|
||||
is protected by both the lock_sys.mutex and the trx->mutex. */
|
||||
lock_mutex_enter();
|
||||
}
|
||||
|
||||
/* The following assignment makes the transaction committed in memory
|
||||
and makes its changes to data visible to other transactions.
|
||||
NOTE that there is a small discrepancy from the strict formal
|
||||
visibility rules here: a human user of the database can see
|
||||
modifications made by another transaction T even before the necessary
|
||||
log segment has been flushed to the disk. If the database happens to
|
||||
crash before the flush, the user has seen modifications from T which
|
||||
will never be a committed transaction. However, any transaction T2
|
||||
which sees the modifications of the committing transaction T, and
|
||||
which also itself makes modifications to the database, will get an lsn
|
||||
larger than the committing transaction T. In the case where the log
|
||||
flush fails, and T never gets committed, also T2 will never get
|
||||
committed. */
|
||||
|
||||
/*--------------------------------------*/
|
||||
trx_mutex_enter(trx);
|
||||
trx->state = TRX_STATE_COMMITTED_IN_MEMORY;
|
||||
trx_mutex_exit(trx);
|
||||
/*--------------------------------------*/
|
||||
|
||||
if (trx->is_referenced()) {
|
||||
|
||||
ut_a(release_lock);
|
||||
|
||||
lock_mutex_exit();
|
||||
|
||||
while (trx->is_referenced()) {
|
||||
|
||||
DEBUG_SYNC_C("waiting_trx_is_not_referenced");
|
||||
|
||||
/** Doing an implicit to explicit conversion
|
||||
should not be expensive. */
|
||||
ut_delay(srv_spin_wait_delay);
|
||||
}
|
||||
|
||||
lock_mutex_enter();
|
||||
}
|
||||
|
||||
ut_ad(!trx->is_referenced());
|
||||
|
||||
if (release_lock) {
|
||||
|
||||
lock_release(trx);
|
||||
|
||||
lock_mutex_exit();
|
||||
}
|
||||
ut_ad(UT_LIST_GET_LEN(trx->lock.trx_locks));
|
||||
|
||||
lock_mutex_enter();
|
||||
lock_release(trx);
|
||||
trx->lock.n_rec_locks = 0;
|
||||
|
||||
/* We don't remove the locks one by one from the vector for
|
||||
efficiency reasons. We simply reset it because we would have
|
||||
released all the locks anyway. */
|
||||
|
||||
trx->lock.table_locks.clear();
|
||||
|
||||
ut_a(UT_LIST_GET_LEN(trx->lock.trx_locks) == 0);
|
||||
ut_a(ib_vector_is_empty(trx->autoinc_locks));
|
||||
ut_a(trx->lock.table_locks.empty());
|
||||
|
||||
ut_ad(UT_LIST_GET_LEN(trx->lock.trx_locks) == 0);
|
||||
ut_ad(ib_vector_is_empty(trx->autoinc_locks));
|
||||
lock_mutex_exit();
|
||||
mem_heap_empty(trx->lock.lock_heap);
|
||||
}
|
||||
|
||||
@ -6403,21 +6325,26 @@ static my_bool lock_table_locks_lookup(rw_trx_hash_element_t *element,
|
||||
mutex_enter(&element->mutex);
|
||||
if (element->trx)
|
||||
{
|
||||
trx_mutex_enter(element->trx);
|
||||
check_trx_state(element->trx);
|
||||
for (const lock_t *lock= UT_LIST_GET_FIRST(element->trx->lock.trx_locks);
|
||||
lock != NULL;
|
||||
lock= UT_LIST_GET_NEXT(trx_locks, lock))
|
||||
if (element->trx->state != TRX_STATE_COMMITTED_IN_MEMORY)
|
||||
{
|
||||
ut_ad(lock->trx == element->trx);
|
||||
if (lock_get_type_low(lock) == LOCK_REC)
|
||||
for (const lock_t *lock= UT_LIST_GET_FIRST(element->trx->lock.trx_locks);
|
||||
lock != NULL;
|
||||
lock= UT_LIST_GET_NEXT(trx_locks, lock))
|
||||
{
|
||||
ut_ad(!dict_index_is_online_ddl(lock->index) ||
|
||||
dict_index_is_clust(lock->index));
|
||||
ut_ad(lock->index->table != table);
|
||||
ut_ad(lock->trx == element->trx);
|
||||
if (lock_get_type_low(lock) == LOCK_REC)
|
||||
{
|
||||
ut_ad(!dict_index_is_online_ddl(lock->index) ||
|
||||
lock->index->is_primary());
|
||||
ut_ad(lock->index->table != table);
|
||||
}
|
||||
else
|
||||
ut_ad(lock->un_member.tab_lock.table != table);
|
||||
}
|
||||
else
|
||||
ut_ad(lock->un_member.tab_lock.table != table);
|
||||
}
|
||||
trx_mutex_exit(element->trx);
|
||||
}
|
||||
mutex_exit(&element->mutex);
|
||||
return 0;
|
||||
@ -6585,7 +6512,7 @@ DeadlockChecker::start_print()
|
||||
|
||||
if (srv_print_all_deadlocks) {
|
||||
ib::info() << "Transactions deadlock detected, dumping"
|
||||
<< " detailed information.";
|
||||
" detailed information.";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,8 @@ index record.
|
||||
@param[in] index secondary index
|
||||
@param[in] offsets rec_get_offsets(rec, index)
|
||||
@param[in,out] mtr mini-transaction
|
||||
@return the active transaction; trx->release_reference() must be invoked
|
||||
@return the active transaction; state must be rechecked after
|
||||
trx_mutex_enter(), and trx->release_reference() must be invoked
|
||||
@retval NULL if the record was committed */
|
||||
UNIV_INLINE
|
||||
trx_t*
|
||||
@ -90,9 +91,6 @@ row_vers_impl_x_locked_low(
|
||||
mtr_t* mtr)
|
||||
{
|
||||
trx_id_t trx_id;
|
||||
ulint comp;
|
||||
ulint rec_del;
|
||||
const rec_t* version;
|
||||
rec_t* prev_version = NULL;
|
||||
ulint* clust_offsets;
|
||||
mem_heap_t* heap;
|
||||
@ -144,12 +142,12 @@ row_vers_impl_x_locked_low(
|
||||
}
|
||||
}
|
||||
|
||||
comp = page_rec_is_comp(rec);
|
||||
const ulint comp = page_rec_is_comp(rec);
|
||||
ut_ad(index->table == clust_index->table);
|
||||
ut_ad(!!comp == dict_table_is_comp(index->table));
|
||||
ut_ad(!comp == !page_rec_is_comp(clust_rec));
|
||||
|
||||
rec_del = rec_get_deleted_flag(rec, comp);
|
||||
const ulint rec_del = rec_get_deleted_flag(rec, comp);
|
||||
|
||||
if (dict_index_has_virtual(index)) {
|
||||
ulint n_ext;
|
||||
@ -174,7 +172,7 @@ row_vers_impl_x_locked_low(
|
||||
modify rec, and does not necessarily have an implicit x-lock
|
||||
on rec. */
|
||||
|
||||
for (version = clust_rec;; version = prev_version) {
|
||||
for (const rec_t* version = clust_rec;; version = prev_version) {
|
||||
row_ext_t* ext;
|
||||
dtuple_t* row;
|
||||
dtuple_t* entry;
|
||||
@ -194,16 +192,24 @@ row_vers_impl_x_locked_low(
|
||||
heap, &prev_version, NULL,
|
||||
dict_index_has_virtual(index) ? &vrow : NULL, 0);
|
||||
|
||||
trx_mutex_enter(trx);
|
||||
const bool committed = trx_state_eq(
|
||||
trx, TRX_STATE_COMMITTED_IN_MEMORY);
|
||||
trx_mutex_exit(trx);
|
||||
|
||||
/* The oldest visible clustered index version must not be
|
||||
delete-marked, because we never start a transaction by
|
||||
inserting a delete-marked record. */
|
||||
ut_ad(prev_version
|
||||
|| !rec_get_deleted_flag(version, comp)
|
||||
|| !trx_sys.is_registered(caller_trx, trx_id));
|
||||
ut_ad(committed || prev_version
|
||||
|| !rec_get_deleted_flag(version, comp));
|
||||
|
||||
/* Free version and clust_offsets. */
|
||||
mem_heap_free(old_heap);
|
||||
|
||||
if (committed) {
|
||||
goto not_locked;
|
||||
}
|
||||
|
||||
if (prev_version == NULL) {
|
||||
|
||||
/* We reached the oldest visible version without
|
||||
@ -223,6 +229,7 @@ row_vers_impl_x_locked_low(
|
||||
or updated, the leaf page record always is
|
||||
created with a clear delete-mark flag.
|
||||
(We never insert a delete-marked record.) */
|
||||
not_locked:
|
||||
trx->release_reference();
|
||||
trx = 0;
|
||||
}
|
||||
@ -349,14 +356,14 @@ result_check:
|
||||
if (trx->id != prev_trx_id) {
|
||||
/* prev_version was the first version modified by
|
||||
the trx_id transaction: no implicit x-lock */
|
||||
|
||||
trx->release_reference();
|
||||
trx = 0;
|
||||
break;
|
||||
goto not_locked;
|
||||
}
|
||||
}
|
||||
|
||||
DBUG_PRINT("info", ("Implicit lock is held by trx:" TRX_ID_FMT, trx_id));
|
||||
if (trx) {
|
||||
DBUG_PRINT("info", ("Implicit lock is held by trx:" TRX_ID_FMT,
|
||||
trx_id));
|
||||
}
|
||||
|
||||
if (v_heap != NULL) {
|
||||
mem_heap_free(v_heap);
|
||||
@ -372,7 +379,8 @@ index record.
|
||||
@param[in] rec secondary index record
|
||||
@param[in] index secondary index
|
||||
@param[in] offsets rec_get_offsets(rec, index)
|
||||
@return the active transaction; trx->release_reference() must be invoked
|
||||
@return the active transaction; state must be rechecked after
|
||||
trx_mutex_enter(), and trx->release_reference() must be invoked
|
||||
@retval NULL if the record was committed */
|
||||
trx_t*
|
||||
row_vers_impl_x_locked(
|
||||
|
@ -764,6 +764,10 @@ static my_bool trx_rollback_recovered_callback(rw_trx_hash_element_t *element,
|
||||
mutex_enter(&element->mutex);
|
||||
if (trx_t *trx= element->trx)
|
||||
{
|
||||
/* The trx->is_recovered flag and trx->state are set
|
||||
atomically under the protection of the trx->mutex in
|
||||
trx_t::commit_state(). We do not want to accidentally clean up
|
||||
a non-recovered transaction here. */
|
||||
mutex_enter(&trx->mutex);
|
||||
if (trx->is_recovered && trx_state_eq(trx, TRX_STATE_ACTIVE))
|
||||
trx_list->push_back(trx);
|
||||
|
@ -460,10 +460,57 @@ void trx_free(trx_t*& trx)
|
||||
trx = NULL;
|
||||
}
|
||||
|
||||
/** Transition to committed state, to release implicit locks. */
|
||||
inline void trx_t::commit_state()
|
||||
{
|
||||
/* This makes the transaction committed in memory and makes its
|
||||
changes to data visible to other transactions. NOTE that there is a
|
||||
small discrepancy from the strict formal visibility rules here: a
|
||||
user of the database can see modifications made by another
|
||||
transaction T even before the necessary redo log segment has been
|
||||
flushed to the disk. If the database happens to crash before the
|
||||
flush, the user has seen modifications from T which will never be a
|
||||
committed transaction. However, any transaction T2 which sees the
|
||||
modifications of the committing transaction T, and which also itself
|
||||
makes modifications to the database, will get an lsn larger than the
|
||||
committing transaction T. In the case where the log flush fails, and
|
||||
T never gets committed, also T2 will never get committed. */
|
||||
ut_ad(trx_mutex_own(this));
|
||||
ut_ad(state != TRX_STATE_NOT_STARTED);
|
||||
ut_ad(state != TRX_STATE_COMMITTED_IN_MEMORY
|
||||
|| (is_recovered && !UT_LIST_GET_LEN(lock.trx_locks)));
|
||||
state= TRX_STATE_COMMITTED_IN_MEMORY;
|
||||
|
||||
/* If the background thread trx_rollback_or_clean_recovered()
|
||||
is still active then there is a chance that the rollback
|
||||
thread may see this trx as COMMITTED_IN_MEMORY and goes ahead
|
||||
to clean it up calling trx_cleanup_at_db_startup(). This can
|
||||
happen in the case we are committing a trx here that is left
|
||||
in PREPARED state during the crash. Note that commit of the
|
||||
rollback of a PREPARED trx happens in the recovery thread
|
||||
while the rollback of other transactions happen in the
|
||||
background thread. To avoid this race we unconditionally unset
|
||||
the is_recovered flag. */
|
||||
is_recovered= false;
|
||||
ut_ad(id || !is_referenced());
|
||||
}
|
||||
|
||||
/** Release any explicit locks of a committing transaction. */
|
||||
inline void trx_t::release_locks()
|
||||
{
|
||||
DBUG_ASSERT(state == TRX_STATE_COMMITTED_IN_MEMORY);
|
||||
|
||||
if (UT_LIST_GET_LEN(lock.trx_locks))
|
||||
lock_trx_release_locks(this);
|
||||
else
|
||||
lock.table_locks.clear(); // Work around a bug
|
||||
}
|
||||
|
||||
/** At shutdown, frees a transaction object. */
|
||||
void
|
||||
trx_free_at_shutdown(trx_t *trx)
|
||||
{
|
||||
trx_mutex_enter(trx);
|
||||
ut_ad(trx->is_recovered);
|
||||
ut_a(trx_state_eq(trx, TRX_STATE_PREPARED)
|
||||
|| trx_state_eq(trx, TRX_STATE_PREPARED_RECOVERED)
|
||||
@ -477,21 +524,16 @@ trx_free_at_shutdown(trx_t *trx)
|
||||
&& !srv_undo_sources && srv_fast_shutdown))));
|
||||
ut_a(trx->magic_n == TRX_MAGIC_N);
|
||||
|
||||
lock_trx_release_locks(trx);
|
||||
trx->commit_state();
|
||||
trx_mutex_exit(trx);
|
||||
trx->release_locks();
|
||||
trx_undo_free_at_shutdown(trx);
|
||||
|
||||
ut_a(!trx->read_only);
|
||||
|
||||
DBUG_LOG("trx", "Free prepared: " << trx);
|
||||
trx->state = TRX_STATE_NOT_STARTED;
|
||||
|
||||
/* Undo trx_resurrect_table_locks(). */
|
||||
lock_trx_lock_list_init(&trx->lock.trx_locks);
|
||||
|
||||
/* Note: This vector is not guaranteed to be empty because the
|
||||
transaction was never committed and therefore lock_trx_release()
|
||||
was not called. */
|
||||
trx->lock.table_locks.clear();
|
||||
ut_ad(!UT_LIST_GET_LEN(trx->lock.trx_locks));
|
||||
trx->id = 0;
|
||||
|
||||
trx_free(trx);
|
||||
@ -1308,8 +1350,8 @@ trx_commit_in_memory(
|
||||
|
||||
/* Note: We are asserting without holding the lock mutex. But
|
||||
that is OK because this transaction is not waiting and cannot
|
||||
be rolled back and no new locks can (or should not) be added
|
||||
becuase it is flagged as a non-locking read-only transaction. */
|
||||
be rolled back and no new locks can (or should) be added
|
||||
because it is flagged as a non-locking read-only transaction. */
|
||||
|
||||
ut_a(UT_LIST_GET_LEN(trx->lock.trx_locks) == 0);
|
||||
|
||||
@ -1327,30 +1369,35 @@ trx_commit_in_memory(
|
||||
DBUG_LOG("trx", "Autocommit in memory: " << trx);
|
||||
trx->state = TRX_STATE_NOT_STARTED;
|
||||
} else {
|
||||
if (trx->id > 0) {
|
||||
/* For consistent snapshot, we need to remove current
|
||||
transaction from rw_trx_hash before doing commit and
|
||||
releasing locks. */
|
||||
trx_mutex_enter(trx);
|
||||
trx->commit_state();
|
||||
trx_mutex_exit(trx);
|
||||
|
||||
if (trx->id) {
|
||||
trx_sys.deregister_rw(trx);
|
||||
|
||||
/* Wait for any implicit-to-explicit lock
|
||||
conversions to cease, so that there will be no
|
||||
race condition in lock_release(). */
|
||||
while (UNIV_UNLIKELY(trx->is_referenced())) {
|
||||
ut_delay(srv_spin_wait_delay);
|
||||
}
|
||||
|
||||
trx->release_locks();
|
||||
trx->id = 0;
|
||||
} else {
|
||||
ut_ad(trx->read_only || !trx->rsegs.m_redo.rseg);
|
||||
trx->release_locks();
|
||||
}
|
||||
|
||||
lock_trx_release_locks(trx);
|
||||
ut_ad(trx->read_only || !trx->rsegs.m_redo.rseg || trx->id);
|
||||
|
||||
/* Remove the transaction from the list of active
|
||||
transactions now that it no longer holds any user locks. */
|
||||
|
||||
ut_ad(trx_state_eq(trx, TRX_STATE_COMMITTED_IN_MEMORY));
|
||||
DEBUG_SYNC_C("after_trx_committed_in_memory");
|
||||
|
||||
if (trx->read_only || trx->rsegs.m_redo.rseg == NULL) {
|
||||
if (trx->read_only || !trx->rsegs.m_redo.rseg) {
|
||||
MONITOR_INC(MONITOR_TRX_RO_COMMIT);
|
||||
} else {
|
||||
trx_update_mod_tables_timestamp(trx);
|
||||
MONITOR_INC(MONITOR_TRX_RW_COMMIT);
|
||||
}
|
||||
|
||||
trx->id = 0;
|
||||
}
|
||||
|
||||
ut_ad(!trx->rsegs.m_redo.undo);
|
||||
@ -2166,7 +2213,7 @@ int trx_recover_for_mysql(XID *xid_list, uint len)
|
||||
|
||||
struct trx_get_trx_by_xid_callback_arg
|
||||
{
|
||||
XID *xid;
|
||||
const XID *xid;
|
||||
trx_t *trx;
|
||||
};
|
||||
|
||||
@ -2178,6 +2225,7 @@ static my_bool trx_get_trx_by_xid_callback(rw_trx_hash_element_t *element,
|
||||
mutex_enter(&element->mutex);
|
||||
if (trx_t *trx= element->trx)
|
||||
{
|
||||
trx_mutex_enter(trx);
|
||||
if (trx->is_recovered &&
|
||||
(trx_state_eq(trx, TRX_STATE_PREPARED) ||
|
||||
trx_state_eq(trx, TRX_STATE_PREPARED_RECOVERED)) &&
|
||||
@ -2194,23 +2242,19 @@ static my_bool trx_get_trx_by_xid_callback(rw_trx_hash_element_t *element,
|
||||
arg->trx= trx;
|
||||
found= 1;
|
||||
}
|
||||
trx_mutex_exit(trx);
|
||||
}
|
||||
mutex_exit(&element->mutex);
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Finds PREPARED XA transaction by xid.
|
||||
|
||||
trx may have been committed, unless the caller is holding lock_sys.mutex.
|
||||
|
||||
@param[in] xid X/Open XA transaction identifier
|
||||
|
||||
@return trx or NULL; on match, the trx->xid will be invalidated;
|
||||
*/
|
||||
|
||||
trx_t *trx_get_trx_by_xid(XID *xid)
|
||||
/** Look up an X/Open distributed transaction in XA PREPARE state.
|
||||
@param[in] xid X/Open XA transaction identifier
|
||||
@return transaction on match (the trx_t::xid will be invalidated);
|
||||
note that the trx may have been committed before the caller acquires
|
||||
trx_t::mutex
|
||||
@retval NULL if no match */
|
||||
trx_t* trx_get_trx_by_xid(const XID* xid)
|
||||
{
|
||||
trx_get_trx_by_xid_callback_arg arg= { xid, 0 };
|
||||
|
||||
|
@ -1634,7 +1634,7 @@ trx_undo_free_at_shutdown(trx_t *trx)
|
||||
TRX_STATE_COMMITTED_IN_MEMORY));
|
||||
/* fall through */
|
||||
case TRX_UNDO_ACTIVE:
|
||||
/* lock_trx_release_locks() assigns
|
||||
/* trx_t::commit_state() assigns
|
||||
trx->state = TRX_STATE_COMMITTED_IN_MEMORY. */
|
||||
ut_a(!srv_was_started
|
||||
|| srv_read_only_mode
|
||||
@ -1661,7 +1661,7 @@ trx_undo_free_at_shutdown(trx_t *trx)
|
||||
TRX_STATE_COMMITTED_IN_MEMORY));
|
||||
/* fall through */
|
||||
case TRX_UNDO_ACTIVE:
|
||||
/* lock_trx_release_locks() assigns
|
||||
/* trx_t::commit_state() assigns
|
||||
trx->state = TRX_STATE_COMMITTED_IN_MEMORY. */
|
||||
ut_a(!srv_was_started
|
||||
|| srv_read_only_mode
|
||||
|
@ -2785,7 +2785,20 @@ static void reset_thd_trn(THD *thd, MARIA_HA *first_table)
|
||||
THD_TRN= NULL;
|
||||
for (MARIA_HA *table= first_table; table ;
|
||||
table= table->trn_next)
|
||||
{
|
||||
_ma_reset_trn_for_table(table);
|
||||
|
||||
/*
|
||||
If table has changed by this statement, invalidate it from the query
|
||||
cache
|
||||
*/
|
||||
if (table->row_changes != table->start_row_changes)
|
||||
{
|
||||
table->start_row_changes= table->row_changes;
|
||||
DBUG_ASSERT(table->s->chst_invalidator != NULL);
|
||||
(*table->s->chst_invalidator)(table->s->data_file_name.str);
|
||||
}
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@ -3252,7 +3265,10 @@ static int maria_commit(handlerton *hton __attribute__ ((unused)),
|
||||
THD *thd, bool all)
|
||||
{
|
||||
TRN *trn= THD_TRN;
|
||||
int res;
|
||||
MARIA_HA *used_instances= (MARIA_HA*) trn->used_instances;
|
||||
DBUG_ENTER("maria_commit");
|
||||
|
||||
trnman_reset_locked_tables(trn, 0);
|
||||
trnman_set_flags(trn, trnman_get_flags(trn) & ~TRN_STATE_INFO_LOGGED);
|
||||
|
||||
@ -3260,8 +3276,9 @@ static int maria_commit(handlerton *hton __attribute__ ((unused)),
|
||||
if ((thd->variables.option_bits & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
|
||||
!all)
|
||||
DBUG_RETURN(0); // end of statement
|
||||
reset_thd_trn(thd, (MARIA_HA*) trn->used_instances);
|
||||
DBUG_RETURN(ma_commit(trn)); // end of transaction
|
||||
res= ma_commit(trn);
|
||||
reset_thd_trn(thd, used_instances);
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
|
||||
|
@ -641,6 +641,7 @@ struct st_maria_handler
|
||||
invalidator_by_filename invalidator; /* query cache invalidator */
|
||||
ulonglong last_auto_increment; /* auto value at start of statement */
|
||||
ulonglong row_changes; /* Incremented for each change */
|
||||
ulonglong start_row_changes; /* Row changes since start trans */
|
||||
ulong this_unique; /* uniq filenumber or thread */
|
||||
ulong last_unique; /* last unique number */
|
||||
ulong this_loop; /* counter for this open */
|
||||
|
Loading…
x
Reference in New Issue
Block a user