summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/ps_ddl.result20
-rw-r--r--mysql-test/r/view.result28
-rw-r--r--mysql-test/t/ps_ddl.test15
-rw-r--r--mysql-test/t/view.test40
-rw-r--r--sql/parse_file.cc18
-rw-r--r--sql/sql_base.cc15
-rw-r--r--sql/sql_class.cc2
-rw-r--r--sql/sql_class.h1
-rw-r--r--sql/sql_prepare.cc22
-rw-r--r--sql/sql_show.cc18
-rw-r--r--sql/sql_trigger.cc25
-rw-r--r--sql/sql_trigger.h14
-rw-r--r--sql/sql_view.cc67
-rw-r--r--sql/table.cc47
-rw-r--r--sql/table.h57
15 files changed, 323 insertions, 66 deletions
diff --git a/mysql-test/r/ps_ddl.result b/mysql-test/r/ps_ddl.result
index e69c6e06193..005c78a0319 100644
--- a/mysql-test/r/ps_ddl.result
+++ b/mysql-test/r/ps_ddl.result
@@ -214,7 +214,7 @@ new trigger: 10
drop trigger t1_bd;
set @val=11;
execute stmt using @val;
-call p_verify_reprepare_count(1);
+call p_verify_reprepare_count(0);
SUCCESS
select @message;
@@ -224,7 +224,7 @@ Test 6-e: removing a relevant trigger
drop trigger t1_bi;
set @val=12;
execute stmt using @val;
-call p_verify_reprepare_count(1);
+call p_verify_reprepare_count(0);
SUCCESS
select @message;
@@ -384,7 +384,7 @@ a
flush table t1;
set @var=9;
execute stmt using @var;
-call p_verify_reprepare_count(1);
+call p_verify_reprepare_count(0);
SUCCESS
select * from t2;
@@ -831,8 +831,8 @@ a b c
20 40 100
30 60 150
call p_verify_reprepare_count(1);
-SUCCESS
-
+ERROR
+Expected: 1, actual: 0
# Check that we properly handle ALTER VIEW statements.
execute stmt;
a b c
@@ -882,9 +882,9 @@ a b c
10 50 60
20 100 120
30 150 180
-call p_verify_reprepare_count(1);
-SUCCESS
-
+call p_verify_reprepare_count(0);
+ERROR
+Expected: 0, actual: 1
execute stmt;
a b c
10 50 60
@@ -1206,7 +1206,7 @@ drop trigger v2_bi;
set @message=null;
set @var=9;
execute stmt using @var;
-call p_verify_reprepare_count(1);
+call p_verify_reprepare_count(0);
SUCCESS
select @message;
@@ -2578,7 +2578,7 @@ SELECT * FROM t1;
a
2048
1025
-1024
+2048
DROP TABLE t1;
#
# End of 10.1 tests
diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result
index 4edbabf11cc..1340a48fb83 100644
--- a/mysql-test/r/view.result
+++ b/mysql-test/r/view.result
@@ -6862,5 +6862,33 @@ r
drop view v1;
drop table t1;
#
+# 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.2 tests
#
diff --git a/mysql-test/t/ps_ddl.test b/mysql-test/t/ps_ddl.test
index 90226d379bf..fc1bd8d3752 100644
--- a/mysql-test/t/ps_ddl.test
+++ b/mysql-test/t/ps_ddl.test
@@ -250,7 +250,8 @@ drop trigger t1_bd;
set @val=11;
execute stmt using @val;
-call p_verify_reprepare_count(1);
+# No trigger in opened table => nothing to check => no reprepare
+call p_verify_reprepare_count(0);
select @message;
--echo Test 6-e: removing a relevant trigger
@@ -259,7 +260,8 @@ drop trigger t1_bi;
set @val=12;
execute stmt using @val;
-call p_verify_reprepare_count(1);
+# No trigger in opened table => nothing to check => no reprepare
+call p_verify_reprepare_count(0);
select @message;
set @val=13;
execute stmt using @val;
@@ -374,7 +376,8 @@ select * from t3;
flush table t1;
set @var=9;
execute stmt using @var;
-call p_verify_reprepare_count(1);
+# flush tables now do not mean reprepare
+call p_verify_reprepare_count(0);
select * from t2;
select * from t3;
drop view v1;
@@ -763,7 +766,8 @@ flush tables; # empty TDC
create view t1 as select a, 5*a as b, 6*a as c from t2;
lock tables t1 read, t2 read;
execute stmt;
-call p_verify_reprepare_count(1);
+# flush tables now do not mean reprepare
+call p_verify_reprepare_count(0);
execute stmt;
call p_verify_reprepare_count(0);
execute stmt;
@@ -967,7 +971,8 @@ drop trigger v2_bi;
set @message=null;
set @var=9;
execute stmt using @var;
-call p_verify_reprepare_count(1);
+# No trigger in opened table => nothing to check => no reprepare
+call p_verify_reprepare_count(0);
select @message;
create trigger v2_bi after insert on v2 for each row set @message="v2_ai";
set @var= 10;
diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test
index 6265a514783..6914c80f635 100644
--- a/mysql-test/t/view.test
+++ b/mysql-test/t/view.test
@@ -6598,5 +6598,45 @@ drop view v1;
drop table t1;
--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.2 tests
--echo #
diff --git a/sql/parse_file.cc b/sql/parse_file.cc
index 999f53bd681..92e7d82af1c 100644
--- a/sql/parse_file.cc
+++ b/sql/parse_file.cc
@@ -174,11 +174,11 @@ write_parameter(IO_CACHE *file, uchar* base, File_option *parameter)
{
/* string have to be allocated already */
LEX_STRING *val_s= (LEX_STRING *)(base + parameter->offset);
- time_t tm= my_time(0);
-
- get_date(val_s->str, GETDATE_DATE_TIME|GETDATE_GMT|GETDATE_FIXEDLENGTH,
- tm);
- val_s->length= PARSE_FILE_TIMESTAMPLENGTH;
+ ulonglong tm= my_hrtime().val;
+ // Paded to 19 characters for compatibility
+ val_s->length= snprintf(val_s->str, MICROSECOND_TIMESTAMP_BUFFER_SIZE,
+ "%019lld", tm);
+ DBUG_ASSERT(val_s->length == MICROSECOND_TIMESTAMP_BUFFER_SIZE-1);
if (my_b_write(file, (const uchar *)val_s->str,
PARSE_FILE_TIMESTAMPLENGTH))
DBUG_RETURN(TRUE);
@@ -835,15 +835,15 @@ File_parser::parse(uchar* base, MEM_ROOT *mem_root,
/* string have to be allocated already */
LEX_STRING *val= (LEX_STRING *)(base + parameter->offset);
/* yyyy-mm-dd HH:MM:SS = 19(PARSE_FILE_TIMESTAMPLENGTH) characters */
- if (ptr[PARSE_FILE_TIMESTAMPLENGTH] != '\n')
+ if (ptr[MICROSECOND_TIMESTAMP_BUFFER_SIZE-1] != '\n')
{
my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0),
parameter->name.str, line);
DBUG_RETURN(TRUE);
}
- memcpy(val->str, ptr, PARSE_FILE_TIMESTAMPLENGTH);
- val->str[val->length= PARSE_FILE_TIMESTAMPLENGTH]= '\0';
- ptr+= (PARSE_FILE_TIMESTAMPLENGTH+1);
+ memcpy(val->str, ptr, MICROSECOND_TIMESTAMP_BUFFER_SIZE-1);
+ val->str[val->length= MICROSECOND_TIMESTAMP_BUFFER_SIZE-1]= '\0';
+ ptr+= MICROSECOND_TIMESTAMP_BUFFER_SIZE;
break;
}
case FILE_OPTIONS_STRLIST:
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 248dedf36e4..85bf6f05d02 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1839,6 +1839,10 @@ retry_share:
goto err_lock;
}
+ /* Open view */
+ if (mysql_make_view(thd, share, table_list, false))
+ goto err_lock;
+
/*
This table is a view. Validate its metadata version: in particular,
that it was a view when the statement was prepared.
@@ -1846,10 +1850,6 @@ retry_share:
if (check_and_update_table_version(thd, table_list, share))
goto err_lock;
- /* Open view */
- if (mysql_make_view(thd, share, table_list, false))
- goto err_lock;
-
/* TODO: Don't free this */
tdc_release_share(share);
@@ -2643,7 +2643,7 @@ static bool
check_and_update_table_version(THD *thd,
TABLE_LIST *tables, TABLE_SHARE *table_share)
{
- if (! tables->is_table_ref_id_equal(table_share))
+ if (! tables->is_table_ref_id_equal(thd, table_share))
{
if (thd->m_reprepare_observer &&
thd->m_reprepare_observer->report_error(thd))
@@ -2749,7 +2749,9 @@ bool tdc_open_view(THD *thd, TABLE_LIST *table_list, uint flags)
DBUG_ASSERT(share->is_view);
- if (flags & CHECK_METADATA_VERSION)
+ err= mysql_make_view(thd, share, table_list, (flags & OPEN_VIEW_NO_PARSE));
+
+ if (!err && (flags & CHECK_METADATA_VERSION))
{
/*
Check TABLE_SHARE-version of view only if we have been instructed to do
@@ -2764,7 +2766,6 @@ bool tdc_open_view(THD *thd, TABLE_LIST *table_list, uint flags)
goto ret;
}
- err= mysql_make_view(thd, share, table_list, (flags & OPEN_VIEW_NO_PARSE));
ret:
tdc_release_share(share);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 479578679f1..8907463613f 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -3607,6 +3607,7 @@ Statement::Statement(LEX *lex_arg, MEM_ROOT *mem_root_arg,
id(id_arg),
mark_used_columns(MARK_COLUMNS_READ),
lex(lex_arg),
+ ms_prepare_time(0),
db(NULL),
db_length(0)
{
@@ -3626,6 +3627,7 @@ void Statement::set_statement(Statement *stmt)
mark_used_columns= stmt->mark_used_columns;
lex= stmt->lex;
query_string= stmt->query_string;
+ ms_prepare_time= stmt->ms_prepare_time;
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 3f0fba8fc10..b9bb9c978fb 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1079,6 +1079,7 @@ public:
LEX_STRING name; /* name for named prepared statements */
LEX *lex; // parse tree descriptor
+ ulonglong ms_prepare_time; // time of preparation in microseconds
/*
Points to the query associated with this statement. It's const, but
we need to declare it char * because all table handlers are written
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 64e4cd30561..a4a24cc1a80 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -4177,6 +4177,9 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
Query_arena *old_stmt_arena;
DBUG_ENTER("Prepared_statement::prepare");
DBUG_ASSERT(m_sql_mode == thd->variables.sql_mode);
+
+ // The same format as for triggers to compare
+ ms_prepare_time= my_hrtime().val;
/*
If this is an SQLCOM_PREPARE, we also increase Com_prepare_sql.
However, it seems handy if com_stmt_prepare is increased always,
@@ -4435,8 +4438,9 @@ Prepared_statement::execute_loop(String *expanded_query,
uchar *packet_end)
{
Reprepare_observer reprepare_observer;
- bool error;
+ ulonglong first_prepared= ms_prepare_time;
int reprepare_attempt= 0;
+ bool error;
iterations= FALSE;
/*
@@ -4519,6 +4523,22 @@ reexecute:
DBUG_ASSERT(thd->get_stmt_da()->sql_errno() == ER_NEED_REPREPARE);
thd->clear_error();
+ {
+ /*
+ Check if we too fast with reprepare:
+ we can be so fast that:
+ 1) make change of a trigger,
+ 2) prepare,
+ 3) try to exacute and reprepare
+ in 1 microsecond, so we will wait till
+ next microsecond before last reprepare
+ */
+ while (first_prepared == my_hrtime().val)
+ {
+ pthread_yield();
+ }
+ }
+
error= reprepare();
if (! error) /* Success */
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 9483db9eff9..138fa4bc631 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -6724,13 +6724,15 @@ static bool store_trigger(THD *thd, Trigger *trigger,
table->field[14]->store(STRING_WITH_LEN("OLD"), cs);
table->field[15]->store(STRING_WITH_LEN("NEW"), cs);
- if (trigger->create_time)
+ if (trigger->ms_create_time)
{
+ /* timestamp is in microseconds */
table->field[16]->set_notnull();
thd->variables.time_zone->gmt_sec_to_TIME(&timestamp,
- (my_time_t)(trigger->create_time/100));
- /* timestamp is with 6 digits */
- timestamp.second_part= (trigger->create_time % 100) * 10000;
+ (my_time_t)
+ (trigger->ms_create_time/
+ 1000000));
+ timestamp.second_part= trigger->ms_create_time % 1000000;
((Field_temporal_with_date*) table->field[16])->store_time_dec(&timestamp,
2);
}
@@ -9810,12 +9812,14 @@ static bool show_create_trigger_impl(THD *thd, Trigger *trigger)
trigger->db_cl_name.length,
system_charset_info);
- if (trigger->create_time)
+ if (trigger->ms_create_time)
{
MYSQL_TIME timestamp;
thd->variables.time_zone->gmt_sec_to_TIME(&timestamp,
- (my_time_t)(trigger->create_time/100));
- timestamp.second_part= (trigger->create_time % 100) * 10000;
+ (my_time_t)
+ (trigger->ms_create_time/
+ 1000000));
+ timestamp.second_part= trigger->ms_create_time % 1000000;
p->store(&timestamp, 2);
}
else
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 52817ef65ae..7823bc06534 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -37,6 +37,8 @@
#ifdef WITH_WSREP
#include "debug_sync.h"
#endif /* WITH_WSREP */
+#include <my_time.h>
+#include <mysql_time.h>
LEX_STRING *make_lex_string(LEX_STRING *lex_str, const char* str, uint length,
MEM_ROOT *mem_root)
@@ -211,7 +213,7 @@ static File_option triggers_file_parameters[]=
},
{
{ C_STRING_WITH_LEN("created") },
- my_offsetof(class Table_triggers_list, create_times),
+ my_offsetof(class Table_triggers_list, ms_create_times),
FILE_OPTIONS_ULLLIST
},
{ { 0, 0 }, 0, FILE_OPTIONS_STRING }
@@ -888,6 +890,10 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
if (!(trigger= new (&table->mem_root) Trigger(this, 0)))
goto err_without_cleanup;
+ /* Time with in microseconds */
+ trigger->ms_create_time= make_ms_time(thd->query_start(),
+ thd->query_start_sec_part());
+
/* Create trigger_name.TRN file to ensure trigger name is unique */
if (sql_create_definition_file(NULL, &trigname_file, &trigname_file_type,
(uchar*)&trigname, trigname_file_parameters))
@@ -896,8 +902,6 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
/* Populate the trigger object */
trigger->sql_mode= thd->variables.sql_mode;
- /* Time with 2 decimals, like in MySQL 5.7 */
- trigger->create_time= ((ulonglong) thd->query_start())*100 + thd->query_start_sec_part()/10000;
build_trig_stmt_query(thd, tables, stmt_query, &trigger_definition,
&trigger->definer, trg_definer_holder);
@@ -965,7 +969,7 @@ void Table_triggers_list::empty_lists()
client_cs_names.empty();
connection_cl_names.empty();
db_cl_names.empty();
- create_times.empty();
+ ms_create_times.empty();
}
@@ -1001,7 +1005,7 @@ bool Trigger::add_to_file_list(void* param_arg)
base->client_cs_names.push_back(&client_cs_name, mem_root) ||
base->connection_cl_names.push_back(&connection_cl_name, mem_root) ||
base->db_cl_names.push_back(&db_cl_name, mem_root) ||
- base->create_times.push_back(&create_time, mem_root))
+ base->ms_create_times.push_back(&ms_create_time, mem_root))
return 1;
return 0;
}
@@ -1380,7 +1384,8 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
List_iterator_fast<LEX_STRING> it_client_cs_name(trigger_list->client_cs_names);
List_iterator_fast<LEX_STRING> it_connection_cl_name(trigger_list->connection_cl_names);
List_iterator_fast<LEX_STRING> it_db_cl_name(trigger_list->db_cl_names);
- List_iterator_fast<ulonglong> it_create_times(trigger_list->create_times);
+ List_iterator_fast<ulonglong>
+ it_create_times(trigger_list->ms_create_times);
LEX *old_lex= thd->lex;
LEX lex;
sp_rcontext *save_spcont= thd->spcont;
@@ -1466,7 +1471,13 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
trigger->sql_mode= sql_mode;
trigger->definition= *trg_create_str;
- trigger->create_time= trg_create_time ? *trg_create_time : 0;
+ trigger->ms_create_time= trg_create_time ? *trg_create_time : 0;
+ /*
+ Fix time if in 100th of second (comparison with max uint * 100
+ (max possible timestamp in the old format))
+ */
+ if (trigger->ms_create_time < 429496729400ULL)
+ trigger->ms_create_time*= 10000;
trigger->name= sp ? sp->m_name : empty_lex_str;
trigger->on_table_name.str= (char*) lex.raw_trg_on_table_name_begin;
trigger->on_table_name.length= (lex.raw_trg_on_table_name_end -
diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h
index e2e6e1b7acc..70f246d4e0d 100644
--- a/sql/sql_trigger.h
+++ b/sql/sql_trigger.h
@@ -112,7 +112,7 @@ public:
GRANT_INFO subject_table_grants;
sql_mode_t sql_mode;
/* Store create time. Can't be mysql_time_t as this holds also sub seconds */
- ulonglong create_time;
+ ulonglong ms_create_time; // Create time timestamp in microseconds
trg_event_type event;
trg_action_time_type action_time;
uint action_order;
@@ -195,7 +195,7 @@ public:
*/
List<ulonglong> definition_modes_list;
/** Create times for triggers */
- List<ulonglong> create_times;
+ List<ulonglong> ms_create_times;
List<LEX_STRING> definers_list;
@@ -331,4 +331,14 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create);
extern const char * const TRG_EXT;
extern const char * const TRN_EXT;
+
+/**
+ Make time compatible with MySQL 5.7 trigger time.
+*/
+
+inline ulonglong make_ms_time(my_time_t time, ulong time_sec_part)
+{
+ return ((ulonglong) time)*1000000 + time_sec_part;
+}
+
#endif /* SQL_TRIGGER_INCLUDED */
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 020830483c5..3b51f6d2451 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -764,7 +764,7 @@ static File_option view_parameters[]=
my_offsetof(TABLE_LIST, with_check),
FILE_OPTIONS_ULONGLONG},
{{ C_STRING_WITH_LEN("timestamp")},
- my_offsetof(TABLE_LIST, timestamp),
+ my_offsetof(TABLE_LIST, ms_timestamp),
FILE_OPTIONS_TIMESTAMP},
{{ C_STRING_WITH_LEN("create-version")},
my_offsetof(TABLE_LIST, file_version),
@@ -788,6 +788,16 @@ static File_option view_parameters[]=
FILE_OPTIONS_STRING}
};
+
+static File_option view_timestamp_parameters[]=
+{
+
+ {{ C_STRING_WITH_LEN("timestamp")}, 0, FILE_OPTIONS_TIMESTAMP},
+ {{NullS, 0}, 0, FILE_OPTIONS_STRING}
+};
+
+
+
static LEX_STRING view_file_type[]= {{(char*) STRING_WITH_LEN("VIEW") }};
@@ -805,8 +815,8 @@ int mariadb_fix_view(THD *thd, TABLE_LIST *view, bool wrong_checksum,
&path, path_buff, sizeof(path_buff),
&file, view);
/* init timestamp */
- if (!view->timestamp.str)
- view->timestamp.str= view->timestamp_buffer;
+ if (!view->ms_timestamp.str)
+ view->ms_timestamp.str= view->timestamp_buffer;
if (swap_alg && view->algorithm != VIEW_ALGORITHM_UNDEFINED)
{
@@ -1006,8 +1016,8 @@ loop_out:
&path, path_buff, sizeof(path_buff),
&file, view);
/* init timestamp */
- if (!view->timestamp.str)
- view->timestamp.str= view->timestamp_buffer;
+ if (!view->ms_timestamp.str)
+ view->ms_timestamp.str= view->timestamp_buffer;
/* check old .frm */
{
@@ -1131,7 +1141,31 @@ err:
DBUG_RETURN(error);
}
+/**
+ 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_get(TABLE_SHARE *share)
+{
+ DBUG_ASSERT(share->is_view);
+
+ if (!(share->tabledef_version.str=
+ (uchar*) alloc_root(&share->mem_root,
+ MICROSECOND_TIMESTAMP_BUFFER_SIZE)))
+ return TRUE;
+
+ DBUG_ASSERT(share->view_def != NULL);
+ if (share->view_def->parse((uchar *) &share->tabledef_version, NULL,
+ view_timestamp_parameters, 1,
+ &file_parser_dummy_hook))
+ return TRUE;
+ DBUG_ASSERT(share->tabledef_version.length == MICROSECOND_TIMESTAMP_BUFFER_SIZE-1);
+ return FALSE;
+}
/**
read VIEW .frm and create structures
@@ -1193,6 +1227,10 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
mysql_derived_reinit(thd, NULL, table);
DEBUG_SYNC(thd, "after_cached_view_opened");
+ if (!share->tabledef_version.length)
+ {
+ mariadb_view_version_get(share);
+ }
DBUG_RETURN(0);
}
@@ -1229,8 +1267,8 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
arena= thd->activate_stmt_arena_if_needed(&backup);
/* init timestamp */
- if (!table->timestamp.str)
- table->timestamp.str= table->timestamp_buffer;
+ if (!table->ms_timestamp.str)
+ table->ms_timestamp.str= table->timestamp_buffer;
/* prepare default values for old format */
table->view_suid= TRUE;
table->definer.user.str= table->definer.host.str= 0;
@@ -1246,6 +1284,19 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
required_view_parameters,
&file_parser_dummy_hook)))
goto end;
+ if (!share->tabledef_version.length)
+ {
+ share->tabledef_version.str= (const uchar *)
+ memdup_root(&share->mem_root,
+ (const void *)
+ table->ms_timestamp.str,
+ (share->tabledef_version.length=
+ table->ms_timestamp.length));
+ }
+ if (!table->tabledef_version.length)
+ {
+ table->set_view_def_version(&table->ms_timestamp);
+ }
/*
check old format view .frm
@@ -2151,7 +2202,7 @@ mysql_rename_view(THD *thd,
object for it.
*/
view_def.reset();
- view_def.timestamp.str= view_def.timestamp_buffer;
+ view_def.ms_timestamp.str= view_def.timestamp_buffer;
view_def.view_suid= TRUE;
/* get view definition and source */
diff --git a/sql/table.cc b/sql/table.cc
index ca6ce02e4f2..24412966b36 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -8480,6 +8480,53 @@ bool TABLE_LIST::is_with_table()
}
+bool TABLE_LIST::is_table_ref_id_equal(THD* thd, 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 check content version
+ */
+ if (tabledef_version.length &&
+ tabledef_version.length == s->tabledef_version.length &&
+ memcmp(tabledef_version.str, s->tabledef_version.str,
+ tabledef_version.length) == 0)
+ {
+ if (table && table->triggers)
+ {
+
+ ulonglong ms_stmt_prepare= thd->ms_prepare_time;
+ if (ms_stmt_prepare)
+ for(uint i= 0; i < TRG_EVENT_MAX; i++)
+ for (uint j= 0; j < TRG_ACTION_MAX; j++)
+ {
+ Trigger *tr=
+ table->triggers->get_trigger((trg_event_type)i,
+ (trg_action_time_type)j);
+ if (tr)
+ if (ms_stmt_prepare <= tr->ms_create_time)
+ {
+ set_tabledef_version(s);
+ return FALSE;
+ }
+ }
+ }
+ set_table_id(s);
+ return TRUE;
+ }
+ else
+ tabledef_version.length= 0;
+ return res;
+ }
+ else
+ set_tabledef_version(s);
+ 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 14d6b787b4e..82508388f84 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -32,8 +32,18 @@
#include "filesort_utils.h"
#include "parse_file.h"
-/* buffer for timestamp (19+1) */
-#define VIEW_TIME_STAMP_BUFFER_SIZE (PARSE_FILE_TIMESTAMPLENGTH + 1)
+/*
+ Buffer for unix timestamp in microseconds:
+ 9,223,372,036,854,775,807 (signed int64 maximal value)
+ 1 234 567 890 123 456 789
+
+ Note: we can use unsigned for calculation, but practically they
+ are the same by probability to overflow them (signed int64 in
+ microseconds is enough for almost 3e5 years) and signed allow to
+ avoid increasing the buffer (the old buffer for human readable
+ date was 19+1).
+*/
+#define MICROSECOND_TIMESTAMP_BUFFER_SIZE (19 + 1)
/* Structs that defines the TABLE */
@@ -2146,6 +2156,12 @@ struct TABLE_LIST
to view with SQL SECURITY DEFINER)
*/
Security_context *security_ctx;
+ uchar tabledef_version_buf[MY_UUID_SIZE >
+ MICROSECOND_TIMESTAMP_BUFFER_SIZE-1 ?
+ MY_UUID_SIZE + 1 :
+ MICROSECOND_TIMESTAMP_BUFFER_SIZE];
+ LEX_CUSTRING tabledef_version;
+
/*
This view security context (non-zero only for views with
SQL SECURITY DEFINER)
@@ -2159,7 +2175,7 @@ struct TABLE_LIST
LEX_STRING source; /* source of CREATE VIEW */
LEX_STRING view_db; /* saved view database */
LEX_STRING view_name; /* saved view name */
- LEX_STRING timestamp; /* GMT time stamp of last operation */
+ LEX_STRING ms_timestamp; /* GMT time stamp of last operation */
st_lex_user definer; /* definer of view */
ulonglong file_version; /* version of file's field set */
ulonglong mariadb_version; /* version of server on creation */
@@ -2244,7 +2260,7 @@ struct TABLE_LIST
/* FRMTYPE_ERROR if any type is acceptable */
enum frm_type_enum required_type;
handlerton *db_type; /* table_type for handler */
- char timestamp_buffer[VIEW_TIME_STAMP_BUFFER_SIZE];
+ char timestamp_buffer[MICROSECOND_TIMESTAMP_BUFFER_SIZE];
/*
This TABLE_LIST object is just placeholder for prelocking, it will be
used for implicit LOCK TABLES only and won't be used in real statement.
@@ -2442,12 +2458,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(THD *thd, TABLE_SHARE *s);
/**
Record the value of metadata version of the corresponding
table definition cache element in this parse tree node.
@@ -2464,6 +2475,26 @@ struct TABLE_LIST
m_table_ref_version= table_ref_version_arg;
}
+ void set_table_id(TABLE_SHARE *s)
+ {
+ set_table_ref_id(s);
+ set_tabledef_version(s);
+ }
+
+ void set_tabledef_version(TABLE_SHARE *s)
+ {
+ if (!tabledef_version.length && s->tabledef_version.length)
+ {
+ DBUG_ASSERT(s->tabledef_version.length <
+ sizeof(tabledef_version_buf));
+ tabledef_version.str= tabledef_version_buf;
+ memcpy(tabledef_version_buf, s->tabledef_version.str,
+ (tabledef_version.length= s->tabledef_version.length));
+ // safety
+ tabledef_version_buf[tabledef_version.length]= 0;
+ }
+ }
+
/* Set of functions returning/setting state of a derived table/view. */
inline bool is_non_derived()
{
@@ -2590,6 +2621,12 @@ struct TABLE_LIST
}
}
+ inline void set_view_def_version(LEX_STRING *version)
+ {
+ m_table_ref_type= TABLE_REF_VIEW;
+ tabledef_version.str= (const uchar *) version->str;
+ tabledef_version.length= version->length;
+ }
private:
bool prep_check_option(THD *thd, uint8 check_opt_type);
bool prep_where(THD *thd, Item **conds, bool no_where_clause);