diff options
author | Nikita Malyavin <nikitamalyavin@gmail.com> | 2019-03-13 22:25:48 +1000 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2019-04-02 11:03:32 +0200 |
commit | 04055060b6fa29e72a7e851486085bd59e708614 (patch) | |
tree | af1810b46a882e96b12917ef59729b5b987a28eb | |
parent | 74c9872a9aae825ca6ab73feff048ff2ccb4beb8 (diff) | |
download | mariadb-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-x | mysql-test/mysql-test-run.pl | 1 | ||||
-rw-r--r-- | mysql-test/suite/period/r/delete.result | 2 | ||||
-rw-r--r-- | mysql-test/suite/period/t/delete.test | 2 | ||||
-rw-r--r-- | sql/sql_delete.cc | 26 | ||||
-rw-r--r-- | sql/sql_select.cc | 14 | ||||
-rw-r--r-- | sql/sql_update.cc | 30 |
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, |