Commit 56adced3 authored by Aleksey Midenkov's avatar Aleksey Midenkov

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

parent f4898655
...@@ -43,6 +43,18 @@ begin ...@@ -43,6 +43,18 @@ begin
return NULL; return NULL;
end~~ 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)) create function if not exists sys_commit_ts(sys_field varchar(255))
returns varchar(255) returns varchar(255)
deterministic deterministic
......
...@@ -4,6 +4,7 @@ drop procedure innodb_verify_vtq; ...@@ -4,6 +4,7 @@ drop procedure innodb_verify_vtq;
drop function default_engine; drop function default_engine;
drop function sys_commit_ts; drop function sys_commit_ts;
drop function sys_datatype; drop function sys_datatype;
drop function current_row;
drop procedure concat_exec2; drop procedure concat_exec2;
drop procedure concat_exec3; drop procedure concat_exec3;
--enable_query_log --enable_query_log
--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
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;
...@@ -66,14 +66,15 @@ set @str= concat(' ...@@ -66,14 +66,15 @@ set @str= concat('
with system versioning with system versioning
engine ', engine); engine ', engine);
prepare stmt from @str; execute stmt; drop prepare stmt; 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; start transaction;
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 = 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 > 3;
update t1 set y= y + 1 where x > 4;
commit; commit;
select x, y from t1 for system_time select x, y, sys_trx_end = 18446744073709551615 as current from t1 for system_time all;
between timestamp '0000-0-0 0:0:0'
and timestamp '2038-01-19 04:14:07';
drop table t1; drop table t1;
end~~ end~~
create procedure test_04( create procedure test_04(
...@@ -285,19 +286,19 @@ call verify_vtq; ...@@ -285,19 +286,19 @@ call verify_vtq;
No A B C D No A B C D
1 1 1 1 1 1 1 1 1 1
2 1 1 1 1 2 1 1 1 1
call test_03('timestamp(6)', 'myisam', 'sys_end'); # Multiple UPDATE of same rows in single transaction create historical
x y # rows only once (applicable to InnoDB only).
1 1
2 1
3 3
3 1
3 2
call test_03('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)'); call test_03('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)');
x y x y current
1 1 1 1 1
2 1 2 2 1
3 3 3 3 1
3 1 4 2 1
5 3 1
3 1 0
2 1 0
4 1 0
5 1 0
call verify_vtq; call verify_vtq;
No A B C D No A B C D
1 1 1 1 1 1 1 1 1 1
......
--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;
...@@ -74,16 +74,17 @@ begin ...@@ -74,16 +74,17 @@ begin
engine ', engine); engine ', engine);
prepare stmt from @str; execute stmt; drop prepare stmt; 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; start transaction;
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 = 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 > 3;
update t1 set y= y + 1 where x > 4;
commit; commit;
select x, y from t1 for system_time select x, y, sys_trx_end = 18446744073709551615 as current from t1 for system_time all;
between timestamp '0000-0-0 0:0:0'
and timestamp '2038-01-19 04:14:07';
drop table t1; drop table t1;
end~~ end~~
...@@ -234,7 +235,8 @@ call test_02('timestamp(6)', 'myisam', 'sys_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 test_02('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)');
call verify_vtq; 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 test_03('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)');
call verify_vtq; call verify_vtq;
......
...@@ -4642,4 +4642,19 @@ bool check_expression(Virtual_column_info *vcol, LEX_CSTRING *name, ...@@ -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_bit_as_char(x) ((x) & FIELDFLAG_TREAT_BIT_AS_CHAR)
#define f_is_hex_escape(x) ((x) & FIELDFLAG_HEX_ESCAPE) #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 */ #endif /* FIELD_INCLUDED */
...@@ -1050,7 +1050,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, ...@@ -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(); table->vers_update_fields();
if ((res= table_list->view_check_option(thd, if ((res= table_list->view_check_option(thd,
...@@ -1937,15 +1937,30 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) ...@@ -1937,15 +1937,30 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
*/ */
if (last_uniq_key(table,key_nr) && if (last_uniq_key(table,key_nr) &&
!table->file->referenced_by_foreign_key() && !table->file->referenced_by_foreign_key() &&
(!table->triggers || !table->triggers->has_delete_triggers()) && (!table->triggers || !table->triggers->has_delete_triggers()))
!table->versioned_by_sql())
{ {
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], if ((error=table->file->ha_update_row(table->record[1],
table->record[0])) && table->record[0])) &&
error != HA_ERR_RECORD_IS_THE_SAME) error != HA_ERR_RECORD_IS_THE_SAME)
goto err; goto err;
if (error != HA_ERR_RECORD_IS_THE_SAME) if (error != HA_ERR_RECORD_IS_THE_SAME)
{
info->deleted++; 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 else
error= 0; error= 0;
thd->record_first_successful_insert_id_in_cur_stmt(table->file->insert_id_for_cur_row); 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) ...@@ -3832,7 +3847,7 @@ int select_insert::send_data(List<Item> &values)
DBUG_RETURN(0); DBUG_RETURN(0);
thd->count_cuted_fields= CHECK_FIELD_WARN; // Calculate cuted fields thd->count_cuted_fields= CHECK_FIELD_WARN; // Calculate cuted fields
if (table->versioned_by_sql()) if (table->versioned())
table->vers_update_fields(); table->vers_update_fields();
store_values(values); store_values(values);
if (table->default_field && table->update_default_fields(0, info.ignore)) if (table->default_field && table->update_default_fields(0, info.ignore))
......
...@@ -781,7 +781,7 @@ int mysql_update(THD *thd, ...@@ -781,7 +781,7 @@ int mysql_update(THD *thd,
TRG_EVENT_UPDATE)) TRG_EVENT_UPDATE))
break; /* purecov: inspected */ break; /* purecov: inspected */
if (has_vers_fields && table->versioned_by_sql()) if (has_vers_fields && table->versioned())
table->vers_update_fields(); table->vers_update_fields();
found++; found++;
...@@ -2195,7 +2195,7 @@ int multi_update::send_data(List<Item> &not_used_values) ...@@ -2195,7 +2195,7 @@ int multi_update::send_data(List<Item> &not_used_values)
if (table->default_field && table->update_default_fields(1, ignore)) if (table->default_field && table->update_default_fields(1, ignore))
DBUG_RETURN(1); DBUG_RETURN(1);
if (has_vers_fields && table->versioned_by_sql()) if (has_vers_fields && table->versioned())
table->vers_update_fields(); table->vers_update_fields();
if ((error= cur_table->view_check_option(thd, ignore)) != if ((error= cur_table->view_check_option(thd, ignore)) !=
...@@ -2550,7 +2550,7 @@ int multi_update::do_updates() ...@@ -2550,7 +2550,7 @@ int multi_update::do_updates()
goto err2; goto err2;
} }
} }
if (has_vers_fields && table->versioned_by_sql()) if (has_vers_fields && table->versioned())
table->vers_update_fields(); table->vers_update_fields();
if ((local_error=table->file->ha_update_row(table->record[1], if ((local_error=table->file->ha_update_row(table->record[1],
......
...@@ -7691,11 +7691,14 @@ void TABLE::vers_update_fields() ...@@ -7691,11 +7691,14 @@ void TABLE::vers_update_fields()
{ {
DBUG_ENTER("vers_update_fields"); DBUG_ENTER("vers_update_fields");
bitmap_set_bit(write_set, vers_start_field()->field_index); if (versioned_by_sql())
bitmap_set_bit(write_set, vers_end_field()->field_index); {
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()) bitmap_set_bit(write_set, vers_end_field()->field_index);
DBUG_ASSERT(0);
vers_end_field()->set_max(); vers_end_field()->set_max();
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
......
...@@ -1546,6 +1546,9 @@ struct TABLE ...@@ -1546,6 +1546,9 @@ struct TABLE
return field[s->row_end_field]; return field[s->row_end_field];
} }
ulonglong vers_start_id() const;
ulonglong vers_end_id() const;
int delete_row(); int delete_row();
/** Number of additional fields used in versioned tables */ /** Number of additional fields used in versioned tables */
......
...@@ -9185,8 +9185,9 @@ ha_innobase::update_row( ...@@ -9185,8 +9185,9 @@ ha_innobase::update_row(
error = row_update_for_mysql(m_prebuilt); error = row_update_for_mysql(m_prebuilt);
if (error == DB_SUCCESS && vers_ins_row if (error == DB_SUCCESS && vers_ins_row
&& trx->id != static_cast<trx_id_t>( /* Multiple UPDATE of same rows in single transaction create
table->vers_start_field()->val_int())) { historical rows only once. */
&& trx->id != table->vers_start_id()) {
error = row_insert_for_mysql((byte*) old_row, error = row_insert_for_mysql((byte*) old_row,
m_prebuilt, m_prebuilt,
ROW_INS_HISTORICAL); ROW_INS_HISTORICAL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment