summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/view.result28
-rw-r--r--mysql-test/t/view.test39
-rw-r--r--sql/parse_file.cc17
-rw-r--r--sql/parse_file.h4
-rw-r--r--sql/sql_view.cc41
-rw-r--r--sql/sql_view.h1
-rw-r--r--sql/table.cc26
-rw-r--r--sql/table.h8
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.