diff options
Diffstat (limited to 'sql/sql_show.cc')
-rw-r--r-- | sql/sql_show.cc | 1032 |
1 files changed, 1032 insertions, 0 deletions
diff --git a/sql/sql_show.cc b/sql/sql_show.cc new file mode 100644 index 00000000000..55142e21dad --- /dev/null +++ b/sql/sql_show.cc @@ -0,0 +1,1032 @@ +/* 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 */ + +#undef USE_RAID +#define USE_RAID +#include "mysql_priv.h" +#include "sql_select.h" // For select_describe +#include "sql_acl.h" +#include <my_dir.h> +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); + +/**************************************************************************** +** 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); + List<Item> field_list; + char *end; + List<char> files; + char *file_name; + DBUG_ENTER("mysqld_show_dbs"); + + field->name=(char*) sql_alloc(20+ (wild ? 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<char> it(files); + while ((file_name=it++)) + { + thd->packet.length(0); + net_store_data(&thd->packet,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 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); + List<Item> field_list; + char path[FN_LEN],*end; + List<char> files; + char *file_name; + DBUG_ENTER("mysqld_show_tables"); + + field->name=(char*) sql_alloc(20+strlen(db)+(wild ? 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<char> it(files); + while ((file_name=it++)) + { + thd->packet.length(0); + net_store_data(&thd->packet,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); +} + + +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"); + + 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[0] && wild_compare(file->name,wild))) + continue; + } + } + else + { + // Return only .frm files which isn't temp files. + if (my_strcasecmp(ext=fn_ext(file->name),reg_ext) || + is_prefix(file->name,tmp_file_prefix)) // Mysql temp table + continue; + *ext=0; + if (wild && wild[0] && 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)) + continue; + } + if (files->push_back(sql_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; + 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)); + 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<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,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,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, file->table_type()); + net_store_data(packet, + (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, " 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, option_buff+1, + (ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1)); + } + net_store_data(packet, table->comment); + + 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) +{ + TABLE *table; + handler *file; + char tmp[MAX_FIELD_WIDTH]; + 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(new Item_empty_string("Default",NAME_LEN)); + field_list.push_back(new Item_empty_string("Extra",20)); + field_list.push_back(new Item_empty_string("Privileges",80)); + + // 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; + for (ptr=table->field; (field= *ptr) ; ptr++) + { + if (!wild || !wild[0] || !wild_case_compare(field->field_name,wild)) + { +#ifdef NOT_USED + if (thd->col_access & TABLE_ACLS || + ! check_grant_column(thd,table,field->field_name, + strlen(field->field_name),1)) +#endif + { + byte *pos; + uint flags=field->flags; + String *packet= &thd->packet,type(tmp,sizeof(tmp)); + uint col_access; + bool null_default_value=0; + + packet->length(0); + net_store_data(packet,field->field_name); + field->sql_type(type); + net_store_data(packet,type.ptr(),type.length()); + + pos=(byte*) ((flags & NOT_NULL_FLAG) && + field->type() != FIELD_TYPE_TIMESTAMP ? + "" : "YES"); + net_store_data(packet,(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,(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)); + field->val_str(&type,&type); + net_store_data(packet,type.ptr(),type.length()); + } + else if (field->maybe_null() || null_default_value) + net_store_null(packet); // Null as default + else + net_store_data(packet,tmp,0); + + char *end=tmp; + if (field->unireg_check == Field::NEXT_NUMBER) + end=strmov(tmp,"auto_increment"); + net_store_data(packet,tmp,(uint) (end-tmp)); + + /* Add grant options */ + 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,tmp+1,end == tmp ? 0 : (uint) (end-tmp-1)); + 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; + DBUG_ENTER("mysqld_show_create"); + 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; + 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; + for(;table; table = table->next) + { + packet->length(0); + net_store_data(packet, 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; + if(create_len > 0x00ffffff) // better readable in HEX ... + DBUG_RETURN(1); // just in case somebody manages to create a table + // with *that* much stuff in the definition + + // now we have to store the length in three bytes, even if it would fit + // into fewer, 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_keys(THD *thd, TABLE_LIST *table_list) +{ + TABLE *table; + char buff[256]; + 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("Comment",255)); + item->maybe_null=1; + + if (send_fields(thd,field_list,1)) + DBUG_RETURN(1); + + 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; + String *packet= &thd->packet; + for (uint j=0 ; j < key_info->key_parts ; j++,key_part++) + { + packet->length(0); + net_store_data(packet,table->table_name); + net_store_data(packet,((key_info->flags & HA_NOSAME) ? "0" :"1"), 1); + net_store_data(packet,key_info->name); + end=int10_to_str((long) (j+1),(char*) buff,10); + net_store_data(packet,buff,(uint) (end-buff)); + net_store_data(packet,key_part->field ? key_part->field->field_name : + "?unknown field?"); + if (table->file->option_flag() & HA_READ_ORDER) + net_store_data(packet,((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,buff,(uint) (end-buff)); + } + else + net_store_null(packet); + 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,buff,(uint) (end-buff)); /* purecov: inspected */ + } + else + net_store_null(packet); + net_store_null(packet); // No pack_information yet + net_store_null(packet); // No comments yet + 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(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) +{ + 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(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 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)); + packet->append("create table ", 13); + packet->append(table->real_name); + packet->append('('); + + Field **ptr,*field; + for (ptr=table->field ; (field= *ptr); ptr++) + { + if(ptr != table->field) + packet->append(','); + + uint flags = field->flags; + packet->append(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)); + + field->sql_type(type); + packet->append(type.ptr(),type.length()); + + bool null_default_value = (field->type() == FIELD_TYPE_TIMESTAMP || + field->unireg_check == Field::NEXT_NUMBER); + bool has_default = (field->type() != FIELD_TYPE_BLOB); + + if((flags & NOT_NULL_FLAG) && !null_default_value) + packet->append(" not null", 9); + + + if(has_default) + { + packet->append(" default ", 9); + if (!null_default_value && !field->is_null()) + { // Not null by default + type.set(tmp,sizeof(tmp)); + field->val_str(&type,&type); + packet->append('\''); + packet->append(type.ptr(),type.length()); + packet->append('\''); + } + else if (field->maybe_null() || null_default_value) + packet->append("NULL", 4); // Null as default + else + packet->append(tmp,0); + } + + if (field->unireg_check == Field::NEXT_NUMBER) + packet->append(" auto_increment", 15 ); + + + } + + 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++) + { + packet->append(','); + + KEY_PART_INFO *key_part= key_info->key_part; + if(i == primary_key) + packet->append("primary", 7); + else if(key_info->flags & HA_NOSAME) + packet->append("unique", 6); + packet->append(" key ", 5); + + if(i != primary_key) + packet->append(key_info->name); + + packet->append('('); + + for (uint j=0 ; j < key_info->key_parts ; j++,key_part++) + { + if(j) + packet->append(','); + + if(key_part->field) + packet->append(key_part->field->field_name); + KEY *key=table->key_info+i; + + if (!key_part->field || + key_part->length != + table->field[key_part->fieldnr-1]->key_length()) + { + 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(')'); + } + + packet->append(')'); + + handler *file = table->file; + packet->append(" type=", 6); + packet->append(file->table_type()); + char buff[128]; + char* p; + + 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->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); + + + 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(size); } + static void operator delete(void *ptr __attribute__((unused)), + size_t size __attribute__((unused))) {} /*lint -e715 */ + + ulong thread_id,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; + 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=sql_strdup(tmp->user ? tmp->user : (tmp->system_thread ? + "system user" : "unauthenticated user")); + thd_info->host=sql_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=sql_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 + thd_info->start_time= tmp->start_time; + thd_info->query=0; + if (tmp->query) + { + uint length=strlen(tmp->query); + if (length > max_query_length) + length=max_query_length; + thd_info->query=(char*) sql_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,buff,(uint) (end-buff)); + net_store_data(packet,thd_info->user); + net_store_data(packet,thd_info->host); + if (thd_info->db) + net_store_data(packet,thd_info->db); + else + net_store_null(packet); + if (thd_info->proc_info) + net_store_data(packet,thd_info->proc_info); + else + net_store_data(packet,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,thd_info->state_info); + else + net_store_null(packet); + if (thd_info->query) + net_store_data(packet,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(THD *thd, const char *wild, show_var_st *variables) +{ + uint i; + char buff[8192]; + String packet2(buff,sizeof(buff)); + List<Item> field_list; + 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_compare(variables[i].name,wild))) + { + packet2.length(0); + net_store_data(&packet2,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_CHAR: + net_store_data(&packet2,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_OPENTABLES: + net_store_data(&packet2,(uint32) cached_tables()); + break; + case SHOW_CHAR_PTR: + { + char *value= *(char**) variables[i].value; + net_store_data(&packet2,value ? value : ""); + break; + } + } + 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<char>; +template class List<char>; +#endif |