sql_show.cc 64.2 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(files_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 1602 1603 1604
	  /* 
            query_length is always set to 0 when we set query = NULL; see
	    the comment in sql_class.h why this prevents crashes in possible
            races with query_length
          */
unknown's avatar
unknown committed
1605
          uint length= min(max_query_length, tmp->query_length);
1606
          thd_info->query=(char*) thd->strmake(tmp->query,length);
1607 1608
        }
        thread_infos.append(thd_info);
unknown's avatar
unknown committed
1609 1610 1611 1612 1613 1614
      }
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));

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

/*****************************************************************************
unknown's avatar
unknown committed
1641
  Status functions
unknown's avatar
unknown committed
1642 1643
*****************************************************************************/

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

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

1664 1665
  DBUG_ENTER("mysqld_show_charsets");

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

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

1676
  for ( cs= all_charsets ; cs < all_charsets+255 ; cs++ )
1677
  {
1678
    CHARSET_INFO **cl;
unknown's avatar
unknown committed
1679 1680 1681
    if (!cs[0] || !(cs[0]->state & MY_CS_AVAILABLE) || 
        !(cs[0]->state & MY_CS_PRIMARY))
      continue;
1682 1683
    for ( cl= all_charsets; cl < all_charsets+255 ;cl ++)
    {
unknown's avatar
unknown committed
1684 1685
      if (!cl[0] || !(cl[0]->state & MY_CS_AVAILABLE) || 
          !my_charset_same(cs[0],cl[0]))
1686
	continue;
unknown's avatar
unknown committed
1687
      if (!(wild && wild[0] &&
unknown's avatar
unknown committed
1688
	  wild_case_compare(system_charset_info,cl[0]->name,wild)))
1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704
      {
        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);
1705
  protocol->store(cs->comment ? cs->comment : "", system_charset_info);
1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721
  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));
1722
  field_list.push_back(new Item_empty_string("Description",60));
1723 1724 1725 1726 1727 1728 1729 1730
  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
1731 1732 1733 1734
    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)))
1735
    {
1736
      if (write_charset(protocol, cs[0]))
1737
	goto err;
1738 1739
    }
  }
1740
  send_eof(thd); 
1741 1742 1743 1744 1745
  DBUG_RETURN(0);
err:
  DBUG_RETURN(1);
}

unknown's avatar
unknown committed
1746
  
unknown's avatar
unknown committed
1747

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

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

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

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

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

#endif /* HAVE_OPENSSL */
2026
      case SHOW_KEY_CACHE_LONG:
2027
      case SHOW_KEY_CACHE_CONST_LONG:
2028 2029 2030
	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
2031 2032
      case SHOW_UNDEF:				// Show never happen
      case SHOW_SYS:
2033
	break;					// Return empty string
unknown's avatar
SCRUM  
unknown committed
2034 2035
      default:
	break;
unknown's avatar
unknown committed
2036
      }
2037
      if (protocol->store(pos, (uint32) (end - pos), system_charset_info) ||
2038
	  protocol->write())
2039
        goto err;                               /* purecov: inspected */
unknown's avatar
unknown committed
2040 2041
    }
  }
unknown's avatar
unknown committed
2042
  pthread_mutex_unlock(mutex);
2043
  send_eof(thd);
unknown's avatar
unknown committed
2044 2045 2046
  DBUG_RETURN(0);

 err:
unknown's avatar
unknown committed
2047
  pthread_mutex_unlock(mutex);
unknown's avatar
unknown committed
2048 2049 2050 2051
  DBUG_RETURN(1);
}

#ifdef __GNUC__
unknown's avatar
unknown committed
2052
template class List_iterator_fast<char>;
unknown's avatar
unknown committed
2053 2054
template class List<char>;
#endif