summaryrefslogtreecommitdiff
path: root/sql/sql_show.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_show.cc')
-rw-r--r--sql/sql_show.cc692
1 files changed, 459 insertions, 233 deletions
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index ea17cd73e1c..2d06f383612 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1,4 +1,4 @@
-/* Copyright 2000, 2010 Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -30,6 +30,8 @@
#include "repl_failsafe.h"
#include "sql_parse.h" // check_access, check_table_access
#include "sql_partition.h" // partition_element
+#include "sql_derived.h" // mysql_derived_prepare,
+ // mysql_handle_derived,
#include "sql_db.h" // check_db_dir_existence, load_db_opt_by_name
#include "sql_time.h" // interval_type_to_name
#include "tztime.h" // struct Time_zone
@@ -104,11 +106,13 @@ static const char *ha_choice_values[] = {"", "0", "1"};
static void store_key_options(THD *thd, String *packet, TABLE *table,
KEY *key_info);
+#ifdef WITH_PARTITION_STORAGE_ENGINE
static void get_cs_converted_string_value(THD *thd,
String *input_str,
String *output_str,
CHARSET_INFO *cs,
bool use_hex);
+#endif
static void
append_algorithm(TABLE_LIST *table, String *buff);
@@ -224,27 +228,27 @@ static my_bool show_plugins(THD *thd, plugin_ref plugin,
strlen(PLUGIN_LICENSE_PROPRIETARY_STRING), cs);
break;
}
- table->field[9]->set_notnull();
- if ((uint) plug->maturity <= MariaDB_PLUGIN_MATURITY_STABLE)
- table->field[10]->store(maturity_name[plug->maturity].str,
+ table->field[10]->store(
+ global_plugin_typelib_names[plugin_load_option(plugin)],
+ strlen(global_plugin_typelib_names[plugin_load_option(plugin)]),
+ cs);
+
+ if (plug->maturity <= MariaDB_PLUGIN_MATURITY_STABLE)
+ table->field[11]->store(maturity_name[plug->maturity].str,
maturity_name[plug->maturity].length,
cs);
else
- {
- DBUG_ASSERT(0);
- table->field[10]->store("Unknown", 7, cs);
- }
- table->field[10]->set_notnull();
+ table->field[11]->store("Unknown", 7, cs);
if (plug->version_info)
{
- table->field[11]->store(plug->version_info,
+ table->field[12]->store(plug->version_info,
strlen(plug->version_info), cs);
- table->field[11]->set_notnull();
+ table->field[12]->set_notnull();
}
else
- table->field[11]->set_null();
+ table->field[12]->set_null();
return schema_table_store_record(thd, table);
}
@@ -362,6 +366,7 @@ static struct show_privileges_st sys_privileges[]=
{"Insert", "Tables", "To insert data into tables"},
{"Lock tables","Databases","To use LOCK TABLES (together with SELECT privilege)"},
{"Process", "Server Admin", "To view the plain text of currently executing queries"},
+ {"Proxy", "Server Admin", "To make proxy user possible"},
{"References", "Databases,Tables", "To have references on tables"},
{"Reload", "Server Admin", "To reload or refresh tables, logs and privileges"},
{"Replication client","Server Admin","To ask where the slave or master servers are"},
@@ -506,12 +511,6 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db,
else if (wild_compare(uname, wild, 0))
continue;
}
- if (!(file_name=
- thd->make_lex_string(file_name, uname, file_name_len, TRUE)))
- {
- my_dirend(dirp);
- DBUG_RETURN(FIND_FILES_OOM);
- }
}
else
{
@@ -628,11 +627,11 @@ public:
return m_view_access_denied_message_ptr;
}
- bool handle_condition(THD *thd, uint sql_errno, const char */* sqlstate */,
+ bool handle_condition(THD *thd, uint sql_errno, const char * /* sqlstate */,
MYSQL_ERROR::enum_warning_level level,
- const char *message, MYSQL_ERROR **/* cond_hdl */)
+ const char *message, MYSQL_ERROR ** /* cond_hdl */)
{
- /*
+ /*
The handler does not handle the errors raised by itself.
At this point we know if top_view is really a view.
*/
@@ -642,7 +641,7 @@ public:
m_handling= TRUE;
bool is_handled;
-
+
switch (sql_errno)
{
case ER_TABLEACCESS_DENIED_ERROR:
@@ -703,17 +702,24 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
Metadata locks taken during SHOW CREATE should be released when
the statmement completes as it is an information statement.
*/
- MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint();
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
/* We want to preserve the tree for views. */
- thd->lex->view_prepare_mode= TRUE;
+ thd->lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW;
{
+ /*
+ Use open_tables() directly rather than open_normal_and_derived_tables().
+ This ensures that close_thread_tables() is not called if open tables fails
+ and the error is ignored. This allows us to handle broken views nicely.
+ */
+ uint counter;
Show_create_error_handler view_error_suppressor(thd, table_list);
thd->push_internal_handler(&view_error_suppressor);
bool open_error=
- open_normal_and_derived_tables(thd, table_list,
- MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL);
+ open_tables(thd, &table_list, &counter,
+ MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL) ||
+ mysql_handle_derived(thd->lex, &mysql_derived_prepare);
thd->pop_internal_handler();
if (open_error && (thd->killed || thd->is_error()))
goto exit;
@@ -1444,18 +1450,6 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
if (!(thd->variables.sql_mode & MODE_NO_TABLE_OPTIONS) && !foreign_db_mode)
{
show_table_options= TRUE;
- /*
- Get possible table space definitions and append them
- to the CREATE TABLE statement
- */
-
- if ((for_str= file->get_tablespace_name(thd,0,0)))
- {
- packet->append(STRING_WITH_LEN(" /*!50100 TABLESPACE "));
- packet->append(for_str, strlen(for_str));
- packet->append(STRING_WITH_LEN(" STORAGE DISK */"));
- my_free(for_str);
- }
/*
IF check_create_info
@@ -1813,7 +1807,7 @@ public:
time_t start_time;
uint command;
const char *user,*host,*db,*proc_info,*state_info;
- char *query;
+ CSET_STRING query_string;
};
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
@@ -1910,12 +1904,14 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
if (mysys_var)
mysql_mutex_unlock(&mysys_var->mutex);
- thd_info->query=0;
/* Lock THD mutex that protects its data when looking at it. */
if (tmp->query())
{
uint length= min(max_query_length, tmp->query_length());
- thd_info->query= (char*) thd->strmake(tmp->query(),length);
+ char *q= thd->strmake(tmp->query(),length);
+ /* Safety: in case strmake failed, we set length to 0. */
+ thd_info->query_string=
+ CSET_STRING(q, q ? length : 0, tmp->query_charset());
}
mysql_mutex_unlock(&tmp->LOCK_thd_data);
thd_info->start_time= tmp->start_time;
@@ -1943,7 +1939,8 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
else
protocol->store_null();
protocol->store(thd_info->state_info, system_charset_info);
- protocol->store(thd_info->query, system_charset_info);
+ protocol->store(thd_info->query_string.str(),
+ thd_info->query_string.charset());
if (protocol->write())
break; /* purecov: inspected */
}
@@ -2780,12 +2777,11 @@ bool schema_table_store_record(THD *thd, TABLE *table)
}
-int make_table_list(THD *thd, SELECT_LEX *sel,
- LEX_STRING *db_name, LEX_STRING *table_name)
+static int make_table_list(THD *thd, SELECT_LEX *sel,
+ LEX_STRING *db_name, LEX_STRING *table_name)
{
Table_ident *table_ident;
table_ident= new Table_ident(thd, *db_name, *table_name, 1);
- sel->init_query();
if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, MDL_SHARED_READ))
return 1;
return 0;
@@ -3355,91 +3351,190 @@ make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex,
/**
- @brief Fill I_S table for SHOW COLUMNS|INDEX commands
+ Fill I_S table with data obtained by performing full-blown table open.
+
+ @param thd Thread handler.
+ @param is_show_fields_or_keys Indicates whether it is a legacy SHOW
+ COLUMNS or SHOW KEYS statement.
+ @param table TABLE object for I_S table to be filled.
+ @param schema_table I_S table description structure.
+ @param orig_db_name Database name.
+ @param orig_table_name Table name.
+ @param open_tables_state_backup Open_tables_state object which is used
+ to save/restore original status of
+ variables related to open tables state.
+ @param can_deadlock Indicates that deadlocks are possible
+ due to metadata locks, so to avoid
+ them we should not wait in case if
+ conflicting lock is present.
+
+ @retval FALSE - Success.
+ @retval TRUE - Failure.
+*/
+static bool
+fill_schema_table_by_open(THD *thd, bool is_show_fields_or_keys,
+ TABLE *table, ST_SCHEMA_TABLE *schema_table,
+ LEX_STRING *orig_db_name,
+ LEX_STRING *orig_table_name,
+ Open_tables_backup *open_tables_state_backup,
+ bool can_deadlock)
+{
+ Query_arena i_s_arena(thd->mem_root,
+ Query_arena::STMT_CONVENTIONAL_EXECUTION),
+ backup_arena, *old_arena;
+ LEX *old_lex= thd->lex, temp_lex, *lex;
+ LEX_STRING db_name, table_name;
+ TABLE_LIST *table_list;
+ bool result= true;
+
+ DBUG_ENTER("fill_schema_table_by_open");
+ /*
+ When a view is opened its structures are allocated on a permanent
+ statement arena and linked into the LEX tree for the current statement
+ (this happens even in cases when view is handled through TEMPTABLE
+ algorithm).
- @param[in] thd thread handler
- @param[in] tables TABLE_LIST for I_S table
- @param[in] schema_table pointer to I_S structure
- @param[in] can_deadlock Indicates that deadlocks are possible
- due to metadata locks, so to avoid
- them we should not wait in case if
- conflicting lock is present.
- @param[in] open_tables_state_backup pointer to Open_tables_backup object
- which is used to save|restore original
- status of variables related to
- open tables state
+ To prevent this process from unnecessary hogging of memory in the permanent
+ arena of our I_S query and to avoid damaging its LEX we use temporary
+ arena and LEX for table/view opening.
- @return Operation status
- @retval 0 success
- @retval 1 error
-*/
+ Use temporary arena instead of statement permanent arena. Also make
+ it active arena and save original one for successive restoring.
+ */
+ old_arena= thd->stmt_arena;
+ thd->stmt_arena= &i_s_arena;
+ thd->set_n_backup_active_arena(&i_s_arena, &backup_arena);
-static int
-fill_schema_show_cols_or_idxs(THD *thd, TABLE_LIST *tables,
- ST_SCHEMA_TABLE *schema_table,
- bool can_deadlock,
- Open_tables_backup *open_tables_state_backup)
-{
- LEX *lex= thd->lex;
- bool res;
- LEX_STRING tmp_lex_string, tmp_lex_string1, *db_name, *table_name;
- enum_sql_command save_sql_command= lex->sql_command;
- TABLE_LIST *show_table_list= tables->schema_select_lex->table_list.first;
- TABLE *table= tables->table;
- int error= 1;
- DBUG_ENTER("fill_schema_show");
+ /* Prepare temporary LEX. */
+ thd->lex= lex= &temp_lex;
+ lex_start(thd);
+
+ /* Disable constant subquery evaluation as we won't be locking tables. */
+ lex->context_analysis_only= CONTEXT_ANALYSIS_ONLY_VIEW;
+
+ /*
+ Some of process_table() functions rely on wildcard being passed from
+ old LEX (or at least being initialized).
+ */
+ lex->wild= old_lex->wild;
- lex->all_selects_list= tables->schema_select_lex;
/*
- Restore thd->temporary_tables to be able to process
- temporary tables(only for 'show index' & 'show columns').
- This should be changed when processing of temporary tables for
- I_S tables will be done.
+ Since make_table_list() might change database and table name passed
+ to it we create copies of orig_db_name and orig_table_name here.
+ These copies are used for make_table_list() while unaltered values
+ are passed to process_table() functions.
*/
- thd->temporary_tables= open_tables_state_backup->temporary_tables;
+ if (!thd->make_lex_string(&db_name, orig_db_name->str,
+ orig_db_name->length, FALSE) ||
+ !thd->make_lex_string(&table_name, orig_table_name->str,
+ orig_table_name->length, FALSE))
+ goto end;
+
+ /*
+ Create table list element for table to be open. Link it with the
+ temporary LEX. The latter is required to correctly open views and
+ produce table describing their structure.
+ */
+ if (make_table_list(thd, &lex->select_lex, &db_name, &table_name))
+ goto end;
+
+ table_list= lex->select_lex.table_list.first;
+
+ if (is_show_fields_or_keys)
+ {
+ /*
+ Restore thd->temporary_tables to be able to process
+ temporary tables (only for 'show index' & 'show columns').
+ This should be changed when processing of temporary tables for
+ I_S tables will be done.
+ */
+ thd->temporary_tables= open_tables_state_backup->temporary_tables;
+ }
+ else
+ {
+ /*
+ Apply optimization flags for table opening which are relevant for
+ this I_S table. We can't do this for SHOW COLUMNS/KEYS because of
+ backward compatibility.
+ */
+ table_list->i_s_requested_object= schema_table->i_s_requested_object;
+ }
+
/*
Let us set fake sql_command so views won't try to merge
themselves into main statement. If we don't do this,
SELECT * from information_schema.xxxx will cause problems.
- SQLCOM_SHOW_FIELDS is used because it satisfies 'only_view_structure()'
+ SQLCOM_SHOW_FIELDS is used because it satisfies
+ 'only_view_structure()'.
*/
lex->sql_command= SQLCOM_SHOW_FIELDS;
- res= open_normal_and_derived_tables(thd, show_table_list,
- (MYSQL_OPEN_IGNORE_FLUSH |
- MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
- (can_deadlock ?
- MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)));
- lex->sql_command= save_sql_command;
+ result= open_normal_and_derived_tables(thd, table_list,
+ (MYSQL_OPEN_IGNORE_FLUSH |
+ MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
+ (can_deadlock ?
+ MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)));
+ /*
+ Restore old value of sql_command back as it is being looked at in
+ process_table() function.
+ */
+ lex->sql_command= old_lex->sql_command;
DEBUG_SYNC(thd, "after_open_table_ignore_flush");
/*
- get_all_tables() returns 1 on failure and 0 on success thus
- return only these and not the result code of ::process_table()
-
- We should use show_table_list->alias instead of
- show_table_list->table_name because table_name
- could be changed during opening of I_S tables. It's safe
- to use alias because alias contains original table name
- in this case(this part of code is used only for
- 'show columns' & 'show statistics' commands).
+ XXX: show_table_list has a flag i_is_requested,
+ and when it's set, open_normal_and_derived_tables()
+ can return an error without setting an error message
+ in THD, which is a hack. This is why we have to
+ check for res, then for thd->is_error() and only then
+ for thd->main_da.sql_errno().
+
+ Again we don't do this for SHOW COLUMNS/KEYS because
+ of backward compatibility.
*/
- table_name= thd->make_lex_string(&tmp_lex_string1, show_table_list->alias,
- strlen(show_table_list->alias), FALSE);
- if (!show_table_list->view)
- db_name= thd->make_lex_string(&tmp_lex_string, show_table_list->db,
- show_table_list->db_length, FALSE);
- else
- db_name= &show_table_list->view_db;
+ if (!is_show_fields_or_keys && result && thd->is_error() &&
+ thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE)
+ {
+ /*
+ Hide error for a non-existing table.
+ For example, this error can occur when we use a where condition
+ with a db name and table, but the table does not exist.
+ */
+ result= false;
+ thd->clear_error();
+ }
+ else
+ {
+ result= schema_table->process_table(thd, table_list,
+ table, result,
+ orig_db_name,
+ orig_table_name);
+ }
+
+
+end:
+ lex->unit.cleanup();
+
+ /* Restore original LEX value, statement's arena and THD arena values. */
+ lex_end(thd->lex);
+
+ if (i_s_arena.free_list)
+ i_s_arena.free_items();
+
+ /*
+ For safety reset list of open temporary tables before closing
+ all tables open within this Open_tables_state.
+ */
+ thd->temporary_tables= NULL;
+ close_thread_tables(thd);
+ thd->mdl_context.rollback_to_savepoint(open_tables_state_backup->mdl_system_tables_svp);
+
+ thd->lex= old_lex;
+ thd->stmt_arena= old_arena;
+ thd->restore_active_arena(&i_s_arena, &backup_arena);
- error= test(schema_table->process_table(thd, show_table_list,
- table, res, db_name,
- table_name));
- thd->temporary_tables= 0;
- close_tables_for_reopen(thd, &show_table_list,
- open_tables_state_backup->mdl_system_tables_svp);
- DBUG_RETURN(error);
+ DBUG_RETURN(result);
}
@@ -3579,7 +3674,7 @@ try_acquire_high_prio_shared_mdl_lock(THD *thd, TABLE_LIST *table,
{
bool error;
table->mdl_request.init(MDL_key::TABLE, table->db, table->table_name,
- MDL_SHARED_HIGH_PRIO);
+ MDL_SHARED_HIGH_PRIO, MDL_TRANSACTION);
if (can_deadlock)
{
@@ -3789,6 +3884,45 @@ end:
/**
+ Trigger_error_handler is intended to intercept and silence SQL conditions
+ that might happen during trigger loading for SHOW statements.
+ The potential SQL conditions are:
+
+ - ER_PARSE_ERROR -- this error is thrown if a trigger definition file
+ is damaged or contains invalid CREATE TRIGGER statement. That should
+ not happen in normal life.
+
+ - ER_TRG_NO_DEFINER -- this warning is thrown when we're loading a
+ trigger created/imported in/from the version of MySQL, which does not
+ support trigger definers.
+
+ - ER_TRG_NO_CREATION_CTX -- this warning is thrown when we're loading a
+ trigger created/imported in/from the version of MySQL, which does not
+ support trigger creation contexts.
+*/
+
+class Trigger_error_handler : public Internal_error_handler
+{
+public:
+ bool handle_condition(THD *thd,
+ uint sql_errno,
+ const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg,
+ MYSQL_ERROR ** cond_hdl)
+ {
+ if (sql_errno == ER_PARSE_ERROR ||
+ sql_errno == ER_TRG_NO_DEFINER ||
+ sql_errno == ER_TRG_NO_CREATION_CTX)
+ return true;
+
+ return false;
+ }
+};
+
+
+
+/**
@brief Fill I_S tables whose data are retrieved
from frm files and storage engine
@@ -3811,10 +3945,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
{
LEX *lex= thd->lex;
TABLE *table= tables->table;
- SELECT_LEX *old_all_select_lex= lex->all_selects_list;
SELECT_LEX *lsel= tables->schema_select_lex;
ST_SCHEMA_TABLE *schema_table= tables->schema_table;
- SELECT_LEX sel;
LOOKUP_FIELD_VALUES lookup_field_vals;
LEX_STRING *db_name, *table_name;
bool with_i_schema;
@@ -3822,11 +3954,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
List<LEX_STRING> db_names;
List_iterator_fast<LEX_STRING> it(db_names);
COND *partial_cond= 0;
- uint derived_tables= lex->derived_tables;
int error= 1;
Open_tables_backup open_tables_state_backup;
- bool save_view_prepare_mode= lex->view_prepare_mode;
- Query_tables_list query_tables_list_backup;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
Security_context *sctx= thd->security_ctx;
#endif
@@ -3845,15 +3974,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
*/
can_deadlock= thd->mdl_context.has_locks();
- lex->view_prepare_mode= TRUE;
- lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
- /*
- Restore Query_tables_list::sql_command value, which was reset
- above, as ST_SCHEMA_TABLE::process_table() functions often rely
- that this value reflects which SHOW statement is executed.
- */
- lex->sql_command= query_tables_list_backup.sql_command;
-
/*
We should not introduce deadlocks even if we already have some
tables open and locked, since we won't lock tables which we will
@@ -3873,9 +3993,19 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
*/
if (lsel && lsel->table_list.first)
{
- error= fill_schema_show_cols_or_idxs(thd, tables, schema_table,
- can_deadlock,
- &open_tables_state_backup);
+ LEX_STRING db_name, table_name;
+
+ db_name.str= lsel->table_list.first->db;
+ db_name.length= lsel->table_list.first->db_length;
+
+ table_name.str= lsel->table_list.first->table_name;
+ table_name.length= lsel->table_list.first->table_name_length;
+
+ error= fill_schema_table_by_open(thd, TRUE,
+ table, schema_table,
+ &db_name, &table_name,
+ &open_tables_state_backup,
+ can_deadlock);
goto err;
}
@@ -3937,7 +4067,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0))
#endif
{
- thd->no_warnings_for_error= 1;
List<LEX_STRING> table_names;
int res= make_table_name_list(thd, &table_names, lex,
&lookup_field_vals,
@@ -3986,77 +4115,34 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
if (!(table_open_method & ~OPEN_FRM_ONLY) &&
!with_i_schema)
{
- if (!fill_schema_table_from_frm(thd, tables, schema_table, db_name,
- table_name, schema_table_idx,
- can_deadlock))
+ /*
+ Here we need to filter out warnings, which can happen
+ during loading of triggers in fill_schema_table_from_frm(),
+ because we don't need those warnings to pollute output of
+ SELECT from I_S / SHOW-statements.
+ */
+
+ Trigger_error_handler err_handler;
+ thd->push_internal_handler(&err_handler);
+
+ int res= fill_schema_table_from_frm(thd, tables, schema_table,
+ db_name, table_name,
+ schema_table_idx,
+ can_deadlock);
+
+ thd->pop_internal_handler();
+
+ if (!res)
continue;
}
- int res;
- LEX_STRING tmp_lex_string, orig_db_name;
- /*
- Set the parent lex of 'sel' because it is needed by
- sel.init_query() which is called inside make_table_list.
- */
- thd->no_warnings_for_error= 1;
- sel.parent_lex= lex;
- /* db_name can be changed in make_table_list() func */
- if (!thd->make_lex_string(&orig_db_name, db_name->str,
- db_name->length, FALSE))
- goto err;
- if (make_table_list(thd, &sel, db_name, table_name))
- goto err;
- TABLE_LIST *show_table_list= sel.table_list.first;
- lex->all_selects_list= &sel;
- lex->derived_tables= 0;
- lex->sql_command= SQLCOM_SHOW_FIELDS;
- show_table_list->i_s_requested_object=
- schema_table->i_s_requested_object;
DEBUG_SYNC(thd, "before_open_in_get_all_tables");
- res= open_normal_and_derived_tables(thd, show_table_list,
- (MYSQL_OPEN_IGNORE_FLUSH |
- MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
- (can_deadlock ? MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)));
- lex->sql_command= query_tables_list_backup.sql_command;
- /*
- XXX: show_table_list has a flag i_is_requested,
- and when it's set, open_normal_and_derived_tables()
- can return an error without setting an error message
- in THD, which is a hack. This is why we have to
- check for res, then for thd->is_error() only then
- for thd->stmt_da->sql_errno().
- */
- if (res && thd->is_error() &&
- thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE)
- {
- /*
- Hide error for not existing table.
- This error can occur for example when we use
- where condition with db name and table name and this
- table does not exist.
- */
- res= 0;
- thd->clear_error();
- }
- else
- {
- /*
- We should use show_table_list->alias instead of
- show_table_list->table_name because table_name
- could be changed during opening of I_S tables. It's safe
- to use alias because alias contains original table name
- in this case.
- */
- thd->make_lex_string(&tmp_lex_string, show_table_list->alias,
- strlen(show_table_list->alias), FALSE);
- res= schema_table->process_table(thd, show_table_list, table,
- res, &orig_db_name,
- &tmp_lex_string);
- close_tables_for_reopen(thd, &show_table_list,
- open_tables_state_backup.mdl_system_tables_svp);
- }
- DBUG_ASSERT(!lex->query_tables_own_last);
- if (res)
+
+ if (fill_schema_table_by_open(thd, FALSE,
+ table, schema_table,
+ db_name, table_name,
+ &open_tables_state_backup,
+ can_deadlock))
goto err;
}
}
@@ -4072,10 +4158,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
error= 0;
err:
thd->restore_backup_open_tables_state(&open_tables_state_backup);
- lex->restore_backup_query_tables_list(&query_tables_list_backup);
- lex->derived_tables= derived_tables;
- lex->all_selects_list= old_all_select_lex;
- lex->view_prepare_mode= save_view_prepare_mode;
+
DBUG_RETURN(error);
}
@@ -4171,6 +4254,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
{
const char *tmp_buff;
MYSQL_TIME time;
+ int info_error= 0;
CHARSET_INFO *cs= system_charset_info;
DBUG_ENTER("get_schema_tables_record");
@@ -4178,22 +4262,21 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
table->field[0]->store(STRING_WITH_LEN("def"), cs);
table->field[1]->store(db_name->str, db_name->length, cs);
table->field[2]->store(table_name->str, table_name->length, cs);
+
if (res)
{
- /*
- there was errors during opening tables
- */
- const char *error= thd->is_error() ? thd->stmt_da->message() : "";
+ /* There was a table open error, so set the table type and return */
if (tables->view)
table->field[3]->store(STRING_WITH_LEN("VIEW"), cs);
else if (tables->schema_table)
table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs);
else
table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs);
- table->field[20]->store(error, strlen(error), cs);
- thd->clear_error();
+
+ goto err;
}
- else if (tables->view)
+
+ if (tables->view)
{
table->field[3]->store(STRING_WITH_LEN("VIEW"), cs);
table->field[20]->store(STRING_WITH_LEN("VIEW"), cs);
@@ -4209,6 +4292,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
#ifdef WITH_PARTITION_STORAGE_ENGINE
bool is_partitioned= FALSE;
#endif
+
if (share->tmp_table == SYSTEM_TMP_TABLE)
table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs);
else if (share->tmp_table)
@@ -4222,6 +4306,9 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
continue;
table->field[i]->set_notnull();
}
+
+ /* Collect table info from the table share */
+
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (share->db_type() == partition_hton &&
share->partition_info_str_len)
@@ -4230,73 +4317,96 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
is_partitioned= TRUE;
}
#endif
+
tmp_buff= (char *) ha_resolve_storage_engine_name(tmp_db_type);
table->field[4]->store(tmp_buff, strlen(tmp_buff), cs);
table->field[5]->store((longlong) share->frm_version, TRUE);
str.length(0);
+
if (share->min_rows)
{
str.qs_append(STRING_WITH_LEN(" min_rows="));
str.qs_append(share->min_rows);
}
+
if (share->max_rows)
{
str.qs_append(STRING_WITH_LEN(" max_rows="));
str.qs_append(share->max_rows);
}
+
if (share->avg_row_length)
{
str.qs_append(STRING_WITH_LEN(" avg_row_length="));
str.qs_append(share->avg_row_length);
}
+
if (share->db_create_options & HA_OPTION_PACK_KEYS)
str.qs_append(STRING_WITH_LEN(" pack_keys=1"));
+
if (share->db_create_options & HA_OPTION_NO_PACK_KEYS)
str.qs_append(STRING_WITH_LEN(" pack_keys=0"));
+
/* We use CHECKSUM, instead of TABLE_CHECKSUM, for backward compability */
if (share->db_create_options & HA_OPTION_CHECKSUM)
str.qs_append(STRING_WITH_LEN(" checksum=1"));
+
if (share->page_checksum != HA_CHOICE_UNDEF)
{
str.qs_append(STRING_WITH_LEN(" page_checksum="));
str.qs_append(ha_choice_values[(uint) share->page_checksum]);
}
+
if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
str.qs_append(STRING_WITH_LEN(" delay_key_write=1"));
+
if (share->row_type != ROW_TYPE_DEFAULT)
{
str.qs_append(STRING_WITH_LEN(" row_format="));
str.qs_append(ha_row_type[(uint) share->row_type]);
}
+
if (share->key_block_size)
{
str.qs_append(STRING_WITH_LEN(" key_block_size="));
str.qs_append(share->key_block_size);
}
+
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (is_partitioned)
str.qs_append(STRING_WITH_LEN(" partitioned"));
#endif
+
if (share->transactional != HA_CHOICE_UNDEF)
{
str.qs_append(STRING_WITH_LEN(" transactional="));
str.qs_append(ha_choice_values[(uint) share->transactional]);
}
append_create_options(thd, &str, share->option_list);
+
if (str.length())
table->field[19]->store(str.ptr()+1, str.length()-1, cs);
tmp_buff= (share->table_charset ?
share->table_charset->name : "default");
+
table->field[17]->store(tmp_buff, strlen(tmp_buff), cs);
if (share->comment.str)
table->field[20]->store(share->comment.str, share->comment.length, cs);
+ /* Collect table info from the storage engine */
+
if(file)
{
- file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_AUTO);
+ /* If info() fails, then there's nothing else to do */
+ if ((info_error= file->info(HA_STATUS_VARIABLE |
+ HA_STATUS_TIME |
+ HA_STATUS_VARIABLE_EXTRA |
+ HA_STATUS_AUTO)) != 0)
+ goto err;
+
enum row_type row_type = file->get_row_type();
switch (row_type) {
case ROW_TYPE_NOT_USED:
@@ -4325,7 +4435,9 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
tmp_buff= "Page";
break;
}
+
table->field[6]->store(tmp_buff, strlen(tmp_buff), cs);
+
if (!tables->schema_table)
{
table->field[7]->store((longlong) file->stats.records, TRUE);
@@ -4374,6 +4486,26 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
}
}
}
+
+err:
+ if (res || info_error)
+ {
+ /*
+ If an error was encountered, push a warning, set the TABLE COMMENT
+ column with the error text, and clear the error so that the operation
+ can continue.
+ */
+ const char *error= thd->is_error() ? thd->stmt_da->message() : "";
+ table->field[20]->store(error, strlen(error), cs);
+
+ if (thd->is_error())
+ {
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ thd->stmt_da->sql_errno(), thd->stmt_da->message());
+ thd->clear_error();
+ }
+ }
+
DBUG_RETURN(schema_table_store_record(thd, table));
}
@@ -5337,18 +5469,29 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables,
else
table->field[4]->store(STRING_WITH_LEN("NONE"), cs);
- if (table->pos_in_table_list->table_open_method &
- OPEN_FULL_TABLE)
+ /*
+ Only try to fill in the information about view updatability
+ if it is requested as part of the top-level query (i.e.
+ it's select * from i_s.views, as opposed to, say, select
+ security_type from i_s.views). Do not try to access the
+ underlying tables if there was an error when opening the
+ view: all underlying tables are released back to the table
+ definition cache on error inside open_normal_and_derived_tables().
+ If a field is not assigned explicitly, it defaults to NULL.
+ */
+ if (res == FALSE &&
+ table->pos_in_table_list->table_open_method & OPEN_FULL_TABLE)
{
updatable_view= 0;
if (tables->algorithm != VIEW_ALGORITHM_TMPTABLE)
{
/*
- We should use tables->view->select_lex.item_list here and
- can not use Field_iterator_view because the view always uses
- temporary algorithm during opening for I_S and
- TABLE_LIST fields 'field_translation' & 'field_translation_end'
- are uninitialized is this case.
+ We should use tables->view->select_lex.item_list here
+ and can not use Field_iterator_view because the view
+ always uses temporary algorithm during opening for I_S
+ and TABLE_LIST fields 'field_translation'
+ & 'field_translation_end' are uninitialized is this
+ case.
*/
List<Item> *fields= &tables->view->select_lex.item_list;
List_iterator<Item> it(*fields);
@@ -5471,8 +5614,8 @@ static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables,
while ((f_key_info=it++))
{
if (store_constraints(thd, table, db_name, table_name,
- f_key_info->forein_id->str,
- strlen(f_key_info->forein_id->str),
+ f_key_info->foreign_id->str,
+ strlen(f_key_info->foreign_id->str),
"FOREIGN KEY", 11))
DBUG_RETURN(1);
}
@@ -5671,8 +5814,8 @@ static int get_schema_key_column_usage_record(THD *thd,
f_idx++;
restore_record(table, s->default_values);
store_key_column_usage(table, db_name, table_name,
- f_key_info->forein_id->str,
- f_key_info->forein_id->length,
+ f_key_info->foreign_id->str,
+ f_key_info->foreign_id->length,
f_info->str, f_info->length,
(longlong) f_idx);
table->field[8]->store((longlong) f_idx, TRUE);
@@ -5832,12 +5975,9 @@ static void store_schema_partitions_record(THD *thd, TABLE *schema_table,
strlen(part_elem->tablespace_name), cs);
else
{
- char *ts= showing_table->file->get_tablespace_name(thd,0,0);
+ char *ts= showing_table->s->tablespace;
if(ts)
- {
table->field[24]->store(ts, strlen(ts), cs);
- my_free(ts);
- }
else
table->field[24]->set_null();
}
@@ -6461,8 +6601,8 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables,
table->field[0]->store(STRING_WITH_LEN("def"), cs);
table->field[1]->store(db_name->str, db_name->length, cs);
table->field[9]->store(table_name->str, table_name->length, cs);
- table->field[2]->store(f_key_info->forein_id->str,
- f_key_info->forein_id->length, cs);
+ table->field[2]->store(f_key_info->foreign_id->str,
+ f_key_info->foreign_id->length, cs);
table->field[3]->store(STRING_WITH_LEN("def"), cs);
table->field[4]->store(f_key_info->referenced_db->str,
f_key_info->referenced_db->length, cs);
@@ -7086,6 +7226,92 @@ int make_schema_select(THD *thd, SELECT_LEX *sel,
}
+/**
+ Fill INFORMATION_SCHEMA-table, leave correct Diagnostics_area /
+ Warning_info state after itself.
+
+ This function is a wrapper around ST_SCHEMA_TABLE::fill_table(), which
+ may "partially silence" some errors. The thing is that during
+ fill_table() many errors might be emitted. These errors stem from the
+ nature of fill_table().
+
+ For example, SELECT ... FROM INFORMATION_SCHEMA.xxx WHERE TABLE_NAME = 'xxx'
+ results in a number of 'Table <db name>.xxx does not exist' errors,
+ because fill_table() tries to open the 'xxx' table in every possible
+ database.
+
+ Those errors are cleared (the error status is cleared from
+ Diagnostics_area) inside fill_table(), but they remain in Warning_info
+ (Warning_info is not cleared because it may contain useful warnings).
+
+ This function is responsible for making sure that Warning_info does not
+ contain warnings corresponding to the cleared errors.
+
+ @note: THD::no_warnings_for_error used to be set before calling
+ fill_table(), thus those errors didn't go to Warning_info. This is not
+ the case now (THD::no_warnings_for_error was eliminated as a hack), so we
+ need to take care of those warnings here.
+
+ @param thd Thread context.
+ @param table_list I_S table.
+ @param join_table JOIN/SELECT table.
+
+ @return Error status.
+ @retval TRUE Error.
+ @retval FALSE Success.
+*/
+static bool do_fill_table(THD *thd,
+ TABLE_LIST *table_list,
+ JOIN_TAB *join_table)
+{
+ // NOTE: fill_table() may generate many "useless" warnings, which will be
+ // ignored afterwards. On the other hand, there might be "useful"
+ // warnings, which should be presented to the user. Warning_info usually
+ // stores no more than THD::variables.max_error_count warnings.
+ // The problem is that "useless warnings" may occupy all the slots in the
+ // Warning_info, so "useful warnings" get rejected. In order to avoid
+ // that problem we create a Warning_info instance, which is capable of
+ // storing "unlimited" number of warnings.
+ Warning_info wi(thd->query_id, true);
+ Warning_info *wi_saved= thd->warning_info;
+
+ thd->warning_info= &wi;
+
+ bool res= table_list->schema_table->fill_table(
+ thd, table_list, join_table->select_cond);
+
+ thd->warning_info= wi_saved;
+
+ // Pass an error if any.
+
+ if (thd->stmt_da->is_error())
+ {
+ thd->warning_info->push_warning(thd,
+ thd->stmt_da->sql_errno(),
+ thd->stmt_da->get_sqlstate(),
+ MYSQL_ERROR::WARN_LEVEL_ERROR,
+ thd->stmt_da->message());
+ }
+
+ // Pass warnings (if any).
+ //
+ // Filter out warnings with WARN_LEVEL_ERROR level, because they
+ // correspond to the errors which were filtered out in fill_table().
+
+
+ List_iterator_fast<MYSQL_ERROR> it(wi.warn_list());
+ MYSQL_ERROR *err;
+
+ while ((err= it++))
+ {
+ if (err->get_level() != MYSQL_ERROR::WARN_LEVEL_ERROR)
+ thd->warning_info->push_warning(thd, err);
+ }
+
+ return res;
+}
+
+
/*
Fill temporary schema tables before SELECT
@@ -7108,7 +7334,6 @@ bool get_schema_tables_result(JOIN *join,
bool result= 0;
DBUG_ENTER("get_schema_tables_result");
- thd->no_warnings_for_error= 1;
for (JOIN_TAB *tab= join->join_tab; tab < tmp_join_tab; tab++)
{
if (!tab->table || !tab->table->pos_in_table_list)
@@ -7159,8 +7384,7 @@ bool get_schema_tables_result(JOIN *join,
else
table_list->table->file->stats.records= 0;
- if (table_list->schema_table->fill_table(thd, table_list,
- tab->select_cond))
+ if (do_fill_table(thd, table_list, tab))
{
result= 1;
join->error= 1;
@@ -7172,7 +7396,6 @@ bool get_schema_tables_result(JOIN *join,
table_list->schema_table_state= executed_place;
}
}
- thd->no_warnings_for_error= 0;
DBUG_RETURN(result);
}
@@ -7789,8 +8012,9 @@ ST_FIELD_INFO plugin_fields_info[]=
{"PLUGIN_LIBRARY_VERSION", 20, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
{"PLUGIN_AUTHOR", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
{"PLUGIN_DESCRIPTION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"PLUGIN_LICENSE", 80, MYSQL_TYPE_STRING, 0, 1, "License", SKIP_OPEN_TABLE},
- {"PLUGIN_MATURITY", 12, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
+ {"PLUGIN_LICENSE", 80, MYSQL_TYPE_STRING, 0, 0, "License", SKIP_OPEN_TABLE},
+ {"LOAD_OPTION", 64, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
+ {"PLUGIN_MATURITY", 12, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
{"PLUGIN_AUTH_VERSION", 80, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
};
@@ -8349,7 +8573,7 @@ bool show_create_trigger(THD *thd, const sp_name *trg_name)
Metadata locks taken during SHOW CREATE TRIGGER should be released when
the statement completes as it is an information statement.
*/
- MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint();
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
/*
Open the table by name in order to load Table_triggers_list object.
@@ -8450,6 +8674,7 @@ void initialize_information_schema_acl()
&is_internal_schema_access);
}
+#ifdef WITH_PARTITION_STORAGE_ENGINE
/*
Convert a string in character set in column character set format
to utf8 character set if possible, the utf8 character set string
@@ -8541,3 +8766,4 @@ static void get_cs_converted_string_value(THD *thd,
}
return;
}
+#endif