summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Midenkov <midenok@gmail.com>2017-12-20 16:12:32 +0300
committerAleksey Midenkov <midenok@gmail.com>2017-12-20 16:12:32 +0300
commit7eff2080fdd5be9175e26479222b36e3ae475e09 (patch)
tree58323b9abaf687d8720a04f672f9f2ecb7e15a46
parentc5d0c38efce836c3c87b520880e2b119dc41f4f7 (diff)
downloadmariadb-git-7eff2080fdd5be9175e26479222b36e3ae475e09.tar.gz
MDEV-14687 DELETE HISTORY in prepared stmt crash [fixes #421]
Also fixes broken truncate after 617e108fb6e2bc24e5c9badb94e7d8eaa65d8851
-rw-r--r--mysql-test/suite/versioning/r/truncate.result22
-rw-r--r--mysql-test/suite/versioning/t/truncate.test21
-rw-r--r--sql/share/errmsg-utf8.txt4
-rw-r--r--sql/sql_delete.cc30
4 files changed, 52 insertions, 25 deletions
diff --git a/mysql-test/suite/versioning/r/truncate.result b/mysql-test/suite/versioning/r/truncate.result
index 7c368b99a15..238d7d97bad 100644
--- a/mysql-test/suite/versioning/r/truncate.result
+++ b/mysql-test/suite/versioning/r/truncate.result
@@ -28,15 +28,23 @@ select * from t for system_time all;
a
11
22
-1
2
-delete history from t before system_time timestamp now(6);
+prepare stmt from 'delete history from t before system_time timestamp now(6)';
+execute stmt;
+drop prepare stmt;
select * from t for system_time all;
a
11
22
-1
-2
+delete from t;
+create or replace procedure truncate_sp()
+begin
+delete history from t before system_time timestamp now(6);
+end~~
+call truncate_sp;
+select * from t for system_time all;
+a
+drop procedure truncate_sp;
### Issue #399, truncate partitioned table is now unimplemented
create or replace table t (a int)
with system versioning
@@ -50,12 +58,14 @@ create or replace table t (i int) with system versioning;
delete history from t before system_time now();
create or replace view v as select * from t;
delete history from v before system_time now();
-ERROR HY000: TRUNCATE table_name TO doesn't work with VIEWs
+ERROR HY000: DELETE HISTORY from VIEW is prohibited
create or replace table t (i int);
delete history from t before system_time now();
ERROR HY000: Table `t` is not system-versioned
create or replace view v as select * from t;
delete history from v before system_time now();
-ERROR HY000: TRUNCATE table_name TO doesn't work with VIEWs
+ERROR HY000: DELETE HISTORY from VIEW is prohibited
+prepare stmt from 'delete history from t before system_time now()';
+ERROR HY000: Table `t` is not system-versioned
drop table t;
drop view v;
diff --git a/mysql-test/suite/versioning/t/truncate.test b/mysql-test/suite/versioning/t/truncate.test
index 9623ee0d310..3b209364d7a 100644
--- a/mysql-test/suite/versioning/t/truncate.test
+++ b/mysql-test/suite/versioning/t/truncate.test
@@ -25,8 +25,21 @@ update t set a=22 where a=2;
select * from t for system_time all;
delete history from t before system_time timestamp @ts1;
select * from t for system_time all;
-delete history from t before system_time timestamp now(6);
+prepare stmt from 'delete history from t before system_time timestamp now(6)';
+execute stmt; drop prepare stmt;
select * from t for system_time all;
+delete from t;
+
+delimiter ~~;
+create or replace procedure truncate_sp()
+begin
+ delete history from t before system_time timestamp now(6);
+end~~
+delimiter ;~~
+call truncate_sp;
+select * from t for system_time all;
+
+drop procedure truncate_sp;
--echo ### Issue #399, truncate partitioned table is now unimplemented
@@ -43,15 +56,17 @@ delete history from t before system_time current_timestamp;
create or replace table t (i int) with system versioning;
delete history from t before system_time now();
create or replace view v as select * from t;
---error ER_VERS_TRUNCATE_TO_VIEW
+--error ER_VERS_TRUNCATE_VIEW
delete history from v before system_time now();
create or replace table t (i int);
--error ER_VERS_NOT_VERSIONED
delete history from t before system_time now();
create or replace view v as select * from t;
---error ER_VERS_TRUNCATE_TO_VIEW
+--error ER_VERS_TRUNCATE_VIEW
delete history from v before system_time now();
+--error ER_VERS_NOT_VERSIONED
+prepare stmt from 'delete history from t before system_time now()';
drop table t;
drop view v;
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index f76efb95185..3fe0d33dc03 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -7930,5 +7930,5 @@ ER_VERS_ALREADY_VERSIONED
WARN_VERS_TRT_EXPERIMENTAL
eng "Transaction-based system versioning is EXPERIMENTAL and is subject to change in future."
-ER_VERS_TRUNCATE_TO_VIEW
- eng "TRUNCATE table_name TO doesn't work with VIEWs"
+ER_VERS_TRUNCATE_VIEW
+ eng "DELETE HISTORY from VIEW is prohibited"
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index fcd5708863a..42ff093ce0a 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -223,25 +223,21 @@ bool Update_plan::save_explain_data_intern(MEM_ROOT *mem_root,
static bool record_should_be_deleted(THD *thd, TABLE *table, SQL_SELECT *sel,
- Explain_delete *explain)
+ Explain_delete *explain, bool truncate_history)
{
+ bool check_delete= true;
+
if (table->versioned())
{
- bool row_is_alive= table->vers_end_field()->is_max();
- /* If we are doing TRUNCATE TABLE with SYSTEM_TIME condition then historical
- record is deleted and current record is kept. Otherwise alive record is
- deleted and historical record is kept. */
- if ((thd->lex->sql_command == SQLCOM_TRUNCATE && table->pos_in_table_list->vers_conditions)
- ? row_is_alive
- : !row_is_alive)
- return false;
+ bool historical= !table->vers_end_field()->is_max();
+ check_delete= truncate_history ? historical : !historical;
}
explain->tracker.on_record_read();
thd->inc_examined_row_count(1);
if (table->vfield)
(void) table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_DELETE);
- if (!sel || sel->skip_record(thd) > 0)
+ if (check_delete && (!sel || sel->skip_record(thd) > 0))
{
explain->tracker.on_record_after_where();
return true;
@@ -314,7 +310,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
{
if (table_list->is_view_or_derived())
{
- my_error(ER_VERS_TRUNCATE_TO_VIEW, MYF(0));
+ my_error(ER_VERS_TRUNCATE_VIEW, MYF(0));
DBUG_RETURN(true);
}
@@ -329,7 +325,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
}
#endif
- DBUG_ASSERT(!conds);
+ DBUG_ASSERT(!conds || thd->stmt_arena->is_stmt_execute());
if (select_lex->vers_setup_conds(thd, table_list, &conds))
DBUG_RETURN(TRUE);
@@ -708,7 +704,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
while (!(error=info.read_record()) && !thd->killed &&
! thd->is_error())
{
- if (record_should_be_deleted(thd, table, select, explain))
+ if (record_should_be_deleted(thd, table, select, explain, truncate_history))
{
table->file->position(table->record[0]);
if ((error= deltempfile->unique_add((char*) table->file->ref)))
@@ -735,7 +731,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
! thd->is_error())
{
if (delete_while_scanning)
- delete_record= record_should_be_deleted(thd, table, select, explain);
+ delete_record= record_should_be_deleted(thd, table, select, explain,
+ truncate_history);
if (delete_record)
{
if (!truncate_history && table->triggers &&
@@ -945,6 +942,11 @@ l
select_lex->leaf_tables, FALSE,
DELETE_ACL, SELECT_ACL, TRUE))
DBUG_RETURN(TRUE);
+ if (table_list->vers_conditions &&
+ select_lex->vers_setup_conds(thd, table_list, conds))
+ {
+ DBUG_RETURN(TRUE);
+ }
if ((wild_num && setup_wild(thd, table_list, field_list, NULL, wild_num)) ||
setup_fields(thd, Ref_ptr_array(),
field_list, MARK_COLUMNS_READ, NULL, NULL, 0) ||