diff options
Diffstat (limited to 'sql/sql_show.cc')
-rw-r--r-- | sql/sql_show.cc | 1967 |
1 files changed, 1544 insertions, 423 deletions
diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 70bdef302df..28bedf62ea5 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -19,14 +19,17 @@ #include "mysql_priv.h" #include "sql_select.h" // For select_describe +#include "sql_show.h" #include "repl_failsafe.h" #include "sp.h" #include "sp_head.h" #include "sql_trigger.h" +#include "authors.h" +#include "event.h" #include <my_dir.h> -#ifdef HAVE_BERKELEY_DB -#include "ha_berkeley.h" // For berkeley_show_logs +#ifdef WITH_PARTITION_STORAGE_ENGINE +#include "ha_partition.h" #endif static const char *grant_names[]={ @@ -39,17 +42,39 @@ static TYPELIB grant_types = { sizeof(grant_names)/sizeof(char **), grant_names, NULL}; #endif -static int -store_create_info(THD *thd, TABLE_LIST *table_list, String *packet); -static int -view_store_create_info(THD *thd, TABLE_LIST *table, String *buff); -static bool schema_table_store_record(THD *thd, TABLE *table); - +static void store_key_options(THD *thd, String *packet, TABLE *table, + KEY *key_info); /*************************************************************************** ** List all table types supported ***************************************************************************/ +static my_bool show_handlerton(THD *thd, st_plugin_int *plugin, + void *arg) +{ + handlerton *default_type= (handlerton *) arg; + Protocol *protocol= thd->protocol; + handlerton *hton= (handlerton *) plugin->plugin->info; + + if (!(hton->flags & HTON_HIDDEN)) + { + protocol->prepare_for_resend(); + protocol->store(hton->name, system_charset_info); + const char *option_name= show_comp_option_name[(int) hton->state]; + + if (hton->state == SHOW_OPTION_YES && default_type == hton) + option_name= "DEFAULT"; + protocol->store(option_name, system_charset_info); + protocol->store(hton->comment, system_charset_info); + protocol->store(hton->commit ? "YES" : "NO", system_charset_info); + protocol->store(hton->prepare ? "YES" : "NO", system_charset_info); + protocol->store(hton->savepoint_set ? "YES" : "NO", system_charset_info); + + return protocol->write() ? 1 : 0; + } + return 0; +} + bool mysqld_show_storage_engines(THD *thd) { List<Item> field_list; @@ -59,37 +84,151 @@ bool mysqld_show_storage_engines(THD *thd) field_list.push_back(new Item_empty_string("Engine",10)); field_list.push_back(new Item_empty_string("Support",10)); field_list.push_back(new Item_empty_string("Comment",80)); + field_list.push_back(new Item_empty_string("Transactions",3)); + field_list.push_back(new Item_empty_string("XA",3)); + field_list.push_back(new Item_empty_string("Savepoints",3)); if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); - const char *default_type_name= - ha_get_storage_engine((enum db_type)thd->variables.table_type); + if (plugin_foreach(thd, show_handlerton, + MYSQL_STORAGE_ENGINE_PLUGIN, thd->variables.table_type)) + DBUG_RETURN(TRUE); + + send_eof(thd); + DBUG_RETURN(FALSE); +} - handlerton **types; - for (types= sys_table_types; *types; types++) +static int make_version_string(char *buf, int buf_length, uint version) +{ + return my_snprintf(buf, buf_length, "%d.%d", version>>8,version&0xff); +} + +static my_bool show_plugins(THD *thd, st_plugin_int *plugin, + void *arg) +{ + TABLE *table= (TABLE*) arg; + struct st_mysql_plugin *plug= plugin->plugin; + Protocol *protocol= thd->protocol; + CHARSET_INFO *cs= system_charset_info; + char version_buf[20]; + + restore_record(table, s->default_values); + + table->field[0]->store(plugin->name.str, plugin->name.length, cs); + + table->field[1]->store(version_buf, + make_version_string(version_buf, sizeof(version_buf), plug->version), + cs); + + + switch (plugin->state) { - if (!((*types)->flags & HTON_HIDDEN)) - { - protocol->prepare_for_resend(); - protocol->store((*types)->name, system_charset_info); - const char *option_name= show_comp_option_name[(int) (*types)->state]; - - if ((*types)->state == SHOW_OPTION_YES && - !my_strcasecmp(system_charset_info, default_type_name, (*types)->name)) - option_name= "DEFAULT"; - protocol->store(option_name, system_charset_info); - protocol->store((*types)->comment, system_charset_info); - if (protocol->write()) - DBUG_RETURN(TRUE); - } + /* case PLUGIN_IS_FREED: does not happen */ + case PLUGIN_IS_DELETED: + table->field[2]->store(STRING_WITH_LEN("DELETED"), cs); + break; + case PLUGIN_IS_UNINITIALIZED: + table->field[2]->store(STRING_WITH_LEN("INACTIVE"), cs); + break; + case PLUGIN_IS_READY: + table->field[2]->store(STRING_WITH_LEN("ACTIVE"), cs); + break; + default: + DBUG_ASSERT(0); + } + + table->field[3]->store(plugin_type_names[plug->type].str, + plugin_type_names[plug->type].length, + cs); + table->field[4]->store(version_buf, + make_version_string(version_buf, sizeof(version_buf), + *(uint *)plug->info), cs); + + if (plugin->plugin_dl) + { + table->field[5]->store(plugin->plugin_dl->dl.str, + plugin->plugin_dl->dl.length, cs); + table->field[5]->set_notnull(); + table->field[6]->store(version_buf, + make_version_string(version_buf, sizeof(version_buf), + plugin->plugin_dl->version), + cs); + table->field[6]->set_notnull(); + } + else + { + table->field[5]->set_null(); + table->field[6]->set_null(); + } + + + if (plug->author) + { + table->field[7]->store(plug->author, strlen(plug->author), cs); + table->field[7]->set_notnull(); + } + else + table->field[7]->set_null(); + + if (plug->descr) + { + table->field[8]->store(plug->descr, strlen(plug->descr), cs); + table->field[8]->set_notnull(); + } + else + table->field[8]->set_null(); + + return schema_table_store_record(thd, table); +} + + +int fill_plugins(THD *thd, TABLE_LIST *tables, COND *cond) +{ + DBUG_ENTER("fill_plugins"); + TABLE *table= tables->table; + + if (plugin_foreach(thd, show_plugins, MYSQL_ANY_PLUGIN, table)) + DBUG_RETURN(1); + + DBUG_RETURN(0); +} + + +/*************************************************************************** +** List all Authors. +** If you can update it, you get to be in it :) +***************************************************************************/ + +bool mysqld_show_authors(THD *thd) +{ + List<Item> field_list; + Protocol *protocol= thd->protocol; + DBUG_ENTER("mysqld_show_authors"); + + 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)); + + if (protocol->send_fields(&field_list, + Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) + DBUG_RETURN(TRUE); + + show_table_authors_st *authors; + for (authors= show_table_authors; authors->name; authors++) + { + protocol->prepare_for_resend(); + protocol->store(authors->name, system_charset_info); + protocol->store(authors->location, system_charset_info); + protocol->store(authors->comment, system_charset_info); + if (protocol->write()) + DBUG_RETURN(TRUE); } send_eof(thd); DBUG_RETURN(FALSE); } - /*************************************************************************** List all privileges supported ***************************************************************************/ @@ -111,6 +250,7 @@ static struct show_privileges_st sys_privileges[]= {"Create user", "Server Admin", "To create new users"}, {"Delete", "Tables", "To delete existing rows"}, {"Drop", "Databases,Tables", "To drop databases, tables, and views"}, + {"Event","Server Admin","To create, alter, drop and execute events"}, {"Execute", "Functions,Procedures", "To execute stored routines"}, {"File", "File access on server", "To read and write files on the server"}, {"Grant option", "Databases,Tables,Functions,Procedures", "To give to other users those privileges you possess"}, @@ -127,6 +267,7 @@ static struct show_privileges_st sys_privileges[]= {"Show view","Tables","To see views with SHOW CREATE VIEW"}, {"Shutdown","Server Admin", "To shut down the server"}, {"Super","Server Admin","To use KILL thread, SET GLOBAL, CHANGE MASTER, etc."}, + {"Trigger","Tables", "To use triggers"}, {"Update", "Tables", "To update existing rows"}, {"Usage","Server Admin","No privileges - allow connect only"}, {NullS, NullS, NullS} @@ -278,9 +419,14 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path, for (i=0 ; i < (uint) dirp->number_off_files ; i++) { + char uname[NAME_LEN*3+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 .. */ #ifdef USE_SYMDIR char *ext; char buff[FN_REFLEN]; @@ -297,17 +443,22 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path, continue; } #endif - if (file->name[0] == '.' || !MY_S_ISDIR(file->mystat->st_mode) || - (wild && wild_compare(file->name,wild,0))) - continue; + if (!MY_S_ISDIR(file->mystat->st_mode)) + continue; + VOID(filename_to_tablename(file->name, uname, sizeof(uname))); + if (wild && wild_compare(uname, wild, 0)) + continue; + file->name= uname; } else { // Return only .frm files which aren't temp files. - if (my_strcasecmp(system_charset_info, ext=fn_ext(file->name),reg_ext) || + if (my_strcasecmp(system_charset_info, ext=fn_rext(file->name),reg_ext) || is_prefix(file->name,tmp_file_prefix)) continue; *ext=0; + VOID(filename_to_tablename(file->name, uname, sizeof(uname))); + file->name= uname; if (wild) { if (lower_case_table_names) @@ -392,7 +543,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) buffer.length(0); if ((table_list->view ? view_store_create_info(thd, table_list, &buffer) : - store_create_info(thd, table_list, &buffer))) + store_create_info(thd, table_list, &buffer, NULL))) DBUG_RETURN(TRUE); List<Item> field_list; @@ -449,12 +600,6 @@ bool mysqld_show_create_db(THD *thd, char *dbname, Protocol *protocol=thd->protocol; DBUG_ENTER("mysql_show_create_db"); - if (check_db_name(dbname)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), dbname); - DBUG_RETURN(TRUE); - } - #ifndef NO_EMBEDDED_ACCESS_CHECKS if (test_all_bits(sctx->master_access, DB_ACLS)) db_access=DB_ACLS; @@ -465,8 +610,8 @@ bool mysqld_show_create_db(THD *thd, char *dbname, { my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), sctx->priv_user, sctx->host_or_ip, dbname); - mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), - sctx->priv_user, sctx->host_or_ip, dbname); + general_log_print(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), + sctx->priv_user, sctx->host_or_ip, dbname); DBUG_RETURN(TRUE); } #endif @@ -478,8 +623,7 @@ bool mysqld_show_create_db(THD *thd, char *dbname, } else { - (void) sprintf(path,"%s/%s",mysql_data_home, dbname); - length=unpack_dirname(path,path); // Convert if not unix + length= build_table_filename(path, sizeof(path), dbname, "", ""); found_libchar= 0; if (length && path[length-1] == FN_LIBCHAR) { @@ -532,29 +676,6 @@ bool mysqld_show_create_db(THD *thd, char *dbname, DBUG_RETURN(FALSE); } -bool -mysqld_show_logs(THD *thd) -{ - List<Item> field_list; - Protocol *protocol= thd->protocol; - DBUG_ENTER("mysqld_show_logs"); - - field_list.push_back(new Item_empty_string("File",FN_REFLEN)); - field_list.push_back(new Item_empty_string("Type",10)); - field_list.push_back(new Item_empty_string("Status",10)); - - if (protocol->send_fields(&field_list, - Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) - DBUG_RETURN(TRUE); - -#ifdef HAVE_BERKELEY_DB - if ((have_berkeley_db == SHOW_OPTION_YES) && berkeley_show_logs(protocol)) - DBUG_RETURN(TRUE); -#endif - - send_eof(thd); - DBUG_RETURN(FALSE); -} /**************************************************************************** @@ -597,10 +718,10 @@ mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd) Protocol *protocol= thd->protocol; String *packet= protocol->storage_packet(); DBUG_ENTER("mysqld_dump_create_info"); - DBUG_PRINT("enter",("table: %s",table_list->table->s->table_name)); + DBUG_PRINT("enter",("table: %s",table_list->table->s->table_name.str)); protocol->prepare_for_resend(); - if (store_create_info(thd, table_list, packet)) + if (store_create_info(thd, table_list, packet, NULL)) DBUG_RETURN(-1); if (fd < 0) @@ -635,6 +756,7 @@ mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd) static const char *require_quotes(const char *name, uint name_length) { uint length; + bool pure_digit= TRUE; const char *end= name + name_length; for (; name < end ; name++) @@ -643,7 +765,11 @@ static const char *require_quotes(const char *name, uint name_length) length= my_mbcharlen(system_charset_info, chr); if (length == 1 && !system_charset_info->ident_map[chr]) return name; + if (length == 1 && (chr < '0' || chr > '9')) + pure_digit= FALSE; } + if (pure_digit) + return name; return 0; } @@ -769,11 +895,34 @@ static void append_directory(THD *thd, String *packet, const char *dir_type, #define LIST_PROCESS_HOST_LEN 64 -static int -store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) +/* + Build a CREATE TABLE statement for a table. + + SYNOPSIS + store_create_info() + thd The thread + table_list A list containing one table to write statement + for. + packet Pointer to a string where statement will be + written. + create_info_arg Pointer to create information that can be used + to tailor the format of the statement. Can be + NULL, in which case only SQL_MODE is considered + when building the statement. + + NOTE + Currently always return 0, but might return error code in the + future. + + RETURN + 0 OK + */ +int +store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, + HA_CREATE_INFO *create_info_arg) { List<Item> field_list; - char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], *end; + char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], *end, uname[NAME_LEN*3+1]; const char *alias; String type(tmp, sizeof(tmp), system_charset_info); Field **ptr,*field; @@ -783,17 +932,17 @@ 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; - my_bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL | - MODE_ORACLE | - MODE_MSSQL | - MODE_DB2 | - MODE_MAXDB | - MODE_ANSI)) != 0; - my_bool limited_mysql_mode= (thd->variables.sql_mode & - (MODE_NO_FIELD_OPTIONS | MODE_MYSQL323 | - MODE_MYSQL40)) != 0; + 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; DBUG_ENTER("store_create_info"); - DBUG_PRINT("enter",("table: %s", table->s->table_name)); + DBUG_PRINT("enter",("table: %s", table->s->table_name.str)); restore_record(table, s->default_values); // Get empty record @@ -804,8 +953,14 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) if (table_list->schema_table) alias= table_list->schema_table->table_name; else - alias= (lower_case_table_names == 2 ? table->alias : - share->table_name); + { + if (lower_case_table_names == 2) + alias= table->alias; + else + { + alias= share->table_name.str; + } + } append_identifier(thd, packet, alias, strlen(alias)); packet->append(STRING_WITH_LEN(" (\n")); @@ -835,7 +990,7 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) { if (field->charset() != share->table_charset) { - packet->append(STRING_WITH_LEN(" character set ")); + packet->append(STRING_WITH_LEN(" CHARACTER SET ")); packet->append(field->charset()->csname); } /* @@ -844,7 +999,7 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) */ if (!(field->charset()->state & MY_CS_PRIMARY)) { - packet->append(STRING_WITH_LEN(" collate ")); + packet->append(STRING_WITH_LEN(" COLLATE ")); packet->append(field->charset()->name); } } @@ -875,7 +1030,7 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) if (has_default) { - packet->append(STRING_WITH_LEN(" default ")); + packet->append(STRING_WITH_LEN(" DEFAULT ")); if (has_now_default) packet->append(STRING_WITH_LEN("CURRENT_TIMESTAMP")); else if (!field->is_null()) @@ -902,11 +1057,11 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) if (!limited_mysql_mode && table->timestamp_field == field && field->unireg_check != Field::TIMESTAMP_DN_FIELD) - packet->append(STRING_WITH_LEN(" on update CURRENT_TIMESTAMP")); + packet->append(STRING_WITH_LEN(" ON UPDATE CURRENT_TIMESTAMP")); if (field->unireg_check == Field::NEXT_NUMBER && !(thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS)) - packet->append(STRING_WITH_LEN(" auto_increment")); + packet->append(STRING_WITH_LEN(" AUTO_INCREMENT")); if (field->comment.length) { @@ -929,35 +1084,24 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) if (i == primary_key && !strcmp(key_info->name, primary_key_name)) { found_primary=1; - packet->append(STRING_WITH_LEN("PRIMARY ")); + /* + No space at end, because a space will be added after where the + identifier would go, but that is not added for primary key. + */ + packet->append(STRING_WITH_LEN("PRIMARY KEY")); } else if (key_info->flags & HA_NOSAME) - packet->append(STRING_WITH_LEN("UNIQUE ")); + packet->append(STRING_WITH_LEN("UNIQUE KEY ")); else if (key_info->flags & HA_FULLTEXT) - packet->append(STRING_WITH_LEN("FULLTEXT ")); + packet->append(STRING_WITH_LEN("FULLTEXT KEY ")); else if (key_info->flags & HA_SPATIAL) - packet->append(STRING_WITH_LEN("SPATIAL ")); - packet->append(STRING_WITH_LEN("KEY ")); + packet->append(STRING_WITH_LEN("SPATIAL KEY ")); + else + packet->append(STRING_WITH_LEN("KEY ")); if (!found_primary) append_identifier(thd, packet, key_info->name, strlen(key_info->name)); - if (!(thd->variables.sql_mode & MODE_NO_KEY_OPTIONS) && - !limited_mysql_mode && !foreign_db_mode) - { - if (key_info->algorithm == HA_KEY_ALG_BTREE) - packet->append(STRING_WITH_LEN(" USING BTREE")); - - if (key_info->algorithm == HA_KEY_ALG_HASH) - packet->append(STRING_WITH_LEN(" USING HASH")); - - // +BAR: send USING only in non-default case: non-spatial rtree - if ((key_info->algorithm == HA_KEY_ALG_RTREE) && - !(key_info->flags & HA_SPATIAL)) - packet->append(STRING_WITH_LEN(" USING RTREE")); - - // No need to send USING FULLTEXT, it is sent as FULLTEXT KEY - } packet->append(STRING_WITH_LEN(" (")); for (uint j=0 ; j < key_info->key_parts ; j++,key_part++) @@ -982,6 +1126,13 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) } } packet->append(')'); + store_key_options(thd, packet, table, key_info); + if (key_info->parser) + { + packet->append(" WITH PARSER ", 13); + append_identifier(thd, packet, key_info->parser->name.str, + key_info->parser->name.length); + } } /* @@ -998,11 +1149,40 @@ 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 (thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) - packet->append(STRING_WITH_LEN(" TYPE=")); + /* + Get possible table space definitions and append them + to the CREATE TABLE statement + */ + + if ((for_str= file->get_tablespace_name(thd))) + { + packet->append(" TABLESPACE "); + packet->append(for_str, strlen(for_str)); + packet->append(" STORAGE DISK"); + my_free(for_str, MYF(0)); + } + + /* + IF check_create_info + THEN add ENGINE only if it was used when creating the table + */ + if (!create_info_arg || + (create_info_arg->used_fields & HA_CREATE_USED_ENGINE)) + { + if (thd->variables.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(STRING_WITH_LEN(" ENGINE=")); - packet->append(file->table_type()); + packet->append(file->table_type()); +#else + packet->append(file->table_type()); +#endif + } /* Add AUTO_INCREMENT=... if there is an AUTO_INCREMENT column, @@ -1027,12 +1207,20 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) !(thd->variables.sql_mode & MODE_MYSQL323) && !(thd->variables.sql_mode & MODE_MYSQL40)) { - packet->append(STRING_WITH_LEN(" DEFAULT CHARSET=")); - packet->append(share->table_charset->csname); - if (!(share->table_charset->state & MY_CS_PRIMARY)) + /* + IF check_create_info + THEN add DEFAULT CHARSET only if it was used when creating the table + */ + if (!create_info_arg || + (create_info_arg->used_fields & HA_CREATE_USED_DEFAULT_CHARSET)) { - packet->append(STRING_WITH_LEN(" COLLATE=")); - packet->append(table->s->table_charset->name); + packet->append(STRING_WITH_LEN(" DEFAULT CHARSET=")); + packet->append(share->table_charset->csname); + if (!(share->table_charset->state & MY_CS_PRIMARY)) + { + packet->append(STRING_WITH_LEN(" COLLATE=")); + packet->append(table->s->table_charset->name); + } } } @@ -1070,6 +1258,12 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) packet->append(STRING_WITH_LEN(" ROW_FORMAT=")); packet->append(ha_row_type[(uint) share->row_type]); } + if (table->s->key_block_size) + { + packet->append(STRING_WITH_LEN(" KEY_BLOCK_SIZE=")); + end= longlong10_to_str(table->s->key_block_size, buff, 10); + packet->append(buff, (uint) (end - buff)); + } table->file->append_create_info(packet); if (share->comment && share->comment[0]) { @@ -1081,21 +1275,71 @@ 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); } - if (file->raid_type) - { - uint length; - length= my_snprintf(buff,sizeof(buff), - " RAID_TYPE=%s RAID_CHUNKS=%d RAID_CHUNKSIZE=%ld", - my_raid_type(file->raid_type), file->raid_chunks, - file->raid_chunksize/RAID_BLOCK_SIZE); - packet->append(buff, length); - } append_directory(thd, packet, "DATA", create_info.data_file_name); append_directory(thd, packet, "INDEX", create_info.index_file_name); } +#ifdef WITH_PARTITION_STORAGE_ENGINE + { + /* + Partition syntax for CREATE TABLE is at the end of the syntax. + */ + uint part_syntax_len; + char *part_syntax; + if (table->part_info && + (!table->part_info->is_auto_partitioned) && + ((part_syntax= generate_partition_syntax(table->part_info, + &part_syntax_len, + FALSE,FALSE)))) + { + packet->append(part_syntax, part_syntax_len); + my_free(part_syntax, MYF(0)); + } + } +#endif DBUG_RETURN(0); } + +static void store_key_options(THD *thd, String *packet, TABLE *table, + KEY *key_info) +{ + bool limited_mysql_mode= (thd->variables.sql_mode & + (MODE_NO_FIELD_OPTIONS | MODE_MYSQL323 | + MODE_MYSQL40)) != 0; + bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL | + MODE_ORACLE | + MODE_MSSQL | + MODE_DB2 | + MODE_MAXDB | + MODE_ANSI)) != 0; + char *end, buff[32]; + + if (!(thd->variables.sql_mode & MODE_NO_KEY_OPTIONS) && + !limited_mysql_mode && !foreign_db_mode) + { + + if (key_info->algorithm == HA_KEY_ALG_BTREE) + packet->append(STRING_WITH_LEN(" USING BTREE")); + + if (key_info->algorithm == HA_KEY_ALG_HASH) + packet->append(STRING_WITH_LEN(" USING HASH")); + + /* send USING only in non-default case: non-spatial rtree */ + if ((key_info->algorithm == HA_KEY_ALG_RTREE) && + !(key_info->flags & HA_SPATIAL)) + packet->append(STRING_WITH_LEN(" USING RTREE")); + + if ((key_info->flags & HA_USES_BLOCK_SIZE) && + table->s->key_block_size != key_info->block_size) + { + packet->append(STRING_WITH_LEN(" KEY_BLOCK_SIZE=")); + end= longlong10_to_str(key_info->block_size, buff, 10); + packet->append(buff, (uint) (end - buff)); + } + } +} + + void view_store_options(THD *thd, TABLE_LIST *table, String *buff) { @@ -1120,7 +1364,6 @@ view_store_options(THD *thd, TABLE_LIST *table, String *buff) buff->append(STRING_WITH_LEN("SQL SECURITY INVOKER ")); } - /* Append DEFINER clause to the given buffer. @@ -1143,7 +1386,7 @@ void append_definer(THD *thd, String *buffer, const LEX_STRING *definer_user, } -static int +int view_store_create_info(THD *thd, TABLE_LIST *table, String *buff) { my_bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL | @@ -1345,7 +1588,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) if (thd_info->proc_info) protocol->store(thd_info->proc_info, system_charset_info); else - protocol->store(command_name[thd_info->command], system_charset_info); + protocol->store(command_name[thd_info->command].str, system_charset_info); if (thd_info->start_time) protocol->store((uint32) (now - thd_info->start_time)); else @@ -1359,46 +1602,323 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) DBUG_VOID_RETURN; } +int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) +{ + TABLE *table= tables->table; + CHARSET_INFO *cs= system_charset_info; + char *user; + time_t now= time(0); + DBUG_ENTER("fill_process_list"); + + user= thd->security_ctx->master_access & PROCESS_ACL ? + NullS : thd->security_ctx->priv_user; + + VOID(pthread_mutex_lock(&LOCK_thread_count)); + + if (!thd->killed) + { + I_List_iterator<THD> it(threads); + THD* tmp; + + while ((tmp= it++)) + { + Security_context *tmp_sctx= tmp->security_ctx; + struct st_my_thread_var *mysys_var; + const char *val; + + if ((!tmp->vio_ok() && !tmp->system_thread) || + (user && (!tmp_sctx->user || strcmp(tmp_sctx->user, user)))) + continue; + + restore_record(table, s->default_values); + /* ID */ + table->field[0]->store((longlong) tmp->thread_id, TRUE); + /* USER */ + val= tmp_sctx->user ? tmp_sctx->user : + (tmp->system_thread ? "system user" : "unauthenticated user"); + table->field[1]->store(val, strlen(val), cs); + /* HOST */ + if (tmp->peer_port && (tmp_sctx->host || tmp_sctx->ip) && + thd->security_ctx->host_or_ip[0]) + { + char host[LIST_PROCESS_HOST_LEN + 1]; + my_snprintf(host, LIST_PROCESS_HOST_LEN, "%s:%u", + tmp_sctx->host_or_ip, tmp->peer_port); + table->field[2]->store(host, strlen(host), cs); + } + else + table->field[2]->store(tmp_sctx->host_or_ip, + strlen(tmp_sctx->host_or_ip), cs); + /* DB */ + if (tmp->db) + { + table->field[3]->store(tmp->db, strlen(tmp->db), cs); + table->field[3]->set_notnull(); + } + + if ((mysys_var= tmp->mysys_var)) + pthread_mutex_lock(&mysys_var->mutex); + /* COMMAND */ + if ((val= (char *) (tmp->killed == THD::KILL_CONNECTION? "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); + /* TIME */ + table->field[5]->store((uint32)(tmp->start_time ? + now - tmp->start_time : 0), TRUE); + /* STATE */ +#ifndef EMBEDDED_LIBRARY + val= (char*) (tmp->locked ? "Locked" : + tmp->net.reading_or_writing ? + (tmp->net.reading_or_writing == 2 ? + "Writing to net" : + tmp->command == COM_SLEEP ? "" : + "Reading from net") : + tmp->proc_info ? tmp->proc_info : + tmp->mysys_var && + tmp->mysys_var->current_cond ? + "Waiting on cond" : NullS); +#else + val= (char *) "Writing to net"; +#endif + if (val) + { + table->field[6]->store(val, strlen(val), cs); + table->field[6]->set_notnull(); + } + + if (mysys_var) + pthread_mutex_unlock(&mysys_var->mutex); + + /* INFO */ + if (tmp->query) + { + table->field[7]->store(tmp->query, + min(PROCESS_LIST_INFO_WIDTH, + tmp->query_length), cs); + table->field[7]->set_notnull(); + } + + if (schema_table_store_record(thd, table)) + { + VOID(pthread_mutex_unlock(&LOCK_thread_count)); + DBUG_RETURN(1); + } + } + } + + VOID(pthread_mutex_unlock(&LOCK_thread_count)); + DBUG_RETURN(0); +} + /***************************************************************************** Status functions *****************************************************************************/ +static DYNAMIC_ARRAY all_status_vars; +static bool status_vars_inited= 0; +static int show_var_cmp(const void *var1, const void *var2) +{ + return strcmp(((SHOW_VAR*)var1)->name, ((SHOW_VAR*)var2)->name); +} + +/* + deletes all the SHOW_UNDEF elements from the array and calls + delete_dynamic() if it's completely empty. +*/ +static void shrink_var_array(DYNAMIC_ARRAY *array) +{ + uint a,b; + SHOW_VAR *all= dynamic_element(array, 0, SHOW_VAR *); + + for (a= b= 0; b < array->elements; b++) + if (all[b].type != SHOW_UNDEF) + all[a++]= all[b]; + if (a) + { + bzero(all+a, sizeof(SHOW_VAR)); // writing NULL-element to the end + array->elements= a; + } + else // array is completely empty - delete it + delete_dynamic(array); +} + +/* + Adds an array of SHOW_VAR entries to the output of SHOW STATUS + + SYNOPSIS + add_status_vars(SHOW_VAR *list) + list - an array of SHOW_VAR entries to add to all_status_vars + the last entry must be {0,0,SHOW_UNDEF} + + NOTE + The handling of all_status_vars[] is completely internal, it's allocated + automatically when something is added to it, and deleted completely when + the last entry is removed. + + As a special optimization, if add_status_vars() is called before + init_status_vars(), it assumes "startup mode" - neither concurrent access + to the array nor SHOW STATUS are possible (thus it skips locks and qsort) + + The last entry of the all_status_vars[] should always be {0,0,SHOW_UNDEF} +*/ +int add_status_vars(SHOW_VAR *list) +{ + int res= 0; + if (status_vars_inited) + pthread_mutex_lock(&LOCK_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)) + { + res= 1; + goto err; + } + while (list->name) + res|= insert_dynamic(&all_status_vars, (gptr)list++); + res|= insert_dynamic(&all_status_vars, (gptr)list); // appending NULL-element + all_status_vars.elements--; // but next insert_dynamic should overwite it + if (status_vars_inited) + sort_dynamic(&all_status_vars, show_var_cmp); +err: + if (status_vars_inited) + pthread_mutex_unlock(&LOCK_status); + return res; +} + +/* + Make all_status_vars[] usable for SHOW STATUS + + NOTE + See add_status_vars(). Before init_status_vars() call, add_status_vars() + works in a special fast "startup" mode. Thus init_status_vars() + should be called as late as possible but before enabling multi-threading. +*/ +void init_status_vars() +{ + status_vars_inited=1; + sort_dynamic(&all_status_vars, show_var_cmp); +} + +/* + catch-all cleanup function, cleans up everything no matter what + + DESCRIPTION + This function is not strictly required if all add_to_status/ + 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 +*/ +void free_status_vars() +{ + delete_dynamic(&all_status_vars); +} + +/* + Removes an array of SHOW_VAR entries from the output of SHOW STATUS + + SYNOPSIS + remove_status_vars(SHOW_VAR *list) + list - an array of SHOW_VAR entries to remove to all_status_vars + the last entry must be {0,0,SHOW_UNDEF} + + NOTE + there's lots of room for optimizing this, especially in non-sorted mode, + but nobody cares - it may be called only in case of failed plugin + initialization in the mysqld startup. +*/ + +void remove_status_vars(SHOW_VAR *list) +{ + if (status_vars_inited) + { + pthread_mutex_lock(&LOCK_status); + SHOW_VAR *all= dynamic_element(&all_status_vars, 0, SHOW_VAR *); + int a= 0, b= all_status_vars.elements, c= (a+b)/2; + + for (; list->name; list++) + { + int res= 0; + for (a= 0, b= all_status_vars.elements; b-a > 1; c= (a+b)/2) + { + res= show_var_cmp(list, all+c); + if (res < 0) + b= c; + else if (res > 0) + a= c; + else + break; + } + if (res == 0) + all[c].type= SHOW_UNDEF; + } + shrink_var_array(&all_status_vars); + pthread_mutex_unlock(&LOCK_status); + } + else + { + SHOW_VAR *all= dynamic_element(&all_status_vars, 0, SHOW_VAR *); + uint i; + for (; list->name; list++) + { + for (i= 0; i < all_status_vars.elements; i++) + { + if (show_var_cmp(list, all+i)) + continue; + all[i].type= SHOW_UNDEF; + break; + } + } + shrink_var_array(&all_status_vars); + } +} static bool show_status_array(THD *thd, const char *wild, - show_var_st *variables, + SHOW_VAR *variables, enum enum_var_type value_type, struct system_status_var *status_var, const char *prefix, TABLE *table) { - char buff[1024], *prefix_end; + char buff[SHOW_VAR_FUNC_BUFF_SIZE], *prefix_end; /* the variable name should not be longer then 80 characters */ char name_buffer[80]; int len; LEX_STRING null_lex_str; + SHOW_VAR tmp, *var; DBUG_ENTER("show_status_array"); null_lex_str.str= 0; // For sys_var->value_ptr() null_lex_str.length= 0; prefix_end=strnmov(name_buffer, prefix, sizeof(name_buffer)-1); + if (*prefix) + *prefix_end++= '_'; len=name_buffer + sizeof(name_buffer) - prefix_end; for (; variables->name; variables++) { strnmov(prefix_end, variables->name, len); name_buffer[sizeof(name_buffer)-1]=0; /* Safety */ - SHOW_TYPE show_type=variables->type; - if (show_type == SHOW_VARS) + + /* + if var->type is SHOW_FUNC, call the function. + Repeat as necessary, if new var is again SHOW_FUNC + */ + for (var=variables; var->type == SHOW_FUNC; var= &tmp) + ((mysql_show_var_func)(var->value))(thd, &tmp, buff); + + SHOW_TYPE show_type=var->type; + if (show_type == SHOW_ARRAY) { - show_status_array(thd, wild, (show_var_st *) variables->value, - value_type, status_var, variables->name, table); + show_status_array(thd, wild, (SHOW_VAR *) var->value, + value_type, status_var, name_buffer, table); } else { if (!(wild && wild[0] && wild_case_compare(system_charset_info, name_buffer, wild))) { - char *value=variables->value; + char *value=var->value; const char *pos, *end; // We assign a lot of const's long nr; if (show_type == SHOW_SYS) @@ -1409,13 +1929,22 @@ static bool show_status_array(THD *thd, const char *wild, } pos= end= buff; + /* + note that value may be == buff. All SHOW_xxx code below + should still work in this case + */ switch (show_type) { + case SHOW_DOUBLE_STATUS: + { + value= ((char *) status_var + (ulong) value); + end= buff + sprintf(buff, "%f", *(double*) value); + break; + } case SHOW_LONG_STATUS: - case SHOW_LONG_CONST_STATUS: value= ((char *) status_var + (ulong) value); /* fall through */ case SHOW_LONG: - case SHOW_LONG_CONST: + case SHOW_LONG_NOFLUSH: // the difference lies in refresh_status() end= int10_to_str(*(long*) value, buff, 10); break; case SHOW_LONGLONG: @@ -1430,7 +1959,6 @@ static bool show_status_array(THD *thd, const char *wild, case SHOW_MY_BOOL: end= strmov(buff, *(my_bool*) value ? "ON" : "OFF"); break; - case SHOW_INT_CONST: case SHOW_INT: end= int10_to_str((long) *(uint32*) value, buff, 10); break; @@ -1448,77 +1976,6 @@ static bool show_status_array(THD *thd, const char *wild, end= strend(pos); break; } - case SHOW_STARTTIME: - nr= (long) (thd->query_start() - start_time); - end= int10_to_str(nr, buff, 10); - break; - case SHOW_QUESTION: - end= int10_to_str((long) thd->query_id, buff, 10); - break; -#ifdef HAVE_REPLICATION - case SHOW_RPL_STATUS: - end= strmov(buff, rpl_status_type[(int)rpl_status]); - break; - case SHOW_SLAVE_RUNNING: - { - pthread_mutex_lock(&LOCK_active_mi); - end= strmov(buff, (active_mi && active_mi->slave_running && - active_mi->rli.slave_running) ? "ON" : "OFF"); - pthread_mutex_unlock(&LOCK_active_mi); - break; - } - case SHOW_SLAVE_RETRIED_TRANS: - { - /* - TODO: in 5.1 with multimaster, have one such counter per line in - SHOW SLAVE STATUS, and have the sum over all lines here. - */ - pthread_mutex_lock(&LOCK_active_mi); - if (active_mi) - { - pthread_mutex_lock(&active_mi->rli.data_lock); - end= int10_to_str(active_mi->rli.retried_trans, buff, 10); - pthread_mutex_unlock(&active_mi->rli.data_lock); - } - pthread_mutex_unlock(&LOCK_active_mi); - break; - } - case SHOW_SLAVE_SKIP_ERRORS: - { - MY_BITMAP *bitmap= (MY_BITMAP *)value; - if (!use_slave_mask || bitmap_is_clear_all(bitmap)) - { - end= strmov(buff, "OFF"); - } - else if (bitmap_is_set_all(bitmap)) - { - end= strmov(buff, "ALL"); - } - else - { - /* 10 is enough assuming errors are max 4 digits */ - int i; - for (i= 1; - i < MAX_SLAVE_ERROR && (uint) (end-buff) < sizeof(buff)-10; - i++) - { - if (bitmap_is_set(bitmap, i)) - { - end= int10_to_str(i, (char*) end, 10); - *(char*) end++= ','; - } - } - if (end != buff) - end--; // Remove last ',' - if (i < MAX_SLAVE_ERROR) - end= strmov((char*) end, "..."); // Couldn't show all errors - } - break; - } -#endif /* HAVE_REPLICATION */ - case SHOW_OPENTABLES: - end= int10_to_str((long) cached_tables(), buff, 10); - break; case SHOW_CHAR_PTR: { if (!(pos= *(char**) value)) @@ -1526,203 +1983,19 @@ static bool show_status_array(THD *thd, const char *wild, end= strend(pos); break; } - case SHOW_DOUBLE_STATUS: - { - value= ((char *) status_var + (ulong) value); - end= buff + sprintf(buff, "%f", *(double*) value); - break; - } -#ifdef HAVE_OPENSSL - /* First group - functions relying on CTX */ - case SHOW_SSL_CTX_SESS_ACCEPT: - end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_accept(ssl_acceptor_fd-> - ssl_context)), - buff, 10); - break; - case SHOW_SSL_CTX_SESS_ACCEPT_GOOD: - end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_accept_good(ssl_acceptor_fd-> - ssl_context)), - buff, 10); - break; - case SHOW_SSL_CTX_SESS_CONNECT_GOOD: - end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_connect_good(ssl_acceptor_fd-> - ssl_context)), - buff, 10); - break; - case SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE: - end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context)), - buff, 10); - break; - case SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE: - end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd-> ssl_context)), - buff, 10); - break; - case SHOW_SSL_CTX_SESS_CB_HITS: - end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_cb_hits(ssl_acceptor_fd-> - ssl_context)), - buff, 10); - break; - case SHOW_SSL_CTX_SESS_HITS: - end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_hits(ssl_acceptor_fd-> - ssl_context)), - buff, 10); - break; - case SHOW_SSL_CTX_SESS_CACHE_FULL: - end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_cache_full(ssl_acceptor_fd-> - ssl_context)), - buff, 10); - break; - case SHOW_SSL_CTX_SESS_MISSES: - end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_misses(ssl_acceptor_fd-> - ssl_context)), - buff, 10); - break; - case SHOW_SSL_CTX_SESS_TIMEOUTS: - end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context)), - buff,10); - break; - case SHOW_SSL_CTX_SESS_NUMBER: - end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context)), - buff,10); - break; - case SHOW_SSL_CTX_SESS_CONNECT: - end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context)), - buff,10); - break; - case SHOW_SSL_CTX_SESS_GET_CACHE_SIZE: - end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context)), - buff,10); - break; - case SHOW_SSL_CTX_GET_VERIFY_MODE: - end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : - SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context)), - buff,10); - break; - case SHOW_SSL_CTX_GET_VERIFY_DEPTH: - end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : - SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context)), - buff,10); - break; - case SHOW_SSL_CTX_GET_SESSION_CACHE_MODE: - if (!ssl_acceptor_fd) - { - pos= "NONE"; - end= pos+4; - break; - } - switch (SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context)) - { - case SSL_SESS_CACHE_OFF: - pos= "OFF"; - break; - case SSL_SESS_CACHE_CLIENT: - pos= "CLIENT"; - break; - case SSL_SESS_CACHE_SERVER: - pos= "SERVER"; - break; - case SSL_SESS_CACHE_BOTH: - pos= "BOTH"; - break; - case SSL_SESS_CACHE_NO_AUTO_CLEAR: - pos= "NO_AUTO_CLEAR"; - break; - case SSL_SESS_CACHE_NO_INTERNAL_LOOKUP: - pos= "NO_INTERNAL_LOOKUP"; - break; - default: - pos= "Unknown"; - break; - } - end= strend(pos); - break; - /* First group - functions relying on SSL */ - case SHOW_SSL_GET_VERSION: - pos= (thd->net.vio->ssl_arg ? - SSL_get_version((SSL*) thd->net.vio->ssl_arg) : ""); - end= strend(pos); - break; - case SHOW_SSL_SESSION_REUSED: - end= int10_to_str((long) (thd->net.vio->ssl_arg ? - SSL_session_reused((SSL*) thd->net.vio-> - ssl_arg) : - 0), - buff, 10); - break; - case SHOW_SSL_GET_DEFAULT_TIMEOUT: - end= int10_to_str((long) (thd->net.vio->ssl_arg ? - SSL_get_default_timeout((SSL*) thd->net.vio-> - ssl_arg) : - 0), - buff, 10); - break; - case SHOW_SSL_GET_VERIFY_MODE: - end= int10_to_str((long) (thd->net.vio->ssl_arg ? - SSL_get_verify_mode((SSL*) thd->net.vio-> - ssl_arg): - 0), - buff, 10); - break; - case SHOW_SSL_GET_VERIFY_DEPTH: - end= int10_to_str((long) (thd->net.vio->ssl_arg ? - SSL_get_verify_depth((SSL*) thd->net.vio-> - ssl_arg): - 0), - buff, 10); - break; - case SHOW_SSL_GET_CIPHER: - pos= (thd->net.vio->ssl_arg ? - SSL_get_cipher((SSL*) thd->net.vio->ssl_arg) : "" ); - end= strend(pos); - break; - case SHOW_SSL_GET_CIPHER_LIST: - if (thd->net.vio->ssl_arg) - { - char *to= buff; - for (int i=0 ; i++ ;) - { - const char *p= SSL_get_cipher_list((SSL*) thd->net.vio->ssl_arg,i); - if (p == NULL) - break; - to= strmov(to, p); - *to++= ':'; - } - if (to != buff) - to--; // Remove last ':' - end= to; - } - break; - -#endif /* HAVE_OPENSSL */ case SHOW_KEY_CACHE_LONG: - case SHOW_KEY_CACHE_CONST_LONG: - value= (value-(char*) &dflt_key_cache_var)+ (char*) dflt_key_cache; + value= (char*) dflt_key_cache + (ulong)value; end= int10_to_str(*(long*) value, buff, 10); break; case SHOW_KEY_CACHE_LONGLONG: - value= (value-(char*) &dflt_key_cache_var)+ (char*) dflt_key_cache; + value= (char*) dflt_key_cache + (ulong)value; end= longlong10_to_str(*(longlong*) value, buff, 10); break; - case SHOW_NET_COMPRESSION: - end= strmov(buff, thd->net.compress ? "ON" : "OFF"); - break; - case SHOW_UNDEF: // Show never happen - case SHOW_SYS: - break; // Return empty string + case SHOW_UNDEF: + break; // Return empty string + case SHOW_SYS: // Cannot happen default: + DBUG_ASSERT(0); break; } restore_record(table, s->default_values); @@ -1803,10 +2076,10 @@ typedef struct st_index_field_values 1 error */ -static bool schema_table_store_record(THD *thd, TABLE *table) +bool schema_table_store_record(THD *thd, TABLE *table) { int error; - if ((error= table->file->write_row(table->record[0]))) + if ((error= table->file->ha_write_row(table->record[0]))) { if (create_myisam_from_heap(thd, table, table->pos_in_table_list->schema_table_param, @@ -1827,6 +2100,7 @@ void get_index_field_values(LEX *lex, INDEX_FIELD_VALUES *index_field_values) case SQLCOM_SHOW_TABLES: case SQLCOM_SHOW_TABLE_STATUS: case SQLCOM_SHOW_TRIGGERS: + case SQLCOM_SHOW_EVENTS: index_field_values->db_value= lex->select_lex.db; index_field_values->table_value= wild; break; @@ -2081,7 +2355,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) Security_context *sctx= thd->security_ctx; uint derived_tables= lex->derived_tables; int error= 1; - db_type not_used; + enum legacy_db_type not_used; Open_tables_state open_tables_state_backup; bool save_view_prepare_mode= lex->view_prepare_mode; lex->view_prepare_mode= TRUE; @@ -2174,8 +2448,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) } else { - strxmov(path, mysql_data_home, "/", base_name, NullS); - end= path + (len= unpack_dirname(path,path)); + len= build_table_filename(path, sizeof(path), base_name, "", ""); + end= path + len; len= FN_LEN - len; if (mysql_find_files(thd, &files, base_name, path, idx_field_vals.table_value, 0)) @@ -2323,8 +2597,7 @@ int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond) (grant_option && !check_grant_db(thd, file_name))) #endif { - strxmov(path, mysql_data_home, "/", file_name, NullS); - length=unpack_dirname(path,path); // Convert if not unix + length= build_table_filename(path, sizeof(path), file_name, "", ""); found_libchar= 0; if (length && path[length-1] == FN_LIBCHAR) { @@ -2504,15 +2777,12 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables, ptr=strxmov(ptr, " row_format=", ha_row_type[(uint) share->row_type], NullS); - if (file->raid_type) - { - char buff[100]; - my_snprintf(buff,sizeof(buff), - " raid_type=%s raid_chunks=%d raid_chunksize=%ld", - my_raid_type(file->raid_type), file->raid_chunks, - file->raid_chunksize/RAID_BLOCK_SIZE); - ptr=strmov(ptr,buff); - } +#ifdef WITH_PARTITION_STORAGE_ENGINE + if (show_table->s->db_type == &partition_hton && + show_table->part_info != NULL && + show_table->part_info->no_parts > 0) + ptr= strmov(ptr, " partitioned"); +#endif table->field[19]->store(option_buff+1, (ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1), cs); @@ -2762,6 +3032,7 @@ int fill_schema_charsets(THD *thd, TABLE_LIST *tables, COND *cond) CHARSET_INFO *tmp_cs= cs[0]; if (tmp_cs && (tmp_cs->state & MY_CS_PRIMARY) && (tmp_cs->state & MY_CS_AVAILABLE) && + !(tmp_cs->state & MY_CS_HIDDEN) && !(wild && wild[0] && wild_case_compare(scs, tmp_cs->csname,wild))) { @@ -2780,6 +3051,49 @@ int fill_schema_charsets(THD *thd, TABLE_LIST *tables, COND *cond) } +static my_bool iter_schema_engines(THD *thd, st_plugin_int *plugin, + void *ptable) +{ + TABLE *table= (TABLE *) ptable; + handlerton *hton= (handlerton *) plugin->plugin->info; + const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS; + CHARSET_INFO *scs= system_charset_info; + DBUG_ENTER("iter_schema_engines"); + + if (!(hton->flags & HTON_HIDDEN)) + { + if (!(wild && wild[0] && + wild_case_compare(scs, hton->name,wild))) + { + const char *tmp; + restore_record(table, s->default_values); + + table->field[0]->store(hton->name, strlen(hton->name), scs); + tmp= hton->state ? "DISABLED" : "ENABLED"; + table->field[1]->store( tmp, strlen(tmp), scs); + table->field[2]->store(hton->comment, strlen(hton->comment), scs); + tmp= hton->commit ? "YES" : "NO"; + table->field[3]->store( tmp, strlen(tmp), scs); + tmp= hton->prepare ? "YES" : "NO"; + table->field[4]->store( tmp, strlen(tmp), scs); + tmp= hton->savepoint_set ? "YES" : "NO"; + table->field[5]->store( tmp, strlen(tmp), scs); + + if (schema_table_store_record(thd, table)) + DBUG_RETURN(1); + } + } + DBUG_RETURN(0); +} + + +int fill_schema_engines(THD *thd, TABLE_LIST *tables, COND *cond) +{ + return plugin_foreach(thd, iter_schema_engines, + MYSQL_STORAGE_ENGINE_PLUGIN, tables->table); +} + + int fill_schema_collation(THD *thd, TABLE_LIST *tables, COND *cond) { CHARSET_INFO **cs; @@ -2791,6 +3105,7 @@ int fill_schema_collation(THD *thd, TABLE_LIST *tables, COND *cond) CHARSET_INFO **cl; CHARSET_INFO *tmp_cs= cs[0]; if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) || + (tmp_cs->state & MY_CS_HIDDEN) || !(tmp_cs->state & MY_CS_PRIMARY)) continue; for (cl= all_charsets; cl < all_charsets+255 ;cl ++) @@ -2947,7 +3262,7 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond) { DBUG_RETURN(1); } - proc_table->file->ha_index_init(0); + proc_table->file->ha_index_init(0, 1); if ((res= proc_table->file->index_first(proc_table->record[0]))) { res= (res == HA_ERR_END_OF_FILE) ? 0 : 1; @@ -3382,6 +3697,536 @@ static int get_schema_key_column_usage_record(THD *thd, } +static void collect_partition_expr(List<char> &field_list, String *str) +{ + List_iterator<char> part_it(field_list); + ulong no_fields= field_list.elements; + const char *field_str; + str->length(0); + while ((field_str= part_it++)) + { + str->append(field_str); + if (--no_fields != 0) + str->append(","); + } + return; +} + + +static void store_schema_partitions_record(THD *thd, TABLE *table, + partition_element *part_elem, + handler *file, uint part_id) +{ + CHARSET_INFO *cs= system_charset_info; + PARTITION_INFO stat_info; + TIME time; + file->get_dynamic_partition_info(&stat_info, part_id); + table->field[12]->store((longlong) stat_info.records, TRUE); + table->field[13]->store((longlong) stat_info.mean_rec_length, TRUE); + table->field[14]->store((longlong) stat_info.data_file_length, TRUE); + if (stat_info.max_data_file_length) + { + table->field[15]->store((longlong) stat_info.max_data_file_length, TRUE); + table->field[15]->set_notnull(); + } + table->field[16]->store((longlong) stat_info.index_file_length, TRUE); + table->field[17]->store((longlong) stat_info.delete_length, TRUE); + if (stat_info.create_time) + { + thd->variables.time_zone->gmt_sec_to_TIME(&time, + stat_info.create_time); + table->field[18]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); + table->field[18]->set_notnull(); + } + if (stat_info.update_time) + { + thd->variables.time_zone->gmt_sec_to_TIME(&time, + stat_info.update_time); + table->field[19]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); + table->field[19]->set_notnull(); + } + if (stat_info.check_time) + { + thd->variables.time_zone->gmt_sec_to_TIME(&time, stat_info.check_time); + table->field[20]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); + table->field[20]->set_notnull(); + } + if (file->table_flags() & (ulong) HA_HAS_CHECKSUM) + { + table->field[21]->store((longlong) stat_info.check_sum, TRUE); + table->field[21]->set_notnull(); + } + if (part_elem) + { + if (part_elem->part_comment) + table->field[22]->store(part_elem->part_comment, + strlen(part_elem->part_comment), cs); + else + table->field[22]->store(STRING_WITH_LEN("default"), cs); + if (part_elem->nodegroup_id != UNDEF_NODEGROUP) + table->field[23]->store((longlong) part_elem->nodegroup_id, TRUE); + else + table->field[23]->store(STRING_WITH_LEN("default"), cs); + if (part_elem->tablespace_name) + table->field[24]->store(part_elem->tablespace_name, + strlen(part_elem->tablespace_name), cs); + else + table->field[24]->store(STRING_WITH_LEN("default"), cs); + } + return; +} + + +static int get_schema_partitions_record(THD *thd, struct st_table_list *tables, + TABLE *table, bool res, + const char *base_name, + const char *file_name) +{ + CHARSET_INFO *cs= system_charset_info; + char buff[61]; + String tmp_res(buff, sizeof(buff), cs); + String tmp_str; + TIME time; + TABLE *show_table= tables->table; + handler *file; +#ifdef WITH_PARTITION_STORAGE_ENGINE + partition_info *part_info; +#endif + DBUG_ENTER("get_schema_partitions_record"); + + if (res) + { + if (!tables->view) + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + thd->net.last_errno, thd->net.last_error); + thd->clear_error(); + DBUG_RETURN(0); + } + file= show_table->file; +#ifdef WITH_PARTITION_STORAGE_ENGINE + part_info= show_table->part_info; + if (part_info) + { + partition_element *part_elem; + List_iterator<partition_element> part_it(part_info->partitions); + uint part_pos= 0, part_id= 0; + uint no_parts= part_info->no_parts; + handler *part_file; + + restore_record(table, s->default_values); + table->field[1]->store(base_name, strlen(base_name), cs); + table->field[2]->store(file_name, strlen(file_name), cs); + + + /* Partition method*/ + switch (part_info->part_type) { + case RANGE_PARTITION: + table->field[7]->store(partition_keywords[PKW_RANGE].str, + partition_keywords[PKW_RANGE].length, cs); + break; + case LIST_PARTITION: + table->field[7]->store(partition_keywords[PKW_LIST].str, + partition_keywords[PKW_LIST].length, cs); + break; + case HASH_PARTITION: + tmp_res.length(0); + if (part_info->linear_hash_ind) + tmp_res.append(partition_keywords[PKW_LINEAR].str, + partition_keywords[PKW_LINEAR].length); + if (part_info->list_of_part_fields) + tmp_res.append(partition_keywords[PKW_KEY].str, + partition_keywords[PKW_KEY].length); + else + tmp_res.append(partition_keywords[PKW_HASH].str, + partition_keywords[PKW_HASH].length); + table->field[7]->store(tmp_res.ptr(), tmp_res.length(), cs); + break; + default: + DBUG_ASSERT(0); + current_thd->fatal_error(); + DBUG_RETURN(1); + } + table->field[7]->set_notnull(); + + /* Partition expression */ + if (part_info->part_expr) + { + table->field[9]->store(part_info->part_func_string, + part_info->part_func_len, cs); + table->field[9]->set_notnull(); + } + else if (part_info->list_of_part_fields) + { + collect_partition_expr(part_info->part_field_list, &tmp_str); + table->field[9]->store(tmp_str.ptr(), tmp_str.length(), cs); + table->field[9]->set_notnull(); + } + + if (part_info->is_sub_partitioned()) + { + /* Subpartition method */ + if (part_info->list_of_subpart_fields) + table->field[8]->store(partition_keywords[PKW_KEY].str, + partition_keywords[PKW_KEY].length, cs); + else + table->field[8]->store(partition_keywords[PKW_HASH].str, + partition_keywords[PKW_HASH].length, cs); + table->field[8]->set_notnull(); + + /* Subpartition expression */ + if (part_info->subpart_expr) + { + table->field[10]->store(part_info->subpart_func_string, + part_info->subpart_func_len, cs); + table->field[10]->set_notnull(); + } + else if (part_info->list_of_subpart_fields) + { + collect_partition_expr(part_info->subpart_field_list, &tmp_str); + table->field[10]->store(tmp_str.ptr(), tmp_str.length(), cs); + table->field[10]->set_notnull(); + } + } + + while ((part_elem= part_it++)) + { + + + table->field[3]->store(part_elem->partition_name, + strlen(part_elem->partition_name), cs); + table->field[3]->set_notnull(); + /* PARTITION_ORDINAL_POSITION */ + table->field[5]->store((longlong) ++part_pos, TRUE); + table->field[5]->set_notnull(); + + /* Partition description */ + if (part_info->part_type == RANGE_PARTITION) + { + if (part_elem->range_value != LONGLONG_MAX) + table->field[11]->store((longlong) part_elem->range_value, FALSE); + else + table->field[11]->store(partition_keywords[PKW_MAXVALUE].str, + partition_keywords[PKW_MAXVALUE].length, cs); + table->field[11]->set_notnull(); + } + else if (part_info->part_type == LIST_PARTITION) + { + List_iterator<longlong> list_val_it(part_elem->list_val_list); + longlong *list_value; + uint no_items= part_elem->list_val_list.elements; + tmp_str.length(0); + tmp_res.length(0); + if (part_elem->has_null_value) + { + tmp_str.append("NULL"); + if (no_items > 0) + tmp_str.append(","); + } + while ((list_value= list_val_it++)) + { + tmp_res.set(*list_value, cs); + tmp_str.append(tmp_res); + if (--no_items != 0) + tmp_str.append(","); + }; + table->field[11]->store(tmp_str.ptr(), tmp_str.length(), cs); + table->field[11]->set_notnull(); + } + + if (part_elem->subpartitions.elements) + { + List_iterator<partition_element> sub_it(part_elem->subpartitions); + partition_element *subpart_elem; + uint subpart_pos= 0; + + while ((subpart_elem= sub_it++)) + { + table->field[4]->store(subpart_elem->partition_name, + strlen(subpart_elem->partition_name), cs); + table->field[4]->set_notnull(); + /* SUBPARTITION_ORDINAL_POSITION */ + table->field[6]->store((longlong) ++subpart_pos, TRUE); + table->field[6]->set_notnull(); + + store_schema_partitions_record(thd, table, subpart_elem, + file, part_id); + part_id++; + if(schema_table_store_record(thd, table)) + DBUG_RETURN(1); + } + } + else + { + store_schema_partitions_record(thd, table, part_elem, + file, part_id); + part_id++; + if(schema_table_store_record(thd, table)) + DBUG_RETURN(1); + } + } + DBUG_RETURN(0); + } + else +#endif + { + store_schema_partitions_record(thd, table, 0, file, 0); + if(schema_table_store_record(thd, table)) + DBUG_RETURN(1); + } + DBUG_RETURN(0); +} + + +static interval_type get_real_interval_type(interval_type i_type) +{ + switch (i_type) { + case INTERVAL_YEAR: + return INTERVAL_YEAR; + + case INTERVAL_QUARTER: + case INTERVAL_YEAR_MONTH: + case INTERVAL_MONTH: + return INTERVAL_MONTH; + + case INTERVAL_WEEK: + case INTERVAL_DAY: + return INTERVAL_DAY; + + case INTERVAL_DAY_HOUR: + case INTERVAL_HOUR: + return INTERVAL_HOUR; + + case INTERVAL_DAY_MINUTE: + case INTERVAL_HOUR_MINUTE: + case INTERVAL_MINUTE: + return INTERVAL_MINUTE; + + case INTERVAL_DAY_SECOND: + case INTERVAL_HOUR_SECOND: + case INTERVAL_MINUTE_SECOND: + case INTERVAL_SECOND: + return INTERVAL_SECOND; + + case INTERVAL_DAY_MICROSECOND: + case INTERVAL_HOUR_MICROSECOND: + case INTERVAL_MINUTE_MICROSECOND: + case INTERVAL_SECOND_MICROSECOND: + case INTERVAL_MICROSECOND: + return INTERVAL_MICROSECOND; + } + DBUG_ASSERT(0); + return INTERVAL_SECOND; +} + +extern LEX_STRING interval_type_to_name[]; + +static int +fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) +{ + const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS; + CHARSET_INFO *scs= system_charset_info; + TIME time; + Event_timed et; + DBUG_ENTER("fill_events_copy_to_schema_tab"); + + restore_record(sch_table, s->default_values); + + if (et.load_from_row(thd->mem_root, event_table)) + { + my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0)); + DBUG_RETURN(1); + } + + if (!(!wild || !wild[0] || !wild_compare(et.name.str, wild, 0))) + DBUG_RETURN(0); + + /* ->field[0] is EVENT_CATALOG and is by default NULL */ + + sch_table->field[1]->store(et.dbname.str, et.dbname.length, scs); + sch_table->field[2]->store(et.name.str, et.name.length, scs); + sch_table->field[3]->store(et.definer.str, et.definer.length, scs); + sch_table->field[4]->store(et.body.str, et.body.length, scs); + + /* [9] is SQL_MODE */ + { + byte *sql_mode_str; + ulong sql_mode_len=0; + sql_mode_str= + sys_var_thd_sql_mode::symbolic_mode_representation(thd, et.sql_mode, + &sql_mode_len); + sch_table->field[9]->store((const char*)sql_mode_str, sql_mode_len, scs); + } + + if (et.expression) + { + String show_str; + /* type */ + sch_table->field[5]->store(STRING_WITH_LEN("RECURRING"), scs); + + if (event_reconstruct_interval_expression(&show_str, et.interval, + et.expression)) + DBUG_RETURN(1); + + sch_table->field[7]->set_notnull(); + sch_table->field[7]->store(show_str.c_ptr(), show_str.length(), scs); + + LEX_STRING *ival= &interval_type_to_name[et.interval]; + sch_table->field[8]->set_notnull(); + sch_table->field[8]->store(ival->str, ival->length, scs); + + //starts & ends + sch_table->field[10]->set_notnull(); + sch_table->field[10]->store_time(&et.starts, MYSQL_TIMESTAMP_DATETIME); + + if (!et.ends_null) + { + sch_table->field[11]->set_notnull(); + sch_table->field[11]->store_time(&et.ends, MYSQL_TIMESTAMP_DATETIME); + } + } + else + { + //type + sch_table->field[5]->store(STRING_WITH_LEN("ONE TIME"), scs); + + sch_table->field[6]->set_notnull(); + sch_table->field[6]->store_time(&et.execute_at, MYSQL_TIMESTAMP_DATETIME); + } + + //status + if (et.status == MYSQL_EVENT_ENABLED) + sch_table->field[12]->store(STRING_WITH_LEN("ENABLED"), scs); + else + sch_table->field[12]->store(STRING_WITH_LEN("DISABLED"), scs); + + //on_completion + if (et.on_completion == MYSQL_EVENT_ON_COMPLETION_DROP) + sch_table->field[13]->store(STRING_WITH_LEN("NOT PRESERVE"), scs); + else + sch_table->field[13]->store(STRING_WITH_LEN("PRESERVE"), scs); + + int not_used=0; + number_to_datetime(et.created, &time, 0, ¬_used); + DBUG_ASSERT(not_used==0); + sch_table->field[14]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); + + number_to_datetime(et.modified, &time, 0, ¬_used); + DBUG_ASSERT(not_used==0); + sch_table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); + + if (et.last_executed.year) + { + sch_table->field[16]->set_notnull(); + sch_table->field[16]->store_time(&et.last_executed,MYSQL_TIMESTAMP_DATETIME); + } + + sch_table->field[17]->store(et.comment.str, et.comment.length, scs); + + if (schema_table_store_record(thd, sch_table)) + DBUG_RETURN(1); + + DBUG_RETURN(0); +} + + +int fill_schema_events(THD *thd, TABLE_LIST *tables, COND *cond) +{ + TABLE *table= tables->table; + CHARSET_INFO *scs= system_charset_info; + TABLE *event_table= NULL; + Open_tables_state backup; + int ret=0; + bool verbose= false; + char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2]; + bool use_prefix_scanning= true; + uint key_len= 0; + byte *key_buf= NULL; + LINT_INIT(key_buf); + + DBUG_ENTER("fill_schema_events"); + + strxmov(definer, thd->security_ctx->priv_user,"@",thd->security_ctx->priv_host, + NullS); + + DBUG_PRINT("info",("db=%s current_user=%s", thd->lex->select_lex.db, definer)); + + thd->reset_n_backup_open_tables_state(&backup); + + if ((ret= evex_open_event_table(thd, TL_READ, &event_table))) + { + sql_print_error("Table mysql.event is damaged."); + ret= 1; + goto err; + } + + event_table->file->ha_index_init(0, 1); + + /* + see others' events only if you have PROCESS_ACL !! + thd->lex->verbose is set either if SHOW FULL EVENTS or + in case of SELECT FROM I_S.EVENTS + */ + verbose= (thd->lex->verbose + && (thd->security_ctx->master_access & PROCESS_ACL)); + + if (verbose && thd->security_ctx->user) + { + ret= event_table->file->index_first(event_table->record[0]); + use_prefix_scanning= false; + } + else + { + event_table->field[EVEX_FIELD_DEFINER]->store(definer, strlen(definer), scs); + key_len= event_table->key_info->key_part[0].store_length; + + if (thd->lex->select_lex.db) + { + event_table->field[EVEX_FIELD_DB]-> + store(thd->lex->select_lex.db, strlen(thd->lex->select_lex.db), scs); + key_len+= event_table->key_info->key_part[1].store_length; + } + if (!(key_buf= (byte *)alloc_root(thd->mem_root, key_len))) + { + ret= 1; + goto err; + } + + key_copy(key_buf, event_table->record[0], event_table->key_info, key_len); + ret= event_table->file->index_read(event_table->record[0], key_buf, key_len, + HA_READ_PREFIX); + } + + if (ret) + { + ret= (ret == HA_ERR_END_OF_FILE || ret == HA_ERR_KEY_NOT_FOUND) ? 0 : 1; + goto err; + } + + while (!ret) + { + if ((ret= fill_events_copy_to_schema_table(thd, table, event_table))) + goto err; + + if (use_prefix_scanning) + ret= event_table->file-> + index_next_same(event_table->record[0], key_buf, key_len); + else + ret= event_table->file->index_next(event_table->record[0]); + } + // ret is guaranteed to be != 0 + ret= (ret != HA_ERR_END_OF_FILE); +err: + if (event_table) + { + event_table->file->ha_index_end(); + close_thread_tables(thd); + } + + thd->restore_backup_open_tables_state(&backup); + DBUG_RETURN(ret); +} + + int fill_open_tables(THD *thd, TABLE_LIST *tables, COND *cond) { DBUG_ENTER("fill_open_tables"); @@ -3414,7 +4259,7 @@ int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond) LEX *lex= thd->lex; const char *wild= lex->wild ? lex->wild->ptr() : NullS; pthread_mutex_lock(&LOCK_global_system_variables); - res= show_status_array(thd, wild, init_vars, + res= show_status_array(thd, wild, init_vars, lex->option_type, 0, "", tables->table); pthread_mutex_unlock(&LOCK_global_system_variables); DBUG_RETURN(res); @@ -3428,12 +4273,13 @@ int fill_status(THD *thd, TABLE_LIST *tables, COND *cond) const char *wild= lex->wild ? lex->wild->ptr() : NullS; int res= 0; STATUS_VAR tmp; - ha_update_statistics(); /* Export engines statistics */ pthread_mutex_lock(&LOCK_status); if (lex->option_type == OPT_GLOBAL) calc_sum_of_all_status(&tmp); - res= show_status_array(thd, wild, status_vars, OPT_GLOBAL, - (lex->option_type == OPT_GLOBAL ? + res= show_status_array(thd, wild, + (SHOW_VAR *)all_status_vars.buffer, + OPT_GLOBAL, + (lex->option_type == OPT_GLOBAL ? &tmp: &thd->status_var), "",tables->table); pthread_mutex_unlock(&LOCK_status); DBUG_RETURN(res); @@ -3441,6 +4287,75 @@ int fill_status(THD *thd, TABLE_LIST *tables, COND *cond) /* + Fill and store records into I_S.referential_constraints table + + SYNOPSIS + get_referential_constraints_record() + thd thread handle + tables table list struct(processed table) + table I_S table + res 1 means the error during opening of the processed table + 0 means processed table is opened without error + base_name db name + file_name table name + + RETURN + 0 ok + # error +*/ + +static int +get_referential_constraints_record(THD *thd, struct st_table_list *tables, + TABLE *table, bool res, + const char *base_name, const char *file_name) +{ + CHARSET_INFO *cs= system_charset_info; + DBUG_ENTER("get_referential_constraints_record"); + + if (res) + { + if (!tables->view) + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + thd->net.last_errno, thd->net.last_error); + thd->clear_error(); + DBUG_RETURN(0); + } + if (!tables->view) + { + List<FOREIGN_KEY_INFO> f_key_list; + TABLE *show_table= tables->table; + show_table->file->info(HA_STATUS_VARIABLE | + HA_STATUS_NO_LOCK | + HA_STATUS_TIME); + + show_table->file->get_foreign_key_list(thd, &f_key_list); + FOREIGN_KEY_INFO *f_key_info; + List_iterator_fast<FOREIGN_KEY_INFO> it(f_key_list); + while ((f_key_info= it++)) + { + restore_record(table, s->default_values); + table->field[1]->store(base_name, strlen(base_name), cs); + table->field[9]->store(file_name, strlen(file_name), cs); + table->field[2]->store(f_key_info->forein_id->str, + f_key_info->forein_id->length, cs); + table->field[4]->store(f_key_info->referenced_db->str, + f_key_info->referenced_db->length, cs); + table->field[5]->store(f_key_info->referenced_table->str, + f_key_info->referenced_table->length, cs); + 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); + if (schema_table_store_record(thd, table)) + DBUG_RETURN(1); + } + } + DBUG_RETURN(0); +} + + +/* Find schema_tables elment by name SYNOPSIS @@ -3765,8 +4680,8 @@ int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list) table->alias_name_used= my_strcasecmp(table_alias_charset, table_list->schema_table_name, table_list->alias); - table_list->table_name= (char*) table->s->table_name; - table_list->table_name_length= strlen(table->s->table_name); + table_list->table_name= table->s->table_name.str; + table_list->table_name_length= table->s->table_name.length; table_list->table= table; table->next= thd->derived_tables; thd->derived_tables= table; @@ -3835,6 +4750,7 @@ int make_schema_select(THD *thd, SELECT_LEX *sel, ST_SCHEMA_TABLE *schema_table= get_schema_table(schema_table_idx); LEX_STRING db, table; DBUG_ENTER("mysql_schema_select"); + DBUG_PRINT("enter", ("mysql_schema_select: %s", schema_table->table_name)); /* We have to make non const db_name & table_name because of lower_case_table_names @@ -3913,6 +4829,38 @@ bool get_schema_tables_result(JOIN *join) DBUG_RETURN(result); } +struct run_hton_fill_schema_files_args +{ + TABLE_LIST *tables; + COND *cond; +}; + +static my_bool run_hton_fill_schema_files(THD *thd, st_plugin_int *plugin, + void *arg) +{ + struct run_hton_fill_schema_files_args *args= + (run_hton_fill_schema_files_args *) arg; + handlerton *hton= (handlerton *) plugin->plugin->info; + if(hton->fill_files_table) + hton->fill_files_table(thd, args->tables, args->cond); + return false; +} + +int fill_schema_files(THD *thd, TABLE_LIST *tables, COND *cond) +{ + int i; + TABLE *table= tables->table; + DBUG_ENTER("fill_schema_files"); + + struct run_hton_fill_schema_files_args args; + args.tables= tables; + args.cond= cond; + + plugin_foreach(thd, run_hton_fill_schema_files, + MYSQL_STORAGE_ENGINE_PLUGIN, &args); + + DBUG_RETURN(0); +} ST_FIELD_INFO schema_fields_info[]= { @@ -3999,6 +4947,43 @@ ST_FIELD_INFO collation_fields_info[]= }; +ST_FIELD_INFO engines_fields_info[]= +{ + {"ENGINE", 64, MYSQL_TYPE_STRING, 0, 0, "Engine"}, + {"SUPPORT", 8, MYSQL_TYPE_STRING, 0, 0, "Support"}, + {"COMMENT", 80, MYSQL_TYPE_STRING, 0, 0, "Comment"}, + {"TRANSACTIONS", 3, MYSQL_TYPE_STRING, 0, 0, "Transactions"}, + {"XA", 3, MYSQL_TYPE_STRING, 0, 0, "XA"}, + {"SAVEPOINTS", 3 ,MYSQL_TYPE_STRING, 0, 0, "Savepoints"}, + {0, 0, MYSQL_TYPE_STRING, 0, 0, 0} +}; + + +ST_FIELD_INFO events_fields_info[]= +{ + {"EVENT_CATALOG", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0}, + {"EVENT_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Db"}, + {"EVENT_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Name"}, + {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, "Definer"}, + {"EVENT_BODY", 65535, MYSQL_TYPE_STRING, 0, 0, 0}, + {"EVENT_TYPE", 9, MYSQL_TYPE_STRING, 0, 0, "Type"}, + {"EXECUTE_AT", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Execute at"}, + {"INTERVAL_VALUE", 256, MYSQL_TYPE_STRING, 0, 1, "Interval value"}, + {"INTERVAL_FIELD", 18, MYSQL_TYPE_STRING, 0, 1, "Interval field"}, + {"SQL_MODE", 65535, MYSQL_TYPE_STRING, 0, 0, 0}, + {"STARTS", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Starts"}, + {"ENDS", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Ends"}, + {"STATUS", 8, MYSQL_TYPE_STRING, 0, 0, "Status"}, + {"ON_COMPLETION", 12, MYSQL_TYPE_STRING, 0, 0, 0}, + {"CREATED", 0, MYSQL_TYPE_TIMESTAMP, 0, 0, 0}, + {"LAST_ALTERED", 0, MYSQL_TYPE_TIMESTAMP, 0, 0, 0}, + {"LAST_EXECUTED", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, 0}, + {"EVENT_COMMENT", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {0, 0, MYSQL_TYPE_STRING, 0, 0, 0} +}; + + + ST_FIELD_INFO coll_charset_app_fields_info[]= { {"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 0, 0}, @@ -4189,6 +5174,37 @@ ST_FIELD_INFO triggers_fields_info[]= }; +ST_FIELD_INFO partitions_fields_info[]= +{ + {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0}, + {"TABLE_SCHEMA",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {"PARTITION_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0}, + {"SUBPARTITION_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0}, + {"PARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONG, 0, 1, 0}, + {"SUBPARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONG, 0, 1, 0}, + {"PARTITION_METHOD", 12, MYSQL_TYPE_STRING, 0, 1, 0}, + {"SUBPARTITION_METHOD", 5, MYSQL_TYPE_STRING, 0, 1, 0}, + {"PARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0}, + {"SUBPARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0}, + {"PARTITION_DESCRIPTION", 65535, MYSQL_TYPE_STRING, 0, 1, 0}, + {"TABLE_ROWS", 21 , MYSQL_TYPE_LONG, 0, 0, 0}, + {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 0, 0}, + {"DATA_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 0, 0}, + {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0}, + {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 0, 0}, + {"DATA_FREE", 21 , MYSQL_TYPE_LONG, 0, 0, 0}, + {"CREATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, 0}, + {"UPDATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, 0}, + {"CHECK_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, 0}, + {"CHECKSUM", 21 , MYSQL_TYPE_LONG, 0, 1, 0}, + {"PARTITION_COMMENT", 80, MYSQL_TYPE_STRING, 0, 0, 0}, + {"NODEGROUP", 21 , MYSQL_TYPE_LONG, 0, 0, 0}, + {"TABLESPACE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {0, 0, MYSQL_TYPE_STRING, 0, 0, 0} +}; + + ST_FIELD_INFO variables_fields_info[]= { {"Variable_name", 80, MYSQL_TYPE_STRING, 0, 0, "Variable_name"}, @@ -4197,8 +5213,98 @@ ST_FIELD_INFO variables_fields_info[]= }; +ST_FIELD_INFO processlist_fields_info[]= +{ + {"ID", 4, MYSQL_TYPE_LONG, 0, 0, "Id"}, + {"USER", 16, MYSQL_TYPE_STRING, 0, 0, "User"}, + {"HOST", LIST_PROCESS_HOST_LEN, MYSQL_TYPE_STRING, 0, 0, "Host"}, + {"DB", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, "Db"}, + {"COMMAND", 16, MYSQL_TYPE_STRING, 0, 0, "Command"}, + {"TIME", 7, MYSQL_TYPE_LONG, 0, 0, "Time"}, + {"STATE", 30, MYSQL_TYPE_STRING, 0, 1, "State"}, + {"INFO", PROCESS_LIST_INFO_WIDTH, MYSQL_TYPE_STRING, 0, 1, "Info"}, + {0, 0, MYSQL_TYPE_STRING, 0, 0, 0} +}; + + +ST_FIELD_INFO plugin_fields_info[]= +{ + {"PLUGIN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Name"}, + {"PLUGIN_VERSION", 20, MYSQL_TYPE_STRING, 0, 0, 0}, + {"PLUGIN_STATUS", 10, MYSQL_TYPE_STRING, 0, 0, "Status"}, + {"PLUGIN_TYPE", 80, MYSQL_TYPE_STRING, 0, 0, "Type"}, + {"PLUGIN_TYPE_VERSION", 20, MYSQL_TYPE_STRING, 0, 0, 0}, + {"PLUGIN_LIBRARY", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, "Library"}, + {"PLUGIN_LIBRARY_VERSION", 20, MYSQL_TYPE_STRING, 0, 1, 0}, + {"PLUGIN_AUTHOR", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0}, + {"PLUGIN_DESCRIPTION", 65535, MYSQL_TYPE_STRING, 0, 1, 0}, + {0, 0, MYSQL_TYPE_STRING, 0, 0, 0} +}; + +ST_FIELD_INFO files_fields_info[]= +{ + {"FILE_ID", 4, MYSQL_TYPE_LONG, 0, 0, 0}, + {"FILE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {"FILE_TYPE", 20, MYSQL_TYPE_STRING, 0, 0, 0}, + {"TABLESPACE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {"TABLE_CATALOG", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {"LOGFILE_GROUP_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {"LOGFILE_GROUP_NUMBER", 4, MYSQL_TYPE_LONG, 0, 0, 0}, + {"ENGINE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {"FULLTEXT_KEYS", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {"DELETED_ROWS", 4, MYSQL_TYPE_LONG, 0, 0, 0}, + {"UPDATE_COUNT", 4, MYSQL_TYPE_LONG, 0, 0, 0}, + {"FREE_EXTENTS", 4, MYSQL_TYPE_LONG, 0, 0, 0}, + {"TOTAL_EXTENTS", 4, MYSQL_TYPE_LONG, 0, 0, 0}, + {"EXTENT_SIZE", 4, MYSQL_TYPE_LONG, 0, 0, 0}, + {"INITIAL_SIZE", 8, MYSQL_TYPE_LONGLONG, 0, 0, 0}, + {"MAXIMUM_SIZE", 8, MYSQL_TYPE_LONGLONG, 0, 0, 0}, + {"AUTOEXTEND_SIZE", 8, MYSQL_TYPE_LONGLONG, 0, 0, 0}, + {"CREATION_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 0, 0}, + {"LAST_UPDATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 0, 0}, + {"LAST_ACCESS_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 0, 0}, + {"RECOVER_TIME", 4, MYSQL_TYPE_LONG, 0, 0, 0}, + {"TRANSACTION_COUNTER", 4, MYSQL_TYPE_LONG, 0, 0, 0}, + {"VERSION", 21 , MYSQL_TYPE_LONG, 0, 1, "Version"}, + {"ROW_FORMAT", 10, MYSQL_TYPE_STRING, 0, 1, "Row_format"}, + {"TABLE_ROWS", 21 , MYSQL_TYPE_LONG, 0, 1, "Rows"}, + {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Avg_row_length"}, + {"DATA_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Data_length"}, + {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Max_data_length"}, + {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Index_length"}, + {"DATA_FREE", 21 , MYSQL_TYPE_LONG, 0, 1, "Data_free"}, + {"CREATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Create_time"}, + {"UPDATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Update_time"}, + {"CHECK_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Check_time"}, + {"CHECKSUM", 21 , MYSQL_TYPE_LONG, 0, 1, "Checksum"}, + {"STATUS", 20, MYSQL_TYPE_STRING, 0, 0, 0}, + {"EXTRA", 255, MYSQL_TYPE_STRING, 0, 0, 0}, + {0, 0, MYSQL_TYPE_STRING, 0, 0, 0} +}; + +ST_FIELD_INFO referential_constraints_fields_info[]= +{ + {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0}, + {"CONSTRAINT_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {"CONSTRAINT_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {"UNIQUE_CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0}, + {"UNIQUE_CONSTRAINT_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {"UNIQUE_CONSTRAINT_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {"MATCH_OPTION", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {"UPDATE_RULE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {"DELETE_RULE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {0, 0, MYSQL_TYPE_STRING, 0, 0, 0} +}; + + /* Description of ST_FIELD_INFO in table.h + + Make sure that the order of schema_tables and enum_schema_tables are the same. + */ ST_SCHEMA_TABLE schema_tables[]= @@ -4213,10 +5319,25 @@ ST_SCHEMA_TABLE schema_tables[]= get_all_tables, make_columns_old_format, get_schema_column_record, 1, 2, 0}, {"COLUMN_PRIVILEGES", column_privileges_fields_info, create_schema_table, fill_schema_column_privileges, 0, 0, -1, -1, 0}, + {"ENGINES", engines_fields_info, create_schema_table, + fill_schema_engines, make_old_format, 0, -1, -1, 0}, + {"EVENTS", events_fields_info, create_schema_table, + fill_schema_events, make_old_format, 0, -1, -1, 0}, + {"FILES", files_fields_info, create_schema_table, + fill_schema_files, 0, 0, -1, -1, 0}, {"KEY_COLUMN_USAGE", key_column_usage_fields_info, create_schema_table, get_all_tables, 0, get_schema_key_column_usage_record, 4, 5, 0}, {"OPEN_TABLES", open_tables_fields_info, create_schema_table, fill_open_tables, make_old_format, 0, -1, -1, 1}, + {"PARTITIONS", partitions_fields_info, create_schema_table, + get_all_tables, 0, get_schema_partitions_record, 1, 2, 0}, + {"PLUGINS", plugin_fields_info, create_schema_table, + fill_plugins, make_old_format, 0, -1, -1, 0}, + {"PROCESSLIST", processlist_fields_info, create_schema_table, + fill_schema_processlist, make_old_format, 0, -1, -1, 0}, + {"REFERENTIAL_CONSTRAINTS", referential_constraints_fields_info, + create_schema_table, get_all_tables, 0, get_referential_constraints_record, + 1, 9, 0}, {"ROUTINES", proc_fields_info, create_schema_table, fill_schema_proc, make_proc_old_format, 0, -1, -1, 0}, {"SCHEMATA", schema_fields_info, create_schema_table, |