sql_show.cc 66.4 KB
Newer Older
monty@mysql.com's avatar
monty@mysql.com committed
1
/* Copyright (C) 2000-2004 MySQL AB
2

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3 4 5 6
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
7

bk@work.mysql.com's avatar
bk@work.mysql.com committed
8 9 10 11
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
12

bk@work.mysql.com's avatar
bk@work.mysql.com committed
13 14 15 16 17 18 19 20
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */


/* Function with list databases, tables or fields */

#include "mysql_priv.h"
21
#include "sql_select.h"                         // For select_describe
22
#include "repl_failsafe.h"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
23
#include <my_dir.h>
24

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
29 30 31 32
static const char *grant_names[]={
  "select","insert","update","delete","create","drop","reload","shutdown",
  "process","file","grant","references","index","alter"};

33
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bk@work.mysql.com's avatar
bk@work.mysql.com committed
34
static TYPELIB grant_types = { sizeof(grant_names)/sizeof(char **),
35
                               "grant_types",
36
                               grant_names, NULL};
37
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
38 39

static int
40 41
store_create_info(THD *thd, TABLE *table, String *packet);

tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
42

43 44 45 46
/*
  Report list of databases
  A database is a directory in the mysql_data_home directory
*/
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
47

bk@work.mysql.com's avatar
bk@work.mysql.com committed
48 49 50
int
mysqld_show_dbs(THD *thd,const char *wild)
{
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
51
  Item_string *field=new Item_string("",0,thd->charset());
bk@work.mysql.com's avatar
bk@work.mysql.com committed
52 53 54 55
  List<Item> field_list;
  char *end;
  List<char> files;
  char *file_name;
56
  Protocol *protocol= thd->protocol;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
57 58
  DBUG_ENTER("mysqld_show_dbs");

59
  field->name=(char*) thd->alloc(20+ (wild ? (uint) strlen(wild)+4: 0));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
60 61 62 63 64 65
  field->max_length=NAME_LEN;
  end=strmov(field->name,"Database");
  if (wild && wild[0])
    strxmov(end," (",wild,")",NullS);
  field_list.push_back(field);

66
  if (protocol->send_fields(&field_list,1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
67 68 69
    DBUG_RETURN(1);
  if (mysql_find_files(thd,&files,NullS,mysql_data_home,wild,1))
    DBUG_RETURN(1);
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
70
  List_iterator_fast<char> it(files);
71

bk@work.mysql.com's avatar
bk@work.mysql.com committed
72 73
  while ((file_name=it++))
  {
hf@deer.(none)'s avatar
hf@deer.(none) committed
74
#ifndef NO_EMBEDDED_ACCESS_CHECKS
75
    if (thd->master_access & (DB_ACLS | SHOW_DB_ACL) ||
76
	acl_get(thd->host, thd->ip, thd->priv_user, file_name,0) ||
77
	(grant_option && !check_grant_db(thd, file_name)))
hf@deer.(none)'s avatar
hf@deer.(none) committed
78
#endif
79
    {
80
      protocol->prepare_for_resend();
81
      protocol->store(file_name, system_charset_info);
82
      if (protocol->write())
83 84
	DBUG_RETURN(-1);
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
85
  }
86
  send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
87 88 89
  DBUG_RETURN(0);
}

90

91
/***************************************************************************
92
  List all open tables in a database
93 94
***************************************************************************/

95
int mysqld_show_open_tables(THD *thd,const char *wild)
96 97
{
  List<Item> field_list;
98
  OPEN_TABLE_LIST *open_list;
99
  Protocol *protocol= thd->protocol;
100 101
  DBUG_ENTER("mysqld_show_open_tables");

102 103
  field_list.push_back(new Item_empty_string("Database",NAME_LEN));
  field_list.push_back(new Item_empty_string("Table",NAME_LEN));
104 105
  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));
106

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

110
  if (!(open_list=list_open_tables(thd,wild)) && thd->is_fatal_error)
111 112
    DBUG_RETURN(-1);

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

129

bk@work.mysql.com's avatar
bk@work.mysql.com committed
130 131 132 133 134 135 136
/***************************************************************************
** 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)
{
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
137
  Item_string *field=new Item_string("",0,thd->charset());
bk@work.mysql.com's avatar
bk@work.mysql.com committed
138 139 140 141
  List<Item> field_list;
  char path[FN_LEN],*end;
  List<char> files;
  char *file_name;
142
  Protocol *protocol= thd->protocol;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
143 144
  DBUG_ENTER("mysqld_show_tables");

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

170 171 172 173
/***************************************************************************
** List all table types supported 
***************************************************************************/

174
int mysqld_show_storage_engines(THD *thd)
175 176
{
  List<Item> field_list;
177
  Protocol *protocol= thd->protocol;
178
  DBUG_ENTER("mysqld_show_storage_engines");
179

monty@mishka.local's avatar
monty@mishka.local committed
180
  field_list.push_back(new Item_empty_string("Engine",10));
181
  field_list.push_back(new Item_empty_string("Support",10));
182
  field_list.push_back(new Item_empty_string("Comment",80));
183

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

187
  const char *default_type_name= 
188
    ha_get_storage_engine((enum db_type)thd->variables.table_type);
189

190 191
  show_table_type_st *types;
  for (types= sys_table_types; types->type; types++)
192
  {
193
    protocol->prepare_for_resend();
194
    protocol->store(types->type, system_charset_info);
195 196 197
    const char *option_name= show_comp_option_name[(int) *types->value];

    if (*types->value == SHOW_OPTION_YES &&
198
	!my_strcasecmp(system_charset_info, default_type_name, types->type))
199
      option_name= "DEFAULT";
200 201
    protocol->store(option_name, system_charset_info);
    protocol->store(types->comment, system_charset_info);
202
    if (protocol->write())
203 204
      DBUG_RETURN(-1);
  }
205
  send_eof(thd);
206 207 208
  DBUG_RETURN(0);
}

209

210
/***************************************************************************
211
 List all privileges supported
212 213
***************************************************************************/

214 215 216 217
struct show_privileges_st {
  const char *privilege;
  const char *context;
  const char *comment;
218 219
};

220 221
static struct show_privileges_st sys_privileges[]=
{
222 223
  {"Alter", "Tables",  "To alter the table"},
  {"Create temporary tables","Databases","To use CREATE TEMPORARY TABLE"},
224
  {"Create", "Databases,Tables,Indexes",  "To create new databases and tables"},
225 226 227 228 229 230 231 232
  {"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"},
233
  {"References", "Databases,Tables", "To have references on tables"},
234 235 236 237 238
  {"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"},
239
  {"Shutdown","Server Admin", "To shutdown the server"},
240 241 242
  {"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"},
243 244 245
  {NullS, NullS, NullS}
};

246 247 248
int mysqld_show_privileges(THD *thd)
{
  List<Item> field_list;
249
  Protocol *protocol= thd->protocol;
250 251 252 253 254 255
  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));

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

259 260
  show_privileges_st *privilege= sys_privileges;
  for (privilege= sys_privileges; privilege->privilege ; privilege++)
261
  {
262
    protocol->prepare_for_resend();
263 264 265
    protocol->store(privilege->privilege, system_charset_info);
    protocol->store(privilege->context, system_charset_info);
    protocol->store(privilege->comment, system_charset_info);
266
    if (protocol->write())
267 268
      DBUG_RETURN(-1);
  }
269
  send_eof(thd);
270 271 272 273 274
  DBUG_RETURN(0);
}


/***************************************************************************
275
  List all column types
276 277
***************************************************************************/

278 279
struct show_column_type_st
{
280 281
  const char *type;
  uint size;
282 283 284 285 286 287 288 289 290 291 292 293
  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;
294
};
295 296 297 298 299

/* TODO: Add remaning types */

static struct show_column_type_st sys_column_types[]=
{
300 301
  {"tinyint",
    1,  "-128",  "127",  0,  0,  "YES",  "YES",
302 303
    "NO",   "YES", "YES",  "NO",  "NULL,0",
    "A very small integer"},
304
  {"tinyint unsigned",
305 306
    1,  "0"   ,  "255",  0,  0,  "YES",  "YES",
    "YES",  "YES",  "YES",  "NO",  "NULL,0",
307 308 309 310 311 312
    "A very small integer"},
};

int mysqld_show_column_types(THD *thd)
{
  List<Item> field_list;
313
  Protocol *protocol= thd->protocol;
314 315 316 317 318 319
  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));
320 321
  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));
322 323 324 325 326 327 328 329 330
  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));

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

334
  /* TODO: Change the loop to not use 'i' */
335 336
  for (uint i=0; i < sizeof(sys_column_types)/sizeof(sys_column_types[0]); i++)
  {
337
    protocol->prepare_for_resend();
338
    protocol->store(sys_column_types[i].type, system_charset_info);
339
    protocol->store((ulonglong) sys_column_types[i].size);
340 341
    protocol->store(sys_column_types[i].min_value, system_charset_info);
    protocol->store(sys_column_types[i].max_value, system_charset_info);
342 343
    protocol->store_short((longlong) sys_column_types[i].precision);
    protocol->store_short((longlong) sys_column_types[i].scale);
344 345 346 347 348 349 350 351
    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);
352
    if (protocol->write())
353 354
      DBUG_RETURN(-1);
  }
355
  send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
356 357 358 359
  DBUG_RETURN(0);
}


360
int
bk@work.mysql.com's avatar
bk@work.mysql.com committed
361
mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
362
                 const char *wild, bool dir)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
363 364 365 366 367
{
  uint i;
  char *ext;
  MY_DIR *dirp;
  FILEINFO *file;
368
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bk@work.mysql.com's avatar
bk@work.mysql.com committed
369
  uint col_access=thd->col_access;
370
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
371 372 373
  TABLE_LIST table_list;
  DBUG_ENTER("mysql_find_files");

374 375
  if (wild && !wild[0])
    wild=0;
376

bk@work.mysql.com's avatar
bk@work.mysql.com committed
377 378 379 380 381
  bzero((char*) &table_list,sizeof(table_list));

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

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

  VOID(ha_find_files(thd,db,path,wild,dir,files));

bk@work.mysql.com's avatar
bk@work.mysql.com committed
447 448 449
  DBUG_RETURN(0);
}

450

bk@work.mysql.com's avatar
bk@work.mysql.com committed
451
/***************************************************************************
452
 Extended version of mysqld_show_tables
bk@work.mysql.com's avatar
bk@work.mysql.com committed
453 454 455 456 457 458 459 460 461 462
***************************************************************************/

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;
463 464
  Protocol *protocol= thd->protocol;
  TIME time;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
465 466 467 468 469
  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));
monty@mishka.local's avatar
monty@mishka.local committed
470
  field_list.push_back(item=new Item_empty_string("Engine",10));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
471
  item->maybe_null=1;
472 473
  field_list.push_back(item=new Item_int("Version", (longlong) 0, 21));
  item->maybe_null=1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
  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;
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
496
  field_list.push_back(item=new Item_empty_string("Collation",32));
497
  item->maybe_null=1;
serg@serg.mylan's avatar
serg@serg.mylan committed
498 499
  field_list.push_back(item=new Item_int("Checksum",(longlong) 1,21));
  item->maybe_null=1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
500 501 502
  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));
503
  item->maybe_null=1;
504
  if (protocol->send_fields(&field_list,1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
505 506 507 508
    DBUG_RETURN(1);

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


/***************************************************************************
643
** List all columns in a table_list->real_name
bk@work.mysql.com's avatar
bk@work.mysql.com committed
644
***************************************************************************/
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
645

bk@work.mysql.com's avatar
bk@work.mysql.com committed
646
int
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
647 648
mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
		   bool verbose)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
649 650 651 652
{
  TABLE *table;
  handler *file;
  char tmp[MAX_FIELD_WIDTH];
653
  char tmp1[MAX_FIELD_WIDTH];
654
  Item *item;
655
  Protocol *protocol= thd->protocol;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
656 657
  DBUG_ENTER("mysqld_show_fields");
  DBUG_PRINT("enter",("db: %s  table: %s",table_list->db,
658
                      table_list->real_name));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
659 660 661

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

  Field **ptr,*field;
  for (ptr=table->field; (field= *ptr) ; ptr++)
  {
694 695
    if (!wild || !wild[0] || 
        !wild_case_compare(system_charset_info, field->field_name,wild))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
696 697
    {
      {
698 699
        byte *pos;
        uint flags=field->flags;
700
        String type(tmp,sizeof(tmp), system_charset_info);
701
#ifndef NO_EMBEDDED_ACCESS_CHECKS
702
        uint col_access;
703
#endif
704
	protocol->prepare_for_resend();
705
        protocol->store(field->field_name, system_charset_info);
706
        field->sql_type(type);
707
        protocol->store(type.ptr(), type.length(), system_charset_info);
708 709
	if (verbose)
	  protocol->store(field->has_charset() ? field->charset()->name : "NULL",
710
			system_charset_info);
711
        /*
712
          Even if TIMESTAMP field can't contain NULL as its value it
713
          will accept NULL if you will try to insert such value and will
714 715 716
          convert NULL value to current TIMESTAMP. So YES here means
          that NULL is allowed for assignment (but may be won't be
          returned).
717
        */
718 719 720
        pos=(byte*) ((flags & NOT_NULL_FLAG) &&
                     field->type() != FIELD_TYPE_TIMESTAMP ?
                     "" : "YES");
721
        protocol->store((const char*) pos, system_charset_info);
722 723 724
        pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
                     (field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
                     (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
725
        protocol->store((char*) pos, system_charset_info);
726

727 728 729 730 731 732 733 734 735
        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);
        }
736
        else if (field->unireg_check != Field::NEXT_NUMBER &&
737
                 !field->is_null())
738
        {                                               // Not null by default
739 740 741 742 743 744 745 746 747 748 749 750 751
          /*
            Note: we have to convert the default value into
            system_charset_info before sending.
            This is necessary for "SET NAMES binary":
            If the client character set is binary, we want to
            send metadata in UTF8 rather than in the column's
            character set.
            This conversion also makes "SHOW COLUMNS" and
            "SHOW CREATE TABLE" output consistent. Without
            this conversion the default values were displayed
            differently.
          */
          String def(tmp1,sizeof(tmp1), system_charset_info);
752
          type.set(tmp, sizeof(tmp), field->charset());
753
          field->val_str(&type);
754
          uint dummy_errors;
755
          def.copy(type.ptr(), type.length(), type.charset(), 
756
                   system_charset_info, &dummy_errors);
757
          protocol->store(def.ptr(), def.length(), def.charset());
758
        }
759 760
        else if (field->unireg_check == Field::NEXT_NUMBER ||
                 field->maybe_null())
761
          protocol->store_null();                       // Null as default
762
        else
763
          protocol->store("",0, system_charset_info);	// empty string
764 765 766 767

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

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
770 771
	if (verbose)
	{
772
	  /* Add grant options & comments */
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
773
	  end=tmp;
hf@deer.(none)'s avatar
hf@deer.(none) committed
774
#ifndef NO_EMBEDDED_ACCESS_CHECKS
775
	  col_access= get_column_grant(thd,table_list,field) & COL_ACLS;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
776 777 778 779 780 781 782 783
	  for (uint bitnr=0; col_access ; col_access>>=1,bitnr++)
	  {
	    if (col_access & 1)
	    {
	      *end++=',';
	      end=strmov(end,grant_types.type_names[bitnr]);
	    }
	  }
hf@deer.(none)'s avatar
hf@deer.(none) committed
784 785 786
#else
	  end=strmov(end,"");
#endif
787 788 789 790
	  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);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
791
	}
792
        if (protocol->write())
793
          DBUG_RETURN(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
794 795 796
      }
    }
  }
797
  send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
798 799 800
  DBUG_RETURN(0);
}

801

bk@work.mysql.com's avatar
bk@work.mysql.com committed
802 803 804 805
int
mysqld_show_create(THD *thd, TABLE_LIST *table_list)
{
  TABLE *table;
806 807 808
  Protocol *protocol= thd->protocol;
  char buff[2048];
  String buffer(buff, sizeof(buff), system_charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
809 810
  DBUG_ENTER("mysqld_show_create");
  DBUG_PRINT("enter",("db: %s  table: %s",table_list->db,
811
                      table_list->real_name));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
812

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
813
  /* Only one table for now */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
814 815
  if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
  {
816
    send_error(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
817 818 819
    DBUG_RETURN(1);
  }

serg@serg.mylan's avatar
serg@serg.mylan committed
820
  buffer.length(0);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
821
  if (store_create_info(thd, table, &buffer))
822 823
    DBUG_RETURN(-1);

bk@work.mysql.com's avatar
bk@work.mysql.com committed
824 825
  List<Item> field_list;
  field_list.push_back(new Item_empty_string("Table",NAME_LEN));
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
826
  // 1024 is for not to confuse old clients
827
  field_list.push_back(new Item_empty_string("Create Table",
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
828
					     max(buffer.length(),1024)));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
829

830 831 832
  if (protocol->send_fields(&field_list, 1))
    DBUG_RETURN(1);
  protocol->prepare_for_resend();
833 834
  protocol->store(table->table_name, system_charset_info);
  protocol->store(buffer.ptr(), buffer.length(), buffer.charset());
835
  if (protocol->write())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
836
    DBUG_RETURN(1);
837
  send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
838 839 840
  DBUG_RETURN(0);
}

841 842 843 844 845 846 847
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);
848
#ifndef NO_EMBEDDED_ACCESS_CHECKS
849
  uint db_access;
850
#endif
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 919 920 921 922 923 924 925 926 927 928 929 930
  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);
}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
931

tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
932 933 934
int
mysqld_show_logs(THD *thd)
{
935 936
  List<Item> field_list;
  Protocol *protocol= thd->protocol;
tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
937 938 939 940 941 942
  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));

943
  if (protocol->send_fields(&field_list,1))
tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
944 945
    DBUG_RETURN(1);

946
#ifdef HAVE_BERKELEY_DB
947
  if ((have_berkeley_db == SHOW_OPTION_YES) && berkeley_show_logs(protocol))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
948
    DBUG_RETURN(-1);
949
#endif
tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
950

951
  send_eof(thd);
tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
952 953 954 955
  DBUG_RETURN(0);
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
956 957 958 959
int
mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
{
  TABLE *table;
960
  Protocol *protocol= thd->protocol;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
961 962
  DBUG_ENTER("mysqld_show_keys");
  DBUG_PRINT("enter",("db: %s  table: %s",table_list->db,
963
                      table_list->real_name));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
964 965 966

  if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
  {
967
    send_error(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
968 969 970 971 972 973
    DBUG_RETURN(1);
  }

  List<Item> field_list;
  Item *item;
  field_list.push_back(new Item_empty_string("Table",NAME_LEN));
974
  field_list.push_back(new Item_return_int("Non_unique",1, MYSQL_TYPE_TINY));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
975
  field_list.push_back(new Item_empty_string("Key_name",NAME_LEN));
976
  field_list.push_back(new Item_return_int("Seq_in_index",2, MYSQL_TYPE_TINY));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
977 978 979
  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;
980
  field_list.push_back(item=new Item_int("Cardinality",0,21));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
981
  item->maybe_null=1;
982
  field_list.push_back(item=new Item_return_int("Sub_part",3,
sergefp@mysql.com's avatar
sergefp@mysql.com committed
983
						MYSQL_TYPE_SHORT));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
984 985 986
  item->maybe_null=1;
  field_list.push_back(item=new Item_empty_string("Packed",10));
  item->maybe_null=1;
987 988
  field_list.push_back(new Item_empty_string("Null",3));
  field_list.push_back(new Item_empty_string("Index_type",16));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
989 990 991
  field_list.push_back(new Item_empty_string("Comment",255));
  item->maybe_null=1;

992
  if (protocol->send_fields(&field_list,1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
993 994 995 996 997 998 999
    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;
1000
    const char *str;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1001 1002
    for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
    {
1003
      protocol->prepare_for_resend();
1004
      protocol->store(table->table_name, system_charset_info);
1005
      protocol->store_tiny((longlong) ((key_info->flags & HA_NOSAME) ? 0 :1));
1006
      protocol->store(key_info->name, system_charset_info);
1007 1008 1009
      protocol->store_tiny((longlong) (j+1));
      str=(key_part->field ? key_part->field->field_name :
	   "?unknown field?");
1010
      protocol->store(str, system_charset_info);
1011
      if (table->file->index_flags(i, j, 0) & HA_READ_ORDER)
1012
        protocol->store(((key_part->key_part_flag & HA_REVERSE_SORT) ?
1013
			 "D" : "A"), 1, system_charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1014
      else
1015
        protocol->store_null(); /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1016 1017 1018
      KEY *key=table->key_info+i;
      if (key->rec_per_key[j])
      {
1019
        ha_rows records=(table->file->records / key->rec_per_key[j]);
1020
        protocol->store((ulonglong) records);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1021 1022
      }
      else
1023
        protocol->store_null();
1024 1025

      /* Check if we have a key part that only uses part of the field */
serg@serg.mylan's avatar
serg@serg.mylan committed
1026 1027
      if (!(key_info->flags & HA_FULLTEXT) && (!key_part->field ||
          key_part->length != table->field[key_part->fieldnr-1]->key_length()))
sergefp@mysql.com's avatar
sergefp@mysql.com committed
1028
        protocol->store_short((longlong) key_part->length / 
1029
                             key_part->field->charset()->mbmaxlen);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1030
      else
1031 1032
        protocol->store_null();
      protocol->store_null();                   // No pack_information yet
1033 1034 1035

      /* Null flag */
      uint flags= key_part->field ? key_part->field->flags : 0;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1036
      char *pos=(char*) ((flags & NOT_NULL_FLAG) ? "" : "YES");
1037 1038
      protocol->store((const char*) pos, system_charset_info);
      protocol->store(table->file->index_type(i), system_charset_info);
1039
      /* Comment */
1040
      if (!table->keys_in_use.is_set(i))
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1041
	protocol->store("disabled",8, system_charset_info);
1042
      else
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1043
        protocol->store("", 0, system_charset_info);
1044
      if (protocol->write())
1045
        DBUG_RETURN(1); /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1046 1047
    }
  }
1048
  send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1049 1050 1051 1052 1053
  DBUG_RETURN(0);
}


/****************************************************************************
1054 1055
  Return only fields for API mysql_list_fields
  Use "show table wildcard" in mysql instead of this
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
****************************************************************************/

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)))
  {
1067
    send_error(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1068 1069 1070 1071 1072 1073 1074
    DBUG_VOID_RETURN;
  }
  List<Item> field_list;

  Field **ptr,*field;
  for (ptr=table->field ; (field= *ptr); ptr++)
  {
1075 1076
    if (!wild || !wild[0] || 
        !wild_case_compare(system_charset_info, field->field_name,wild))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1077
      field_list.push_back(new Item_field(field));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1078
  }
1079
  restore_record(table,default_values);              // Get empty record
1080
  if (thd->protocol->send_fields(&field_list,2))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1081
    DBUG_VOID_RETURN;
1082
  thd->protocol->flush();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1083 1084 1085
  DBUG_VOID_RETURN;
}

1086

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1087 1088 1089
int
mysqld_dump_create_info(THD *thd, TABLE *table, int fd)
{
1090 1091
  Protocol *protocol= thd->protocol;
  String *packet= protocol->storage_packet();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1092 1093
  DBUG_ENTER("mysqld_dump_create_info");
  DBUG_PRINT("enter",("table: %s",table->real_name));
1094

1095 1096
  protocol->prepare_for_resend();
  if (store_create_info(thd, table, packet))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1097
    DBUG_RETURN(-1);
1098

1099
  if (fd < 0)
1100
  {
1101
    if (protocol->write())
1102
      DBUG_RETURN(-1);
1103
    protocol->flush();
1104
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1105
  else
1106
  {
1107 1108
    if (my_write(fd, (const byte*) packet->ptr(), packet->length(),
		 MYF(MY_WME)))
1109 1110
      DBUG_RETURN(-1);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1111 1112
  DBUG_RETURN(0);
}
1113

1114
/*
1115 1116
  Go through all character combinations and ensure that sql_lex.cc can
  parse it as an identifer.
1117 1118

  SYNOPSIS
1119 1120 1121 1122 1123 1124 1125
  require_quotes()
  name			attribute name
  name_length		length of name

  RETURN
    #	Pointer to conflicting character
    0	No conflicting character
1126 1127
*/

1128
static const char *require_quotes(const char *name, uint name_length)
1129
{
1130 1131 1132 1133
  uint length;
  const char *end= name + name_length;

  for ( ; name < end ; name++)
1134
  {
1135
    uchar chr= (uchar) *name;
1136
    length= my_mbcharlen(system_charset_info, chr);
1137 1138
    if (length == 1 && !system_charset_info->ident_map[chr])
      return name;
1139 1140 1141
  }
  return 0;
}
1142

1143

1144 1145
void
append_identifier(THD *thd, String *packet, const char *name, uint length)
1146
{
1147
  const char *name_end;
1148
  char quote_char;
1149
  int q= get_quote_char_for_identifier(thd, name, length);
1150

1151 1152
  if (q == EOF)
  {
1153
    packet->append(name, length, system_charset_info);
1154
    return;
1155
  }
1156

1157 1158 1159 1160
  /*
    The identifier must be quoted as it includes a quote character or
   it's a keyword
  */
1161 1162

  packet->reserve(length*2 + 2);
1163
  quote_char= (char) q;
1164 1165 1166 1167
  packet->append(&quote_char, 1, system_charset_info);

  for (name_end= name+length ; name < name_end ; name+= length)
  {
1168 1169
    uchar chr= (uchar) *name;
    length= my_mbcharlen(system_charset_info, chr);
1170 1171 1172 1173 1174 1175 1176 1177 1178
    /*
      my_mbcharlen can retur 0 on a wrong multibyte
      sequence. It is possible when upgrading from 4.0,
      and identifier contains some accented characters.
      The manual says it does not work. So we'll just
      change length to 1 not to hang in the endless loop.
    */
    if (!length)
      length= 1;
1179
    if (length == 1 && chr == (uchar) quote_char)
1180 1181
      packet->append(&quote_char, 1, system_charset_info);
    packet->append(name, length, packet->charset());
1182
  }
1183
  packet->append(&quote_char, 1, system_charset_info);
1184 1185
}

1186

1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205
/*
  Get the quote character for displaying an identifier.

  SYNOPSIS
    get_quote_char_for_identifier()
    thd		Thread handler
    name	name to quote
    length	length of name

  IMPLEMENTATION
    If name is a keyword or includes a special character, then force
    quoting.
    Otherwise identifier is quoted only if the option OPTION_QUOTE_SHOW_CREATE
    is set.

  RETURN
    EOF	  No quote character is needed
    #	  Quote character
*/
1206 1207 1208 1209 1210 1211 1212

int get_quote_char_for_identifier(THD *thd, const char *name, uint length)
{
  if (!is_keyword(name,length) &&
      !require_quotes(name, length) &&
      !(thd->options & OPTION_QUOTE_SHOW_CREATE))
    return EOF;
1213
  if (thd->variables.sql_mode & MODE_ANSI_QUOTES)
1214
    return '"';
1215
  return '`';
1216 1217 1218
}


1219 1220 1221 1222 1223
/* Append directory name (if exists) to CREATE INFO */

static void append_directory(THD *thd, String *packet, const char *dir_type,
			     const char *filename)
{
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1224
  if (filename && !(thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE))
1225
  {
1226
    uint length= dirname_length(filename);
1227 1228 1229
    packet->append(' ');
    packet->append(dir_type);
    packet->append(" DIRECTORY='", 12);
1230
#ifdef __WIN__
1231
    char *winfilename = thd->memdup(filename, length);
1232 1233 1234 1235 1236
    for (uint i=0; i < length; i++)
	    if (winfilename[i] == '\\')
		    winfilename[i] = '/';
    packet->append(winfilename, length);
#else
1237
    packet->append(filename, length);
1238
#endif
1239 1240 1241 1242 1243
    packet->append('\'');
  }
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1244
#define LIST_PROCESS_HOST_LEN 64
1245

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1246
static int
1247
store_create_info(THD *thd, TABLE *table, String *packet)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1248
{
1249
  List<Item> field_list;
monty@mysql.com's avatar
monty@mysql.com committed
1250
  char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], *end, *alias;
1251
  String type(tmp, sizeof(tmp), system_charset_info);
1252 1253 1254 1255 1256
  Field **ptr,*field;
  uint primary_key;
  KEY *key_info;
  handler *file= table->file;
  HA_CREATE_INFO create_info;
1257 1258 1259 1260
  my_bool foreign_db_mode=    (thd->variables.sql_mode & (MODE_POSTGRESQL |
							  MODE_ORACLE |
							  MODE_MSSQL |
							  MODE_DB2 |
1261
							  MODE_MAXDB |
1262 1263 1264 1265
							  MODE_ANSI)) != 0;
  my_bool limited_mysql_mode= (thd->variables.sql_mode &
			       (MODE_NO_FIELD_OPTIONS | MODE_MYSQL323 |
				MODE_MYSQL40)) != 0;
1266

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1267 1268 1269
  DBUG_ENTER("store_create_info");
  DBUG_PRINT("enter",("table: %s",table->real_name));

1270
  restore_record(table,default_values); // Get empty record
1271

1272 1273 1274 1275
  if (table->tmp_table)
    packet->append("CREATE TEMPORARY TABLE ", 23);
  else
    packet->append("CREATE TABLE ", 13);
monty@mysql.com's avatar
monty@mysql.com committed
1276 1277 1278
  alias= (lower_case_table_names == 2 ? table->table_name :
	  table->real_name);
  append_identifier(thd, packet, alias, strlen(alias));
1279
  packet->append(" (\n", 3);
1280

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1281 1282
  for (ptr=table->field ; (field= *ptr); ptr++)
  {
1283
    bool has_default;
1284
    bool has_now_default;
1285 1286
    uint flags = field->flags;

1287
    if (ptr != table->field)
1288
      packet->append(",\n", 2);
1289

1290
    packet->append("  ", 2);
1291
    append_identifier(thd,packet,field->field_name, strlen(field->field_name));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1292 1293
    packet->append(' ');
    // check for surprises from the previous call to Field::sql_type()
1294
    if (type.ptr() != tmp)
1295
      type.set(tmp, sizeof(tmp), system_charset_info);
1296 1297
    else
      type.set_charset(system_charset_info);
1298

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1299
    field->sql_type(type);
1300
    packet->append(type.ptr(), type.length(), system_charset_info);
1301

1302
    if (field->has_charset() && !limited_mysql_mode && !foreign_db_mode)
1303
    {
1304
      if (field->charset() != table->table_charset)
1305
      {
1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316
	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);
1317
      }
1318
    }
1319

1320 1321
    if (flags & NOT_NULL_FLAG)
      packet->append(" NOT NULL", 9);
1322 1323 1324 1325 1326 1327 1328 1329
    else if (field->type() == FIELD_TYPE_TIMESTAMP)
    {
      /*
        TIMESTAMP field require explicit NULL flag, because unlike
        all other fields they are treated as NOT NULL by default.
      */
      packet->append(" NULL", 5);
    }
1330 1331

    /* 
1332
      Again we are using CURRENT_TIMESTAMP instead of NOW because it is
1333 1334 1335 1336 1337
      more standard 
    */
    has_now_default= table->timestamp_field == field && 
                     field->unireg_check != Field::TIMESTAMP_UN_FIELD;
    
1338
    has_default= (field->type() != FIELD_TYPE_BLOB &&
1339 1340 1341
		  field->unireg_check != Field::NEXT_NUMBER &&
                  !((foreign_db_mode || limited_mysql_mode) &&
                    has_now_default));
1342

1343
    if (has_default)
1344 1345
    {
      packet->append(" default ", 9);
1346 1347 1348
      if (has_now_default)
        packet->append("CURRENT_TIMESTAMP",17);
      else if (!field->is_null())
1349
      {                                             // Not null by default
1350
        type.set(tmp, sizeof(tmp), field->charset());
1351
        field->val_str(&type);
1352
	if (type.length())
1353
	{
1354
	  String def_val;
1355
          uint dummy_errors;
1356 1357
	  /* convert to system_charset_info == utf8 */
	  def_val.copy(type.ptr(), type.length(), field->charset(),
1358
		       system_charset_info, &dummy_errors);
1359 1360
          append_unescaped(packet, def_val.ptr(), def_val.length());
	}
1361 1362
        else
	  packet->append("''",2);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1363
      }
1364
      else if (field->maybe_null())
1365 1366
        packet->append("NULL", 4);                    // Null as default
      else
1367
        packet->append(tmp);
1368
    }
1369

1370 1371 1372 1373 1374
    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);

1375
    if (field->unireg_check == Field::NEXT_NUMBER && !foreign_db_mode)
1376 1377 1378 1379 1380 1381 1382
      packet->append(" auto_increment", 15 );

    if (field->comment.length)
    {
      packet->append(" COMMENT ",9);
      append_unescaped(packet, field->comment.str, field->comment.length);
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1383 1384
  }

1385 1386
  key_info= table->key_info;
  file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME);
1387
  bzero((char*) &create_info, sizeof(create_info));
1388 1389
  file->update_create_info(&create_info);
  primary_key= table->primary_key;
1390

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1391 1392
  for (uint i=0 ; i < table->keys ; i++,key_info++)
  {
1393 1394
    KEY_PART_INFO *key_part= key_info->key_part;
    bool found_primary=0;
1395
    packet->append(",\n  ", 4);
1396

1397
    if (i == primary_key && !strcmp(key_info->name, primary_key_name))
1398 1399
    {
      found_primary=1;
1400
      packet->append("PRIMARY ", 8);
1401
    }
1402
    else if (key_info->flags & HA_NOSAME)
1403
      packet->append("UNIQUE ", 7);
1404
    else if (key_info->flags & HA_FULLTEXT)
1405
      packet->append("FULLTEXT ", 9);
1406 1407
    else if (key_info->flags & HA_SPATIAL)
      packet->append("SPATIAL ", 8);
1408
    packet->append("KEY ", 4);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1409

1410
    if (!found_primary)
1411
     append_identifier(thd, packet, key_info->name, strlen(key_info->name));
1412

1413 1414 1415
    if (!(thd->variables.sql_mode & MODE_NO_KEY_OPTIONS) &&
	!limited_mysql_mode && !foreign_db_mode)
    {
1416
      if (key_info->algorithm == HA_KEY_ALG_BTREE)
1417 1418
	packet->append(" TYPE BTREE", 11);
      
1419 1420 1421
      if (key_info->algorithm == HA_KEY_ALG_HASH)
	packet->append(" TYPE HASH", 10);
      
1422 1423 1424 1425
      // +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);
1426 1427

      // No need to send TYPE FULLTEXT, it is sent as FULLTEXT KEY
1428
    }
1429
    packet->append(" (", 2);
1430

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1431 1432
    for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
    {
1433
      if (j)
1434
        packet->append(',');
1435

1436
      if (key_part->field)
1437 1438
        append_identifier(thd,packet,key_part->field->field_name,
			  strlen(key_part->field->field_name));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1439
      if (!key_part->field ||
1440 1441 1442
          (key_part->length !=
           table->field[key_part->fieldnr-1]->key_length() &&
           !(key_info->flags & HA_FULLTEXT)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1443
      {
1444
        buff[0] = '(';
1445 1446 1447
        char* end=int10_to_str((long) key_part->length / 
			       key_part->field->charset()->mbmaxlen,
			       buff + 1,10);
1448 1449
        *end++ = ')';
        packet->append(buff,(uint) (end-buff));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1450 1451 1452 1453
      }
    }
    packet->append(')');
  }
1454

1455 1456 1457 1458
  /*
    Get possible foreign key definitions stored in InnoDB and append them
    to the CREATE TABLE statement
  */
1459

1460
  if ((for_str= file->get_foreign_key_create_info()))
1461 1462 1463
  {
    packet->append(for_str, strlen(for_str));
    file->free_foreign_key_create_info(for_str);
1464 1465 1466
  }

  packet->append("\n)", 2);
1467
  if (!(thd->variables.sql_mode & MODE_NO_TABLE_OPTIONS) && !foreign_db_mode)
1468
  {
1469 1470 1471 1472
    if (thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))
      packet->append(" TYPE=", 6);
    else
      packet->append(" ENGINE=", 8);
1473 1474
    packet->append(file->table_type());
    
1475 1476 1477
    if (table->table_charset &&
	!(thd->variables.sql_mode & MODE_MYSQL323) &&
	!(thd->variables.sql_mode & MODE_MYSQL40))
1478
    {
1479
      packet->append(" DEFAULT CHARSET=", 17);
1480 1481 1482
      packet->append(table->table_charset->csname);
      if (!(table->table_charset->state & MY_CS_PRIMARY))
      {
1483
	packet->append(" COLLATE=", 9);
1484 1485
	packet->append(table->table_charset->name);
      }
1486
    }
1487

1488 1489
    if (table->min_rows)
    {
1490
      packet->append(" MIN_ROWS=", 10);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1491 1492
      end= longlong10_to_str(table->min_rows, buff, 10);
      packet->append(buff, (uint) (end- buff));
1493
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1494

1495 1496
    if (table->max_rows)
    {
1497
      packet->append(" MAX_ROWS=", 10);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1498 1499
      end= longlong10_to_str(table->max_rows, buff, 10);
      packet->append(buff, (uint) (end - buff));
1500
    }
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1501

1502 1503
    if (table->avg_row_length)
    {
1504
      packet->append(" AVG_ROW_LENGTH=", 16);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1505 1506
      end= longlong10_to_str(table->avg_row_length, buff,10);
      packet->append(buff, (uint) (end - buff));
1507
    }
1508

1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529
    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)
    {
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1530 1531 1532 1533 1534 1535
      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);
1536
    }
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1537 1538
    append_directory(thd, packet, "DATA",  create_info.data_file_name);
    append_directory(thd, packet, "INDEX", create_info.index_file_name);
1539
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1540 1541 1542 1543 1544
  DBUG_RETURN(0);
}


/****************************************************************************
1545 1546
  Return info about all processes
  returns for each thread: thread id, user, host, db, command, info
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1547 1548 1549 1550
****************************************************************************/

class thread_info :public ilink {
public:
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1551
  static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1552
  static void operator delete(void *ptr __attribute__((unused)),
1553
                              size_t size __attribute__((unused))) {} /*lint -e715 */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1554

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1555 1556
  ulong thread_id;
  time_t start_time;
1557
  uint   command;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570
  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;
1571 1572
  ulong max_query_length= (verbose ? thd->variables.max_allowed_packet :
			   PROCESS_LIST_WIDTH);
1573
  Protocol *protocol= thd->protocol;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1574 1575
  DBUG_ENTER("mysqld_list_processes");

1576
  field_list.push_back(new Item_int("Id",0,11));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1577
  field_list.push_back(new Item_empty_string("User",16));
1578
  field_list.push_back(new Item_empty_string("Host",LIST_PROCESS_HOST_LEN));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1579 1580 1581
  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));
1582
  field_list.push_back(new Item_return_int("Time",7, FIELD_TYPE_LONG));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1583 1584 1585 1586
  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;
1587
  if (protocol->send_fields(&field_list,1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1588 1589 1590 1591 1592 1593 1594 1595 1596
    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++))
    {
1597
      struct st_my_thread_var *mysys_var;
1598
      if ((tmp->vio_ok() || tmp->system_thread) &&
1599
          (!user || (tmp->user && !strcmp(tmp->user,user))))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1600
      {
1601 1602 1603
        thread_info *thd_info=new thread_info;

        thd_info->thread_id=tmp->thread_id;
1604 1605 1606
        thd_info->user=thd->strdup(tmp->user ? tmp->user :
				   (tmp->system_thread ?
				    "system user" : "unauthenticated user"));
1607
	if (tmp->peer_port && (tmp->host || tmp->ip) && thd->host_or_ip[0])
1608 1609
	{
	  if ((thd_info->host= thd->alloc(LIST_PROCESS_HOST_LEN+1)))
1610
	    my_snprintf((char *) thd_info->host, LIST_PROCESS_HOST_LEN,
1611
			"%s:%u", tmp->host_or_ip, tmp->peer_port);
1612 1613
	}
	else
1614
	  thd_info->host= thd->strdup(tmp->host_or_ip);
1615 1616 1617
        if ((thd_info->db=tmp->db))             // Safe test
          thd_info->db=thd->strdup(thd_info->db);
        thd_info->command=(int) tmp->command;
1618 1619
        if ((mysys_var= tmp->mysys_var))
          pthread_mutex_lock(&mysys_var->mutex);
1620
        thd_info->proc_info= (char*) (tmp->killed ? "Killed" : 0);
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
1621
#ifndef EMBEDDED_LIBRARY
1622 1623 1624 1625 1626 1627 1628 1629 1630 1631
        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);
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
1632 1633 1634
#else
        thd_info->state_info= (char*)"Writing to net";
#endif
1635 1636
        if (mysys_var)
          pthread_mutex_unlock(&mysys_var->mutex);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1637 1638

#if !defined(DONT_USE_THR_ALARM) && ! defined(SCO)
1639 1640
        if (pthread_kill(tmp->real_id,0))
          tmp->proc_info="*** DEAD ***";        // This shouldn't happen
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1641
#endif
1642 1643 1644
#ifdef EXTRA_DEBUG
        thd_info->start_time= tmp->time_after_lock;
#else
1645
        thd_info->start_time= tmp->start_time;
1646
#endif
1647 1648 1649
        thd_info->query=0;
        if (tmp->query)
        {
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
1650 1651 1652 1653 1654
	  /* 
            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
          */
1655
          uint length= min(max_query_length, tmp->query_length);
1656
          thd_info->query=(char*) thd->strmake(tmp->query,length);
1657 1658
        }
        thread_infos.append(thd_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1659 1660 1661 1662 1663 1664
      }
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));

  thread_info *thd_info;
1665
  time_t now= time(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1666 1667
  while ((thd_info=thread_infos.get()))
  {
1668 1669
    protocol->prepare_for_resend();
    protocol->store((ulonglong) thd_info->thread_id);
1670 1671 1672
    protocol->store(thd_info->user, system_charset_info);
    protocol->store(thd_info->host, system_charset_info);
    protocol->store(thd_info->db, system_charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1673
    if (thd_info->proc_info)
1674
      protocol->store(thd_info->proc_info, system_charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1675
    else
1676
      protocol->store(command_name[thd_info->command], system_charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1677
    if (thd_info->start_time)
1678
      protocol->store((uint32) (now - thd_info->start_time));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1679
    else
1680
      protocol->store_null();
1681 1682
    protocol->store(thd_info->state_info, system_charset_info);
    protocol->store(thd_info->query, system_charset_info);
1683
    if (protocol->write())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1684 1685
      break; /* purecov: inspected */
  }
1686
  send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1687 1688 1689 1690
  DBUG_VOID_RETURN;
}

/*****************************************************************************
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1691
  Status functions
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1692 1693
*****************************************************************************/

1694 1695 1696 1697
static bool write_collation(Protocol *protocol, CHARSET_INFO *cs)
{
  protocol->prepare_for_resend();
  protocol->store(cs->name, system_charset_info);
1698
  protocol->store(cs->csname, system_charset_info);
1699
  protocol->store_short((longlong) cs->number);
1700 1701
  protocol->store((cs->state & MY_CS_PRIMARY) ? "Yes" : "",system_charset_info);
  protocol->store((cs->state & MY_CS_COMPILED)? "Yes" : "",system_charset_info);
1702 1703 1704 1705 1706
  protocol->store_short((longlong) cs->strxfrm_multiply);
  return protocol->write();
}

int mysqld_show_collations(THD *thd, const char *wild)
1707 1708
{
  char buff[8192];
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
1709
  String packet2(buff,sizeof(buff),thd->charset());
1710
  List<Item> field_list;
1711
  CHARSET_INFO **cs;
1712
  Protocol *protocol= thd->protocol;
1713

1714 1715
  DBUG_ENTER("mysqld_show_charsets");

1716
  field_list.push_back(new Item_empty_string("Collation",30));
1717
  field_list.push_back(new Item_empty_string("Charset",30));
1718
  field_list.push_back(new Item_return_int("Id",11, FIELD_TYPE_SHORT));
1719 1720
  field_list.push_back(new Item_empty_string("Default",30));
  field_list.push_back(new Item_empty_string("Compiled",30));
1721
  field_list.push_back(new Item_return_int("Sortlen",3, FIELD_TYPE_SHORT));
1722

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

1726
  for ( cs= all_charsets ; cs < all_charsets+255 ; cs++ )
1727
  {
1728
    CHARSET_INFO **cl;
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
1729 1730 1731
    if (!cs[0] || !(cs[0]->state & MY_CS_AVAILABLE) || 
        !(cs[0]->state & MY_CS_PRIMARY))
      continue;
1732 1733
    for ( cl= all_charsets; cl < all_charsets+255 ;cl ++)
    {
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
1734 1735
      if (!cl[0] || !(cl[0]->state & MY_CS_AVAILABLE) || 
          !my_charset_same(cs[0],cl[0]))
1736
	continue;
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
1737
      if (!(wild && wild[0] &&
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
1738
	  wild_case_compare(system_charset_info,cl[0]->name,wild)))
1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754
      {
        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);
1755
  protocol->store(cs->comment ? cs->comment : "", system_charset_info);
1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771
  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));
1772
  field_list.push_back(new Item_empty_string("Description",60));
1773 1774 1775 1776 1777 1778 1779 1780
  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++ )
  {
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
1781 1782 1783 1784
    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)))
1785
    {
1786
      if (write_charset(protocol, cs[0]))
1787
	goto err;
1788 1789
    }
  }
1790
  send_eof(thd); 
1791 1792 1793 1794 1795
  DBUG_RETURN(0);
err:
  DBUG_RETURN(1);
}

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1796
  
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1797

1798
int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
1799 1800
		enum enum_var_type value_type,
		pthread_mutex_t *mutex)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1801
{
1802
  char buff[1024];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1803
  List<Item> field_list;
1804
  Protocol *protocol= thd->protocol;
1805
  LEX_STRING null_lex_str;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1806
  DBUG_ENTER("mysqld_show");
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1807

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1808 1809
  field_list.push_back(new Item_empty_string("Variable_name",30));
  field_list.push_back(new Item_empty_string("Value",256));
1810
  if (protocol->send_fields(&field_list,1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1811
    DBUG_RETURN(1); /* purecov: inspected */
1812
  null_lex_str.str= 0;				// For sys_var->value_ptr()
1813
  null_lex_str.length= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1814

1815
  pthread_mutex_lock(mutex);
1816
  for (; variables->name; variables++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1817
  {
1818
    if (!(wild && wild[0] && wild_case_compare(system_charset_info,
1819
					       variables->name,wild)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1820
    {
1821
      protocol->prepare_for_resend();
1822
      protocol->store(variables->name, system_charset_info);
1823 1824
      SHOW_TYPE show_type=variables->type;
      char *value=variables->value;
1825 1826 1827
      const char *pos, *end;
      long nr;

1828 1829 1830
      if (show_type == SHOW_SYS)
      {
	show_type= ((sys_var*) value)->type();
1831 1832
	value=     (char*) ((sys_var*) value)->value_ptr(thd, value_type,
							 &null_lex_str);
1833 1834
      }

1835
      pos= end= buff;
1836
      switch (show_type) {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1837 1838
      case SHOW_LONG:
      case SHOW_LONG_CONST:
1839
	end= int10_to_str(*(long*) value, buff, 10);
1840 1841
        break;
      case SHOW_LONGLONG:
1842
	end= longlong10_to_str(*(longlong*) value, buff, 10);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1843
	break;
1844
      case SHOW_HA_ROWS:
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1845
        end= longlong10_to_str((longlong) *(ha_rows*) value, buff, 10);
1846
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1847
      case SHOW_BOOL:
1848
	end= strmov(buff, *(bool*) value ? "ON" : "OFF");
1849
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1850
      case SHOW_MY_BOOL:
1851
	end= strmov(buff, *(my_bool*) value ? "ON" : "OFF");
1852
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1853 1854
      case SHOW_INT_CONST:
      case SHOW_INT:
1855
	end= int10_to_str((long) *(uint32*) value, buff, 10);
1856
        break;
1857 1858
      case SHOW_HAVE:
      {
1859
	SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) value;
1860 1861
	pos= show_comp_option_name[(int) tmp];
	end= strend(pos);
1862 1863
        break;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1864
      case SHOW_CHAR:
gluh@gluh.mysql.r18.ru's avatar
gluh@gluh.mysql.r18.ru committed
1865 1866 1867 1868
      {
        if (!(pos= value))
          pos= "";
        end= strend(pos);
1869
        break;
gluh@gluh.mysql.r18.ru's avatar
gluh@gluh.mysql.r18.ru committed
1870
       }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1871
      case SHOW_STARTTIME:
1872 1873
	nr= (long) (thd->query_start() - start_time);
	end= int10_to_str(nr, buff, 10);
1874
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1875
      case SHOW_QUESTION:
1876
	end= int10_to_str((long) thd->query_id, buff, 10);
1877
        break;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1878
#ifdef HAVE_REPLICATION
1879
      case SHOW_RPL_STATUS:
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
1880
	end= strmov(buff, rpl_status_type[(int)rpl_status]);
1881
	break;
1882 1883
      case SHOW_SLAVE_RUNNING:
      {
1884
	pthread_mutex_lock(&LOCK_active_mi);
1885 1886
	end= strmov(buff, (active_mi->slave_running &&
			   active_mi->rli.slave_running) ? "ON" : "OFF");
1887
	pthread_mutex_unlock(&LOCK_active_mi);
1888 1889
	break;
      }
1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902
      case SHOW_SLAVE_RETRIED_TRANS:
      {
        /*
          TODO: in 5.1 with multimaster, have one such counter per line in SHOW
          SLAVE STATUS, and have the sum over all lines here.
        */
	pthread_mutex_lock(&LOCK_active_mi);
        pthread_mutex_lock(&active_mi->rli.data_lock);
	end= int10_to_str(active_mi->rli.retried_trans, buff, 10);
        pthread_mutex_unlock(&active_mi->rli.data_lock);
	pthread_mutex_unlock(&LOCK_active_mi);
	break;
      }
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1903
#endif /* HAVE_REPLICATION */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1904
      case SHOW_OPENTABLES:
1905
	end= int10_to_str((long) cached_tables(), buff, 10);
1906
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1907
      case SHOW_CHAR_PTR:
1908
      {
1909 1910 1911 1912
        if (!(pos= *(char**) value))
          pos= "";
        end= strend(pos);
        break;
1913
      }
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1914
#ifdef HAVE_OPENSSL
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1915
	/* First group - functions relying on CTX */
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1916
      case SHOW_SSL_CTX_SESS_ACCEPT:
1917 1918
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_accept(ssl_acceptor_fd->
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1919
						      ssl_context)),
1920
			  buff, 10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1921 1922
        break;
      case SHOW_SSL_CTX_SESS_ACCEPT_GOOD:
1923 1924
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_accept_good(ssl_acceptor_fd->
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1925
							   ssl_context)),
1926
			  buff, 10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1927
        break;
1928
      case SHOW_SSL_CTX_SESS_CONNECT_GOOD:
1929 1930
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_connect_good(ssl_acceptor_fd->
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1931
							    ssl_context)),
1932
			  buff, 10);
1933
        break;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1934
      case SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE:
1935
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1936
				  SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context)),
1937
			  buff, 10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1938
        break;
1939
      case SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE:
1940
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1941
				  SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd-> ssl_context)),
1942
			  buff, 10);
1943
        break;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1944
      case SHOW_SSL_CTX_SESS_CB_HITS:
1945 1946
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_cb_hits(ssl_acceptor_fd->
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1947
						       ssl_context)),
1948
			  buff, 10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1949
        break;
1950
      case SHOW_SSL_CTX_SESS_HITS:
1951 1952
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_hits(ssl_acceptor_fd->
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1953
						    ssl_context)),
1954
			  buff, 10);
1955 1956
        break;
      case SHOW_SSL_CTX_SESS_CACHE_FULL:
1957 1958
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_cache_full(ssl_acceptor_fd->
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1959
							  ssl_context)),
1960
			  buff, 10);
1961 1962
        break;
      case SHOW_SSL_CTX_SESS_MISSES:
1963 1964
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_misses(ssl_acceptor_fd->
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1965
						      ssl_context)),
1966
			  buff, 10);
1967 1968
        break;
      case SHOW_SSL_CTX_SESS_TIMEOUTS:
1969
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1970
				  SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context)),
1971
			  buff,10);
1972
        break;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1973
      case SHOW_SSL_CTX_SESS_NUMBER:
1974
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1975
				  SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context)),
1976
			  buff,10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1977
        break;
1978
      case SHOW_SSL_CTX_SESS_CONNECT:
1979
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1980
				  SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context)),
1981
			  buff,10);
1982
        break;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1983
      case SHOW_SSL_CTX_SESS_GET_CACHE_SIZE:
1984
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1985
				  SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context)),
1986
				  buff,10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1987 1988
        break;
      case SHOW_SSL_CTX_GET_VERIFY_MODE:
1989
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1990
				  SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context)),
1991
			  buff,10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1992 1993
        break;
      case SHOW_SSL_CTX_GET_VERIFY_DEPTH:
1994
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1995
				  SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context)),
1996
			  buff,10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1997 1998
        break;
      case SHOW_SSL_CTX_GET_SESSION_CACHE_MODE:
1999 2000
	if (!ssl_acceptor_fd)
	{
2001 2002
	  pos= "NONE";
	  end= pos+4;
2003 2004
	  break;
	}
2005
	switch (SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context))
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
2006 2007
	{
          case SSL_SESS_CACHE_OFF:
2008
            pos= "OFF";
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
2009 2010
	    break;
          case SSL_SESS_CACHE_CLIENT:
2011
            pos= "CLIENT";
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
2012 2013
	    break;
          case SSL_SESS_CACHE_SERVER:
2014
            pos= "SERVER";
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
2015 2016
	    break;
          case SSL_SESS_CACHE_BOTH:
2017
            pos= "BOTH";
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
2018 2019
	    break;
          case SSL_SESS_CACHE_NO_AUTO_CLEAR:
2020
            pos= "NO_AUTO_CLEAR";
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
2021 2022
	    break;
          case SSL_SESS_CACHE_NO_INTERNAL_LOOKUP:
2023
            pos= "NO_INTERNAL_LOOKUP";
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
2024 2025
	    break;
	  default:
2026
            pos= "Unknown";
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
2027 2028
	    break;
	}
2029
	end= strend(pos);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
2030
        break;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
2031 2032
	/* First group - functions relying on SSL */
      case SHOW_SSL_GET_VERSION:
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2033 2034
	pos= (thd->net.vio->ssl_arg ?
	      SSL_get_version((SSL*) thd->net.vio->ssl_arg) : "");
2035
	end= strend(pos);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
2036 2037
        break;
      case SHOW_SSL_SESSION_REUSED:
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2038 2039 2040 2041 2042
	end= int10_to_str((long) (thd->net.vio->ssl_arg ?
				  SSL_session_reused((SSL*) thd->net.vio->
						     ssl_arg) :
				  0),
			  buff, 10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
2043 2044
        break;
      case SHOW_SSL_GET_DEFAULT_TIMEOUT:
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2045 2046 2047 2048 2049
	end= int10_to_str((long) (thd->net.vio->ssl_arg ?
				  SSL_get_default_timeout((SSL*) thd->net.vio->
							  ssl_arg) :
				  0),
			  buff, 10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
2050 2051
        break;
      case SHOW_SSL_GET_VERIFY_MODE:
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2052 2053 2054 2055 2056
	end= int10_to_str((long) (thd->net.vio->ssl_arg ?
				  SSL_get_verify_mode((SSL*) thd->net.vio->
						      ssl_arg):
				  0),
			  buff, 10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
2057 2058
        break;
      case SHOW_SSL_GET_VERIFY_DEPTH:
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2059 2060 2061 2062 2063
	end= int10_to_str((long) (thd->net.vio->ssl_arg ?
				  SSL_get_verify_depth((SSL*) thd->net.vio->
						       ssl_arg):
				  0),
			  buff, 10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
2064 2065
        break;
      case SHOW_SSL_GET_CIPHER:
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2066 2067
	pos= (thd->net.vio->ssl_arg ?
	      SSL_get_cipher((SSL*) thd->net.vio->ssl_arg) : "" );
2068
	end= strend(pos);
2069
	break;
2070
      case SHOW_SSL_GET_CIPHER_LIST:
2071
	if (thd->net.vio->ssl_arg)
2072
	{
2073
	  char *to= buff;
2074
	  for (int i=0 ; i++ ;)
2075
	  {
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2076
	    const char *p= SSL_get_cipher_list((SSL*) thd->net.vio->ssl_arg,i);
2077 2078
	    if (p == NULL) 
	      break;
2079 2080
	    to= strmov(to, p);
	    *to++= ':';
2081
	  }
2082 2083 2084
	  if (to != buff)
	    to--;				// Remove last ':'
	  end= to;
2085
        }
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
2086
        break;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
2087 2088

#endif /* HAVE_OPENSSL */
2089
      case SHOW_KEY_CACHE_LONG:
2090
      case SHOW_KEY_CACHE_CONST_LONG:
timour@mysql.com's avatar
timour@mysql.com committed
2091
	value= (value-(char*) &dflt_key_cache_var)+ (char*) dflt_key_cache;
2092 2093
	end= int10_to_str(*(long*) value, buff, 10);
        break;
2094 2095
      case SHOW_UNDEF:				// Show never happen
      case SHOW_SYS:
2096
	break;					// Return empty string
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
2097 2098
      default:
	break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2099
      }
2100
      if (protocol->store(pos, (uint32) (end - pos), system_charset_info) ||
2101
	  protocol->write())
2102
        goto err;                               /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2103 2104
    }
  }
2105
  pthread_mutex_unlock(mutex);
2106
  send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2107 2108 2109
  DBUG_RETURN(0);

 err:
2110
  pthread_mutex_unlock(mutex);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2111 2112 2113 2114
  DBUG_RETURN(1);
}

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