SQL,IB: REPLACE semantics [#365 bug 8]

This commit is contained in:
Aleksey Midenkov 2017-12-04 12:36:07 +03:00
parent f489865558
commit 56adced376
14 changed files with 135 additions and 34 deletions

View file

@ -43,6 +43,18 @@ begin
return NULL;
end~~
create function if not exists current_row(sys_trx_end varbinary(255))
returns int
deterministic
begin
if default_engine() = 'innodb' then
return sys_trx_end = 18446744073709551615;
elseif default_engine() = 'myisam' then
return sys_trx_end = timestamp'2038-01-19 03:14:07.999999';
end if;
return NULL;
end~~
create function if not exists sys_commit_ts(sys_field varchar(255))
returns varchar(255)
deterministic

View file

@ -4,6 +4,7 @@ drop procedure innodb_verify_vtq;
drop function default_engine;
drop function sys_commit_ts;
drop function sys_datatype;
drop function current_row;
drop procedure concat_exec2;
drop procedure concat_exec3;
--enable_query_log

View file

@ -0,0 +1,2 @@
[unique]
[pk]

View file

@ -0,0 +1,23 @@
--disable_query_log
if ($MTR_COMBINATION_UNIQUE)
{
set @KEY_TYPE= 'unique';
}
if ($MTR_COMBINATION_PK)
{
set @KEY_TYPE= 'primary key';
}
delimiter ~~;
create procedure create_table(name varchar(255), cols varchar(255))
begin
if (cols is null or cols = '') then
set cols= '';
else
set cols= concat(', ', cols);
end if;
set @str= concat('create or replace table ', name, '(id int ', @KEY_TYPE, cols, ') with system versioning');
prepare stmt from @str; execute stmt; drop prepare stmt;
end~~
delimiter ;~~
--enable_query_log

View file

@ -0,0 +1,10 @@
call create_table('t', 'x int');
insert t values (1, 2);
replace t values (1, 3);
select *, current_row(sys_trx_end) as current from t for system_time all
order by x;
id x current
1 2 0
1 3 1
drop database test;
create database test;

View file

@ -66,14 +66,15 @@ set @str= concat('
with system versioning
engine ', engine);
prepare stmt from @str; execute stmt; drop prepare stmt;
insert into t1 (x, y) values (1, 1), (2, 1), (3, 1);
insert into t1 (x, y) values (1, 1), (2, 1), (3, 1), (4, 1), (5, 1);
start transaction;
update t1 set y= y + 1 where x = 3;
update t1 set y= y + 1 where x = 2;
update t1 set y= y + 1 where x = 3;
update t1 set y= y + 1 where x > 3;
update t1 set y= y + 1 where x > 4;
commit;
select x, y from t1 for system_time
between timestamp '0000-0-0 0:0:0'
and timestamp '2038-01-19 04:14:07';
select x, y, sys_trx_end = 18446744073709551615 as current from t1 for system_time all;
drop table t1;
end~~
create procedure test_04(
@ -285,19 +286,19 @@ call verify_vtq;
No A B C D
1 1 1 1 1
2 1 1 1 1
call test_03('timestamp(6)', 'myisam', 'sys_end');
x y
1 1
2 1
3 3
3 1
3 2
# Multiple UPDATE of same rows in single transaction create historical
# rows only once (applicable to InnoDB only).
call test_03('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)');
x y
1 1
2 1
3 3
3 1
x y current
1 1 1
2 2 1
3 3 1
4 2 1
5 3 1
3 1 0
2 1 0
4 1 0
5 1 0
call verify_vtq;
No A B C D
1 1 1 1 1

View file

@ -0,0 +1,13 @@
--source suite/versioning/common.inc
--source suite/versioning/key_type.inc
--source suite/versioning/engines.inc
call create_table('t', 'x int');
insert t values (1, 2);
replace t values (1, 3);
select *, current_row(sys_trx_end) as current from t for system_time all
order by x;
drop database test;
create database test;

View file

@ -74,16 +74,17 @@ begin
engine ', engine);
prepare stmt from @str; execute stmt; drop prepare stmt;
insert into t1 (x, y) values (1, 1), (2, 1), (3, 1);
insert into t1 (x, y) values (1, 1), (2, 1), (3, 1), (4, 1), (5, 1);
start transaction;
update t1 set y= y + 1 where x = 3;
update t1 set y= y + 1 where x = 2;
update t1 set y= y + 1 where x = 3;
update t1 set y= y + 1 where x > 3;
update t1 set y= y + 1 where x > 4;
commit;
select x, y from t1 for system_time
between timestamp '0000-0-0 0:0:0'
and timestamp '2038-01-19 04:14:07';
select x, y, sys_trx_end = 18446744073709551615 as current from t1 for system_time all;
drop table t1;
end~~
@ -234,7 +235,8 @@ call test_02('timestamp(6)', 'myisam', 'sys_end');
call test_02('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)');
call verify_vtq;
call test_03('timestamp(6)', 'myisam', 'sys_end');
--echo # Multiple UPDATE of same rows in single transaction create historical
--echo # rows only once (applicable to InnoDB only).
call test_03('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)');
call verify_vtq;

View file

@ -4642,4 +4642,19 @@ bool check_expression(Virtual_column_info *vcol, LEX_CSTRING *name,
#define f_bit_as_char(x) ((x) & FIELDFLAG_TREAT_BIT_AS_CHAR)
#define f_is_hex_escape(x) ((x) & FIELDFLAG_HEX_ESCAPE)
inline
ulonglong TABLE::vers_end_id() const
{
DBUG_ASSERT(versioned_by_engine());
return static_cast<ulonglong>(vers_end_field()->val_int());
}
inline
ulonglong TABLE::vers_start_id() const
{
DBUG_ASSERT(versioned_by_engine());
return static_cast<ulonglong>(vers_start_field()->val_int());
}
#endif /* FIELD_INCLUDED */

View file

@ -1050,7 +1050,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
}
}
if (table->versioned_by_sql())
if (table->versioned())
table->vers_update_fields();
if ((res= table_list->view_check_option(thd,
@ -1937,15 +1937,30 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
*/
if (last_uniq_key(table,key_nr) &&
!table->file->referenced_by_foreign_key() &&
(!table->triggers || !table->triggers->has_delete_triggers()) &&
!table->versioned_by_sql())
(!table->triggers || !table->triggers->has_delete_triggers()))
{
if (table->versioned_by_engine())
{
bitmap_set_bit(table->write_set, table->vers_start_field()->field_index);
table->vers_start_field()->set_notnull();
table->vers_start_field()->store(0, false);
}
if ((error=table->file->ha_update_row(table->record[1],
table->record[0])) &&
error != HA_ERR_RECORD_IS_THE_SAME)
goto err;
if (error != HA_ERR_RECORD_IS_THE_SAME)
{
info->deleted++;
if (table->versioned_by_sql())
{
store_record(table, record[2]);
error= vers_insert_history_row(table);
restore_record(table, record[2]);
if (error)
goto err;
}
}
else
error= 0;
thd->record_first_successful_insert_id_in_cur_stmt(table->file->insert_id_for_cur_row);
@ -3832,7 +3847,7 @@ int select_insert::send_data(List<Item> &values)
DBUG_RETURN(0);
thd->count_cuted_fields= CHECK_FIELD_WARN; // Calculate cuted fields
if (table->versioned_by_sql())
if (table->versioned())
table->vers_update_fields();
store_values(values);
if (table->default_field && table->update_default_fields(0, info.ignore))

View file

@ -781,7 +781,7 @@ int mysql_update(THD *thd,
TRG_EVENT_UPDATE))
break; /* purecov: inspected */
if (has_vers_fields && table->versioned_by_sql())
if (has_vers_fields && table->versioned())
table->vers_update_fields();
found++;
@ -2195,7 +2195,7 @@ int multi_update::send_data(List<Item> &not_used_values)
if (table->default_field && table->update_default_fields(1, ignore))
DBUG_RETURN(1);
if (has_vers_fields && table->versioned_by_sql())
if (has_vers_fields && table->versioned())
table->vers_update_fields();
if ((error= cur_table->view_check_option(thd, ignore)) !=
@ -2550,7 +2550,7 @@ int multi_update::do_updates()
goto err2;
}
}
if (has_vers_fields && table->versioned_by_sql())
if (has_vers_fields && table->versioned())
table->vers_update_fields();
if ((local_error=table->file->ha_update_row(table->record[1],

View file

@ -7691,11 +7691,14 @@ void TABLE::vers_update_fields()
{
DBUG_ENTER("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_by_sql())
{
bitmap_set_bit(write_set, vers_start_field()->field_index);
if (vers_start_field()->set_time())
DBUG_ASSERT(0);
}
if (vers_start_field()->set_time())
DBUG_ASSERT(0);
bitmap_set_bit(write_set, vers_end_field()->field_index);
vers_end_field()->set_max();
DBUG_VOID_RETURN;

View file

@ -1546,6 +1546,9 @@ public:
return field[s->row_end_field];
}
ulonglong vers_start_id() const;
ulonglong vers_end_id() const;
int delete_row();
/** Number of additional fields used in versioned tables */

View file

@ -9185,8 +9185,9 @@ ha_innobase::update_row(
error = row_update_for_mysql(m_prebuilt);
if (error == DB_SUCCESS && vers_ins_row
&& trx->id != static_cast<trx_id_t>(
table->vers_start_field()->val_int())) {
/* Multiple UPDATE of same rows in single transaction create
historical rows only once. */
&& trx->id != table->vers_start_id()) {
error = row_insert_for_mysql((byte*) old_row,
m_prebuilt,
ROW_INS_HISTORICAL);