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.cc1718
1 files changed, 1182 insertions, 536 deletions
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 998432e8443..4b608ee040b 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2009, 2016, MariaDB
+ Copyright (c) 2009, 2017, MariaDB
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
@@ -17,7 +17,7 @@
/* Function with list databases, tables or fields */
-#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_plugin.h" // Includes my_global.h
#include "sql_priv.h"
#include "unireg.h"
#include "sql_acl.h" // fill_schema_*_privileges
@@ -45,6 +45,7 @@
#include "set_var.h"
#include "sql_trigger.h"
#include "sql_derived.h"
+#include "sql_statistics.h"
#include "sql_connect.h"
#include "authors.h"
#include "contributors.h"
@@ -56,11 +57,8 @@
#include <my_dir.h>
#include "lock.h" // MYSQL_OPEN_IGNORE_FLUSH
#include "debug_sync.h"
-#include "datadict.h" // dd_frm_type()
#include "keycaches.h"
-#define STR_OR_NIL(S) ((S) ? (S) : "<nil>")
-
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
#endif
@@ -92,6 +90,8 @@ enum enum_i_s_events_fields
ISE_DB_CL
};
+#define USERNAME_WITH_HOST_CHAR_LENGTH (USERNAME_CHAR_LENGTH + HOSTNAME_LENGTH + 2)
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
static const char *grant_names[]={
"select","insert","update","delete","create","drop","reload","shutdown",
@@ -116,11 +116,49 @@ static void get_cs_converted_string_value(THD *thd,
bool use_hex);
#endif
-static void
-append_algorithm(TABLE_LIST *table, String *buff);
+static int show_create_view(THD *thd, TABLE_LIST *table, String *buff);
+
+static void append_algorithm(TABLE_LIST *table, String *buff);
static COND * make_cond_for_info_schema(COND *cond, TABLE_LIST *table);
+/**
+ Condition pushdown used for INFORMATION_SCHEMA / SHOW queries.
+ This structure is to implement an optimization when
+ accessing data dictionary data in the INFORMATION_SCHEMA
+ or SHOW commands.
+ When the query contain a TABLE_SCHEMA or TABLE_NAME clause,
+ narrow the search for data based on the constraints given.
+*/
+typedef struct st_lookup_field_values
+{
+ /**
+ Value of a TABLE_SCHEMA clause.
+ Note that this value length may exceed @c NAME_LEN.
+ @sa wild_db_value
+ */
+ LEX_STRING db_value;
+ /**
+ Value of a TABLE_NAME clause.
+ Note that this value length may exceed @c NAME_LEN.
+ @sa wild_table_value
+ */
+ LEX_STRING table_value;
+ /**
+ True when @c db_value is a LIKE clause,
+ false when @c db_value is an '=' clause.
+ */
+ bool wild_db_value;
+ /**
+ True when @c table_value is a LIKE clause,
+ false when @c table_value is an '=' clause.
+ */
+ bool wild_table_value;
+} LOOKUP_FIELD_VALUES;
+
+
+bool get_lookup_field_values(THD *, COND *, TABLE_LIST *, LOOKUP_FIELD_VALUES *);
+
/***************************************************************************
** List all table types supported
***************************************************************************/
@@ -159,7 +197,6 @@ static my_bool show_plugins(THD *thd, plugin_ref plugin,
cs);
switch (plugin_state(plugin)) {
- /* case PLUGIN_IS_FREED: does not happen */
case PLUGIN_IS_DELETED:
table->field[2]->store(STRING_WITH_LEN("DELETED"), cs);
break;
@@ -172,6 +209,9 @@ static my_bool show_plugins(THD *thd, plugin_ref plugin,
case PLUGIN_IS_DISABLED:
table->field[2]->store(STRING_WITH_LEN("DISABLED"), cs);
break;
+ case PLUGIN_IS_FREED: // filtered in fill_plugins, used in fill_all_plugins
+ table->field[2]->store(STRING_WITH_LEN("NOT INSTALLED"), cs);
+ break;
default:
DBUG_ASSERT(0);
}
@@ -269,6 +309,65 @@ int fill_plugins(THD *thd, TABLE_LIST *tables, COND *cond)
}
+int fill_all_plugins(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+ DBUG_ENTER("fill_all_plugins");
+ TABLE *table= tables->table;
+ LOOKUP_FIELD_VALUES lookup;
+
+ if (get_lookup_field_values(thd, cond, tables, &lookup))
+ DBUG_RETURN(0);
+
+ if (lookup.db_value.str && !lookup.db_value.str[0])
+ DBUG_RETURN(0); // empty string never matches a valid SONAME
+
+ MY_DIR *dirp= my_dir(opt_plugin_dir, MY_THREAD_SPECIFIC);
+ if (!dirp)
+ {
+ my_error(ER_CANT_READ_DIR, MYF(0), opt_plugin_dir, my_errno);
+ DBUG_RETURN(1);
+ }
+
+ if (!lookup.db_value.str)
+ plugin_dl_foreach(thd, 0, show_plugins, table);
+
+ const char *wstr= lookup.db_value.str, *wend= wstr + lookup.db_value.length;
+ for (uint i=0; i < (uint) dirp->number_of_files; i++)
+ {
+ FILEINFO *file= dirp->dir_entry+i;
+ LEX_STRING dl= { file->name, strlen(file->name) };
+ const char *dlend= dl.str + dl.length;
+ const size_t so_ext_len= sizeof(SO_EXT) - 1;
+
+ if (strcasecmp(dlend - so_ext_len, SO_EXT))
+ continue;
+
+ if (lookup.db_value.str)
+ {
+ if (lookup.wild_db_value)
+ {
+ if (my_wildcmp(files_charset_info, dl.str, dlend, wstr, wend,
+ wild_prefix, wild_one, wild_many))
+ continue;
+ }
+ else
+ {
+ if (my_strnncoll(files_charset_info,
+ (uchar*)dl.str, dl.length,
+ (uchar*)lookup.db_value.str, lookup.db_value.length))
+ continue;
+ }
+ }
+
+ plugin_dl_foreach(thd, &dl, show_plugins, table);
+ thd->clear_error();
+ }
+
+ my_dirend(dirp);
+ DBUG_RETURN(0);
+}
+
+
/***************************************************************************
** List all Authors.
** If you can update it, you get to be in it :)
@@ -282,7 +381,7 @@ bool mysqld_show_authors(THD *thd)
field_list.push_back(new Item_empty_string("Name",40));
field_list.push_back(new Item_empty_string("Location",40));
- field_list.push_back(new Item_empty_string("Comment",80));
+ field_list.push_back(new Item_empty_string("Comment",512));
if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
@@ -316,7 +415,7 @@ bool mysqld_show_contributors(THD *thd)
field_list.push_back(new Item_empty_string("Name",40));
field_list.push_back(new Item_empty_string("Location",40));
- field_list.push_back(new Item_empty_string("Comment",80));
+ field_list.push_back(new Item_empty_string("Comment", 512));
if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
@@ -457,7 +556,7 @@ bool
ignore_db_dirs_init()
{
return my_init_dynamic_array(&ignore_db_dirs_array, sizeof(LEX_STRING *),
- 0, 0);
+ 0, 0, MYF(0));
}
@@ -621,12 +720,24 @@ ignore_db_dirs_process_additions()
for (i= 0; i < ignore_db_dirs_array.elements; i++)
{
get_dynamic(&ignore_db_dirs_array, (uchar *) &dir, i);
- if (my_hash_insert(&ignore_db_dirs_hash, (uchar *) dir))
+ if (my_hash_insert(&ignore_db_dirs_hash, (uchar *)dir))
+ {
+ /* ignore duplicates from the config file */
+ if (my_hash_search(&ignore_db_dirs_hash, (uchar *)dir->str, dir->length))
+ {
+ sql_print_warning("Duplicate ignore-db-dir directory name '%.*s' "
+ "found in the config file(s). Ignoring the duplicate.",
+ (int) dir->length, dir->str);
+ my_free(dir);
+ goto continue_loop;
+ }
+
return true;
+ }
ptr= strnmov(ptr, dir->str, dir->length);
- if (i + 1 < ignore_db_dirs_array.elements)
- ptr= strmov(ptr, ",");
+ *(ptr++)= ',';
+continue_loop:
/*
Set the transferred array element to NULL to avoid double free
in case of error.
@@ -635,6 +746,12 @@ ignore_db_dirs_process_additions()
set_dynamic(&ignore_db_dirs_array, (uchar *) &dir, i);
}
+ if (ptr > opt_ignore_db_dirs)
+ {
+ ptr--;
+ DBUG_ASSERT(*ptr == ',');
+ }
+
/* make sure the string is terminated */
DBUG_ASSERT(ptr - opt_ignore_db_dirs <= (ptrdiff_t) len);
*ptr= 0;
@@ -688,6 +805,11 @@ db_name_is_in_ignore_db_dirs_list(const char *directory)
return my_hash_search(&ignore_db_dirs_hash, (uchar *) buff, buff_len)!=NULL;
}
+enum find_files_result {
+ FIND_FILES_OK,
+ FIND_FILES_OOM,
+ FIND_FILES_DIR
+};
/*
find_files() - find files in a given directory.
@@ -696,11 +818,10 @@ db_name_is_in_ignore_db_dirs_list(const char *directory)
find_files()
thd thread handler
files put found files in this list
- db database name to set in TABLE_LIST structure
+ db database name to search tables in
+ or NULL to search for databases
path path to database
wild filter for found files
- dir read databases in path if TRUE, read .frm files in
- database otherwise
RETURN
FIND_FILES_OK success
@@ -709,64 +830,40 @@ db_name_is_in_ignore_db_dirs_list(const char *directory)
*/
-find_files_result
-find_files(THD *thd, List<LEX_STRING> *files, const char *db,
- const char *path, const char *wild, bool dir)
+static find_files_result
+find_files(THD *thd, Dynamic_array<LEX_STRING*> *files, LEX_STRING *db,
+ const char *path, const LEX_STRING *wild)
{
- uint i;
- char *ext;
MY_DIR *dirp;
- FILEINFO *file;
- LEX_STRING *file_name= 0;
- uint file_name_len;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- uint col_access=thd->col_access;
-#endif
- uint wild_length= 0;
- TABLE_LIST table_list;
+ Discovered_table_list tl(thd, files, wild);
DBUG_ENTER("find_files");
- if (wild)
- {
- if (!wild[0])
- wild= 0;
- else
- wild_length= strlen(wild);
- }
-
- bzero((char*) &table_list,sizeof(table_list));
-
- if (!(dirp = my_dir(path,MYF(dir ? MY_WANT_STAT : 0))))
+ if (!(dirp = my_dir(path, MY_THREAD_SPECIFIC | (db ? 0 : MY_WANT_STAT))))
{
if (my_errno == ENOENT)
- my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), db);
+ my_error(ER_BAD_DB_ERROR, MYF(ME_BELL | ME_WAITTANG), db->str);
else
- my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), path, my_errno);
+ my_error(ER_CANT_READ_DIR, MYF(ME_BELL | ME_WAITTANG), path, my_errno);
DBUG_RETURN(FIND_FILES_DIR);
}
- for (i=0 ; i < (uint) dirp->number_off_files ; i++)
+ if (!db) /* Return databases */
{
- char uname[SAFE_NAME_LEN + 1]; /* Unencoded name */
- file=dirp->dir_entry+i;
- if (dir)
- { /* Return databases */
- if ((file->name[0] == '.' &&
- ((file->name[1] == '.' && file->name[2] == '\0') ||
- file->name[1] == '\0')))
- continue; /* . or .. */
+ for (uint i=0; i < (uint) dirp->number_of_files; i++)
+ {
+ FILEINFO *file= dirp->dir_entry+i;
#ifdef USE_SYMDIR
char *ext;
char buff[FN_REFLEN];
if (my_use_symdir && !strcmp(ext=fn_ext(file->name), ".sym"))
{
- /* Only show the sym file if it points to a directory */
- char *end;
+ /* Only show the sym file if it points to a directory */
+ char *end;
*ext=0; /* Remove extension */
- unpack_dirname(buff, file->name);
- end= strend(buff);
- if (end != buff && end[-1] == FN_LIBCHAR)
- end[-1]= 0; // Remove end FN_LIBCHAR
+ unpack_dirname(buff, file->name);
+ end= strend(buff);
+ if (end != buff && end[-1] == FN_LIBCHAR)
+ end[-1]= 0; // Remove end FN_LIBCHAR
if (!mysql_file_stat(key_file_misc, buff, file->mystat, MYF(0)))
continue;
}
@@ -777,70 +874,25 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db,
if (is_in_ignore_db_dirs_list(file->name))
continue;
- file_name_len= filename_to_tablename(file->name, uname, sizeof(uname));
- if (wild)
- {
- if (lower_case_table_names)
- {
- if (my_wildcmp(files_charset_info,
- uname, uname + file_name_len,
- wild, wild + wild_length,
- wild_prefix, wild_one, wild_many))
- continue;
- }
- else if (wild_compare(uname, wild, 0))
- continue;
- }
- }
- else
- {
- // Return only .frm files which aren't temp files.
- if (my_strcasecmp(system_charset_info, ext=fn_rext(file->name),reg_ext) ||
- is_prefix(file->name, tmp_file_prefix))
- continue;
- *ext=0;
- file_name_len= filename_to_tablename(file->name, uname, sizeof(uname));
- if (wild)
- {
- if (lower_case_table_names)
- {
- if (my_wildcmp(files_charset_info,
- uname, uname + file_name_len,
- wild, wild + wild_length,
- wild_prefix, wild_one,wild_many))
- continue;
- }
- else if (wild_compare(uname, wild, 0))
- continue;
- }
- }
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- /* Don't show tables where we don't have any privileges */
- if (db && !(col_access & TABLE_ACLS))
- {
- table_list.db= (char*) db;
- table_list.db_length= strlen(db);
- table_list.table_name= uname;
- table_list.table_name_length= file_name_len;
- table_list.grant.privilege=col_access;
- if (check_grant(thd, TABLE_ACLS, &table_list, TRUE, 1, TRUE))
- continue;
- }
-#endif
- if (!(file_name=
- thd->make_lex_string(file_name, uname, file_name_len, TRUE)) ||
- files->push_back(file_name))
- {
- my_dirend(dirp);
- DBUG_RETURN(FIND_FILES_OOM);
+ if (tl.add_file(file->name))
+ goto err;
}
+ tl.sort();
+ }
+ else
+ {
+ if (ha_discover_table_names(thd, db, dirp, &tl, false))
+ goto err;
}
- DBUG_PRINT("info",("found: %d files", files->elements));
- my_dirend(dirp);
- (void) ha_find_files(thd, db, path, wild, dir, files);
+ DBUG_PRINT("info",("found: %zu files", files->elements()));
+ my_dirend(dirp);
DBUG_RETURN(FIND_FILES_OK);
+
+err:
+ my_dirend(dirp);
+ DBUG_RETURN(FIND_FILES_OOM);
}
@@ -881,7 +933,7 @@ public:
m_view_access_denied_message_ptr(NULL)
{
- m_sctx = test(m_top_view->security_ctx) ?
+ m_sctx= MY_TEST(m_top_view->security_ctx) ?
m_top_view->security_ctx : thd->security_ctx;
}
@@ -908,8 +960,8 @@ public:
}
bool handle_condition(THD *thd, uint sql_errno, const char * /* sqlstate */,
- MYSQL_ERROR::enum_warning_level level,
- const char *message, MYSQL_ERROR ** /* cond_hdl */)
+ Sql_condition::enum_warning_level level,
+ const char *message, Sql_condition ** /* cond_hdl */)
{
/*
The handler does not handle the errors raised by itself.
@@ -944,7 +996,7 @@ public:
case ER_NO_SUCH_TABLE_IN_ENGINE:
/* Established behavior: warn if underlying tables, columns, or functions
are missing. */
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_VIEW_INVALID,
ER(ER_VIEW_INVALID),
m_top_view->get_db_name(),
@@ -1000,9 +1052,10 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
{
/*
- 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.
+ 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);
@@ -1030,16 +1083,15 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
buffer.set_charset(table_list->view_creation_ctx->get_client_cs());
if ((table_list->view ?
- view_store_create_info(thd, table_list, &buffer) :
- store_create_info(thd, table_list, &buffer, NULL,
- FALSE /* show_database */)))
+ show_create_view(thd, table_list, &buffer) :
+ show_create_table(thd, table_list, &buffer, NULL, WITHOUT_DB_NAME)))
goto exit;
if (table_list->view)
{
field_list.push_back(new Item_empty_string("View",NAME_CHAR_LEN));
field_list.push_back(new Item_empty_string("Create View",
- max(buffer.length(),1024)));
+ MY_MAX(buffer.length(),1024)));
field_list.push_back(new Item_empty_string("character_set_client",
MY_CS_NAME_SIZE));
field_list.push_back(new Item_empty_string("collation_connection",
@@ -1050,7 +1102,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
field_list.push_back(new Item_empty_string("Table",NAME_CHAR_LEN));
// 1024 is for not to confuse old clients
field_list.push_back(new Item_empty_string("Create Table",
- max(buffer.length(),1024)));
+ MY_MAX(buffer.length(),1024)));
}
if (protocol->send_result_set_metadata(&field_list,
@@ -1096,7 +1148,8 @@ exit:
DBUG_RETURN(error);
}
-bool mysqld_show_create_db(THD *thd, char *dbname,
+bool mysqld_show_create_db(THD *thd, LEX_STRING *dbname,
+ LEX_STRING *orig_dbname,
HA_CREATE_INFO *create_info)
{
char buff[2048];
@@ -1114,32 +1167,37 @@ bool mysqld_show_create_db(THD *thd, char *dbname,
if (test_all_bits(sctx->master_access, DB_ACLS))
db_access=DB_ACLS;
else
- db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname, 0) |
- sctx->master_access);
- if (!(db_access & DB_ACLS) && check_grant_db(thd,dbname))
+ {
+ db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname->str, 0) |
+ sctx->master_access;
+ if (sctx->priv_role[0])
+ db_access|= acl_get("", "", sctx->priv_role, dbname->str, 0);
+ }
+
+ if (!(db_access & DB_ACLS) && check_grant_db(thd,dbname->str))
{
status_var_increment(thd->status_var.access_denied_errors);
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
- sctx->priv_user, sctx->host_or_ip, dbname);
+ sctx->priv_user, sctx->host_or_ip, dbname->str);
general_log_print(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
- sctx->priv_user, sctx->host_or_ip, dbname);
+ sctx->priv_user, sctx->host_or_ip, orig_dbname->str);
DBUG_RETURN(TRUE);
}
#endif
- if (is_infoschema_db(dbname))
+ if (is_infoschema_db(dbname->str))
{
- dbname= INFORMATION_SCHEMA_NAME.str;
+ *dbname= INFORMATION_SCHEMA_NAME;
create.default_table_charset= system_charset_info;
}
else
{
- if (check_db_dir_existence(dbname))
+ if (check_db_dir_existence(dbname->str))
{
- my_error(ER_BAD_DB_ERROR, MYF(0), dbname);
+ my_error(ER_BAD_DB_ERROR, MYF(0), dbname->str);
DBUG_RETURN(TRUE);
}
- load_db_opt_by_name(thd, dbname, &create);
+ load_db_opt_by_name(thd, dbname->str, &create);
}
List<Item> field_list;
field_list.push_back(new Item_empty_string("Database",NAME_CHAR_LEN));
@@ -1150,12 +1208,12 @@ bool mysqld_show_create_db(THD *thd, char *dbname,
DBUG_RETURN(TRUE);
protocol->prepare_for_resend();
- protocol->store(dbname, strlen(dbname), system_charset_info);
+ protocol->store(orig_dbname->str, orig_dbname->length, system_charset_info);
buffer.length(0);
buffer.append(STRING_WITH_LEN("CREATE DATABASE "));
if (create_options & HA_LEX_CREATE_IF_NOT_EXISTS)
buffer.append(STRING_WITH_LEN("/*!32312 IF NOT EXISTS*/ "));
- append_identifier(thd, &buffer, dbname, strlen(dbname));
+ append_identifier(thd, &buffer, dbname->str, dbname->length);
if (create.default_table_charset)
{
@@ -1284,9 +1342,22 @@ append_identifier(THD *thd, String *packet, const char *name, uint length)
it's a keyword
*/
+ /*
+ Special code for swe7. It encodes the letter "E WITH ACUTE" on
+ the position 0x60, where backtick normally resides.
+ In swe7 we cannot append 0x60 using system_charset_info,
+ because it cannot be converted to swe7 and will be replaced to
+ question mark '?'. Use &my_charset_bin to avoid this.
+ It will prevent conversion and will append the backtick as is.
+ */
+ CHARSET_INFO *quote_charset= q == 0x60 &&
+ (packet->charset()->state & MY_CS_NONASCII) &&
+ packet->charset()->mbmaxlen == 1 ?
+ &my_charset_bin : system_charset_info;
+
(void) packet->reserve(length*2 + 2);
quote_char= (char) q;
- if (packet->append(&quote_char, 1, system_charset_info))
+ if (packet->append(&quote_char, 1, quote_charset))
return true;
for (name_end= name+length ; name < name_end ; name+= length)
@@ -1303,12 +1374,12 @@ append_identifier(THD *thd, String *packet, const char *name, uint length)
if (!length)
length= 1;
if (length == 1 && chr == (uchar) quote_char &&
- packet->append(&quote_char, 1, system_charset_info))
+ packet->append(&quote_char, 1, quote_charset))
return true;
if (packet->append(name, length, system_charset_info))
return true;
}
- return packet->append(&quote_char, 1, system_charset_info);
+ return packet->append(&quote_char, 1, quote_charset);
}
@@ -1378,8 +1449,35 @@ static void append_directory(THD *thd, String *packet, const char *dir_type,
#define LIST_PROCESS_HOST_LEN 64
-static bool get_field_default_value(THD *thd, Field *timestamp_field,
- Field *field, String *def_value,
+
+/**
+ Print "ON UPDATE" clause of a field into a string.
+
+ @param timestamp_field Pointer to timestamp field of a table.
+ @param field The field to generate ON UPDATE clause for.
+ @bool lcase Whether to print in lower case.
+ @return false on success, true on error.
+*/
+static bool print_on_update_clause(Field *field, String *val, bool lcase)
+{
+ DBUG_ASSERT(val->charset()->mbminlen == 1);
+ val->length(0);
+ if (field->has_update_default_function())
+ {
+ if (lcase)
+ val->append(STRING_WITH_LEN("on update "));
+ else
+ val->append(STRING_WITH_LEN("ON UPDATE "));
+ val->append(STRING_WITH_LEN("CURRENT_TIMESTAMP"));
+ if (field->decimals() > 0)
+ val->append_parenthesized(field->decimals());
+ return true;
+ }
+ return false;
+}
+
+
+static bool get_field_default_value(THD *thd, Field *field, String *def_value,
bool quoted)
{
bool has_default;
@@ -1390,8 +1488,7 @@ static bool get_field_default_value(THD *thd, Field *timestamp_field,
We are using CURRENT_TIMESTAMP instead of NOW because it is
more standard
*/
- has_now_default= (timestamp_field == field &&
- field->unireg_check != Field::TIMESTAMP_UN_FIELD);
+ has_now_default= field->has_insert_default_function();
has_default= (field_type != FIELD_TYPE_BLOB &&
!(field->flags & NO_DEFAULT_VALUE_FLAG) &&
@@ -1403,7 +1500,11 @@ static bool get_field_default_value(THD *thd, Field *timestamp_field,
if (has_default)
{
if (has_now_default)
+ {
def_value->append(STRING_WITH_LEN("CURRENT_TIMESTAMP"));
+ if (field->decimals() > 0)
+ def_value->append_parenthesized(field->decimals());
+ }
else if (!field->is_null())
{ // Not null by default
char tmp[MAX_FIELD_WIDTH];
@@ -1452,13 +1553,34 @@ static bool get_field_default_value(THD *thd, Field *timestamp_field,
@param thd thread handler
@param packet string to append
@param opt list of options
+ @param check_options only print known options
+ @param rules list of known options
*/
static void append_create_options(THD *thd, String *packet,
- engine_option_value *opt)
+ engine_option_value *opt,
+ bool check_options,
+ ha_create_table_option *rules)
{
+ bool in_comment= false;
for(; opt; opt= opt->next)
{
+ if (check_options)
+ {
+ if (is_engine_option_known(opt, rules))
+ {
+ if (in_comment)
+ packet->append(STRING_WITH_LEN(" */"));
+ in_comment= false;
+ }
+ else
+ {
+ if (!in_comment)
+ packet->append(STRING_WITH_LEN(" /*"));
+ in_comment= true;
+ }
+ }
+
DBUG_ASSERT(opt->value.str);
packet->append(' ');
append_identifier(thd, packet, opt->name.str, opt->name.length);
@@ -1468,13 +1590,15 @@ static void append_create_options(THD *thd, String *packet,
else
packet->append(opt->value.str, opt->value.length);
}
+ if (in_comment)
+ packet->append(STRING_WITH_LEN(" */"));
}
/*
Build a CREATE TABLE statement for a table.
SYNOPSIS
- store_create_info()
+ show_create_table()
thd The thread
table_list A list containing one table to write statement
for.
@@ -1484,11 +1608,7 @@ static void append_create_options(THD *thd, String *packet,
to tailor the format of the statement. Can be
NULL, in which case only SQL_MODE is considered
when building the statement.
- show_database If true, then print the database before the table
- name. The database name is only printed in the event
- that it is different from the current database.
- If false, then do not print the database before
- the table name.
+ with_db_name Add database name to table name
NOTE
Currently always return 0, but might return error code in the
@@ -1498,8 +1618,9 @@ static void append_create_options(THD *thd, String *packet,
0 OK
*/
-int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
- HA_CREATE_INFO *create_info_arg, bool show_database)
+int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
+ HA_CREATE_INFO *create_info_arg,
+ enum_with_db_name with_db_name)
{
List<Item> field_list;
char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], def_value_buf[MAX_FIELD_WIDTH];
@@ -1513,29 +1634,39 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
handler *file= table->file;
TABLE_SHARE *share= table->s;
HA_CREATE_INFO create_info;
-#ifdef WITH_PARTITION_STORAGE_ENGINE
- bool show_table_options= FALSE;
-#endif /* WITH_PARTITION_STORAGE_ENGINE */
- bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL |
- MODE_ORACLE |
- MODE_MSSQL |
- MODE_DB2 |
- MODE_MAXDB |
- MODE_ANSI)) != 0;
- bool limited_mysql_mode= (thd->variables.sql_mode & (MODE_NO_FIELD_OPTIONS |
- MODE_MYSQL323 |
- MODE_MYSQL40)) != 0;
+ sql_mode_t sql_mode= thd->variables.sql_mode;
+ bool foreign_db_mode= sql_mode & (MODE_POSTGRESQL | MODE_ORACLE |
+ MODE_MSSQL | MODE_DB2 |
+ MODE_MAXDB | MODE_ANSI);
+ bool limited_mysql_mode= sql_mode & (MODE_NO_FIELD_OPTIONS | MODE_MYSQL323 |
+ MODE_MYSQL40);
+ bool show_table_options= !(sql_mode & MODE_NO_TABLE_OPTIONS) &&
+ !foreign_db_mode;
+ bool check_options= !(sql_mode & MODE_IGNORE_BAD_TABLE_OPTIONS) &&
+ !create_info_arg;
+ handlerton *hton;
my_bitmap_map *old_map;
int error= 0;
- DBUG_ENTER("store_create_info");
+ DBUG_ENTER("show_create_table");
DBUG_PRINT("enter",("table: %s", table->s->table_name.str));
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ if (table->part_info)
+ hton= table->part_info->default_engine_type;
+ else
+#endif
+ hton= file->ht;
+
restore_record(table, s->default_values); // Get empty record
+ packet->append(STRING_WITH_LEN("CREATE "));
+ if (create_info_arg &&
+ (create_info_arg->org_options & HA_LEX_CREATE_REPLACE ||
+ create_info_arg->table_was_deleted))
+ packet->append(STRING_WITH_LEN("OR REPLACE "));
if (share->tmp_table)
- packet->append(STRING_WITH_LEN("CREATE TEMPORARY TABLE "));
- else
- packet->append(STRING_WITH_LEN("CREATE TABLE "));
+ packet->append(STRING_WITH_LEN("TEMPORARY "));
+ packet->append(STRING_WITH_LEN("TABLE "));
if (create_info_arg &&
(create_info_arg->options & HA_LEX_CREATE_IF_NOT_EXISTS))
packet->append(STRING_WITH_LEN("IF NOT EXISTS "));
@@ -1558,7 +1689,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
avoid having to update gazillions of tests and result files, but
it also saves a few bytes of the binary log.
*/
- if (show_database)
+ if (with_db_name == WITH_DB_NAME)
{
const LEX_STRING *const db=
table_list->schema_table ? &INFORMATION_SCHEMA_NAME : &table->s->db;
@@ -1597,8 +1728,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
field->sql_type(type);
packet->append(type.ptr(), type.length(), system_charset_info);
- if (field->has_charset() &&
- !(thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)))
+ if (field->has_charset() && !(sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)))
{
if (field->charset() != share->table_charset)
{
@@ -1641,19 +1771,21 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
}
if (!field->vcol_info &&
- get_field_default_value(thd, table->timestamp_field,
- field, &def_value, 1))
+ get_field_default_value(thd, field, &def_value, 1))
{
packet->append(STRING_WITH_LEN(" DEFAULT "));
packet->append(def_value.ptr(), def_value.length(), system_charset_info);
}
- if (!limited_mysql_mode && table->timestamp_field == field &&
- field->unireg_check != Field::TIMESTAMP_DN_FIELD)
- packet->append(STRING_WITH_LEN(" ON UPDATE CURRENT_TIMESTAMP"));
+ if (!limited_mysql_mode && print_on_update_clause(field, &def_value, false))
+ {
+ packet->append(STRING_WITH_LEN(" "));
+ packet->append(def_value);
+ }
+
if (field->unireg_check == Field::NEXT_NUMBER &&
- !(thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS))
+ !(sql_mode & MODE_NO_FIELD_OPTIONS))
packet->append(STRING_WITH_LEN(" AUTO_INCREMENT"));
if (field->comment.length)
@@ -1661,7 +1793,8 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
packet->append(STRING_WITH_LEN(" COMMENT "));
append_unescaped(packet, field->comment.str, field->comment.length);
}
- append_create_options(thd, packet, field->option_list);
+ append_create_options(thd, packet, field->option_list, check_options,
+ hton->field_options);
}
key_info= table->key_info;
@@ -1702,7 +1835,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
packet->append(STRING_WITH_LEN(" ("));
- for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
+ for (uint j=0 ; j < key_info->user_defined_key_parts ; j++,key_part++)
{
if (j)
packet->append(',');
@@ -1715,13 +1848,8 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
table->field[key_part->fieldnr-1]->key_length() &&
!(key_info->flags & (HA_FULLTEXT | HA_SPATIAL))))
{
- char *end;
- buff[0] = '(';
- end= int10_to_str((long) key_part->length /
- key_part->field->charset()->mbmaxlen,
- buff + 1,10);
- *end++ = ')';
- packet->append(buff,(uint) (end-buff));
+ packet->append_parenthesized((long) key_part->length /
+ key_part->field->charset()->mbmaxlen);
}
}
packet->append(')');
@@ -1733,7 +1861,8 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
append_identifier(thd, packet, parser_name->str, parser_name->length);
packet->append(STRING_WITH_LEN(" */ "));
}
- append_create_options(thd, packet, key_info->option_list);
+ append_create_options(thd, packet, key_info->option_list, check_options,
+ hton->index_options);
}
/*
@@ -1748,12 +1877,8 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
}
packet->append(STRING_WITH_LEN("\n)"));
- if (!(thd->variables.sql_mode & MODE_NO_TABLE_OPTIONS) && !foreign_db_mode)
+ if (show_table_options)
{
-#ifdef WITH_PARTITION_STORAGE_ENGINE
- show_table_options= TRUE;
-#endif /* WITH_PARTITION_STORAGE_ENGINE */
-
/*
IF check_create_info
THEN add ENGINE only if it was used when creating the table
@@ -1761,19 +1886,11 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
if (!create_info_arg ||
(create_info_arg->used_fields & HA_CREATE_USED_ENGINE))
{
- if (thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))
+ if (sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))
packet->append(STRING_WITH_LEN(" TYPE="));
else
packet->append(STRING_WITH_LEN(" ENGINE="));
-#ifdef WITH_PARTITION_STORAGE_ENGINE
- if (table->part_info)
- packet->append(ha_resolve_storage_engine_name(
- table->part_info->default_engine_type));
- else
- packet->append(file->table_type());
-#else
- packet->append(file->table_type());
-#endif
+ packet->append(hton_name(hton));
}
/*
@@ -1795,9 +1912,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
packet->append(buff, (uint) (end - buff));
}
- if (share->table_charset &&
- !(thd->variables.sql_mode & MODE_MYSQL323) &&
- !(thd->variables.sql_mode & MODE_MYSQL40))
+ if (share->table_charset && !(sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)))
{
/*
IF check_create_info
@@ -1844,6 +1959,22 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
packet->append(STRING_WITH_LEN(" PACK_KEYS=1"));
if (create_info.options & HA_OPTION_NO_PACK_KEYS)
packet->append(STRING_WITH_LEN(" PACK_KEYS=0"));
+ if (share->db_create_options & HA_OPTION_STATS_PERSISTENT)
+ packet->append(STRING_WITH_LEN(" STATS_PERSISTENT=1"));
+ if (share->db_create_options & HA_OPTION_NO_STATS_PERSISTENT)
+ packet->append(STRING_WITH_LEN(" STATS_PERSISTENT=0"));
+ if (share->stats_auto_recalc == HA_STATS_AUTO_RECALC_ON)
+ packet->append(STRING_WITH_LEN(" STATS_AUTO_RECALC=1"));
+ else if (share->stats_auto_recalc == HA_STATS_AUTO_RECALC_OFF)
+ packet->append(STRING_WITH_LEN(" STATS_AUTO_RECALC=0"));
+ if (share->stats_sample_pages != 0)
+ {
+ char *end;
+ packet->append(STRING_WITH_LEN(" STATS_SAMPLE_PAGES="));
+ end= longlong10_to_str(share->stats_sample_pages, buff, 10);
+ packet->append(buff, (uint) (end - buff));
+ }
+
/* We use CHECKSUM, instead of TABLE_CHECKSUM, for backward compability */
if (create_info.options & HA_OPTION_CHECKSUM)
packet->append(STRING_WITH_LEN(" CHECKSUM=1"));
@@ -1882,7 +2013,8 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
packet->append(STRING_WITH_LEN(" CONNECTION="));
append_unescaped(packet, share->connect_string.str, share->connect_string.length);
}
- append_create_options(thd, packet, share->option_list);
+ append_create_options(thd, packet, share->option_list, check_options,
+ hton->table_options);
append_directory(thd, packet, "DATA", create_info.data_file_name);
append_directory(thd, packet, "INDEX", create_info.index_file_name);
}
@@ -1956,7 +2088,7 @@ static void store_key_options(THD *thd, String *packet, TABLE *table,
end= longlong10_to_str(key_info->block_size, buff, 10);
packet->append(buff, (uint) (end - buff));
}
- DBUG_ASSERT(test(key_info->flags & HA_USES_COMMENT) ==
+ DBUG_ASSERT(MY_TEST(key_info->flags & HA_USES_COMMENT) ==
(key_info->comment.length > 0));
if (key_info->flags & HA_USES_COMMENT)
{
@@ -2025,14 +2157,16 @@ void append_definer(THD *thd, String *buffer, const LEX_STRING *definer_user,
{
buffer->append(STRING_WITH_LEN("DEFINER="));
append_identifier(thd, buffer, definer_user->str, definer_user->length);
- buffer->append('@');
- append_identifier(thd, buffer, definer_host->str, definer_host->length);
+ if (definer_host->str[0])
+ {
+ buffer->append('@');
+ append_identifier(thd, buffer, definer_host->str, definer_host->length);
+ }
buffer->append(' ');
}
-int
-view_store_create_info(THD *thd, TABLE_LIST *table, String *buff)
+static int show_create_view(THD *thd, TABLE_LIST *table, String *buff)
{
my_bool compact_view_name= TRUE;
my_bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL |
@@ -2121,10 +2255,6 @@ public:
double progress;
};
-#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-template class I_List<thread_info>;
-#endif
-
static const char *thread_state_info(THD *tmp)
{
#ifndef EMBEDDED_LIBRARY
@@ -2132,21 +2262,21 @@ static const char *thread_state_info(THD *tmp)
{
if (tmp->net.reading_or_writing == 2)
return "Writing to net";
- else if (tmp->command == COM_SLEEP)
+ else if (tmp->get_command() == COM_SLEEP)
return "";
else
return "Reading from net";
}
- else
+#else
+ if (tmp->get_command() == COM_SLEEP)
+ return "";
#endif
- {
- if (tmp->proc_info)
- return tmp->proc_info;
- else if (tmp->mysys_var && tmp->mysys_var->current_cond)
- return "Waiting on cond";
- else
- return NULL;
- }
+ if (tmp->proc_info)
+ return tmp->proc_info;
+ else if (tmp->mysys_var && tmp->mysys_var->current_cond)
+ return "Waiting on cond";
+ else
+ return NULL;
}
void mysqld_list_processes(THD *thd,const char *user, bool verbose)
@@ -2212,7 +2342,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
thd_info->host= thd->strdup(tmp_sctx->host_or_ip[0] ?
tmp_sctx->host_or_ip :
tmp_sctx->host ? tmp_sctx->host : "");
- thd_info->command=(int) tmp->command;
+ thd_info->command=(int) tmp->get_command();
mysql_mutex_lock(&tmp->LOCK_thd_data);
if ((thd_info->db= tmp->db)) // Safe test
thd_info->db= thd->strdup(thd_info->db);
@@ -2227,7 +2357,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
/* Lock THD mutex that protects its data when looking at it. */
if (tmp->query())
{
- uint length= min(max_query_length, tmp->query_length());
+ uint length= MY_MIN(max_query_length, tmp->query_length());
char *q= thd->strmake(tmp->query(),length);
/* Safety: in case strmake failed, we set length to 0. */
thd_info->query_string=
@@ -2240,7 +2370,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
*/
if (tmp->progress.max_counter)
{
- uint max_stage= max(tmp->progress.max_stage, 1);
+ uint max_stage= MY_MAX(tmp->progress.max_stage, 1);
thd_info->progress= (((tmp->progress.stage / (double) max_stage) +
((tmp->progress.counter /
(double) tmp->progress.max_counter) /
@@ -2294,6 +2424,259 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
DBUG_VOID_RETURN;
}
+
+/*
+ Produce EXPLAIN data.
+
+ This function is APC-scheduled to be run in the context of the thread that
+ we're producing EXPLAIN for.
+*/
+
+void Show_explain_request::call_in_target_thread()
+{
+ Query_arena backup_arena;
+ bool printed_anything= FALSE;
+
+ /*
+ Change the arena because JOIN::print_explain and co. are going to allocate
+ items. Let them allocate them on our arena.
+ */
+ target_thd->set_n_backup_active_arena((Query_arena*)request_thd,
+ &backup_arena);
+
+ query_str.copy(target_thd->query(),
+ target_thd->query_length(),
+ target_thd->query_charset());
+
+ DBUG_ASSERT(current_thd == target_thd);
+ set_current_thd(request_thd);
+ if (target_thd->lex->print_explain(explain_buf, 0 /* explain flags*/,
+ &printed_anything))
+ {
+ failed_to_produce= TRUE;
+ }
+ set_current_thd(target_thd);
+
+ if (!printed_anything)
+ failed_to_produce= TRUE;
+
+ target_thd->restore_active_arena((Query_arena*)request_thd, &backup_arena);
+}
+
+
+int select_result_explain_buffer::send_data(List<Item> &items)
+{
+ int res;
+ THD *cur_thd= current_thd;
+ DBUG_ENTER("select_result_explain_buffer::send_data");
+
+ /*
+ Switch to the recieveing thread, so that we correctly count memory used
+ by it. This is needed as it's the receiving thread that will free the
+ memory.
+ */
+ set_current_thd(thd);
+ fill_record(thd, dst_table, dst_table->field, items, TRUE, FALSE);
+ res= dst_table->file->ha_write_tmp_row(dst_table->record[0]);
+ set_current_thd(cur_thd);
+ DBUG_RETURN(MY_TEST(res));
+}
+
+bool select_result_text_buffer::send_result_set_metadata(List<Item> &fields, uint flag)
+{
+ n_columns= fields.elements;
+ return append_row(fields, true /*send item names */);
+ return send_data(fields);
+}
+
+
+int select_result_text_buffer::send_data(List<Item> &items)
+{
+ return append_row(items, false /*send item values */);
+}
+
+int select_result_text_buffer::append_row(List<Item> &items, bool send_names)
+{
+ List_iterator<Item> it(items);
+ Item *item;
+ char **row;
+ int column= 0;
+
+ if (!(row= (char**) thd->alloc(sizeof(char*) * n_columns)))
+ return true;
+ rows.push_back(row);
+
+ while ((item= it++))
+ {
+ DBUG_ASSERT(column < n_columns);
+ StringBuffer<32> buf;
+ const char *data_ptr;
+ size_t data_len;
+ if (send_names)
+ {
+ data_ptr= item->name;
+ data_len= strlen(item->name);
+ }
+ else
+ {
+ String *res;
+ res= item->val_str(&buf);
+ if (item->null_value)
+ {
+ data_ptr= "NULL";
+ data_len=4;
+ }
+ else
+ {
+ data_ptr= res->c_ptr_safe();
+ data_len= res->length();
+ }
+ }
+
+ char *ptr= (char*)thd->alloc(data_len + 1);
+ memcpy(ptr, data_ptr, data_len + 1);
+ row[column]= ptr;
+
+ column++;
+ }
+ return false;
+}
+
+
+void select_result_text_buffer::save_to(String *res)
+{
+ List_iterator<char*> it(rows);
+ char **row;
+ res->append("#\n");
+ while ((row= it++))
+ {
+ res->append("# explain: ");
+ for (int i=0; i < n_columns; i++)
+ {
+ if (i)
+ res->append('\t');
+ res->append(row[i]);
+ }
+ res->append("\n");
+ }
+ res->append("#\n");
+}
+
+
+/*
+ Store the SHOW EXPLAIN output in the temporary table.
+*/
+
+int fill_show_explain(THD *thd, TABLE_LIST *table, COND *cond)
+{
+ const char *calling_user;
+ THD *tmp;
+ my_thread_id thread_id;
+ DBUG_ENTER("fill_show_explain");
+
+ DBUG_ASSERT(cond==NULL);
+ thread_id= thd->lex->value_list.head()->val_int();
+ calling_user= (thd->security_ctx->master_access & PROCESS_ACL) ? NullS :
+ thd->security_ctx->priv_user;
+
+ if ((tmp= find_thread_by_id(thread_id)))
+ {
+ Security_context *tmp_sctx= tmp->security_ctx;
+ /*
+ If calling_user==NULL, calling thread has SUPER or PROCESS
+ privilege, and so can do SHOW EXPLAIN on any user.
+
+ if calling_user!=NULL, he's only allowed to view SHOW EXPLAIN on
+ his own threads.
+ */
+ if (calling_user && (!tmp_sctx->user || strcmp(calling_user,
+ tmp_sctx->user)))
+ {
+ my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "PROCESS");
+ mysql_mutex_unlock(&tmp->LOCK_thd_data);
+ DBUG_RETURN(1);
+ }
+
+ if (tmp == thd)
+ {
+ mysql_mutex_unlock(&tmp->LOCK_thd_data);
+ my_error(ER_TARGET_NOT_EXPLAINABLE, MYF(0));
+ DBUG_RETURN(1);
+ }
+
+ bool bres;
+ /*
+ Ok we've found the thread of interest and it won't go away because
+ we're holding its LOCK_thd data. Post it a SHOW EXPLAIN request.
+ */
+ bool timed_out;
+ int timeout_sec= 30;
+ Show_explain_request explain_req;
+ select_result_explain_buffer *explain_buf;
+
+ explain_buf= new select_result_explain_buffer(thd, table->table);
+
+ explain_req.explain_buf= explain_buf;
+ explain_req.target_thd= tmp;
+ explain_req.request_thd= thd;
+ explain_req.failed_to_produce= FALSE;
+
+ /* Ok, we have a lock on target->LOCK_thd_data, can call: */
+ bres= tmp->apc_target.make_apc_call(thd, &explain_req, timeout_sec, &timed_out);
+
+ if (bres || explain_req.failed_to_produce)
+ {
+ if (thd->killed)
+ thd->send_kill_message();
+ else if (timed_out)
+ my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));
+ else
+ my_error(ER_TARGET_NOT_EXPLAINABLE, MYF(0));
+
+ bres= TRUE;
+ }
+ else
+ {
+ /*
+ Push the query string as a warning. The query may be in a different
+ charset than the charset that's used for error messages, so, convert it
+ if needed.
+ */
+ CHARSET_INFO *fromcs= explain_req.query_str.charset();
+ CHARSET_INFO *tocs= error_message_charset_info;
+ char *warning_text;
+ if (!my_charset_same(fromcs, tocs))
+ {
+ uint conv_length= 1 + tocs->mbmaxlen * explain_req.query_str.length() /
+ fromcs->mbminlen;
+ uint dummy_errors;
+ char *to, *p;
+ if (!(to= (char*)thd->alloc(conv_length + 1)))
+ DBUG_RETURN(1);
+ p= to;
+ p+= copy_and_convert(to, conv_length, tocs,
+ explain_req.query_str.c_ptr(),
+ explain_req.query_str.length(), fromcs,
+ &dummy_errors);
+ *p= 0;
+ warning_text= to;
+ }
+ else
+ warning_text= explain_req.query_str.c_ptr_safe();
+
+ push_warning(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_YES, warning_text);
+ }
+ DBUG_RETURN(bres);
+ }
+ else
+ {
+ my_error(ER_NO_SUCH_THREAD, MYF(0), thread_id);
+ DBUG_RETURN(1);
+ }
+}
+
+
int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
{
TABLE *table= tables->table;
@@ -2360,8 +2743,8 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
"Killed" : 0))))
table->field[4]->store(val, strlen(val), cs);
else
- table->field[4]->store(command_name[tmp->command].str,
- command_name[tmp->command].length, cs);
+ table->field[4]->store(command_name[tmp->get_command()].str,
+ command_name[tmp->get_command()].length, cs);
/* MYSQL_TIME */
ulonglong start_utime= tmp->start_time * HRTIME_RESOLUTION + tmp->start_time_sec_part;
ulonglong utime= start_utime && start_utime < unow.val
@@ -2387,7 +2770,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
if (tmp->query())
{
table->field[7]->store(tmp->query(),
- min(PROCESS_LIST_INFO_WIDTH,
+ MY_MIN(PROCESS_LIST_INFO_WIDTH,
tmp->query_length()), cs);
table->field[7]->set_notnull();
}
@@ -2405,6 +2788,21 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
}
mysql_mutex_unlock(&tmp->LOCK_thd_data);
+ /*
+ This may become negative if we free a memory allocated by another
+ thread in this thread. However it's better that we notice it eventually
+ than hide it.
+ */
+ table->field[12]->store((longlong) (tmp->status_var.memory_used +
+ sizeof(THD)),
+ FALSE);
+ table->field[12]->set_notnull();
+ table->field[13]->store((longlong) tmp->get_examined_row_count(), TRUE);
+ table->field[13]->set_notnull();
+
+ /* QUERY_ID */
+ table->field[14]->store(tmp->query_id, TRUE);
+
if (schema_table_store_record(thd, table))
{
mysql_mutex_unlock(&LOCK_thread_count);
@@ -2427,7 +2825,7 @@ static bool status_vars_inited= 0;
C_MODE_START
static int show_var_cmp(const void *var1, const void *var2)
{
- return strcmp(((SHOW_VAR*)var1)->name, ((SHOW_VAR*)var2)->name);
+ return strcasecmp(((SHOW_VAR*)var1)->name, ((SHOW_VAR*)var2)->name);
}
C_MODE_END
@@ -2475,9 +2873,9 @@ int add_status_vars(SHOW_VAR *list)
{
int res= 0;
if (status_vars_inited)
- mysql_mutex_lock(&LOCK_status);
+ mysql_mutex_lock(&LOCK_show_status);
if (!all_status_vars.buffer && // array is not allocated yet - do it now
- my_init_dynamic_array(&all_status_vars, sizeof(SHOW_VAR), 200, 20))
+ my_init_dynamic_array(&all_status_vars, sizeof(SHOW_VAR), 200, 20, MYF(0)))
{
res= 1;
goto err;
@@ -2490,7 +2888,7 @@ int add_status_vars(SHOW_VAR *list)
sort_dynamic(&all_status_vars, show_var_cmp);
err:
if (status_vars_inited)
- mysql_mutex_unlock(&LOCK_status);
+ mysql_mutex_unlock(&LOCK_show_status);
return res;
}
@@ -2524,7 +2922,7 @@ void reset_status_vars()
catch-all cleanup function, cleans up everything no matter what
DESCRIPTION
- This function is not strictly required if all add_to_status/
+ This function is not strictly required if all add_status_vars/
remove_status_vars are properly paired, but it's a safety measure that
deletes everything from the all_status_vars[] even if some
remove_status_vars were forgotten
@@ -2552,7 +2950,7 @@ void remove_status_vars(SHOW_VAR *list)
{
if (status_vars_inited)
{
- mysql_mutex_lock(&LOCK_status);
+ mysql_mutex_lock(&LOCK_show_status);
SHOW_VAR *all= dynamic_element(&all_status_vars, 0, SHOW_VAR *);
for (; list->name; list++)
@@ -2573,7 +2971,7 @@ void remove_status_vars(SHOW_VAR *list)
}
}
shrink_var_array(&all_status_vars);
- mysql_mutex_unlock(&LOCK_status);
+ mysql_mutex_unlock(&LOCK_show_status);
}
else
{
@@ -2627,19 +3025,45 @@ static bool show_status_array(THD *thd, const char *wild,
for (; variables->name; variables++)
{
+ bool wild_checked= 0;
strnmov(prefix_end, variables->name, len);
name_buffer[sizeof(name_buffer)-1]=0; /* Safety */
if (ucase_names)
my_caseup_str(system_charset_info, name_buffer);
+ else
+ {
+ my_casedn_str(system_charset_info, name_buffer);
+ DBUG_ASSERT(name_buffer[0] >= 'a');
+ DBUG_ASSERT(name_buffer[0] <= 'z');
+
+ /* traditionally status variables have a first letter uppercased */
+ if (status_var)
+ name_buffer[0]-= 'a' - 'A';
+ }
+
restore_record(table, s->default_values);
table->field[0]->store(name_buffer, strlen(name_buffer),
system_charset_info);
+
/*
- if var->type is SHOW_FUNC, call the function.
- Repeat as necessary, if new var is again SHOW_FUNC
+ Compare name for types that can't return arrays. We do this to not
+ calculate the value for function variables that we will not access
*/
- for (var=variables; var->type == SHOW_FUNC; var= &tmp)
+ if ((variables->type != SHOW_FUNC && variables->type != SHOW_ARRAY))
+ {
+ if (wild && wild[0] && wild_case_compare(system_charset_info,
+ name_buffer, wild))
+ continue;
+ wild_checked= 1; // Avoid checking it again
+ }
+
+ /*
+ if var->type is SHOW_FUNC or SHOW_SIMPLE_FUNC, call the function.
+ Repeat as necessary, if new var is again one of the above
+ */
+ for (var=variables; var->type == SHOW_FUNC ||
+ var->type == SHOW_SIMPLE_FUNC; var= &tmp)
((mysql_show_var_func)(var->value))(thd, &tmp, buff);
SHOW_TYPE show_type=var->type;
@@ -2650,8 +3074,9 @@ static bool show_status_array(THD *thd, const char *wild,
}
else
{
- if (!(wild && wild[0] && wild_case_compare(system_charset_info,
- name_buffer, wild)) &&
+ if ((wild_checked ||
+ (wild && wild[0] && wild_case_compare(system_charset_info,
+ name_buffer, wild))) &&
(!cond || cond->val_int()))
{
char *value=var->value;
@@ -2796,7 +3221,7 @@ static int aggregate_user_stats(HASH *all_user_stats, HASH *agg_user_stats)
{
DBUG_ENTER("aggregate_user_stats");
if (my_hash_init(agg_user_stats, system_charset_info,
- max(all_user_stats->records, 1),
+ MY_MAX(all_user_stats->records, 1),
0, 0, (my_hash_get_key)get_key_user_stats,
(my_hash_free_key)free_user_stats, 0))
{
@@ -2816,7 +3241,8 @@ static int aggregate_user_stats(HASH *all_user_stats, HASH *agg_user_stats)
{
// First entry for this role.
if (!(agg_user= (USER_STATS*) my_malloc(sizeof(USER_STATS),
- MYF(MY_WME | MY_ZEROFILL))))
+ MYF(MY_WME | MY_ZEROFILL|
+ MY_THREAD_SPECIFIC))))
{
sql_print_error("Malloc in aggregate_user_stats failed");
DBUG_RETURN(1);
@@ -3044,6 +3470,100 @@ int fill_schema_table_stats(THD *thd, TABLE_LIST *tables, COND *cond)
DBUG_RETURN(0);
}
+/* Remove all indexes for a given table from global index statistics */
+
+static
+int del_global_index_stats_for_table(THD *thd, uchar* cache_key, uint cache_key_length)
+{
+ int res = 0;
+ DBUG_ENTER("del_global_index_stats_for_table");
+
+ mysql_mutex_lock(&LOCK_global_index_stats);
+
+ for (uint i= 0; i < global_index_stats.records;)
+ {
+ INDEX_STATS *index_stats =
+ (INDEX_STATS*) my_hash_element(&global_index_stats, i);
+
+ /* We search correct db\0table_name\0 string */
+ if (index_stats &&
+ index_stats->index_name_length >= cache_key_length &&
+ !memcmp(index_stats->index, cache_key, cache_key_length))
+ {
+ res= my_hash_delete(&global_index_stats, (uchar*)index_stats);
+ /*
+ In our HASH implementation on deletion one elements
+ is moved into a place where a deleted element was,
+ and the last element is moved into the empty space.
+ Thus we need to re-examine the current element, but
+ we don't have to restart the search from the beginning.
+ */
+ }
+ else
+ i++;
+ }
+
+ mysql_mutex_unlock(&LOCK_global_index_stats);
+ DBUG_RETURN(res);
+}
+
+/* Remove a table from global table statistics */
+
+int del_global_table_stat(THD *thd, LEX_STRING *db, LEX_STRING *table)
+{
+ TABLE_STATS *table_stats;
+ int res = 0;
+ uchar *cache_key;
+ uint cache_key_length;
+ DBUG_ENTER("del_global_table_stat");
+
+ cache_key_length= db->length + 1 + table->length + 1;
+
+ if(!(cache_key= (uchar *)my_malloc(cache_key_length,
+ MYF(MY_WME | MY_ZEROFILL))))
+ {
+ /* Out of memory error already given */
+ res = 1;
+ goto end;
+ }
+
+ memcpy(cache_key, db->str, db->length);
+ memcpy(cache_key + db->length + 1, table->str, table->length);
+
+ res= del_global_index_stats_for_table(thd, cache_key, cache_key_length);
+
+ mysql_mutex_lock(&LOCK_global_table_stats);
+
+ if((table_stats= (TABLE_STATS*) my_hash_search(&global_table_stats,
+ cache_key,
+ cache_key_length)))
+ res= my_hash_delete(&global_table_stats, (uchar*)table_stats);
+
+ my_free(cache_key);
+ mysql_mutex_unlock(&LOCK_global_table_stats);
+
+end:
+ DBUG_RETURN(res);
+}
+
+/* Remove a index from global index statistics */
+
+int del_global_index_stat(THD *thd, TABLE* table, KEY* key_info)
+{
+ INDEX_STATS *index_stats;
+ uint key_length= table->s->table_cache_key.length + key_info->name_length + 1;
+ int res = 0;
+ DBUG_ENTER("del_global_index_stat");
+ mysql_mutex_lock(&LOCK_global_index_stats);
+
+ if((index_stats= (INDEX_STATS*) my_hash_search(&global_index_stats,
+ key_info->cache_name,
+ key_length)))
+ res= my_hash_delete(&global_index_stats, (uchar*)index_stats);
+
+ mysql_mutex_unlock(&LOCK_global_index_stats);
+ DBUG_RETURN(res);
+}
/* Fill information schema table with index statistics */
@@ -3124,41 +3644,6 @@ void calc_sum_of_all_status(STATUS_VAR *to)
/* This is only used internally, but we need it here as a forward reference */
extern ST_SCHEMA_TABLE schema_tables[];
-/**
- Condition pushdown used for INFORMATION_SCHEMA / SHOW queries.
- This structure is to implement an optimization when
- accessing data dictionary data in the INFORMATION_SCHEMA
- or SHOW commands.
- When the query contain a TABLE_SCHEMA or TABLE_NAME clause,
- narrow the search for data based on the constraints given.
-*/
-typedef struct st_lookup_field_values
-{
- /**
- Value of a TABLE_SCHEMA clause.
- Note that this value length may exceed @c NAME_LEN.
- @sa wild_db_value
- */
- LEX_STRING db_value;
- /**
- Value of a TABLE_NAME clause.
- Note that this value length may exceed @c NAME_LEN.
- @sa wild_table_value
- */
- LEX_STRING table_value;
- /**
- True when @c db_value is a LIKE clause,
- false when @c db_value is an '=' clause.
- */
- bool wild_db_value;
- /**
- True when @c table_value is a LIKE clause,
- false when @c table_value is an '=' clause.
- */
- bool wild_table_value;
-} LOOKUP_FIELD_VALUES;
-
-
/*
Store record to I_S table, convert HEAP table
to MyISAM if necessary
@@ -3266,8 +3751,8 @@ bool get_lookup_value(THD *thd, Item_func *item_func,
(uchar *) item_field->field_name,
strlen(item_field->field_name), 0))
{
- thd->make_lex_string(&lookup_field_vals->db_value, tmp_str->ptr(),
- tmp_str->length(), FALSE);
+ thd->make_lex_string(&lookup_field_vals->db_value,
+ tmp_str->ptr(), tmp_str->length());
}
/* Lookup value is table name */
else if (!cs->coll->strnncollsp(cs, (uchar *) field_name2,
@@ -3275,8 +3760,8 @@ bool get_lookup_value(THD *thd, Item_func *item_func,
(uchar *) item_field->field_name,
strlen(item_field->field_name), 0))
{
- thd->make_lex_string(&lookup_field_vals->table_value, tmp_str->ptr(),
- tmp_str->length(), FALSE);
+ thd->make_lex_string(&lookup_field_vals->table_value,
+ tmp_str->ptr(), tmp_str->length());
}
}
return 0;
@@ -3453,7 +3938,7 @@ bool get_lookup_field_values(THD *thd, COND *cond, TABLE_LIST *tables,
LOOKUP_FIELD_VALUES *lookup_field_values)
{
LEX *lex= thd->lex;
- const char *wild= lex->wild ? lex->wild->ptr() : NullS;
+ String *wild= lex->wild;
bool rc= 0;
bzero((char*) lookup_field_values, sizeof(LOOKUP_FIELD_VALUES));
@@ -3461,8 +3946,8 @@ bool get_lookup_field_values(THD *thd, COND *cond, TABLE_LIST *tables,
case SQLCOM_SHOW_DATABASES:
if (wild)
{
- thd->make_lex_string(&lookup_field_values->db_value,
- wild, strlen(wild), 0);
+ thd->make_lex_string(&lookup_field_values->db_value,
+ wild->ptr(), wild->length());
lookup_field_values->wild_db_value= 1;
}
break;
@@ -3471,14 +3956,25 @@ bool get_lookup_field_values(THD *thd, COND *cond, TABLE_LIST *tables,
case SQLCOM_SHOW_TRIGGERS:
case SQLCOM_SHOW_EVENTS:
thd->make_lex_string(&lookup_field_values->db_value,
- lex->select_lex.db, strlen(lex->select_lex.db), 0);
+ lex->select_lex.db, strlen(lex->select_lex.db));
if (wild)
{
thd->make_lex_string(&lookup_field_values->table_value,
- wild, strlen(wild), 0);
+ wild->ptr(), wild->length());
lookup_field_values->wild_table_value= 1;
}
break;
+ case SQLCOM_SHOW_PLUGINS:
+ if (lex->ident.str)
+ thd->make_lex_string(&lookup_field_values->db_value,
+ lex->ident.str, lex->ident.length);
+ else if (lex->wild)
+ {
+ thd->make_lex_string(&lookup_field_values->db_value,
+ lex->wild->ptr(), lex->wild->length());
+ lookup_field_values->wild_db_value= 1;
+ }
+ break;
default:
/*
The "default" is for queries over I_S.
@@ -3521,23 +4017,15 @@ enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table)
wild wild string
idx_field_vals idx_field_vals->db_name contains db name or
wild string
- with_i_schema returns 1 if we added 'IS' name to list
- otherwise returns 0
RETURN
zero success
non-zero error
*/
-int make_db_list(THD *thd, List<LEX_STRING> *files,
- LOOKUP_FIELD_VALUES *lookup_field_vals,
- bool *with_i_schema)
+int make_db_list(THD *thd, Dynamic_array<LEX_STRING*> *files,
+ LOOKUP_FIELD_VALUES *lookup_field_vals)
{
- LEX_STRING *i_s_name_copy= 0;
- i_s_name_copy= thd->make_lex_string(i_s_name_copy,
- INFORMATION_SCHEMA_NAME.str,
- INFORMATION_SCHEMA_NAME.length, TRUE);
- *with_i_schema= 0;
if (lookup_field_vals->wild_db_value)
{
/*
@@ -3550,12 +4038,11 @@ int make_db_list(THD *thd, List<LEX_STRING> *files,
INFORMATION_SCHEMA_NAME.str,
lookup_field_vals->db_value.str))
{
- *with_i_schema= 1;
- if (files->push_back(i_s_name_copy))
+ if (files->append_val(&INFORMATION_SCHEMA_NAME))
return 1;
}
- return (find_files(thd, files, NullS, mysql_data_home,
- lookup_field_vals->db_value.str, 1) != FIND_FILES_OK);
+ return find_files(thd, files, 0, mysql_data_home,
+ &lookup_field_vals->db_value);
}
@@ -3579,12 +4066,11 @@ int make_db_list(THD *thd, List<LEX_STRING> *files,
if (is_infoschema_db(lookup_field_vals->db_value.str,
lookup_field_vals->db_value.length))
{
- *with_i_schema= 1;
- if (files->push_back(i_s_name_copy))
+ if (files->append_val(&INFORMATION_SCHEMA_NAME))
return 1;
return 0;
}
- if (files->push_back(&lookup_field_vals->db_value))
+ if (files->append_val(&lookup_field_vals->db_value))
return 1;
return 0;
}
@@ -3593,17 +4079,15 @@ int make_db_list(THD *thd, List<LEX_STRING> *files,
Create list of existing databases. It is used in case
of select from information schema table
*/
- if (files->push_back(i_s_name_copy))
+ if (files->append_val(&INFORMATION_SCHEMA_NAME))
return 1;
- *with_i_schema= 1;
- return (find_files(thd, files, NullS,
- mysql_data_home, NullS, 1) != FIND_FILES_OK);
+ return find_files(thd, files, 0, mysql_data_home, &null_lex_str);
}
struct st_add_schema_table
{
- List<LEX_STRING> *files;
+ Dynamic_array<LEX_STRING*> *files;
const char *wild;
};
@@ -3613,7 +4097,7 @@ static my_bool add_schema_table(THD *thd, plugin_ref plugin,
{
LEX_STRING *file_name= 0;
st_add_schema_table *data= (st_add_schema_table *)p_data;
- List<LEX_STRING> *file_list= data->files;
+ Dynamic_array<LEX_STRING*> *file_list= data->files;
const char *wild= data->wild;
ST_SCHEMA_TABLE *schema_table= plugin_data(plugin, ST_SCHEMA_TABLE *);
DBUG_ENTER("add_schema_table");
@@ -3633,16 +4117,16 @@ static my_bool add_schema_table(THD *thd, plugin_ref plugin,
DBUG_RETURN(0);
}
- if ((file_name= thd->make_lex_string(file_name, schema_table->table_name,
- strlen(schema_table->table_name),
- TRUE)) &&
- !file_list->push_back(file_name))
+ if ((file_name= thd->make_lex_string(schema_table->table_name,
+ strlen(schema_table->table_name))) &&
+ !file_list->append(file_name))
DBUG_RETURN(0);
DBUG_RETURN(1);
}
-int schema_tables_add(THD *thd, List<LEX_STRING> *files, const char *wild)
+int schema_tables_add(THD *thd, Dynamic_array<LEX_STRING*> *files,
+ const char *wild)
{
LEX_STRING *file_name= 0;
ST_SCHEMA_TABLE *tmp_schema_table= schema_tables;
@@ -3666,9 +4150,9 @@ int schema_tables_add(THD *thd, List<LEX_STRING> *files, const char *wild)
continue;
}
if ((file_name=
- thd->make_lex_string(file_name, tmp_schema_table->table_name,
- strlen(tmp_schema_table->table_name), TRUE)) &&
- !files->push_back(file_name))
+ thd->make_lex_string(tmp_schema_table->table_name,
+ strlen(tmp_schema_table->table_name))) &&
+ !files->append(file_name))
continue;
DBUG_RETURN(1);
}
@@ -3693,7 +4177,6 @@ int schema_tables_add(THD *thd, List<LEX_STRING> *files, const char *wild)
@param[in] table_names List of table names in database
@param[in] lex pointer to LEX struct
@param[in] lookup_field_vals pointer to LOOKUP_FIELD_VALUE struct
- @param[in] with_i_schema TRUE means that we add I_S tables to list
@param[in] db_name database name
@return Operation status
@@ -3703,9 +4186,9 @@ int schema_tables_add(THD *thd, List<LEX_STRING> *files, const char *wild)
*/
static int
-make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex,
- LOOKUP_FIELD_VALUES *lookup_field_vals,
- bool with_i_schema, LEX_STRING *db_name)
+make_table_name_list(THD *thd, Dynamic_array<LEX_STRING*> *table_names,
+ LEX *lex, LOOKUP_FIELD_VALUES *lookup_field_vals,
+ LEX_STRING *db_name)
{
char path[FN_REFLEN + 1];
build_table_filename(path, sizeof(path) - 1, db_name->str, "", "", 0);
@@ -3720,32 +4203,23 @@ make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex,
*/
return 0;
}
-
- if (with_i_schema)
+ if (db_name == &INFORMATION_SCHEMA_NAME)
{
LEX_STRING *name;
ST_SCHEMA_TABLE *schema_table=
find_schema_table(thd, lookup_field_vals->table_value.str);
if (schema_table && !schema_table->hidden)
{
- if (!(name=
- thd->make_lex_string(NULL, schema_table->table_name,
- strlen(schema_table->table_name), TRUE)) ||
- table_names->push_back(name))
+ if (!(name= thd->make_lex_string(schema_table->table_name,
+ strlen(schema_table->table_name))) ||
+ table_names->append(name))
return 1;
}
}
else
{
- if (table_names->push_back(&lookup_field_vals->table_value))
+ if (table_names->append_val(&lookup_field_vals->table_value))
return 1;
- /*
- Check that table is relevant in current transaction.
- (used for ndb engine, see ndbcluster_find_files(), ha_ndbcluster.cc)
- */
- (void) ha_find_files(thd, db_name->str, path,
- lookup_field_vals->table_value.str, 0,
- table_names);
}
return 0;
}
@@ -3754,12 +4228,12 @@ make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex,
This call will add all matching the wildcards (if specified) IS tables
to the list
*/
- if (with_i_schema)
+ if (db_name == &INFORMATION_SCHEMA_NAME)
return (schema_tables_add(thd, table_names,
lookup_field_vals->table_value.str));
- find_files_result res= find_files(thd, table_names, db_name->str, path,
- lookup_field_vals->table_value.str, 0);
+ find_files_result res= find_files(thd, table_names, db_name, path,
+ &lookup_field_vals->table_value);
if (res != FIND_FILES_OK)
{
/*
@@ -3855,10 +4329,10 @@ fill_schema_table_by_open(THD *thd, bool is_show_fields_or_keys,
These copies are used for make_table_list() while unaltered values
are passed to process_table() functions.
*/
- 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))
+ if (!thd->make_lex_string(&db_name,
+ orig_db_name->str, orig_db_name->length) ||
+ !thd->make_lex_string(&table_name,
+ orig_table_name->str, orig_table_name->length))
goto end;
/*
@@ -3899,12 +4373,13 @@ fill_schema_table_by_open(THD *thd, bool is_show_fields_or_keys,
'only_view_structure()'.
*/
lex->sql_command= SQLCOM_SHOW_FIELDS;
- 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)),
- DT_PREPARE | DT_CREATE);
+ result= (open_temporary_tables(thd, table_list) ||
+ 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)),
+ DT_PREPARE | DT_CREATE));
/*
Restore old value of sql_command back as it is being looked at in
process_table() function.
@@ -3924,13 +4399,15 @@ fill_schema_table_by_open(THD *thd, bool is_show_fields_or_keys,
Again we don't do this for SHOW COLUMNS/KEYS because
of backward compatibility.
*/
- if (!is_show_fields_or_keys && result && thd->is_error() &&
- thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE)
+ if (!is_show_fields_or_keys && result &&
+ (thd->get_stmt_da()->sql_errno() == ER_NO_SUCH_TABLE ||
+ thd->get_stmt_da()->sql_errno() == ER_WRONG_OBJECT))
{
/*
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.
+ with a db name and table, but the table does not exist or
+ there is a view with the same name.
*/
result= false;
thd->clear_error();
@@ -3982,7 +4459,6 @@ end:
@param[in] table TABLE struct for I_S table
@param[in] db_name database name
@param[in] table_name table name
- @param[in] with_i_schema I_S table if TRUE
@return Operation status
@retval 0 success
@@ -3990,38 +4466,29 @@ end:
*/
static int fill_schema_table_names(THD *thd, TABLE_LIST *tables,
- LEX_STRING *db_name, LEX_STRING *table_name,
- bool with_i_schema)
+ LEX_STRING *db_name, LEX_STRING *table_name)
{
TABLE *table= tables->table;
- if (with_i_schema)
+ if (db_name == &INFORMATION_SCHEMA_NAME)
{
table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"),
system_charset_info);
}
else if (tables->table_open_method != SKIP_OPEN_TABLE)
{
- enum legacy_db_type not_used;
- char path[FN_REFLEN + 1];
- (void) build_table_filename(path, sizeof(path) - 1, db_name->str,
- table_name->str, reg_ext, 0);
- switch (dd_frm_type(thd, path, &not_used)) {
- case FRMTYPE_ERROR:
- table->field[3]->store(STRING_WITH_LEN("ERROR"),
- system_charset_info);
- break;
- case FRMTYPE_TABLE:
- table->field[3]->store(STRING_WITH_LEN("BASE TABLE"),
- system_charset_info);
- break;
- case FRMTYPE_VIEW:
- table->field[3]->store(STRING_WITH_LEN("VIEW"),
- system_charset_info);
- break;
- default:
- DBUG_ASSERT(0);
+ CHARSET_INFO *cs= system_charset_info;
+ handlerton *hton;
+ if (ha_table_exists(thd, db_name->str, table_name->str, &hton))
+ {
+ if (hton == view_pseudo_hton)
+ table->field[3]->store(STRING_WITH_LEN("VIEW"), cs);
+ else
+ table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs);
}
- if (thd->is_error() && thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE)
+ else
+ table->field[3]->store(STRING_WITH_LEN("ERROR"), cs);
+
+ if (thd->is_error() && thd->get_stmt_da()->sql_errno() == ER_NO_SUCH_TABLE)
{
thd->clear_error();
return 0;
@@ -4065,7 +4532,7 @@ uint get_table_open_method(TABLE_LIST *tables,
for (ptr=tables->table->field; (field= *ptr) ; ptr++)
{
star_table_open_method=
- min(star_table_open_method,
+ MY_MIN(star_table_open_method,
schema_table->fields_info[field_indx].open_method);
if (bitmap_is_set(tables->table->read_set, field->field_index))
{
@@ -4103,7 +4570,7 @@ uint get_table_open_method(TABLE_LIST *tables,
@retval FALSE No error, if lock was obtained TABLE_LIST::mdl_request::ticket
is set to non-NULL value.
- @retval TRUE Some error occured (probably thread was killed).
+ @retval TRUE Some error occurred (probably thread was killed).
*/
static bool
@@ -4175,10 +4642,6 @@ static int fill_schema_table_from_frm(THD *thd, TABLE_LIST *tables,
TABLE tbl;
TABLE_LIST table_list;
uint res= 0;
- int not_used;
- my_hash_value_type hash_value;
- char key[MAX_DBKEY_LENGTH];
- uint key_length;
char db_name_buff[NAME_LEN + 1], table_name_buff[NAME_LEN + 1];
bzero((char*) &table_list, sizeof(TABLE_LIST));
@@ -4215,7 +4678,7 @@ static int fill_schema_table_from_frm(THD *thd, TABLE_LIST *tables,
if (try_acquire_high_prio_shared_mdl_lock(thd, &table_list, can_deadlock))
{
/*
- Some error occured (most probably we have been killed while
+ Some error occurred (most probably we have been killed while
waiting for conflicting locks to go away), let the caller to
handle the situation.
*/
@@ -4231,7 +4694,7 @@ static int fill_schema_table_from_frm(THD *thd, TABLE_LIST *tables,
*/
DBUG_ASSERT(can_deadlock);
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_WARN_I_S_SKIPPED_TABLE,
ER(ER_WARN_I_S_SKIPPED_TABLE),
table_list.db, table_list.table_name);
@@ -4240,7 +4703,7 @@ static int fill_schema_table_from_frm(THD *thd, TABLE_LIST *tables,
if (schema_table->i_s_requested_object & OPEN_TRIGGER_ONLY)
{
- init_sql_alloc(&tbl.mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
+ init_sql_alloc(&tbl.mem_root, TABLE_ALLOC_BLOCK_SIZE, 0, MYF(0));
if (!Table_triggers_list::check_n_load(thd, db_name->str,
table_name->str, &tbl, 1))
{
@@ -4253,15 +4716,11 @@ static int fill_schema_table_from_frm(THD *thd, TABLE_LIST *tables,
goto end;
}
- key_length= create_table_def_key(thd, key, &table_list, 0);
- hash_value= my_calc_hash(&table_def_cache, (uchar*) key, key_length);
- mysql_mutex_lock(&LOCK_open);
- share= get_table_share(thd, &table_list, key,
- key_length, OPEN_VIEW, &not_used, hash_value);
+ share= tdc_acquire_share_shortlived(thd, &table_list, GTS_TABLE | GTS_VIEW);
if (!share)
{
res= 0;
- goto end_unlock;
+ goto end;
}
if (share->is_view)
@@ -4281,10 +4740,7 @@ static int fill_schema_table_from_frm(THD *thd, TABLE_LIST *tables,
res= 1;
goto end_share;
}
- }
- if (share->is_view)
- {
if (open_new_frm(thd, share, table_name->str,
(uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
HA_GET_INDEX | HA_TRY_READ_ONLY),
@@ -4310,11 +4766,9 @@ static int fill_schema_table_from_frm(THD *thd, TABLE_LIST *tables,
free_root(&tbl.mem_root, MYF(0));
}
-end_share:
- release_table_share(share);
-end_unlock:
- mysql_mutex_unlock(&LOCK_open);
+end_share:
+ tdc_release_share(share);
end:
/*
@@ -4347,20 +4801,20 @@ public:
bool handle_condition(THD *thd,
uint sql_errno,
const char* sqlstate,
- MYSQL_ERROR::enum_warning_level level,
+ Sql_condition::enum_warning_level level,
const char* msg,
- MYSQL_ERROR ** cond_hdl)
+ Sql_condition ** cond_hdl)
{
if (sql_errno == ER_PARSE_ERROR ||
sql_errno == ER_TRG_NO_DEFINER ||
sql_errno == ER_TRG_NO_CREATION_CTX)
return true;
- if (level != MYSQL_ERROR::WARN_LEVEL_ERROR)
+ if (level != Sql_condition::WARN_LEVEL_ERROR)
return false;
- if (!thd->stmt_da->is_error())
- thd->stmt_da->set_error_status(thd, sql_errno, msg, sqlstate);
+ if (!thd->get_stmt_da()->is_error())
+ thd->get_stmt_da()->set_error_status(sql_errno, msg, sqlstate, *cond_hdl);
return true; // handled!
}
};
@@ -4389,14 +4843,12 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
{
LEX *lex= thd->lex;
TABLE *table= tables->table;
+ TABLE_LIST table_acl_check;
SELECT_LEX *lsel= tables->schema_select_lex;
ST_SCHEMA_TABLE *schema_table= tables->schema_table;
LOOKUP_FIELD_VALUES lookup_field_vals;
- LEX_STRING *db_name, *table_name;
- bool with_i_schema;
enum enum_schema_tables schema_table_idx;
- List<LEX_STRING> db_names;
- List_iterator_fast<LEX_STRING> it(db_names);
+ Dynamic_array<LEX_STRING*> db_names;
COND *partial_cond= 0;
int error= 1;
Open_tables_backup open_tables_state_backup;
@@ -4459,9 +4911,9 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
goto err;
}
- DBUG_PRINT("INDEX VALUES",("db_name='%s', table_name='%s'",
- STR_OR_NIL(lookup_field_vals.db_value.str),
- STR_OR_NIL(lookup_field_vals.table_value.str)));
+ DBUG_PRINT("info",("db_name='%s', table_name='%s'",
+ lookup_field_vals.db_value.str,
+ lookup_field_vals.table_value.str));
if (!lookup_field_vals.wild_db_value && !lookup_field_vals.wild_table_value)
{
@@ -4498,11 +4950,13 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
goto err;
}
- if (make_db_list(thd, &db_names, &lookup_field_vals, &with_i_schema))
+ bzero((char*) &table_acl_check, sizeof(table_acl_check));
+
+ if (make_db_list(thd, &db_names, &lookup_field_vals))
goto err;
- it.rewind(); /* To get access to new elements in basis list */
- while ((db_name= it++))
+ for (size_t i=0; i < db_names.elements(); i++)
{
+ LEX_STRING *db_name= db_names.at(i);
DBUG_ASSERT(db_name->length <= NAME_LEN);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (!(check_access(thd, SELECT_ACL, db_name->str,
@@ -4512,19 +4966,31 @@ 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
{
- List<LEX_STRING> table_names;
+ Dynamic_array<LEX_STRING*> table_names;
int res= make_table_name_list(thd, &table_names, lex,
- &lookup_field_vals,
- with_i_schema, db_name);
+ &lookup_field_vals, db_name);
if (res == 2) /* Not fatal error, continue */
continue;
if (res)
goto err;
- List_iterator_fast<LEX_STRING> it_files(table_names);
- while ((table_name= it_files++))
+ for (size_t i=0; i < table_names.elements(); i++)
{
+ LEX_STRING *table_name= table_names.at(i);
DBUG_ASSERT(table_name->length <= NAME_LEN);
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (!(thd->col_access & TABLE_ACLS))
+ {
+ table_acl_check.db= db_name->str;
+ table_acl_check.db_length= db_name->length;
+ table_acl_check.table_name= table_name->str;
+ table_acl_check.table_name_length= table_name->length;
+ table_acl_check.grant.privilege= thd->col_access;
+ if (check_grant(thd, TABLE_ACLS, &table_acl_check, TRUE, 1, TRUE))
+ continue;
+ }
+#endif
restore_record(table, s->default_values);
table->field[schema_table->idx_field1]->
store(db_name->str, db_name->length, system_charset_info);
@@ -4552,18 +5018,18 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
/* SHOW TABLE NAMES command */
if (schema_table_idx == SCH_TABLE_NAMES)
{
- if (fill_schema_table_names(thd, tables, db_name,
- table_name, with_i_schema))
+ if (fill_schema_table_names(thd, tables, db_name, table_name))
continue;
}
- else if (schema_table_idx == SCH_TRIGGERS && with_i_schema)
+ else if (schema_table_idx == SCH_TRIGGERS &&
+ db_name == &INFORMATION_SCHEMA_NAME)
{
continue;
}
else
{
if (!(table_open_method & ~OPEN_FRM_ONLY) &&
- !with_i_schema)
+ db_name != &INFORMATION_SCHEMA_NAME)
{
if (!fill_schema_table_from_frm(thd, tables, schema_table,
db_name, table_name,
@@ -4583,11 +5049,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
}
}
}
- /*
- If we have information schema its always the first table and only
- the first table. Reset for other tables.
- */
- with_i_schema= 0;
}
}
@@ -4619,9 +5080,7 @@ int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond)
*/
LOOKUP_FIELD_VALUES lookup_field_vals;
- List<LEX_STRING> db_names;
- LEX_STRING *db_name;
- bool with_i_schema;
+ Dynamic_array<LEX_STRING*> db_names;
HA_CREATE_INFO create;
TABLE *table= tables->table;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -4634,15 +5093,14 @@ int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond)
DBUG_PRINT("INDEX VALUES",("db_name: %s table_name: %s",
lookup_field_vals.db_value.str,
lookup_field_vals.table_value.str));
- if (make_db_list(thd, &db_names, &lookup_field_vals,
- &with_i_schema))
+ if (make_db_list(thd, &db_names, &lookup_field_vals))
DBUG_RETURN(1);
/*
If we have lookup db value we should check that the database exists
*/
if(lookup_field_vals.db_value.str && !lookup_field_vals.wild_db_value &&
- !with_i_schema)
+ db_names.at(0) != &INFORMATION_SCHEMA_NAME)
{
char path[FN_REFLEN+16];
uint path_len;
@@ -4656,22 +5114,23 @@ int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond)
DBUG_RETURN(0);
}
- List_iterator_fast<LEX_STRING> it(db_names);
- while ((db_name=it++))
+ for (size_t i=0; i < db_names.elements(); i++)
{
+ LEX_STRING *db_name= db_names.at(i);
DBUG_ASSERT(db_name->length <= NAME_LEN);
- if (with_i_schema) // information schema name is always first in list
+ if (db_name == &INFORMATION_SCHEMA_NAME)
{
if (store_schema_shemata(thd, table, db_name,
system_charset_info))
DBUG_RETURN(1);
- with_i_schema= 0;
continue;
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
- acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0) ||
- !check_grant_db(thd, db_name->str))
+ acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, false) ||
+ (sctx->priv_role[0] ?
+ acl_get("", "", sctx->priv_role, db_name->str, false) : 0) ||
+ !check_grant_db(thd, db_name->str))
#endif
{
load_db_opt_by_name(thd, db_name->str, &create);
@@ -4720,7 +5179,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
}
else
{
- char option_buff[350];
+ char option_buff[512];
String str(option_buff,sizeof(option_buff), system_charset_info);
TABLE *show_table= tables->table;
TABLE_SHARE *share= show_table->s;
@@ -4750,7 +5209,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
if (share->db_type() == partition_hton &&
share->partition_info_str_len)
{
- tmp_db_type= share->default_part_db_type;
+ tmp_db_type= plugin_hton(share->default_part_plugin);
is_partitioned= TRUE;
}
#endif
@@ -4785,6 +5244,23 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
if (share->db_create_options & HA_OPTION_NO_PACK_KEYS)
str.qs_append(STRING_WITH_LEN(" pack_keys=0"));
+ if (share->db_create_options & HA_OPTION_STATS_PERSISTENT)
+ str.qs_append(STRING_WITH_LEN(" stats_persistent=1"));
+
+ if (share->db_create_options & HA_OPTION_NO_STATS_PERSISTENT)
+ str.qs_append(STRING_WITH_LEN(" stats_persistent=0"));
+
+ if (share->stats_auto_recalc == HA_STATS_AUTO_RECALC_ON)
+ str.qs_append(STRING_WITH_LEN(" stats_auto_recalc=1"));
+ else if (share->stats_auto_recalc == HA_STATS_AUTO_RECALC_OFF)
+ str.qs_append(STRING_WITH_LEN(" stats_auto_recalc=0"));
+
+ if (share->stats_sample_pages != 0)
+ {
+ str.qs_append(STRING_WITH_LEN(" stats_sample_pages="));
+ str.qs_append(share->stats_sample_pages);
+ }
+
/* 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"));
@@ -4820,7 +5296,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
str.qs_append(STRING_WITH_LEN(" transactional="));
str.qs_append(ha_choice_values[(uint) share->transactional]);
}
- append_create_options(thd, &str, share->option_list);
+ append_create_options(thd, &str, share->option_list, false, 0);
if (str.length())
table->field[19]->store(str.ptr()+1, str.length()-1, cs);
@@ -4842,7 +5318,10 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
HA_STATUS_TIME |
HA_STATUS_VARIABLE_EXTRA |
HA_STATUS_AUTO)) != 0)
+ {
+ file->print_error(info_error, MYF(0));
goto err;
+ }
enum row_type row_type = file->get_row_type();
switch (row_type) {
@@ -4932,15 +5411,12 @@ err:
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() : "";
+ const char *error= thd->get_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();
- }
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
+ thd->get_stmt_da()->sql_errno(), error);
+ thd->clear_error();
}
DBUG_RETURN(schema_table_store_record(thd, table));
@@ -5089,7 +5565,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
const char *wild= lex->wild ? lex->wild->ptr() : NullS;
CHARSET_INFO *cs= system_charset_info;
TABLE *show_table;
- Field **ptr, *field, *timestamp_field;
+ Field **ptr, *field;
int count;
DBUG_ENTER("get_schema_column_record");
@@ -5101,9 +5577,9 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
I.e. we are in SELECT FROM INFORMATION_SCHEMA.COLUMS
rather than in SHOW COLUMNS
*/
- if (thd->is_error())
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->stmt_da->sql_errno(), thd->stmt_da->message());
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
+ thd->get_stmt_da()->sql_errno(),
+ thd->get_stmt_da()->message());
thd->clear_error();
res= 0;
}
@@ -5113,7 +5589,6 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
show_table= tables->table;
count= 0;
ptr= show_table->field;
- timestamp_field= show_table->timestamp_field;
show_table->use_all_columns(); // Required for default
restore_record(show_table, s->default_values);
@@ -5136,7 +5611,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
#ifndef NO_EMBEDDED_ACCESS_CHECKS
uint col_access;
check_access(thd,SELECT_ACL, db_name->str,
- &tables->grant.privilege, 0, 0, test(tables->schema_table));
+ &tables->grant.privilege, 0, 0, MY_TEST(tables->schema_table));
col_access= get_column_grant(thd, &tables->grant,
db_name->str, table_name->str,
field->field_name) & COL_ACLS;
@@ -5161,7 +5636,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
cs);
table->field[4]->store((longlong) count, TRUE);
- if (get_field_default_value(thd, timestamp_field, field, &type, 0))
+ if (get_field_default_value(thd, field, &type, 0))
{
table->field[5]->store(type.ptr(), type.length(), cs);
table->field[5]->set_notnull();
@@ -5178,10 +5653,8 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
if (field->unireg_check == Field::NEXT_NUMBER)
table->field[17]->store(STRING_WITH_LEN("auto_increment"), cs);
- if (timestamp_field == field &&
- field->unireg_check != Field::TIMESTAMP_DN_FIELD)
- table->field[17]->store(STRING_WITH_LEN("on update CURRENT_TIMESTAMP"),
- cs);
+ if (print_on_update_clause(field, &type, true))
+ table->field[17]->store(type.ptr(), type.length(), cs);
if (field->vcol_info)
{
if (field->stored_in_db)
@@ -5234,7 +5707,7 @@ static my_bool iter_schema_engines(THD *thd, plugin_ref plugin,
void *ptable)
{
TABLE *table= (TABLE *) ptable;
- handlerton *hton= plugin_data(plugin, handlerton *);
+ handlerton *hton= plugin_hton(plugin);
const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
CHARSET_INFO *scs= system_charset_info;
handlerton *default_type= ha_default_handlerton(thd);
@@ -5277,13 +5750,13 @@ static my_bool iter_schema_engines(THD *thd, plugin_ref plugin,
table->field[1]->store(option_name, strlen(option_name), scs);
table->field[2]->store(plugin_decl(plugin)->descr,
strlen(plugin_decl(plugin)->descr), scs);
- tmp= &yesno[test(hton->commit)];
+ tmp= &yesno[MY_TEST(hton->commit)];
table->field[3]->store(tmp->str, tmp->length, scs);
table->field[3]->set_notnull();
- tmp= &yesno[test(hton->prepare)];
+ tmp= &yesno[MY_TEST(hton->prepare)];
table->field[4]->store(tmp->str, tmp->length, scs);
table->field[4]->set_notnull();
- tmp= &yesno[test(hton->savepoint_set)];
+ tmp= &yesno[MY_TEST(hton->savepoint_set)];
table->field[5]->store(tmp->str, tmp->length, scs);
table->field[5]->set_notnull();
@@ -5503,16 +5976,16 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
for (uint i= 0 ; i < params ; i++)
{
const char *tmp_buff;
- sp_variable_t *spvar= spcont->find_variable(i);
+ sp_variable *spvar= spcont->find_variable(i);
field_def= &spvar->field_def;
switch (spvar->mode) {
- case sp_param_in:
+ case sp_variable::MODE_IN:
tmp_buff= "IN";
break;
- case sp_param_out:
+ case sp_variable::MODE_OUT:
tmp_buff= "OUT";
break;
- case sp_param_inout:
+ case sp_variable::MODE_INOUT:
tmp_buff= "INOUT";
break;
default:
@@ -5782,8 +6255,9 @@ static int get_schema_stat_record(THD *thd, TABLE_LIST *tables,
rather than in SHOW KEYS
*/
if (thd->is_error())
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->stmt_da->sql_errno(), thd->stmt_da->message());
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
+ thd->get_stmt_da()->sql_errno(),
+ thd->get_stmt_da()->message());
thd->clear_error();
res= 0;
}
@@ -5794,14 +6268,17 @@ static int get_schema_stat_record(THD *thd, TABLE_LIST *tables,
TABLE *show_table= tables->table;
KEY *key_info=show_table->s->key_info;
if (show_table->file)
+ {
show_table->file->info(HA_STATUS_VARIABLE |
HA_STATUS_NO_LOCK |
HA_STATUS_TIME);
+ set_statistics_for_table(thd, show_table);
+ }
for (uint i=0 ; i < show_table->s->keys ; i++,key_info++)
{
KEY_PART_INFO *key_part= key_info->key_part;
const char *str;
- for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
+ for (uint j=0 ; j < key_info->user_defined_key_parts ; j++,key_part++)
{
restore_record(table, s->default_values);
table->field[0]->store(STRING_WITH_LEN("def"), cs);
@@ -5827,8 +6304,8 @@ static int get_schema_stat_record(THD *thd, TABLE_LIST *tables,
KEY *key=show_table->key_info+i;
if (key->rec_per_key[j])
{
- ha_rows records=(show_table->file->stats.records /
- key->rec_per_key[j]);
+ ha_rows records= (ha_rows) ((double) show_table->stat_records() /
+ key->actual_rec_per_key(j));
table->field[9]->store((longlong) records, TRUE);
table->field[9]->set_notnull();
}
@@ -5852,7 +6329,7 @@ static int get_schema_stat_record(THD *thd, TABLE_LIST *tables,
else
table->field[14]->store("", 0, cs);
table->field[14]->set_notnull();
- DBUG_ASSERT(test(key_info->flags & HA_USES_COMMENT) ==
+ DBUG_ASSERT(MY_TEST(key_info->flags & HA_USES_COMMENT) ==
(key_info->comment.length > 0));
if (key_info->flags & HA_USES_COMMENT)
table->field[15]->store(key_info->comment.str,
@@ -5964,7 +6441,7 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables,
*/
while ((item= it++))
{
- if ((field= item->filed_for_view_update()) && field->field &&
+ if ((field= item->field_for_view_update()) && field->field &&
!field->field->table->pos_in_table_list->schema_table)
{
updatable_view= 1;
@@ -6001,8 +6478,9 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables,
if (schema_table_store_record(thd, table))
DBUG_RETURN(1);
if (res && thd->is_error())
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->stmt_da->sql_errno(), thd->stmt_da->message());
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
+ thd->get_stmt_da()->sql_errno(),
+ thd->get_stmt_da()->message());
}
if (res)
thd->clear_error();
@@ -6035,8 +6513,9 @@ static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables,
if (res)
{
if (thd->is_error())
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->stmt_da->sql_errno(), thd->stmt_da->message());
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
+ thd->get_stmt_da()->sql_errno(),
+ thd->get_stmt_da()->message());
thd->clear_error();
DBUG_RETURN(0);
}
@@ -6141,8 +6620,9 @@ static int get_schema_triggers_record(THD *thd, TABLE_LIST *tables,
if (res)
{
if (thd->is_error())
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->stmt_da->sql_errno(), thd->stmt_da->message());
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
+ thd->get_stmt_da()->sql_errno(),
+ thd->get_stmt_da()->message());
thd->clear_error();
DBUG_RETURN(0);
}
@@ -6222,8 +6702,9 @@ static int get_schema_key_column_usage_record(THD *thd,
if (res)
{
if (thd->is_error())
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->stmt_da->sql_errno(), thd->stmt_da->message());
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
+ thd->get_stmt_da()->sql_errno(),
+ thd->get_stmt_da()->message());
thd->clear_error();
DBUG_RETURN(0);
}
@@ -6242,7 +6723,7 @@ static int get_schema_key_column_usage_record(THD *thd,
continue;
uint f_idx= 0;
KEY_PART_INFO *key_part= key_info->key_part;
- for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
+ for (uint j=0 ; j < key_info->user_defined_key_parts ; j++,key_part++)
{
if (key_part->field)
{
@@ -6437,7 +6918,7 @@ 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);
else
@@ -6512,8 +6993,9 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables,
if (res)
{
if (thd->is_error())
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->stmt_da->sql_errno(), thd->stmt_da->message());
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
+ thd->get_stmt_da()->sql_errno(),
+ thd->get_stmt_da()->message());
thd->clear_error();
DBUG_RETURN(0);
}
@@ -6764,7 +7246,7 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
if (et.load_from_row(thd, event_table))
{
- my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), event_table->alias.c_ptr());
+ my_error(ER_CANNOT_LOAD_FROM_TABLE_V2, MYF(0), "mysql", "event");
DBUG_RETURN(1);
}
@@ -7014,14 +7496,20 @@ int fill_status(THD *thd, TABLE_LIST *tables, COND *cond)
if (partial_cond)
partial_cond->val_int();
- mysql_mutex_lock(&LOCK_status);
if (option_type == OPT_GLOBAL)
+ {
+ /* We only hold LOCK_status for summary status vars */
+ mysql_mutex_lock(&LOCK_status);
calc_sum_of_all_status(&tmp);
+ mysql_mutex_unlock(&LOCK_status);
+ }
+
+ mysql_mutex_lock(&LOCK_show_status);
res= show_status_array(thd, wild,
(SHOW_VAR *)all_status_vars.buffer,
option_type, tmp1, "", tables->table,
upper_case_names, partial_cond);
- mysql_mutex_unlock(&LOCK_status);
+ mysql_mutex_unlock(&LOCK_show_status);
DBUG_RETURN(res);
}
@@ -7050,13 +7538,15 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables,
LEX_STRING *db_name, LEX_STRING *table_name)
{
CHARSET_INFO *cs= system_charset_info;
+ LEX_CSTRING *s;
DBUG_ENTER("get_referential_constraints_record");
if (res)
{
if (thd->is_error())
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- thd->stmt_da->sql_errno(), thd->stmt_da->message());
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
+ thd->get_stmt_da()->sql_errno(),
+ thd->get_stmt_da()->message());
thd->clear_error();
DBUG_RETURN(0);
}
@@ -7093,10 +7583,10 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables,
else
table->field[5]->set_null();
table->field[6]->store(STRING_WITH_LEN("NONE"), cs);
- table->field[7]->store(f_key_info->update_method->str,
- f_key_info->update_method->length, cs);
- table->field[8]->store(f_key_info->delete_method->str,
- f_key_info->delete_method->length, cs);
+ s= fk_option_name(f_key_info->update_method);
+ table->field[7]->store(s->str, s->length, cs);
+ s= fk_option_name(f_key_info->delete_method);
+ table->field[8]->store(s->str, s->length, cs);
if (schema_table_store_record(thd, table))
DBUG_RETURN(1);
}
@@ -7399,7 +7889,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
DBUG_RETURN(0);
my_bitmap_map* bitmaps=
(my_bitmap_map*) thd->alloc(bitmap_buffer_size(field_count));
- bitmap_init(&table->def_read_set, (my_bitmap_map*) bitmaps, field_count,
+ my_bitmap_init(&table->def_read_set, (my_bitmap_map*) bitmaps, field_count,
FALSE);
table->read_set= &table->def_read_set;
bitmap_clear_all(table->read_set);
@@ -7697,16 +8187,22 @@ int make_schema_select(THD *thd, SELECT_LEX *sel,
We have to make non const db_name & table_name
because of lower_case_table_names
*/
- thd->make_lex_string(&db, INFORMATION_SCHEMA_NAME.str,
- INFORMATION_SCHEMA_NAME.length, 0);
- thd->make_lex_string(&table, schema_table->table_name,
- strlen(schema_table->table_name), 0);
- if (schema_table->old_format(thd, schema_table) || /* Handle old syntax */
- !sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0),
+ if (!thd->make_lex_string(&db, INFORMATION_SCHEMA_NAME.str,
+ INFORMATION_SCHEMA_NAME.length))
+ DBUG_RETURN(1);
+
+ if (!thd->make_lex_string(&table, schema_table->table_name,
+ strlen(schema_table->table_name)))
+ DBUG_RETURN(1);
+
+ if (schema_table->old_format(thd, schema_table))
+
+ DBUG_RETURN(1);
+
+ if (!sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0),
0, 0, TL_READ, MDL_SHARED_READ))
- {
DBUG_RETURN(1);
- }
+
DBUG_RETURN(0);
}
@@ -7730,12 +8226,13 @@ bool get_schema_tables_result(JOIN *join,
THD *thd= join->thd;
LEX *lex= thd->lex;
bool result= 0;
- const char *old_proc_info;
+ PSI_stage_info org_stage;
DBUG_ENTER("get_schema_tables_result");
Warnings_only_error_handler err_handler;
thd->push_internal_handler(&err_handler);
- old_proc_info= thd_proc_info(thd, "Filling schema table");
+ thd->enter_stage(&stage_filling_schema_table, &org_stage, __func__, __FILE__,
+ __LINE__);
JOIN_TAB *tab;
for (tab= first_linear_tab(join, WITHOUT_BUSH_ROOTS, WITH_CONST_TABLES);
@@ -7796,9 +8293,22 @@ bool get_schema_tables_result(JOIN *join,
else
table_list->table->file->stats.records= 0;
+
+ Item *cond= tab->select_cond;
+ if (tab->cache_select && tab->cache_select->cond)
+ {
+ /*
+ If join buffering is used, we should use the condition that is
+ attached to the join cache. Cache condition has a part of WHERE that
+ can be checked when we're populating this table.
+ join_tab->select_cond is of no interest, because it only has
+ conditions that depend on both this table and previous tables in the
+ join order.
+ */
+ cond= tab->cache_select->cond;
+ }
- if (table_list->schema_table->fill_table(thd, table_list,
- tab->select_cond))
+ if (table_list->schema_table->fill_table(thd, table_list, cond))
{
result= 1;
join->error= 1;
@@ -7824,15 +8334,15 @@ bool get_schema_tables_result(JOIN *join,
It also means that an audit plugin cannot process the error correctly
either. See also thd->clear_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());
+ thd->get_stmt_da()->push_warning(thd,
+ thd->get_stmt_da()->sql_errno(),
+ thd->get_stmt_da()->get_sqlstate(),
+ Sql_condition::WARN_LEVEL_ERROR,
+ thd->get_stmt_da()->message());
}
else if (result)
my_error(ER_UNKNOWN_ERROR, MYF(0));
- thd_proc_info(thd, old_proc_info);
+ THD_STAGE_INFO(thd, org_stage);
DBUG_RETURN(result);
}
@@ -7847,7 +8357,7 @@ static my_bool run_hton_fill_schema_table(THD *thd, plugin_ref plugin,
{
struct run_hton_fill_schema_table_args *args=
(run_hton_fill_schema_table_args *) arg;
- handlerton *hton= plugin_data(plugin, handlerton *);
+ handlerton *hton= plugin_hton(plugin);
if (hton->fill_is_table && hton->state == SHOW_OPTION_YES)
hton->fill_is_table(hton, thd, args->tables, args->cond,
get_schema_table_idx(args->tables->schema_table));
@@ -8073,6 +8583,22 @@ ST_FIELD_INFO collation_fields_info[]=
};
+ST_FIELD_INFO applicable_roles_fields_info[]=
+{
+ {"GRANTEE", USERNAME_WITH_HOST_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
+ {"ROLE_NAME", USERNAME_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
+ {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+};
+
+
+ST_FIELD_INFO enabled_roles_fields_info[]=
+{
+ {"ROLE_NAME", USERNAME_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, SKIP_OPEN_TABLE},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+};
+
+
ST_FIELD_INFO engines_fields_info[]=
{
{"ENGINE", 64, MYSQL_TYPE_STRING, 0, 0, "Engine", SKIP_OPEN_TABLE},
@@ -8226,7 +8752,7 @@ ST_FIELD_INFO view_fields_info[]=
ST_FIELD_INFO user_privileges_fields_info[]=
{
- {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
+ {"GRANTEE", USERNAME_WITH_HOST_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
{"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
{"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
{"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
@@ -8236,7 +8762,7 @@ ST_FIELD_INFO user_privileges_fields_info[]=
ST_FIELD_INFO schema_privileges_fields_info[]=
{
- {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
+ {"GRANTEE", USERNAME_WITH_HOST_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
{"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
{"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
{"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
@@ -8247,7 +8773,7 @@ ST_FIELD_INFO schema_privileges_fields_info[]=
ST_FIELD_INFO table_privileges_fields_info[]=
{
- {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
+ {"GRANTEE", USERNAME_WITH_HOST_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
{"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
{"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
{"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
@@ -8259,7 +8785,7 @@ ST_FIELD_INFO table_privileges_fields_info[]=
ST_FIELD_INFO column_privileges_fields_info[]=
{
- {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
+ {"GRANTEE", USERNAME_WITH_HOST_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
{"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
{"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
{"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
@@ -8441,6 +8967,9 @@ ST_FIELD_INFO processlist_fields_info[]=
{"MAX_STAGE", 2, MYSQL_TYPE_TINY, 0, 0, "Max_stage", SKIP_OPEN_TABLE},
{"PROGRESS", 703, MYSQL_TYPE_DECIMAL, 0, 0, "Progress",
SKIP_OPEN_TABLE},
+ {"MEMORY_USED", 7, MYSQL_TYPE_LONG, 0, 0, "Memory_used", SKIP_OPEN_TABLE},
+ {"EXAMINED_ROWS", 7, MYSQL_TYPE_LONG, 0, 0, "Examined_rows", SKIP_OPEN_TABLE},
+ {"QUERY_ID", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, SKIP_OPEN_TABLE},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
};
@@ -8450,7 +8979,7 @@ ST_FIELD_INFO plugin_fields_info[]=
{"PLUGIN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name",
SKIP_OPEN_TABLE},
{"PLUGIN_VERSION", 20, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"PLUGIN_STATUS", 10, MYSQL_TYPE_STRING, 0, 0, "Status", SKIP_OPEN_TABLE},
+ {"PLUGIN_STATUS", 16, MYSQL_TYPE_STRING, 0, 0, "Status", SKIP_OPEN_TABLE},
{"PLUGIN_TYPE", 80, MYSQL_TYPE_STRING, 0, 0, "Type", SKIP_OPEN_TABLE},
{"PLUGIN_TYPE_VERSION", 20, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
{"PLUGIN_LIBRARY", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, "Library",
@@ -8630,6 +9159,32 @@ ST_FIELD_INFO keycache_fields_info[]=
};
+ST_FIELD_INFO show_explain_fields_info[]=
+{
+ /* field_name, length, type, value, field_flags, old_name*/
+ {"id", 3, MYSQL_TYPE_LONGLONG, 0 /*value*/, MY_I_S_MAYBE_NULL, "id",
+ SKIP_OPEN_TABLE},
+ {"select_type", 19, MYSQL_TYPE_STRING, 0 /*value*/, 0, "select_type",
+ SKIP_OPEN_TABLE},
+ {"table", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0 /*value*/, MY_I_S_MAYBE_NULL,
+ "table", SKIP_OPEN_TABLE},
+ {"type", 15, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, "type", SKIP_OPEN_TABLE},
+ {"possible_keys", NAME_CHAR_LEN*MAX_KEY, MYSQL_TYPE_STRING, 0/*value*/,
+ MY_I_S_MAYBE_NULL, "possible_keys", SKIP_OPEN_TABLE},
+ {"key", NAME_CHAR_LEN*MAX_KEY, MYSQL_TYPE_STRING, 0/*value*/,
+ MY_I_S_MAYBE_NULL, "key", SKIP_OPEN_TABLE},
+ {"key_len", NAME_CHAR_LEN*MAX_KEY, MYSQL_TYPE_STRING, 0/*value*/,
+ MY_I_S_MAYBE_NULL, "key_len", SKIP_OPEN_TABLE},
+ {"ref", NAME_CHAR_LEN*MAX_REF_PARTS, MYSQL_TYPE_STRING, 0/*value*/,
+ MY_I_S_MAYBE_NULL, "ref", SKIP_OPEN_TABLE},
+ {"rows", 10, MYSQL_TYPE_LONGLONG, 0/*value*/, MY_I_S_MAYBE_NULL, "rows",
+ SKIP_OPEN_TABLE},
+ {"Extra", 255, MYSQL_TYPE_STRING, 0/*value*/, 0 /*flags*/, "Extra",
+ SKIP_OPEN_TABLE},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+};
+
+
/*
Description of ST_FIELD_INFO in table.h
@@ -8639,6 +9194,10 @@ ST_FIELD_INFO keycache_fields_info[]=
ST_SCHEMA_TABLE schema_tables[]=
{
+ {"ALL_PLUGINS", plugin_fields_info, create_schema_table,
+ fill_all_plugins, make_old_format, 0, 5, -1, 0, 0},
+ {"APPLICABLE_ROLES", applicable_roles_fields_info, create_schema_table,
+ fill_schema_applicable_roles, 0, 0, -1, -1, 0, 0},
{"CHARACTER_SETS", charsets_fields_info, create_schema_table,
fill_schema_charsets, make_character_sets_old_format, 0, -1, -1, 0, 0},
{"CLIENT_STATISTICS", client_stats_fields_info, create_schema_table,
@@ -8652,6 +9211,8 @@ ST_SCHEMA_TABLE schema_tables[]=
OPTIMIZE_I_S_TABLE|OPEN_VIEW_FULL},
{"COLUMN_PRIVILEGES", column_privileges_fields_info, create_schema_table,
fill_schema_column_privileges, 0, 0, -1, -1, 0, 0},
+ {"ENABLED_ROLES", enabled_roles_fields_info, create_schema_table,
+ fill_schema_enabled_roles, 0, 0, -1, -1, 0, 0},
{"ENGINES", engines_fields_info, create_schema_table,
fill_schema_engines, make_old_format, 0, -1, -1, 0, 0},
#ifdef HAVE_EVENT_SCHEDULER
@@ -8661,6 +9222,8 @@ ST_SCHEMA_TABLE schema_tables[]=
{"EVENTS", events_fields_info, create_schema_table,
0, make_old_format, 0, -1, -1, 0, 0},
#endif
+ {"EXPLAIN", show_explain_fields_info, create_schema_table, fill_show_explain,
+ make_old_format, 0, -1, -1, TRUE /*hidden*/ , 0},
{"FILES", files_fields_info, create_schema_table,
hton_fill_schema_table, 0, 0, -1, -1, 0, 0},
{"GLOBAL_STATUS", variables_fields_info, create_schema_table,
@@ -8736,18 +9299,13 @@ ST_SCHEMA_TABLE schema_tables[]=
};
-#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-template class List_iterator_fast<char>;
-template class List<char>;
-#endif
-
int initialize_schema_table(st_plugin_int *plugin)
{
ST_SCHEMA_TABLE *schema_table;
DBUG_ENTER("initialize_schema_table");
if (!(schema_table= (ST_SCHEMA_TABLE *)my_malloc(sizeof(ST_SCHEMA_TABLE),
- MYF(MY_WME | MY_ZEROFILL))))
+ MYF(MY_WME | MY_ZEROFILL))))
DBUG_RETURN(1);
/* Historical Requirement */
plugin->data= schema_table; // shortcut for the future
@@ -8870,7 +9428,7 @@ static bool show_create_trigger_impl(THD *thd,
Item_empty_string *stmt_fld=
new Item_empty_string("SQL Original Statement",
- max(trg_sql_original_stmt.length, 1024));
+ MY_MAX(trg_sql_original_stmt.length, 1024));
stmt_fld->maybe_null= TRUE;
@@ -8977,6 +9535,9 @@ TABLE_LIST *get_trigger_table(THD *thd, const sp_name *trg_name)
db= trg_name->m_db;
db.str= thd->strmake(db.str, db.length);
+ if (lower_case_table_names)
+ db.length= my_casedn_str(files_charset_info, db.str);
+
tbl_name.str= thd->strmake(tbl_name.str, tbl_name.length);
if (db.str == NULL || tbl_name.str == NULL)
@@ -9215,3 +9776,88 @@ static void get_cs_converted_string_value(THD *thd,
return;
}
#endif
+
+/**
+ Dumps a text description of a thread, its security context
+ (user, host) and the current query.
+
+ @param thd thread context
+ @param buffer pointer to preferred result buffer
+ @param length length of buffer
+ @param max_query_len how many chars of query to copy (0 for all)
+
+ @return Pointer to string
+*/
+
+extern "C"
+char *thd_get_error_context_description(THD *thd, char *buffer,
+ unsigned int length,
+ unsigned int max_query_len)
+{
+ String str(buffer, length, &my_charset_latin1);
+ const Security_context *sctx= &thd->main_security_ctx;
+ char header[256];
+ int len;
+
+ mysql_mutex_lock(&LOCK_thread_count);
+
+ len= my_snprintf(header, sizeof(header),
+ "MySQL thread id %lu, OS thread handle 0x%lx, query id %lu",
+ thd->thread_id, (ulong) thd->real_id, (ulong) thd->query_id);
+ str.length(0);
+ str.append(header, len);
+
+ if (sctx->host)
+ {
+ str.append(' ');
+ str.append(sctx->host);
+ }
+
+ if (sctx->ip)
+ {
+ str.append(' ');
+ str.append(sctx->ip);
+ }
+
+ if (sctx->user)
+ {
+ str.append(' ');
+ str.append(sctx->user);
+ }
+
+ /* Don't wait if LOCK_thd_data is used as this could cause a deadlock */
+ if (!mysql_mutex_trylock(&thd->LOCK_thd_data))
+ {
+ if (const char *info= thread_state_info(thd))
+ {
+ str.append(' ');
+ str.append(info);
+ }
+
+ if (thd->query())
+ {
+ if (max_query_len < 1)
+ len= thd->query_length();
+ else
+ len= MY_MIN(thd->query_length(), max_query_len);
+ str.append('\n');
+ str.append(thd->query(), len);
+ }
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
+ }
+ mysql_mutex_unlock(&LOCK_thread_count);
+
+ if (str.c_ptr_safe() == buffer)
+ return buffer;
+
+ /*
+ We have to copy the new string to the destination buffer because the string
+ was reallocated to a larger buffer to be able to fit.
+ */
+ DBUG_ASSERT(buffer != NULL);
+ length= MY_MIN(str.length(), length-1);
+ memcpy(buffer, str.c_ptr_quick(), length);
+ /* Make sure that the new string is null terminated */
+ buffer[length]= '\0';
+ return buffer;
+}