sql_show.cc 44.3 KB
Newer Older
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
2

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3 4 5 6
   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.
7

bk@work.mysql.com's avatar
bk@work.mysql.com committed
8 9 10 11
   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.
12

bk@work.mysql.com's avatar
bk@work.mysql.com committed
13 14 15 16 17 18 19 20
   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"
21
#include "sql_select.h"                         // For select_describe
bk@work.mysql.com's avatar
bk@work.mysql.com committed
22
#include "sql_acl.h"
23
#include "repl_failsafe.h"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
24
#include <my_dir.h>
25

tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
26 27 28 29
#ifdef HAVE_BERKELEY_DB
#include "ha_berkeley.h"			// For berkeley_show_logs
#endif

30
/* extern "C" pthread_mutex_t THR_LOCK_keycache; */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
31 32 33 34 35 36

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 **),
37 38
                               "grant_types",
                               grant_names};
bk@work.mysql.com's avatar
bk@work.mysql.com committed
39 40

static int mysql_find_files(THD *thd,List<char> *files, const char *db,
41
                            const char *path, const char *wild, bool dir);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
42 43

static int
44 45 46 47
store_create_info(THD *thd, TABLE *table, String *packet);

static void
append_identifier(THD *thd, String *packet, const char *name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
48

tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
49 50
extern struct st_VioSSLAcceptorFd * ssl_acceptor_fd;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
/****************************************************************************
** 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");

67
  field->name=(char*) thd->alloc(20+ (wild ? (uint) strlen(wild)+4: 0));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
68 69 70 71 72 73 74 75 76 77
  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);
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
78
  List_iterator_fast<char> it(files);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
79 80
  while ((file_name=it++))
  {
81
    if (thd->master_access & (DB_ACLS | SHOW_DB_ACL) ||
82 83 84
	acl_get(thd->host, thd->ip, (char*) &thd->remote.sin_addr,
		thd->priv_user, file_name) ||
	(grant_option && !check_grant_db(thd, file_name)))
85
    {
86
      thd->packet.length(0);
87
      net_store_data(&thd->packet, thd->variables.convert_set, file_name);
88 89 90 91
      if (my_net_write(&thd->net, (char*) thd->packet.ptr(),
		       thd->packet.length()))
	DBUG_RETURN(-1);
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
92 93 94 95 96
  }
  send_eof(&thd->net);
  DBUG_RETURN(0);
}

97 98 99 100
/***************************************************************************
** List all open tables in a database
***************************************************************************/

101
int mysqld_show_open_tables(THD *thd,const char *wild)
102 103
{
  List<Item> field_list;
104
  OPEN_TABLE_LIST *open_list;
105
  CONVERT *convert=thd->variables.convert_set;
106 107
  DBUG_ENTER("mysqld_show_open_tables");

108 109 110 111
  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));
112 113 114

  if (send_fields(thd,field_list,1))
    DBUG_RETURN(1);
115

monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
116
  if (!(open_list=list_open_tables(thd,wild)) && thd->fatal_error)
117 118
    DBUG_RETURN(-1);

119
  for (; open_list ; open_list=open_list->next)
120 121
  {
    thd->packet.length(0);
122 123 124 125
    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);
126
    if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
127
    {
128
      DBUG_RETURN(-1);
129
    }
130 131 132 133 134
  }
  send_eof(&thd->net);
  DBUG_RETURN(0);
}

135

bk@work.mysql.com's avatar
bk@work.mysql.com committed
136 137 138 139 140 141 142 143 144 145 146 147 148 149
/***************************************************************************
** 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");

150
  field->name=(char*) thd->alloc(20+(uint) strlen(db)+(wild ? (uint) strlen(wild)+4:0));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
151 152 153 154 155 156 157 158 159 160 161
  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);
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
162
  List_iterator_fast<char> it(files);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
163 164 165
  while ((file_name=it++))
  {
    thd->packet.length(0);
166
    net_store_data(&thd->packet, thd->variables.convert_set, file_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
167 168 169 170 171 172 173 174 175 176
    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,
177
                 const char *wild, bool dir)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
178 179 180 181 182 183 184 185 186
{
  uint i;
  char *ext;
  MY_DIR *dirp;
  FILEINFO *file;
  uint col_access=thd->col_access;
  TABLE_LIST table_list;
  DBUG_ENTER("mysql_find_files");

187 188
  if (wild && !wild[0])
    wild=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
189 190 191 192 193
  bzero((char*) &table_list,sizeof(table_list));

  if (!(dirp = my_dir(path,MYF(MY_WME | (dir ? MY_WANT_STAT : 0)))))
    DBUG_RETURN(-1);

194
  for (i=0 ; i < (uint) dirp->number_off_files  ; i++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
195 196 197
  {
    file=dirp->dir_entry+i;
    if (dir)
198
    {                                           /* Return databases */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
199 200 201
#ifdef USE_SYMDIR
      char *ext;
      if (my_use_symdir && !strcmp(ext=fn_ext(file->name), ".sym"))
202
        *ext=0;                                 /* Remove extension */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
203 204 205
      else
#endif
      {
206
        if (file->name[0] == '.' || !MY_S_ISDIR(file->mystat.st_mode) ||
207
            (wild && wild_compare(file->name,wild)))
208
          continue;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
209 210 211 212
      }
    }
    else
    {
213
        // Return only .frm files which aren't temp files.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
214
      if (my_strcasecmp(ext=fn_ext(file->name),reg_ext) ||
215
          is_prefix(file->name,tmp_file_prefix))
216
        continue;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
217
      *ext=0;
218 219 220 221 222 223 224 225 226 227
      if (wild)
      {
	if (lower_case_table_names)
	{
	  if (wild_case_compare(file->name,wild))
	    continue;
	}
	else if (wild_compare(file->name,wild))
	  continue;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
228 229 230 231 232 233 234
    }
    /* 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;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
235
      if (check_grant(thd,TABLE_ACLS,&table_list,1,1))
236
        continue;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
237
    }
238
    if (files->push_back(thd->strdup(file->name)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
    {
      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;
262
  CONVERT *convert=thd->variables.convert_set;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
  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);
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
302
  List_iterator_fast<char> it(files);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
303 304 305 306 307
  while ((file_name=it++))
  {
    TABLE_LIST table_list;
    bzero((char*) &table_list,sizeof(table_list));
    packet->length(0);
308
    net_store_data(packet,convert, file_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
309
    table_list.db=(char*) db;
310
    table_list.real_name= table_list.alias= file_name;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
311 312 313
    if (!(table = open_ltable(thd, &table_list, TL_READ)))
    {
      for (uint i=0 ; i < field_list.elements ; i++)
314
        net_store_null(packet);
315
      net_store_data(packet,convert, thd->net.last_error);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
316 317 318 319 320 321 322
      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);
323 324
      net_store_data(packet, convert, file->table_type());
      net_store_data(packet, convert,
325 326
                     (table->db_options_in_use & HA_OPTION_COMPRESS_RECORD) ?
		     "Compressed" :
327
                     (table->db_options_in_use & HA_OPTION_PACK_RECORD) ?
328
                     "Dynamic" : "Fixed");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
329 330 331 332
      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)
333
        net_store_data(packet, (longlong) file->max_data_file_length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
334
      else
335
        net_store_null(packet);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
336 337 338 339
      net_store_data(packet, (longlong) file->index_file_length);
      net_store_data(packet, (longlong) file->delete_length);
      if (table->found_next_number_field)
      {
340 341 342 343 344
        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;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
345 346
      }
      else
347
        net_store_null(packet);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
348
      if (!file->create_time)
349
        net_store_null(packet);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
350 351
      else
      {
352 353
        localtime_r(&file->create_time,&tm_tmp);
        net_store_data(packet, &tm_tmp);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
354 355
      }
      if (!file->update_time)
356
        net_store_null(packet);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
357 358
      else
      {
359 360
        localtime_r(&file->update_time,&tm_tmp);
        net_store_data(packet, &tm_tmp);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
361 362
      }
      if (!file->check_time)
363
        net_store_null(packet);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
364 365
      else
      {
366 367
        localtime_r(&file->check_time,&tm_tmp);
        net_store_data(packet, &tm_tmp);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
368 369
      }
      {
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
        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)
396
          ptr=strxmov(ptr, " row_format=", ha_row_type[(uint) table->row_type],
397 398 399 400 401 402 403 404
                      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);
        }
405
        net_store_data(packet, convert, option_buff+1,
406
                       (ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
407
      }
408 409 410 411 412 413
      {
	char *comment=table->file->update_table_comment(table->comment);
	net_store_data(packet, comment);
	if (comment != table->comment)
	  my_free(comment,MYF(0));
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
414 415 416
      close_thread_tables(thd,0);
    }
    if (my_net_write(&thd->net,(char*) packet->ptr(),
417
                     packet->length()))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
418 419 420 421 422 423 424 425 426
      DBUG_RETURN(-1);
  }
  send_eof(&thd->net);
  DBUG_RETURN(0);
}



/***************************************************************************
427
** List all columns in a table_list->real_name
bk@work.mysql.com's avatar
bk@work.mysql.com committed
428 429 430
***************************************************************************/

int
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
431 432
mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
		   bool verbose)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
433 434 435 436
{
  TABLE *table;
  handler *file;
  char tmp[MAX_FIELD_WIDTH];
437
  Item *item;
438
  CONVERT *convert=thd->variables.convert_set;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
439 440
  DBUG_ENTER("mysqld_show_fields");
  DBUG_PRINT("enter",("db: %s  table: %s",table_list->db,
441
                      table_list->real_name));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456

  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));
457 458
  field_list.push_back(item=new Item_empty_string("Default",NAME_LEN));
  item->maybe_null=1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
459
  field_list.push_back(new Item_empty_string("Extra",20));
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
460 461
  if (verbose)
    field_list.push_back(new Item_empty_string("Privileges",80));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
462

463
        // Send first number of fields and records
bk@work.mysql.com's avatar
bk@work.mysql.com committed
464 465 466 467 468 469 470 471 472
  {
    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);
473
  restore_record(table,2);      // Get empty record
bk@work.mysql.com's avatar
bk@work.mysql.com committed
474 475

  Field **ptr,*field;
tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
476
  String *packet= &thd->packet;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
477 478 479 480 481 482
  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 ||
483 484
          ! check_grant_column(thd,table,field->field_name,
                               (uint) strlen(field->field_name),1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
485 486
#endif
      {
487 488
        byte *pos;
        uint flags=field->flags;
tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
489
        String type(tmp,sizeof(tmp));
490 491 492 493
        uint col_access;
        bool null_default_value=0;

        packet->length(0);
494
        net_store_data(packet,convert,field->field_name);
495
        field->sql_type(type);
496
        net_store_data(packet,convert,type.ptr(),type.length());
497 498 499 500

        pos=(byte*) ((flags & NOT_NULL_FLAG) &&
                     field->type() != FIELD_TYPE_TIMESTAMP ?
                     "" : "YES");
501
        net_store_data(packet,convert,(const char*) pos);
502 503 504
        pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
                     (field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
                     (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
505
        net_store_data(packet,convert,(char*) pos);
506 507 508 509 510 511 512 513

        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);
514
          net_store_data(packet,convert,type.ptr(),type.length());
515 516 517 518
        }
        else if (field->maybe_null() || null_default_value)
          net_store_null(packet);                       // Null as default
        else
519
          net_store_data(packet,convert,tmp,0);
520 521 522 523

        char *end=tmp;
        if (field->unireg_check == Field::NEXT_NUMBER)
          end=strmov(tmp,"auto_increment");
524
        net_store_data(packet,convert,tmp,(uint) (end-tmp));
525

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
526 527 528 529 530 531 532 533 534 535 536 537 538
	if (verbose)
	{
	  /* 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]);
	    }
	  }
539
	  net_store_data(packet,convert, tmp+1,end == tmp ? 0 : (uint) (end-tmp-1));
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
540
	}
541 542
        if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
          DBUG_RETURN(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
543 544 545 546 547 548 549 550 551 552 553
      }
    }
  }
  send_eof(&thd->net);
  DBUG_RETURN(0);
}

int
mysqld_show_create(THD *thd, TABLE_LIST *table_list)
{
  TABLE *table;
554
  CONVERT *convert=thd->variables.convert_set;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
555 556
  DBUG_ENTER("mysqld_show_create");
  DBUG_PRINT("enter",("db: %s  table: %s",table_list->db,
557
                      table_list->real_name));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
558

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
559
  /* Only one table for now */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
560 561 562 563 564 565 566 567 568 569 570 571
  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);
572

bk@work.mysql.com's avatar
bk@work.mysql.com committed
573
  String *packet = &thd->packet;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
574 575
  {
    packet->length(0);
576
    net_store_data(packet,convert, table->table_name);
577 578 579 580 581
    /*
      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 :-) )
    */
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
582 583 584 585 586 587
    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 ...
588 589 590 591 592 593 594
    {
      /*
	Just in case somebody manages to create a table
	with *that* much stuff in the definition
      */
      DBUG_RETURN(1);
    }
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
595

596 597 598 599 600
    /*
      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
    */
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
601 602 603 604 605 606 607 608
    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);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
609 610 611 612 613
  send_eof(&thd->net);
  DBUG_RETURN(0);
}


tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
614 615 616 617 618 619 620 621 622 623 624 625 626
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);

627
#ifdef HAVE_BERKELEY_DB
628
  if (!berkeley_skip && berkeley_show_logs(thd))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
629
    DBUG_RETURN(-1);
630
#endif
tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
631 632 633 634 635 636

  send_eof(&thd->net);
  DBUG_RETURN(0);
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
637 638 639 640 641
int
mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
{
  TABLE *table;
  char buff[256];
642
  CONVERT *convert=thd->variables.convert_set;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
643 644
  DBUG_ENTER("mysqld_show_keys");
  DBUG_PRINT("enter",("db: %s  table: %s",table_list->db,
645
                      table_list->real_name));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661

  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;
662
  field_list.push_back(item=new Item_int("Cardinality",0,21));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
663 664 665 666 667
  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;
668 669
  field_list.push_back(new Item_empty_string("Null",3));
  field_list.push_back(new Item_empty_string("Index_type",16));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
670 671 672 673 674 675
  field_list.push_back(new Item_empty_string("Comment",255));
  item->maybe_null=1;

  if (send_fields(thd,field_list,1))
    DBUG_RETURN(1);

tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
676
  String *packet= &thd->packet;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
677 678 679 680 681 682 683 684 685
  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);
686 687 688
      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);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
689
      end=int10_to_str((long) (j+1),(char*) buff,10);
690 691 692
      net_store_data(packet,convert,buff,(uint) (end-buff));
      net_store_data(packet,convert,
		     key_part->field ? key_part->field->field_name :
693
                     "?unknown field?");
694
      if (table->file->index_flags(i) & HA_READ_ORDER)
695 696 697
        net_store_data(packet,convert,
		       ((key_part->key_part_flag & HA_REVERSE_SORT) ?
			"D" : "A"), 1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
698
      else
699
        net_store_null(packet); /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
700 701 702
      KEY *key=table->key_info+i;
      if (key->rec_per_key[j])
      {
703 704
        ha_rows records=(table->file->records / key->rec_per_key[j]);
        end=longlong10_to_str((longlong) records, buff, 10);
705
        net_store_data(packet,convert,buff,(uint) (end-buff));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
706 707
      }
      else
708
        net_store_null(packet);
709 710

      /* Check if we have a key part that only uses part of the field */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
711
      if (!key_part->field ||
712 713
          key_part->length !=
          table->field[key_part->fieldnr-1]->key_length())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
714
      {
715
        end=int10_to_str((long) key_part->length, buff,10); /* purecov: inspected */
716
        net_store_data(packet,convert,buff,(uint) (end-buff)); /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
717 718
      }
      else
719 720
        net_store_null(packet);
      net_store_null(packet);                   // No pack_information yet
721 722 723

      /* Null flag */
      uint flags= key_part->field ? key_part->field->flags : 0;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
724
      char *pos=(char*) ((flags & NOT_NULL_FLAG) ? "" : "YES");
725 726 727 728
      net_store_data(packet,convert,(const char*) pos);
      net_store_data(packet,convert,table->file->index_type(i));
      /* Comment */
      net_store_data(packet,convert,"");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
729
      if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
730
        DBUG_RETURN(1); /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762
    }
  }
  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));
  }
763
  restore_record(table,2);              // Get empty record
bk@work.mysql.com's avatar
bk@work.mysql.com committed
764 765 766 767 768 769 770 771 772
  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)
{
773
  CONVERT *convert=thd->variables.convert_set;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
774 775
  DBUG_ENTER("mysqld_dump_create_info");
  DBUG_PRINT("enter",("table: %s",table->real_name));
776

bk@work.mysql.com's avatar
bk@work.mysql.com committed
777 778
  String* packet = &thd->packet;
  packet->length(0);
779
  if (store_create_info(thd,table,packet))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
780
    DBUG_RETURN(-1);
781

782 783 784
  if (convert)
    convert->convert((char*) packet->ptr(), packet->length());
  if (fd < 0)
785
  {
786
    if (my_net_write(&thd->net, (char*)packet->ptr(), packet->length()))
787 788 789
      DBUG_RETURN(-1);
    VOID(net_flush(&thd->net));
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
790
  else
791
  {
792 793
    if (my_write(fd, (const byte*) packet->ptr(), packet->length(),
		 MYF(MY_WME)))
794 795
      DBUG_RETURN(-1);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
796 797
  DBUG_RETURN(0);
}
798

799 800 801 802 803 804 805 806 807 808 809 810 811 812 813
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);
  }
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
814
static int
815
store_create_info(THD *thd, TABLE *table, String *packet)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
816 817 818 819 820
{
  DBUG_ENTER("store_create_info");
  DBUG_PRINT("enter",("table: %s",table->real_name));

  restore_record(table,2); // Get empty record
821

bk@work.mysql.com's avatar
bk@work.mysql.com committed
822 823 824
  List<Item> field_list;
  char tmp[MAX_FIELD_WIDTH];
  String type(tmp, sizeof(tmp));
825 826 827 828
  if (table->tmp_table)
    packet->append("CREATE TEMPORARY TABLE ", 23);
  else
    packet->append("CREATE TABLE ", 13);
829
  append_identifier(thd,packet,table->real_name);
830
  packet->append(" (\n", 3);
831

bk@work.mysql.com's avatar
bk@work.mysql.com committed
832 833 834
  Field **ptr,*field;
  for (ptr=table->field ; (field= *ptr); ptr++)
  {
835
    if (ptr != table->field)
836
      packet->append(",\n", 2);
837

bk@work.mysql.com's avatar
bk@work.mysql.com committed
838
    uint flags = field->flags;
839
    packet->append("  ", 2);
840
    append_identifier(thd,packet,field->field_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
841 842
    packet->append(' ');
    // check for surprises from the previous call to Field::sql_type()
843
    if (type.ptr() != tmp)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
844
      type.set(tmp, sizeof(tmp));
845

bk@work.mysql.com's avatar
bk@work.mysql.com committed
846 847
    field->sql_type(type);
    packet->append(type.ptr(),type.length());
848

849
    bool has_default = (field->type() != FIELD_TYPE_BLOB &&
850 851 852 853
			field->type() != FIELD_TYPE_TIMESTAMP &&
			field->unireg_check != Field::NEXT_NUMBER);
    if (flags & NOT_NULL_FLAG)
      packet->append(" NOT NULL", 9);
854

855
    if (has_default)
856 857
    {
      packet->append(" default ", 9);
858
      if (!field->is_null())
859 860 861 862
      {                                             // Not null by default
        type.set(tmp,sizeof(tmp));
        field->val_str(&type,&type);
        packet->append('\'');
863
	if (type.length())
864
          append_unescaped(packet, type.c_ptr());
865
        packet->append('\'');
bk@work.mysql.com's avatar
bk@work.mysql.com committed
866
      }
867
      else if (field->maybe_null())
868 869 870 871
        packet->append("NULL", 4);                    // Null as default
      else
        packet->append(tmp,0);
    }
872

bk@work.mysql.com's avatar
bk@work.mysql.com committed
873
    if (field->unireg_check == Field::NEXT_NUMBER)
874
          packet->append(" auto_increment", 15 );
bk@work.mysql.com's avatar
bk@work.mysql.com committed
875 876 877 878 879
  }

  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;
880

bk@work.mysql.com's avatar
bk@work.mysql.com committed
881 882
  for (uint i=0 ; i < table->keys ; i++,key_info++)
  {
883 884
    KEY_PART_INFO *key_part= key_info->key_part;
    bool found_primary=0;
885
    packet->append(",\n  ", 4);
886

887 888 889
    if (i == primary_key && !strcmp(key_info->name,"PRIMARY"))
    {
      found_primary=1;
890
      packet->append("PRIMARY ", 8);
891
    }
892
    else if (key_info->flags & HA_NOSAME)
893
      packet->append("UNIQUE ", 7);
894
    else if (key_info->flags & HA_FULLTEXT)
895 896
      packet->append("FULLTEXT ", 9);
    packet->append("KEY ", 4);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
897

898
    if (!found_primary)
899
     append_identifier(thd,packet,key_info->name);
900

901
    packet->append(" (", 2);
902

bk@work.mysql.com's avatar
bk@work.mysql.com committed
903 904
    for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
    {
905
      if (j)
906
        packet->append(',');
907

908
      if (key_part->field)
909
        append_identifier(thd,packet,key_part->field->field_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
910
      if (!key_part->field ||
911 912 913
          (key_part->length !=
           table->field[key_part->fieldnr-1]->key_length() &&
           !(key_info->flags & HA_FULLTEXT)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
914
      {
915 916 917 918 919
        char buff[64];
        buff[0] = '(';
        char* end=int10_to_str((long) key_part->length, buff + 1,10);
        *end++ = ')';
        packet->append(buff,(uint) (end-buff));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
920 921 922 923
      }
    }
    packet->append(')');
  }
924

bk@work.mysql.com's avatar
bk@work.mysql.com committed
925
  handler *file = table->file;
926 927 928 929 930 931 932 933 934 935 936 937 938

  /* 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);
939
  packet->append(" TYPE=", 6);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
940 941 942
  packet->append(file->table_type());
  char buff[128];
  char* p;
943

944
  if (table->min_rows)
945 946 947 948 949
  {
    packet->append(" MIN_ROWS=");
    p = longlong10_to_str(table->min_rows, buff, 10);
    packet->append(buff, (uint) (p - buff));
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
950

951
  if (table->max_rows)
952 953 954 955 956
  {
    packet->append(" MAX_ROWS=");
    p = longlong10_to_str(table->max_rows, buff, 10);
    packet->append(buff, (uint) (p - buff));
  }
957 958 959 960 961 962
  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));
  }
963

bk@work.mysql.com's avatar
bk@work.mysql.com committed
964
  if (table->db_create_options & HA_OPTION_PACK_KEYS)
965
    packet->append(" PACK_KEYS=1", 12);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
966
  if (table->db_create_options & HA_OPTION_NO_PACK_KEYS)
967
    packet->append(" PACK_KEYS=0", 12);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
968
  if (table->db_create_options & HA_OPTION_CHECKSUM)
969
    packet->append(" CHECKSUM=1", 11);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
970
  if (table->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
971
    packet->append(" DELAY_KEY_WRITE=1",18);
972 973 974 975 976
  if (table->row_type != ROW_TYPE_DEFAULT)
  {
    packet->append(" ROW_FORMAT=",12);
    packet->append(ha_row_type[(uint) table->row_type]);
  }
977
  table->file->append_create_info(packet);
monty@donna.mysql.com's avatar
merge  
monty@donna.mysql.com committed
978
  if (table->comment && table->comment[0])
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
979 980 981 982 983
  {
    packet->append(" COMMENT='", 10);
    append_unescaped(packet, table->comment);
    packet->append('\'');
  }
984 985 986 987 988 989 990
  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);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
991 992 993 994 995 996 997 998 999 1000 1001
  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:
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1002
  static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1003
  static void operator delete(void *ptr __attribute__((unused)),
1004
                              size_t size __attribute__((unused))) {} /*lint -e715 */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1005

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1006 1007
  ulong thread_id;
  time_t start_time;
1008
  uint   command;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022
  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;
1023 1024 1025
  ulong max_query_length= (verbose ? thd->variables.max_allowed_packet :
			   PROCESS_LIST_WIDTH);
  CONVERT *convert=thd->variables.convert_set;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
  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++))
    {
1049
      struct st_my_thread_var *mysys_var;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1050
      if ((tmp->net.vio || tmp->system_thread) &&
1051
          (!user || (tmp->user && !strcmp(tmp->user,user))))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1052
      {
1053 1054 1055
        thread_info *thd_info=new thread_info;

        thd_info->thread_id=tmp->thread_id;
1056 1057 1058 1059 1060 1061 1062
        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")));
1063 1064 1065
        if ((thd_info->db=tmp->db))             // Safe test
          thd_info->db=thd->strdup(thd_info->db);
        thd_info->command=(int) tmp->command;
1066 1067
        if ((mysys_var= tmp->mysys_var))
          pthread_mutex_lock(&mysys_var->mutex);
1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078
        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);
1079 1080
        if (mysys_var)
          pthread_mutex_unlock(&mysys_var->mutex);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1081 1082

#if !defined(DONT_USE_THR_ALARM) && ! defined(SCO)
1083 1084
        if (pthread_kill(tmp->real_id,0))
          tmp->proc_info="*** DEAD ***";        // This shouldn't happen
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1085
#endif
1086 1087 1088
#ifdef EXTRA_DEBUG
        thd_info->start_time= tmp->time_after_lock;
#else
1089
        thd_info->start_time= tmp->start_time;
1090
#endif
1091 1092 1093
        thd_info->query=0;
        if (tmp->query)
        {
1094 1095
	  /* query_length is always set before tmp->query */
          uint length= min(max_query_length, tmp->query_length);
1096 1097 1098 1099
          thd_info->query=(char*) thd->memdup(tmp->query,length+1);
          thd_info->query[length]=0;
        }
        thread_infos.append(thd_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
      }
    }
  }
  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);
1112 1113 1114
    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);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1115
    if (thd_info->db)
1116
      net_store_data(packet,convert,thd_info->db);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1117 1118 1119
    else
      net_store_null(packet);
    if (thd_info->proc_info)
1120
      net_store_data(packet,convert,thd_info->proc_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1121
    else
1122
      net_store_data(packet,convert,command_name[thd_info->command]);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1123
    if (thd_info->start_time)
1124 1125
      net_store_data(packet,
		     (uint32) (time((time_t*) 0) - thd_info->start_time));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1126 1127 1128
    else
      net_store_null(packet);
    if (thd_info->state_info)
1129
      net_store_data(packet,convert,thd_info->state_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1130 1131 1132
    else
      net_store_null(packet);
    if (thd_info->query)
1133
      net_store_data(packet,convert,thd_info->query);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148
    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
*****************************************************************************/


1149
int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
1150
		enum enum_var_type value_type)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1151 1152 1153 1154
{
  char buff[8192];
  String packet2(buff,sizeof(buff));
  List<Item> field_list;
1155
  CONVERT *convert=thd->variables.convert_set;
1156

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1157 1158 1159 1160 1161 1162
  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 */

1163
  /* pthread_mutex_lock(&THR_LOCK_keycache); */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1164
  pthread_mutex_lock(&LOCK_status);
1165
  for (; variables->name; variables++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1166
  {
1167
    if (!(wild && wild[0] && wild_case_compare(variables->name,wild)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1168 1169
    {
      packet2.length(0);
1170 1171 1172 1173 1174 1175
      net_store_data(&packet2,convert,variables->name);
      SHOW_TYPE show_type=variables->type;
      char *value=variables->value;
      if (show_type == SHOW_SYS)
      {
	show_type= ((sys_var*) value)->type();
1176
	value=     (char*) ((sys_var*) value)->value_ptr(thd, value_type);
1177 1178 1179
      }

      switch (show_type) {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1180 1181
      case SHOW_LONG:
      case SHOW_LONG_CONST:
1182 1183 1184 1185
        net_store_data(&packet2,(uint32) *(ulong*) value);
        break;
      case SHOW_LONGLONG:
        net_store_data(&packet2,(longlong) *(longlong*) value);
1186
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1187
      case SHOW_BOOL:
1188
        net_store_data(&packet2,(ulong) *(bool*) value ? "ON" : "OFF");
1189
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1190
      case SHOW_MY_BOOL:
1191
        net_store_data(&packet2,(ulong) *(my_bool*) value ? "ON" : "OFF");
1192
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1193 1194
      case SHOW_INT_CONST:
      case SHOW_INT:
1195
        net_store_data(&packet2,(uint32) *(int*) value);
1196
        break;
1197 1198
      case SHOW_HAVE:
      {
1199
	SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) value;
1200 1201 1202 1203 1204
        net_store_data(&packet2, (tmp == SHOW_OPTION_NO ? "NO" :
				  tmp == SHOW_OPTION_YES ? "YES" :
				  "DISABLED"));
        break;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1205
      case SHOW_CHAR:
1206
        net_store_data(&packet2,convert, value);
1207
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1208
      case SHOW_STARTTIME:
1209 1210
        net_store_data(&packet2,(uint32) (thd->query_start() - start_time));
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1211
      case SHOW_QUESTION:
1212 1213
        net_store_data(&packet2,(uint32) thd->query_id);
        break;
1214 1215 1216
      case SHOW_RPL_STATUS:
	net_store_data(&packet2, rpl_status_type[(int)rpl_status]);
	break;
1217 1218 1219 1220 1221 1222 1223 1224 1225
      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;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1226
      case SHOW_OPENTABLES:
1227 1228
        net_store_data(&packet2,(uint32) cached_tables());
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1229
      case SHOW_CHAR_PTR:
1230 1231 1232 1233 1234
      {
	value= *(char**) value;
	net_store_data(&packet2,convert, value ? value : "");
	break;
      }
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1235
#ifdef HAVE_OPENSSL
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1236
	/* First group - functions relying on CTX */
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1237 1238
      case SHOW_SSL_CTX_SESS_ACCEPT:
	net_store_data(&packet2,(uint32) 
1239 1240
		       (!ssl_acceptor_fd ? 0 :
			SSL_CTX_sess_accept(ssl_acceptor_fd->ssl_context_)));
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1241 1242 1243
        break;
      case SHOW_SSL_CTX_SESS_ACCEPT_GOOD:
	net_store_data(&packet2,(uint32) 
1244 1245
		       (!ssl_acceptor_fd ? 0 :
			SSL_CTX_sess_accept_good(ssl_acceptor_fd->ssl_context_)));
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1246
        break;
1247 1248
      case SHOW_SSL_CTX_SESS_CONNECT_GOOD:
	net_store_data(&packet2,(uint32) 
1249 1250
		       (!ssl_acceptor_fd ? 0 :
			SSL_CTX_sess_connect_good(ssl_acceptor_fd->ssl_context_)));
1251
        break;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1252 1253
      case SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE:
	net_store_data(&packet2,(uint32) 
1254 1255
		       (!ssl_acceptor_fd ? 0 :
			SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context_)));
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1256
        break;
1257 1258
      case SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE:
	net_store_data(&packet2,(uint32) 
1259 1260
		       (!ssl_acceptor_fd ? 0 :
			SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd->ssl_context_)));
1261
        break;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1262 1263
      case SHOW_SSL_CTX_SESS_CB_HITS:
	net_store_data(&packet2,(uint32) 
1264 1265
		       (!ssl_acceptor_fd ? 0 :
			SSL_CTX_sess_cb_hits(ssl_acceptor_fd->ssl_context_)));
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1266
        break;
1267 1268
      case SHOW_SSL_CTX_SESS_HITS:
	net_store_data(&packet2,(uint32) 
1269 1270
		       (!ssl_acceptor_fd ? 0 :
			SSL_CTX_sess_hits(ssl_acceptor_fd->ssl_context_)));
1271 1272 1273
        break;
      case SHOW_SSL_CTX_SESS_CACHE_FULL:
	net_store_data(&packet2,(uint32) 
1274 1275
		       (!ssl_acceptor_fd ? 0 :
			SSL_CTX_sess_cache_full(ssl_acceptor_fd->ssl_context_)));
1276 1277 1278
        break;
      case SHOW_SSL_CTX_SESS_MISSES:
	net_store_data(&packet2,(uint32) 
1279 1280
		       (!ssl_acceptor_fd ? 0 :
			SSL_CTX_sess_misses(ssl_acceptor_fd->ssl_context_)));
1281 1282 1283
        break;
      case SHOW_SSL_CTX_SESS_TIMEOUTS:
	net_store_data(&packet2,(uint32) 
1284 1285
		       (!ssl_acceptor_fd ? 0 :
			SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context_)));
1286
        break;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1287 1288
      case SHOW_SSL_CTX_SESS_NUMBER:
	net_store_data(&packet2,(uint32) 
1289 1290
		       (!ssl_acceptor_fd ? 0 :
			SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context_)));
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1291
        break;
1292 1293
      case SHOW_SSL_CTX_SESS_CONNECT:
	net_store_data(&packet2,(uint32) 
1294 1295
		       (!ssl_acceptor_fd ? 0 :
			SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context_)));
1296
        break;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1297 1298
      case SHOW_SSL_CTX_SESS_GET_CACHE_SIZE:
	net_store_data(&packet2,(uint32) 
1299 1300
		       (!ssl_acceptor_fd ? 0 :
			SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context_)));
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1301 1302 1303
        break;
      case SHOW_SSL_CTX_GET_VERIFY_MODE:
	net_store_data(&packet2,(uint32) 
1304 1305
		       (!ssl_acceptor_fd ? 0 :
			SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context_)));
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1306 1307 1308
        break;
      case SHOW_SSL_CTX_GET_VERIFY_DEPTH:
	net_store_data(&packet2,(uint32) 
1309 1310
		       (!ssl_acceptor_fd ? 0 :
			SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context_)));
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1311 1312
        break;
      case SHOW_SSL_CTX_GET_SESSION_CACHE_MODE:
1313 1314 1315 1316 1317
	if (!ssl_acceptor_fd)
	{
	  net_store_data(&packet2,"NONE" );
	  break;
	}
1318
	switch (SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context_))
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342
	{
          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;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364
	/* 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:
1365 1366 1367
	net_store_data(&packet2, thd->net.vio->ssl_ ?
		       SSL_get_cipher(thd->net.vio->ssl_) : "");
	break;
1368
      case SHOW_SSL_GET_CIPHER_LIST:
1369
	if (thd->net.vio->ssl_)
1370
	{
1371 1372 1373
	  char buf[1024], *pos;
	  pos=buf;
	  for (int i=0 ; i++ ;)
1374 1375 1376 1377
	  {
	    const char *p=SSL_get_cipher_list(thd->net.vio->ssl_,i);
	    if (p == NULL) 
	      break;
1378 1379
	    pos=strmov(pos, p);
	    *pos++= ':';
1380
	  }
1381 1382 1383
	  if (pos != buf)
	    pos--;				// Remove last ':'
	  *pos=0;
1384
 	  net_store_data(&packet2, buf);
1385 1386
        }
	else
1387
 	  net_store_data(&packet2, "");
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1388
        break;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1389 1390

#endif /* HAVE_OPENSSL */
1391 1392 1393 1394
      case SHOW_UNDEF:				// Show never happen
      case SHOW_SYS:
	net_store_data(&packet2, "");		// Safety
	break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1395 1396
      }
      if (my_net_write(&thd->net, (char*) packet2.ptr(),packet2.length()))
1397
        goto err;                               /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1398 1399 1400
    }
  }
  pthread_mutex_unlock(&LOCK_status);
1401
  /* pthread_mutex_unlock(&THR_LOCK_keycache); */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1402 1403 1404 1405 1406
  send_eof(&thd->net);
  DBUG_RETURN(0);

 err:
  pthread_mutex_unlock(&LOCK_status);
1407
  /* pthread_mutex_unlock(&THR_LOCK_keycache); */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1408 1409 1410 1411
  DBUG_RETURN(1);
}

#ifdef __GNUC__
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1412
template class List_iterator_fast<char>;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1413 1414
template class List<char>;
#endif