sql_show.cc 64 KB
Newer Older
1
/* Copyright (C) 2000 MySQL AB
2

unknown's avatar
unknown 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

unknown's avatar
unknown 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

unknown's avatar
unknown 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
unknown's avatar
unknown committed
22
#include "sql_acl.h"
23
#include "repl_failsafe.h"
unknown's avatar
unknown committed
24
#include <my_dir.h>
unknown's avatar
unknown committed
25

unknown's avatar
unknown committed
26 27 28 29
#ifdef HAVE_BERKELEY_DB
#include "ha_berkeley.h"			// For berkeley_show_logs
#endif

unknown's avatar
unknown committed
30 31 32 33
static const char *grant_names[]={
  "select","insert","update","delete","create","drop","reload","shutdown",
  "process","file","grant","references","index","alter"};

unknown's avatar
unknown committed
34
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
35
static TYPELIB grant_types = { sizeof(grant_names)/sizeof(char **),
36 37
                               "grant_types",
                               grant_names};
unknown's avatar
unknown committed
38
#endif
unknown's avatar
unknown 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);
unknown's avatar
unknown committed
42 43

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

unknown's avatar
unknown committed
46

47 48 49 50
/*
  Report list of databases
  A database is a directory in the mysql_data_home directory
*/
unknown's avatar
SCRUM  
unknown committed
51

unknown's avatar
unknown committed
52 53 54
int
mysqld_show_dbs(THD *thd,const char *wild)
{
unknown's avatar
unknown committed
55
  Item_string *field=new Item_string("",0,thd->charset());
unknown's avatar
unknown committed
56 57 58 59
  List<Item> field_list;
  char *end;
  List<char> files;
  char *file_name;
60
  Protocol *protocol= thd->protocol;
unknown's avatar
unknown committed
61 62
  DBUG_ENTER("mysqld_show_dbs");

unknown's avatar
unknown committed
63
  field->name=(char*) thd->alloc(20+ (wild ? (uint) strlen(wild)+4: 0));
unknown's avatar
unknown committed
64 65 66 67 68 69
  field->max_length=NAME_LEN;
  end=strmov(field->name,"Database");
  if (wild && wild[0])
    strxmov(end," (",wild,")",NullS);
  field_list.push_back(field);

70
  if (protocol->send_fields(&field_list,1))
unknown's avatar
unknown committed
71 72 73
    DBUG_RETURN(1);
  if (mysql_find_files(thd,&files,NullS,mysql_data_home,wild,1))
    DBUG_RETURN(1);
unknown's avatar
unknown committed
74
  List_iterator_fast<char> it(files);
75

unknown's avatar
unknown committed
76 77
  while ((file_name=it++))
  {
unknown's avatar
unknown committed
78
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
79
    if (thd->master_access & (DB_ACLS | SHOW_DB_ACL) ||
80
	acl_get(thd->host, thd->ip, thd->priv_user, file_name,0) ||
81
	(grant_option && !check_grant_db(thd, file_name)))
unknown's avatar
unknown committed
82
#endif
unknown's avatar
unknown committed
83
    {
84
      protocol->prepare_for_resend();
85
      protocol->store(file_name, system_charset_info);
86
      if (protocol->write())
87 88
	DBUG_RETURN(-1);
    }
unknown's avatar
unknown committed
89
  }
90
  send_eof(thd);
unknown's avatar
unknown committed
91 92 93
  DBUG_RETURN(0);
}

94

95
/***************************************************************************
96
  List all open tables in a database
97 98
***************************************************************************/

99
int mysqld_show_open_tables(THD *thd,const char *wild)
100 101
{
  List<Item> field_list;
102
  OPEN_TABLE_LIST *open_list;
103
  Protocol *protocol= thd->protocol;
104 105
  DBUG_ENTER("mysqld_show_open_tables");

106 107
  field_list.push_back(new Item_empty_string("Database",NAME_LEN));
  field_list.push_back(new Item_empty_string("Table",NAME_LEN));
108 109
  field_list.push_back(new Item_return_int("In_use", 1, MYSQL_TYPE_TINY));
  field_list.push_back(new Item_return_int("Name_locked", 4, MYSQL_TYPE_TINY));
110

111
  if (protocol->send_fields(&field_list,1))
112
    DBUG_RETURN(1);
113

114
  if (!(open_list=list_open_tables(thd,wild)) && thd->is_fatal_error)
115 116
    DBUG_RETURN(-1);

117
  for (; open_list ; open_list=open_list->next)
118
  {
119
    protocol->prepare_for_resend();
120 121
    protocol->store(open_list->db, system_charset_info);
    protocol->store(open_list->table, system_charset_info);
122 123 124
    protocol->store_tiny((longlong) open_list->in_use);
    protocol->store_tiny((longlong) open_list->locked);
    if (protocol->write())
125
    {
126
      DBUG_RETURN(-1);
127
    }
128
  }
129
  send_eof(thd);
130 131 132
  DBUG_RETURN(0);
}

133

unknown's avatar
unknown committed
134 135 136 137 138 139 140
/***************************************************************************
** 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)
{
unknown's avatar
unknown committed
141
  Item_string *field=new Item_string("",0,thd->charset());
unknown's avatar
unknown committed
142 143 144 145
  List<Item> field_list;
  char path[FN_LEN],*end;
  List<char> files;
  char *file_name;
146
  Protocol *protocol= thd->protocol;
unknown's avatar
unknown committed
147 148
  DBUG_ENTER("mysqld_show_tables");

149 150
  field->name=(char*) thd->alloc(20+(uint) strlen(db)+
				 (wild ? (uint) strlen(wild)+4:0));
unknown's avatar
unknown committed
151 152 153 154 155 156 157
  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);
158
  if (protocol->send_fields(&field_list,1))
unknown's avatar
unknown committed
159 160 161
    DBUG_RETURN(1);
  if (mysql_find_files(thd,&files,db,path,wild,0))
    DBUG_RETURN(-1);
unknown's avatar
unknown committed
162
  List_iterator_fast<char> it(files);
unknown's avatar
unknown committed
163 164
  while ((file_name=it++))
  {
165
    protocol->prepare_for_resend();
166
    protocol->store(file_name, system_charset_info);
167
    if (protocol->write())
unknown's avatar
unknown committed
168 169
      DBUG_RETURN(-1);
  }
170
  send_eof(thd);
unknown's avatar
unknown committed
171 172 173
  DBUG_RETURN(0);
}

unknown's avatar
unknown committed
174 175 176 177
/***************************************************************************
** List all table types supported 
***************************************************************************/

unknown's avatar
unknown committed
178
int mysqld_show_storage_engines(THD *thd)
unknown's avatar
unknown committed
179 180
{
  List<Item> field_list;
181
  Protocol *protocol= thd->protocol;
unknown's avatar
unknown committed
182
  DBUG_ENTER("mysqld_show_storage_engines");
unknown's avatar
unknown committed
183

unknown's avatar
unknown committed
184
  field_list.push_back(new Item_empty_string("Engine",10));
unknown's avatar
unknown committed
185
  field_list.push_back(new Item_empty_string("Support",10));
186
  field_list.push_back(new Item_empty_string("Comment",80));
unknown's avatar
unknown committed
187

188
  if (protocol->send_fields(&field_list,1))
unknown's avatar
unknown committed
189 190
    DBUG_RETURN(1);

191
  const char *default_type_name= 
unknown's avatar
unknown committed
192
    ha_get_storage_engine((enum db_type)thd->variables.table_type);
unknown's avatar
unknown committed
193

194 195
  show_table_type_st *types;
  for (types= sys_table_types; types->type; types++)
unknown's avatar
unknown committed
196
  {
197
    protocol->prepare_for_resend();
198
    protocol->store(types->type, system_charset_info);
199 200 201
    const char *option_name= show_comp_option_name[(int) *types->value];

    if (*types->value == SHOW_OPTION_YES &&
202
	!my_strcasecmp(system_charset_info, default_type_name, types->type))
203
      option_name= "DEFAULT";
204 205
    protocol->store(option_name, system_charset_info);
    protocol->store(types->comment, system_charset_info);
206
    if (protocol->write())
unknown's avatar
unknown committed
207 208
      DBUG_RETURN(-1);
  }
209
  send_eof(thd);
unknown's avatar
unknown committed
210 211 212
  DBUG_RETURN(0);
}

213

unknown's avatar
unknown committed
214
/***************************************************************************
215
 List all privileges supported
unknown's avatar
unknown committed
216 217
***************************************************************************/

218 219 220 221
struct show_privileges_st {
  const char *privilege;
  const char *context;
  const char *comment;
unknown's avatar
unknown committed
222 223
};

224 225
static struct show_privileges_st sys_privileges[]=
{
unknown's avatar
unknown committed
226 227
  {"Alter", "Tables",  "To alter the table"},
  {"Create temporary tables","Databases","To use CREATE TEMPORARY TABLE"},
228
  {"Create", "Databases,Tables,Indexes",  "To create new databases and tables"},
unknown's avatar
unknown committed
229 230 231 232 233 234 235 236
  {"Delete", "Tables",  "To delete existing rows"},
  {"Drop", "Databases,Tables", "To drop databases and tables"},
  {"File", "File access on server",   "To read and write files on the server"},
  {"Grant option",  "Databases,Tables", "To give to other users those privileges you possess"},
  {"Index", "Tables",  "To create or drop indexes"},
  {"Insert", "Tables",  "To insert data into tables"},
  {"Lock tables","Databases","To use LOCK TABLES (together with SELECT privilege)"},
  {"Process", "Server Admin", "To view the plain text of currently executing queries"},
237
  {"References", "Databases,Tables", "To have references on tables"},
unknown's avatar
unknown committed
238 239 240 241 242
  {"Reload", "Server Admin", "To reload or refresh tables, logs and privileges"},
  {"Replication client","Server Admin","To ask where the slave or master servers are"},
  {"Replication slave","Server Admin","To read binary log events from the master"},
  {"Select", "Tables",  "To retrieve rows from table"},
  {"Show databases","Server Admin","To see all databases with SHOW DATABASES"},
243
  {"Shutdown","Server Admin", "To shutdown the server"},
unknown's avatar
unknown committed
244 245 246
  {"Super","Server Admin","To use KILL thread, SET GLOBAL, CHANGE MASTER, etc."},
  {"Update", "Tables",  "To update existing rows"},
  {"Usage","Server Admin","No privileges - allow connect only"},
247 248 249
  {NullS, NullS, NullS}
};

unknown's avatar
unknown committed
250 251 252
int mysqld_show_privileges(THD *thd)
{
  List<Item> field_list;
253
  Protocol *protocol= thd->protocol;
unknown's avatar
unknown committed
254 255 256 257 258 259
  DBUG_ENTER("mysqld_show_privileges");

  field_list.push_back(new Item_empty_string("Privilege",10));
  field_list.push_back(new Item_empty_string("Context",15));
  field_list.push_back(new Item_empty_string("Comment",NAME_LEN));

260
  if (protocol->send_fields(&field_list,1))
unknown's avatar
unknown committed
261 262
    DBUG_RETURN(1);

263 264
  show_privileges_st *privilege= sys_privileges;
  for (privilege= sys_privileges; privilege->privilege ; privilege++)
unknown's avatar
unknown committed
265
  {
266
    protocol->prepare_for_resend();
267 268 269
    protocol->store(privilege->privilege, system_charset_info);
    protocol->store(privilege->context, system_charset_info);
    protocol->store(privilege->comment, system_charset_info);
270
    if (protocol->write())
unknown's avatar
unknown committed
271 272
      DBUG_RETURN(-1);
  }
273
  send_eof(thd);
unknown's avatar
unknown committed
274 275 276 277 278
  DBUG_RETURN(0);
}


/***************************************************************************
279
  List all column types
unknown's avatar
unknown committed
280 281
***************************************************************************/

282 283
struct show_column_type_st
{
unknown's avatar
unknown committed
284 285
  const char *type;
  uint size;
286 287 288 289 290 291 292 293 294 295 296 297
  const char *min_value;
  const char *max_value;
  uint precision;
  uint scale;
  const char *nullable;
  const char *auto_increment;
  const char *unsigned_attr;
  const char *zerofill;
  const char *searchable;
  const char *case_sensitivity;
  const char *default_value;
  const char *comment;
unknown's avatar
unknown committed
298
};
299 300 301 302 303

/* TODO: Add remaning types */

static struct show_column_type_st sys_column_types[]=
{
unknown's avatar
unknown committed
304 305
  {"tinyint",
    1,  "-128",  "127",  0,  0,  "YES",  "YES",
unknown's avatar
unknown committed
306 307
    "NO",   "YES", "YES",  "NO",  "NULL,0",
    "A very small integer"},
unknown's avatar
unknown committed
308
  {"tinyint unsigned",
unknown's avatar
unknown committed
309 310
    1,  "0"   ,  "255",  0,  0,  "YES",  "YES",
    "YES",  "YES",  "YES",  "NO",  "NULL,0",
unknown's avatar
unknown committed
311 312 313 314 315 316
    "A very small integer"},
};

int mysqld_show_column_types(THD *thd)
{
  List<Item> field_list;
317
  Protocol *protocol= thd->protocol;
unknown's avatar
unknown committed
318 319 320 321 322 323
  DBUG_ENTER("mysqld_show_column_types");

  field_list.push_back(new Item_empty_string("Type",30));
  field_list.push_back(new Item_int("Size",(longlong) 1,21));
  field_list.push_back(new Item_empty_string("Min_Value",20));
  field_list.push_back(new Item_empty_string("Max_Value",20));
324 325
  field_list.push_back(new Item_return_int("Prec", 4, MYSQL_TYPE_SHORT));
  field_list.push_back(new Item_return_int("Scale", 4, MYSQL_TYPE_SHORT));
unknown's avatar
unknown committed
326 327 328 329 330 331 332 333 334
  field_list.push_back(new Item_empty_string("Nullable",4));
  field_list.push_back(new Item_empty_string("Auto_Increment",4));
  field_list.push_back(new Item_empty_string("Unsigned",4));
  field_list.push_back(new Item_empty_string("Zerofill",4));
  field_list.push_back(new Item_empty_string("Searchable",4));
  field_list.push_back(new Item_empty_string("Case_Sensitive",4));
  field_list.push_back(new Item_empty_string("Default",NAME_LEN));
  field_list.push_back(new Item_empty_string("Comment",NAME_LEN));

335
  if (protocol->send_fields(&field_list,1))
unknown's avatar
unknown committed
336 337
    DBUG_RETURN(1);

338
  /* TODO: Change the loop to not use 'i' */
unknown's avatar
unknown committed
339 340
  for (uint i=0; i < sizeof(sys_column_types)/sizeof(sys_column_types[0]); i++)
  {
341
    protocol->prepare_for_resend();
342
    protocol->store(sys_column_types[i].type, system_charset_info);
343
    protocol->store((ulonglong) sys_column_types[i].size);
344 345
    protocol->store(sys_column_types[i].min_value, system_charset_info);
    protocol->store(sys_column_types[i].max_value, system_charset_info);
346 347
    protocol->store_short((longlong) sys_column_types[i].precision);
    protocol->store_short((longlong) sys_column_types[i].scale);
348 349 350 351 352 353 354 355
    protocol->store(sys_column_types[i].nullable, system_charset_info);
    protocol->store(sys_column_types[i].auto_increment, system_charset_info);
    protocol->store(sys_column_types[i].unsigned_attr, system_charset_info);
    protocol->store(sys_column_types[i].zerofill, system_charset_info);
    protocol->store(sys_column_types[i].searchable, system_charset_info);
    protocol->store(sys_column_types[i].case_sensitivity, system_charset_info);
    protocol->store(sys_column_types[i].default_value, system_charset_info);
    protocol->store(sys_column_types[i].comment, system_charset_info);
356
    if (protocol->write())
unknown's avatar
unknown committed
357 358
      DBUG_RETURN(-1);
  }
359
  send_eof(thd);
unknown's avatar
unknown committed
360 361 362 363 364 365
  DBUG_RETURN(0);
}


static int
mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
366
                 const char *wild, bool dir)
unknown's avatar
unknown committed
367 368 369 370 371
{
  uint i;
  char *ext;
  MY_DIR *dirp;
  FILEINFO *file;
unknown's avatar
unknown committed
372
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
373
  uint col_access=thd->col_access;
unknown's avatar
unknown committed
374
#endif
unknown's avatar
unknown committed
375 376 377
  TABLE_LIST table_list;
  DBUG_ENTER("mysql_find_files");

378 379
  if (wild && !wild[0])
    wild=0;
unknown's avatar
unknown committed
380 381 382 383 384
  bzero((char*) &table_list,sizeof(table_list));

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

385
  for (i=0 ; i < (uint) dirp->number_off_files  ; i++)
unknown's avatar
unknown committed
386 387 388
  {
    file=dirp->dir_entry+i;
    if (dir)
389
    {                                           /* Return databases */
unknown's avatar
unknown committed
390 391 392
#ifdef USE_SYMDIR
      char *ext;
      if (my_use_symdir && !strcmp(ext=fn_ext(file->name), ".sym"))
393 394 395 396
      {
	/* Only show the sym file if it points to a directory */
	char buff[FN_REFLEN], *end;
	MY_STAT status;
397
        *ext=0;                                 /* Remove extension */
398 399 400 401 402 403 404 405
	unpack_dirname(buff, file->name);
	end= strend(buff);
	if (end != buff && end[-1] == FN_LIBCHAR)
	  end[-1]= 0;				// Remove end FN_LIBCHAR
	if (!my_stat(buff, &status, MYF(0)) ||
	    !MY_S_ISDIR(status.st_mode))
	  continue;
      }
unknown's avatar
unknown committed
406 407 408
      else
#endif
      {
unknown's avatar
unknown committed
409
        if (file->name[0] == '.' || !MY_S_ISDIR(file->mystat->st_mode) ||
410
            (wild && wild_compare(file->name,wild,0)))
411
          continue;
unknown's avatar
unknown committed
412 413 414 415
      }
    }
    else
    {
416
        // Return only .frm files which aren't temp files.
417
      if (my_strcasecmp(system_charset_info, ext=fn_ext(file->name),reg_ext) ||
418
          is_prefix(file->name,tmp_file_prefix))
419
        continue;
unknown's avatar
unknown committed
420
      *ext=0;
421 422 423 424
      if (wild)
      {
	if (lower_case_table_names)
	{
425
	  if (wild_case_compare(system_charset_info,file->name,wild))
426 427
	    continue;
	}
428
	else if (wild_compare(file->name,wild,0))
429 430
	  continue;
      }
unknown's avatar
unknown committed
431
    }
unknown's avatar
unknown committed
432
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
433 434 435 436 437 438
    /* 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;
unknown's avatar
unknown committed
439
      if (check_grant(thd, TABLE_ACLS, &table_list, 1, UINT_MAX, 1))
440
        continue;
unknown's avatar
unknown committed
441
    }
unknown's avatar
unknown committed
442
#endif
443
    if (files->push_back(thd->strdup(file->name)))
unknown's avatar
unknown committed
444 445 446 447 448 449 450 451 452 453
    {
      my_dirend(dirp);
      DBUG_RETURN(-1);
    }
  }
  DBUG_PRINT("info",("found: %d files", files->elements));
  my_dirend(dirp);
  DBUG_RETURN(0);
}

454

unknown's avatar
unknown committed
455
/***************************************************************************
456
 Extended version of mysqld_show_tables
unknown's avatar
unknown committed
457 458 459 460 461 462 463 464 465 466
***************************************************************************/

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;
467 468
  Protocol *protocol= thd->protocol;
  TIME time;
unknown's avatar
unknown committed
469 470 471 472 473
  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));
unknown's avatar
unknown committed
474
  field_list.push_back(item=new Item_empty_string("Engine",10));
unknown's avatar
unknown committed
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
  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;
unknown's avatar
unknown committed
498
  field_list.push_back(item=new Item_empty_string("Collation",32));
499
  item->maybe_null=1;
unknown's avatar
unknown committed
500 501
  field_list.push_back(item=new Item_int("Checksum",(longlong) 1,21));
  item->maybe_null=1;
unknown's avatar
unknown committed
502 503 504
  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));
505
  item->maybe_null=1;
506
  if (protocol->send_fields(&field_list,1))
unknown's avatar
unknown committed
507 508 509 510
    DBUG_RETURN(1);

  if (mysql_find_files(thd,&files,db,path,wild,0))
    DBUG_RETURN(-1);
unknown's avatar
unknown committed
511
  List_iterator_fast<char> it(files);
unknown's avatar
unknown committed
512 513 514 515
  while ((file_name=it++))
  {
    TABLE_LIST table_list;
    bzero((char*) &table_list,sizeof(table_list));
516
    protocol->prepare_for_resend();
517
    protocol->store(file_name, system_charset_info);
unknown's avatar
unknown committed
518
    table_list.db=(char*) db;
519
    table_list.real_name= table_list.alias= file_name;
520
    if (lower_case_table_names)
521
      my_casedn_str(files_charset_info, file_name);
unknown's avatar
unknown committed
522 523
    if (!(table = open_ltable(thd, &table_list, TL_READ)))
    {
524
      for (uint i=2 ; i < field_list.elements ; i++)
525
        protocol->store_null();
526
      // Send error to Comment field
527
      protocol->store(thd->net.last_error, system_charset_info);
unknown's avatar
unknown committed
528
      thd->clear_error();
unknown's avatar
unknown committed
529 530 531 532
    }
    else
    {
      struct tm tm_tmp;
533
      const char *str;
unknown's avatar
unknown committed
534 535
      handler *file=table->file;
      file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_NO_LOCK);
536
      protocol->store(file->table_type(), system_charset_info);
537 538 539 540
      str= ((table->db_options_in_use & HA_OPTION_COMPRESS_RECORD) ?
	    "Compressed" :
	    (table->db_options_in_use & HA_OPTION_PACK_RECORD) ?
	    "Dynamic" : "Fixed");
541
      protocol->store(str, system_charset_info);
542 543 544
      protocol->store((ulonglong) file->records);
      protocol->store((ulonglong) file->mean_rec_length);
      protocol->store((ulonglong) file->data_file_length);
unknown's avatar
unknown committed
545
      if (file->max_data_file_length)
546
        protocol->store((ulonglong) file->max_data_file_length);
unknown's avatar
unknown committed
547
      else
548 549 550
        protocol->store_null();
      protocol->store((ulonglong) file->index_file_length);
      protocol->store((ulonglong) file->delete_length);
unknown's avatar
unknown committed
551 552
      if (table->found_next_number_field)
      {
553 554 555
        table->next_number_field=table->found_next_number_field;
        table->next_number_field->reset();
        file->update_auto_increment();
556
        protocol->store(table->next_number_field->val_int());
557
        table->next_number_field=0;
unknown's avatar
unknown committed
558 559
      }
      else
560
        protocol->store_null();
unknown's avatar
unknown committed
561
      if (!file->create_time)
562
        protocol->store_null();
unknown's avatar
unknown committed
563 564
      else
      {
565
        localtime_r(&file->create_time,&tm_tmp);
566 567
	localtime_to_TIME(&time, &tm_tmp);
        protocol->store(&time);
unknown's avatar
unknown committed
568 569
      }
      if (!file->update_time)
570
        protocol->store_null();
unknown's avatar
unknown committed
571 572
      else
      {
573
        localtime_r(&file->update_time,&tm_tmp);
574 575
	localtime_to_TIME(&time, &tm_tmp);
        protocol->store(&time);
unknown's avatar
unknown committed
576 577
      }
      if (!file->check_time)
578
        protocol->store_null();
unknown's avatar
unknown committed
579 580
      else
      {
581
        localtime_r(&file->check_time,&tm_tmp);
582 583
	localtime_to_TIME(&time, &tm_tmp);
        protocol->store(&time);
unknown's avatar
unknown committed
584
      }
585
      str= (table->table_charset ? table->table_charset->name : "default");
586
      protocol->store(str, system_charset_info);
unknown's avatar
unknown committed
587 588 589 590
      if (file->table_flags() & HA_HAS_CHECKSUM)
        protocol->store((ulonglong)file->checksum());
      else
        protocol->store_null(); // Checksum
unknown's avatar
unknown committed
591
      {
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617
        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)
618
          ptr=strxmov(ptr, " row_format=", ha_row_type[(uint) table->row_type],
619 620 621 622 623 624 625 626
                      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);
        }
627
        protocol->store(option_buff+1,
628 629
			(ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1)
			, system_charset_info);
unknown's avatar
unknown committed
630
      }
631 632
      {
	char *comment=table->file->update_table_comment(table->comment);
633
	protocol->store(comment, system_charset_info);
634 635 636
	if (comment != table->comment)
	  my_free(comment,MYF(0));
      }
unknown's avatar
unknown committed
637 638
      close_thread_tables(thd,0);
    }
639
    if (protocol->write())
unknown's avatar
unknown committed
640 641
      DBUG_RETURN(-1);
  }
642
  send_eof(thd);
unknown's avatar
unknown committed
643 644 645 646 647
  DBUG_RETURN(0);
}


/***************************************************************************
648
** List all columns in a table_list->real_name
unknown's avatar
unknown committed
649
***************************************************************************/
unknown's avatar
SCRUM  
unknown committed
650

unknown's avatar
unknown committed
651
int
unknown's avatar
unknown committed
652 653
mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
		   bool verbose)
unknown's avatar
unknown committed
654 655 656 657
{
  TABLE *table;
  handler *file;
  char tmp[MAX_FIELD_WIDTH];
unknown's avatar
unknown committed
658
  Item *item;
659
  Protocol *protocol= thd->protocol;
unknown's avatar
unknown committed
660 661
  DBUG_ENTER("mysqld_show_fields");
  DBUG_PRINT("enter",("db: %s  table: %s",table_list->db,
662
                      table_list->real_name));
unknown's avatar
unknown committed
663 664 665

  if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
  {
666
    send_error(thd);
unknown's avatar
unknown committed
667 668 669 670
    DBUG_RETURN(1);
  }
  file=table->file;
  file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
unknown's avatar
unknown committed
671
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
672
  (void) get_table_grant(thd, table_list);
unknown's avatar
unknown committed
673
#endif
unknown's avatar
unknown committed
674 675 676
  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));
677 678
  if (verbose)
    field_list.push_back(new Item_empty_string("Collation",40));
unknown's avatar
unknown committed
679 680
  field_list.push_back(new Item_empty_string("Null",1));
  field_list.push_back(new Item_empty_string("Key",3));
unknown's avatar
unknown committed
681 682
  field_list.push_back(item=new Item_empty_string("Default",NAME_LEN));
  item->maybe_null=1;
unknown's avatar
unknown committed
683
  field_list.push_back(new Item_empty_string("Extra",20));
unknown's avatar
unknown committed
684
  if (verbose)
685
  {
unknown's avatar
unknown committed
686
    field_list.push_back(new Item_empty_string("Privileges",80));
687 688
    field_list.push_back(new Item_empty_string("Comment",255));
  }
689
        // Send first number of fields and records
unknown's avatar
SCRUM  
unknown committed
690 691
  if (protocol->send_records_num(&field_list, (ulonglong)file->records) ||
      protocol->send_fields(&field_list,0))
unknown's avatar
unknown committed
692
    DBUG_RETURN(1);
unknown's avatar
unknown committed
693
  restore_record(table,default_values);      // Get empty record
unknown's avatar
unknown committed
694 695 696 697

  Field **ptr,*field;
  for (ptr=table->field; (field= *ptr) ; ptr++)
  {
698 699
    if (!wild || !wild[0] || 
        !wild_case_compare(system_charset_info, field->field_name,wild))
unknown's avatar
unknown committed
700 701
    {
      {
702 703
        byte *pos;
        uint flags=field->flags;
704
        String type(tmp,sizeof(tmp), system_charset_info);
705 706
        uint col_access;

707
	protocol->prepare_for_resend();
708
        protocol->store(field->field_name, system_charset_info);
709
        field->sql_type(type);
710
        protocol->store(type.ptr(), type.length(), system_charset_info);
711 712
	if (verbose)
	  protocol->store(field->has_charset() ? field->charset()->name : "NULL",
713
			system_charset_info);
714 715 716 717 718 719
        /*
          Altough TIMESTAMP fields can't contain NULL as its value they
          will accept NULL if you will try to insert such value and will
          convert it to current TIMESTAMP. So YES here means that NULL 
          is allowed for assignment but can't be returned.
        */
720 721 722
        pos=(byte*) ((flags & NOT_NULL_FLAG) &&
                     field->type() != FIELD_TYPE_TIMESTAMP ?
                     "" : "YES");
723
        protocol->store((const char*) pos, system_charset_info);
724 725 726
        pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
                     (field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
                     (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
727
        protocol->store((char*) pos, system_charset_info);
728

729 730 731 732 733 734 735 736 737
        if (table->timestamp_field == field &&
            field->unireg_check != Field::TIMESTAMP_UN_FIELD)
        {
          /*
            We have NOW() as default value but we use CURRENT_TIMESTAMP form
            because it is more SQL standard comatible
          */
          protocol->store("CURRENT_TIMESTAMP", system_charset_info);
        }
738
        else if (field->unireg_check != Field::NEXT_NUMBER &&
739
                 !field->is_null())
740
        {                                               // Not null by default
741
          type.set(tmp, sizeof(tmp), field->charset());
742
          field->val_str(&type);
743
          protocol->store(type.ptr(),type.length(),type.charset());
744
        }
745 746
        else if (field->unireg_check == Field::NEXT_NUMBER ||
                 field->maybe_null())
747
          protocol->store_null();                       // Null as default
748
        else
749
          protocol->store("",0, system_charset_info);	// empty string
750 751 752 753

        char *end=tmp;
        if (field->unireg_check == Field::NEXT_NUMBER)
          end=strmov(tmp,"auto_increment");
754
        protocol->store(tmp,(uint) (end-tmp), system_charset_info);
755

unknown's avatar
unknown committed
756 757
	if (verbose)
	{
758
	  /* Add grant options & comments */
unknown's avatar
unknown committed
759
	  end=tmp;
unknown's avatar
unknown committed
760
#ifndef NO_EMBEDDED_ACCESS_CHECKS
761
	  col_access= get_column_grant(thd,table_list,field) & COL_ACLS;
unknown's avatar
unknown committed
762 763 764 765 766 767 768 769
	  for (uint bitnr=0; col_access ; col_access>>=1,bitnr++)
	  {
	    if (col_access & 1)
	    {
	      *end++=',';
	      end=strmov(end,grant_types.type_names[bitnr]);
	    }
	  }
unknown's avatar
unknown committed
770 771 772
#else
	  end=strmov(end,"");
#endif
773 774 775 776
	  protocol->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1),
			  system_charset_info);
	  protocol->store(field->comment.str, field->comment.length,
			  system_charset_info);
unknown's avatar
unknown committed
777
	}
778
        if (protocol->write())
779
          DBUG_RETURN(1);
unknown's avatar
unknown committed
780 781 782
      }
    }
  }
783
  send_eof(thd);
unknown's avatar
unknown committed
784 785 786
  DBUG_RETURN(0);
}

787

unknown's avatar
unknown committed
788 789 790 791
int
mysqld_show_create(THD *thd, TABLE_LIST *table_list)
{
  TABLE *table;
792 793 794
  Protocol *protocol= thd->protocol;
  char buff[2048];
  String buffer(buff, sizeof(buff), system_charset_info);
unknown's avatar
unknown committed
795 796
  DBUG_ENTER("mysqld_show_create");
  DBUG_PRINT("enter",("db: %s  table: %s",table_list->db,
797
                      table_list->real_name));
unknown's avatar
unknown committed
798

unknown's avatar
unknown committed
799
  /* Only one table for now */
unknown's avatar
unknown committed
800 801
  if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
  {
802
    send_error(thd);
unknown's avatar
unknown committed
803 804 805
    DBUG_RETURN(1);
  }

unknown's avatar
unknown committed
806
  if (store_create_info(thd, table, &buffer))
807 808
    DBUG_RETURN(-1);

unknown's avatar
unknown committed
809 810
  List<Item> field_list;
  field_list.push_back(new Item_empty_string("Table",NAME_LEN));
unknown's avatar
unknown committed
811
  // 1024 is for not to confuse old clients
812
  field_list.push_back(new Item_empty_string("Create Table",
unknown's avatar
unknown committed
813
					     max(buffer.length(),1024)));
unknown's avatar
unknown committed
814

815 816 817
  if (protocol->send_fields(&field_list, 1))
    DBUG_RETURN(1);
  protocol->prepare_for_resend();
818
  protocol->store(table->table_name, system_charset_info);
819
  buffer.length(0);
820 821
  if (store_create_info(thd, table, &buffer))
    DBUG_RETURN(-1);
822
  protocol->store(buffer.ptr(), buffer.length(), buffer.charset());
823
  if (protocol->write())
unknown's avatar
unknown committed
824
    DBUG_RETURN(1);
825
  send_eof(thd);
unknown's avatar
unknown committed
826 827 828
  DBUG_RETURN(0);
}

829 830 831 832 833 834 835
int mysqld_show_create_db(THD *thd, char *dbname,
			  HA_CREATE_INFO *create_info)
{
  int length;
  char	path[FN_REFLEN];
  char buff[2048];
  String buffer(buff, sizeof(buff), system_charset_info);
unknown's avatar
unknown committed
836
#ifndef NO_EMBEDDED_ACCESS_CHECKS
837
  uint db_access;
unknown's avatar
unknown committed
838
#endif
839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918
  bool found_libchar;
  HA_CREATE_INFO create;
  uint create_options = create_info ? create_info->options : 0;
  Protocol *protocol=thd->protocol;
  DBUG_ENTER("mysql_show_create_db");

  if (check_db_name(dbname))
  {
    net_printf(thd,ER_WRONG_DB_NAME, dbname);
    DBUG_RETURN(1);
  }

#ifndef NO_EMBEDDED_ACCESS_CHECKS
  if (test_all_bits(thd->master_access,DB_ACLS))
    db_access=DB_ACLS;
  else
    db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) |
		thd->master_access);
  if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname)))
  {
    net_printf(thd,ER_DBACCESS_DENIED_ERROR,
	       thd->priv_user, thd->host_or_ip, dbname);
    mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
		    thd->priv_user, thd->host_or_ip, dbname);
    DBUG_RETURN(1);
  }
#endif

  (void) sprintf(path,"%s/%s",mysql_data_home, dbname);
  length=unpack_dirname(path,path);		// Convert if not unix
  found_libchar= 0;
  if (length && path[length-1] == FN_LIBCHAR)
  {
    found_libchar= 1;
    path[length-1]=0;				// remove ending '\'
  }
  if (access(path,F_OK))
  {
    net_printf(thd,ER_BAD_DB_ERROR,dbname);
    DBUG_RETURN(1);
  }
  if (found_libchar)
    path[length-1]= FN_LIBCHAR;
  strmov(path+length, MY_DB_OPT_FILE);
  load_db_opt(thd, path, &create);

  List<Item> field_list;
  field_list.push_back(new Item_empty_string("Database",NAME_LEN));
  field_list.push_back(new Item_empty_string("Create Database",1024));

  if (protocol->send_fields(&field_list,1))
    DBUG_RETURN(1);

  protocol->prepare_for_resend();
  protocol->store(dbname, strlen(dbname), system_charset_info);
  buffer.length(0);
  buffer.append("CREATE DATABASE ", 16);
  if (create_options & HA_LEX_CREATE_IF_NOT_EXISTS)
    buffer.append("/*!32312 IF NOT EXISTS*/ ", 25);
  append_identifier(thd, &buffer, dbname, strlen(dbname));

  if (create.default_table_charset)
  {
    buffer.append(" /*!40100", 9);
    buffer.append(" DEFAULT CHARACTER SET ", 23);
    buffer.append(create.default_table_charset->csname);
    if (!(create.default_table_charset->state & MY_CS_PRIMARY))
    {
      buffer.append(" COLLATE ", 9);
      buffer.append(create.default_table_charset->name);
    }
    buffer.append(" */", 3);
  }
  protocol->store(buffer.ptr(), buffer.length(), buffer.charset());

  if (protocol->write())
    DBUG_RETURN(1);
  send_eof(thd);
  DBUG_RETURN(0);
}
unknown's avatar
unknown committed
919

unknown's avatar
unknown committed
920 921 922
int
mysqld_show_logs(THD *thd)
{
923 924
  List<Item> field_list;
  Protocol *protocol= thd->protocol;
unknown's avatar
unknown committed
925 926 927 928 929 930
  DBUG_ENTER("mysqld_show_logs");

  field_list.push_back(new Item_empty_string("File",FN_REFLEN));
  field_list.push_back(new Item_empty_string("Type",10));
  field_list.push_back(new Item_empty_string("Status",10));

931
  if (protocol->send_fields(&field_list,1))
unknown's avatar
unknown committed
932 933
    DBUG_RETURN(1);

934
#ifdef HAVE_BERKELEY_DB
935
  if ((have_berkeley_db == SHOW_OPTION_YES) && berkeley_show_logs(protocol))
unknown's avatar
unknown committed
936
    DBUG_RETURN(-1);
937
#endif
unknown's avatar
unknown committed
938

939
  send_eof(thd);
unknown's avatar
unknown committed
940 941 942 943
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
944 945 946 947
int
mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
{
  TABLE *table;
948
  Protocol *protocol= thd->protocol;
unknown's avatar
unknown committed
949 950
  DBUG_ENTER("mysqld_show_keys");
  DBUG_PRINT("enter",("db: %s  table: %s",table_list->db,
951
                      table_list->real_name));
unknown's avatar
unknown committed
952 953 954

  if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
  {
955
    send_error(thd);
unknown's avatar
unknown committed
956 957 958 959 960 961
    DBUG_RETURN(1);
  }

  List<Item> field_list;
  Item *item;
  field_list.push_back(new Item_empty_string("Table",NAME_LEN));
962
  field_list.push_back(new Item_return_int("Non_unique",1, MYSQL_TYPE_TINY));
unknown's avatar
unknown committed
963
  field_list.push_back(new Item_empty_string("Key_name",NAME_LEN));
964
  field_list.push_back(new Item_return_int("Seq_in_index",2, MYSQL_TYPE_TINY));
unknown's avatar
unknown committed
965 966 967
  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;
968
  field_list.push_back(item=new Item_int("Cardinality",0,21));
unknown's avatar
unknown committed
969
  item->maybe_null=1;
970 971
  field_list.push_back(item=new Item_return_int("Sub_part",3,
						MYSQL_TYPE_TINY));
unknown's avatar
unknown committed
972 973 974
  item->maybe_null=1;
  field_list.push_back(item=new Item_empty_string("Packed",10));
  item->maybe_null=1;
975 976
  field_list.push_back(new Item_empty_string("Null",3));
  field_list.push_back(new Item_empty_string("Index_type",16));
unknown's avatar
unknown committed
977 978 979
  field_list.push_back(new Item_empty_string("Comment",255));
  item->maybe_null=1;

980
  if (protocol->send_fields(&field_list,1))
unknown's avatar
unknown committed
981 982 983 984 985 986 987
    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;
988
    const char *str;
unknown's avatar
unknown committed
989 990
    for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
    {
991
      protocol->prepare_for_resend();
992
      protocol->store(table->table_name, system_charset_info);
993
      protocol->store_tiny((longlong) ((key_info->flags & HA_NOSAME) ? 0 :1));
994
      protocol->store(key_info->name, system_charset_info);
995 996 997
      protocol->store_tiny((longlong) (j+1));
      str=(key_part->field ? key_part->field->field_name :
	   "?unknown field?");
998
      protocol->store(str, system_charset_info);
999
      if (table->file->index_flags(i) & HA_READ_ORDER)
1000
        protocol->store(((key_part->key_part_flag & HA_REVERSE_SORT) ?
1001
			 "D" : "A"), 1, system_charset_info);
unknown's avatar
unknown committed
1002
      else
1003
        protocol->store_null(); /* purecov: inspected */
unknown's avatar
unknown committed
1004 1005 1006
      KEY *key=table->key_info+i;
      if (key->rec_per_key[j])
      {
1007
        ha_rows records=(table->file->records / key->rec_per_key[j]);
1008
        protocol->store((ulonglong) records);
unknown's avatar
unknown committed
1009 1010
      }
      else
1011
        protocol->store_null();
1012 1013

      /* Check if we have a key part that only uses part of the field */
unknown's avatar
unknown committed
1014 1015
      if (!(key_info->flags & HA_FULLTEXT) && (!key_part->field ||
          key_part->length != table->field[key_part->fieldnr-1]->key_length()))
1016
        protocol->store_tiny((longlong) key_part->length);
unknown's avatar
unknown committed
1017
      else
1018 1019
        protocol->store_null();
      protocol->store_null();                   // No pack_information yet
1020 1021 1022

      /* Null flag */
      uint flags= key_part->field ? key_part->field->flags : 0;
unknown's avatar
unknown committed
1023
      char *pos=(char*) ((flags & NOT_NULL_FLAG) ? "" : "YES");
1024 1025
      protocol->store((const char*) pos, system_charset_info);
      protocol->store(table->file->index_type(i), system_charset_info);
1026
      /* Comment */
1027
      if (!table->keys_in_use.is_set(i))
unknown's avatar
unknown committed
1028
	protocol->store("disabled",8, system_charset_info);
1029
      else
unknown's avatar
unknown committed
1030
        protocol->store("", 0, system_charset_info);
1031
      if (protocol->write())
1032
        DBUG_RETURN(1); /* purecov: inspected */
unknown's avatar
unknown committed
1033 1034
    }
  }
1035
  send_eof(thd);
unknown's avatar
unknown committed
1036 1037 1038 1039 1040
  DBUG_RETURN(0);
}


/****************************************************************************
1041 1042
  Return only fields for API mysql_list_fields
  Use "show table wildcard" in mysql instead of this
unknown's avatar
unknown committed
1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
****************************************************************************/

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)))
  {
1054
    send_error(thd);
unknown's avatar
unknown committed
1055 1056 1057 1058 1059 1060 1061
    DBUG_VOID_RETURN;
  }
  List<Item> field_list;

  Field **ptr,*field;
  for (ptr=table->field ; (field= *ptr); ptr++)
  {
1062 1063
    if (!wild || !wild[0] || 
        !wild_case_compare(system_charset_info, field->field_name,wild))
unknown's avatar
unknown committed
1064
      field_list.push_back(new Item_field(field));
unknown's avatar
unknown committed
1065
  }
unknown's avatar
unknown committed
1066
  restore_record(table,default_values);              // Get empty record
1067
  if (thd->protocol->send_fields(&field_list,2))
unknown's avatar
unknown committed
1068
    DBUG_VOID_RETURN;
1069
  net_flush(&thd->net);
unknown's avatar
unknown committed
1070 1071 1072
  DBUG_VOID_RETURN;
}

1073

unknown's avatar
unknown committed
1074 1075 1076
int
mysqld_dump_create_info(THD *thd, TABLE *table, int fd)
{
1077 1078
  Protocol *protocol= thd->protocol;
  String *packet= protocol->storage_packet();
unknown's avatar
unknown committed
1079 1080
  DBUG_ENTER("mysqld_dump_create_info");
  DBUG_PRINT("enter",("table: %s",table->real_name));
1081

1082 1083
  protocol->prepare_for_resend();
  if (store_create_info(thd, table, packet))
unknown's avatar
unknown committed
1084
    DBUG_RETURN(-1);
1085

unknown's avatar
unknown committed
1086 1087
  //if (protocol->convert)
  //  protocol->convert->convert((char*) packet->ptr(), packet->length());
1088
  if (fd < 0)
1089
  {
1090
    if (protocol->write())
1091
      DBUG_RETURN(-1);
1092
    net_flush(&thd->net);
1093
  }
unknown's avatar
unknown committed
1094
  else
1095
  {
1096 1097
    if (my_write(fd, (const byte*) packet->ptr(), packet->length(),
		 MYF(MY_WME)))
1098 1099
      DBUG_RETURN(-1);
  }
unknown's avatar
unknown committed
1100 1101
  DBUG_RETURN(0);
}
1102

1103
/*
1104 1105
  Go through all character combinations and ensure that sql_lex.cc can
  parse it as an identifer.
1106 1107

  SYNOPSIS
1108 1109 1110 1111 1112 1113 1114
  require_quotes()
  name			attribute name
  name_length		length of name

  RETURN
    #	Pointer to conflicting character
    0	No conflicting character
1115 1116
*/

1117
static const char *require_quotes(const char *name, uint name_length)
1118
{
1119 1120 1121 1122
  uint length;
  const char *end= name + name_length;

  for ( ; name < end ; name++)
1123
  {
1124 1125 1126 1127
    uchar chr= (uchar) *name;
    length= my_mbcharlen(system_charset_info, chr);
    if (length == 1 && !system_charset_info->ident_map[chr])
      return name;
1128 1129 1130
  }
  return 0;
}
1131

1132 1133 1134 1135 1136 1137 1138 1139 1140 1141

static void append_quoted_simple_identifier(String *packet, char quote_char,
					    const char *name, uint length)
{
  packet->append(&quote_char, 1, system_charset_info);
  packet->append(name, length, system_charset_info);
  packet->append(&quote_char, 1, system_charset_info);
}  


1142 1143
void
append_identifier(THD *thd, String *packet, const char *name, uint length)
1144
{
1145 1146 1147
  const char *name_end;
  char quote_char;

1148
  if (thd->variables.sql_mode & MODE_ANSI_QUOTES)
1149
    quote_char= '\"';
1150
  else
1151
    quote_char= '`';
1152

1153
  if (is_keyword(name,length))
1154
  {
1155 1156
    append_quoted_simple_identifier(packet, quote_char, name, length);
    return;
1157
  }
1158 1159

  if (!require_quotes(name, length))
1160
  {
1161
    if (!(thd->options & OPTION_QUOTE_SHOW_CREATE))
1162
      packet->append(name, length, system_charset_info);
1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179
    else
      append_quoted_simple_identifier(packet, quote_char, name, length);
    return;
  }

  /* The identifier must be quoted as it includes a quote character */

  packet->reserve(length*2 + 2);
  packet->append(&quote_char, 1, system_charset_info);

  for (name_end= name+length ; name < name_end ; name+= length)
  {
    char chr= *name;
    length= my_mbcharlen(system_charset_info, chr);
    if (length == 1 && chr == quote_char)
      packet->append(&quote_char, 1, system_charset_info);
    packet->append(name, length, packet->charset());
1180
  }
1181
  packet->append(&quote_char, 1, system_charset_info);
1182 1183
}

1184 1185 1186 1187 1188 1189 1190

/* Append directory name (if exists) to CREATE INFO */

static void append_directory(THD *thd, String *packet, const char *dir_type,
			     const char *filename)
{
  uint length;
unknown's avatar
unknown committed
1191
  if (filename && !(thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE))
1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202
  {
    length= dirname_length(filename);
    packet->append(' ');
    packet->append(dir_type);
    packet->append(" DIRECTORY='", 12);
    packet->append(filename, length);
    packet->append('\'');
  }
}


unknown's avatar
unknown committed
1203
#define LIST_PROCESS_HOST_LEN 64
1204

unknown's avatar
unknown committed
1205
static int
1206
store_create_info(THD *thd, TABLE *table, String *packet)
unknown's avatar
unknown committed
1207
{
1208
  List<Item> field_list;
unknown's avatar
unknown committed
1209
  char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], *end, *alias;
unknown's avatar
unknown committed
1210
  String type(tmp, sizeof(tmp),&my_charset_bin);
1211 1212 1213 1214 1215
  Field **ptr,*field;
  uint primary_key;
  KEY *key_info;
  handler *file= table->file;
  HA_CREATE_INFO create_info;
1216 1217 1218 1219
  my_bool foreign_db_mode=    (thd->variables.sql_mode & (MODE_POSTGRESQL |
							  MODE_ORACLE |
							  MODE_MSSQL |
							  MODE_DB2 |
1220
							  MODE_MAXDB |
1221 1222 1223 1224
							  MODE_ANSI)) != 0;
  my_bool limited_mysql_mode= (thd->variables.sql_mode &
			       (MODE_NO_FIELD_OPTIONS | MODE_MYSQL323 |
				MODE_MYSQL40)) != 0;
1225

unknown's avatar
unknown committed
1226 1227 1228
  DBUG_ENTER("store_create_info");
  DBUG_PRINT("enter",("table: %s",table->real_name));

unknown's avatar
unknown committed
1229
  restore_record(table,default_values); // Get empty record
1230

1231 1232 1233 1234
  if (table->tmp_table)
    packet->append("CREATE TEMPORARY TABLE ", 23);
  else
    packet->append("CREATE TABLE ", 13);
unknown's avatar
unknown committed
1235 1236 1237
  alias= (lower_case_table_names == 2 ? table->table_name :
	  table->real_name);
  append_identifier(thd, packet, alias, strlen(alias));
1238
  packet->append(" (\n", 3);
1239

unknown's avatar
unknown committed
1240 1241
  for (ptr=table->field ; (field= *ptr); ptr++)
  {
1242
    bool has_default;
1243
    bool has_now_default;
1244 1245
    uint flags = field->flags;

1246
    if (ptr != table->field)
1247
      packet->append(",\n", 2);
1248

1249
    packet->append("  ", 2);
1250
    append_identifier(thd,packet,field->field_name, strlen(field->field_name));
unknown's avatar
unknown committed
1251 1252
    packet->append(' ');
    // check for surprises from the previous call to Field::sql_type()
1253
    if (type.ptr() != tmp)
unknown's avatar
unknown committed
1254
      type.set(tmp, sizeof(tmp),&my_charset_bin);
1255

unknown's avatar
unknown committed
1256 1257
    field->sql_type(type);
    packet->append(type.ptr(),type.length());
1258

1259
    if (field->has_charset() && !limited_mysql_mode && !foreign_db_mode)
1260
    {
1261
      if (field->charset() != table->table_charset)
1262
      {
1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273
	packet->append(" character set ", 15);
	packet->append(field->charset()->csname);
      }
      /* 
	For string types dump collation name only if 
	collation is not primary for the given charset
      */
      if (!(field->charset()->state & MY_CS_PRIMARY))
      {
	packet->append(" collate ", 9);
	packet->append(field->charset()->name);
1274
      }
1275
    }
1276

1277 1278
    if (flags & NOT_NULL_FLAG)
      packet->append(" NOT NULL", 9);
1279

1280 1281

    /* 
1282
      Again we are using CURRENT_TIMESTAMP instead of NOW because it is
1283 1284 1285 1286 1287
      more standard 
    */
    has_now_default= table->timestamp_field == field && 
                     field->unireg_check != Field::TIMESTAMP_UN_FIELD;
    
1288
    has_default= (field->type() != FIELD_TYPE_BLOB &&
1289 1290 1291
		  field->unireg_check != Field::NEXT_NUMBER &&
                  !((foreign_db_mode || limited_mysql_mode) &&
                    has_now_default));
1292

1293
    if (has_default)
1294 1295
    {
      packet->append(" default ", 9);
1296 1297 1298
      if (has_now_default)
        packet->append("CURRENT_TIMESTAMP",17);
      else if (!field->is_null())
1299
      {                                             // Not null by default
1300
        type.set(tmp, sizeof(tmp), field->charset());
1301
        field->val_str(&type);
1302
	if (type.length())
1303
	{
1304
	  String def_val;
1305 1306 1307 1308 1309
	  /* convert to system_charset_info == utf8 */
	  def_val.copy(type.ptr(), type.length(), field->charset(),
		       system_charset_info);
          append_unescaped(packet, def_val.ptr(), def_val.length());
	}
1310 1311
        else
	  packet->append("''",2);
unknown's avatar
unknown committed
1312
      }
1313
      else if (field->maybe_null())
1314 1315 1316 1317
        packet->append("NULL", 4);                    // Null as default
      else
        packet->append(tmp,0);
    }
1318

1319 1320 1321 1322 1323
    if (!foreign_db_mode && !limited_mysql_mode &&
        table->timestamp_field == field && 
        field->unireg_check != Field::TIMESTAMP_DN_FIELD)
      packet->append(" on update CURRENT_TIMESTAMP",28);

1324
    if (field->unireg_check == Field::NEXT_NUMBER && !foreign_db_mode)
1325 1326 1327 1328 1329 1330 1331
      packet->append(" auto_increment", 15 );

    if (field->comment.length)
    {
      packet->append(" COMMENT ",9);
      append_unescaped(packet, field->comment.str, field->comment.length);
    }
unknown's avatar
unknown committed
1332 1333
  }

1334 1335
  key_info= table->key_info;
  file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME);
1336
  bzero((char*) &create_info, sizeof(create_info));
1337 1338
  file->update_create_info(&create_info);
  primary_key= table->primary_key;
1339

unknown's avatar
unknown committed
1340 1341
  for (uint i=0 ; i < table->keys ; i++,key_info++)
  {
1342 1343
    KEY_PART_INFO *key_part= key_info->key_part;
    bool found_primary=0;
1344
    packet->append(",\n  ", 4);
1345

1346
    if (i == primary_key && !strcmp(key_info->name, primary_key_name))
1347 1348
    {
      found_primary=1;
1349
      packet->append("PRIMARY ", 8);
1350
    }
1351
    else if (key_info->flags & HA_NOSAME)
1352
      packet->append("UNIQUE ", 7);
1353
    else if (key_info->flags & HA_FULLTEXT)
1354
      packet->append("FULLTEXT ", 9);
unknown's avatar
unknown committed
1355 1356
    else if (key_info->flags & HA_SPATIAL)
      packet->append("SPATIAL ", 8);
1357
    packet->append("KEY ", 4);
unknown's avatar
unknown committed
1358

1359
    if (!found_primary)
1360
     append_identifier(thd, packet, key_info->name, strlen(key_info->name));
unknown's avatar
unknown committed
1361

1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373
    if (!(thd->variables.sql_mode & MODE_NO_KEY_OPTIONS) &&
	!limited_mysql_mode && !foreign_db_mode)
    {
      if (table->db_type == DB_TYPE_HEAP &&
	  key_info->algorithm == HA_KEY_ALG_BTREE)
	packet->append(" TYPE BTREE", 11);
      
      // +BAR: send USING only in non-default case: non-spatial rtree
      if ((key_info->algorithm == HA_KEY_ALG_RTREE) &&
	  !(key_info->flags & HA_SPATIAL))
	packet->append(" TYPE RTREE", 11);
    }
1374
    packet->append(" (", 2);
1375

unknown's avatar
unknown committed
1376 1377
    for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
    {
1378
      if (j)
1379
        packet->append(',');
1380

1381
      if (key_part->field)
1382 1383
        append_identifier(thd,packet,key_part->field->field_name,
			  strlen(key_part->field->field_name));
unknown's avatar
unknown committed
1384
      if (!key_part->field ||
1385 1386 1387
          (key_part->length !=
           table->field[key_part->fieldnr-1]->key_length() &&
           !(key_info->flags & HA_FULLTEXT)))
unknown's avatar
unknown committed
1388
      {
1389
        buff[0] = '(';
1390 1391 1392
        char* end=int10_to_str((long) key_part->length / 
			       key_part->field->charset()->mbmaxlen,
			       buff + 1,10);
1393 1394
        *end++ = ')';
        packet->append(buff,(uint) (end-buff));
unknown's avatar
unknown committed
1395 1396 1397 1398
      }
    }
    packet->append(')');
  }
1399

1400 1401 1402 1403
  /*
    Get possible foreign key definitions stored in InnoDB and append them
    to the CREATE TABLE statement
  */
1404

1405
  if ((for_str= file->get_foreign_key_create_info()))
1406 1407 1408
  {
    packet->append(for_str, strlen(for_str));
    file->free_foreign_key_create_info(for_str);
1409 1410 1411
  }

  packet->append("\n)", 2);
1412
  if (!(thd->variables.sql_mode & MODE_NO_TABLE_OPTIONS) && !foreign_db_mode)
1413
  {
unknown's avatar
unknown committed
1414 1415 1416 1417
    if (thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))
      packet->append(" TYPE=", 6);
    else
      packet->append(" ENGINE=", 8);
1418 1419
    packet->append(file->table_type());
    
1420 1421 1422
    if (table->table_charset &&
	!(thd->variables.sql_mode & MODE_MYSQL323) &&
	!(thd->variables.sql_mode & MODE_MYSQL40))
1423
    {
1424
      packet->append(" DEFAULT CHARSET=", 17);
1425 1426 1427
      packet->append(table->table_charset->csname);
      if (!(table->table_charset->state & MY_CS_PRIMARY))
      {
1428
	packet->append(" COLLATE=", 9);
1429 1430
	packet->append(table->table_charset->name);
      }
1431
    }
1432

1433 1434
    if (table->min_rows)
    {
1435
      packet->append(" MIN_ROWS=", 10);
unknown's avatar
unknown committed
1436 1437
      end= longlong10_to_str(table->min_rows, buff, 10);
      packet->append(buff, (uint) (end- buff));
1438
    }
unknown's avatar
unknown committed
1439

1440 1441
    if (table->max_rows)
    {
1442
      packet->append(" MAX_ROWS=", 10);
unknown's avatar
unknown committed
1443 1444
      end= longlong10_to_str(table->max_rows, buff, 10);
      packet->append(buff, (uint) (end - buff));
1445
    }
unknown's avatar
unknown committed
1446

1447 1448
    if (table->avg_row_length)
    {
1449
      packet->append(" AVG_ROW_LENGTH=", 16);
unknown's avatar
unknown committed
1450 1451
      end= longlong10_to_str(table->avg_row_length, buff,10);
      packet->append(buff, (uint) (end - buff));
1452
    }
1453

1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474
    if (table->db_create_options & HA_OPTION_PACK_KEYS)
      packet->append(" PACK_KEYS=1", 12);
    if (table->db_create_options & HA_OPTION_NO_PACK_KEYS)
      packet->append(" PACK_KEYS=0", 12);
    if (table->db_create_options & HA_OPTION_CHECKSUM)
      packet->append(" CHECKSUM=1", 11);
    if (table->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
      packet->append(" DELAY_KEY_WRITE=1",18);
    if (table->row_type != ROW_TYPE_DEFAULT)
    {
      packet->append(" ROW_FORMAT=",12);
      packet->append(ha_row_type[(uint) table->row_type]);
    }
    table->file->append_create_info(packet);
    if (table->comment && table->comment[0])
    {
      packet->append(" COMMENT=", 9);
      append_unescaped(packet, table->comment, strlen(table->comment));
    }
    if (file->raid_type)
    {
unknown's avatar
unknown committed
1475 1476 1477 1478 1479 1480
      uint length;
      length= my_snprintf(buff,sizeof(buff),
			  " RAID_TYPE=%s RAID_CHUNKS=%d RAID_CHUNKSIZE=%ld",
			  my_raid_type(file->raid_type), file->raid_chunks,
			  file->raid_chunksize/RAID_BLOCK_SIZE);
      packet->append(buff, length);
1481
    }
unknown's avatar
unknown committed
1482 1483
    append_directory(thd, packet, "DATA",  create_info.data_file_name);
    append_directory(thd, packet, "INDEX", create_info.index_file_name);
1484
  }
unknown's avatar
unknown committed
1485 1486 1487 1488 1489
  DBUG_RETURN(0);
}


/****************************************************************************
1490 1491
  Return info about all processes
  returns for each thread: thread id, user, host, db, command, info
unknown's avatar
unknown committed
1492 1493 1494 1495
****************************************************************************/

class thread_info :public ilink {
public:
unknown's avatar
unknown committed
1496
  static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); }
unknown's avatar
unknown committed
1497
  static void operator delete(void *ptr __attribute__((unused)),
1498
                              size_t size __attribute__((unused))) {} /*lint -e715 */
unknown's avatar
unknown committed
1499

unknown's avatar
unknown committed
1500 1501
  ulong thread_id;
  time_t start_time;
1502
  uint   command;
unknown's avatar
unknown committed
1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515
  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;
unknown's avatar
unknown committed
1516 1517
  ulong max_query_length= (verbose ? thd->variables.max_allowed_packet :
			   PROCESS_LIST_WIDTH);
1518
  Protocol *protocol= thd->protocol;
unknown's avatar
unknown committed
1519 1520
  DBUG_ENTER("mysqld_list_processes");

1521
  field_list.push_back(new Item_int("Id",0,11));
unknown's avatar
unknown committed
1522
  field_list.push_back(new Item_empty_string("User",16));
1523
  field_list.push_back(new Item_empty_string("Host",LIST_PROCESS_HOST_LEN));
unknown's avatar
unknown committed
1524 1525 1526
  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));
1527
  field_list.push_back(new Item_return_int("Time",7, FIELD_TYPE_LONG));
unknown's avatar
unknown committed
1528 1529 1530 1531
  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;
1532
  if (protocol->send_fields(&field_list,1))
unknown's avatar
unknown committed
1533 1534 1535 1536 1537 1538 1539 1540 1541
    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++))
    {
1542
      struct st_my_thread_var *mysys_var;
unknown's avatar
SCRUM  
unknown committed
1543
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
1544
      if ((tmp->net.vio || tmp->system_thread) &&
1545
          (!user || (tmp->user && !strcmp(tmp->user,user))))
unknown's avatar
SCRUM  
unknown committed
1546 1547 1548 1549
#else
      if (tmp->system_thread &&
          (!user || (tmp->user && !strcmp(tmp->user,user))))
#endif
unknown's avatar
unknown committed
1550
      {
1551 1552 1553
        thread_info *thd_info=new thread_info;

        thd_info->thread_id=tmp->thread_id;
1554 1555 1556
        thd_info->user=thd->strdup(tmp->user ? tmp->user :
				   (tmp->system_thread ?
				    "system user" : "unauthenticated user"));
1557
	if (tmp->peer_port && (tmp->host || tmp->ip) && thd->host_or_ip[0])
1558 1559
	{
	  if ((thd_info->host= thd->alloc(LIST_PROCESS_HOST_LEN+1)))
unknown's avatar
unknown committed
1560
	    my_snprintf((char *) thd_info->host, LIST_PROCESS_HOST_LEN,
1561
			"%s:%u", tmp->host_or_ip, tmp->peer_port);
1562 1563
	}
	else
1564
	  thd_info->host= thd->strdup(tmp->host_or_ip);
1565 1566 1567
        if ((thd_info->db=tmp->db))             // Safe test
          thd_info->db=thd->strdup(thd_info->db);
        thd_info->command=(int) tmp->command;
1568 1569
        if ((mysys_var= tmp->mysys_var))
          pthread_mutex_lock(&mysys_var->mutex);
1570
        thd_info->proc_info= (char*) (tmp->killed ? "Killed" : 0);
unknown's avatar
SCRUM  
unknown committed
1571
#ifndef EMBEDDED_LIBRARY
1572 1573 1574 1575 1576 1577 1578 1579 1580 1581
        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);
unknown's avatar
SCRUM  
unknown committed
1582 1583 1584
#else
        thd_info->state_info= (char*)"Writing to net";
#endif
1585 1586
        if (mysys_var)
          pthread_mutex_unlock(&mysys_var->mutex);
unknown's avatar
unknown committed
1587 1588

#if !defined(DONT_USE_THR_ALARM) && ! defined(SCO)
1589 1590
        if (pthread_kill(tmp->real_id,0))
          tmp->proc_info="*** DEAD ***";        // This shouldn't happen
unknown's avatar
unknown committed
1591
#endif
unknown's avatar
unknown committed
1592 1593 1594
#ifdef EXTRA_DEBUG
        thd_info->start_time= tmp->time_after_lock;
#else
1595
        thd_info->start_time= tmp->start_time;
unknown's avatar
unknown committed
1596
#endif
1597 1598 1599
        thd_info->query=0;
        if (tmp->query)
        {
unknown's avatar
unknown committed
1600 1601
	  /* query_length is always set before tmp->query */
          uint length= min(max_query_length, tmp->query_length);
1602 1603 1604 1605
          thd_info->query=(char*) thd->memdup(tmp->query,length+1);
          thd_info->query[length]=0;
        }
        thread_infos.append(thd_info);
unknown's avatar
unknown committed
1606 1607 1608 1609 1610 1611
      }
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));

  thread_info *thd_info;
1612
  time_t now= time(0);
unknown's avatar
unknown committed
1613 1614
  while ((thd_info=thread_infos.get()))
  {
1615 1616
    protocol->prepare_for_resend();
    protocol->store((ulonglong) thd_info->thread_id);
1617 1618 1619
    protocol->store(thd_info->user, system_charset_info);
    protocol->store(thd_info->host, system_charset_info);
    protocol->store(thd_info->db, system_charset_info);
unknown's avatar
unknown committed
1620
    if (thd_info->proc_info)
1621
      protocol->store(thd_info->proc_info, system_charset_info);
unknown's avatar
unknown committed
1622
    else
1623
      protocol->store(command_name[thd_info->command], system_charset_info);
unknown's avatar
unknown committed
1624
    if (thd_info->start_time)
1625
      protocol->store((uint32) (now - thd_info->start_time));
unknown's avatar
unknown committed
1626
    else
1627
      protocol->store_null();
1628 1629
    protocol->store(thd_info->state_info, system_charset_info);
    protocol->store(thd_info->query, system_charset_info);
1630
    if (protocol->write())
unknown's avatar
unknown committed
1631 1632
      break; /* purecov: inspected */
  }
1633
  send_eof(thd);
unknown's avatar
unknown committed
1634 1635 1636 1637
  DBUG_VOID_RETURN;
}

/*****************************************************************************
unknown's avatar
unknown committed
1638
  Status functions
unknown's avatar
unknown committed
1639 1640
*****************************************************************************/

1641 1642 1643 1644
static bool write_collation(Protocol *protocol, CHARSET_INFO *cs)
{
  protocol->prepare_for_resend();
  protocol->store(cs->name, system_charset_info);
1645
  protocol->store(cs->csname, system_charset_info);
1646
  protocol->store_short((longlong) cs->number);
1647 1648
  protocol->store((cs->state & MY_CS_PRIMARY) ? "Yes" : "",system_charset_info);
  protocol->store((cs->state & MY_CS_COMPILED)? "Yes" : "",system_charset_info);
1649 1650 1651 1652 1653
  protocol->store_short((longlong) cs->strxfrm_multiply);
  return protocol->write();
}

int mysqld_show_collations(THD *thd, const char *wild)
1654 1655
{
  char buff[8192];
unknown's avatar
unknown committed
1656
  String packet2(buff,sizeof(buff),thd->charset());
1657
  List<Item> field_list;
1658
  CHARSET_INFO **cs;
1659
  Protocol *protocol= thd->protocol;
1660

1661 1662
  DBUG_ENTER("mysqld_show_charsets");

1663
  field_list.push_back(new Item_empty_string("Collation",30));
1664
  field_list.push_back(new Item_empty_string("Charset",30));
1665
  field_list.push_back(new Item_return_int("Id",11, FIELD_TYPE_SHORT));
1666 1667
  field_list.push_back(new Item_empty_string("Default",30));
  field_list.push_back(new Item_empty_string("Compiled",30));
1668
  field_list.push_back(new Item_return_int("Sortlen",3, FIELD_TYPE_SHORT));
1669

1670
  if (protocol->send_fields(&field_list, 1))
1671 1672
    DBUG_RETURN(1);

1673
  for ( cs= all_charsets ; cs < all_charsets+255 ; cs++ )
1674
  {
1675
    CHARSET_INFO **cl;
unknown's avatar
unknown committed
1676 1677 1678
    if (!cs[0] || !(cs[0]->state & MY_CS_AVAILABLE) || 
        !(cs[0]->state & MY_CS_PRIMARY))
      continue;
1679 1680
    for ( cl= all_charsets; cl < all_charsets+255 ;cl ++)
    {
unknown's avatar
unknown committed
1681 1682
      if (!cl[0] || !(cl[0]->state & MY_CS_AVAILABLE) || 
          !my_charset_same(cs[0],cl[0]))
1683
	continue;
unknown's avatar
unknown committed
1684
      if (!(wild && wild[0] &&
unknown's avatar
unknown committed
1685
	  wild_case_compare(system_charset_info,cl[0]->name,wild)))
1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701
      {
        if (write_collation(protocol, cl[0]))
	  goto err;
      }
    }
  }
  send_eof(thd); 
  DBUG_RETURN(0);
err:
  DBUG_RETURN(1);
}

static bool write_charset(Protocol *protocol, CHARSET_INFO *cs)
{
  protocol->prepare_for_resend();
  protocol->store(cs->csname, system_charset_info);
1702
  protocol->store(cs->comment ? cs->comment : "", system_charset_info);
1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718
  protocol->store(cs->name, system_charset_info);
  protocol->store_short((longlong) cs->mbmaxlen);
  return protocol->write();
}

int mysqld_show_charsets(THD *thd, const char *wild)
{
  char buff[8192];
  String packet2(buff,sizeof(buff),thd->charset());
  List<Item> field_list;
  CHARSET_INFO **cs;
  Protocol *protocol= thd->protocol;

  DBUG_ENTER("mysqld_show_charsets");

  field_list.push_back(new Item_empty_string("Charset",30));
1719
  field_list.push_back(new Item_empty_string("Description",60));
1720 1721 1722 1723 1724 1725 1726 1727
  field_list.push_back(new Item_empty_string("Default collation",60));
  field_list.push_back(new Item_return_int("Maxlen",3, FIELD_TYPE_SHORT));

  if (protocol->send_fields(&field_list, 1))
    DBUG_RETURN(1);

  for ( cs= all_charsets ; cs < all_charsets+255 ; cs++ )
  {
unknown's avatar
unknown committed
1728 1729 1730 1731
    if (cs[0] && (cs[0]->state & MY_CS_PRIMARY) && 
        (cs[0]->state & MY_CS_AVAILABLE) &&
        !(wild && wild[0] &&
        wild_case_compare(system_charset_info,cs[0]->csname,wild)))
1732
    {
1733
      if (write_charset(protocol, cs[0]))
1734
	goto err;
1735 1736
    }
  }
1737
  send_eof(thd); 
1738 1739 1740 1741 1742
  DBUG_RETURN(0);
err:
  DBUG_RETURN(1);
}

unknown's avatar
unknown committed
1743
  
unknown's avatar
unknown committed
1744

1745
int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
1746 1747
		enum enum_var_type value_type,
		pthread_mutex_t *mutex)
unknown's avatar
unknown committed
1748
{
1749
  char buff[1024];
unknown's avatar
unknown committed
1750
  List<Item> field_list;
1751
  Protocol *protocol= thd->protocol;
1752
  LEX_STRING null_lex_str;
unknown's avatar
unknown committed
1753
  DBUG_ENTER("mysqld_show");
unknown's avatar
unknown committed
1754

unknown's avatar
unknown committed
1755 1756
  field_list.push_back(new Item_empty_string("Variable_name",30));
  field_list.push_back(new Item_empty_string("Value",256));
1757
  if (protocol->send_fields(&field_list,1))
unknown's avatar
unknown committed
1758
    DBUG_RETURN(1); /* purecov: inspected */
1759
  null_lex_str.str= 0;				// For sys_var->value_ptr()
1760
  null_lex_str.length= 0;
unknown's avatar
unknown committed
1761

1762
  pthread_mutex_lock(mutex);
unknown's avatar
unknown committed
1763
  for (; variables->name; variables++)
unknown's avatar
unknown committed
1764
  {
unknown's avatar
unknown committed
1765
    if (!(wild && wild[0] && wild_case_compare(system_charset_info,
1766
					       variables->name,wild)))
unknown's avatar
unknown committed
1767
    {
1768
      protocol->prepare_for_resend();
1769
      protocol->store(variables->name, system_charset_info);
unknown's avatar
unknown committed
1770 1771
      SHOW_TYPE show_type=variables->type;
      char *value=variables->value;
1772 1773 1774
      const char *pos, *end;
      long nr;

unknown's avatar
unknown committed
1775 1776 1777
      if (show_type == SHOW_SYS)
      {
	show_type= ((sys_var*) value)->type();
1778 1779
	value=     (char*) ((sys_var*) value)->value_ptr(thd, value_type,
							 &null_lex_str);
unknown's avatar
unknown committed
1780 1781
      }

1782
      pos= end= buff;
unknown's avatar
unknown committed
1783
      switch (show_type) {
unknown's avatar
unknown committed
1784 1785
      case SHOW_LONG:
      case SHOW_LONG_CONST:
1786
	end= int10_to_str(*(long*) value, buff, 10);
unknown's avatar
unknown committed
1787 1788
        break;
      case SHOW_LONGLONG:
1789
	end= longlong10_to_str(*(longlong*) value, buff, 10);
unknown's avatar
unknown committed
1790
	break;
1791
      case SHOW_HA_ROWS:
unknown's avatar
unknown committed
1792
        end= longlong10_to_str((longlong) *(ha_rows*) value, buff, 10);
1793
        break;
unknown's avatar
unknown committed
1794
      case SHOW_BOOL:
1795
	end= strmov(buff, *(bool*) value ? "ON" : "OFF");
1796
        break;
unknown's avatar
unknown committed
1797
      case SHOW_MY_BOOL:
1798
	end= strmov(buff, *(my_bool*) value ? "ON" : "OFF");
1799
        break;
unknown's avatar
unknown committed
1800 1801
      case SHOW_INT_CONST:
      case SHOW_INT:
1802
	end= int10_to_str((long) *(uint32*) value, buff, 10);
1803
        break;
1804 1805
      case SHOW_HAVE:
      {
unknown's avatar
unknown committed
1806
	SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) value;
1807 1808
	pos= show_comp_option_name[(int) tmp];
	end= strend(pos);
1809 1810
        break;
      }
unknown's avatar
unknown committed
1811
      case SHOW_CHAR:
unknown's avatar
unknown committed
1812 1813 1814 1815
      {
        if (!(pos= value))
          pos= "";
        end= strend(pos);
1816
        break;
unknown's avatar
unknown committed
1817
       }
unknown's avatar
unknown committed
1818
      case SHOW_STARTTIME:
1819 1820
	nr= (long) (thd->query_start() - start_time);
	end= int10_to_str(nr, buff, 10);
1821
        break;
unknown's avatar
unknown committed
1822
      case SHOW_QUESTION:
1823
	end= int10_to_str((long) thd->query_id, buff, 10);
1824
        break;
unknown's avatar
unknown committed
1825
#ifdef HAVE_REPLICATION
1826
      case SHOW_RPL_STATUS:
unknown's avatar
unknown committed
1827
	end= strmov(buff, rpl_status_type[(int)rpl_status]);
1828
	break;
1829 1830
      case SHOW_SLAVE_RUNNING:
      {
1831
	pthread_mutex_lock(&LOCK_active_mi);
1832 1833
	end= strmov(buff, (active_mi->slave_running &&
			   active_mi->rli.slave_running) ? "ON" : "OFF");
1834
	pthread_mutex_unlock(&LOCK_active_mi);
1835 1836
	break;
      }
unknown's avatar
unknown committed
1837
#endif /* HAVE_REPLICATION */
unknown's avatar
unknown committed
1838
      case SHOW_OPENTABLES:
1839
	end= int10_to_str((long) cached_tables(), buff, 10);
1840
        break;
unknown's avatar
unknown committed
1841
      case SHOW_CHAR_PTR:
unknown's avatar
unknown committed
1842
      {
1843 1844 1845 1846
        if (!(pos= *(char**) value))
          pos= "";
        end= strend(pos);
        break;
unknown's avatar
unknown committed
1847
      }
unknown's avatar
unknown committed
1848
#ifdef HAVE_OPENSSL
unknown's avatar
unknown committed
1849
	/* First group - functions relying on CTX */
unknown's avatar
unknown committed
1850
      case SHOW_SSL_CTX_SESS_ACCEPT:
1851 1852
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_accept(ssl_acceptor_fd->
unknown's avatar
unknown committed
1853
						      ssl_context)),
1854
			  buff, 10);
unknown's avatar
unknown committed
1855 1856
        break;
      case SHOW_SSL_CTX_SESS_ACCEPT_GOOD:
1857 1858
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_accept_good(ssl_acceptor_fd->
unknown's avatar
unknown committed
1859
							   ssl_context)),
1860
			  buff, 10);
unknown's avatar
unknown committed
1861
        break;
1862
      case SHOW_SSL_CTX_SESS_CONNECT_GOOD:
1863 1864
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_connect_good(ssl_acceptor_fd->
unknown's avatar
unknown committed
1865
							    ssl_context)),
1866
			  buff, 10);
1867
        break;
unknown's avatar
unknown committed
1868
      case SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE:
1869
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
unknown's avatar
unknown committed
1870
				  SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context)),
1871
			  buff, 10);
unknown's avatar
unknown committed
1872
        break;
1873
      case SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE:
1874
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
unknown's avatar
unknown committed
1875
				  SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd-> ssl_context)),
1876
			  buff, 10);
1877
        break;
unknown's avatar
unknown committed
1878
      case SHOW_SSL_CTX_SESS_CB_HITS:
1879 1880
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_cb_hits(ssl_acceptor_fd->
unknown's avatar
unknown committed
1881
						       ssl_context)),
1882
			  buff, 10);
unknown's avatar
unknown committed
1883
        break;
1884
      case SHOW_SSL_CTX_SESS_HITS:
1885 1886
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_hits(ssl_acceptor_fd->
unknown's avatar
unknown committed
1887
						    ssl_context)),
1888
			  buff, 10);
1889 1890
        break;
      case SHOW_SSL_CTX_SESS_CACHE_FULL:
1891 1892
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_cache_full(ssl_acceptor_fd->
unknown's avatar
unknown committed
1893
							  ssl_context)),
1894
			  buff, 10);
1895 1896
        break;
      case SHOW_SSL_CTX_SESS_MISSES:
1897 1898
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_misses(ssl_acceptor_fd->
unknown's avatar
unknown committed
1899
						      ssl_context)),
1900
			  buff, 10);
1901 1902
        break;
      case SHOW_SSL_CTX_SESS_TIMEOUTS:
1903
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
unknown's avatar
unknown committed
1904
				  SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context)),
1905
			  buff,10);
1906
        break;
unknown's avatar
unknown committed
1907
      case SHOW_SSL_CTX_SESS_NUMBER:
1908
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
unknown's avatar
unknown committed
1909
				  SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context)),
1910
			  buff,10);
unknown's avatar
unknown committed
1911
        break;
1912
      case SHOW_SSL_CTX_SESS_CONNECT:
1913
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
unknown's avatar
unknown committed
1914
				  SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context)),
1915
			  buff,10);
1916
        break;
unknown's avatar
unknown committed
1917
      case SHOW_SSL_CTX_SESS_GET_CACHE_SIZE:
1918
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
unknown's avatar
unknown committed
1919
				  SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context)),
1920
				  buff,10);
unknown's avatar
unknown committed
1921 1922
        break;
      case SHOW_SSL_CTX_GET_VERIFY_MODE:
1923
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
unknown's avatar
unknown committed
1924
				  SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context)),
1925
			  buff,10);
unknown's avatar
unknown committed
1926 1927
        break;
      case SHOW_SSL_CTX_GET_VERIFY_DEPTH:
1928
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
unknown's avatar
unknown committed
1929
				  SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context)),
1930
			  buff,10);
unknown's avatar
unknown committed
1931 1932
        break;
      case SHOW_SSL_CTX_GET_SESSION_CACHE_MODE:
1933 1934
	if (!ssl_acceptor_fd)
	{
1935 1936
	  pos= "NONE";
	  end= pos+4;
1937 1938
	  break;
	}
1939
	switch (SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context))
unknown's avatar
unknown committed
1940 1941
	{
          case SSL_SESS_CACHE_OFF:
1942
            pos= "OFF";
unknown's avatar
unknown committed
1943 1944
	    break;
          case SSL_SESS_CACHE_CLIENT:
1945
            pos= "CLIENT";
unknown's avatar
unknown committed
1946 1947
	    break;
          case SSL_SESS_CACHE_SERVER:
1948
            pos= "SERVER";
unknown's avatar
unknown committed
1949 1950
	    break;
          case SSL_SESS_CACHE_BOTH:
1951
            pos= "BOTH";
unknown's avatar
unknown committed
1952 1953
	    break;
          case SSL_SESS_CACHE_NO_AUTO_CLEAR:
1954
            pos= "NO_AUTO_CLEAR";
unknown's avatar
unknown committed
1955 1956
	    break;
          case SSL_SESS_CACHE_NO_INTERNAL_LOOKUP:
1957
            pos= "NO_INTERNAL_LOOKUP";
unknown's avatar
unknown committed
1958 1959
	    break;
	  default:
1960
            pos= "Unknown";
unknown's avatar
unknown committed
1961 1962
	    break;
	}
1963
	end= strend(pos);
unknown's avatar
unknown committed
1964
        break;
unknown's avatar
unknown committed
1965 1966
	/* First group - functions relying on SSL */
      case SHOW_SSL_GET_VERSION:
unknown's avatar
unknown committed
1967 1968
	pos= (thd->net.vio->ssl_arg ?
	      SSL_get_version((SSL*) thd->net.vio->ssl_arg) : "");
1969
	end= strend(pos);
unknown's avatar
unknown committed
1970 1971
        break;
      case SHOW_SSL_SESSION_REUSED:
unknown's avatar
unknown committed
1972 1973 1974 1975 1976
	end= int10_to_str((long) (thd->net.vio->ssl_arg ?
				  SSL_session_reused((SSL*) thd->net.vio->
						     ssl_arg) :
				  0),
			  buff, 10);
unknown's avatar
unknown committed
1977 1978
        break;
      case SHOW_SSL_GET_DEFAULT_TIMEOUT:
unknown's avatar
unknown committed
1979 1980 1981 1982 1983
	end= int10_to_str((long) (thd->net.vio->ssl_arg ?
				  SSL_get_default_timeout((SSL*) thd->net.vio->
							  ssl_arg) :
				  0),
			  buff, 10);
unknown's avatar
unknown committed
1984 1985
        break;
      case SHOW_SSL_GET_VERIFY_MODE:
unknown's avatar
unknown committed
1986 1987 1988 1989 1990
	end= int10_to_str((long) (thd->net.vio->ssl_arg ?
				  SSL_get_verify_mode((SSL*) thd->net.vio->
						      ssl_arg):
				  0),
			  buff, 10);
unknown's avatar
unknown committed
1991 1992
        break;
      case SHOW_SSL_GET_VERIFY_DEPTH:
unknown's avatar
unknown committed
1993 1994 1995 1996 1997
	end= int10_to_str((long) (thd->net.vio->ssl_arg ?
				  SSL_get_verify_depth((SSL*) thd->net.vio->
						       ssl_arg):
				  0),
			  buff, 10);
unknown's avatar
unknown committed
1998 1999
        break;
      case SHOW_SSL_GET_CIPHER:
unknown's avatar
unknown committed
2000 2001
	pos= (thd->net.vio->ssl_arg ?
	      SSL_get_cipher((SSL*) thd->net.vio->ssl_arg) : "" );
2002
	end= strend(pos);
2003
	break;
2004
      case SHOW_SSL_GET_CIPHER_LIST:
2005
	if (thd->net.vio->ssl_arg)
2006
	{
2007
	  char *to= buff;
2008
	  for (int i=0 ; i++ ;)
2009
	  {
unknown's avatar
unknown committed
2010
	    const char *p= SSL_get_cipher_list((SSL*) thd->net.vio->ssl_arg,i);
2011 2012
	    if (p == NULL) 
	      break;
2013 2014
	    to= strmov(to, p);
	    *to++= ':';
2015
	  }
2016 2017 2018
	  if (to != buff)
	    to--;				// Remove last ':'
	  end= to;
2019
        }
unknown's avatar
unknown committed
2020
        break;
unknown's avatar
unknown committed
2021 2022

#endif /* HAVE_OPENSSL */
2023 2024 2025 2026
      case SHOW_KEY_CACHE_LONG:
	value= (value-(char*) &dflt_key_cache_var)+ (char*) sql_key_cache;
	end= int10_to_str(*(long*) value, buff, 10);
        break;
unknown's avatar
unknown committed
2027 2028
      case SHOW_UNDEF:				// Show never happen
      case SHOW_SYS:
2029
	break;					// Return empty string
unknown's avatar
SCRUM  
unknown committed
2030 2031
      default:
	break;
unknown's avatar
unknown committed
2032
      }
2033
      if (protocol->store(pos, (uint32) (end - pos), system_charset_info) ||
2034
	  protocol->write())
2035
        goto err;                               /* purecov: inspected */
unknown's avatar
unknown committed
2036 2037
    }
  }
unknown's avatar
unknown committed
2038
  pthread_mutex_unlock(mutex);
2039
  send_eof(thd);
unknown's avatar
unknown committed
2040 2041 2042
  DBUG_RETURN(0);

 err:
unknown's avatar
unknown committed
2043
  pthread_mutex_unlock(mutex);
unknown's avatar
unknown committed
2044 2045 2046 2047
  DBUG_RETURN(1);
}

#ifdef __GNUC__
unknown's avatar
unknown committed
2048
template class List_iterator_fast<char>;
unknown's avatar
unknown committed
2049 2050
template class List<char>;
#endif