1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-01 03:47:19 +03:00

MDEV-7671: Cache VIEW definitions in the TDC

(changes of backported patch are very small: strlen removed, error processing fixed, view open statistics added)
This commit is contained in:
Oleksandr Byelkin
2015-03-10 10:24:20 +01:00
parent 3aa1a600bb
commit 80f03abcca
17 changed files with 141 additions and 213 deletions

View File

@ -86,6 +86,7 @@ Warnings:
Note 1449 The user specified as a definer ('role4'@'') does not exist Note 1449 The user specified as a definer ('role4'@'') does not exist
select * from test.v5; select * from test.v5;
ERROR HY000: The user specified as a definer ('role4'@'') does not exist ERROR HY000: The user specified as a definer ('role4'@'') does not exist
flush tables;
show create view test.v5; show create view test.v5;
View Create View character_set_client collation_connection View Create View character_set_client collation_connection
v5 CREATE ALGORITHM=UNDEFINED DEFINER=`role4`@`%` SQL SECURITY DEFINER VIEW `test`.`v5` AS select (`mysqltest1`.`t1`.`a` + `mysqltest1`.`t1`.`b`) AS `a+b`,`mysqltest1`.`t1`.`c` AS `c` from `mysqltest1`.`t1` latin1 latin1_swedish_ci v5 CREATE ALGORITHM=UNDEFINED DEFINER=`role4`@`%` SQL SECURITY DEFINER VIEW `test`.`v5` AS select (`mysqltest1`.`t1`.`a` + `mysqltest1`.`t1`.`b`) AS `a+b`,`mysqltest1`.`t1`.`c` AS `c` from `mysqltest1`.`t1` latin1 latin1_swedish_ci

View File

@ -115,6 +115,7 @@ open(F, '>', $f) or die "open(>$f): $!";
syswrite F, $_ or die "syswrite($f): $!" syswrite F, $_ or die "syswrite($f): $!"
EOF EOF
flush tables;
show create view test.v5; show create view test.v5;
select * from test.v5; select * from test.v5;
drop user role4; drop user role4;

View File

@ -1016,7 +1016,7 @@ dbcontext::cmd_open(dbcallback_i& cb, const cmd_open_args& arg)
tables.mdl_request.init(MDL_key::TABLE, arg.dbn, arg.tbl, tables.mdl_request.init(MDL_key::TABLE, arg.dbn, arg.tbl,
for_write_flag ? MDL_SHARED_WRITE : MDL_SHARED_READ, MDL_TRANSACTION); for_write_flag ? MDL_SHARED_WRITE : MDL_SHARED_READ, MDL_TRANSACTION);
Open_table_context ot_act(thd, 0); Open_table_context ot_act(thd, 0);
if (!open_table(thd, &tables, thd->mem_root, &ot_act)) { if (!open_table(thd, &tables, &ot_act)) {
table = tables.table; table = tables.table;
} }
#else #else

View File

@ -404,7 +404,7 @@ sql_parse_prepare(const LEX_STRING *file_name, MEM_ROOT *mem_root,
{ {
MY_STAT stat_info; MY_STAT stat_info;
size_t len; size_t len;
char *end, *sign; char *buff, *end, *sign;
File_parser *parser; File_parser *parser;
File file; File file;
DBUG_ENTER("sql_parse_prepare"); DBUG_ENTER("sql_parse_prepare");
@ -426,7 +426,7 @@ sql_parse_prepare(const LEX_STRING *file_name, MEM_ROOT *mem_root,
DBUG_RETURN(0); DBUG_RETURN(0);
} }
if (!(parser->buff= (char*) alloc_root(mem_root, (size_t)(stat_info.st_size+1)))) if (!(buff= (char*) alloc_root(mem_root, (size_t)(stat_info.st_size+1))))
{ {
DBUG_RETURN(0); DBUG_RETURN(0);
} }
@ -437,9 +437,8 @@ sql_parse_prepare(const LEX_STRING *file_name, MEM_ROOT *mem_root,
DBUG_RETURN(0); DBUG_RETURN(0);
} }
if ((len= mysql_file_read(file, (uchar *)parser->buff, if ((len= mysql_file_read(file, (uchar *)buff, stat_info.st_size,
stat_info.st_size, MYF(MY_WME))) == MYF(MY_WME))) == MY_FILE_ERROR)
MY_FILE_ERROR)
{ {
mysql_file_close(file, MYF(MY_WME)); mysql_file_close(file, MYF(MY_WME));
DBUG_RETURN(0); DBUG_RETURN(0);
@ -450,20 +449,20 @@ sql_parse_prepare(const LEX_STRING *file_name, MEM_ROOT *mem_root,
DBUG_RETURN(0); DBUG_RETURN(0);
} }
end= parser->end= parser->buff + len; end= buff + len;
*end= '\0'; // barrier for more simple parsing *end= '\0'; // barrier for more simple parsing
// 7 = 5 (TYPE=) + 1 (letter at least of type name) + 1 ('\n') // 7 = 5 (TYPE=) + 1 (letter at least of type name) + 1 ('\n')
if (len < 7 || if (len < 7 ||
parser->buff[0] != 'T' || buff[0] != 'T' ||
parser->buff[1] != 'Y' || buff[1] != 'Y' ||
parser->buff[2] != 'P' || buff[2] != 'P' ||
parser->buff[3] != 'E' || buff[3] != 'E' ||
parser->buff[4] != '=') buff[4] != '=')
goto frm_error; goto frm_error;
// skip signature; // skip signature;
parser->file_type.str= sign= parser->buff + 5; parser->file_type.str= sign= buff + 5;
while (*sign >= 'A' && *sign <= 'Z' && sign < end) while (*sign >= 'A' && *sign <= 'Z' && sign < end)
sign++; sign++;
if (*sign != '\n') if (*sign != '\n')
@ -472,6 +471,7 @@ sql_parse_prepare(const LEX_STRING *file_name, MEM_ROOT *mem_root,
// EOS for file signature just for safety // EOS for file signature just for safety
*sign= '\0'; *sign= '\0';
parser->end= end;
parser->start= sign + 1; parser->start= sign + 1;
parser->content_ok= 1; parser->content_ok= 1;
@ -504,11 +504,12 @@ frm_error:
*/ */
static char * static const char *
parse_string(char *ptr, char *end, MEM_ROOT *mem_root, LEX_STRING *str) parse_string(const char *ptr, const char *end, MEM_ROOT *mem_root,
LEX_STRING *str)
{ {
// get string length // get string length
char *eol= strchr(ptr, '\n'); const char *eol= strchr(ptr, '\n');
if (eol >= end) if (eol >= end)
return 0; return 0;
@ -535,7 +536,7 @@ parse_string(char *ptr, char *end, MEM_ROOT *mem_root, LEX_STRING *str)
*/ */
my_bool my_bool
read_escaped_string(char *ptr, char *eol, LEX_STRING *str) read_escaped_string(const char *ptr, const char *eol, LEX_STRING *str)
{ {
char *write_pos= str->str; char *write_pos= str->str;
@ -595,10 +596,11 @@ read_escaped_string(char *ptr, char *eol, LEX_STRING *str)
*/ */
char * const char *
parse_escaped_string(char *ptr, char *end, MEM_ROOT *mem_root, LEX_STRING *str) parse_escaped_string(const char *ptr, const char *end, MEM_ROOT *mem_root,
LEX_STRING *str)
{ {
char *eol= strchr(ptr, '\n'); const char *eol= strchr(ptr, '\n');
if (eol == 0 || eol >= end || if (eol == 0 || eol >= end ||
!(str->str= (char*) alloc_root(mem_root, (eol - ptr) + 1)) || !(str->str= (char*) alloc_root(mem_root, (eol - ptr) + 1)) ||
@ -624,11 +626,11 @@ parse_escaped_string(char *ptr, char *end, MEM_ROOT *mem_root, LEX_STRING *str)
\# pointer on symbol after string \# pointer on symbol after string
*/ */
static char * static const char *
parse_quoted_escaped_string(char *ptr, char *end, parse_quoted_escaped_string(const char *ptr, const char *end,
MEM_ROOT *mem_root, LEX_STRING *str) MEM_ROOT *mem_root, LEX_STRING *str)
{ {
char *eol; const char *eol;
uint result_len= 0; uint result_len= 0;
bool escaped= 0; bool escaped= 0;
@ -665,7 +667,7 @@ parse_quoted_escaped_string(char *ptr, char *end,
@param[in] mem_root MEM_ROOT for parameters allocation @param[in] mem_root MEM_ROOT for parameters allocation
*/ */
bool get_file_options_ulllist(char *&ptr, char *end, char *line, bool get_file_options_ulllist(const char *&ptr, const char *end, const char *line,
uchar* base, File_option *parameter, uchar* base, File_option *parameter,
MEM_ROOT *mem_root) MEM_ROOT *mem_root)
{ {
@ -676,7 +678,7 @@ bool get_file_options_ulllist(char *&ptr, char *end, char *line,
while (ptr < end) while (ptr < end)
{ {
int not_used; int not_used;
char *num_end= end; char *num_end= const_cast<char *>(end);
if (!(num= (ulonglong*)alloc_root(mem_root, sizeof(ulonglong))) || if (!(num= (ulonglong*)alloc_root(mem_root, sizeof(ulonglong))) ||
nlist->push_back(num, mem_root)) nlist->push_back(num, mem_root))
goto nlist_err; goto nlist_err;
@ -731,18 +733,18 @@ nlist_err:
my_bool my_bool
File_parser::parse(uchar* base, MEM_ROOT *mem_root, File_parser::parse(uchar* base, MEM_ROOT *mem_root,
struct File_option *parameters, uint required, struct File_option *parameters, uint required,
Unknown_key_hook *hook) Unknown_key_hook *hook) const
{ {
uint first_param= 0, found= 0; uint first_param= 0, found= 0;
char *ptr= start; const char *ptr= start;
char *eol; const char *eol;
LEX_STRING *str; LEX_STRING *str;
List<LEX_STRING> *list; List<LEX_STRING> *list;
DBUG_ENTER("File_parser::parse"); DBUG_ENTER("File_parser::parse");
while (ptr < end && found < required) while (ptr < end && found < required)
{ {
char *line= ptr; const char *line= ptr;
if (*ptr == '#') if (*ptr == '#')
{ {
// it is comment // it is comment
@ -940,9 +942,9 @@ list_err:
*/ */
bool bool
File_parser_dummy_hook::process_unknown_string(char *&unknown_key, File_parser_dummy_hook::process_unknown_string(const char *&unknown_key,
uchar* base, MEM_ROOT *mem_root, uchar* base, MEM_ROOT *mem_root,
char *end) const char *end)
{ {
DBUG_ENTER("file_parser_dummy_hook::process_unknown_string"); DBUG_ENTER("file_parser_dummy_hook::process_unknown_string");
DBUG_PRINT("info", ("Unknown key: '%60s'", unknown_key)); DBUG_PRINT("info", ("Unknown key: '%60s'", unknown_key));

View File

@ -58,8 +58,8 @@ class Unknown_key_hook
public: public:
Unknown_key_hook() {} /* Remove gcc warning */ Unknown_key_hook() {} /* Remove gcc warning */
virtual ~Unknown_key_hook() {} /* Remove gcc warning */ virtual ~Unknown_key_hook() {} /* Remove gcc warning */
virtual bool process_unknown_string(char *&unknown_key, uchar* base, virtual bool process_unknown_string(const char *&unknown_key, uchar* base,
MEM_ROOT *mem_root, char *end)= 0; MEM_ROOT *mem_root, const char *end)= 0;
}; };
@ -69,18 +69,20 @@ class File_parser_dummy_hook: public Unknown_key_hook
{ {
public: public:
File_parser_dummy_hook() {} /* Remove gcc warning */ File_parser_dummy_hook() {} /* Remove gcc warning */
virtual bool process_unknown_string(char *&unknown_key, uchar* base, virtual bool process_unknown_string(const char *&unknown_key, uchar* base,
MEM_ROOT *mem_root, char *end); MEM_ROOT *mem_root, const char *end);
}; };
extern File_parser_dummy_hook file_parser_dummy_hook; extern File_parser_dummy_hook file_parser_dummy_hook;
bool get_file_options_ulllist(char *&ptr, char *end, char *line, bool get_file_options_ulllist(const char *&ptr, const char *end,
uchar* base, File_option *parameter, const char *line, uchar* base,
File_option *parameter,
MEM_ROOT *mem_root); MEM_ROOT *mem_root);
char * const char *
parse_escaped_string(char *ptr, char *end, MEM_ROOT *mem_root, LEX_STRING *str); parse_escaped_string(const char *ptr, const char *end, MEM_ROOT *mem_root,
LEX_STRING *str);
class File_parser; class File_parser;
File_parser *sql_parse_prepare(const LEX_STRING *file_name, File_parser *sql_parse_prepare(const LEX_STRING *file_name,
@ -96,18 +98,18 @@ my_bool rename_in_schema_file(THD *thd,
class File_parser: public Sql_alloc class File_parser: public Sql_alloc
{ {
char *buff, *start, *end; char *start, *end;
LEX_STRING file_type; LEX_STRING file_type;
bool content_ok; bool content_ok;
public: public:
File_parser() :buff(0), start(0), end(0), content_ok(0) File_parser() :start(0), end(0), content_ok(0)
{ file_type.str= 0; file_type.length= 0; } { file_type.str= 0; file_type.length= 0; }
bool ok() { return content_ok; } bool ok() { return content_ok; }
LEX_STRING *type() { return &file_type; } const LEX_STRING *type() const { return &file_type; }
my_bool parse(uchar* base, MEM_ROOT *mem_root, my_bool parse(uchar* base, MEM_ROOT *mem_root,
struct File_option *parameters, uint required, struct File_option *parameters, uint required,
Unknown_key_hook *hook); Unknown_key_hook *hook) const;
friend File_parser *sql_parse_prepare(const LEX_STRING *file_name, friend File_parser *sql_parse_prepare(const LEX_STRING *file_name,
MEM_ROOT *mem_root, MEM_ROOT *mem_root,

View File

@ -250,7 +250,7 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
Now we should be able to open the partially repaired table Now we should be able to open the partially repaired table
to finish the repair in the handler later on. to finish the repair in the handler later on.
*/ */
if (open_table(thd, table_list, thd->mem_root, &ot_ctx)) if (open_table(thd, table_list, &ot_ctx))
{ {
error= send_check_errmsg(thd, table_list, "repair", error= send_check_errmsg(thd, table_list, "repair",
"Failed to open partially repaired table"); "Failed to open partially repaired table");

View File

@ -27,7 +27,6 @@
// mysql_lock_have_duplicate // mysql_lock_have_duplicate
#include "sql_show.h" // append_identifier #include "sql_show.h" // append_identifier
#include "strfunc.h" // find_type #include "strfunc.h" // find_type
#include "parse_file.h" // sql_parse_prepare, File_parser
#include "sql_view.h" // mysql_make_view, VIEW_ANY_ACL #include "sql_view.h" // mysql_make_view, VIEW_ANY_ACL
#include "sql_parse.h" // check_table_access #include "sql_parse.h" // check_table_access
#include "sql_insert.h" // kill_delayed_threads #include "sql_insert.h" // kill_delayed_threads
@ -2075,8 +2074,6 @@ open_table_get_mdl_lock(THD *thd, Open_table_context *ot_ctx,
@param thd Thread context. @param thd Thread context.
@param table_list Open first table in list. @param table_list Open first table in list.
@param mem_root Temporary MEM_ROOT to be used for
parsing .FRMs for views.
@param ot_ctx Context with flags which modify how open works @param ot_ctx Context with flags which modify how open works
and which is used to recover from a failed and which is used to recover from a failed
open_table() attempt. open_table() attempt.
@ -2105,8 +2102,7 @@ open_table_get_mdl_lock(THD *thd, Open_table_context *ot_ctx,
TABLE_LIST::view is set for views). TABLE_LIST::view is set for views).
*/ */
bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
Open_table_context *ot_ctx)
{ {
TABLE *table; TABLE *table;
const char *key; const char *key;
@ -2242,7 +2238,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
if (dd_frm_is_view(thd, path)) if (dd_frm_is_view(thd, path))
{ {
if (!tdc_open_view(thd, table_list, alias, key, key_length, if (!tdc_open_view(thd, table_list, alias, key, key_length,
mem_root, CHECK_METADATA_VERSION)) CHECK_METADATA_VERSION))
{ {
DBUG_ASSERT(table_list->view != 0); DBUG_ASSERT(table_list->view != 0);
DBUG_RETURN(FALSE); // VIEW DBUG_RETURN(FALSE); // VIEW
@ -2416,14 +2412,10 @@ retry_share:
goto err_lock; goto err_lock;
/* Open view */ /* Open view */
if (open_new_frm(thd, share, alias, if (mysql_make_view(thd, share, table_list, false))
(uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
HA_GET_INDEX | HA_TRY_READ_ONLY),
READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
thd->open_options,
0, table_list, mem_root))
goto err_lock; goto err_lock;
/* TODO: Don't free this */ /* TODO: Don't free this */
tdc_release_share(share); tdc_release_share(share);
@ -2981,7 +2973,7 @@ Locked_tables_list::reopen_tables(THD *thd)
continue; continue;
/* Links into thd->open_tables upon success */ /* Links into thd->open_tables upon success */
if (open_table(thd, table_list, thd->mem_root, &ot_ctx)) if (open_table(thd, table_list, &ot_ctx))
{ {
unlink_all_closed_tables(thd, 0, reopen_count); unlink_all_closed_tables(thd, 0, reopen_count);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
@ -3220,7 +3212,6 @@ check_and_update_routine_version(THD *thd, Sroutine_hash_entry *rt,
@param alias Alias name @param alias Alias name
@param cache_key Key for table definition cache @param cache_key Key for table definition cache
@param cache_key_length Length of cache_key @param cache_key_length Length of cache_key
@param mem_root Memory to be used for .frm parsing.
@param flags Flags which modify how we open the view @param flags Flags which modify how we open the view
@todo This function is needed for special handling of views under @todo This function is needed for special handling of views under
@ -3231,7 +3222,7 @@ check_and_update_routine_version(THD *thd, Sroutine_hash_entry *rt,
bool tdc_open_view(THD *thd, TABLE_LIST *table_list, const char *alias, bool tdc_open_view(THD *thd, TABLE_LIST *table_list, const char *alias,
const char *cache_key, uint cache_key_length, const char *cache_key, uint cache_key_length,
MEM_ROOT *mem_root, uint flags) uint flags)
{ {
TABLE not_used; TABLE not_used;
TABLE_SHARE *share; TABLE_SHARE *share;
@ -3258,12 +3249,7 @@ bool tdc_open_view(THD *thd, TABLE_LIST *table_list, const char *alias,
goto ret; goto ret;
} }
err= open_new_frm(thd, share, alias, err= mysql_make_view(thd, share, table_list, (flags & OPEN_VIEW_NO_PARSE));
(HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
HA_GET_INDEX | HA_TRY_READ_ONLY),
READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD | flags,
thd->open_options, &not_used, table_list, mem_root);
ret: ret:
tdc_release_share(share); tdc_release_share(share);
@ -3800,8 +3786,6 @@ open_and_process_routine(THD *thd, Query_tables_list *prelocking_ctx,
this statement has already been built. this statement has already been built.
@param[in] ot_ctx Context used to recover from a failed @param[in] ot_ctx Context used to recover from a failed
open_table() attempt. open_table() attempt.
@param[in] new_frm_mem Temporary MEM_ROOT to be used for
parsing .FRMs for views.
@retval FALSE Success. @retval FALSE Success.
@retval TRUE Error, reported unless there is a chance to recover from it. @retval TRUE Error, reported unless there is a chance to recover from it.
@ -3812,8 +3796,7 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables,
uint *counter, uint flags, uint *counter, uint flags,
Prelocking_strategy *prelocking_strategy, Prelocking_strategy *prelocking_strategy,
bool has_prelocking_list, bool has_prelocking_list,
Open_table_context *ot_ctx, Open_table_context *ot_ctx)
MEM_ROOT *new_frm_mem)
{ {
bool error= FALSE; bool error= FALSE;
bool safe_to_ignore_table= FALSE; bool safe_to_ignore_table= FALSE;
@ -3945,7 +3928,7 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables,
error= open_temporary_table(thd, tables); error= open_temporary_table(thd, tables);
if (!error && !tables->table) if (!error && !tables->table)
error= open_table(thd, tables, new_frm_mem, ot_ctx); error= open_table(thd, tables, ot_ctx);
thd->pop_internal_handler(); thd->pop_internal_handler();
safe_to_ignore_table= no_such_table_handler.safely_trapped_errors(); safe_to_ignore_table= no_such_table_handler.safely_trapped_errors();
@ -3963,7 +3946,7 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables,
error= open_temporary_table(thd, tables); error= open_temporary_table(thd, tables);
if (!error && !tables->table) if (!error && !tables->table)
error= open_table(thd, tables, new_frm_mem, ot_ctx); error= open_table(thd, tables, ot_ctx);
thd->pop_internal_handler(); thd->pop_internal_handler();
safe_to_ignore_table= repair_mrg_table_handler.safely_trapped_errors(); safe_to_ignore_table= repair_mrg_table_handler.safely_trapped_errors();
@ -3981,11 +3964,9 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables,
} }
if (!error && !tables->table) if (!error && !tables->table)
error= open_table(thd, tables, new_frm_mem, ot_ctx); error= open_table(thd, tables, ot_ctx);
} }
free_root(new_frm_mem, MYF(MY_KEEP_PREALLOC));
if (error) if (error)
{ {
if (! ot_ctx->can_recover_from_failed_open() && safe_to_ignore_table) if (! ot_ctx->can_recover_from_failed_open() && safe_to_ignore_table)
@ -4409,7 +4390,6 @@ bool open_tables(THD *thd, const DDL_options_st &options,
TABLE_LIST *tables; TABLE_LIST *tables;
Open_table_context ot_ctx(thd, flags); Open_table_context ot_ctx(thd, flags);
bool error= FALSE; bool error= FALSE;
MEM_ROOT new_frm_mem;
bool some_routine_modifies_data= FALSE; bool some_routine_modifies_data= FALSE;
bool has_prelocking_list; bool has_prelocking_list;
DBUG_ENTER("open_tables"); DBUG_ENTER("open_tables");
@ -4422,13 +4402,6 @@ bool open_tables(THD *thd, const DDL_options_st &options,
DBUG_RETURN(true); DBUG_RETURN(true);
} }
/*
Initialize temporary MEM_ROOT for new .FRM parsing. Do not alloctaate
anything yet, to avoid penalty for statements which don't use views
and thus new .FRM format.
*/
init_sql_alloc(&new_frm_mem, 8024, 0, MYF(0));
thd->current_tablenr= 0; thd->current_tablenr= 0;
restart: restart:
/* /*
@ -4516,8 +4489,7 @@ restart:
{ {
error= open_and_process_table(thd, thd->lex, tables, counter, error= open_and_process_table(thd, thd->lex, tables, counter,
flags, prelocking_strategy, flags, prelocking_strategy,
has_prelocking_list, &ot_ctx, has_prelocking_list, &ot_ctx);
&new_frm_mem);
if (error) if (error)
{ {
@ -4684,8 +4656,6 @@ error:
THD_STAGE_INFO(thd, stage_after_opening_tables); THD_STAGE_INFO(thd, stage_after_opening_tables);
thd_proc_info(thd, 0); thd_proc_info(thd, 0);
free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block
if (error && *table_to_open) if (error && *table_to_open)
{ {
(*table_to_open)->table= NULL; (*table_to_open)->table= NULL;
@ -5079,7 +5049,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
/* This function can't properly handle requests for such metadata locks. */ /* This function can't properly handle requests for such metadata locks. */
DBUG_ASSERT(table_list->mdl_request.type < MDL_SHARED_UPGRADABLE); DBUG_ASSERT(table_list->mdl_request.type < MDL_SHARED_UPGRADABLE);
while ((error= open_table(thd, table_list, thd->mem_root, &ot_ctx)) && while ((error= open_table(thd, table_list, &ot_ctx)) &&
ot_ctx.can_recover_from_failed_open()) ot_ctx.can_recover_from_failed_open())
{ {
/* /*
@ -9150,72 +9120,6 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order)
} }
/*
open new .frm format table
SYNOPSIS
open_new_frm()
THD thread handler
path path to .frm file (without extension)
alias alias for table
db database
table_name name of table
db_stat open flags (for example ->OPEN_KEYFILE|HA_OPEN_RNDFILE..)
can be 0 (example in ha_example_table)
prgflag READ_ALL etc..
ha_open_flags HA_OPEN_ABORT_IF_LOCKED etc..
outparam result table
table_desc TABLE_LIST descriptor
mem_root temporary MEM_ROOT for parsing
*/
bool
open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias,
uint db_stat, uint prgflag,
uint ha_open_flags, TABLE *outparam, TABLE_LIST *table_desc,
MEM_ROOT *mem_root)
{
LEX_STRING pathstr;
File_parser *parser;
char path[FN_REFLEN+1];
DBUG_ENTER("open_new_frm");
/* Create path with extension */
pathstr.length= (uint) (strxnmov(path, sizeof(path) - 1,
share->normalized_path.str,
reg_ext,
NullS) - path);
pathstr.str= path;
if ((parser= sql_parse_prepare(&pathstr, mem_root, 1)))
{
if (is_equal(&view_type, parser->type()))
{
if (table_desc == 0 || table_desc->required_type == FRMTYPE_TABLE)
{
my_error(ER_WRONG_OBJECT, MYF(0), share->db.str, share->table_name.str,
"BASE TABLE");
goto err;
}
if (mysql_make_view(thd, parser, table_desc,
(prgflag & OPEN_VIEW_NO_PARSE)))
goto err;
status_var_increment(thd->status_var.opened_views);
}
else
{
/* only VIEWs are supported now */
my_error(ER_FRM_UNKNOWN_TYPE, MYF(0), share->path.str, parser->type()->str);
goto err;
}
DBUG_RETURN(0);
}
err:
DBUG_RETURN(1);
}
bool is_equal(const LEX_STRING *a, const LEX_STRING *b) bool is_equal(const LEX_STRING *a, const LEX_STRING *b)
{ {
return a->length == b->length && !strncmp(a->str, b->str, a->length); return a->length == b->length && !strncmp(a->str, b->str, a->length);

View File

@ -117,13 +117,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update,
MYSQL_OPEN_GET_NEW_TABLE |\ MYSQL_OPEN_GET_NEW_TABLE |\
MYSQL_OPEN_HAS_MDL_LOCK) MYSQL_OPEN_HAS_MDL_LOCK)
bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx);
Open_table_context *ot_ctx);
bool open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias,
uint db_stat, uint prgflag,
uint ha_open_flags, TABLE *outparam, TABLE_LIST *table_desc,
MEM_ROOT *mem_root);
bool get_key_map_from_key_list(key_map *map, TABLE *table, bool get_key_map_from_key_list(key_map *map, TABLE *table,
List<String> *index_list); List<String> *index_list);
@ -308,16 +302,14 @@ void close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
TABLE *skip_table); TABLE *skip_table);
OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild); OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild);
bool tdc_open_view(THD *thd, TABLE_LIST *table_list, const char *alias, bool tdc_open_view(THD *thd, TABLE_LIST *table_list, const char *alias,
const char *cache_key, uint cache_key_length, const char *cache_key, uint cache_key_length, uint flags);
MEM_ROOT *mem_root, uint flags);
static inline bool tdc_open_view(THD *thd, TABLE_LIST *table_list, static inline bool tdc_open_view(THD *thd, TABLE_LIST *table_list,
const char *alias, MEM_ROOT *mem_root, const char *alias, uint flags)
uint flags)
{ {
const char *key; const char *key;
uint key_length= get_table_def_key(table_list, &key); uint key_length= get_table_def_key(table_list, &key);
return tdc_open_view(thd, table_list, alias, key, key_length, mem_root, flags); return tdc_open_view(thd, table_list, alias, key, key_length, flags);
} }
TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db, TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db,

View File

@ -3966,7 +3966,7 @@ static TABLE *create_table_from_items(THD *thd,
Here we open the destination table, on which we already have Here we open the destination table, on which we already have
an exclusive metadata lock. an exclusive metadata lock.
*/ */
if (open_table(thd, create_table, thd->mem_root, &ot_ctx)) if (open_table(thd, create_table, &ot_ctx))
{ {
quick_rm_table(thd, create_info->db_type, create_table->db, quick_rm_table(thd, create_info->db_type, create_table->db,
table_case_name(create_info, create_table->table_name), table_case_name(create_info, create_table->table_name),

View File

@ -542,8 +542,8 @@ public:
friend class st_select_lex_unit; friend class st_select_lex_unit;
friend bool mysql_new_select(LEX *lex, bool move_down); friend bool mysql_new_select(LEX *lex, bool move_down);
friend bool mysql_make_view(THD *thd, File_parser *parser, friend bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
TABLE_LIST *table, uint flags); bool open_view_no_parse);
friend bool mysql_derived_prepare(THD *thd, LEX *lex, friend bool mysql_derived_prepare(THD *thd, LEX *lex,
TABLE_LIST *orig_table_list); TABLE_LIST *orig_table_list);
friend bool mysql_derived_merge(THD *thd, LEX *lex, friend bool mysql_derived_merge(THD *thd, LEX *lex,

View File

@ -28,6 +28,7 @@
#include "sql_table.h" // filename_to_tablename, #include "sql_table.h" // filename_to_tablename,
// primary_key_name, // primary_key_name,
// build_table_filename // build_table_filename
#include "sql_view.h"
#include "repl_failsafe.h" #include "repl_failsafe.h"
#include "sql_parse.h" // check_access, check_table_access #include "sql_parse.h" // check_access, check_table_access
#include "sql_partition.h" // partition_element #include "sql_partition.h" // partition_element
@ -4371,12 +4372,7 @@ static int fill_schema_table_from_frm(THD *thd, TABLE_LIST *tables,
goto end_share; goto end_share;
} }
if (open_new_frm(thd, share, table_name->str, if (mysql_make_view(thd, share, &table_list, true))
(uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
HA_GET_INDEX | HA_TRY_READ_ONLY),
READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD |
OPEN_VIEW_NO_PARSE,
thd->open_options, &tbl, &table_list, thd->mem_root))
goto end_share; goto end_share;
table_list.view= (LEX*) share->is_view; table_list.view= (LEX*) share->is_view;
res= schema_table->process_table(thd, &table_list, table, res= schema_table->process_table(thd, &table_list, table,

View File

@ -5436,7 +5436,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
lock on this table. The table will be closed by lock on this table. The table will be closed by
close_thread_table() at the end of this branch. close_thread_table() at the end of this branch.
*/ */
open_res= open_table(thd, table, thd->mem_root, &ot_ctx); open_res= open_table(thd, table, &ot_ctx);
/* Restore */ /* Restore */
table->open_strategy= save_open_strategy; table->open_strategy= save_open_strategy;
if (open_res) if (open_res)
@ -7059,7 +7059,7 @@ static bool mysql_inplace_alter_table(THD *thd,
} }
table_list->mdl_request.ticket= mdl_ticket; table_list->mdl_request.ticket= mdl_ticket;
if (open_table(thd, table_list, thd->mem_root, &ot_ctx)) if (open_table(thd, table_list, &ot_ctx))
DBUG_RETURN(true); DBUG_RETURN(true);
/* /*

View File

@ -286,8 +286,8 @@ public:
Handle_old_incorrect_sql_modes_hook(char *file_path) Handle_old_incorrect_sql_modes_hook(char *file_path)
:path(file_path) :path(file_path)
{}; {};
virtual bool process_unknown_string(char *&unknown_key, uchar* base, virtual bool process_unknown_string(const char *&unknown_key, uchar* base,
MEM_ROOT *mem_root, char *end); MEM_ROOT *mem_root, const char *end);
}; };
@ -298,8 +298,8 @@ public:
LEX_STRING *trigger_table_arg) LEX_STRING *trigger_table_arg)
:path(file_path), trigger_table_value(trigger_table_arg) :path(file_path), trigger_table_value(trigger_table_arg)
{}; {};
virtual bool process_unknown_string(char *&unknown_key, uchar* base, virtual bool process_unknown_string(const char *&unknown_key, uchar* base,
MEM_ROOT *mem_root, char *end); MEM_ROOT *mem_root, const char *end);
private: private:
char *path; char *path;
LEX_STRING *trigger_table_value; LEX_STRING *trigger_table_value;
@ -2316,10 +2316,9 @@ void Table_triggers_list::set_parse_error_message(char *error_message)
#define INVALID_SQL_MODES_LENGTH 13 #define INVALID_SQL_MODES_LENGTH 13
bool bool
Handle_old_incorrect_sql_modes_hook::process_unknown_string(char *&unknown_key, Handle_old_incorrect_sql_modes_hook::
uchar* base, process_unknown_string(const char *&unknown_key, uchar* base,
MEM_ROOT *mem_root, MEM_ROOT *mem_root, const char *end)
char *end)
{ {
DBUG_ENTER("Handle_old_incorrect_sql_modes_hook::process_unknown_string"); DBUG_ENTER("Handle_old_incorrect_sql_modes_hook::process_unknown_string");
DBUG_PRINT("info", ("unknown key: %60s", unknown_key)); DBUG_PRINT("info", ("unknown key: %60s", unknown_key));
@ -2328,7 +2327,7 @@ Handle_old_incorrect_sql_modes_hook::process_unknown_string(char *&unknown_key,
unknown_key[INVALID_SQL_MODES_LENGTH] == '=' && unknown_key[INVALID_SQL_MODES_LENGTH] == '=' &&
!memcmp(unknown_key, STRING_WITH_LEN("sql_modes"))) !memcmp(unknown_key, STRING_WITH_LEN("sql_modes")))
{ {
char *ptr= unknown_key + INVALID_SQL_MODES_LENGTH + 1; const char *ptr= unknown_key + INVALID_SQL_MODES_LENGTH + 1;
DBUG_PRINT("info", ("sql_modes affected by BUG#14090 detected")); DBUG_PRINT("info", ("sql_modes affected by BUG#14090 detected"));
push_warning_printf(current_thd, push_warning_printf(current_thd,
@ -2359,8 +2358,8 @@ Handle_old_incorrect_sql_modes_hook::process_unknown_string(char *&unknown_key,
*/ */
bool bool
Handle_old_incorrect_trigger_table_hook:: Handle_old_incorrect_trigger_table_hook::
process_unknown_string(char *&unknown_key, uchar* base, MEM_ROOT *mem_root, process_unknown_string(const char *&unknown_key, uchar* base,
char *end) MEM_ROOT *mem_root, const char *end)
{ {
DBUG_ENTER("Handle_old_incorrect_trigger_table_hook::process_unknown_string"); DBUG_ENTER("Handle_old_incorrect_trigger_table_hook::process_unknown_string");
DBUG_PRINT("info", ("unknown key: %60s", unknown_key)); DBUG_PRINT("info", ("unknown key: %60s", unknown_key));
@ -2369,7 +2368,7 @@ process_unknown_string(char *&unknown_key, uchar* base, MEM_ROOT *mem_root,
unknown_key[INVALID_TRIGGER_TABLE_LENGTH] == '=' && unknown_key[INVALID_TRIGGER_TABLE_LENGTH] == '=' &&
!memcmp(unknown_key, STRING_WITH_LEN("trigger_table"))) !memcmp(unknown_key, STRING_WITH_LEN("trigger_table")))
{ {
char *ptr= unknown_key + INVALID_TRIGGER_TABLE_LENGTH + 1; const char *ptr= unknown_key + INVALID_TRIGGER_TABLE_LENGTH + 1;
DBUG_PRINT("info", ("trigger_table affected by BUG#15921 detected")); DBUG_PRINT("info", ("trigger_table affected by BUG#15921 detected"));
push_warning_printf(current_thd, push_warning_printf(current_thd,

View File

@ -215,8 +215,7 @@ fill_defined_view_parts (THD *thd, TABLE_LIST *view)
TABLE_LIST decoy; TABLE_LIST decoy;
memcpy (&decoy, view, sizeof (TABLE_LIST)); memcpy (&decoy, view, sizeof (TABLE_LIST));
if (tdc_open_view(thd, &decoy, decoy.alias, thd->mem_root, if (tdc_open_view(thd, &decoy, decoy.alias, OPEN_VIEW_NO_PARSE))
OPEN_VIEW_NO_PARSE))
return TRUE; return TRUE;
if (!lex->definer) if (!lex->definer)
@ -1038,22 +1037,19 @@ err:
/* /**
read VIEW .frm and create structures read VIEW .frm and create structures
SYNOPSIS @param[in] thd Thread handler
mysql_make_view() @param[in] share Share object of view
thd Thread handler @param[in] table TABLE_LIST structure for filling
parser parser object @param[in] open_view_no_parse Flag to indicate open view but
table TABLE_LIST structure for filling do not parse.
flags flags
RETURN
0 ok
1 error
*/
bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, @return false-in case of success, true-in case of error.
uint flags) */
bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
bool open_view_no_parse)
{ {
SELECT_LEX *end, *UNINIT_VAR(view_select); SELECT_LEX *end, *UNINIT_VAR(view_select);
LEX *old_lex, *lex; LEX *old_lex, *lex;
@ -1065,6 +1061,13 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
DBUG_ENTER("mysql_make_view"); DBUG_ENTER("mysql_make_view");
DBUG_PRINT("info", ("table: 0x%lx (%s)", (ulong) table, table->table_name)); DBUG_PRINT("info", ("table: 0x%lx (%s)", (ulong) table, table->table_name));
if (table->required_type == FRMTYPE_TABLE)
{
my_error(ER_WRONG_OBJECT, MYF(0), share->db.str, share->table_name.str,
"BASE TABLE");
DBUG_RETURN(true);
}
if (table->view) if (table->view)
{ {
/* /*
@ -1137,12 +1140,14 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
table->definer.user.length= table->definer.host.length= 0; table->definer.user.length= table->definer.host.length= 0;
/* /*
TODO: when VIEWs will be stored in cache, table mem_root should TODO: when VIEWs will be stored in cache (not only parser),
be used here table mem_root should be used here
*/ */
if ((result= parser->parse((uchar*)table, thd->mem_root, DBUG_ASSERT(share->view_def != NULL);
view_parameters, required_view_parameters, if ((result= share->view_def->parse((uchar*)table, thd->mem_root,
&file_parser_dummy_hook))) view_parameters,
required_view_parameters,
&file_parser_dummy_hook)))
goto end; goto end;
/* /*
@ -1174,7 +1179,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
*/ */
table->view_creation_ctx= View_creation_ctx::create(thd, table); table->view_creation_ctx= View_creation_ctx::create(thd, table);
if (flags & OPEN_VIEW_NO_PARSE) if (open_view_no_parse)
{ {
if (arena) if (arena)
thd->restore_active_arena(arena, &backup); thd->restore_active_arena(arena, &backup);
@ -1613,6 +1618,7 @@ end:
if (arena) if (arena)
thd->restore_active_arena(arena, &backup); thd->restore_active_arena(arena, &backup);
thd->lex= old_lex; thd->lex= old_lex;
status_var_increment(thd->status_var.opened_views);
DBUG_RETURN(result); DBUG_RETURN(result);
err: err:

View File

@ -34,8 +34,8 @@ bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view,
bool mysql_create_view(THD *thd, TABLE_LIST *view, bool mysql_create_view(THD *thd, TABLE_LIST *view,
enum_view_create_mode mode); enum_view_create_mode mode);
bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
uint flags); bool open_view_no_parse);
bool mysql_drop_view(THD *thd, TABLE_LIST *view, enum_drop_mode drop_mode); bool mysql_drop_view(THD *thd, TABLE_LIST *view, enum_drop_mode drop_mode);

View File

@ -40,6 +40,7 @@
#include "sql_statistics.h" #include "sql_statistics.h"
#include "discover.h" #include "discover.h"
#include "mdl.h" // MDL_wait_for_graph_visitor #include "mdl.h" // MDL_wait_for_graph_visitor
#include "sql_view.h"
/* INFORMATION_SCHEMA name */ /* INFORMATION_SCHEMA name */
LEX_STRING INFORMATION_SCHEMA_NAME= {C_STRING_WITH_LEN("information_schema")}; LEX_STRING INFORMATION_SCHEMA_NAME= {C_STRING_WITH_LEN("information_schema")};
@ -558,13 +559,15 @@ enum open_frm_error open_table_def(THD *thd, TABLE_SHARE *share, uint flags)
uchar head[FRM_HEADER_SIZE]; uchar head[FRM_HEADER_SIZE];
char path[FN_REFLEN]; char path[FN_REFLEN];
size_t frmlen, read_length; size_t frmlen, read_length;
uint length;
DBUG_ENTER("open_table_def"); DBUG_ENTER("open_table_def");
DBUG_PRINT("enter", ("table: '%s'.'%s' path: '%s'", share->db.str, DBUG_PRINT("enter", ("table: '%s'.'%s' path: '%s'", share->db.str,
share->table_name.str, share->normalized_path.str)); share->table_name.str, share->normalized_path.str));
share->error= OPEN_FRM_OPEN_ERROR; share->error= OPEN_FRM_OPEN_ERROR;
strxmov(path, share->normalized_path.str, reg_ext, NullS); length=(uint) (strxmov(path, share->normalized_path.str, reg_ext, NullS) -
path);
if (flags & GTS_FORCE_DISCOVERY) if (flags & GTS_FORCE_DISCOVERY)
{ {
DBUG_ASSERT(flags & GTS_TABLE); DBUG_ASSERT(flags & GTS_TABLE);
@ -595,7 +598,21 @@ enum open_frm_error open_table_def(THD *thd, TABLE_SHARE *share, uint flags)
if (memcmp(head, STRING_WITH_LEN("TYPE=VIEW\n")) == 0) if (memcmp(head, STRING_WITH_LEN("TYPE=VIEW\n")) == 0)
{ {
share->is_view= 1; share->is_view= 1;
share->error= flags & GTS_VIEW ? OPEN_FRM_OK : OPEN_FRM_NOT_A_TABLE; if (flags & GTS_VIEW)
{
LEX_STRING pathstr= { path, length };
/*
Create view file parser and hold it in TABLE_SHARE member
view_def.
*/
share->view_def= sql_parse_prepare(&pathstr, &share->mem_root, true);
if (!share->view_def)
share->error= OPEN_FRM_ERROR_ALREADY_ISSUED;
else
share->error= OPEN_FRM_OK;
}
else
share->error= OPEN_FRM_NOT_A_TABLE;
goto err; goto err;
} }
if (!is_binary_frm_header(head)) if (!is_binary_frm_header(head))

View File

@ -30,6 +30,7 @@
#include "mysql_com.h" /* enum_field_types */ #include "mysql_com.h" /* enum_field_types */
#include "thr_lock.h" /* thr_lock_type */ #include "thr_lock.h" /* thr_lock_type */
#include "filesort_utils.h" #include "filesort_utils.h"
#include "parse_file.h"
/* Structs that defines the TABLE */ /* Structs that defines the TABLE */
@ -730,6 +731,13 @@ struct TABLE_SHARE
*/ */
ulong incompatible_version; ulong incompatible_version;
/**
For shares representing views File_parser object with view
definition read from .FRM file.
*/
const File_parser *view_def;
/* /*
Cache for row-based replication table share checks that does not Cache for row-based replication table share checks that does not
need to be repeated. Possible values are: -1 when cache value is need to be repeated. Possible values are: -1 when cache value is