mirror of
https://github.com/MariaDB/server.git
synced 2025-05-29 21:42:28 +03:00
New multi-key-cache handling. This was needed becasue the old one didn't work reliable with MERGE tables. ALTER TABLE table_name ... CHARACTER SET ... now changes all char/varchar/text columns to the given character set (One must use ALTER TABLE ... DEFAULT CHARACTER SET ... to change the default character set) Fixed that have_compress is detected properly (fixes problems with func_compress.test on platforms without zlib) New syntax for CACHE INDEX ('keys' is optional if no index name is given and one mentions the key cache name only ones) Removed compiler warnings Added mysql_set_server_option() to allow clients like PHP to easaily set/reset the multi-statement flag. BUILD/compile-pentium-valgrind-max: Add test of isam client/mysql.cc: CLIENT_MULTI_QUERIES -> CLIENT_MULTI_STATEMENTS include/my_base.h: Remove HA_EXTRA_SET_KEY_CACHE include/my_no_pthread.h: Add defines to ignore rw-locks when running without threads include/my_sys.h: Added function for multi-key-caches include/myisam.h: Added function to handle multi-key-caches include/mysql.h: Added mysql_set_server_option include/mysql_com.h: CLIENT_MULTI_QUERIES -> CLIENT_MULTI_STATEMENTS Added enum_mysql_set_option include/mysqld_error.h: Added error message for unknown key cache innobase/srv/srv0start.c: Removed warning that is confused for MySQL users libmysql/libmysql.c: Added mysql_set_server_option() libmysql/libmysql.def: Added mysql_set_server_option() myisam/ft_nlq_search.c: Removed compiler warning myisam/ft_static.c: Removed compiler warning and fixed wrong return value myisam/mi_check.c: Clean up multi-key-cache usage myisam/mi_checksum.c: Removed not used variable myisam/mi_close.c: keycache -> key_cache myisam/mi_delete_all.c: keycache -> key_cache myisam/mi_extra.c: keycache -> key_cache Removed HA_EXTRA_SET_KEY_CACHE myisam/mi_keycache.c: Changed logic so that it's MyISAM that is responsible for assign tables to different key caches instead of the upper level myisam/mi_locking.c: Don't change key cache on unlock (must be done before) myisam/mi_open.c: Fetch key cache to use from multi_key_cache_search() myisam/mi_page.c: keycache -> key_cache myisam/mi_panic.c: keycache -> key_cache myisam/mi_preload.c: keycache -> key_cache myisam/mi_test1.c: Use KEY_CACHE_BLOCK_SIZE myisam/mi_test2.c: Always test resize_key_cache() myisam/mi_test3.c: Use KEY_CACHE_BLOCK_SIZE instead of 512 myisam/myisamchk.c: update for multiple key caches myisam/myisamdef.h: Remove reg_keycache Add unique_name_length for storing length of unique_file_name myisam/myisamlog.c: Change how end_key_cache() is called mysql-test/mysql-test-run.sh: Fixed web link Added name of failed test to abort row. mysql-test/r/alter_table.result: Testing of ALTER TABLE ... [DEFAULT] CHARACTER SET mysql-test/r/case.result: Update result for DEFAULT CHARSET... mysql-test/r/cast.result: Update result for DEFAULT CHARSET... mysql-test/r/create.result: Update result for DEFAULT CHARSET... mysql-test/r/ctype_collate.result: Update result for DEFAULT CHARSET... mysql-test/r/ctype_latin1_de.result: Update result for DEFAULT CHARSET... mysql-test/r/ctype_many.result: Update result for DEFAULT CHARSET... mysql-test/r/ctype_mb.result: Update result for DEFAULT CHARSET... mysql-test/r/ctype_recoding.result: Update result for DEFAULT CHARSET... mysql-test/r/ctype_ucs.result: Update result for DEFAULT CHARSET... mysql-test/r/derived.result: Use STRAIGHT_JOIN to make join order predictable mysql-test/r/fulltext.result: Update result for DEFAULT CHARSET... mysql-test/r/func_str.result: Update result for DEFAULT CHARSET... mysql-test/r/func_system.result: Update result for DEFAULT CHARSET... mysql-test/r/gis-rtree.result: Update result for DEFAULT CHARSET... mysql-test/r/innodb.result: Update result for DEFAULT CHARSET... mysql-test/r/key_cache.result: Update test for new key cache syntax. Added more tests mysql-test/r/merge.result: Update result for DEFAULT CHARSET... mysql-test/r/preload.result: New syntax mysql-test/r/show_check.result: Update result for DEFAULT CHARSET... mysql-test/r/sql_mode.result: Update result for DEFAULT CHARSET... mysql-test/r/subselect.result: Update result for DEFAULT CHARSET... mysql-test/r/type_blob.result: Update result for DEFAULT CHARSET... mysql-test/r/type_enum.result: Update result for DEFAULT CHARSET... mysql-test/r/type_nchar.result: Update result for DEFAULT CHARSET... mysql-test/r/type_set.result: Update result for DEFAULT CHARSET... mysql-test/r/union.result: Use STRAIGHT_JOIN to make join order predictable mysql-test/t/alter_table.test: Testing of ALTER TABLE ... [DEFAULT] CHARACTER SET mysql-test/t/ctype_many.test: Update result for DEFAULT CHARSET... mysql-test/t/derived.test: Use STRAIGHT_JOIN to make join order predictable mysql-test/t/isam.test: Use disable warnings for test loop mysql-test/t/join.test: Update test now when we only support 61 tables in join mysql-test/t/key_cache.test: Update test for new key cache syntax. Added more tests mysql-test/t/preload.test: Update for new syntax mysql-test/t/union.test: Use STRAIGHT_JOIN to make join order predictable mysys/Makefile.am: Added mf_keycaches.c mysys/hash.c: TRUE -> 1 mysys/mf_keycache.c: Removed compiler warnings Striped end space Fixed indentation and improved function comments TRUE -> 1 Changed parameters to end_key_cache() to make it easer to use Fixed bug when using key blocks size > 1024 bytes (First part of index file could be overwritten with wrong data) Split function flush_key_blocks into two functions to not get mutex used twice when called from flush_all_key_blocks() mysys/my_bitmap.c: More debugging Safe bitmap_free() Fixed indentation mysys/my_getopt.c: Ensure that we initialize option->value, option->max_value and value from GET_ASK_ADDR mysys/my_thr_init.c: Remove not used mutex THR_LOCK_keycache mysys/typelib.c: Fixed function comments sql-common/client.c: CLIENT_MULTI_QUERIES -> CLIENT_MULTI_STATEMENTS Fixed the multi_result flag is set also on SELECT;s sql/ha_myisam.cc: Fixed multiple key_cache handling (Now done on MyISAM level) sql/ha_myisammrg.cc: Fixed multiple key_cache handling (Now done on MyISAM level) sql/handler.cc: New multi key cache handling sql/handler.h: New multi key cache handling Added support for default character set sql/item.h: Added function cleanup() (Needed for prepared statements / cursors) sql/item_cmpfunc.h: Added cleanup function sql/item_func.cc: Indentation cleanup sql/mysql_priv.h: New multi-key-cache functions Removed LOCK_assign sql/mysqld.cc: New multi-key-cache handling Fixed that variable have_compress is set correctly sql/protocol.cc: SELECT didn't work reliable in multi-statements sql/set_var.cc: Support for new key cache variables sql/set_var.h: Support for new key cache variables sql/share/czech/errmsg.txt: New error messages sql/share/danish/errmsg.txt: New error messages sql/share/dutch/errmsg.txt: New error messages sql/share/english/errmsg.txt: New error messages sql/share/estonian/errmsg.txt: New error messages sql/share/french/errmsg.txt: New error messages sql/share/german/errmsg.txt: New error messages sql/share/greek/errmsg.txt: New error messages sql/share/hungarian/errmsg.txt: New error messages sql/share/italian/errmsg.txt: New error messages sql/share/japanese/errmsg.txt: New error messages sql/share/korean/errmsg.txt: New error messages sql/share/norwegian-ny/errmsg.txt: New error messages sql/share/norwegian/errmsg.txt: New error messages sql/share/polish/errmsg.txt: New error messages sql/share/portuguese/errmsg.txt: New error messages sql/share/romanian/errmsg.txt: New error messages sql/share/russian/errmsg.txt: New error messages sql/share/serbian/errmsg.txt: New error messages sql/share/slovak/errmsg.txt: New error messages sql/share/spanish/errmsg.txt: New error messages sql/share/swedish/errmsg.txt: New error messages sql/share/ukrainian/errmsg.txt: New error messages sql/sql_base.cc: Removed all key_cache handling (this is now done on MyISAM level) Change table_charset -> default_table_charset sql/sql_db.cc: table_charset -> default_table_charset sql/sql_delete.cc: table_charset -> default_table_charset sql/sql_lex.cc: CLIENT_MULTI_QUERIES -> CLIENT_MULTI_STATEMENTS sql/sql_lex.h: New option to store a name and length sql/sql_parse.cc: Support for mysql_set_server_option() Reset "default" keycache status variables in 'FLUSH STATUS' (Need to be improved later) sql/sql_show.cc: Add DEFAULT before CHARSET (for table character sets) Fetch key cache variables from 'sql_key_cache' sql/sql_table.cc: table_charset -> default_table_charset New multi-key-cache handling sql/sql_test.cc: Write information from all key caches sql/sql_yacc.yy: Changed syntax for CACHE INDEX ... Force user to use DEFAULT before database/table level character sets sql/structs.h: Added SHOW_KEY_CACHE_LONG (to get values from sql_key_cache) sql/table.cc: table_charset -> default_table_charset sql/table.h: New key cache handling (this is now done in mysys/mf_keycaches.c) sql/unireg.h: A
1880 lines
58 KiB
C++
1880 lines
58 KiB
C++
/* Copyright (C) 2000 MySQL AB
|
|
|
|
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
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
|
|
|
|
/* Function with list databases, tables or fields */
|
|
|
|
#include "mysql_priv.h"
|
|
#include "sql_select.h" // For select_describe
|
|
#include "sql_acl.h"
|
|
#include "repl_failsafe.h"
|
|
#include <my_dir.h>
|
|
|
|
#ifdef HAVE_BERKELEY_DB
|
|
#include "ha_berkeley.h" // For berkeley_show_logs
|
|
#endif
|
|
|
|
static const char *grant_names[]={
|
|
"select","insert","update","delete","create","drop","reload","shutdown",
|
|
"process","file","grant","references","index","alter"};
|
|
|
|
static TYPELIB grant_types = { sizeof(grant_names)/sizeof(char **),
|
|
"grant_types",
|
|
grant_names};
|
|
|
|
static int mysql_find_files(THD *thd,List<char> *files, const char *db,
|
|
const char *path, const char *wild, bool dir);
|
|
|
|
static int
|
|
store_create_info(THD *thd, TABLE *table, String *packet);
|
|
|
|
|
|
/*
|
|
Report list of databases
|
|
A database is a directory in the mysql_data_home directory
|
|
*/
|
|
|
|
int
|
|
mysqld_show_dbs(THD *thd,const char *wild)
|
|
{
|
|
Item_string *field=new Item_string("",0,thd->charset());
|
|
List<Item> field_list;
|
|
char *end;
|
|
List<char> files;
|
|
char *file_name;
|
|
Protocol *protocol= thd->protocol;
|
|
DBUG_ENTER("mysqld_show_dbs");
|
|
|
|
field->name=(char*) thd->alloc(20+ (wild ? (uint) strlen(wild)+4: 0));
|
|
field->max_length=NAME_LEN;
|
|
end=strmov(field->name,"Database");
|
|
if (wild && wild[0])
|
|
strxmov(end," (",wild,")",NullS);
|
|
field_list.push_back(field);
|
|
|
|
if (protocol->send_fields(&field_list,1))
|
|
DBUG_RETURN(1);
|
|
if (mysql_find_files(thd,&files,NullS,mysql_data_home,wild,1))
|
|
DBUG_RETURN(1);
|
|
List_iterator_fast<char> it(files);
|
|
|
|
while ((file_name=it++))
|
|
{
|
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
|
if (thd->master_access & (DB_ACLS | SHOW_DB_ACL) ||
|
|
acl_get(thd->host, thd->ip, thd->priv_user, file_name,0) ||
|
|
(grant_option && !check_grant_db(thd, file_name)))
|
|
#endif
|
|
{
|
|
protocol->prepare_for_resend();
|
|
protocol->store(file_name, system_charset_info);
|
|
if (protocol->write())
|
|
DBUG_RETURN(-1);
|
|
}
|
|
}
|
|
send_eof(thd);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
List all open tables in a database
|
|
***************************************************************************/
|
|
|
|
int mysqld_show_open_tables(THD *thd,const char *wild)
|
|
{
|
|
List<Item> field_list;
|
|
OPEN_TABLE_LIST *open_list;
|
|
Protocol *protocol= thd->protocol;
|
|
DBUG_ENTER("mysqld_show_open_tables");
|
|
|
|
field_list.push_back(new Item_empty_string("Database",NAME_LEN));
|
|
field_list.push_back(new Item_empty_string("Table",NAME_LEN));
|
|
field_list.push_back(new Item_return_int("In_use", 1, MYSQL_TYPE_TINY));
|
|
field_list.push_back(new Item_return_int("Name_locked", 4, MYSQL_TYPE_TINY));
|
|
|
|
if (protocol->send_fields(&field_list,1))
|
|
DBUG_RETURN(1);
|
|
|
|
if (!(open_list=list_open_tables(thd,wild)) && thd->is_fatal_error)
|
|
DBUG_RETURN(-1);
|
|
|
|
for (; open_list ; open_list=open_list->next)
|
|
{
|
|
protocol->prepare_for_resend();
|
|
protocol->store(open_list->db, system_charset_info);
|
|
protocol->store(open_list->table, system_charset_info);
|
|
protocol->store_tiny((longlong) open_list->in_use);
|
|
protocol->store_tiny((longlong) open_list->locked);
|
|
if (protocol->write())
|
|
{
|
|
DBUG_RETURN(-1);
|
|
}
|
|
}
|
|
send_eof(thd);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
** List all tables in a database (fast version)
|
|
** A table is a .frm file in the current databasedir
|
|
***************************************************************************/
|
|
|
|
int mysqld_show_tables(THD *thd,const char *db,const char *wild)
|
|
{
|
|
Item_string *field=new Item_string("",0,thd->charset());
|
|
List<Item> field_list;
|
|
char path[FN_LEN],*end;
|
|
List<char> files;
|
|
char *file_name;
|
|
Protocol *protocol= thd->protocol;
|
|
DBUG_ENTER("mysqld_show_tables");
|
|
|
|
field->name=(char*) thd->alloc(20+(uint) strlen(db)+
|
|
(wild ? (uint) strlen(wild)+4:0));
|
|
end=strxmov(field->name,"Tables_in_",db,NullS);
|
|
if (wild && wild[0])
|
|
strxmov(end," (",wild,")",NullS);
|
|
field->max_length=NAME_LEN;
|
|
(void) sprintf(path,"%s/%s",mysql_data_home,db);
|
|
(void) unpack_dirname(path,path);
|
|
field_list.push_back(field);
|
|
if (protocol->send_fields(&field_list,1))
|
|
DBUG_RETURN(1);
|
|
if (mysql_find_files(thd,&files,db,path,wild,0))
|
|
DBUG_RETURN(-1);
|
|
List_iterator_fast<char> it(files);
|
|
while ((file_name=it++))
|
|
{
|
|
protocol->prepare_for_resend();
|
|
protocol->store(file_name, system_charset_info);
|
|
if (protocol->write())
|
|
DBUG_RETURN(-1);
|
|
}
|
|
send_eof(thd);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/***************************************************************************
|
|
** List all table types supported
|
|
***************************************************************************/
|
|
|
|
struct show_table_type_st {
|
|
const char *type;
|
|
SHOW_COMP_OPTION *value;
|
|
const char *comment;
|
|
};
|
|
|
|
|
|
SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES;
|
|
|
|
static struct show_table_type_st sys_table_types[]=
|
|
{
|
|
{"MyISAM", &have_yes,
|
|
"Default type from 3.23 with great performance"},
|
|
{"HEAP" , &have_yes,
|
|
"Hash based, stored in memory, useful for temporary tables"},
|
|
{"MERGE", &have_yes,
|
|
"Collection of identical MyISAM tables"},
|
|
{"ISAM", &have_isam,
|
|
"Obsolete table type; Is replaced by MyISAM"},
|
|
{"InnoDB", &have_innodb,
|
|
"Supports transactions, row-level locking and foreign keys"},
|
|
{"BDB", &have_berkeley_db,
|
|
"Supports transactions and page-level locking"},
|
|
{NullS, NULL, NullS}
|
|
};
|
|
|
|
|
|
int mysqld_show_table_types(THD *thd)
|
|
{
|
|
List<Item> field_list;
|
|
Protocol *protocol= thd->protocol;
|
|
DBUG_ENTER("mysqld_show_table_types");
|
|
|
|
field_list.push_back(new Item_empty_string("Type",10));
|
|
field_list.push_back(new Item_empty_string("Support",10));
|
|
field_list.push_back(new Item_empty_string("Comment",80));
|
|
|
|
if (protocol->send_fields(&field_list,1))
|
|
DBUG_RETURN(1);
|
|
|
|
const char *default_type_name=
|
|
ha_table_typelib.type_names[thd->variables.table_type];
|
|
|
|
show_table_type_st *types;
|
|
for (types= sys_table_types; types->type; types++)
|
|
{
|
|
protocol->prepare_for_resend();
|
|
protocol->store(types->type, system_charset_info);
|
|
const char *option_name= show_comp_option_name[(int) *types->value];
|
|
|
|
if (*types->value == SHOW_OPTION_YES &&
|
|
!my_strcasecmp(system_charset_info, default_type_name, types->type))
|
|
option_name= "DEFAULT";
|
|
protocol->store(option_name, system_charset_info);
|
|
protocol->store(types->comment, system_charset_info);
|
|
if (protocol->write())
|
|
DBUG_RETURN(-1);
|
|
}
|
|
send_eof(thd);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
List all privileges supported
|
|
***************************************************************************/
|
|
|
|
struct show_privileges_st {
|
|
const char *privilege;
|
|
const char *context;
|
|
const char *comment;
|
|
};
|
|
|
|
|
|
/*
|
|
TODO: Update with new privileges
|
|
*/
|
|
static struct show_privileges_st sys_privileges[]=
|
|
{
|
|
{"Select", "Tables", "To retrieve rows from table"},
|
|
{"Insert", "Tables", "To insert data into tables"},
|
|
{"Update", "Tables", "To update existing rows "},
|
|
{"Delete", "Tables", "To delete existing rows"},
|
|
{"Index", "Tables", "To create or drop indexes"},
|
|
{"Alter", "Tables", "To alter the table"},
|
|
{"Create", "Databases,Tables,Indexes", "To create new databases and tables"},
|
|
{"Drop", "Databases,Tables", "To drop databases and tables"},
|
|
{"Grant", "Databases,Tables", "To give to other users those privileges you possess"},
|
|
{"References", "Databases,Tables", "To have references on tables"},
|
|
{"Reload", "Server Admin", "To reload or refresh tables, logs and privileges"},
|
|
{"Shutdown","Server Admin", "To shutdown the server"},
|
|
{"Process", "Server Admin", "To view the plain text of currently executing queries"},
|
|
{"File", "File access on server", "To read and write files on the server"},
|
|
{NullS, NullS, NullS}
|
|
};
|
|
|
|
|
|
int mysqld_show_privileges(THD *thd)
|
|
{
|
|
List<Item> field_list;
|
|
Protocol *protocol= thd->protocol;
|
|
DBUG_ENTER("mysqld_show_privileges");
|
|
|
|
field_list.push_back(new Item_empty_string("Privilege",10));
|
|
field_list.push_back(new Item_empty_string("Context",15));
|
|
field_list.push_back(new Item_empty_string("Comment",NAME_LEN));
|
|
|
|
if (protocol->send_fields(&field_list,1))
|
|
DBUG_RETURN(1);
|
|
|
|
show_privileges_st *privilege= sys_privileges;
|
|
for (privilege= sys_privileges; privilege->privilege ; privilege++)
|
|
{
|
|
protocol->prepare_for_resend();
|
|
protocol->store(privilege->privilege, system_charset_info);
|
|
protocol->store(privilege->context, system_charset_info);
|
|
protocol->store(privilege->comment, system_charset_info);
|
|
if (protocol->write())
|
|
DBUG_RETURN(-1);
|
|
}
|
|
send_eof(thd);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
List all column types
|
|
***************************************************************************/
|
|
|
|
struct show_column_type_st
|
|
{
|
|
const char *type;
|
|
uint size;
|
|
const char *min_value;
|
|
const char *max_value;
|
|
uint precision;
|
|
uint scale;
|
|
const char *nullable;
|
|
const char *auto_increment;
|
|
const char *unsigned_attr;
|
|
const char *zerofill;
|
|
const char *searchable;
|
|
const char *case_sensitivity;
|
|
const char *default_value;
|
|
const char *comment;
|
|
};
|
|
|
|
/* TODO: Add remaning types */
|
|
|
|
static struct show_column_type_st sys_column_types[]=
|
|
{
|
|
{"tinyint",
|
|
1, "-128", "127", 0, 0, "YES", "YES",
|
|
"NO", "YES", "YES", "NO", "NULL,0",
|
|
"A very small integer"},
|
|
{"tinyint unsigned",
|
|
1, "0" , "255", 0, 0, "YES", "YES",
|
|
"YES", "YES", "YES", "NO", "NULL,0",
|
|
"A very small integer"},
|
|
};
|
|
|
|
int mysqld_show_column_types(THD *thd)
|
|
{
|
|
List<Item> field_list;
|
|
Protocol *protocol= thd->protocol;
|
|
DBUG_ENTER("mysqld_show_column_types");
|
|
|
|
field_list.push_back(new Item_empty_string("Type",30));
|
|
field_list.push_back(new Item_int("Size",(longlong) 1,21));
|
|
field_list.push_back(new Item_empty_string("Min_Value",20));
|
|
field_list.push_back(new Item_empty_string("Max_Value",20));
|
|
field_list.push_back(new Item_return_int("Prec", 4, MYSQL_TYPE_SHORT));
|
|
field_list.push_back(new Item_return_int("Scale", 4, MYSQL_TYPE_SHORT));
|
|
field_list.push_back(new Item_empty_string("Nullable",4));
|
|
field_list.push_back(new Item_empty_string("Auto_Increment",4));
|
|
field_list.push_back(new Item_empty_string("Unsigned",4));
|
|
field_list.push_back(new Item_empty_string("Zerofill",4));
|
|
field_list.push_back(new Item_empty_string("Searchable",4));
|
|
field_list.push_back(new Item_empty_string("Case_Sensitive",4));
|
|
field_list.push_back(new Item_empty_string("Default",NAME_LEN));
|
|
field_list.push_back(new Item_empty_string("Comment",NAME_LEN));
|
|
|
|
if (protocol->send_fields(&field_list,1))
|
|
DBUG_RETURN(1);
|
|
|
|
/* TODO: Change the loop to not use 'i' */
|
|
for (uint i=0; i < sizeof(sys_column_types)/sizeof(sys_column_types[0]); i++)
|
|
{
|
|
protocol->prepare_for_resend();
|
|
protocol->store(sys_column_types[i].type, system_charset_info);
|
|
protocol->store((ulonglong) sys_column_types[i].size);
|
|
protocol->store(sys_column_types[i].min_value, system_charset_info);
|
|
protocol->store(sys_column_types[i].max_value, system_charset_info);
|
|
protocol->store_short((longlong) sys_column_types[i].precision);
|
|
protocol->store_short((longlong) sys_column_types[i].scale);
|
|
protocol->store(sys_column_types[i].nullable, system_charset_info);
|
|
protocol->store(sys_column_types[i].auto_increment, system_charset_info);
|
|
protocol->store(sys_column_types[i].unsigned_attr, system_charset_info);
|
|
protocol->store(sys_column_types[i].zerofill, system_charset_info);
|
|
protocol->store(sys_column_types[i].searchable, system_charset_info);
|
|
protocol->store(sys_column_types[i].case_sensitivity, system_charset_info);
|
|
protocol->store(sys_column_types[i].default_value, system_charset_info);
|
|
protocol->store(sys_column_types[i].comment, system_charset_info);
|
|
if (protocol->write())
|
|
DBUG_RETURN(-1);
|
|
}
|
|
send_eof(thd);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
static int
|
|
mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
|
|
const char *wild, bool dir)
|
|
{
|
|
uint i;
|
|
char *ext;
|
|
MY_DIR *dirp;
|
|
FILEINFO *file;
|
|
uint col_access=thd->col_access;
|
|
TABLE_LIST table_list;
|
|
DBUG_ENTER("mysql_find_files");
|
|
|
|
if (wild && !wild[0])
|
|
wild=0;
|
|
bzero((char*) &table_list,sizeof(table_list));
|
|
|
|
if (!(dirp = my_dir(path,MYF(MY_WME | (dir ? MY_WANT_STAT : 0)))))
|
|
DBUG_RETURN(-1);
|
|
|
|
for (i=0 ; i < (uint) dirp->number_off_files ; i++)
|
|
{
|
|
file=dirp->dir_entry+i;
|
|
if (dir)
|
|
{ /* Return databases */
|
|
#ifdef USE_SYMDIR
|
|
char *ext;
|
|
if (my_use_symdir && !strcmp(ext=fn_ext(file->name), ".sym"))
|
|
*ext=0; /* Remove extension */
|
|
else
|
|
#endif
|
|
{
|
|
if (file->name[0] == '.' || !MY_S_ISDIR(file->mystat.st_mode) ||
|
|
(wild && wild_compare(file->name,wild,0)))
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Return only .frm files which aren't temp files.
|
|
if (my_strcasecmp(system_charset_info, ext=fn_ext(file->name),reg_ext) ||
|
|
is_prefix(file->name,tmp_file_prefix))
|
|
continue;
|
|
*ext=0;
|
|
if (wild)
|
|
{
|
|
if (lower_case_table_names)
|
|
{
|
|
if (wild_case_compare(system_charset_info,file->name,wild))
|
|
continue;
|
|
}
|
|
else if (wild_compare(file->name,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.real_name=file->name;
|
|
table_list.grant.privilege=col_access;
|
|
if (check_grant(thd,TABLE_ACLS,&table_list,1,1))
|
|
continue;
|
|
}
|
|
#endif
|
|
if (files->push_back(thd->strdup(file->name)))
|
|
{
|
|
my_dirend(dirp);
|
|
DBUG_RETURN(-1);
|
|
}
|
|
}
|
|
DBUG_PRINT("info",("found: %d files", files->elements));
|
|
my_dirend(dirp);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Extended version of mysqld_show_tables
|
|
***************************************************************************/
|
|
|
|
int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
|
|
{
|
|
Item *item;
|
|
List<char> files;
|
|
List<Item> field_list;
|
|
char path[FN_LEN];
|
|
char *file_name;
|
|
TABLE *table;
|
|
Protocol *protocol= thd->protocol;
|
|
TIME time;
|
|
DBUG_ENTER("mysqld_extend_show_tables");
|
|
|
|
(void) sprintf(path,"%s/%s",mysql_data_home,db);
|
|
(void) unpack_dirname(path,path);
|
|
field_list.push_back(item=new Item_empty_string("Name",NAME_LEN));
|
|
field_list.push_back(item=new Item_empty_string("Type",10));
|
|
item->maybe_null=1;
|
|
field_list.push_back(item=new Item_empty_string("Row_format",10));
|
|
item->maybe_null=1;
|
|
field_list.push_back(item=new Item_int("Rows",(longlong) 1,21));
|
|
item->maybe_null=1;
|
|
field_list.push_back(item=new Item_int("Avg_row_length",(int32) 0,21));
|
|
item->maybe_null=1;
|
|
field_list.push_back(item=new Item_int("Data_length",(longlong) 1,21));
|
|
item->maybe_null=1;
|
|
field_list.push_back(item=new Item_int("Max_data_length",(longlong) 1,21));
|
|
item->maybe_null=1;
|
|
field_list.push_back(item=new Item_int("Index_length",(longlong) 1,21));
|
|
item->maybe_null=1;
|
|
field_list.push_back(item=new Item_int("Data_free",(longlong) 1,21));
|
|
item->maybe_null=1;
|
|
field_list.push_back(item=new Item_int("Auto_increment",(longlong) 1,21));
|
|
item->maybe_null=1;
|
|
field_list.push_back(item=new Item_datetime("Create_time"));
|
|
item->maybe_null=1;
|
|
field_list.push_back(item=new Item_datetime("Update_time"));
|
|
item->maybe_null=1;
|
|
field_list.push_back(item=new Item_datetime("Check_time"));
|
|
item->maybe_null=1;
|
|
field_list.push_back(item=new Item_empty_string("Collation",32));
|
|
item->maybe_null=1;
|
|
field_list.push_back(item=new Item_int("Checksum",(longlong) 1,21));
|
|
item->maybe_null=1;
|
|
field_list.push_back(item=new Item_empty_string("Create_options",255));
|
|
item->maybe_null=1;
|
|
field_list.push_back(item=new Item_empty_string("Comment",80));
|
|
item->maybe_null=1;
|
|
if (protocol->send_fields(&field_list,1))
|
|
DBUG_RETURN(1);
|
|
|
|
if (mysql_find_files(thd,&files,db,path,wild,0))
|
|
DBUG_RETURN(-1);
|
|
List_iterator_fast<char> it(files);
|
|
while ((file_name=it++))
|
|
{
|
|
TABLE_LIST table_list;
|
|
bzero((char*) &table_list,sizeof(table_list));
|
|
protocol->prepare_for_resend();
|
|
protocol->store(file_name, system_charset_info);
|
|
table_list.db=(char*) db;
|
|
table_list.real_name= table_list.alias= file_name;
|
|
if (lower_case_table_names)
|
|
my_casedn_str(files_charset_info, file_name);
|
|
if (!(table = open_ltable(thd, &table_list, TL_READ)))
|
|
{
|
|
for (uint i=2 ; i < field_list.elements ; i++)
|
|
protocol->store_null();
|
|
// Send error to Comment field
|
|
protocol->store(thd->net.last_error, system_charset_info);
|
|
thd->net.last_error[0]=0;
|
|
}
|
|
else
|
|
{
|
|
struct tm tm_tmp;
|
|
const char *str;
|
|
handler *file=table->file;
|
|
file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_NO_LOCK);
|
|
protocol->store(file->table_type(), system_charset_info);
|
|
str= ((table->db_options_in_use & HA_OPTION_COMPRESS_RECORD) ?
|
|
"Compressed" :
|
|
(table->db_options_in_use & HA_OPTION_PACK_RECORD) ?
|
|
"Dynamic" : "Fixed");
|
|
protocol->store(str, system_charset_info);
|
|
protocol->store((ulonglong) file->records);
|
|
protocol->store((ulonglong) file->mean_rec_length);
|
|
protocol->store((ulonglong) file->data_file_length);
|
|
if (file->max_data_file_length)
|
|
protocol->store((ulonglong) file->max_data_file_length);
|
|
else
|
|
protocol->store_null();
|
|
protocol->store((ulonglong) file->index_file_length);
|
|
protocol->store((ulonglong) file->delete_length);
|
|
if (table->found_next_number_field)
|
|
{
|
|
table->next_number_field=table->found_next_number_field;
|
|
table->next_number_field->reset();
|
|
file->update_auto_increment();
|
|
protocol->store(table->next_number_field->val_int());
|
|
table->next_number_field=0;
|
|
}
|
|
else
|
|
protocol->store_null();
|
|
if (!file->create_time)
|
|
protocol->store_null();
|
|
else
|
|
{
|
|
localtime_r(&file->create_time,&tm_tmp);
|
|
localtime_to_TIME(&time, &tm_tmp);
|
|
protocol->store(&time);
|
|
}
|
|
if (!file->update_time)
|
|
protocol->store_null();
|
|
else
|
|
{
|
|
localtime_r(&file->update_time,&tm_tmp);
|
|
localtime_to_TIME(&time, &tm_tmp);
|
|
protocol->store(&time);
|
|
}
|
|
if (!file->check_time)
|
|
protocol->store_null();
|
|
else
|
|
{
|
|
localtime_r(&file->check_time,&tm_tmp);
|
|
localtime_to_TIME(&time, &tm_tmp);
|
|
protocol->store(&time);
|
|
}
|
|
str= (table->table_charset ? table->table_charset->name : "default");
|
|
protocol->store(str, system_charset_info);
|
|
if (file->table_flags() & HA_HAS_CHECKSUM)
|
|
protocol->store((ulonglong)file->checksum());
|
|
else
|
|
protocol->store_null(); // Checksum
|
|
{
|
|
char option_buff[350],*ptr;
|
|
ptr=option_buff;
|
|
if (table->min_rows)
|
|
{
|
|
ptr=strmov(ptr," min_rows=");
|
|
ptr=longlong10_to_str(table->min_rows,ptr,10);
|
|
}
|
|
if (table->max_rows)
|
|
{
|
|
ptr=strmov(ptr," max_rows=");
|
|
ptr=longlong10_to_str(table->max_rows,ptr,10);
|
|
}
|
|
if (table->avg_row_length)
|
|
{
|
|
ptr=strmov(ptr," avg_row_length=");
|
|
ptr=longlong10_to_str(table->avg_row_length,ptr,10);
|
|
}
|
|
if (table->db_create_options & HA_OPTION_PACK_KEYS)
|
|
ptr=strmov(ptr," pack_keys=1");
|
|
if (table->db_create_options & HA_OPTION_NO_PACK_KEYS)
|
|
ptr=strmov(ptr," pack_keys=0");
|
|
if (table->db_create_options & HA_OPTION_CHECKSUM)
|
|
ptr=strmov(ptr," checksum=1");
|
|
if (table->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
|
|
ptr=strmov(ptr," delay_key_write=1");
|
|
if (table->row_type != ROW_TYPE_DEFAULT)
|
|
ptr=strxmov(ptr, " row_format=", ha_row_type[(uint) table->row_type],
|
|
NullS);
|
|
if (file->raid_type)
|
|
{
|
|
char buff[100];
|
|
sprintf(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);
|
|
}
|
|
protocol->store(option_buff+1,
|
|
(ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1)
|
|
, system_charset_info);
|
|
}
|
|
{
|
|
char *comment=table->file->update_table_comment(table->comment);
|
|
protocol->store(comment, system_charset_info);
|
|
if (comment != table->comment)
|
|
my_free(comment,MYF(0));
|
|
}
|
|
close_thread_tables(thd,0);
|
|
}
|
|
if (protocol->write())
|
|
DBUG_RETURN(-1);
|
|
}
|
|
send_eof(thd);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
** List all columns in a table_list->real_name
|
|
***************************************************************************/
|
|
|
|
int
|
|
mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
|
|
bool verbose)
|
|
{
|
|
TABLE *table;
|
|
handler *file;
|
|
char tmp[MAX_FIELD_WIDTH];
|
|
Item *item;
|
|
Protocol *protocol= thd->protocol;
|
|
DBUG_ENTER("mysqld_show_fields");
|
|
DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
|
|
table_list->real_name));
|
|
|
|
if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
|
|
{
|
|
send_error(thd);
|
|
DBUG_RETURN(1);
|
|
}
|
|
file=table->file;
|
|
file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
|
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
|
(void) get_table_grant(thd, table_list);
|
|
#endif
|
|
List<Item> field_list;
|
|
field_list.push_back(new Item_empty_string("Field",NAME_LEN));
|
|
field_list.push_back(new Item_empty_string("Type",40));
|
|
if (verbose)
|
|
field_list.push_back(new Item_empty_string("Collation",40));
|
|
field_list.push_back(new Item_empty_string("Null",1));
|
|
field_list.push_back(new Item_empty_string("Key",3));
|
|
field_list.push_back(item=new Item_empty_string("Default",NAME_LEN));
|
|
item->maybe_null=1;
|
|
field_list.push_back(new Item_empty_string("Extra",20));
|
|
if (verbose)
|
|
{
|
|
field_list.push_back(new Item_empty_string("Privileges",80));
|
|
field_list.push_back(new Item_empty_string("Comment",255));
|
|
}
|
|
// Send first number of fields and records
|
|
if (protocol->send_records_num(&field_list, (ulonglong)file->records) ||
|
|
protocol->send_fields(&field_list,0))
|
|
DBUG_RETURN(1);
|
|
restore_record(table,default_values); // Get empty record
|
|
|
|
Field **ptr,*field;
|
|
String *packet= &thd->packet;
|
|
for (ptr=table->field; (field= *ptr) ; ptr++)
|
|
{
|
|
if (!wild || !wild[0] ||
|
|
!wild_case_compare(system_charset_info, field->field_name,wild))
|
|
{
|
|
#ifdef NOT_USED
|
|
if (thd->col_access & TABLE_ACLS ||
|
|
! check_grant_column(thd,table,field->field_name,
|
|
(uint) strlen(field->field_name),1))
|
|
#endif
|
|
{
|
|
byte *pos;
|
|
uint flags=field->flags;
|
|
String type(tmp,sizeof(tmp), system_charset_info);
|
|
uint col_access;
|
|
bool null_default_value=0;
|
|
|
|
protocol->prepare_for_resend();
|
|
protocol->store(field->field_name, system_charset_info);
|
|
field->sql_type(type);
|
|
protocol->store(type.ptr(), type.length(), system_charset_info);
|
|
if (verbose)
|
|
protocol->store(field->has_charset() ? field->charset()->name : "NULL",
|
|
system_charset_info);
|
|
pos=(byte*) ((flags & NOT_NULL_FLAG) &&
|
|
field->type() != FIELD_TYPE_TIMESTAMP ?
|
|
"" : "YES");
|
|
protocol->store((const char*) pos, system_charset_info);
|
|
pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
|
|
(field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
|
|
(field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
|
|
protocol->store((char*) pos, system_charset_info);
|
|
|
|
if (field->type() == FIELD_TYPE_TIMESTAMP ||
|
|
field->unireg_check == Field::NEXT_NUMBER)
|
|
null_default_value=1;
|
|
if (!null_default_value && !field->is_null())
|
|
{ // Not null by default
|
|
type.set(tmp,sizeof(tmp),system_charset_info);
|
|
field->val_str(&type,&type);
|
|
protocol->store(type.ptr(),type.length(),type.charset());
|
|
}
|
|
else if (field->maybe_null() || null_default_value)
|
|
protocol->store_null(); // Null as default
|
|
else
|
|
protocol->store("",0, system_charset_info); // empty string
|
|
|
|
char *end=tmp;
|
|
if (field->unireg_check == Field::NEXT_NUMBER)
|
|
end=strmov(tmp,"auto_increment");
|
|
protocol->store(tmp,(uint) (end-tmp), system_charset_info);
|
|
|
|
if (verbose)
|
|
{
|
|
/* Add grant options & comments */
|
|
end=tmp;
|
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
|
col_access= get_column_grant(thd,table_list,field) & COL_ACLS;
|
|
for (uint bitnr=0; col_access ; col_access>>=1,bitnr++)
|
|
{
|
|
if (col_access & 1)
|
|
{
|
|
*end++=',';
|
|
end=strmov(end,grant_types.type_names[bitnr]);
|
|
}
|
|
}
|
|
#else
|
|
end=strmov(end,"");
|
|
#endif
|
|
protocol->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1),
|
|
system_charset_info);
|
|
protocol->store(field->comment.str, field->comment.length,
|
|
system_charset_info);
|
|
}
|
|
if (protocol->write())
|
|
DBUG_RETURN(1);
|
|
}
|
|
}
|
|
}
|
|
send_eof(thd);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
int
|
|
mysqld_show_create(THD *thd, TABLE_LIST *table_list)
|
|
{
|
|
TABLE *table;
|
|
Protocol *protocol= thd->protocol;
|
|
char buff[2048];
|
|
String buffer(buff, sizeof(buff), system_charset_info);
|
|
DBUG_ENTER("mysqld_show_create");
|
|
DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
|
|
table_list->real_name));
|
|
|
|
/* Only one table for now */
|
|
if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
|
|
{
|
|
send_error(thd);
|
|
DBUG_RETURN(1);
|
|
}
|
|
|
|
if (store_create_info(thd, table, &buffer))
|
|
DBUG_RETURN(-1);
|
|
|
|
List<Item> field_list;
|
|
field_list.push_back(new Item_empty_string("Table",NAME_LEN));
|
|
// 1024 is for not to confuse old clients
|
|
field_list.push_back(new Item_empty_string("Create Table",
|
|
max(buffer.length(),1024)));
|
|
|
|
if (protocol->send_fields(&field_list, 1))
|
|
DBUG_RETURN(1);
|
|
protocol->prepare_for_resend();
|
|
protocol->store(table->table_name, system_charset_info);
|
|
buffer.length(0);
|
|
if (store_create_info(thd, table, &buffer))
|
|
DBUG_RETURN(-1);
|
|
protocol->store(buffer.ptr(), buffer.length(), buffer.charset());
|
|
if (protocol->write())
|
|
DBUG_RETURN(1);
|
|
send_eof(thd);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
int
|
|
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,1))
|
|
DBUG_RETURN(1);
|
|
|
|
#ifdef HAVE_BERKELEY_DB
|
|
if (!berkeley_skip && berkeley_show_logs(protocol))
|
|
DBUG_RETURN(-1);
|
|
#endif
|
|
|
|
send_eof(thd);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
int
|
|
mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
|
|
{
|
|
TABLE *table;
|
|
Protocol *protocol= thd->protocol;
|
|
DBUG_ENTER("mysqld_show_keys");
|
|
DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
|
|
table_list->real_name));
|
|
|
|
if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
|
|
{
|
|
send_error(thd);
|
|
DBUG_RETURN(1);
|
|
}
|
|
|
|
List<Item> field_list;
|
|
Item *item;
|
|
field_list.push_back(new Item_empty_string("Table",NAME_LEN));
|
|
field_list.push_back(new Item_return_int("Non_unique",1, MYSQL_TYPE_TINY));
|
|
field_list.push_back(new Item_empty_string("Key_name",NAME_LEN));
|
|
field_list.push_back(new Item_return_int("Seq_in_index",2, MYSQL_TYPE_TINY));
|
|
field_list.push_back(new Item_empty_string("Column_name",NAME_LEN));
|
|
field_list.push_back(item=new Item_empty_string("Collation",1));
|
|
item->maybe_null=1;
|
|
field_list.push_back(item=new Item_int("Cardinality",0,21));
|
|
item->maybe_null=1;
|
|
field_list.push_back(item=new Item_return_int("Sub_part",3,
|
|
MYSQL_TYPE_TINY));
|
|
item->maybe_null=1;
|
|
field_list.push_back(item=new Item_empty_string("Packed",10));
|
|
item->maybe_null=1;
|
|
field_list.push_back(new Item_empty_string("Null",3));
|
|
field_list.push_back(new Item_empty_string("Index_type",16));
|
|
field_list.push_back(new Item_empty_string("Comment",255));
|
|
item->maybe_null=1;
|
|
|
|
if (protocol->send_fields(&field_list,1))
|
|
DBUG_RETURN(1);
|
|
|
|
String *packet= &thd->packet;
|
|
KEY *key_info=table->key_info;
|
|
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME);
|
|
for (uint i=0 ; i < table->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++)
|
|
{
|
|
protocol->prepare_for_resend();
|
|
protocol->store(table->table_name, system_charset_info);
|
|
protocol->store_tiny((longlong) ((key_info->flags & HA_NOSAME) ? 0 :1));
|
|
protocol->store(key_info->name, system_charset_info);
|
|
protocol->store_tiny((longlong) (j+1));
|
|
str=(key_part->field ? key_part->field->field_name :
|
|
"?unknown field?");
|
|
protocol->store(str, system_charset_info);
|
|
if (table->file->index_flags(i) & HA_READ_ORDER)
|
|
protocol->store(((key_part->key_part_flag & HA_REVERSE_SORT) ?
|
|
"D" : "A"), 1, system_charset_info);
|
|
else
|
|
protocol->store_null(); /* purecov: inspected */
|
|
KEY *key=table->key_info+i;
|
|
if (key->rec_per_key[j])
|
|
{
|
|
ha_rows records=(table->file->records / key->rec_per_key[j]);
|
|
protocol->store((ulonglong) records);
|
|
}
|
|
else
|
|
protocol->store_null();
|
|
|
|
/* Check if we have a key part that only uses part of the field */
|
|
if (!key_part->field ||
|
|
key_part->length !=
|
|
table->field[key_part->fieldnr-1]->key_length())
|
|
protocol->store_tiny((longlong) key_part->length);
|
|
else
|
|
protocol->store_null();
|
|
protocol->store_null(); // No pack_information yet
|
|
|
|
/* Null flag */
|
|
uint flags= key_part->field ? key_part->field->flags : 0;
|
|
char *pos=(char*) ((flags & NOT_NULL_FLAG) ? "" : "YES");
|
|
protocol->store((const char*) pos, system_charset_info);
|
|
protocol->store(table->file->index_type(i), system_charset_info);
|
|
/* Comment */
|
|
if (!table->keys_in_use.is_set(i))
|
|
protocol->store("disabled",8, system_charset_info);
|
|
else
|
|
protocol->store("", 0, system_charset_info);
|
|
if (protocol->write())
|
|
DBUG_RETURN(1); /* purecov: inspected */
|
|
}
|
|
}
|
|
send_eof(thd);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
Return only fields for API mysql_list_fields
|
|
Use "show table wildcard" in mysql instead of this
|
|
****************************************************************************/
|
|
|
|
void
|
|
mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
|
|
{
|
|
TABLE *table;
|
|
DBUG_ENTER("mysqld_list_fields");
|
|
DBUG_PRINT("enter",("table: %s",table_list->real_name));
|
|
|
|
if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
|
|
{
|
|
send_error(thd);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
List<Item> field_list;
|
|
|
|
Field **ptr,*field;
|
|
for (ptr=table->field ; (field= *ptr); ptr++)
|
|
{
|
|
if (!wild || !wild[0] ||
|
|
!wild_case_compare(system_charset_info, field->field_name,wild))
|
|
field_list.push_back(new Item_field(field));
|
|
}
|
|
restore_record(table,default_values); // Get empty record
|
|
if (thd->protocol->send_fields(&field_list,2))
|
|
DBUG_VOID_RETURN;
|
|
net_flush(&thd->net);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
int
|
|
mysqld_dump_create_info(THD *thd, TABLE *table, int fd)
|
|
{
|
|
Protocol *protocol= thd->protocol;
|
|
String *packet= protocol->storage_packet();
|
|
DBUG_ENTER("mysqld_dump_create_info");
|
|
DBUG_PRINT("enter",("table: %s",table->real_name));
|
|
|
|
protocol->prepare_for_resend();
|
|
if (store_create_info(thd, table, packet))
|
|
DBUG_RETURN(-1);
|
|
|
|
//if (protocol->convert)
|
|
// protocol->convert->convert((char*) packet->ptr(), packet->length());
|
|
if (fd < 0)
|
|
{
|
|
if (protocol->write())
|
|
DBUG_RETURN(-1);
|
|
net_flush(&thd->net);
|
|
}
|
|
else
|
|
{
|
|
if (my_write(fd, (const byte*) packet->ptr(), packet->length(),
|
|
MYF(MY_WME)))
|
|
DBUG_RETURN(-1);
|
|
}
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
void
|
|
append_identifier(THD *thd, String *packet, const char *name, uint length)
|
|
{
|
|
char qtype;
|
|
if (thd->variables.sql_mode & MODE_ANSI_QUOTES)
|
|
qtype= '\"';
|
|
else
|
|
qtype= '`';
|
|
|
|
if (thd->options & OPTION_QUOTE_SHOW_CREATE)
|
|
{
|
|
packet->append(&qtype, 1);
|
|
packet->append(name, length, system_charset_info);
|
|
packet->append(&qtype, 1);
|
|
}
|
|
else
|
|
{
|
|
packet->append(name, length, system_charset_info);
|
|
}
|
|
}
|
|
|
|
|
|
/* Append directory name (if exists) to CREATE INFO */
|
|
|
|
static void append_directory(THD *thd, String *packet, const char *dir_type,
|
|
const char *filename)
|
|
{
|
|
uint length;
|
|
if (filename && !(thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE))
|
|
{
|
|
length= dirname_length(filename);
|
|
packet->append(' ');
|
|
packet->append(dir_type);
|
|
packet->append(" DIRECTORY='", 12);
|
|
packet->append(filename, length);
|
|
packet->append('\'');
|
|
}
|
|
}
|
|
|
|
|
|
#define LIST_PROCESS_HOST_LEN 64
|
|
|
|
static int
|
|
store_create_info(THD *thd, TABLE *table, String *packet)
|
|
{
|
|
List<Item> field_list;
|
|
char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], *end;
|
|
String type(tmp, sizeof(tmp),&my_charset_bin);
|
|
Field **ptr,*field;
|
|
uint primary_key;
|
|
KEY *key_info;
|
|
handler *file= table->file;
|
|
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;
|
|
|
|
DBUG_ENTER("store_create_info");
|
|
DBUG_PRINT("enter",("table: %s",table->real_name));
|
|
|
|
restore_record(table,default_values); // Get empty record
|
|
|
|
if (table->tmp_table)
|
|
packet->append("CREATE TEMPORARY TABLE ", 23);
|
|
else
|
|
packet->append("CREATE TABLE ", 13);
|
|
append_identifier(thd,packet, table->real_name, strlen(table->real_name));
|
|
packet->append(" (\n", 3);
|
|
|
|
for (ptr=table->field ; (field= *ptr); ptr++)
|
|
{
|
|
bool has_default;
|
|
uint flags = field->flags;
|
|
|
|
if (ptr != table->field)
|
|
packet->append(",\n", 2);
|
|
|
|
packet->append(" ", 2);
|
|
append_identifier(thd,packet,field->field_name, strlen(field->field_name));
|
|
packet->append(' ');
|
|
// check for surprises from the previous call to Field::sql_type()
|
|
if (type.ptr() != tmp)
|
|
type.set(tmp, sizeof(tmp),&my_charset_bin);
|
|
|
|
field->sql_type(type);
|
|
packet->append(type.ptr(),type.length());
|
|
|
|
if (field->has_charset())
|
|
{
|
|
if (field->charset() == &my_charset_bin)
|
|
packet->append(" binary", 7);
|
|
else if (!limited_mysql_mode && !foreign_db_mode)
|
|
{
|
|
if (field->charset() != table->table_charset)
|
|
{
|
|
packet->append(" character set ", 15);
|
|
packet->append(field->charset()->csname);
|
|
}
|
|
/*
|
|
For string types dump collation name only if
|
|
collation is not primary for the given charset
|
|
*/
|
|
if (!(field->charset()->state & MY_CS_PRIMARY))
|
|
{
|
|
packet->append(" collate ", 9);
|
|
packet->append(field->charset()->name);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (flags & NOT_NULL_FLAG)
|
|
packet->append(" NOT NULL", 9);
|
|
|
|
has_default= (field->type() != FIELD_TYPE_BLOB &&
|
|
field->type() != FIELD_TYPE_TIMESTAMP &&
|
|
field->unireg_check != Field::NEXT_NUMBER);
|
|
|
|
if (has_default)
|
|
{
|
|
packet->append(" default ", 9);
|
|
if (!field->is_null())
|
|
{ // Not null by default
|
|
type.set(tmp,sizeof(tmp),&my_charset_bin);
|
|
field->val_str(&type,&type);
|
|
if (type.length())
|
|
append_unescaped(packet, type.ptr(), type.length());
|
|
else
|
|
packet->append("''",2);
|
|
}
|
|
else if (field->maybe_null())
|
|
packet->append("NULL", 4); // Null as default
|
|
else
|
|
packet->append(tmp,0);
|
|
}
|
|
|
|
if (field->unireg_check == Field::NEXT_NUMBER && !foreign_db_mode)
|
|
packet->append(" auto_increment", 15 );
|
|
|
|
if (field->comment.length)
|
|
{
|
|
packet->append(" COMMENT ",9);
|
|
append_unescaped(packet, field->comment.str, field->comment.length);
|
|
}
|
|
}
|
|
|
|
key_info= table->key_info;
|
|
file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME);
|
|
bzero((char*) &create_info, sizeof(create_info));
|
|
file->update_create_info(&create_info);
|
|
primary_key= table->primary_key;
|
|
|
|
for (uint i=0 ; i < table->keys ; i++,key_info++)
|
|
{
|
|
KEY_PART_INFO *key_part= key_info->key_part;
|
|
bool found_primary=0;
|
|
packet->append(",\n ", 4);
|
|
|
|
if (i == primary_key && !strcmp(key_info->name,"PRIMARY"))
|
|
{
|
|
found_primary=1;
|
|
packet->append("PRIMARY ", 8);
|
|
}
|
|
else if (key_info->flags & HA_NOSAME)
|
|
packet->append("UNIQUE ", 7);
|
|
else if (key_info->flags & HA_FULLTEXT)
|
|
packet->append("FULLTEXT ", 9);
|
|
else if (key_info->flags & HA_SPATIAL)
|
|
packet->append("SPATIAL ", 8);
|
|
packet->append("KEY ", 4);
|
|
|
|
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 (table->db_type == DB_TYPE_HEAP &&
|
|
key_info->algorithm == HA_KEY_ALG_BTREE)
|
|
packet->append(" TYPE BTREE", 11);
|
|
|
|
// +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(" TYPE RTREE", 11);
|
|
}
|
|
packet->append(" (", 2);
|
|
|
|
for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
|
|
{
|
|
if (j)
|
|
packet->append(',');
|
|
|
|
if (key_part->field)
|
|
append_identifier(thd,packet,key_part->field->field_name,
|
|
strlen(key_part->field->field_name));
|
|
if (!key_part->field ||
|
|
(key_part->length !=
|
|
table->field[key_part->fieldnr-1]->key_length() &&
|
|
!(key_info->flags & HA_FULLTEXT)))
|
|
{
|
|
buff[0] = '(';
|
|
char* 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(')');
|
|
}
|
|
|
|
/*
|
|
Get possible foreign key definitions stored in InnoDB and append them
|
|
to the CREATE TABLE statement
|
|
*/
|
|
|
|
if ((for_str= file->get_foreign_key_create_info()))
|
|
{
|
|
packet->append(for_str, strlen(for_str));
|
|
file->free_foreign_key_create_info(for_str);
|
|
}
|
|
|
|
packet->append("\n)", 2);
|
|
if (!(thd->variables.sql_mode & MODE_NO_TABLE_OPTIONS) && !foreign_db_mode)
|
|
{
|
|
packet->append(" TYPE=", 6);
|
|
packet->append(file->table_type());
|
|
|
|
if (table->table_charset &&
|
|
!(thd->variables.sql_mode & MODE_MYSQL323) &&
|
|
!(thd->variables.sql_mode & MODE_MYSQL40))
|
|
{
|
|
packet->append(" DEFAULT CHARSET=", 17);
|
|
packet->append(table->table_charset->csname);
|
|
if (!(table->table_charset->state & MY_CS_PRIMARY))
|
|
{
|
|
packet->append(" COLLATE=", 9);
|
|
packet->append(table->table_charset->name);
|
|
}
|
|
}
|
|
|
|
if (table->min_rows)
|
|
{
|
|
packet->append(" MIN_ROWS=", 10);
|
|
end= longlong10_to_str(table->min_rows, buff, 10);
|
|
packet->append(buff, (uint) (end- buff));
|
|
}
|
|
|
|
if (table->max_rows)
|
|
{
|
|
packet->append(" MAX_ROWS=", 10);
|
|
end= longlong10_to_str(table->max_rows, buff, 10);
|
|
packet->append(buff, (uint) (end - buff));
|
|
}
|
|
|
|
if (table->avg_row_length)
|
|
{
|
|
packet->append(" AVG_ROW_LENGTH=", 16);
|
|
end= longlong10_to_str(table->avg_row_length, buff,10);
|
|
packet->append(buff, (uint) (end - buff));
|
|
}
|
|
|
|
if (table->db_create_options & HA_OPTION_PACK_KEYS)
|
|
packet->append(" PACK_KEYS=1", 12);
|
|
if (table->db_create_options & HA_OPTION_NO_PACK_KEYS)
|
|
packet->append(" PACK_KEYS=0", 12);
|
|
if (table->db_create_options & HA_OPTION_CHECKSUM)
|
|
packet->append(" CHECKSUM=1", 11);
|
|
if (table->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
|
|
packet->append(" DELAY_KEY_WRITE=1",18);
|
|
if (table->row_type != ROW_TYPE_DEFAULT)
|
|
{
|
|
packet->append(" ROW_FORMAT=",12);
|
|
packet->append(ha_row_type[(uint) table->row_type]);
|
|
}
|
|
table->file->append_create_info(packet);
|
|
if (table->comment && table->comment[0])
|
|
{
|
|
packet->append(" COMMENT=", 9);
|
|
append_unescaped(packet, table->comment, strlen(table->comment));
|
|
}
|
|
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);
|
|
}
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
Return info about all processes
|
|
returns for each thread: thread id, user, host, db, command, info
|
|
****************************************************************************/
|
|
|
|
class thread_info :public ilink {
|
|
public:
|
|
static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); }
|
|
static void operator delete(void *ptr __attribute__((unused)),
|
|
size_t size __attribute__((unused))) {} /*lint -e715 */
|
|
|
|
ulong thread_id;
|
|
time_t start_time;
|
|
uint command;
|
|
const char *user,*host,*db,*proc_info,*state_info;
|
|
char *query;
|
|
};
|
|
|
|
#ifdef __GNUC__
|
|
template class I_List<thread_info>;
|
|
#endif
|
|
|
|
void mysqld_list_processes(THD *thd,const char *user, bool verbose)
|
|
{
|
|
Item *field;
|
|
List<Item> field_list;
|
|
I_List<thread_info> thread_infos;
|
|
ulong max_query_length= (verbose ? thd->variables.max_allowed_packet :
|
|
PROCESS_LIST_WIDTH);
|
|
Protocol *protocol= thd->protocol;
|
|
DBUG_ENTER("mysqld_list_processes");
|
|
|
|
field_list.push_back(new Item_int("Id",0,11));
|
|
field_list.push_back(new Item_empty_string("User",16));
|
|
field_list.push_back(new Item_empty_string("Host",LIST_PROCESS_HOST_LEN));
|
|
field_list.push_back(field=new Item_empty_string("db",NAME_LEN));
|
|
field->maybe_null=1;
|
|
field_list.push_back(new Item_empty_string("Command",16));
|
|
field_list.push_back(new Item_return_int("Time",7, FIELD_TYPE_LONG));
|
|
field_list.push_back(field=new Item_empty_string("State",30));
|
|
field->maybe_null=1;
|
|
field_list.push_back(field=new Item_empty_string("Info",max_query_length));
|
|
field->maybe_null=1;
|
|
if (protocol->send_fields(&field_list,1))
|
|
DBUG_VOID_RETURN;
|
|
|
|
VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
|
|
if (!thd->killed)
|
|
{
|
|
I_List_iterator<THD> it(threads);
|
|
THD *tmp;
|
|
while ((tmp=it++))
|
|
{
|
|
struct st_my_thread_var *mysys_var;
|
|
#ifndef EMBEDDED_LIBRARY
|
|
if ((tmp->net.vio || tmp->system_thread) &&
|
|
(!user || (tmp->user && !strcmp(tmp->user,user))))
|
|
#else
|
|
if (tmp->system_thread &&
|
|
(!user || (tmp->user && !strcmp(tmp->user,user))))
|
|
#endif
|
|
{
|
|
thread_info *thd_info=new thread_info;
|
|
|
|
thd_info->thread_id=tmp->thread_id;
|
|
thd_info->user=thd->strdup(tmp->user ? tmp->user :
|
|
(tmp->system_thread ?
|
|
"system user" : "unauthenticated user"));
|
|
if (tmp->peer_port && (tmp->host || tmp->ip) && thd->host_or_ip[0])
|
|
{
|
|
if ((thd_info->host= thd->alloc(LIST_PROCESS_HOST_LEN+1)))
|
|
my_snprintf((char *) thd_info->host, LIST_PROCESS_HOST_LEN,
|
|
"%s:%u", tmp->host_or_ip, tmp->peer_port);
|
|
}
|
|
else
|
|
thd_info->host= thd->strdup(tmp->host_or_ip);
|
|
if ((thd_info->db=tmp->db)) // Safe test
|
|
thd_info->db=thd->strdup(thd_info->db);
|
|
thd_info->command=(int) tmp->command;
|
|
if ((mysys_var= tmp->mysys_var))
|
|
pthread_mutex_lock(&mysys_var->mutex);
|
|
thd_info->proc_info= (char*) (tmp->killed ? "Killed" : 0);
|
|
#ifndef EMBEDDED_LIBRARY
|
|
thd_info->state_info= (char*) (tmp->locked ? "Locked" :
|
|
tmp->net.reading_or_writing ?
|
|
(tmp->net.reading_or_writing == 2 ?
|
|
"Writing to net" :
|
|
thd_info->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
|
|
thd_info->state_info= (char*)"Writing to net";
|
|
#endif
|
|
if (mysys_var)
|
|
pthread_mutex_unlock(&mysys_var->mutex);
|
|
|
|
#if !defined(DONT_USE_THR_ALARM) && ! defined(SCO)
|
|
if (pthread_kill(tmp->real_id,0))
|
|
tmp->proc_info="*** DEAD ***"; // This shouldn't happen
|
|
#endif
|
|
#ifdef EXTRA_DEBUG
|
|
thd_info->start_time= tmp->time_after_lock;
|
|
#else
|
|
thd_info->start_time= tmp->start_time;
|
|
#endif
|
|
thd_info->query=0;
|
|
if (tmp->query)
|
|
{
|
|
/* query_length is always set before tmp->query */
|
|
uint length= min(max_query_length, tmp->query_length);
|
|
thd_info->query=(char*) thd->memdup(tmp->query,length+1);
|
|
thd_info->query[length]=0;
|
|
}
|
|
thread_infos.append(thd_info);
|
|
}
|
|
}
|
|
}
|
|
VOID(pthread_mutex_unlock(&LOCK_thread_count));
|
|
|
|
thread_info *thd_info;
|
|
time_t now= time(0);
|
|
while ((thd_info=thread_infos.get()))
|
|
{
|
|
protocol->prepare_for_resend();
|
|
protocol->store((ulonglong) thd_info->thread_id);
|
|
protocol->store(thd_info->user, system_charset_info);
|
|
protocol->store(thd_info->host, system_charset_info);
|
|
protocol->store(thd_info->db, system_charset_info);
|
|
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);
|
|
if (thd_info->start_time)
|
|
protocol->store((uint32) (now - thd_info->start_time));
|
|
else
|
|
protocol->store_null();
|
|
protocol->store(thd_info->state_info, system_charset_info);
|
|
protocol->store(thd_info->query, system_charset_info);
|
|
if (protocol->write())
|
|
break; /* purecov: inspected */
|
|
}
|
|
send_eof(thd);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Status functions
|
|
*****************************************************************************/
|
|
|
|
static bool write_collation(Protocol *protocol, CHARSET_INFO *cs)
|
|
{
|
|
protocol->prepare_for_resend();
|
|
protocol->store(cs->name, system_charset_info);
|
|
protocol->store(cs->csname, system_charset_info);
|
|
protocol->store_short((longlong) cs->number);
|
|
protocol->store((cs->state & MY_CS_PRIMARY) ? "Yes" : "",system_charset_info);
|
|
protocol->store((cs->state & MY_CS_COMPILED)? "Yes" : "",system_charset_info);
|
|
protocol->store_short((longlong) cs->strxfrm_multiply);
|
|
return protocol->write();
|
|
}
|
|
|
|
int mysqld_show_collations(THD *thd, const char *wild)
|
|
{
|
|
char buff[8192];
|
|
String packet2(buff,sizeof(buff),thd->charset());
|
|
List<Item> field_list;
|
|
CHARSET_INFO **cs;
|
|
Protocol *protocol= thd->protocol;
|
|
|
|
DBUG_ENTER("mysqld_show_charsets");
|
|
|
|
field_list.push_back(new Item_empty_string("Collation",30));
|
|
field_list.push_back(new Item_empty_string("Charset",30));
|
|
field_list.push_back(new Item_return_int("Id",11, FIELD_TYPE_SHORT));
|
|
field_list.push_back(new Item_empty_string("Default",30));
|
|
field_list.push_back(new Item_empty_string("Compiled",30));
|
|
field_list.push_back(new Item_return_int("Sortlen",3, FIELD_TYPE_SHORT));
|
|
|
|
if (protocol->send_fields(&field_list, 1))
|
|
DBUG_RETURN(1);
|
|
|
|
for ( cs= all_charsets ; cs < all_charsets+255 ; cs++ )
|
|
{
|
|
CHARSET_INFO **cl;
|
|
if (!cs[0] || !(cs[0]->state & MY_CS_AVAILABLE) ||
|
|
!(cs[0]->state & MY_CS_PRIMARY))
|
|
continue;
|
|
for ( cl= all_charsets; cl < all_charsets+255 ;cl ++)
|
|
{
|
|
if (!cl[0] || !(cl[0]->state & MY_CS_AVAILABLE) ||
|
|
!my_charset_same(cs[0],cl[0]))
|
|
continue;
|
|
if (!(wild && wild[0] &&
|
|
wild_case_compare(system_charset_info,cl[0]->name,wild)))
|
|
{
|
|
if (write_collation(protocol, cl[0]))
|
|
goto err;
|
|
}
|
|
}
|
|
}
|
|
send_eof(thd);
|
|
DBUG_RETURN(0);
|
|
err:
|
|
DBUG_RETURN(1);
|
|
}
|
|
|
|
static bool write_charset(Protocol *protocol, CHARSET_INFO *cs)
|
|
{
|
|
protocol->prepare_for_resend();
|
|
protocol->store(cs->csname, system_charset_info);
|
|
protocol->store(cs->comment ? cs->comment : "", system_charset_info);
|
|
protocol->store(cs->name, system_charset_info);
|
|
protocol->store_short((longlong) cs->mbmaxlen);
|
|
return protocol->write();
|
|
}
|
|
|
|
int mysqld_show_charsets(THD *thd, const char *wild)
|
|
{
|
|
char buff[8192];
|
|
String packet2(buff,sizeof(buff),thd->charset());
|
|
List<Item> field_list;
|
|
CHARSET_INFO **cs;
|
|
Protocol *protocol= thd->protocol;
|
|
|
|
DBUG_ENTER("mysqld_show_charsets");
|
|
|
|
field_list.push_back(new Item_empty_string("Charset",30));
|
|
field_list.push_back(new Item_empty_string("Description",60));
|
|
field_list.push_back(new Item_empty_string("Default collation",60));
|
|
field_list.push_back(new Item_return_int("Maxlen",3, FIELD_TYPE_SHORT));
|
|
|
|
if (protocol->send_fields(&field_list, 1))
|
|
DBUG_RETURN(1);
|
|
|
|
for ( cs= all_charsets ; cs < all_charsets+255 ; cs++ )
|
|
{
|
|
if (cs[0] && (cs[0]->state & MY_CS_PRIMARY) &&
|
|
(cs[0]->state & MY_CS_AVAILABLE) &&
|
|
!(wild && wild[0] &&
|
|
wild_case_compare(system_charset_info,cs[0]->csname,wild)))
|
|
{
|
|
if (write_charset(protocol, cs[0]))
|
|
goto err;
|
|
}
|
|
}
|
|
send_eof(thd);
|
|
DBUG_RETURN(0);
|
|
err:
|
|
DBUG_RETURN(1);
|
|
}
|
|
|
|
|
|
|
|
int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
|
|
enum enum_var_type value_type,
|
|
pthread_mutex_t *mutex)
|
|
{
|
|
char buff[1024];
|
|
List<Item> field_list;
|
|
Protocol *protocol= thd->protocol;
|
|
LEX_STRING null_lex_str;
|
|
DBUG_ENTER("mysqld_show");
|
|
|
|
field_list.push_back(new Item_empty_string("Variable_name",30));
|
|
field_list.push_back(new Item_empty_string("Value",256));
|
|
if (protocol->send_fields(&field_list,1))
|
|
DBUG_RETURN(1); /* purecov: inspected */
|
|
null_lex_str.str= 0; // For sys_var->value_ptr()
|
|
null_lex_str.length= 0;
|
|
|
|
pthread_mutex_lock(mutex);
|
|
for (; variables->name; variables++)
|
|
{
|
|
if (!(wild && wild[0] && wild_case_compare(system_charset_info,
|
|
variables->name,wild)))
|
|
{
|
|
protocol->prepare_for_resend();
|
|
protocol->store(variables->name, system_charset_info);
|
|
SHOW_TYPE show_type=variables->type;
|
|
char *value=variables->value;
|
|
const char *pos, *end;
|
|
long nr;
|
|
|
|
if (show_type == SHOW_SYS)
|
|
{
|
|
show_type= ((sys_var*) value)->type();
|
|
value= (char*) ((sys_var*) value)->value_ptr(thd, value_type,
|
|
&null_lex_str);
|
|
}
|
|
|
|
pos= end= buff;
|
|
switch (show_type) {
|
|
case SHOW_LONG:
|
|
case SHOW_LONG_CONST:
|
|
end= int10_to_str(*(long*) value, buff, 10);
|
|
break;
|
|
case SHOW_LONGLONG:
|
|
end= longlong10_to_str(*(longlong*) value, buff, 10);
|
|
break;
|
|
case SHOW_HA_ROWS:
|
|
end= longlong10_to_str((longlong) *(ha_rows*) value, buff, 10);
|
|
break;
|
|
case SHOW_BOOL:
|
|
end= strmov(buff, *(bool*) value ? "ON" : "OFF");
|
|
break;
|
|
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;
|
|
case SHOW_HAVE:
|
|
{
|
|
SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) value;
|
|
pos= show_comp_option_name[(int) tmp];
|
|
end= strend(pos);
|
|
break;
|
|
}
|
|
case SHOW_CHAR:
|
|
pos= value;
|
|
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:
|
|
{
|
|
LOCK_ACTIVE_MI;
|
|
end= strmov(buff, (active_mi->slave_running &&
|
|
active_mi->rli.slave_running) ? "ON" : "OFF");
|
|
UNLOCK_ACTIVE_MI;
|
|
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))
|
|
pos= "";
|
|
end= strend(pos);
|
|
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:
|
|
value= (value-(char*) &dflt_key_cache_var)+ (char*) sql_key_cache;
|
|
end= int10_to_str(*(long*) value, buff, 10);
|
|
break;
|
|
case SHOW_UNDEF: // Show never happen
|
|
case SHOW_SYS:
|
|
break; // Return empty string
|
|
default:
|
|
break;
|
|
}
|
|
if (protocol->store(pos, (uint32) (end - pos), system_charset_info) ||
|
|
protocol->write())
|
|
goto err; /* purecov: inspected */
|
|
}
|
|
}
|
|
pthread_mutex_unlock(mutex);
|
|
send_eof(thd);
|
|
DBUG_RETURN(0);
|
|
|
|
err:
|
|
pthread_mutex_unlock(mutex);
|
|
DBUG_RETURN(1);
|
|
}
|
|
|
|
#ifdef __GNUC__
|
|
template class List_iterator_fast<char>;
|
|
template class List<char>;
|
|
#endif
|