mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 13:02:28 +01:00
6340c79c05
New fields in CHARSET_INFO for more nice SHOW CHARACTER SET Dynamic charsets are now handled in faster way SHOW CHARACTER SET now displays not only compiled charsets but dynamic charsets too
1659 lines
54 KiB
C++
1659 lines
54 KiB
C++
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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
|
|
|
|
/* extern "C" pthread_mutex_t THR_LOCK_keycache; */
|
|
|
|
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);
|
|
|
|
static void
|
|
append_identifier(THD *thd, String *packet, const char *name);
|
|
|
|
extern struct st_VioSSLAcceptorFd * ssl_acceptor_fd;
|
|
|
|
/****************************************************************************
|
|
** Send 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,default_charset_info);
|
|
List<Item> field_list;
|
|
char *end;
|
|
List<char> files;
|
|
char *file_name;
|
|
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 (send_fields(thd,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++))
|
|
{
|
|
if (!opt_safe_show_db || thd->master_access ||
|
|
acl_get(thd->host, thd->ip, (char*) &thd->remote.sin_addr,
|
|
thd->priv_user, file_name) ||
|
|
(grant_option && !check_grant_db(thd, file_name)))
|
|
{
|
|
thd->packet.length(0);
|
|
net_store_data(&thd->packet, thd->convert_set, file_name);
|
|
if (my_net_write(&thd->net, (char*) thd->packet.ptr(),
|
|
thd->packet.length()))
|
|
DBUG_RETURN(-1);
|
|
}
|
|
}
|
|
send_eof(&thd->net);
|
|
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;
|
|
CONVERT *convert=thd->convert_set;
|
|
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_int("In_use",0, 4));
|
|
field_list.push_back(new Item_int("Name_locked",0, 4));
|
|
|
|
if (send_fields(thd,field_list,1))
|
|
DBUG_RETURN(1);
|
|
|
|
if (!(open_list=list_open_tables(thd,wild)) && thd->fatal_error)
|
|
DBUG_RETURN(-1);
|
|
|
|
for ( ; open_list ; open_list=open_list->next)
|
|
{
|
|
thd->packet.length(0);
|
|
net_store_data(&thd->packet,convert, open_list->db);
|
|
net_store_data(&thd->packet,convert, open_list->table);
|
|
net_store_data(&thd->packet,open_list->in_use);
|
|
net_store_data(&thd->packet,open_list->locked);
|
|
if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
|
|
DBUG_RETURN(-1);
|
|
}
|
|
|
|
send_eof(&thd->net);
|
|
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,default_charset_info);
|
|
List<Item> field_list;
|
|
char path[FN_LEN],*end;
|
|
List<char> files;
|
|
char *file_name;
|
|
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 (send_fields(thd,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++))
|
|
{
|
|
thd->packet.length(0);
|
|
net_store_data(&thd->packet, thd->convert_set, file_name);
|
|
if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
|
|
DBUG_RETURN(-1);
|
|
}
|
|
send_eof(&thd->net);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/***************************************************************************
|
|
** List all table types supported
|
|
***************************************************************************/
|
|
|
|
static struct show_table_type_st sys_table_types[]= {
|
|
{"MyISAM", (char *)"YES", "Default type from 3.23 with great performance"},
|
|
{"HEAP" , (char *)"YES", "Hash based, stored in memory, useful for temporary tables"},
|
|
{"MERGE", (char *)"YES", "Collection of identical MyISAM tables"},
|
|
{"ISAM", (char*) &have_isam,"Obsolete table type"},
|
|
{"InnoDB", (char*) &have_innodb,"Supports transactions, row-level locking and foreign keys"},
|
|
{"BDB", (char*) &have_berkeley_db, "Supports transactions and page-level locking"},
|
|
};
|
|
|
|
int mysqld_show_table_types(THD *thd)
|
|
{
|
|
List<Item> field_list;
|
|
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",NAME_LEN));
|
|
|
|
if (send_fields(thd,field_list,1))
|
|
DBUG_RETURN(1);
|
|
|
|
const char *default_type_name=ha_table_typelib.type_names[default_table_type-1];
|
|
show_table_type_st *types = sys_table_types;
|
|
|
|
uint i;
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
thd->packet.length(0);
|
|
net_store_data(&thd->packet,types[i].type);
|
|
if (!strcasecmp(default_type_name,types[i].type))
|
|
net_store_data(&thd->packet,"DEFAULT");
|
|
else
|
|
net_store_data(&thd->packet,types[i].value);
|
|
net_store_data(&thd->packet,types[i].comment);
|
|
if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
|
|
DBUG_RETURN(-1);
|
|
}
|
|
|
|
for (; i < sizeof(sys_table_types)/sizeof(sys_table_types[0]); i++)
|
|
{
|
|
thd->packet.length(0);
|
|
net_store_data(&thd->packet,types[i].type);
|
|
SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) types[i].value;
|
|
|
|
if (tmp == SHOW_OPTION_NO)
|
|
net_store_data(&thd->packet,"NO");
|
|
else
|
|
{
|
|
if (tmp == SHOW_OPTION_YES)
|
|
{
|
|
if (!strcasecmp(default_type_name,types[i].type))
|
|
net_store_data(&thd->packet,"DEFAULT");
|
|
else
|
|
net_store_data(&thd->packet,"YES");
|
|
}
|
|
else net_store_data(&thd->packet,"DISABLED");
|
|
}
|
|
net_store_data(&thd->packet,types[i].comment);
|
|
if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
|
|
DBUG_RETURN(-1);
|
|
}
|
|
send_eof(&thd->net);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/***************************************************************************
|
|
** List all privileges supported
|
|
***************************************************************************/
|
|
|
|
static struct show_table_type_st sys_privileges[]= {
|
|
{"Select", (char *)"Tables", "To retrieve rows from table"},
|
|
{"Insert", (char *)"Tables", "To insert data into tables"},
|
|
{"Update", (char *)"Tables", "To update existing rows "},
|
|
{"Delete", (char *)"Tables", "To delete existing rows"},
|
|
{"Index", (char *)"Tables", "To create or drop indexes"},
|
|
{"Alter", (char *)"Tables", "To alter the table"},
|
|
{"Create", (char *)"Databases,Tables,Indexes", "To create new databases and tables"},
|
|
{"Drop", (char *)"Databases,Tables", "To drop databases and tables"},
|
|
{"Grant", (char *)"Databases,Tables", "To give to other users those privileges you possesed"},
|
|
{"References", (char *)"Databases,Tables", "To have references on tables"},
|
|
{"Reload", (char *)"Server Admin", "To reload or refresh tables, logs and privileges"},
|
|
{"Shutdown",(char *)"Server Admin", "To shutdown the server"},
|
|
{"Process", (char *)"Server Admin", "To view the plain text of currently executing queries"},
|
|
{"File", (char *)"File access on server", "To read and write files on the server"},
|
|
};
|
|
|
|
int mysqld_show_privileges(THD *thd)
|
|
{
|
|
List<Item> field_list;
|
|
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 (send_fields(thd,field_list,1))
|
|
DBUG_RETURN(1);
|
|
|
|
for (uint i=0; i < sizeof(sys_privileges)/sizeof(sys_privileges[0]); i++)
|
|
{
|
|
thd->packet.length(0);
|
|
net_store_data(&thd->packet,sys_privileges[i].type);
|
|
net_store_data(&thd->packet,sys_privileges[i].value);
|
|
net_store_data(&thd->packet,sys_privileges[i].comment);
|
|
if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
|
|
DBUG_RETURN(-1);
|
|
}
|
|
send_eof(&thd->net);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
** List all column types
|
|
***************************************************************************/
|
|
|
|
#if 0
|
|
struct show_column_type_st {
|
|
const char *type;
|
|
uint size;
|
|
char *min_value;
|
|
char *max_value;
|
|
uint precision,
|
|
uint scale,
|
|
char *nullable;
|
|
char *auto_increment;
|
|
char *unsigned_attr;
|
|
char *zerofill;
|
|
char *searchable;
|
|
char *case_sensitivity;
|
|
char *default_value;
|
|
char *comment;
|
|
};
|
|
#endif
|
|
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;
|
|
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_int("Prec", 0,4));
|
|
field_list.push_back(new Item_int("Scale", 0,4));
|
|
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 (send_fields(thd,field_list,1))
|
|
DBUG_RETURN(1);
|
|
|
|
for (uint i=0; i < sizeof(sys_column_types)/sizeof(sys_column_types[0]); i++)
|
|
{
|
|
thd->packet.length(0);
|
|
net_store_data(&thd->packet,sys_column_types[i].type);
|
|
net_store_data(&thd->packet,(longlong)sys_column_types[i].size);
|
|
net_store_data(&thd->packet,sys_column_types[i].min_value);
|
|
net_store_data(&thd->packet,sys_column_types[i].max_value);
|
|
net_store_data(&thd->packet,(uint32)sys_column_types[i].precision);
|
|
net_store_data(&thd->packet,(uint32)sys_column_types[i].scale);
|
|
net_store_data(&thd->packet,sys_column_types[i].nullable);
|
|
net_store_data(&thd->packet,sys_column_types[i].auto_increment);
|
|
net_store_data(&thd->packet,sys_column_types[i].unsigned_attr);
|
|
net_store_data(&thd->packet,sys_column_types[i].zerofill);
|
|
net_store_data(&thd->packet,sys_column_types[i].searchable);
|
|
net_store_data(&thd->packet,sys_column_types[i].case_sensitivity);
|
|
net_store_data(&thd->packet,sys_column_types[i].default_value);
|
|
net_store_data(&thd->packet,sys_column_types[i].comment);
|
|
if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
|
|
DBUG_RETURN(-1);
|
|
}
|
|
send_eof(&thd->net);
|
|
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)))
|
|
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))
|
|
continue;
|
|
}
|
|
}
|
|
/* 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;
|
|
}
|
|
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;
|
|
String *packet= &thd->packet;
|
|
CONVERT *convert=thd->convert_set;
|
|
DBUG_ENTER("mysqld_extend_show_tables");
|
|
|
|
(void) sprintf(path,"%s/%s",mysql_data_home,db);
|
|
(void) unpack_dirname(path,path);
|
|
//,default_charset_info
|
|
field_list.push_back(item=new Item_empty_string("Name",NAME_LEN));
|
|
item->maybe_null=1;
|
|
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("Create_options",255));
|
|
item->maybe_null=1;
|
|
field_list.push_back(item=new Item_empty_string("Comment",80));
|
|
if (send_fields(thd,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));
|
|
packet->length(0);
|
|
net_store_data(packet,convert, file_name);
|
|
table_list.db=(char*) db;
|
|
table_list.real_name=table_list.name=file_name;
|
|
if (!(table = open_ltable(thd, &table_list, TL_READ)))
|
|
{
|
|
for (uint i=0 ; i < field_list.elements ; i++)
|
|
net_store_null(packet);
|
|
net_store_data(packet,convert, thd->net.last_error);
|
|
thd->net.last_error[0]=0;
|
|
}
|
|
else
|
|
{
|
|
struct tm tm_tmp;
|
|
handler *file=table->file;
|
|
file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_NO_LOCK);
|
|
net_store_data(packet, convert, file->table_type());
|
|
net_store_data(packet, convert,
|
|
(table->db_options_in_use & HA_OPTION_PACK_RECORD) ?
|
|
"Dynamic" :
|
|
(table->db_options_in_use & HA_OPTION_COMPRESS_RECORD)
|
|
? "Compressed" : "Fixed");
|
|
net_store_data(packet, (longlong) file->records);
|
|
net_store_data(packet, (uint32) file->mean_rec_length);
|
|
net_store_data(packet, (longlong) file->data_file_length);
|
|
if (file->max_data_file_length)
|
|
net_store_data(packet, (longlong) file->max_data_file_length);
|
|
else
|
|
net_store_null(packet);
|
|
net_store_data(packet, (longlong) file->index_file_length);
|
|
net_store_data(packet, (longlong) 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();
|
|
net_store_data(packet, table->next_number_field->val_int());
|
|
table->next_number_field=0;
|
|
}
|
|
else
|
|
net_store_null(packet);
|
|
if (!file->create_time)
|
|
net_store_null(packet);
|
|
else
|
|
{
|
|
localtime_r(&file->create_time,&tm_tmp);
|
|
net_store_data(packet, &tm_tmp);
|
|
}
|
|
if (!file->update_time)
|
|
net_store_null(packet);
|
|
else
|
|
{
|
|
localtime_r(&file->update_time,&tm_tmp);
|
|
net_store_data(packet, &tm_tmp);
|
|
}
|
|
if (!file->check_time)
|
|
net_store_null(packet);
|
|
else
|
|
{
|
|
localtime_r(&file->check_time,&tm_tmp);
|
|
net_store_data(packet, &tm_tmp);
|
|
}
|
|
{
|
|
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);
|
|
}
|
|
net_store_data(packet, convert, option_buff+1,
|
|
(ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1));
|
|
}
|
|
{
|
|
char *comment=table->file->update_table_comment(table->comment);
|
|
net_store_data(packet, comment);
|
|
if (comment != table->comment)
|
|
my_free(comment,MYF(0));
|
|
}
|
|
close_thread_tables(thd,0);
|
|
}
|
|
if (my_net_write(&thd->net,(char*) packet->ptr(),
|
|
packet->length()))
|
|
DBUG_RETURN(-1);
|
|
}
|
|
send_eof(&thd->net);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
** List all columns in a table
|
|
***************************************************************************/
|
|
|
|
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;
|
|
CONVERT *convert=thd->convert_set;
|
|
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->net);
|
|
DBUG_RETURN(1);
|
|
}
|
|
file=table->file;
|
|
file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
|
|
(void) get_table_grant(thd, table_list);
|
|
|
|
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));
|
|
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
|
|
{
|
|
char *pos;
|
|
pos=net_store_length(tmp, (uint) field_list.elements);
|
|
pos=net_store_length(pos,(ulonglong) file->records);
|
|
(void) my_net_write(&thd->net,tmp,(uint) (pos-tmp));
|
|
}
|
|
|
|
if (send_fields(thd,field_list,0))
|
|
DBUG_RETURN(1);
|
|
restore_record(table,2); // 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),default_charset_info);
|
|
uint col_access;
|
|
bool null_default_value=0;
|
|
|
|
packet->length(0);
|
|
net_store_data(packet,convert,field->field_name);
|
|
field->sql_type(type);
|
|
net_store_data(packet,convert,type.ptr(),type.length());
|
|
|
|
pos=(byte*) ((flags & NOT_NULL_FLAG) &&
|
|
field->type() != FIELD_TYPE_TIMESTAMP ?
|
|
"" : "YES");
|
|
net_store_data(packet,convert,(const char*) pos);
|
|
pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
|
|
(field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
|
|
(field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
|
|
net_store_data(packet,convert,(char*) pos);
|
|
|
|
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),default_charset_info);
|
|
field->val_str(&type,&type);
|
|
net_store_data(packet,convert,type.ptr(),type.length());
|
|
}
|
|
else if (field->maybe_null() || null_default_value)
|
|
net_store_null(packet); // Null as default
|
|
else
|
|
net_store_data(packet,convert,tmp,0);
|
|
|
|
char *end=tmp;
|
|
if (field->unireg_check == Field::NEXT_NUMBER)
|
|
end=strmov(tmp,"auto_increment");
|
|
net_store_data(packet,convert,tmp,(uint) (end-tmp));
|
|
|
|
if (verbose)
|
|
{
|
|
/* Add grant options & comments */
|
|
col_access= get_column_grant(thd,table_list,field) & COL_ACLS;
|
|
end=tmp;
|
|
for (uint bitnr=0; col_access ; col_access>>=1,bitnr++)
|
|
{
|
|
if (col_access & 1)
|
|
{
|
|
*end++=',';
|
|
end=strmov(end,grant_types.type_names[bitnr]);
|
|
}
|
|
}
|
|
net_store_data(packet,convert, tmp+1,end == tmp ? 0 : (uint) (end-tmp-1));
|
|
net_store_data(packet, field->comment.str,field->comment.length);
|
|
}
|
|
if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
|
|
DBUG_RETURN(1);
|
|
}
|
|
}
|
|
}
|
|
send_eof(&thd->net);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
int
|
|
mysqld_show_create(THD *thd, TABLE_LIST *table_list)
|
|
{
|
|
TABLE *table;
|
|
CONVERT *convert=thd->convert_set;
|
|
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->net);
|
|
DBUG_RETURN(1);
|
|
}
|
|
|
|
List<Item> field_list;
|
|
field_list.push_back(new Item_empty_string("Table",NAME_LEN));
|
|
field_list.push_back(new Item_empty_string("Create Table",1024));
|
|
|
|
if (send_fields(thd,field_list,1))
|
|
DBUG_RETURN(1);
|
|
|
|
String *packet = &thd->packet;
|
|
{
|
|
packet->length(0);
|
|
net_store_data(packet,convert, table->table_name);
|
|
/*
|
|
A hack - we need to reserve some space for the length before
|
|
we know what it is - let's assume that the length of create table
|
|
statement will fit into 3 bytes ( 16 MB max :-) )
|
|
*/
|
|
ulong store_len_offset = packet->length();
|
|
packet->length(store_len_offset + 4);
|
|
if (store_create_info(thd, table, packet))
|
|
DBUG_RETURN(-1);
|
|
ulong create_len = packet->length() - store_len_offset - 4;
|
|
/*
|
|
Just in case somebody manages to create a table
|
|
with *that* much stuff in the definition
|
|
*/
|
|
if (create_len > 0x00ffffff) // better readable in HEX ...
|
|
{
|
|
/*
|
|
Just in case somebody manages to create a table
|
|
with *that* much stuff in the definition
|
|
*/
|
|
DBUG_RETURN(1);
|
|
}
|
|
|
|
/*
|
|
Now we have to store the length in three bytes, even if it would fit
|
|
into fewer bytes, so we cannot use net_store_data() anymore,
|
|
and do it ourselves
|
|
*/
|
|
char* p = (char*)packet->ptr() + store_len_offset;
|
|
*p++ = (char) 253; // The client the length is stored using 3-bytes
|
|
int3store(p, create_len);
|
|
|
|
// now we are in business :-)
|
|
if (my_net_write(&thd->net, (char*)packet->ptr(), packet->length()))
|
|
DBUG_RETURN(1);
|
|
}
|
|
send_eof(&thd->net);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
int
|
|
mysqld_show_logs(THD *thd)
|
|
{
|
|
DBUG_ENTER("mysqld_show_logs");
|
|
|
|
List<Item> field_list;
|
|
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 (send_fields(thd,field_list,1))
|
|
DBUG_RETURN(1);
|
|
|
|
#ifdef HAVE_BERKELEY_DB
|
|
if (!berkeley_skip && berkeley_show_logs(thd))
|
|
DBUG_RETURN(-1);
|
|
#endif
|
|
|
|
send_eof(&thd->net);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
int
|
|
mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
|
|
{
|
|
TABLE *table;
|
|
char buff[256];
|
|
CONVERT *convert=thd->convert_set;
|
|
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->net);
|
|
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_int("Non_unique",0,1));
|
|
field_list.push_back(new Item_empty_string("Key_name",NAME_LEN));
|
|
field_list.push_back(new Item_int("Seq_in_index",0,2));
|
|
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,11));
|
|
item->maybe_null=1;
|
|
field_list.push_back(item=new Item_int("Sub_part",0,3));
|
|
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 (send_fields(thd,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;
|
|
char *end;
|
|
for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
|
|
{
|
|
packet->length(0);
|
|
net_store_data(packet,convert,table->table_name);
|
|
net_store_data(packet,convert,((key_info->flags & HA_NOSAME) ? "0" :"1"), 1);
|
|
net_store_data(packet,convert,key_info->name);
|
|
end=int10_to_str((long) (j+1),(char*) buff,10);
|
|
net_store_data(packet,convert,buff,(uint) (end-buff));
|
|
net_store_data(packet,convert,
|
|
key_part->field ? key_part->field->field_name :
|
|
"?unknown field?");
|
|
if (table->file->index_flags(i) & HA_READ_ORDER)
|
|
net_store_data(packet,convert,
|
|
((key_part->key_part_flag & HA_REVERSE_SORT) ?
|
|
"D" : "A"), 1);
|
|
else
|
|
net_store_null(packet); /* purecov: inspected */
|
|
KEY *key=table->key_info+i;
|
|
if (key->rec_per_key[j])
|
|
{
|
|
ulong records=(table->file->records / key->rec_per_key[j]);
|
|
end=int10_to_str((long) records, buff, 10);
|
|
net_store_data(packet,convert,buff,(uint) (end-buff));
|
|
}
|
|
else
|
|
net_store_null(packet);
|
|
|
|
/* 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())
|
|
{
|
|
end=int10_to_str((long) key_part->length, buff,10); /* purecov: inspected */
|
|
net_store_data(packet,convert,buff,(uint) (end-buff)); /* purecov: inspected */
|
|
}
|
|
else
|
|
net_store_null(packet);
|
|
net_store_null(packet); // No pack_information yet
|
|
|
|
/* Null flag */
|
|
uint flags= key_part->field ? key_part->field->flags : 0;
|
|
char *pos=(char*) ((flags & NOT_NULL_FLAG) ? "" : "YES");
|
|
net_store_data(packet,convert,(const char*) pos);
|
|
net_store_data(packet,convert,table->file->index_type(i));
|
|
/* Comment */
|
|
net_store_data(packet,convert,"");
|
|
if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
|
|
DBUG_RETURN(1); /* purecov: inspected */
|
|
}
|
|
}
|
|
send_eof(&thd->net);
|
|
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->net);
|
|
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,2); // Get empty record
|
|
if (send_fields(thd,field_list,2))
|
|
DBUG_VOID_RETURN;
|
|
VOID(net_flush(&thd->net));
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
int
|
|
mysqld_dump_create_info(THD *thd, TABLE *table, int fd)
|
|
{
|
|
CONVERT *convert=thd->convert_set;
|
|
DBUG_ENTER("mysqld_dump_create_info");
|
|
DBUG_PRINT("enter",("table: %s",table->real_name));
|
|
|
|
String* packet = &thd->packet;
|
|
packet->length(0);
|
|
if (store_create_info(thd,table,packet))
|
|
DBUG_RETURN(-1);
|
|
|
|
if (convert)
|
|
convert->convert((char*) packet->ptr(), packet->length());
|
|
if (fd < 0)
|
|
{
|
|
if (my_net_write(&thd->net, (char*)packet->ptr(), packet->length()))
|
|
DBUG_RETURN(-1);
|
|
VOID(net_flush(&thd->net));
|
|
}
|
|
else
|
|
{
|
|
if (my_write(fd, (const byte*) packet->ptr(), packet->length(),
|
|
MYF(MY_WME)))
|
|
DBUG_RETURN(-1);
|
|
}
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
static void
|
|
append_identifier(THD *thd, String *packet, const char *name)
|
|
{
|
|
if (thd->options & OPTION_QUOTE_SHOW_CREATE)
|
|
{
|
|
packet->append("`", 1);
|
|
packet->append(name);
|
|
packet->append("`", 1);
|
|
}
|
|
else
|
|
{
|
|
packet->append(name);
|
|
}
|
|
}
|
|
|
|
static int
|
|
store_create_info(THD *thd, TABLE *table, String *packet)
|
|
{
|
|
DBUG_ENTER("store_create_info");
|
|
DBUG_PRINT("enter",("table: %s",table->real_name));
|
|
|
|
restore_record(table,2); // Get empty record
|
|
|
|
List<Item> field_list;
|
|
char tmp[MAX_FIELD_WIDTH];
|
|
String type(tmp, sizeof(tmp),default_charset_info);
|
|
if (table->tmp_table)
|
|
packet->append("CREATE TEMPORARY TABLE ", 23);
|
|
else
|
|
packet->append("CREATE TABLE ", 13);
|
|
append_identifier(thd,packet,table->real_name);
|
|
packet->append(" (\n", 3);
|
|
|
|
Field **ptr,*field;
|
|
for (ptr=table->field ; (field= *ptr); ptr++)
|
|
{
|
|
if (ptr != table->field)
|
|
packet->append(",\n", 2);
|
|
|
|
uint flags = field->flags;
|
|
packet->append(" ", 2);
|
|
append_identifier(thd,packet,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),default_charset_info);
|
|
|
|
field->sql_type(type);
|
|
packet->append(type.ptr(),type.length());
|
|
|
|
bool has_default = (field->type() != FIELD_TYPE_BLOB &&
|
|
field->type() != FIELD_TYPE_TIMESTAMP &&
|
|
field->unireg_check != Field::NEXT_NUMBER);
|
|
if (flags & NOT_NULL_FLAG)
|
|
packet->append(" NOT NULL", 9);
|
|
|
|
if (has_default)
|
|
{
|
|
packet->append(" default ", 9);
|
|
if (!field->is_null())
|
|
{ // Not null by default
|
|
type.set(tmp,sizeof(tmp),default_charset_info);
|
|
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)
|
|
packet->append(" auto_increment", 15 );
|
|
|
|
if (field->comment.length)
|
|
{
|
|
packet->append(" COMMENT ",9);
|
|
append_unescaped(packet, field->comment.str, field->comment.length);
|
|
}
|
|
}
|
|
|
|
KEY *key_info=table->key_info;
|
|
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME);
|
|
uint 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);
|
|
|
|
// +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(" USING RTREE",12);
|
|
|
|
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);
|
|
if (!key_part->field ||
|
|
(key_part->length !=
|
|
table->field[key_part->fieldnr-1]->key_length() &&
|
|
!(key_info->flags & HA_FULLTEXT)))
|
|
{
|
|
char buff[64];
|
|
buff[0] = '(';
|
|
char* end=int10_to_str((long) key_part->length, buff + 1,10);
|
|
*end++ = ')';
|
|
packet->append(buff,(uint) (end-buff));
|
|
}
|
|
}
|
|
packet->append(')');
|
|
}
|
|
|
|
handler *file = table->file;
|
|
|
|
/* Get possible foreign key definitions stored in InnoDB and append them
|
|
to the CREATE TABLE statement */
|
|
|
|
char* for_str = file->get_foreign_key_create_info();
|
|
|
|
if (for_str) {
|
|
packet->append(for_str, strlen(for_str));
|
|
|
|
file->free_foreign_key_create_info(for_str);
|
|
}
|
|
|
|
packet->append("\n)", 2);
|
|
packet->append(" TYPE=", 6);
|
|
packet->append(file->table_type());
|
|
char buff[128];
|
|
char* p;
|
|
|
|
if (table->table_charset)
|
|
{
|
|
packet->append(" CHARSET=");
|
|
packet->append(table->table_charset->name);
|
|
}
|
|
|
|
if (table->min_rows)
|
|
{
|
|
packet->append(" MIN_ROWS=");
|
|
p = longlong10_to_str(table->min_rows, buff, 10);
|
|
packet->append(buff, (uint) (p - buff));
|
|
}
|
|
|
|
if (table->max_rows)
|
|
{
|
|
packet->append(" MAX_ROWS=");
|
|
p = longlong10_to_str(table->max_rows, buff, 10);
|
|
packet->append(buff, (uint) (p - buff));
|
|
}
|
|
if (table->avg_row_length)
|
|
{
|
|
packet->append(" AVG_ROW_LENGTH=");
|
|
p=longlong10_to_str(table->avg_row_length, buff,10);
|
|
packet->append(buff, (uint) (p - 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)
|
|
{
|
|
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);
|
|
packet->append(buff);
|
|
}
|
|
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 ? max_allowed_packet : PROCESS_LIST_WIDTH;
|
|
CONVERT *convert=thd->convert_set;
|
|
DBUG_ENTER("mysqld_list_processes");
|
|
|
|
field_list.push_back(new Item_int("Id",0,7));
|
|
field_list.push_back(new Item_empty_string("User",16));
|
|
field_list.push_back(new Item_empty_string("Host",64));
|
|
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_empty_string("Time",7));
|
|
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 (send_fields(thd,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++))
|
|
{
|
|
if ((tmp->net.vio || tmp->system_thread) &&
|
|
(!user || (tmp->user && !strcmp(tmp->user,user))))
|
|
{
|
|
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"));
|
|
thd_info->host=thd->strdup(tmp->host ? tmp->host :
|
|
(tmp->ip ? tmp->ip :
|
|
(tmp->system_thread ? "none" :
|
|
"connecting host")));
|
|
if ((thd_info->db=tmp->db)) // Safe test
|
|
thd_info->db=thd->strdup(thd_info->db);
|
|
thd_info->command=(int) tmp->command;
|
|
if (tmp->mysys_var)
|
|
pthread_mutex_lock(&tmp->mysys_var->mutex);
|
|
thd_info->proc_info= (char*) (tmp->killed ? "Killed" : 0);
|
|
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);
|
|
if (tmp->mysys_var)
|
|
pthread_mutex_unlock(&tmp->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;
|
|
String *packet= &thd->packet;
|
|
while ((thd_info=thread_infos.get()))
|
|
{
|
|
char buff[20],*end;
|
|
packet->length(0);
|
|
end=int10_to_str((long) thd_info->thread_id, buff,10);
|
|
net_store_data(packet,convert,buff,(uint) (end-buff));
|
|
net_store_data(packet,convert,thd_info->user);
|
|
net_store_data(packet,convert,thd_info->host);
|
|
if (thd_info->db)
|
|
net_store_data(packet,convert,thd_info->db);
|
|
else
|
|
net_store_null(packet);
|
|
if (thd_info->proc_info)
|
|
net_store_data(packet,convert,thd_info->proc_info);
|
|
else
|
|
net_store_data(packet,convert,command_name[thd_info->command]);
|
|
if (thd_info->start_time)
|
|
net_store_data(packet,
|
|
(uint32) (time((time_t*) 0) - thd_info->start_time));
|
|
else
|
|
net_store_null(packet);
|
|
if (thd_info->state_info)
|
|
net_store_data(packet,convert,thd_info->state_info);
|
|
else
|
|
net_store_null(packet);
|
|
if (thd_info->query)
|
|
net_store_data(packet,convert,thd_info->query);
|
|
else
|
|
net_store_null(packet);
|
|
if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
|
|
break; /* purecov: inspected */
|
|
}
|
|
send_eof(&thd->net);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
** Status functions
|
|
*****************************************************************************/
|
|
|
|
int mysqld_show_charsets(THD *thd, const char *wild)
|
|
{
|
|
uint i;
|
|
char buff[8192];
|
|
String packet2(buff,sizeof(buff),default_charset_info);
|
|
List<Item> field_list;
|
|
CONVERT *convert=thd->convert_set;
|
|
CHARSET_INFO *cs;
|
|
DBUG_ENTER("mysqld_show_charsets");
|
|
|
|
field_list.push_back(new Item_empty_string("Name",30));
|
|
field_list.push_back(new Item_int("Id",0,7));
|
|
field_list.push_back(new Item_int("strx_maxlen",0,7));
|
|
field_list.push_back(new Item_int("mb_maxlen",0,7));
|
|
|
|
if (send_fields(thd,field_list,1))
|
|
DBUG_RETURN(1);
|
|
|
|
for (cs=all_charsets ; cs < all_charsets+255 ; cs++ )
|
|
{
|
|
if (!cs->name)
|
|
continue;
|
|
if (!(wild && wild[0] && wild_case_compare(system_charset_info,cs->name,wild)))
|
|
{
|
|
packet2.length(0);
|
|
net_store_data(&packet2,convert,cs->name);
|
|
net_store_data(&packet2,(uint32) cs->number);
|
|
net_store_data(&packet2,(uint32) cs->strxfrm_multiply);
|
|
net_store_data(&packet2,(uint32) cs->mbmaxlen);
|
|
|
|
if (my_net_write(&thd->net, (char*) packet2.ptr(),packet2.length()))
|
|
goto err;
|
|
}
|
|
}
|
|
send_eof(&thd->net);
|
|
DBUG_RETURN(0);
|
|
err:
|
|
DBUG_RETURN(1);
|
|
}
|
|
|
|
|
|
int mysqld_show(THD *thd, const char *wild, show_var_st *variables)
|
|
{
|
|
uint i;
|
|
char buff[8192];
|
|
String packet2(buff,sizeof(buff),default_charset_info);
|
|
List<Item> field_list;
|
|
CONVERT *convert=thd->convert_set;
|
|
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 (send_fields(thd,field_list,1))
|
|
DBUG_RETURN(1); /* purecov: inspected */
|
|
|
|
/* pthread_mutex_lock(&THR_LOCK_keycache); */
|
|
pthread_mutex_lock(&LOCK_status);
|
|
for (i=0; variables[i].name; i++)
|
|
{
|
|
if (!(wild && wild[0] && wild_case_compare(system_charset_info,
|
|
variables[i].name,wild)))
|
|
{
|
|
packet2.length(0);
|
|
net_store_data(&packet2,convert,variables[i].name);
|
|
switch (variables[i].type){
|
|
case SHOW_LONG:
|
|
case SHOW_LONG_CONST:
|
|
net_store_data(&packet2,(uint32) *(ulong*) variables[i].value);
|
|
break;
|
|
case SHOW_BOOL:
|
|
net_store_data(&packet2,(ulong) *(bool*) variables[i].value ?
|
|
"ON" : "OFF");
|
|
break;
|
|
case SHOW_MY_BOOL:
|
|
net_store_data(&packet2,(ulong) *(my_bool*) variables[i].value ?
|
|
"ON" : "OFF");
|
|
break;
|
|
case SHOW_INT_CONST:
|
|
case SHOW_INT:
|
|
net_store_data(&packet2,(uint32) *(int*) variables[i].value);
|
|
break;
|
|
case SHOW_HAVE:
|
|
{
|
|
SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) variables[i].value;
|
|
net_store_data(&packet2, (tmp == SHOW_OPTION_NO ? "NO" :
|
|
tmp == SHOW_OPTION_YES ? "YES" :
|
|
"DISABLED"));
|
|
break;
|
|
}
|
|
case SHOW_CHAR:
|
|
net_store_data(&packet2,convert, variables[i].value);
|
|
break;
|
|
case SHOW_STARTTIME:
|
|
net_store_data(&packet2,(uint32) (thd->query_start() - start_time));
|
|
break;
|
|
case SHOW_QUESTION:
|
|
net_store_data(&packet2,(uint32) thd->query_id);
|
|
break;
|
|
case SHOW_RPL_STATUS:
|
|
net_store_data(&packet2, rpl_status_type[(int)rpl_status]);
|
|
break;
|
|
case SHOW_SLAVE_RUNNING:
|
|
{
|
|
LOCK_ACTIVE_MI;
|
|
net_store_data(&packet2, (active_mi->slave_running &&
|
|
active_mi->rli.slave_running)
|
|
? "ON" : "OFF");
|
|
UNLOCK_ACTIVE_MI;
|
|
break;
|
|
}
|
|
case SHOW_OPENTABLES:
|
|
net_store_data(&packet2,(uint32) cached_tables());
|
|
break;
|
|
case SHOW_CHAR_PTR:
|
|
{
|
|
char *value= *(char**) variables[i].value;
|
|
net_store_data(&packet2,convert, value ? value : "");
|
|
break;
|
|
}
|
|
#ifdef HAVE_OPENSSL
|
|
/* First group - functions relying on CTX */
|
|
case SHOW_SSL_CTX_SESS_ACCEPT:
|
|
net_store_data(&packet2,(uint32)
|
|
(!ssl_acceptor_fd ? 0 :
|
|
SSL_CTX_sess_accept(ssl_acceptor_fd->ssl_context_)));
|
|
break;
|
|
case SHOW_SSL_CTX_SESS_ACCEPT_GOOD:
|
|
net_store_data(&packet2,(uint32)
|
|
(!ssl_acceptor_fd ? 0 :
|
|
SSL_CTX_sess_accept_good(ssl_acceptor_fd->ssl_context_)));
|
|
break;
|
|
case SHOW_SSL_CTX_SESS_CONNECT_GOOD:
|
|
net_store_data(&packet2,(uint32)
|
|
(!ssl_acceptor_fd ? 0 :
|
|
SSL_CTX_sess_connect_good(ssl_acceptor_fd->ssl_context_)));
|
|
break;
|
|
case SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE:
|
|
net_store_data(&packet2,(uint32)
|
|
(!ssl_acceptor_fd ? 0 :
|
|
SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context_)));
|
|
break;
|
|
case SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE:
|
|
net_store_data(&packet2,(uint32)
|
|
(!ssl_acceptor_fd ? 0 :
|
|
SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd->ssl_context_)));
|
|
break;
|
|
case SHOW_SSL_CTX_SESS_CB_HITS:
|
|
net_store_data(&packet2,(uint32)
|
|
(!ssl_acceptor_fd ? 0 :
|
|
SSL_CTX_sess_cb_hits(ssl_acceptor_fd->ssl_context_)));
|
|
break;
|
|
case SHOW_SSL_CTX_SESS_HITS:
|
|
net_store_data(&packet2,(uint32)
|
|
(!ssl_acceptor_fd ? 0 :
|
|
SSL_CTX_sess_hits(ssl_acceptor_fd->ssl_context_)));
|
|
break;
|
|
case SHOW_SSL_CTX_SESS_CACHE_FULL:
|
|
net_store_data(&packet2,(uint32)
|
|
(!ssl_acceptor_fd ? 0 :
|
|
SSL_CTX_sess_cache_full(ssl_acceptor_fd->ssl_context_)));
|
|
break;
|
|
case SHOW_SSL_CTX_SESS_MISSES:
|
|
net_store_data(&packet2,(uint32)
|
|
(!ssl_acceptor_fd ? 0 :
|
|
SSL_CTX_sess_misses(ssl_acceptor_fd->ssl_context_)));
|
|
break;
|
|
case SHOW_SSL_CTX_SESS_TIMEOUTS:
|
|
net_store_data(&packet2,(uint32)
|
|
(!ssl_acceptor_fd ? 0 :
|
|
SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context_)));
|
|
break;
|
|
case SHOW_SSL_CTX_SESS_NUMBER:
|
|
net_store_data(&packet2,(uint32)
|
|
(!ssl_acceptor_fd ? 0 :
|
|
SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context_)));
|
|
break;
|
|
case SHOW_SSL_CTX_SESS_CONNECT:
|
|
net_store_data(&packet2,(uint32)
|
|
(!ssl_acceptor_fd ? 0 :
|
|
SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context_)));
|
|
break;
|
|
case SHOW_SSL_CTX_SESS_GET_CACHE_SIZE:
|
|
net_store_data(&packet2,(uint32)
|
|
(!ssl_acceptor_fd ? 0 :
|
|
SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context_)));
|
|
break;
|
|
case SHOW_SSL_CTX_GET_VERIFY_MODE:
|
|
net_store_data(&packet2,(uint32)
|
|
(!ssl_acceptor_fd ? 0 :
|
|
SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context_)));
|
|
break;
|
|
case SHOW_SSL_CTX_GET_VERIFY_DEPTH:
|
|
net_store_data(&packet2,(uint32)
|
|
(!ssl_acceptor_fd ? 0 :
|
|
SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context_)));
|
|
break;
|
|
case SHOW_SSL_CTX_GET_SESSION_CACHE_MODE:
|
|
if (!ssl_acceptor_fd)
|
|
{
|
|
net_store_data(&packet2,"NONE" );
|
|
break;
|
|
}
|
|
switch(SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context_))
|
|
{
|
|
case SSL_SESS_CACHE_OFF:
|
|
net_store_data(&packet2,"OFF" );
|
|
break;
|
|
case SSL_SESS_CACHE_CLIENT:
|
|
net_store_data(&packet2,"CLIENT" );
|
|
break;
|
|
case SSL_SESS_CACHE_SERVER:
|
|
net_store_data(&packet2,"SERVER" );
|
|
break;
|
|
case SSL_SESS_CACHE_BOTH:
|
|
net_store_data(&packet2,"BOTH" );
|
|
break;
|
|
case SSL_SESS_CACHE_NO_AUTO_CLEAR:
|
|
net_store_data(&packet2,"NO_AUTO_CLEAR" );
|
|
break;
|
|
case SSL_SESS_CACHE_NO_INTERNAL_LOOKUP:
|
|
net_store_data(&packet2,"NO_INTERNAL_LOOKUP" );
|
|
break;
|
|
default:
|
|
net_store_data(&packet2,"Unknown");
|
|
break;
|
|
}
|
|
break;
|
|
/* First group - functions relying on SSL */
|
|
case SHOW_SSL_GET_VERSION:
|
|
net_store_data(&packet2, thd->net.vio->ssl_ ?
|
|
SSL_get_version(thd->net.vio->ssl_) : "");
|
|
break;
|
|
case SHOW_SSL_SESSION_REUSED:
|
|
net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ?
|
|
SSL_session_reused(thd->net.vio->ssl_) : 0));
|
|
break;
|
|
case SHOW_SSL_GET_DEFAULT_TIMEOUT:
|
|
net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ?
|
|
SSL_get_default_timeout(thd->net.vio->ssl_):0));
|
|
break;
|
|
case SHOW_SSL_GET_VERIFY_MODE:
|
|
net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ?
|
|
SSL_get_verify_mode(thd->net.vio->ssl_):0));
|
|
break;
|
|
case SHOW_SSL_GET_VERIFY_DEPTH:
|
|
net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ?
|
|
SSL_get_verify_depth(thd->net.vio->ssl_):0));
|
|
break;
|
|
case SHOW_SSL_GET_CIPHER:
|
|
net_store_data(&packet2, thd->net.vio->ssl_ ?
|
|
SSL_get_cipher(thd->net.vio->ssl_) : "");
|
|
break;
|
|
case SHOW_SSL_GET_CIPHER_LIST:
|
|
if (thd->net.vio->ssl_)
|
|
{
|
|
char buf[1024], *pos;
|
|
pos=buf;
|
|
for (int i=0 ; i++ ;)
|
|
{
|
|
const char *p=SSL_get_cipher_list(thd->net.vio->ssl_,i);
|
|
if (p == NULL)
|
|
break;
|
|
pos=strmov(pos, p);
|
|
*pos++= ':';
|
|
}
|
|
if (pos != buf)
|
|
pos--; // Remove last ':'
|
|
*pos=0;
|
|
net_store_data(&packet2, buf);
|
|
}
|
|
else
|
|
net_store_data(&packet2, "");
|
|
break;
|
|
|
|
#endif /* HAVE_OPENSSL */
|
|
}
|
|
if (my_net_write(&thd->net, (char*) packet2.ptr(),packet2.length()))
|
|
goto err; /* purecov: inspected */
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&LOCK_status);
|
|
/* pthread_mutex_unlock(&THR_LOCK_keycache); */
|
|
send_eof(&thd->net);
|
|
DBUG_RETURN(0);
|
|
|
|
err:
|
|
pthread_mutex_unlock(&LOCK_status);
|
|
/* pthread_mutex_unlock(&THR_LOCK_keycache); */
|
|
DBUG_RETURN(1);
|
|
}
|
|
|
|
#ifdef __GNUC__
|
|
template class List_iterator_fast<char>;
|
|
template class List<char>;
|
|
#endif
|