MDEV-17124: mariadb 10.1.34, views and prepared statements: ERROR 1615 (HY000): Prepared statement needs to be re-prepared
The problem is that if table definition cache (TDC) is full of real tables which are in tables cache, view definition can not stay there so will be removed by its own underlying tables. In situation above old mechanism of detection matching definition in PS and current version always require reprepare and so prevent executing the PS. One work around is to increase TDC, other - improve version check for views/triggers (which is done here). Now in suspicious cases we check: - timestamp (microseconds) of the view to be sure that version really have changed; - time (microseconds) of creation of a trigger related to time (microseconds) of statement preparation.
This commit is contained in:
parent
98e62e6317
commit
f65ba9aeb7
@ -964,6 +964,17 @@ extern ulonglong my_getcputime(void);
|
|||||||
#define hrtime_sec_part(X) ((ulong)((X).val % HRTIME_RESOLUTION))
|
#define hrtime_sec_part(X) ((ulong)((X).val % HRTIME_RESOLUTION))
|
||||||
#define my_time(X) hrtime_to_time(my_hrtime_coarse())
|
#define my_time(X) hrtime_to_time(my_hrtime_coarse())
|
||||||
|
|
||||||
|
/**
|
||||||
|
Make high resolution time from two parts.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline my_hrtime_t make_hr_time(my_time_t time, ulong time_sec_part)
|
||||||
|
{
|
||||||
|
my_hrtime_t res= {((ulonglong) time)*1000000 + time_sec_part};
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if STACK_DIRECTION < 0
|
#if STACK_DIRECTION < 0
|
||||||
#define available_stack_size(CUR,END) (long) ((char*)(CUR) - (char*)(END))
|
#define available_stack_size(CUR,END) (long) ((char*)(CUR) - (char*)(END))
|
||||||
#else
|
#else
|
||||||
|
@ -214,7 +214,7 @@ new trigger: 10
|
|||||||
drop trigger t1_bd;
|
drop trigger t1_bd;
|
||||||
set @val=11;
|
set @val=11;
|
||||||
execute stmt using @val;
|
execute stmt using @val;
|
||||||
call p_verify_reprepare_count(1);
|
call p_verify_reprepare_count(0);
|
||||||
SUCCESS
|
SUCCESS
|
||||||
|
|
||||||
select @message;
|
select @message;
|
||||||
@ -224,7 +224,7 @@ Test 6-e: removing a relevant trigger
|
|||||||
drop trigger t1_bi;
|
drop trigger t1_bi;
|
||||||
set @val=12;
|
set @val=12;
|
||||||
execute stmt using @val;
|
execute stmt using @val;
|
||||||
call p_verify_reprepare_count(1);
|
call p_verify_reprepare_count(0);
|
||||||
SUCCESS
|
SUCCESS
|
||||||
|
|
||||||
select @message;
|
select @message;
|
||||||
@ -384,7 +384,7 @@ a
|
|||||||
flush table t1;
|
flush table t1;
|
||||||
set @var=9;
|
set @var=9;
|
||||||
execute stmt using @var;
|
execute stmt using @var;
|
||||||
call p_verify_reprepare_count(1);
|
call p_verify_reprepare_count(0);
|
||||||
SUCCESS
|
SUCCESS
|
||||||
|
|
||||||
select * from t2;
|
select * from t2;
|
||||||
@ -830,7 +830,7 @@ a b c
|
|||||||
10 20 50
|
10 20 50
|
||||||
20 40 100
|
20 40 100
|
||||||
30 60 150
|
30 60 150
|
||||||
call p_verify_reprepare_count(1);
|
call p_verify_reprepare_count(0);
|
||||||
SUCCESS
|
SUCCESS
|
||||||
|
|
||||||
# Check that we properly handle ALTER VIEW statements.
|
# Check that we properly handle ALTER VIEW statements.
|
||||||
@ -1206,7 +1206,7 @@ drop trigger v2_bi;
|
|||||||
set @message=null;
|
set @message=null;
|
||||||
set @var=9;
|
set @var=9;
|
||||||
execute stmt using @var;
|
execute stmt using @var;
|
||||||
call p_verify_reprepare_count(1);
|
call p_verify_reprepare_count(0);
|
||||||
SUCCESS
|
SUCCESS
|
||||||
|
|
||||||
select @message;
|
select @message;
|
||||||
@ -2578,7 +2578,7 @@ SELECT * FROM t1;
|
|||||||
a
|
a
|
||||||
2048
|
2048
|
||||||
1025
|
1025
|
||||||
1024
|
2048
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
#
|
#
|
||||||
# End of 10.1 tests
|
# End of 10.1 tests
|
||||||
|
@ -250,7 +250,8 @@ drop trigger t1_bd;
|
|||||||
|
|
||||||
set @val=11;
|
set @val=11;
|
||||||
execute stmt using @val;
|
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;
|
select @message;
|
||||||
|
|
||||||
--echo Test 6-e: removing a relevant trigger
|
--echo Test 6-e: removing a relevant trigger
|
||||||
@ -259,7 +260,8 @@ drop trigger t1_bi;
|
|||||||
|
|
||||||
set @val=12;
|
set @val=12;
|
||||||
execute stmt using @val;
|
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;
|
select @message;
|
||||||
set @val=13;
|
set @val=13;
|
||||||
execute stmt using @val;
|
execute stmt using @val;
|
||||||
@ -374,7 +376,8 @@ select * from t3;
|
|||||||
flush table t1;
|
flush table t1;
|
||||||
set @var=9;
|
set @var=9;
|
||||||
execute stmt using @var;
|
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 t2;
|
||||||
select * from t3;
|
select * from t3;
|
||||||
drop view v1;
|
drop view v1;
|
||||||
@ -743,7 +746,7 @@ call p_verify_reprepare_count(1);
|
|||||||
flush table t2;
|
flush table t2;
|
||||||
|
|
||||||
execute stmt;
|
execute stmt;
|
||||||
call p_verify_reprepare_count(1);
|
call p_verify_reprepare_count(0);
|
||||||
|
|
||||||
--echo # Check that we properly handle ALTER VIEW statements.
|
--echo # Check that we properly handle ALTER VIEW statements.
|
||||||
execute stmt;
|
execute stmt;
|
||||||
@ -967,7 +970,8 @@ drop trigger v2_bi;
|
|||||||
set @message=null;
|
set @message=null;
|
||||||
set @var=9;
|
set @var=9;
|
||||||
execute stmt using @var;
|
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;
|
select @message;
|
||||||
create trigger v2_bi after insert on v2 for each row set @message="v2_ai";
|
create trigger v2_bi after insert on v2 for each row set @message="v2_ai";
|
||||||
set @var= 10;
|
set @var= 10;
|
||||||
|
@ -6816,6 +6816,34 @@ r
|
|||||||
drop view v1;
|
drop view v1;
|
||||||
drop table t1;
|
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
|
# End of 10.2 tests
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
@ -6539,6 +6539,46 @@ select * from (select sum((select * from cte)) as r) dt2;
|
|||||||
drop view v1;
|
drop view v1;
|
||||||
drop table t1;
|
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 #
|
||||||
--echo # End of 10.2 tests
|
--echo # End of 10.2 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
@ -173,11 +173,12 @@ write_parameter(IO_CACHE *file, const uchar* base, File_option *parameter)
|
|||||||
{
|
{
|
||||||
/* string have to be allocated already */
|
/* string have to be allocated already */
|
||||||
LEX_STRING *val_s= (LEX_STRING *)(base + parameter->offset);
|
LEX_STRING *val_s= (LEX_STRING *)(base + parameter->offset);
|
||||||
time_t tm= my_time(0);
|
// number of microseconds since Epoch, timezone-independent
|
||||||
|
my_hrtime_t tm= my_hrtime();
|
||||||
get_date(val_s->str, GETDATE_DATE_TIME|GETDATE_GMT|GETDATE_FIXEDLENGTH,
|
// Paded to 19 characters for compatibility
|
||||||
tm);
|
val_s->length= snprintf(val_s->str, MICROSECOND_TIMESTAMP_BUFFER_SIZE,
|
||||||
val_s->length= PARSE_FILE_TIMESTAMPLENGTH;
|
"%019lld", tm.val);
|
||||||
|
DBUG_ASSERT(val_s->length == MICROSECOND_TIMESTAMP_BUFFER_SIZE-1);
|
||||||
if (my_b_write(file, (const uchar *)val_s->str,
|
if (my_b_write(file, (const uchar *)val_s->str,
|
||||||
PARSE_FILE_TIMESTAMPLENGTH))
|
PARSE_FILE_TIMESTAMPLENGTH))
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
@ -833,16 +834,16 @@ File_parser::parse(uchar* base, MEM_ROOT *mem_root,
|
|||||||
{
|
{
|
||||||
/* string have to be allocated already */
|
/* string have to be allocated already */
|
||||||
LEX_STRING *val= (LEX_STRING *)(base + parameter->offset);
|
LEX_STRING *val= (LEX_STRING *)(base + parameter->offset);
|
||||||
/* yyyy-mm-dd HH:MM:SS = 19(PARSE_FILE_TIMESTAMPLENGTH) characters */
|
/* 19 characters of timestamp */
|
||||||
if (ptr[PARSE_FILE_TIMESTAMPLENGTH] != '\n')
|
if (ptr[MICROSECOND_TIMESTAMP_BUFFER_SIZE-1] != '\n')
|
||||||
{
|
{
|
||||||
my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0),
|
my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0),
|
||||||
parameter->name.str, line);
|
parameter->name.str, line);
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
memcpy(val->str, ptr, PARSE_FILE_TIMESTAMPLENGTH);
|
memcpy(val->str, ptr, MICROSECOND_TIMESTAMP_BUFFER_SIZE-1);
|
||||||
val->str[val->length= PARSE_FILE_TIMESTAMPLENGTH]= '\0';
|
val->str[val->length= MICROSECOND_TIMESTAMP_BUFFER_SIZE-1]= '\0';
|
||||||
ptr+= (PARSE_FILE_TIMESTAMPLENGTH+1);
|
ptr+= MICROSECOND_TIMESTAMP_BUFFER_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FILE_OPTIONS_STRLIST:
|
case FILE_OPTIONS_STRLIST:
|
||||||
|
@ -1906,6 +1906,11 @@ retry_share:
|
|||||||
table_list->alias.str);
|
table_list->alias.str);
|
||||||
goto err_lock;
|
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,
|
This table is a view. Validate its metadata version: in particular,
|
||||||
that it was a view when the statement was prepared.
|
that it was a view when the statement was prepared.
|
||||||
@ -1913,10 +1918,6 @@ retry_share:
|
|||||||
if (check_and_update_table_version(thd, table_list, share))
|
if (check_and_update_table_version(thd, table_list, share))
|
||||||
goto err_lock;
|
goto err_lock;
|
||||||
|
|
||||||
/* Open view */
|
|
||||||
if (mysql_make_view(thd, share, table_list, false))
|
|
||||||
goto err_lock;
|
|
||||||
|
|
||||||
|
|
||||||
/* TODO: Don't free this */
|
/* TODO: Don't free this */
|
||||||
tdc_release_share(share);
|
tdc_release_share(share);
|
||||||
@ -2721,7 +2722,7 @@ static bool inject_reprepare(THD *thd)
|
|||||||
|
|
||||||
@sa Execute_observer
|
@sa Execute_observer
|
||||||
@sa check_prepared_statement() to see cases when an observer is installed
|
@sa check_prepared_statement() to see cases when an observer is installed
|
||||||
@sa TABLE_LIST::is_table_ref_id_equal()
|
@sa TABLE_LIST::is_the_same_definition()
|
||||||
@sa TABLE_SHARE::get_table_ref_id()
|
@sa TABLE_SHARE::get_table_ref_id()
|
||||||
|
|
||||||
@param[in] thd used to report errors
|
@param[in] thd used to report errors
|
||||||
@ -2738,7 +2739,7 @@ static bool
|
|||||||
check_and_update_table_version(THD *thd,
|
check_and_update_table_version(THD *thd,
|
||||||
TABLE_LIST *tables, TABLE_SHARE *table_share)
|
TABLE_LIST *tables, TABLE_SHARE *table_share)
|
||||||
{
|
{
|
||||||
if (! tables->is_table_ref_id_equal(table_share))
|
if (! tables->is_the_same_definition(thd, table_share))
|
||||||
{
|
{
|
||||||
if (thd->m_reprepare_observer &&
|
if (thd->m_reprepare_observer &&
|
||||||
thd->m_reprepare_observer->report_error(thd))
|
thd->m_reprepare_observer->report_error(thd))
|
||||||
@ -2844,7 +2845,9 @@ bool tdc_open_view(THD *thd, TABLE_LIST *table_list, uint flags)
|
|||||||
|
|
||||||
DBUG_ASSERT(share->is_view);
|
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
|
Check TABLE_SHARE-version of view only if we have been instructed to do
|
||||||
@ -2859,7 +2862,6 @@ bool tdc_open_view(THD *thd, TABLE_LIST *table_list, uint flags)
|
|||||||
goto ret;
|
goto ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
err= mysql_make_view(thd, share, table_list, (flags & OPEN_VIEW_NO_PARSE));
|
|
||||||
ret:
|
ret:
|
||||||
tdc_release_share(share);
|
tdc_release_share(share);
|
||||||
|
|
||||||
|
@ -3879,6 +3879,7 @@ Statement::Statement(LEX *lex_arg, MEM_ROOT *mem_root_arg,
|
|||||||
id(id_arg),
|
id(id_arg),
|
||||||
column_usage(MARK_COLUMNS_READ),
|
column_usage(MARK_COLUMNS_READ),
|
||||||
lex(lex_arg),
|
lex(lex_arg),
|
||||||
|
hr_prepare_time({0}),
|
||||||
db(null_clex_str)
|
db(null_clex_str)
|
||||||
{
|
{
|
||||||
name= null_clex_str;
|
name= null_clex_str;
|
||||||
@ -3897,6 +3898,7 @@ void Statement::set_statement(Statement *stmt)
|
|||||||
column_usage= stmt->column_usage;
|
column_usage= stmt->column_usage;
|
||||||
lex= stmt->lex;
|
lex= stmt->lex;
|
||||||
query_string= stmt->query_string;
|
query_string= stmt->query_string;
|
||||||
|
hr_prepare_time= stmt->hr_prepare_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1122,6 +1122,7 @@ public:
|
|||||||
|
|
||||||
LEX_CSTRING name; /* name for named prepared statements */
|
LEX_CSTRING name; /* name for named prepared statements */
|
||||||
LEX *lex; // parse tree descriptor
|
LEX *lex; // parse tree descriptor
|
||||||
|
my_hrtime_t hr_prepare_time; // time of preparation in microseconds
|
||||||
/*
|
/*
|
||||||
Points to the query associated with this statement. It's const, but
|
Points to the query associated with this statement. It's const, but
|
||||||
we need to declare it char * because all table handlers are written
|
we need to declare it char * because all table handlers are written
|
||||||
|
@ -4311,6 +4311,8 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
|
|||||||
if (thd->spcont == NULL)
|
if (thd->spcont == NULL)
|
||||||
general_log_write(thd, COM_STMT_PREPARE, query(), query_length());
|
general_log_write(thd, COM_STMT_PREPARE, query(), query_length());
|
||||||
}
|
}
|
||||||
|
// The same format as for triggers to compare
|
||||||
|
hr_prepare_time= my_hrtime();
|
||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4404,8 +4406,8 @@ Prepared_statement::execute_loop(String *expanded_query,
|
|||||||
uchar *packet_end)
|
uchar *packet_end)
|
||||||
{
|
{
|
||||||
Reprepare_observer reprepare_observer;
|
Reprepare_observer reprepare_observer;
|
||||||
bool error;
|
|
||||||
int reprepare_attempt= 0;
|
int reprepare_attempt= 0;
|
||||||
|
bool error;
|
||||||
iterations= FALSE;
|
iterations= FALSE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -7117,13 +7117,15 @@ static bool store_trigger(THD *thd, Trigger *trigger,
|
|||||||
table->field[14]->store(STRING_WITH_LEN("OLD"), cs);
|
table->field[14]->store(STRING_WITH_LEN("OLD"), cs);
|
||||||
table->field[15]->store(STRING_WITH_LEN("NEW"), cs);
|
table->field[15]->store(STRING_WITH_LEN("NEW"), cs);
|
||||||
|
|
||||||
if (trigger->create_time)
|
if (trigger->hr_create_time.val)
|
||||||
{
|
{
|
||||||
|
/* timestamp is in microseconds */
|
||||||
table->field[16]->set_notnull();
|
table->field[16]->set_notnull();
|
||||||
thd->variables.time_zone->gmt_sec_to_TIME(×tamp,
|
thd->variables.time_zone->
|
||||||
(my_time_t)(trigger->create_time/100));
|
gmt_sec_to_TIME(×tamp,
|
||||||
/* timestamp is with 6 digits */
|
(my_time_t)
|
||||||
timestamp.second_part= (trigger->create_time % 100) * 10000;
|
hrtime_to_time(trigger->hr_create_time));
|
||||||
|
timestamp.second_part= hrtime_sec_part(trigger->hr_create_time);
|
||||||
((Field_temporal_with_date*) table->field[16])->store_time_dec(×tamp,
|
((Field_temporal_with_date*) table->field[16])->store_time_dec(×tamp,
|
||||||
2);
|
2);
|
||||||
}
|
}
|
||||||
@ -10294,12 +10296,14 @@ static bool show_create_trigger_impl(THD *thd, Trigger *trigger)
|
|||||||
trigger->db_cl_name.length,
|
trigger->db_cl_name.length,
|
||||||
system_charset_info);
|
system_charset_info);
|
||||||
|
|
||||||
if (trigger->create_time)
|
if (trigger->hr_create_time.val)
|
||||||
{
|
{
|
||||||
MYSQL_TIME timestamp;
|
MYSQL_TIME timestamp;
|
||||||
thd->variables.time_zone->gmt_sec_to_TIME(×tamp,
|
thd->variables.time_zone->
|
||||||
(my_time_t)(trigger->create_time/100));
|
gmt_sec_to_TIME(×tamp,
|
||||||
timestamp.second_part= (trigger->create_time % 100) * 10000;
|
(my_time_t)
|
||||||
|
hrtime_to_time(trigger->hr_create_time));
|
||||||
|
timestamp.second_part= hrtime_sec_part(trigger->hr_create_time);
|
||||||
p->store(×tamp, 2);
|
p->store(×tamp, 2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -37,6 +37,8 @@
|
|||||||
#ifdef WITH_WSREP
|
#ifdef WITH_WSREP
|
||||||
#include "debug_sync.h"
|
#include "debug_sync.h"
|
||||||
#endif /* WITH_WSREP */
|
#endif /* WITH_WSREP */
|
||||||
|
#include <my_time.h>
|
||||||
|
#include <mysql_time.h>
|
||||||
|
|
||||||
LEX_CSTRING *make_lex_string(LEX_CSTRING *lex_str,
|
LEX_CSTRING *make_lex_string(LEX_CSTRING *lex_str,
|
||||||
const char* str, size_t length,
|
const char* str, size_t length,
|
||||||
@ -212,7 +214,7 @@ static File_option triggers_file_parameters[]=
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
{ STRING_WITH_LEN("created") },
|
{ STRING_WITH_LEN("created") },
|
||||||
my_offsetof(class Table_triggers_list, create_times),
|
my_offsetof(class Table_triggers_list, hr_create_times),
|
||||||
FILE_OPTIONS_ULLLIST
|
FILE_OPTIONS_ULLLIST
|
||||||
},
|
},
|
||||||
{ { 0, 0 }, 0, FILE_OPTIONS_STRING }
|
{ { 0, 0 }, 0, FILE_OPTIONS_STRING }
|
||||||
@ -896,6 +898,10 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
|
|||||||
if (!(trigger= new (&table->mem_root) Trigger(this, 0)))
|
if (!(trigger= new (&table->mem_root) Trigger(this, 0)))
|
||||||
goto err_without_cleanup;
|
goto err_without_cleanup;
|
||||||
|
|
||||||
|
/* Time with in microseconds */
|
||||||
|
trigger->hr_create_time= make_hr_time(thd->query_start(),
|
||||||
|
thd->query_start_sec_part());
|
||||||
|
|
||||||
/* Create trigger_name.TRN file to ensure trigger name is unique */
|
/* Create trigger_name.TRN file to ensure trigger name is unique */
|
||||||
if (sql_create_definition_file(NULL, &trigname_file, &trigname_file_type,
|
if (sql_create_definition_file(NULL, &trigname_file, &trigname_file_type,
|
||||||
(uchar*)&trigname, trigname_file_parameters))
|
(uchar*)&trigname, trigname_file_parameters))
|
||||||
@ -904,8 +910,6 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
|
|||||||
/* Populate the trigger object */
|
/* Populate the trigger object */
|
||||||
|
|
||||||
trigger->sql_mode= thd->variables.sql_mode;
|
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,
|
build_trig_stmt_query(thd, tables, stmt_query, &trigger_definition,
|
||||||
&trigger->definer, trg_definer_holder);
|
&trigger->definer, trg_definer_holder);
|
||||||
|
|
||||||
@ -973,7 +977,7 @@ void Table_triggers_list::empty_lists()
|
|||||||
client_cs_names.empty();
|
client_cs_names.empty();
|
||||||
connection_cl_names.empty();
|
connection_cl_names.empty();
|
||||||
db_cl_names.empty();
|
db_cl_names.empty();
|
||||||
create_times.empty();
|
hr_create_times.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1009,7 +1013,7 @@ bool Trigger::add_to_file_list(void* param_arg)
|
|||||||
base->client_cs_names.push_back(&client_cs_name, mem_root) ||
|
base->client_cs_names.push_back(&client_cs_name, mem_root) ||
|
||||||
base->connection_cl_names.push_back(&connection_cl_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->db_cl_names.push_back(&db_cl_name, mem_root) ||
|
||||||
base->create_times.push_back(&create_time, mem_root))
|
base->hr_create_times.push_back(&hr_create_time.val, mem_root))
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1391,7 +1395,8 @@ bool Table_triggers_list::check_n_load(THD *thd, const LEX_CSTRING *db,
|
|||||||
List_iterator_fast<LEX_CSTRING> it_client_cs_name(trigger_list->client_cs_names);
|
List_iterator_fast<LEX_CSTRING> it_client_cs_name(trigger_list->client_cs_names);
|
||||||
List_iterator_fast<LEX_CSTRING> it_connection_cl_name(trigger_list->connection_cl_names);
|
List_iterator_fast<LEX_CSTRING> it_connection_cl_name(trigger_list->connection_cl_names);
|
||||||
List_iterator_fast<LEX_CSTRING> it_db_cl_name(trigger_list->db_cl_names);
|
List_iterator_fast<LEX_CSTRING> 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->hr_create_times);
|
||||||
LEX *old_lex= thd->lex;
|
LEX *old_lex= thd->lex;
|
||||||
LEX lex;
|
LEX lex;
|
||||||
sp_rcontext *save_spcont= thd->spcont;
|
sp_rcontext *save_spcont= thd->spcont;
|
||||||
@ -1477,7 +1482,14 @@ bool Table_triggers_list::check_n_load(THD *thd, const LEX_CSTRING *db,
|
|||||||
|
|
||||||
trigger->sql_mode= sql_mode;
|
trigger->sql_mode= sql_mode;
|
||||||
trigger->definition= *trg_create_str;
|
trigger->definition= *trg_create_str;
|
||||||
trigger->create_time= trg_create_time ? *trg_create_time : 0;
|
trigger->hr_create_time=
|
||||||
|
my_hrtime_t({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->hr_create_time.val < 429496729400ULL)
|
||||||
|
trigger->hr_create_time.val*= 10000;
|
||||||
trigger->name= sp ? sp->m_name : empty_clex_str;
|
trigger->name= sp ? sp->m_name : empty_clex_str;
|
||||||
trigger->on_table_name.str= (char*) lex.raw_trg_on_table_name_begin;
|
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 -
|
trigger->on_table_name.length= (lex.raw_trg_on_table_name_end -
|
||||||
|
@ -115,7 +115,7 @@ public:
|
|||||||
GRANT_INFO subject_table_grants;
|
GRANT_INFO subject_table_grants;
|
||||||
sql_mode_t sql_mode;
|
sql_mode_t sql_mode;
|
||||||
/* Store create time. Can't be mysql_time_t as this holds also sub seconds */
|
/* Store create time. Can't be mysql_time_t as this holds also sub seconds */
|
||||||
ulonglong create_time;
|
my_hrtime_t hr_create_time; // Create time timestamp in microseconds
|
||||||
trg_event_type event;
|
trg_event_type event;
|
||||||
trg_action_time_type action_time;
|
trg_action_time_type action_time;
|
||||||
uint action_order;
|
uint action_order;
|
||||||
@ -198,7 +198,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
List<ulonglong> definition_modes_list;
|
List<ulonglong> definition_modes_list;
|
||||||
/** Create times for triggers */
|
/** Create times for triggers */
|
||||||
List<ulonglong> create_times;
|
List<ulonglong> hr_create_times;
|
||||||
|
|
||||||
List<LEX_CSTRING> definers_list;
|
List<LEX_CSTRING> definers_list;
|
||||||
|
|
||||||
|
@ -786,7 +786,7 @@ static File_option view_parameters[]=
|
|||||||
my_offsetof(TABLE_LIST, with_check),
|
my_offsetof(TABLE_LIST, with_check),
|
||||||
FILE_OPTIONS_ULONGLONG},
|
FILE_OPTIONS_ULONGLONG},
|
||||||
{{ STRING_WITH_LEN("timestamp")},
|
{{ STRING_WITH_LEN("timestamp")},
|
||||||
my_offsetof(TABLE_LIST, timestamp),
|
my_offsetof(TABLE_LIST, hr_timestamp),
|
||||||
FILE_OPTIONS_TIMESTAMP},
|
FILE_OPTIONS_TIMESTAMP},
|
||||||
{{ STRING_WITH_LEN("create-version")},
|
{{ STRING_WITH_LEN("create-version")},
|
||||||
my_offsetof(TABLE_LIST, file_version),
|
my_offsetof(TABLE_LIST, file_version),
|
||||||
@ -810,6 +810,15 @@ static File_option view_parameters[]=
|
|||||||
FILE_OPTIONS_STRING}
|
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_CSTRING view_file_type[]= {{STRING_WITH_LEN("VIEW") }};
|
static LEX_CSTRING view_file_type[]= {{STRING_WITH_LEN("VIEW") }};
|
||||||
|
|
||||||
|
|
||||||
@ -827,8 +836,8 @@ int mariadb_fix_view(THD *thd, TABLE_LIST *view, bool wrong_checksum,
|
|||||||
&path, path_buff, sizeof(path_buff),
|
&path, path_buff, sizeof(path_buff),
|
||||||
&file, view);
|
&file, view);
|
||||||
/* init timestamp */
|
/* init timestamp */
|
||||||
if (!view->timestamp.str)
|
if (!view->hr_timestamp.str)
|
||||||
view->timestamp.str= view->timestamp_buffer;
|
view->hr_timestamp.str= view->timestamp_buffer;
|
||||||
|
|
||||||
if (swap_alg && view->algorithm != VIEW_ALGORITHM_UNDEFINED)
|
if (swap_alg && view->algorithm != VIEW_ALGORITHM_UNDEFINED)
|
||||||
{
|
{
|
||||||
@ -1029,8 +1038,8 @@ loop_out:
|
|||||||
&path, path_buff, sizeof(path_buff),
|
&path, path_buff, sizeof(path_buff),
|
||||||
&file, view);
|
&file, view);
|
||||||
/* init timestamp */
|
/* init timestamp */
|
||||||
if (!view->timestamp.str)
|
if (!view->hr_timestamp.str)
|
||||||
view->timestamp.str= view->timestamp_buffer;
|
view->hr_timestamp.str= view->timestamp_buffer;
|
||||||
|
|
||||||
/* check old .frm */
|
/* check old .frm */
|
||||||
{
|
{
|
||||||
@ -1155,7 +1164,32 @@ err:
|
|||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Reads view definition "version"
|
||||||
|
|
||||||
|
@param[in] share Share object of view
|
||||||
|
|
||||||
|
@return true on error, otherwise false
|
||||||
|
*/
|
||||||
|
|
||||||
|
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;
|
||||||
|
share->tabledef_version.length= 0; // safety if the drfinition file is brocken
|
||||||
|
|
||||||
|
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
|
read VIEW .frm and create structures
|
||||||
@ -1217,6 +1251,10 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
|
|||||||
mysql_derived_reinit(thd, NULL, table);
|
mysql_derived_reinit(thd, NULL, table);
|
||||||
|
|
||||||
DEBUG_SYNC(thd, "after_cached_view_opened");
|
DEBUG_SYNC(thd, "after_cached_view_opened");
|
||||||
|
if (!share->tabledef_version.length)
|
||||||
|
{
|
||||||
|
mariadb_view_version_get(share);
|
||||||
|
}
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1253,8 +1291,8 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
|
|||||||
arena= thd->activate_stmt_arena_if_needed(&backup);
|
arena= thd->activate_stmt_arena_if_needed(&backup);
|
||||||
|
|
||||||
/* init timestamp */
|
/* init timestamp */
|
||||||
if (!table->timestamp.str)
|
if (!table->hr_timestamp.str)
|
||||||
table->timestamp.str= table->timestamp_buffer;
|
table->hr_timestamp.str= table->timestamp_buffer;
|
||||||
/* prepare default values for old format */
|
/* prepare default values for old format */
|
||||||
table->view_suid= TRUE;
|
table->view_suid= TRUE;
|
||||||
table->definer.user.str= table->definer.host.str= 0;
|
table->definer.user.str= table->definer.host.str= 0;
|
||||||
@ -1270,6 +1308,19 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
|
|||||||
required_view_parameters,
|
required_view_parameters,
|
||||||
&file_parser_dummy_hook)))
|
&file_parser_dummy_hook)))
|
||||||
goto end;
|
goto end;
|
||||||
|
if (!share->tabledef_version.length)
|
||||||
|
{
|
||||||
|
share->tabledef_version.str= (const uchar *)
|
||||||
|
memdup_root(&share->mem_root,
|
||||||
|
(const void *)
|
||||||
|
table->hr_timestamp.str,
|
||||||
|
(share->tabledef_version.length=
|
||||||
|
table->hr_timestamp.length));
|
||||||
|
}
|
||||||
|
if (!table->tabledef_version.length)
|
||||||
|
{
|
||||||
|
table->set_view_def_version(&table->hr_timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
check old format view .frm
|
check old format view .frm
|
||||||
@ -2200,7 +2251,7 @@ mysql_rename_view(THD *thd,
|
|||||||
object for it.
|
object for it.
|
||||||
*/
|
*/
|
||||||
view_def.reset();
|
view_def.reset();
|
||||||
view_def.timestamp.str= view_def.timestamp_buffer;
|
view_def.hr_timestamp.str= view_def.timestamp_buffer;
|
||||||
view_def.view_suid= TRUE;
|
view_def.view_suid= TRUE;
|
||||||
|
|
||||||
/* get view definition and source */
|
/* get view definition and source */
|
||||||
|
67
sql/table.cc
67
sql/table.cc
@ -8861,6 +8861,73 @@ bool TABLE_LIST::is_with_table()
|
|||||||
return derived && derived->with_element;
|
return derived && derived->with_element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Check if the definition are the same.
|
||||||
|
|
||||||
|
If versions do not match it check definitions (with checking and setting
|
||||||
|
trigger definition versions (times)
|
||||||
|
|
||||||
|
@param[in] view TABLE_LIST of the view
|
||||||
|
@param[in] share Share object of view
|
||||||
|
|
||||||
|
@return false on error or different definitions.
|
||||||
|
|
||||||
|
@sa check_and_update_table_version()
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool TABLE_LIST::is_the_same_definition(THD* thd, TABLE_SHARE *s)
|
||||||
|
{
|
||||||
|
enum enum_table_ref_type tp= s->get_table_ref_type();
|
||||||
|
if (m_table_ref_type == tp)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Cache have not changed which means that definition was not changed
|
||||||
|
including triggers
|
||||||
|
*/
|
||||||
|
if (m_table_ref_version == s->get_table_ref_version())
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
If cache changed then 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))
|
||||||
|
{
|
||||||
|
// Definition have not changed, let's check if triggers changed.
|
||||||
|
if (table && table->triggers)
|
||||||
|
{
|
||||||
|
|
||||||
|
my_hrtime_t hr_stmt_prepare= thd->hr_prepare_time;
|
||||||
|
if (hr_stmt_prepare.val)
|
||||||
|
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 (hr_stmt_prepare.val <= tr->hr_create_time.val)
|
||||||
|
{
|
||||||
|
set_tabledef_version(s);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set_table_id(s);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tabledef_version.length= 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
set_tabledef_version(s);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
uint TABLE_SHARE::actual_n_key_parts(THD *thd)
|
uint TABLE_SHARE::actual_n_key_parts(THD *thd)
|
||||||
{
|
{
|
||||||
return use_ext_keys &&
|
return use_ext_keys &&
|
||||||
|
66
sql/table.h
66
sql/table.h
@ -32,8 +32,18 @@
|
|||||||
#include "filesort_utils.h"
|
#include "filesort_utils.h"
|
||||||
#include "parse_file.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 */
|
/* Structs that defines the TABLE */
|
||||||
|
|
||||||
@ -1028,7 +1038,7 @@ struct TABLE_SHARE
|
|||||||
with a base table, a base table is replaced with a temporary
|
with a base table, a base table is replaced with a temporary
|
||||||
table and so on.
|
table and so on.
|
||||||
|
|
||||||
@sa TABLE_LIST::is_table_ref_id_equal()
|
@sa TABLE_LIST::is_the_same_definition()
|
||||||
*/
|
*/
|
||||||
ulong get_table_ref_version() const
|
ulong get_table_ref_version() const
|
||||||
{
|
{
|
||||||
@ -2369,6 +2379,12 @@ struct TABLE_LIST
|
|||||||
to view with SQL SECURITY DEFINER)
|
to view with SQL SECURITY DEFINER)
|
||||||
*/
|
*/
|
||||||
Security_context *security_ctx;
|
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
|
This view security context (non-zero only for views with
|
||||||
SQL SECURITY DEFINER)
|
SQL SECURITY DEFINER)
|
||||||
@ -2382,7 +2398,7 @@ struct TABLE_LIST
|
|||||||
LEX_CSTRING source; /* source of CREATE VIEW */
|
LEX_CSTRING source; /* source of CREATE VIEW */
|
||||||
LEX_CSTRING view_db; /* saved view database */
|
LEX_CSTRING view_db; /* saved view database */
|
||||||
LEX_CSTRING view_name; /* saved view name */
|
LEX_CSTRING view_name; /* saved view name */
|
||||||
LEX_STRING timestamp; /* GMT time stamp of last operation */
|
LEX_STRING hr_timestamp; /* time stamp of last operation */
|
||||||
LEX_USER definer; /* definer of view */
|
LEX_USER definer; /* definer of view */
|
||||||
ulonglong file_version; /* version of file's field set */
|
ulonglong file_version; /* version of file's field set */
|
||||||
ulonglong mariadb_version; /* version of server on creation */
|
ulonglong mariadb_version; /* version of server on creation */
|
||||||
@ -2465,7 +2481,7 @@ struct TABLE_LIST
|
|||||||
/* TABLE_TYPE_UNKNOWN if any type is acceptable */
|
/* TABLE_TYPE_UNKNOWN if any type is acceptable */
|
||||||
Table_type required_type;
|
Table_type required_type;
|
||||||
handlerton *db_type; /* table_type for handler */
|
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
|
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.
|
used for implicit LOCK TABLES only and won't be used in real statement.
|
||||||
@ -2657,19 +2673,7 @@ struct TABLE_LIST
|
|||||||
*/
|
*/
|
||||||
bool process_index_hints(TABLE *table);
|
bool process_index_hints(TABLE *table);
|
||||||
|
|
||||||
/**
|
bool is_the_same_definition(THD *thd, TABLE_SHARE *s);
|
||||||
Compare the version of metadata from the previous execution
|
|
||||||
(if any) with values obtained from the current table
|
|
||||||
definition cache element.
|
|
||||||
|
|
||||||
@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());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Record the value of metadata version of the corresponding
|
Record the value of metadata version of the corresponding
|
||||||
table definition cache element in this parse tree node.
|
table definition cache element in this parse tree node.
|
||||||
@ -2686,6 +2690,26 @@ struct TABLE_LIST
|
|||||||
m_table_ref_version= table_ref_version_arg;
|
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. */
|
/* Set of functions returning/setting state of a derived table/view. */
|
||||||
inline bool is_non_derived()
|
inline bool is_non_derived()
|
||||||
{
|
{
|
||||||
@ -2814,6 +2838,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:
|
private:
|
||||||
bool prep_check_option(THD *thd, uint8 check_opt_type);
|
bool prep_check_option(THD *thd, uint8 check_opt_type);
|
||||||
bool prep_where(THD *thd, Item **conds, bool no_where_clause);
|
bool prep_where(THD *thd, Item **conds, bool no_where_clause);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user