mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
Merge 10.3 into 10.4
This commit is contained in:
12
mysql-test/suite/sql_sequence/kill.result
Normal file
12
mysql-test/suite/sql_sequence/kill.result
Normal file
@ -0,0 +1,12 @@
|
||||
#
|
||||
# MDEV-16929 Assertion ... in close_thread_tables upon killing connection
|
||||
# running SHOW on sequence
|
||||
#
|
||||
CREATE SEQUENCE s ENGINE=InnoDB;
|
||||
RENAME TABLE s TO s1;
|
||||
connect con1,localhost,root,,test;
|
||||
SHOW CREATE SEQUENCE s1;
|
||||
connection default;
|
||||
KILL thread_id;
|
||||
connection default;
|
||||
drop sequence s1;
|
20
mysql-test/suite/sql_sequence/kill.test
Normal file
20
mysql-test/suite/sql_sequence/kill.test
Normal file
@ -0,0 +1,20 @@
|
||||
--source include/have_innodb.inc
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-16929 Assertion ... in close_thread_tables upon killing connection
|
||||
--echo # running SHOW on sequence
|
||||
--echo #
|
||||
|
||||
CREATE SEQUENCE s ENGINE=InnoDB;
|
||||
RENAME TABLE s TO s1;
|
||||
--connect (con1,localhost,root,,test)
|
||||
--let $conid= `SELECT CONNECTION_ID()`
|
||||
--send
|
||||
SHOW CREATE SEQUENCE s1;
|
||||
--connection default
|
||||
--replace_result $conid thread_id
|
||||
--eval KILL $conid
|
||||
|
||||
# Cleanup
|
||||
--connection default
|
||||
drop sequence s1;
|
@ -319,3 +319,34 @@ create or replace table t1 (f point, key(f)) with system versioning engine=myisa
|
||||
update t1 set f = null where f = 'foo';
|
||||
ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
|
||||
drop table t1;
|
||||
#
|
||||
# MDEV-22061 InnoDB: Assertion of missing row in sec index row_start upon REPLACE on a system-versioned table
|
||||
#
|
||||
create or replace table t1 (
|
||||
a int,
|
||||
b int,
|
||||
row_start bigint(20) unsigned generated always as row start,
|
||||
row_end bigint(20) unsigned generated always as row end,
|
||||
unique key (b,row_end),
|
||||
key (row_start),
|
||||
period for system_time (row_start,row_end)
|
||||
) engine=innodb with system versioning;
|
||||
insert into t1 (a, b) values (1, 2);
|
||||
replace into t1 (a, b) values (3, 2);
|
||||
replace into t1 (a, b) values (4, 2);
|
||||
drop table t1;
|
||||
#
|
||||
# MDEV-20661 Virtual fields are not recalculated on system fields value assignment
|
||||
#
|
||||
create table t1 (
|
||||
a int,
|
||||
row_start SYS_DATATYPE as row start invisible,
|
||||
row_end SYS_DATATYPE as row end invisible,
|
||||
period for system_time (row_start, row_end),
|
||||
v1 bigint unsigned as (a ^ row_start) unique,
|
||||
v2 bigint unsigned as (a ^ row_end) unique
|
||||
) engine=innodb with system versioning;
|
||||
insert into t1 (a) values (1), (2);
|
||||
update ignore t1 set a= 3;
|
||||
delete history from t1;
|
||||
drop table t1;
|
||||
|
@ -245,4 +245,45 @@ update t1 set f = null where f = 'foo';
|
||||
# cleanup
|
||||
drop table t1;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-22061 InnoDB: Assertion of missing row in sec index row_start upon REPLACE on a system-versioned table
|
||||
--echo #
|
||||
create or replace table t1 (
|
||||
a int,
|
||||
b int,
|
||||
row_start bigint(20) unsigned generated always as row start,
|
||||
row_end bigint(20) unsigned generated always as row end,
|
||||
unique key (b,row_end),
|
||||
key (row_start),
|
||||
period for system_time (row_start,row_end)
|
||||
) engine=innodb with system versioning;
|
||||
|
||||
insert into t1 (a, b) values (1, 2);
|
||||
replace into t1 (a, b) values (3, 2);
|
||||
replace into t1 (a, b) values (4, 2);
|
||||
|
||||
# cleanup
|
||||
drop table t1;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-20661 Virtual fields are not recalculated on system fields value assignment
|
||||
--echo #
|
||||
|
||||
replace_result $sys_datatype_expl SYS_DATATYPE;
|
||||
eval create table t1 (
|
||||
a int,
|
||||
row_start $sys_datatype_expl as row start invisible,
|
||||
row_end $sys_datatype_expl as row end invisible,
|
||||
period for system_time (row_start, row_end),
|
||||
v1 bigint unsigned as (a ^ row_start) unique,
|
||||
v2 bigint unsigned as (a ^ row_end) unique
|
||||
) engine=innodb with system versioning;
|
||||
|
||||
insert into t1 (a) values (1), (2);
|
||||
update ignore t1 set a= 3;
|
||||
delete history from t1;
|
||||
|
||||
# cleanup
|
||||
drop table t1;
|
||||
|
||||
source suite/versioning/common_finish.inc;
|
||||
|
@ -1682,6 +1682,10 @@ int vers_insert_history_row(TABLE *table)
|
||||
if (row_start->cmp(row_start->ptr, row_end->ptr) >= 0)
|
||||
return 0;
|
||||
|
||||
if (table->vfield &&
|
||||
table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_READ))
|
||||
return HA_ERR_GENERIC;
|
||||
|
||||
return table->file->ha_write_row(table->record[0]);
|
||||
}
|
||||
|
||||
|
@ -485,6 +485,10 @@ int SEQUENCE::read_initial_values(TABLE *table)
|
||||
if (mdl_lock_used)
|
||||
thd->mdl_context.release_lock(mdl_request.ticket);
|
||||
write_unlock(table);
|
||||
|
||||
if (!has_active_transaction && !thd->transaction.stmt.is_empty() &&
|
||||
!thd->in_sub_stmt)
|
||||
trans_commit_stmt(thd);
|
||||
DBUG_RETURN(HA_ERR_LOCK_WAIT_TIMEOUT);
|
||||
}
|
||||
DBUG_ASSERT(table->reginfo.lock_type == TL_READ);
|
||||
|
25
sql/table.cc
25
sql/table.cc
@ -8546,29 +8546,24 @@ void TABLE::vers_update_fields()
|
||||
bitmap_set_bit(write_set, vers_start_field()->field_index);
|
||||
bitmap_set_bit(write_set, vers_end_field()->field_index);
|
||||
|
||||
if (versioned(VERS_TIMESTAMP))
|
||||
if (!vers_write)
|
||||
{
|
||||
if (!vers_write)
|
||||
{
|
||||
file->column_bitmaps_signal();
|
||||
return;
|
||||
}
|
||||
if (vers_start_field()->store_timestamp(in_use->query_start(),
|
||||
in_use->query_start_sec_part()))
|
||||
DBUG_ASSERT(0);
|
||||
file->column_bitmaps_signal();
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
if (versioned(VERS_TIMESTAMP) &&
|
||||
vers_start_field()->store_timestamp(in_use->query_start(),
|
||||
in_use->query_start_sec_part()))
|
||||
{
|
||||
if (!vers_write)
|
||||
{
|
||||
file->column_bitmaps_signal();
|
||||
return;
|
||||
}
|
||||
DBUG_ASSERT(0);
|
||||
}
|
||||
|
||||
vers_end_field()->set_max();
|
||||
bitmap_set_bit(read_set, vers_end_field()->field_index);
|
||||
file->column_bitmaps_signal();
|
||||
if (vfield)
|
||||
update_virtual_fields(file, VCOL_UPDATE_FOR_READ);
|
||||
}
|
||||
|
||||
|
||||
|
@ -21707,3 +21707,70 @@ ib_push_frm_error(
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Writes 8 bytes to nth tuple field
|
||||
@param[in] tuple where to write
|
||||
@param[in] nth index in tuple
|
||||
@param[in] data what to write
|
||||
@param[in] buf field data buffer */
|
||||
static void set_tuple_col_8(dtuple_t *tuple, int col, uint64_t data, byte *buf)
|
||||
{
|
||||
dfield_t *dfield= dtuple_get_nth_field(tuple, col);
|
||||
ut_ad(dfield->type.len == 8);
|
||||
if (dfield->len == UNIV_SQL_NULL)
|
||||
{
|
||||
dfield_set_data(dfield, buf, 8);
|
||||
}
|
||||
ut_ad(dfield->len == dfield->type.len && dfield->data);
|
||||
mach_write_to_8(dfield->data, data);
|
||||
}
|
||||
|
||||
void ins_node_t::vers_update_end(row_prebuilt_t *prebuilt, bool history_row)
|
||||
{
|
||||
ut_ad(prebuilt->ins_node == this);
|
||||
trx_t *trx= prebuilt->trx;
|
||||
#ifndef DBUG_OFF
|
||||
ut_ad(table->vers_start != table->vers_end);
|
||||
const mysql_row_templ_t *t= prebuilt->get_template_by_col(table->vers_end);
|
||||
ut_ad(t);
|
||||
ut_ad(t->mysql_col_len == 8);
|
||||
#endif
|
||||
|
||||
if (history_row)
|
||||
{
|
||||
set_tuple_col_8(row, table->vers_end, trx->id, vers_end_buf);
|
||||
}
|
||||
else /* ROW_INS_VERSIONED */
|
||||
{
|
||||
set_tuple_col_8(row, table->vers_end, TRX_ID_MAX, vers_end_buf);
|
||||
#ifndef DBUG_OFF
|
||||
t= prebuilt->get_template_by_col(table->vers_start);
|
||||
ut_ad(t);
|
||||
ut_ad(t->mysql_col_len == 8);
|
||||
#endif
|
||||
set_tuple_col_8(row, table->vers_start, trx->id, vers_start_buf);
|
||||
}
|
||||
dict_index_t *clust_index= dict_table_get_first_index(table);
|
||||
THD *thd= trx->mysql_thd;
|
||||
TABLE *mysql_table= prebuilt->m_mysql_table;
|
||||
mem_heap_t *local_heap= NULL;
|
||||
for (ulint col_no= 0; col_no < dict_table_get_n_v_cols(table); col_no++)
|
||||
{
|
||||
|
||||
const dict_v_col_t *v_col= dict_table_get_nth_v_col(table, col_no);
|
||||
for (ulint i= 0; i < unsigned(v_col->num_base); i++)
|
||||
{
|
||||
dict_col_t *base_col= v_col->base_col[i];
|
||||
if (base_col->ind == table->vers_end)
|
||||
{
|
||||
innobase_get_computed_value(row, v_col, clust_index, &local_heap,
|
||||
table->heap, NULL, thd, mysql_table,
|
||||
mysql_table->record[0], NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (local_heap)
|
||||
{
|
||||
mem_heap_free(local_heap);
|
||||
}
|
||||
}
|
||||
|
@ -163,6 +163,8 @@ row_ins_step(
|
||||
#define INS_NODE_INSERT_ENTRIES 3 /* index entries should be built and
|
||||
inserted */
|
||||
|
||||
struct row_prebuilt_t;
|
||||
|
||||
/** Insert node structure */
|
||||
struct ins_node_t
|
||||
{
|
||||
@ -203,6 +205,7 @@ struct ins_node_t
|
||||
entry_list and sys fields are stored here;
|
||||
if this is NULL, entry list should be created
|
||||
and buffers for sys fields in row allocated */
|
||||
void vers_update_end(row_prebuilt_t *prebuilt, bool history_row);
|
||||
};
|
||||
|
||||
/** Create an insert object.
|
||||
|
@ -429,7 +429,32 @@ struct upd_t{
|
||||
fields[n_fields++] = field;
|
||||
}
|
||||
|
||||
/** Determine if the given field_no is modified.
|
||||
void remove_element(ulint i)
|
||||
{
|
||||
ut_ad(n_fields > 0);
|
||||
ut_ad(i < n_fields);
|
||||
while (i < n_fields - 1)
|
||||
{
|
||||
fields[i]= fields[i + 1];
|
||||
i++;
|
||||
}
|
||||
n_fields--;
|
||||
}
|
||||
|
||||
bool remove(const ulint field_no)
|
||||
{
|
||||
for (ulint i= 0; i < n_fields; ++i)
|
||||
{
|
||||
if (field_no == fields[i].field_no)
|
||||
{
|
||||
remove_element(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Determine if the given field_no is modified.
|
||||
@return true if modified, false otherwise. */
|
||||
bool is_modified(const ulint field_no) const
|
||||
{
|
||||
@ -569,25 +594,25 @@ private:
|
||||
make_versioned_delete().
|
||||
@param[in] trx transaction
|
||||
@param[in] vers_sys_idx table->row_start or table->row_end */
|
||||
void make_versioned_helper(const trx_t* trx, ulint idx);
|
||||
void vers_update_fields(const trx_t *trx, ulint idx);
|
||||
|
||||
public:
|
||||
/** Also set row_start = CURRENT_TIMESTAMP/trx->id
|
||||
@param[in] trx transaction */
|
||||
void make_versioned_update(const trx_t* trx)
|
||||
{
|
||||
make_versioned_helper(trx, table->vers_start);
|
||||
}
|
||||
void vers_make_update(const trx_t *trx)
|
||||
{
|
||||
vers_update_fields(trx, table->vers_start);
|
||||
}
|
||||
|
||||
/** Only set row_end = CURRENT_TIMESTAMP/trx->id.
|
||||
Do not touch other fields at all.
|
||||
@param[in] trx transaction */
|
||||
void make_versioned_delete(const trx_t* trx)
|
||||
{
|
||||
void vers_make_delete(const trx_t *trx)
|
||||
{
|
||||
update->n_fields = 0;
|
||||
is_delete = VERSIONED_DELETE;
|
||||
make_versioned_helper(trx, table->vers_end);
|
||||
}
|
||||
vers_update_fields(trx, table->vers_end);
|
||||
}
|
||||
};
|
||||
|
||||
#define UPD_NODE_MAGIC_N 1579975
|
||||
|
@ -1332,23 +1332,6 @@ row_mysql_get_table_status(
|
||||
return(err);
|
||||
}
|
||||
|
||||
/** Writes 8 bytes to nth tuple field
|
||||
@param[in] tuple where to write
|
||||
@param[in] nth index in tuple
|
||||
@param[in] data what to write
|
||||
@param[in] buf field data buffer */
|
||||
static
|
||||
void
|
||||
set_tuple_col_8(dtuple_t* tuple, int col, uint64_t data, byte* buf) {
|
||||
dfield_t* dfield = dtuple_get_nth_field(tuple, col);
|
||||
ut_ad(dfield->type.len == 8);
|
||||
if (dfield->len == UNIV_SQL_NULL) {
|
||||
dfield_set_data(dfield, buf, 8);
|
||||
}
|
||||
ut_ad(dfield->len == dfield->type.len && dfield->data);
|
||||
mach_write_to_8(dfield->data, data);
|
||||
}
|
||||
|
||||
/** Does an insert for MySQL.
|
||||
@param[in] mysql_rec row in the MySQL format
|
||||
@param[in,out] prebuilt prebuilt struct in MySQL handle
|
||||
@ -1416,29 +1399,8 @@ row_insert_for_mysql(
|
||||
&blob_heap);
|
||||
|
||||
if (ins_mode != ROW_INS_NORMAL) {
|
||||
#ifndef DBUG_OFF
|
||||
ut_ad(table->vers_start != table->vers_end);
|
||||
const mysql_row_templ_t* t
|
||||
= prebuilt->get_template_by_col(table->vers_end);
|
||||
ut_ad(t);
|
||||
ut_ad(t->mysql_col_len == 8);
|
||||
#endif
|
||||
|
||||
if (ins_mode == ROW_INS_HISTORICAL) {
|
||||
set_tuple_col_8(node->row, table->vers_end, trx->id,
|
||||
node->vers_end_buf);
|
||||
} else /* ROW_INS_VERSIONED */ {
|
||||
set_tuple_col_8(node->row, table->vers_end, TRX_ID_MAX,
|
||||
node->vers_end_buf);
|
||||
#ifndef DBUG_OFF
|
||||
t = prebuilt->get_template_by_col(table->vers_start);
|
||||
ut_ad(t);
|
||||
ut_ad(t->mysql_col_len == 8);
|
||||
#endif
|
||||
set_tuple_col_8(node->row, table->vers_start, trx->id,
|
||||
node->vers_start_buf);
|
||||
}
|
||||
}
|
||||
node->vers_update_end(prebuilt, ins_mode == ROW_INS_HISTORICAL);
|
||||
}
|
||||
|
||||
savept = trx_savept_take(trx);
|
||||
|
||||
@ -1872,10 +1834,10 @@ row_update_for_mysql(row_prebuilt_t* prebuilt)
|
||||
|
||||
if (prebuilt->versioned_write) {
|
||||
if (node->is_delete == VERSIONED_DELETE) {
|
||||
node->make_versioned_delete(trx);
|
||||
} else if (node->update->affects_versioned()) {
|
||||
node->make_versioned_update(trx);
|
||||
}
|
||||
node->vers_make_delete(trx);
|
||||
} else if (node->update->affects_versioned()) {
|
||||
node->vers_make_update(trx);
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
@ -2240,14 +2202,14 @@ row_update_cascade_for_mysql(
|
||||
|
||||
if (table->versioned()) {
|
||||
if (node->is_delete == PLAIN_DELETE) {
|
||||
node->make_versioned_delete(trx);
|
||||
} else if (node->update->affects_versioned()) {
|
||||
node->vers_make_delete(trx);
|
||||
} else if (node->update->affects_versioned()) {
|
||||
dberr_t err = row_update_vers_insert(thr, node);
|
||||
if (err != DB_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
node->make_versioned_update(trx);
|
||||
}
|
||||
node->vers_make_update(trx);
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
|
@ -3477,32 +3477,65 @@ Supposed to be called only by make_versioned_update() and
|
||||
make_versioned_delete().
|
||||
@param[in] trx transaction
|
||||
@param[in] vers_sys_idx table->row_start or table->row_end */
|
||||
void upd_node_t::make_versioned_helper(const trx_t* trx, ulint idx)
|
||||
void upd_node_t::vers_update_fields(const trx_t *trx, ulint idx)
|
||||
{
|
||||
ut_ad(in_mysql_interface); // otherwise needs to recalculate
|
||||
// node->cmpl_info
|
||||
ut_ad(idx == table->vers_start || idx == table->vers_end);
|
||||
|
||||
dict_index_t* clust_index = dict_table_get_first_index(table);
|
||||
const dict_col_t *col= dict_table_get_nth_col(table, idx);
|
||||
ulint field_no= dict_col_get_clust_pos(col, clust_index);
|
||||
upd_field_t *ufield;
|
||||
|
||||
/* row_create_update_node_for_mysql() pre-allocated this much.
|
||||
for (ulint i= 0; i < update->n_fields; ++i)
|
||||
{
|
||||
if (update->fields[i].field_no == field_no)
|
||||
{
|
||||
ufield= &update->fields[i];
|
||||
goto skip_append;
|
||||
}
|
||||
}
|
||||
|
||||
/* row_create_update_node_for_mysql() pre-allocated this much.
|
||||
At least one PK column always remains unchanged. */
|
||||
ut_ad(update->n_fields < ulint(table->n_cols + table->n_v_cols));
|
||||
|
||||
update->n_fields++;
|
||||
upd_field_t* ufield = upd_get_nth_field(update, update->n_fields - 1);
|
||||
const dict_col_t* col = dict_table_get_nth_col(table, idx);
|
||||
ufield= upd_get_nth_field(update, update->n_fields - 1);
|
||||
upd_field_set_field_no(ufield, field_no, clust_index);
|
||||
|
||||
upd_field_set_field_no(ufield, dict_col_get_clust_pos(col, clust_index),
|
||||
clust_index);
|
||||
skip_append:
|
||||
char *where= reinterpret_cast<char *>(update->vers_sys_value);
|
||||
if (col->vers_native())
|
||||
{
|
||||
mach_write_to_8(where, trx->id);
|
||||
}
|
||||
else
|
||||
{
|
||||
thd_get_query_start_data(trx->mysql_thd, where);
|
||||
}
|
||||
|
||||
char* where = reinterpret_cast<char*>(update->vers_sys_value);
|
||||
if (col->vers_native()) {
|
||||
mach_write_to_8(where, trx->id);
|
||||
} else {
|
||||
thd_get_query_start_data(trx->mysql_thd, where);
|
||||
}
|
||||
dfield_set_data(&ufield->new_val, update->vers_sys_value, col->len);
|
||||
|
||||
dfield_set_data(&ufield->new_val, update->vers_sys_value, col->len);
|
||||
for (ulint col_no= 0; col_no < dict_table_get_n_v_cols(table); col_no++)
|
||||
{
|
||||
|
||||
const dict_v_col_t *v_col= dict_table_get_nth_v_col(table, col_no);
|
||||
if (!v_col->m_col.ord_part)
|
||||
continue;
|
||||
for (ulint i= 0; i < unsigned(v_col->num_base); i++)
|
||||
{
|
||||
dict_col_t *base_col= v_col->base_col[i];
|
||||
if (base_col->ind == col->ind)
|
||||
{
|
||||
/* Virtual column depends on system field value
|
||||
which we updated above. Remove it from update
|
||||
vector, so it is recalculated in
|
||||
row_upd_store_v_row() (see !update branch). */
|
||||
update->remove(v_col->v_pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1288,7 +1288,8 @@ trx_update_mod_tables_timestamp(
|
||||
dict_table_t* table = it->first;
|
||||
table->update_time = now;
|
||||
#ifdef UNIV_DEBUG
|
||||
if (preserve_tables || table->get_ref_count()) {
|
||||
if (preserve_tables || table->get_ref_count()
|
||||
|| UT_LIST_GET_LEN(table->locks)) {
|
||||
/* do not evict when committing DDL operations
|
||||
or if some other transaction is holding the
|
||||
table handle */
|
||||
@ -1297,7 +1298,11 @@ trx_update_mod_tables_timestamp(
|
||||
/* recheck while holding the mutex that blocks
|
||||
table->acquire() */
|
||||
mutex_enter(&dict_sys.mutex);
|
||||
if (!table->get_ref_count()) {
|
||||
mutex_enter(&lock_sys.mutex);
|
||||
const bool do_evict = !table->get_ref_count()
|
||||
&& !UT_LIST_GET_LEN(table->locks);
|
||||
mutex_exit(&lock_sys.mutex);
|
||||
if (do_evict) {
|
||||
dict_sys.remove(table, true);
|
||||
}
|
||||
mutex_exit(&dict_sys.mutex);
|
||||
|
Reference in New Issue
Block a user