summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Malyavin <nikitamalyavin@gmail.com>2019-03-13 22:25:48 +1000
committerSergei Golubchik <serg@mariadb.org>2019-04-02 11:03:32 +0200
commit04055060b6fa29e72a7e851486085bd59e708614 (patch)
treeaf1810b46a882e96b12917ef59729b5b987a28eb
parent74c9872a9aae825ca6ab73feff048ff2ccb4beb8 (diff)
downloadmariadb-git-04055060b6fa29e72a7e851486085bd59e708614.tar.gz
MDEV-18852 MDEV-18853 fix `period.delete`, `period.update` tests crashes with ``--ps-protocol`
The main problem was lack of proper QueryArena handling in `period_setup_conds`. Since mysql_prepare_update/mysql_prepare_delete are called during `PREPARE` statement, period conditions, should be allocated on statement query arena. Another problem is incorrect statement state handling in period_setup_conds, which led to unexpected mysql_update termination. * mysql_update: move period_setup_conds() to mysql_prepare_update to store conditions in statement's mem_root * mtr: add period suite to default list, since --ps-protocol is now fixed Fixes bugs: MDEV-18853 Assertion `0' failed in Protocol::end_statement upon DELETE .. FOR PORTION via prepared statement MDEV-18852 Server crashes in reinit_stmt_before_use upon UPDATE .. FOR PORTION via prepared statement
-rwxr-xr-xmysql-test/mysql-test-run.pl1
-rw-r--r--mysql-test/suite/period/r/delete.result2
-rw-r--r--mysql-test/suite/period/t/delete.test2
-rw-r--r--sql/sql_delete.cc26
-rw-r--r--sql/sql_select.cc14
-rw-r--r--sql/sql_update.cc30
6 files changed, 50 insertions, 25 deletions
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index 646b8359f28..0df7f08db0a 100755
--- a/mysql-test/mysql-test-run.pl
+++ b/mysql-test/mysql-test-run.pl
@@ -200,6 +200,7 @@ my @DEFAULT_SUITES= qw(
unit-
vcol-
versioning-
+ period-
);
my $opt_suites;
diff --git a/mysql-test/suite/period/r/delete.result b/mysql-test/suite/period/r/delete.result
index d2ead48e2e7..7aa8ed455a7 100644
--- a/mysql-test/suite/period/r/delete.result
+++ b/mysql-test/suite/period/r/delete.result
@@ -291,7 +291,7 @@ ERROR 42S02: 'v' is a view
# View can't be used
create or replace view v as select t.* from t, t as t1;
delete from v for portion of p from '2000-01-01' to '2018-01-01';
-ERROR 42S02: 'v' is a view
+ERROR HY000: Can not delete from join view 'test.v'
# auto_increment field overflow
create or replace table t (id tinyint auto_increment primary key,
s date, e date, period for apptime(s,e));
diff --git a/mysql-test/suite/period/t/delete.test b/mysql-test/suite/period/t/delete.test
index c83da42bd6c..b614f5d45db 100644
--- a/mysql-test/suite/period/t/delete.test
+++ b/mysql-test/suite/period/t/delete.test
@@ -133,7 +133,7 @@ delete from v for portion of p from '2000-01-01' to '2018-01-01';
--echo # View can't be used
create or replace view v as select t.* from t, t as t1;
---error ER_IT_IS_A_VIEW
+--error ER_VIEW_DELETE_MERGE_VIEW
delete from v for portion of p from '2000-01-01' to '2018-01-01';
--echo # auto_increment field overflow
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index d02d35a7dd8..42f96d876a9 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -380,18 +380,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
table_list->on_expr= NULL;
}
}
- if (table_list->has_period())
- {
- if (table_list->is_view_or_derived())
- {
- my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str);
- DBUG_RETURN(true);
- }
-
- conds= select_lex->period_setup_conds(thd, table_list, conds);
- if (!conds)
- DBUG_RETURN(true);
- }
if (thd->lex->handle_list_of_derived(table_list, DT_MERGE_FOR_INSERT))
DBUG_RETURN(TRUE);
@@ -1055,6 +1043,20 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list,
if (select_lex->vers_setup_conds(thd, table_list))
DBUG_RETURN(true);
}
+
+ if (table_list->has_period())
+ {
+ if (table_list->is_view_or_derived())
+ {
+ my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str);
+ DBUG_RETURN(true);
+ }
+
+ *conds= select_lex->period_setup_conds(thd, table_list, *conds);
+ if (!*conds)
+ DBUG_RETURN(true);
+ }
+
if ((wild_num && setup_wild(thd, table_list, field_list, NULL, wild_num,
&select_lex->hidden_bit_fields)) ||
setup_fields(thd, Ref_ptr_array(),
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index e8b092b1b23..644746d14bb 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -883,7 +883,10 @@ Item* SELECT_LEX::period_setup_conds(THD *thd, TABLE_LIST *tables, Item *where)
DBUG_ENTER("SELECT_LEX::period_setup_conds");
if (skip_setup_conds(thd))
- DBUG_RETURN(NULL);
+ DBUG_RETURN(where);
+
+ Query_arena backup;
+ Query_arena *arena= thd->activate_stmt_arena_if_needed(&backup);
DBUG_ASSERT(!tables->next_local && tables->table);
@@ -896,6 +899,8 @@ Item* SELECT_LEX::period_setup_conds(THD *thd, TABLE_LIST *tables, Item *where)
if (!table->table->s->period.name.streq(conds.name))
{
my_error(ER_PERIOD_NOT_FOUND, MYF(0), conds.name.str);
+ if (arena)
+ thd->restore_active_arena(arena, &backup);
DBUG_RETURN(NULL);
}
@@ -903,7 +908,12 @@ Item* SELECT_LEX::period_setup_conds(THD *thd, TABLE_LIST *tables, Item *where)
result= and_items(thd, result,
period_get_condition(thd, table, this, &conds, true));
}
- DBUG_RETURN(and_items(thd, where, result));
+ result= and_items(thd, where, result);
+
+ if (arena)
+ thd->restore_active_arena(arena, &backup);
+
+ DBUG_RETURN(result);
}
int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 54e13d860a9..4da571a2807 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -432,6 +432,16 @@ int mysql_update(THD *thd,
if (mysql_prepare_update(thd, table_list, &conds, order_num, order))
DBUG_RETURN(1);
+ if (table_list->has_period())
+ {
+ if (!table_list->period_conditions.start.item->const_item()
+ || !table_list->period_conditions.end.item->const_item())
+ {
+ my_error(ER_NOT_CONSTANT_EXPRESSION, MYF(0), "FOR PORTION OF");
+ DBUG_RETURN(true);
+ }
+ }
+
old_covering_keys= table->covering_keys; // Keys used in WHERE
/* Check the fields we are going to modify */
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -1366,15 +1376,6 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
setup_ftfuncs(select_lex))
DBUG_RETURN(TRUE);
- if (table_list->has_period())
- {
- if (!table_list->period_conditions.start.item->const_item()
- || !table_list->period_conditions.end.item->const_item())
- {
- my_error(ER_NOT_CONSTANT_EXPRESSION, MYF(0), "FOR PORTION OF");
- DBUG_RETURN(true);
- }
- }
select_lex->fix_prepare_information(thd, conds, &fake_conds);
DBUG_RETURN(FALSE);
@@ -1665,6 +1666,17 @@ int mysql_multi_update_prepare(THD *thd)
if (mysql_handle_derived(lex, DT_PREPARE))
DBUG_RETURN(TRUE);
+ if (table_list->has_period())
+ {
+ /*
+ Multi-table update is not supported on syntax lexel. However it's possible
+ to get here through PREPARE with update of multi-table view.
+ */
+ DBUG_ASSERT(table_list->is_view_or_derived());
+ my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str);
+ DBUG_RETURN(TRUE);
+ }
+
if (setup_tables_and_check_access(thd,
&lex->first_select_lex()->context,
&lex->first_select_lex()->top_join_list,