diff options
-rw-r--r-- | mysql-test/r/view.result | 28 | ||||
-rw-r--r-- | mysql-test/t/view.test | 39 | ||||
-rw-r--r-- | sql/parse_file.cc | 17 | ||||
-rw-r--r-- | sql/parse_file.h | 4 | ||||
-rw-r--r-- | sql/sql_view.cc | 41 | ||||
-rw-r--r-- | sql/sql_view.h | 1 | ||||
-rw-r--r-- | sql/table.cc | 26 | ||||
-rw-r--r-- | sql/table.h | 8 |
8 files changed, 156 insertions, 8 deletions
diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index e8c96e49977..030d0f0c520 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -6259,5 +6259,33 @@ t1col1 t1col2 t1col3 drop view v1; drop table t1,t2; # +# MDEV-17124: mariadb 10.1.34, views and prepared statements: +# ERROR 1615 (HY000): Prepared statement needs to be re-prepared +# +set @tdc= @@table_definition_cache, @tc= @@table_open_cache; +set global table_definition_cache= 400, table_open_cache= 400; +create table tt (a int, primary key(a)) engine=MyISAM; +create view v as select * from tt; +insert into tt values(1),(2),(3),(4); +prepare stmt from 'select * from tt'; +#fill table definition cache +execute stmt; +a +1 +2 +3 +4 +prepare stmt from 'select * from v'; +execute stmt; +a +1 +2 +3 +4 +drop database db; +drop view v; +drop table tt; +set global table_definition_cache= @tdc, table_open_cache= @tc; +# # End of 10.1 tests # diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 6ff226d738f..ee587181aa4 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -6081,5 +6081,44 @@ drop view v1; drop table t1,t2; --echo # +--echo # MDEV-17124: mariadb 10.1.34, views and prepared statements: +--echo # ERROR 1615 (HY000): Prepared statement needs to be re-prepared +--echo # + +set @tdc= @@table_definition_cache, @tc= @@table_open_cache; +set global table_definition_cache= 400, table_open_cache= 400; + +create table tt (a int, primary key(a)) engine=MyISAM; +create view v as select * from tt; +insert into tt values(1),(2),(3),(4); + +prepare stmt from 'select * from tt'; +--echo #fill table definition cache +--disable_query_log +--disable_result_log +create database db; +use db; +--let $tables=401 +while ($tables) +{ + --eval create table t$tables (i int) engine=MyISAM + --eval select * from t$tables + --dec $tables +} + +use test; + +--enable_query_log +--enable_result_log +execute stmt; +prepare stmt from 'select * from v'; +execute stmt; + +# Cleanup +drop database db; +drop view v; +drop table tt; +set global table_definition_cache= @tdc, table_open_cache= @tc; +--echo # --echo # End of 10.1 tests --echo # diff --git a/sql/parse_file.cc b/sql/parse_file.cc index f3dab4f7b2f..6f188660407 100644 --- a/sql/parse_file.cc +++ b/sql/parse_file.cc @@ -145,6 +145,7 @@ write_parameter(IO_CACHE *file, uchar* base, File_option *parameter) switch (parameter->type) { case FILE_OPTIONS_STRING: + case FILE_OPTIONS_FIXSTRING: { LEX_STRING *val_s= (LEX_STRING *)(base + parameter->offset); if (my_b_write(file, (const uchar *)val_s->str, val_s->length)) @@ -830,6 +831,22 @@ File_parser::parse(uchar* base, MEM_ROOT *mem_root, } ptr= eol+1; break; + case FILE_OPTIONS_FIXSTRING: + { + /* string have to be allocated already and length set */ + LEX_STRING *val= (LEX_STRING *)(base + parameter->offset); + DBUG_ASSERT(val->length != 0); + if (ptr[val->length] != '\n') + { + my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0), + parameter->name.str, line); + DBUG_RETURN(TRUE); + } + memcpy(val->str, ptr, val->length); + val->str[val->length]= '\0'; + ptr+= (val->length + 1); + break; + } case FILE_OPTIONS_TIMESTAMP: { /* string have to be allocated already */ diff --git a/sql/parse_file.h b/sql/parse_file.h index 87917dbd71b..28f4070b437 100644 --- a/sql/parse_file.h +++ b/sql/parse_file.h @@ -36,8 +36,10 @@ enum file_opt_type { allocated with length 20 (19+1) */ FILE_OPTIONS_STRLIST, /**< list of escaped strings (List<LEX_STRING>) */ - FILE_OPTIONS_ULLLIST /**< list of ulonglong values + FILE_OPTIONS_ULLLIST, /**< list of ulonglong values (List<ulonglong>) */ + + FILE_OPTIONS_FIXSTRING /**< fixed length String (LEX_STRING) */ }; struct File_option diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 9a9309a133b..ee169de4c93 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -782,6 +782,16 @@ static File_option view_parameters[]= FILE_OPTIONS_STRING} }; + +static File_option view_md5_parameters[]= +{ + + {{ C_STRING_WITH_LEN("md5")}, 0, FILE_OPTIONS_FIXSTRING}, + {{NullS, 0}, 0, FILE_OPTIONS_STRING} +}; + + + static LEX_STRING view_file_type[]= {{(char*) STRING_WITH_LEN("VIEW") }}; @@ -1125,7 +1135,38 @@ err: DBUG_RETURN(error); } +#define MD5_LEN 32 +/** + Check is TABLE_LEST and SHARE match + @param[in] view TABLE_LIST of the view + @param[in] share Share object of view + + @return false on error or misspatch +*/ +bool mariadb_view_version_check(TABLE_LIST *view, TABLE_SHARE *share) +{ + LEX_STRING md5; + char md5_buffer[MD5_LEN + 1]; + md5.str= md5_buffer; + md5.length= MD5_LEN; + + /* + Check that both were views (view->is_view() could not be checked + because it is not opened). + */ + if (!share->is_view || view->md5.length != MD5_LEN) + return FALSE; + + DBUG_ASSERT(share->view_def != NULL); + if (share->view_def->parse((uchar*)&md5, NULL, + view_md5_parameters, + 1, + &file_parser_dummy_hook)) + return FALSE; + DBUG_ASSERT(md5.length == MD5_LEN); + return (strncmp(md5.str, view->md5.str, MD5_LEN) == 0); +} /** read VIEW .frm and create structures diff --git a/sql/sql_view.h b/sql/sql_view.h index ce83dc656ad..1685169420d 100644 --- a/sql/sql_view.h +++ b/sql/sql_view.h @@ -37,6 +37,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *view, bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, bool open_view_no_parse); +bool mariadb_view_version_check(TABLE_LIST *view, TABLE_SHARE *share); bool mysql_drop_view(THD *thd, TABLE_LIST *view, enum_drop_mode drop_mode); diff --git a/sql/table.cc b/sql/table.cc index e1edcc0b407..a6fbce9f3dd 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -7495,6 +7495,32 @@ void TABLE_LIST::set_lock_type(THD *thd, enum thr_lock_type lock) } } + +bool TABLE_LIST::is_table_ref_id_equal(TABLE_SHARE *s) +{ + enum enum_table_ref_type tp= s->get_table_ref_type(); + if (m_table_ref_type == tp) + { + bool res= m_table_ref_version == s->get_table_ref_version(); + + /* + If definition is different object with view we can check MD5 in frm + to check if the same view got into table definition cache again. + */ + if (!res && + tp == TABLE_REF_VIEW && + mariadb_view_version_check(this, s)) + { + // to avoid relatively expensive parsing of frm next time + set_table_ref_id(s); + return TRUE; + } + return res; + } + return FALSE; +} + + uint TABLE_SHARE::actual_n_key_parts(THD *thd) { return use_ext_keys && diff --git a/sql/table.h b/sql/table.h index a7913844e9d..9e1a061e606 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2271,13 +2271,7 @@ struct TABLE_LIST @sa check_and_update_table_version() */ - inline - bool is_table_ref_id_equal(TABLE_SHARE *s) const - { - return (m_table_ref_type == s->get_table_ref_type() && - m_table_ref_version == s->get_table_ref_version()); - } - + bool is_table_ref_id_equal(TABLE_SHARE *s); /** Record the value of metadata version of the corresponding table definition cache element in this parse tree node. |