sql_show.cc 56.5 KB
Newer Older
1
/* Copyright (C) 2000 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
bk@work.mysql.com's avatar
bk@work.mysql.com committed
22
#include "sql_acl.h"
23
#include "repl_failsafe.h"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
24
#include <my_dir.h>
25

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

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

static const char *grant_names[]={
  "select","insert","update","delete","create","drop","reload","shutdown",
  "process","file","grant","references","index","alter"};

static TYPELIB grant_types = { sizeof(grant_names)/sizeof(char **),
37 38
                               "grant_types",
                               grant_names};
bk@work.mysql.com's avatar
bk@work.mysql.com committed
39 40

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

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

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

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
51 52 53 54
/****************************************************************************
** Send 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
55

bk@work.mysql.com's avatar
bk@work.mysql.com committed
56 57 58
int
mysqld_show_dbs(THD *thd,const char *wild)
{
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
59
  Item_string *field=new Item_string("",0,thd->charset());
bk@work.mysql.com's avatar
bk@work.mysql.com committed
60 61 62 63
  List<Item> field_list;
  char *end;
  List<char> files;
  char *file_name;
64
  Protocol *protocol= thd->protocol;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
65 66
  DBUG_ENTER("mysqld_show_dbs");

67
  field->name=(char*) thd->alloc(20+ (wild ? (uint) strlen(wild)+4: 0));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
68 69 70 71 72 73
  field->max_length=NAME_LEN;
  end=strmov(field->name,"Database");
  if (wild && wild[0])
    strxmov(end," (",wild,")",NullS);
  field_list.push_back(field);

74
  if (protocol->send_fields(&field_list,1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
75 76 77
    DBUG_RETURN(1);
  if (mysql_find_files(thd,&files,NullS,mysql_data_home,wild,1))
    DBUG_RETURN(1);
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
78
  List_iterator_fast<char> it(files);
79

bk@work.mysql.com's avatar
bk@work.mysql.com committed
80 81
  while ((file_name=it++))
  {
82
    if (thd->master_access & (DB_ACLS | SHOW_DB_ACL) ||
83 84 85
	acl_get(thd->host, thd->ip, (char*) &thd->remote.sin_addr,
		thd->priv_user, file_name) ||
	(grant_option && !check_grant_db(thd, file_name)))
86
    {
87
      protocol->prepare_for_resend();
88
      protocol->store(file_name, system_charset_info);
89
      if (protocol->write())
90 91
	DBUG_RETURN(-1);
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
92
  }
93
  send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
94 95 96
  DBUG_RETURN(0);
}

97

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

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

109 110
  field_list.push_back(new Item_empty_string("Database",NAME_LEN));
  field_list.push_back(new Item_empty_string("Table",NAME_LEN));
111 112
  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));
113

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

117
  if (!(open_list=list_open_tables(thd,wild)) && thd->is_fatal_error)
118 119
    DBUG_RETURN(-1);

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

136

bk@work.mysql.com's avatar
bk@work.mysql.com committed
137 138 139 140 141 142 143
/***************************************************************************
** 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
144
  Item_string *field=new Item_string("",0,thd->charset());
bk@work.mysql.com's avatar
bk@work.mysql.com committed
145 146 147 148
  List<Item> field_list;
  char path[FN_LEN],*end;
  List<char> files;
  char *file_name;
149
  Protocol *protocol= thd->protocol;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
150 151
  DBUG_ENTER("mysqld_show_tables");

152 153
  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
154 155 156 157 158 159 160
  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);
161
  if (protocol->send_fields(&field_list,1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
162 163 164
    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
165
  List_iterator_fast<char> it(files);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
166 167
  while ((file_name=it++))
  {
168
    protocol->prepare_for_resend();
169
    protocol->store(file_name, system_charset_info);
170
    if (protocol->write())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
171 172
      DBUG_RETURN(-1);
  }
173
  send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
174 175 176
  DBUG_RETURN(0);
}

177 178 179 180
/***************************************************************************
** List all table types supported 
***************************************************************************/

181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
struct show_table_type_st {
  const char *type;
  SHOW_COMP_OPTION *value;
  const char *comment;
};


SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES;

static struct show_table_type_st sys_table_types[]=
{
  {"MyISAM", &have_yes,
   "Default type from 3.23 with great performance"},
  {"HEAP"  , &have_yes,
   "Hash based, stored in memory, useful for temporary tables"},
  {"MERGE",  &have_yes,
   "Collection of identical MyISAM tables"},
  {"ISAM",   &have_isam,
   "Obsolete table type; Is replaced by MyISAM"},
  {"InnoDB", &have_innodb,
   "Supports transactions, row-level locking and foreign keys"},
  {"BDB",    &have_berkeley_db,
   "Supports transactions and page-level locking"},
  {NullS, NULL, NullS}
205 206
};

207

208 209 210
int mysqld_show_table_types(THD *thd)
{
  List<Item> field_list;
211
  Protocol *protocol= thd->protocol;
212 213 214 215
  DBUG_ENTER("mysqld_show_table_types");

  field_list.push_back(new Item_empty_string("Type",10));
  field_list.push_back(new Item_empty_string("Support",10));
216
  field_list.push_back(new Item_empty_string("Comment",80));
217

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

221 222
  const char *default_type_name=
    ha_table_typelib.type_names[thd->variables.table_type];
223

224 225
  show_table_type_st *types;
  for (types= sys_table_types; types->type; types++)
226
  {
227
    protocol->prepare_for_resend();
228
    protocol->store(types->type, system_charset_info);
229 230 231
    const char *option_name= show_comp_option_name[(int) *types->value];

    if (*types->value == SHOW_OPTION_YES &&
232
	!my_strcasecmp(system_charset_info, default_type_name, types->type))
233
      option_name= "DEFAULT";
234 235
    protocol->store(option_name, system_charset_info);
    protocol->store(types->comment, system_charset_info);
236
    if (protocol->write())
237 238
      DBUG_RETURN(-1);
  }
239
  send_eof(thd);
240 241 242
  DBUG_RETURN(0);
}

243

244
/***************************************************************************
245
 List all privileges supported
246 247
***************************************************************************/

248 249 250 251
struct show_privileges_st {
  const char *privilege;
  const char *context;
  const char *comment;
252 253
};

254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277

/*
  TODO:  Update with new privileges
*/
static struct show_privileges_st sys_privileges[]=
{
  {"Select", "Tables",  "To retrieve rows from table"},
  {"Insert", "Tables",  "To insert data into tables"},
  {"Update", "Tables",  "To update existing rows "},
  {"Delete", "Tables",  "To delete existing rows"},
  {"Index",  "Tables",  "To create or drop indexes"},
  {"Alter",  "Tables",  "To alter the table"},
  {"Create", "Databases,Tables,Indexes",  "To create new databases and tables"},
  {"Drop",   "Databases,Tables", "To drop databases and tables"},
  {"Grant",  "Databases,Tables", "To give to other users those privileges you possess"},
  {"References", "Databases,Tables", "To have references on tables"},
  {"Reload",  "Server Admin", "To reload or refresh tables, logs and privileges"},
  {"Shutdown","Server Admin", "To shutdown the server"},
  {"Process", "Server Admin", "To view the plain text of currently executing queries"},
  {"File",    "File access on server",   "To read and write files on the server"},
  {NullS, NullS, NullS}
};


278 279 280
int mysqld_show_privileges(THD *thd)
{
  List<Item> field_list;
281
  Protocol *protocol= thd->protocol;
282 283 284 285 286 287
  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));

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

291 292
  show_privileges_st *privilege= sys_privileges;
  for (privilege= sys_privileges; privilege->privilege ; privilege++)
293
  {
294
    protocol->prepare_for_resend();
295 296 297
    protocol->store(privilege->privilege, system_charset_info);
    protocol->store(privilege->context, system_charset_info);
    protocol->store(privilege->comment, system_charset_info);
298
    if (protocol->write())
299 300
      DBUG_RETURN(-1);
  }
301
  send_eof(thd);
302 303 304 305 306
  DBUG_RETURN(0);
}


/***************************************************************************
307
  List all column types
308 309
***************************************************************************/

310 311
struct show_column_type_st
{
312 313
  const char *type;
  uint size;
314 315 316 317 318 319 320 321 322 323 324 325
  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;
326
};
327 328 329 330 331

/* TODO: Add remaning types */

static struct show_column_type_st sys_column_types[]=
{
332 333 334 335 336 337 338 339 340 341 342 343 344
  {"tinyint",
    1,  "-128",  "127",  0,  0,  "YES",  "YES",
    "NO",   "YES", "YES",  "NO",  "NULL,0",  
    "A very small integer"}, 
  {"tinyint unsigned",
    1,  "0"   ,  "255",  0,  0,  "YES",  "YES",  
    "YES",  "YES",  "YES",  "NO",  "NULL,0", 
    "A very small integer"},
};

int mysqld_show_column_types(THD *thd)
{
  List<Item> field_list;
345
  Protocol *protocol= thd->protocol;
346 347 348 349 350 351
  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));
352 353
  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));
354 355 356 357 358 359 360 361 362
  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));

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

366
  /* TODO: Change the loop to not use 'i' */
367 368
  for (uint i=0; i < sizeof(sys_column_types)/sizeof(sys_column_types[0]); i++)
  {
369
    protocol->prepare_for_resend();
370
    protocol->store(sys_column_types[i].type, system_charset_info);
371
    protocol->store((ulonglong) sys_column_types[i].size);
372 373
    protocol->store(sys_column_types[i].min_value, system_charset_info);
    protocol->store(sys_column_types[i].max_value, system_charset_info);
374 375
    protocol->store_short((longlong) sys_column_types[i].precision);
    protocol->store_short((longlong) sys_column_types[i].scale);
376 377 378 379 380 381 382 383
    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);
384
    if (protocol->write())
385 386
      DBUG_RETURN(-1);
  }
387
  send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
388 389 390 391 392 393
  DBUG_RETURN(0);
}


static int
mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
394
                 const char *wild, bool dir)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
395 396 397 398 399 400 401 402 403
{
  uint i;
  char *ext;
  MY_DIR *dirp;
  FILEINFO *file;
  uint col_access=thd->col_access;
  TABLE_LIST table_list;
  DBUG_ENTER("mysql_find_files");

404 405
  if (wild && !wild[0])
    wild=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
406 407 408 409 410
  bzero((char*) &table_list,sizeof(table_list));

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

411
  for (i=0 ; i < (uint) dirp->number_off_files  ; i++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
412 413 414
  {
    file=dirp->dir_entry+i;
    if (dir)
415
    {                                           /* Return databases */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
416 417 418
#ifdef USE_SYMDIR
      char *ext;
      if (my_use_symdir && !strcmp(ext=fn_ext(file->name), ".sym"))
419
        *ext=0;                                 /* Remove extension */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
420 421 422
      else
#endif
      {
423
        if (file->name[0] == '.' || !MY_S_ISDIR(file->mystat.st_mode) ||
424
            (wild && wild_compare(file->name,wild)))
425
          continue;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
426 427 428 429
      }
    }
    else
    {
430
        // Return only .frm files which aren't temp files.
431
      if (my_strcasecmp(system_charset_info, ext=fn_ext(file->name),reg_ext) ||
432
          is_prefix(file->name,tmp_file_prefix))
433
        continue;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
434
      *ext=0;
435 436 437 438
      if (wild)
      {
	if (lower_case_table_names)
	{
439
	  if (wild_case_compare(system_charset_info,file->name,wild))
440 441 442 443 444
	    continue;
	}
	else if (wild_compare(file->name,wild))
	  continue;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
445 446 447 448 449 450 451
    }
    /* Don't show tables where we don't have any privileges */
    if (db && !(col_access & TABLE_ACLS))
    {
      table_list.db= (char*) db;
      table_list.real_name=file->name;
      table_list.grant.privilege=col_access;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
452
      if (check_grant(thd,TABLE_ACLS,&table_list,1,1))
453
        continue;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
454
    }
455
    if (files->push_back(thd->strdup(file->name)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
456 457 458 459 460 461 462 463 464 465
    {
      my_dirend(dirp);
      DBUG_RETURN(-1);
    }
  }
  DBUG_PRINT("info",("found: %d files", files->elements));
  my_dirend(dirp);
  DBUG_RETURN(0);
}

466

bk@work.mysql.com's avatar
bk@work.mysql.com committed
467
/***************************************************************************
468
 Extended version of mysqld_show_tables
bk@work.mysql.com's avatar
bk@work.mysql.com committed
469 470 471 472 473 474 475 476 477 478
***************************************************************************/

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;
479 480
  Protocol *protocol= thd->protocol;
  TIME time;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509
  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));
  field_list.push_back(item=new Item_empty_string("Type",10));
  item->maybe_null=1;
  field_list.push_back(item=new Item_empty_string("Row_format",10));
  item->maybe_null=1;
  field_list.push_back(item=new Item_int("Rows",(longlong) 1,21));
  item->maybe_null=1;
  field_list.push_back(item=new Item_int("Avg_row_length",(int32) 0,21));
  item->maybe_null=1;
  field_list.push_back(item=new Item_int("Data_length",(longlong) 1,21));
  item->maybe_null=1;
  field_list.push_back(item=new Item_int("Max_data_length",(longlong) 1,21));
  item->maybe_null=1;
  field_list.push_back(item=new Item_int("Index_length",(longlong) 1,21));
  item->maybe_null=1;
  field_list.push_back(item=new Item_int("Data_free",(longlong) 1,21));
  item->maybe_null=1;
  field_list.push_back(item=new Item_int("Auto_increment",(longlong) 1,21));
  item->maybe_null=1;
  field_list.push_back(item=new Item_datetime("Create_time"));
  item->maybe_null=1;
  field_list.push_back(item=new Item_datetime("Update_time"));
  item->maybe_null=1;
  field_list.push_back(item=new Item_datetime("Check_time"));
  item->maybe_null=1;
510 511
  field_list.push_back(item=new Item_empty_string("Charset",32));
  item->maybe_null=1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
512 513 514
  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));
515
  item->maybe_null=1;
516
  if (protocol->send_fields(&field_list,1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
517 518 519 520
    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
521
  List_iterator_fast<char> it(files);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
522 523 524 525
  while ((file_name=it++))
  {
    TABLE_LIST table_list;
    bzero((char*) &table_list,sizeof(table_list));
526
    protocol->prepare_for_resend();
527
    protocol->store(file_name, system_charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
528
    table_list.db=(char*) db;
529
    table_list.real_name= table_list.alias= file_name;
530
    if (lower_case_table_names)
531
      my_casedn_str(files_charset_info, file_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
532 533
    if (!(table = open_ltable(thd, &table_list, TL_READ)))
    {
534
      for (uint i=2 ; i < field_list.elements ; i++)
535
        protocol->store_null();
536
      // Send error to Comment field
537
      protocol->store(thd->net.last_error, system_charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
538 539 540 541 542
      thd->net.last_error[0]=0;
    }
    else
    {
      struct tm tm_tmp;
543
      const char *str;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
544 545
      handler *file=table->file;
      file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_NO_LOCK);
546
      protocol->store(file->table_type(), system_charset_info);
547 548 549 550
      str= ((table->db_options_in_use & HA_OPTION_COMPRESS_RECORD) ?
	    "Compressed" :
	    (table->db_options_in_use & HA_OPTION_PACK_RECORD) ?
	    "Dynamic" : "Fixed");
551
      protocol->store(str, system_charset_info);
552 553 554
      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
555
      if (file->max_data_file_length)
556
        protocol->store((ulonglong) file->max_data_file_length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
557
      else
558 559 560
        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
561 562
      if (table->found_next_number_field)
      {
563 564 565
        table->next_number_field=table->found_next_number_field;
        table->next_number_field->reset();
        file->update_auto_increment();
566
        protocol->store(table->next_number_field->val_int());
567
        table->next_number_field=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
568 569
      }
      else
570
        protocol->store_null();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
571
      if (!file->create_time)
572
        protocol->store_null();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
573 574
      else
      {
575
        localtime_r(&file->create_time,&tm_tmp);
576 577
	localtime_to_TIME(&time, &tm_tmp);
        protocol->store(&time);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
578 579
      }
      if (!file->update_time)
580
        protocol->store_null();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
581 582
      else
      {
583
        localtime_r(&file->update_time,&tm_tmp);
584 585
	localtime_to_TIME(&time, &tm_tmp);
        protocol->store(&time);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
586 587
      }
      if (!file->check_time)
588
        protocol->store_null();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
589 590
      else
      {
591
        localtime_r(&file->check_time,&tm_tmp);
592 593
	localtime_to_TIME(&time, &tm_tmp);
        protocol->store(&time);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
594
      }
595
      str= (table->table_charset ? table->table_charset->name : "default");
596
      protocol->store(str, system_charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
597
      {
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
        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)
624
          ptr=strxmov(ptr, " row_format=", ha_row_type[(uint) table->row_type],
625 626 627 628 629 630 631 632
                      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);
        }
633
        protocol->store(option_buff+1,
634 635
			(ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1)
			, system_charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
636
      }
637 638
      {
	char *comment=table->file->update_table_comment(table->comment);
639
	protocol->store(comment, system_charset_info);
640 641 642
	if (comment != table->comment)
	  my_free(comment,MYF(0));
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
643 644
      close_thread_tables(thd,0);
    }
645
    if (protocol->write())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
646 647
      DBUG_RETURN(-1);
  }
648
  send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
649 650 651 652 653
  DBUG_RETURN(0);
}


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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
657
int
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
658 659
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
660 661 662 663
{
  TABLE *table;
  handler *file;
  char tmp[MAX_FIELD_WIDTH];
664
  Item *item;
665
  Protocol *protocol= thd->protocol;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
666 667
  DBUG_ENTER("mysqld_show_fields");
  DBUG_PRINT("enter",("db: %s  table: %s",table_list->db,
668
                      table_list->real_name));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
669 670 671

  if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
  {
672
    send_error(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
673 674 675 676 677 678 679 680 681
    DBUG_RETURN(1);
  }
  file=table->file;
  file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
  (void) get_table_grant(thd, table_list);

  List<Item> field_list;
  field_list.push_back(new Item_empty_string("Field",NAME_LEN));
  field_list.push_back(new Item_empty_string("Type",40));
682
  field_list.push_back(new Item_empty_string("Collation",40));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
683 684
  field_list.push_back(new Item_empty_string("Null",1));
  field_list.push_back(new Item_empty_string("Key",3));
685 686
  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
687
  field_list.push_back(new Item_empty_string("Extra",20));
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
688
  if (verbose)
689
  {
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
690
    field_list.push_back(new Item_empty_string("Privileges",80));
691 692
    field_list.push_back(new Item_empty_string("Comment",255));
  }
693
        // Send first number of fields and records
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
694 695
  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
696
    DBUG_RETURN(1);
697
  restore_record(table,2);      // Get empty record
bk@work.mysql.com's avatar
bk@work.mysql.com committed
698 699

  Field **ptr,*field;
tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
700
  String *packet= &thd->packet;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
701 702
  for (ptr=table->field; (field= *ptr) ; ptr++)
  {
703 704
    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
705 706 707
    {
#ifdef NOT_USED
      if (thd->col_access & TABLE_ACLS ||
708 709
          ! check_grant_column(thd,table,field->field_name,
                               (uint) strlen(field->field_name),1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
710 711
#endif
      {
712 713
        byte *pos;
        uint flags=field->flags;
714
        String type(tmp,sizeof(tmp), system_charset_info);
715 716 717
        uint col_access;
        bool null_default_value=0;

718
	protocol->prepare_for_resend();
719
        protocol->store(field->field_name, system_charset_info);
720
        field->sql_type(type);
721 722
        protocol->store(type.ptr(), type.length(), system_charset_info);
	protocol->store(field->charset()->name, system_charset_info);
723 724 725 726

        pos=(byte*) ((flags & NOT_NULL_FLAG) &&
                     field->type() != FIELD_TYPE_TIMESTAMP ?
                     "" : "YES");
727
        protocol->store((const char*) pos, system_charset_info);
728 729 730
        pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
                     (field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
                     (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
731
        protocol->store((char*) pos, system_charset_info);
732 733 734 735 736 737

        if (field->type() == FIELD_TYPE_TIMESTAMP ||
            field->unireg_check == Field::NEXT_NUMBER)
          null_default_value=1;
        if (!null_default_value && !field->is_null())
        {                                               // Not null by default
738
          type.set(tmp,sizeof(tmp),system_charset_info);
739
          field->val_str(&type,&type);
740
          protocol->store(type.ptr(),type.length(),type.charset());
741 742
        }
        else if (field->maybe_null() || null_default_value)
743
          protocol->store_null();                       // Null as default
744
        else
745
          protocol->store("",0, system_charset_info);	// empty string
746 747 748 749

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

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
752 753
	if (verbose)
	{
754
	  /* Add grant options & comments */
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
755
	  end=tmp;
756
	  col_access= get_column_grant(thd,table_list,field) & COL_ACLS;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
757 758 759 760 761 762 763 764
	  for (uint bitnr=0; col_access ; col_access>>=1,bitnr++)
	  {
	    if (col_access & 1)
	    {
	      *end++=',';
	      end=strmov(end,grant_types.type_names[bitnr]);
	    }
	  }
765 766 767 768
	  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
769
	}
770
        if (protocol->write())
771
          DBUG_RETURN(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
772 773 774
      }
    }
  }
775
  send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
776 777 778
  DBUG_RETURN(0);
}

779

bk@work.mysql.com's avatar
bk@work.mysql.com committed
780 781 782 783
int
mysqld_show_create(THD *thd, TABLE_LIST *table_list)
{
  TABLE *table;
784 785 786
  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
787 788
  DBUG_ENTER("mysqld_show_create");
  DBUG_PRINT("enter",("db: %s  table: %s",table_list->db,
789
                      table_list->real_name));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
790

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
791
  /* Only one table for now */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
792 793
  if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
  {
794
    send_error(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
795 796 797 798 799
    DBUG_RETURN(1);
  }

  List<Item> field_list;
  field_list.push_back(new Item_empty_string("Table",NAME_LEN));
800
  field_list.push_back(new Item_empty_string("Create Table", MAX_BLOB_WIDTH));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
801

802 803 804
  if (protocol->send_fields(&field_list, 1))
    DBUG_RETURN(1);
  protocol->prepare_for_resend();
805
  protocol->store(table->table_name, system_charset_info);
806
  buffer.length(0);
807 808
  if (store_create_info(thd, table, &buffer))
    DBUG_RETURN(-1);
809
  protocol->store(buffer.ptr(), buffer.length(), buffer.charset());
810
  if (protocol->write())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
811
    DBUG_RETURN(1);
812
  send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
813 814 815 816
  DBUG_RETURN(0);
}


tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
817 818 819
int
mysqld_show_logs(THD *thd)
{
820 821
  List<Item> field_list;
  Protocol *protocol= thd->protocol;
tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
822 823 824 825 826 827
  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));

828
  if (protocol->send_fields(&field_list,1))
tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
829 830
    DBUG_RETURN(1);

831
#ifdef HAVE_BERKELEY_DB
832
  if (!berkeley_skip && berkeley_show_logs(protocol))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
833
    DBUG_RETURN(-1);
834
#endif
tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
835

836
  send_eof(thd);
tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
837 838 839 840
  DBUG_RETURN(0);
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
841 842 843 844
int
mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
{
  TABLE *table;
845
  Protocol *protocol= thd->protocol;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
846 847
  DBUG_ENTER("mysqld_show_keys");
  DBUG_PRINT("enter",("db: %s  table: %s",table_list->db,
848
                      table_list->real_name));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
849 850 851

  if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
  {
852
    send_error(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
853 854 855 856 857 858
    DBUG_RETURN(1);
  }

  List<Item> field_list;
  Item *item;
  field_list.push_back(new Item_empty_string("Table",NAME_LEN));
859
  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
860
  field_list.push_back(new Item_empty_string("Key_name",NAME_LEN));
861
  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
862 863 864
  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;
865
  field_list.push_back(item=new Item_int("Cardinality",0,21));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
866
  item->maybe_null=1;
867 868
  field_list.push_back(item=new Item_return_int("Sub_part",3,
						MYSQL_TYPE_TINY));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
869 870 871
  item->maybe_null=1;
  field_list.push_back(item=new Item_empty_string("Packed",10));
  item->maybe_null=1;
872 873
  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
874 875 876
  field_list.push_back(new Item_empty_string("Comment",255));
  item->maybe_null=1;

877
  if (protocol->send_fields(&field_list,1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
878 879
    DBUG_RETURN(1);

tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
880
  String *packet= &thd->packet;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
881 882 883 884 885
  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;
886
    const char *str;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
887 888
    for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
    {
889
      protocol->prepare_for_resend();
890
      protocol->store(table->table_name, system_charset_info);
891
      protocol->store_tiny((longlong) ((key_info->flags & HA_NOSAME) ? 0 :1));
892
      protocol->store(key_info->name, system_charset_info);
893 894 895
      protocol->store_tiny((longlong) (j+1));
      str=(key_part->field ? key_part->field->field_name :
	   "?unknown field?");
896
      protocol->store(str, system_charset_info);
897
      if (table->file->index_flags(i) & HA_READ_ORDER)
898
        protocol->store(((key_part->key_part_flag & HA_REVERSE_SORT) ?
899
			 "D" : "A"), 1, system_charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
900
      else
901
        protocol->store_null(); /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
902 903 904
      KEY *key=table->key_info+i;
      if (key->rec_per_key[j])
      {
905
        ha_rows records=(table->file->records / key->rec_per_key[j]);
906
        protocol->store((ulonglong) records);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
907 908
      }
      else
909
        protocol->store_null();
910 911

      /* Check if we have a key part that only uses part of the field */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
912
      if (!key_part->field ||
913 914
          key_part->length !=
          table->field[key_part->fieldnr-1]->key_length())
915
        protocol->store_tiny((longlong) key_part->length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
916
      else
917 918
        protocol->store_null();
      protocol->store_null();                   // No pack_information yet
919 920 921

      /* Null flag */
      uint flags= key_part->field ? key_part->field->flags : 0;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
922
      char *pos=(char*) ((flags & NOT_NULL_FLAG) ? "" : "YES");
923 924
      protocol->store((const char*) pos, system_charset_info);
      protocol->store(table->file->index_type(i), system_charset_info);
925
      /* Comment */
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
926
      protocol->store("", system_charset_info);
927
      if (protocol->write())
928
        DBUG_RETURN(1); /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
929 930
    }
  }
931
  send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
932 933 934 935 936
  DBUG_RETURN(0);
}


/****************************************************************************
937 938
  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
939 940 941 942 943 944 945 946 947 948 949
****************************************************************************/

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)))
  {
950
    send_error(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
951 952 953 954 955 956 957
    DBUG_VOID_RETURN;
  }
  List<Item> field_list;

  Field **ptr,*field;
  for (ptr=table->field ; (field= *ptr); ptr++)
  {
958 959
    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
960 961
      field_list.push_back(new Item_field(field));
  }
962
  restore_record(table,2);              // Get empty record
963
  if (thd->protocol->send_fields(&field_list,2))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
964
    DBUG_VOID_RETURN;
965
  net_flush(&thd->net);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
966 967 968
  DBUG_VOID_RETURN;
}

969

bk@work.mysql.com's avatar
bk@work.mysql.com committed
970 971 972
int
mysqld_dump_create_info(THD *thd, TABLE *table, int fd)
{
973 974
  Protocol *protocol= thd->protocol;
  String *packet= protocol->storage_packet();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
975 976
  DBUG_ENTER("mysqld_dump_create_info");
  DBUG_PRINT("enter",("table: %s",table->real_name));
977

978 979
  protocol->prepare_for_resend();
  if (store_create_info(thd, table, packet))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
980
    DBUG_RETURN(-1);
981

982 983
  //if (protocol->convert)
  //  protocol->convert->convert((char*) packet->ptr(), packet->length());
984
  if (fd < 0)
985
  {
986
    if (protocol->write())
987
      DBUG_RETURN(-1);
988
    net_flush(&thd->net);
989
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
990
  else
991
  {
992 993
    if (my_write(fd, (const byte*) packet->ptr(), packet->length(),
		 MYF(MY_WME)))
994 995
      DBUG_RETURN(-1);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
996 997
  DBUG_RETURN(0);
}
998

999

1000 1001 1002
static void
append_identifier(THD *thd, String *packet, const char *name)
{
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
  char qtype;
  if ((thd->variables.sql_mode & MODE_ANSI_QUOTES) ||
      (thd->variables.sql_mode & MODE_POSTGRESQL) ||
      (thd->variables.sql_mode & MODE_ORACLE) ||
      (thd->variables.sql_mode & MODE_MSSQL) ||
      (thd->variables.sql_mode & MODE_DB2) ||
      (thd->variables.sql_mode & MODE_SAPDB))
    qtype= '\"';
  else
    qtype= '`';

1014 1015
  if (thd->options & OPTION_QUOTE_SHOW_CREATE)
  {
1016
    packet->append(&qtype, 1);
1017
    packet->append(name, 0, system_charset_info);
1018
    packet->append(&qtype, 1);
1019 1020 1021
  }
  else
  {
1022
    packet->append(name, 0, system_charset_info);
1023 1024 1025
  }
}

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1026
#define LIST_PROCESS_HOST_LEN 64
1027

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1028
static int
1029
store_create_info(THD *thd, TABLE *table, String *packet)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1030
{
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
  my_bool foreign_db_mode=    ((thd->variables.sql_mode & MODE_POSTGRESQL) ||
			       (thd->variables.sql_mode & MODE_ORACLE) ||
			       (thd->variables.sql_mode & MODE_MSSQL) ||
			       (thd->variables.sql_mode & MODE_DB2) ||
			       (thd->variables.sql_mode & MODE_SAPDB));
  my_bool limited_mysql_mode= ((thd->variables.sql_mode & 
				MODE_NO_FIELD_OPTIONS) ||
			       (thd->variables.sql_mode & MODE_MYSQL323) ||
			       (thd->variables.sql_mode & MODE_MYSQL40));

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1041 1042 1043 1044
  DBUG_ENTER("store_create_info");
  DBUG_PRINT("enter",("table: %s",table->real_name));

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1046 1047
  List<Item> field_list;
  char tmp[MAX_FIELD_WIDTH];
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
1048
  String type(tmp, sizeof(tmp),&my_charset_bin);
1049 1050 1051 1052
  if (table->tmp_table)
    packet->append("CREATE TEMPORARY TABLE ", 23);
  else
    packet->append("CREATE TABLE ", 13);
1053
  append_identifier(thd,packet,table->real_name);
1054
  packet->append(" (\n", 3);
1055

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1056 1057 1058
  Field **ptr,*field;
  for (ptr=table->field ; (field= *ptr); ptr++)
  {
1059
    if (ptr != table->field)
1060
      packet->append(",\n", 2);
1061

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1062
    uint flags = field->flags;
1063
    packet->append("  ", 2);
1064
    append_identifier(thd,packet,field->field_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1065 1066
    packet->append(' ');
    // check for surprises from the previous call to Field::sql_type()
1067
    if (type.ptr() != tmp)
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
1068
      type.set(tmp, sizeof(tmp),&my_charset_bin);
1069

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1070 1071
    field->sql_type(type);
    packet->append(type.ptr(),type.length());
1072

1073
    bool has_default = (field->type() != FIELD_TYPE_BLOB &&
1074 1075
			field->type() != FIELD_TYPE_TIMESTAMP &&
			field->unireg_check != Field::NEXT_NUMBER);
1076 1077 1078 1079 1080
    
    /* 
      For string types dump collation name only if 
      collation is not primary for the given charset
    */
1081
    if (!(field->charset()->state & MY_CS_PRIMARY) &&
1082
	!limited_mysql_mode && !foreign_db_mode)
1083
    {
1084
      packet->append(" collate ", 9);
1085 1086
      packet->append(field->charset()->name);
    }
1087 1088
    if (flags & NOT_NULL_FLAG)
      packet->append(" NOT NULL", 9);
1089

1090
    if (has_default)
1091 1092
    {
      packet->append(" default ", 9);
1093
      if (!field->is_null())
1094
      {                                             // Not null by default
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
1095
        type.set(tmp,sizeof(tmp),&my_charset_bin);
1096
        field->val_str(&type,&type);
1097
	if (type.length())
1098 1099 1100
          append_unescaped(packet, type.ptr(), type.length());
        else
	  packet->append("''",2);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1101
      }
1102
      else if (field->maybe_null())
1103 1104 1105 1106
        packet->append("NULL", 4);                    // Null as default
      else
        packet->append(tmp,0);
    }
1107

1108
    if (field->unireg_check == Field::NEXT_NUMBER && !foreign_db_mode)
1109 1110 1111 1112 1113 1114 1115
      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
1116 1117 1118 1119 1120
  }

  KEY *key_info=table->key_info;
  table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME);
  uint primary_key = table->primary_key;
1121

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1122 1123
  for (uint i=0 ; i < table->keys ; i++,key_info++)
  {
1124 1125
    KEY_PART_INFO *key_part= key_info->key_part;
    bool found_primary=0;
1126
    packet->append(",\n  ", 4);
1127

1128 1129 1130
    if (i == primary_key && !strcmp(key_info->name,"PRIMARY"))
    {
      found_primary=1;
1131
      packet->append("PRIMARY ", 8);
1132
    }
1133
    else if (key_info->flags & HA_NOSAME)
1134
      packet->append("UNIQUE ", 7);
1135
    else if (key_info->flags & HA_FULLTEXT)
1136
      packet->append("FULLTEXT ", 9);
1137 1138
    else if (key_info->flags & HA_SPATIAL)
      packet->append("SPATIAL ", 8);
1139
    packet->append("KEY ", 4);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1140

1141
    if (!found_primary)
1142
     append_identifier(thd, packet, key_info->name);
1143

1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155
    if (!(thd->variables.sql_mode & MODE_NO_KEY_OPTIONS) &&
	!limited_mysql_mode && !foreign_db_mode)
    {
      if (table->db_type == DB_TYPE_HEAP &&
	  key_info->algorithm == HA_KEY_ALG_BTREE)
	packet->append(" TYPE BTREE", 11);
      
      // +BAR: send USING only in non-default case: non-spatial rtree
      if ((key_info->algorithm == HA_KEY_ALG_RTREE) &&
	  !(key_info->flags & HA_SPATIAL))
	packet->append(" TYPE RTREE", 11);
    }
1156
    packet->append(" (", 2);
1157

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1158 1159
    for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
    {
1160
      if (j)
1161
        packet->append(',');
1162

1163
      if (key_part->field)
1164
        append_identifier(thd,packet,key_part->field->field_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1165
      if (!key_part->field ||
1166 1167 1168
          (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
1169
      {
1170 1171 1172 1173 1174
        char buff[64];
        buff[0] = '(';
        char* end=int10_to_str((long) key_part->length, buff + 1,10);
        *end++ = ')';
        packet->append(buff,(uint) (end-buff));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1175 1176 1177 1178
      }
    }
    packet->append(')');
  }
1179

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1180
  handler *file = table->file;
1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193

  /* Get possible foreign key definitions stored in InnoDB and append them
  to the CREATE TABLE statement */

  char* for_str = file->get_foreign_key_create_info();

  if (for_str) {
  	packet->append(for_str, strlen(for_str));

  	file->free_foreign_key_create_info(for_str);
  }

  packet->append("\n)", 2);
1194
  if (!(thd->variables.sql_mode & MODE_NO_TABLE_OPTIONS) && !foreign_db_mode)
1195
  {
1196 1197 1198 1199 1200
    packet->append(" TYPE=", 6);
    packet->append(file->table_type());
    char buff[128];
    char* p;
    
1201 1202 1203
    if (table->table_charset &&
	!(thd->variables.sql_mode & MODE_MYSQL323) &&
	!(thd->variables.sql_mode & MODE_MYSQL40))
1204
    {
1205 1206 1207 1208 1209 1210 1211
      packet->append(" CHARSET=");
      packet->append(table->table_charset->csname);
      if (!(table->table_charset->state & MY_CS_PRIMARY))
      {
	packet->append(" COLLATE=");
	packet->append(table->table_charset->name);
      }
1212
    }
1213

1214 1215 1216 1217 1218 1219
    if (table->min_rows)
    {
      packet->append(" MIN_ROWS=");
      p = longlong10_to_str(table->min_rows, buff, 10);
      packet->append(buff, (uint) (p - buff));
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1220

1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232
    if (table->max_rows)
    {
      packet->append(" MAX_ROWS=");
      p = longlong10_to_str(table->max_rows, buff, 10);
      packet->append(buff, (uint) (p - buff));
    }
    if (table->avg_row_length)
    {
      packet->append(" AVG_ROW_LENGTH=");
      p=longlong10_to_str(table->avg_row_length, buff,10);
      packet->append(buff, (uint) (p - buff));
    }
1233

1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259
    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)
    {
      char buff[100];
      sprintf(buff," RAID_TYPE=%s RAID_CHUNKS=%d RAID_CHUNKSIZE=%ld",
	      my_raid_type(file->raid_type), file->raid_chunks, file->raid_chunksize/RAID_BLOCK_SIZE);
      packet->append(buff);
    }
1260
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1261 1262 1263 1264 1265
  DBUG_RETURN(0);
}


/****************************************************************************
1266 1267
  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
1268 1269 1270 1271
****************************************************************************/

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

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1276 1277
  ulong thread_id;
  time_t start_time;
1278
  uint   command;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291
  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;
1292 1293
  ulong max_query_length= (verbose ? thd->variables.max_allowed_packet :
			   PROCESS_LIST_WIDTH);
1294
  Protocol *protocol= thd->protocol;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1295 1296
  DBUG_ENTER("mysqld_list_processes");

1297
  field_list.push_back(new Item_int("Id",0,11));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1298
  field_list.push_back(new Item_empty_string("User",16));
1299
  field_list.push_back(new Item_empty_string("Host",LIST_PROCESS_HOST_LEN));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1300 1301 1302
  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));
1303
  field_list.push_back(new Item_return_int("Time",7, FIELD_TYPE_LONG));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1304 1305 1306 1307
  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;
1308
  if (protocol->send_fields(&field_list,1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1309 1310 1311 1312 1313 1314 1315 1316 1317
    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++))
    {
1318
      struct st_my_thread_var *mysys_var;
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
1319
#ifndef EMBEDDED_LIBRARY
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1320
      if ((tmp->net.vio || tmp->system_thread) &&
1321
          (!user || (tmp->user && !strcmp(tmp->user,user))))
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
1322 1323 1324 1325
#else
      if (tmp->system_thread &&
          (!user || (tmp->user && !strcmp(tmp->user,user))))
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1326
      {
1327 1328 1329
        thread_info *thd_info=new thread_info;

        thd_info->thread_id=tmp->thread_id;
1330 1331 1332
        thd_info->user=thd->strdup(tmp->user ? tmp->user :
				   (tmp->system_thread ?
				    "system user" : "unauthenticated user"));
1333 1334 1335
	if (tmp->peer_port && (tmp->host || tmp->ip))
	{
	  if ((thd_info->host= thd->alloc(LIST_PROCESS_HOST_LEN+1)))
1336
	    my_snprintf((char *) thd_info->host, LIST_PROCESS_HOST_LEN,
1337
			"%s:%u", tmp->host_or_ip, tmp->peer_port);
1338 1339
	}
	else
1340
	  thd_info->host= thd->strdup(tmp->host_or_ip);
1341 1342 1343
        if ((thd_info->db=tmp->db))             // Safe test
          thd_info->db=thd->strdup(thd_info->db);
        thd_info->command=(int) tmp->command;
1344 1345
        if ((mysys_var= tmp->mysys_var))
          pthread_mutex_lock(&mysys_var->mutex);
1346
        thd_info->proc_info= (char*) (tmp->killed ? "Killed" : 0);
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
1347
#ifndef EMBEDDED_LIBRARY
1348 1349 1350 1351 1352 1353 1354 1355 1356 1357
        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
1358 1359 1360
#else
        thd_info->state_info= (char*)"Writing to net";
#endif
1361 1362
        if (mysys_var)
          pthread_mutex_unlock(&mysys_var->mutex);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1363 1364

#if !defined(DONT_USE_THR_ALARM) && ! defined(SCO)
1365 1366
        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
1367
#endif
1368 1369 1370
#ifdef EXTRA_DEBUG
        thd_info->start_time= tmp->time_after_lock;
#else
1371
        thd_info->start_time= tmp->start_time;
1372
#endif
1373 1374 1375
        thd_info->query=0;
        if (tmp->query)
        {
1376 1377
	  /* query_length is always set before tmp->query */
          uint length= min(max_query_length, tmp->query_length);
1378 1379 1380 1381
          thd_info->query=(char*) thd->memdup(tmp->query,length+1);
          thd_info->query[length]=0;
        }
        thread_infos.append(thd_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1382 1383 1384 1385 1386 1387
      }
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));

  thread_info *thd_info;
1388
  time_t now= time(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1389 1390
  while ((thd_info=thread_infos.get()))
  {
1391 1392
    protocol->prepare_for_resend();
    protocol->store((ulonglong) thd_info->thread_id);
1393 1394 1395
    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
1396
    if (thd_info->proc_info)
1397
      protocol->store(thd_info->proc_info, system_charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1398
    else
1399
      protocol->store(command_name[thd_info->command], system_charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1400
    if (thd_info->start_time)
1401
      protocol->store((uint32) (now - thd_info->start_time));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1402
    else
1403
      protocol->store_null();
1404 1405
    protocol->store(thd_info->state_info, system_charset_info);
    protocol->store(thd_info->query, system_charset_info);
1406
    if (protocol->write())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1407 1408
      break; /* purecov: inspected */
  }
1409
  send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1410 1411 1412 1413
  DBUG_VOID_RETURN;
}

/*****************************************************************************
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1414
  Status functions
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1415 1416
*****************************************************************************/

1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432
static bool write_collation(Protocol *protocol, CHARSET_INFO *cs)
{
  char flags[4];
  protocol->prepare_for_resend();
  protocol->store(cs->csname, system_charset_info);
  protocol->store(cs->name, system_charset_info);
  protocol->store_short((longlong) cs->number);
  flags[0]='\0';
  if (cs->state & MY_CS_PRIMARY)
    strcat(flags,"def");
  protocol->store(flags, system_charset_info);
  protocol->store_short((longlong) cs->strxfrm_multiply);
  return protocol->write();
}

int mysqld_show_collations(THD *thd, const char *wild)
1433 1434
{
  char buff[8192];
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
1435
  String packet2(buff,sizeof(buff),thd->charset());
1436
  List<Item> field_list;
1437
  CHARSET_INFO **cs;
1438
  Protocol *protocol= thd->protocol;
1439 1440
  char flags[64];

1441 1442
  DBUG_ENTER("mysqld_show_charsets");

1443 1444
  field_list.push_back(new Item_empty_string("Charset",30));
  field_list.push_back(new Item_empty_string("Collation",30));
1445
  field_list.push_back(new Item_return_int("Id",11, FIELD_TYPE_SHORT));
1446
  field_list.push_back(new Item_empty_string("Flags",30));
1447
  field_list.push_back(new Item_return_int("strx_maxlen",3, FIELD_TYPE_SHORT));
1448

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

1452
  for ( cs= all_charsets ; cs < all_charsets+255 ; cs++ )
1453
  {
1454 1455 1456 1457 1458 1459
    CHARSET_INFO **cl;
    for ( cl= all_charsets; cl < all_charsets+255 ;cl ++)
    {
      if (!cs[0] || !cl[0] || !my_charset_same(cs[0],cl[0]) || !(cs[0]->state & MY_CS_PRIMARY))
	continue;
      if (cs[0] && !(wild && wild[0] &&
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
1460
	  wild_case_compare(system_charset_info,cl[0]->name,wild)))
1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476
      {
        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);
1477
  protocol->store(cs->comment ? cs->comment : "", system_charset_info);
1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494
  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;
  char flags[64];

  DBUG_ENTER("mysqld_show_charsets");

  field_list.push_back(new Item_empty_string("Charset",30));
1495
  field_list.push_back(new Item_empty_string("Description",60));
1496 1497 1498 1499 1500 1501 1502 1503 1504 1505
  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++ )
  {
    if (cs[0] && (cs[0]->state & MY_CS_PRIMARY) && !(wild && wild[0] &&
       wild_case_compare(system_charset_info,cs[0]->name,wild)))
1506
    {
1507
      if (write_charset(protocol, cs[0]))
1508
	goto err;
1509 1510
    }
  }
1511
  send_eof(thd); 
1512 1513 1514 1515 1516
  DBUG_RETURN(0);
err:
  DBUG_RETURN(1);
}

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1517
  
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1518

1519
int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
1520
		enum enum_var_type value_type)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1521
{
1522
  char buff[1024];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1523
  List<Item> field_list;
1524
  Protocol *protocol= thd->protocol;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1525
  DBUG_ENTER("mysqld_show");
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1526

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1527 1528
  field_list.push_back(new Item_empty_string("Variable_name",30));
  field_list.push_back(new Item_empty_string("Value",256));
1529
  if (protocol->send_fields(&field_list,1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1530 1531
    DBUG_RETURN(1); /* purecov: inspected */

1532
  /* pthread_mutex_lock(&THR_LOCK_keycache); */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1533
  pthread_mutex_lock(&LOCK_status);
1534
  for (; variables->name; variables++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1535
  {
1536
    if (!(wild && wild[0] && wild_case_compare(system_charset_info,
1537
					       variables->name,wild)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1538
    {
1539
      protocol->prepare_for_resend();
1540
      protocol->store(variables->name, system_charset_info);
1541 1542
      SHOW_TYPE show_type=variables->type;
      char *value=variables->value;
1543 1544 1545
      const char *pos, *end;
      long nr;

1546 1547 1548
      if (show_type == SHOW_SYS)
      {
	show_type= ((sys_var*) value)->type();
1549
	value=     (char*) ((sys_var*) value)->value_ptr(thd, value_type);
1550 1551
      }

1552
      pos= end= buff;
1553
      switch (show_type) {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1554 1555
      case SHOW_LONG:
      case SHOW_LONG_CONST:
1556
	end= int10_to_str(*(long*) value, buff, 10);
1557 1558
        break;
      case SHOW_LONGLONG:
1559
	end= longlong10_to_str(*(longlong*) value, buff, 10);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1560
	break;
1561
      case SHOW_HA_ROWS:
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1562
        end= longlong10_to_str((longlong) *(ha_rows*) value, buff, 10);
1563
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1564
      case SHOW_BOOL:
1565
	end= strmov(buff, *(bool*) value ? "ON" : "OFF");
1566
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1567
      case SHOW_MY_BOOL:
1568
	end= strmov(buff, *(my_bool*) value ? "ON" : "OFF");
1569
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1570 1571
      case SHOW_INT_CONST:
      case SHOW_INT:
1572
	end= int10_to_str((long) *(uint32*) value, buff, 10);
1573
        break;
1574 1575
      case SHOW_HAVE:
      {
1576
	SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) value;
1577 1578
	pos= show_comp_option_name[(int) tmp];
	end= strend(pos);
1579 1580
        break;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1581
      case SHOW_CHAR:
1582 1583
	pos= value;
	end= strend(pos);
1584
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1585
      case SHOW_STARTTIME:
1586 1587
	nr= (long) (thd->query_start() - start_time);
	end= int10_to_str(nr, buff, 10);
1588
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1589
      case SHOW_QUESTION:
1590
	end= int10_to_str((long) thd->query_id, buff, 10);
1591
        break;
1592
#ifndef EMBEDDED_LIBRARY
1593
      case SHOW_RPL_STATUS:
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
1594
	end= strmov(buff, rpl_status_type[(int)rpl_status]);
1595
	break;
1596 1597 1598
      case SHOW_SLAVE_RUNNING:
      {
	LOCK_ACTIVE_MI;
1599 1600
	end= strmov(buff, (active_mi->slave_running &&
			   active_mi->rli.slave_running) ? "ON" : "OFF");
1601 1602 1603
	UNLOCK_ACTIVE_MI;
	break;
      }
1604
#endif /* EMBEDDED_LIBRARY */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1605
      case SHOW_OPENTABLES:
1606
	end= int10_to_str((long) cached_tables(), buff, 10);
1607
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1608
      case SHOW_CHAR_PTR:
1609
      {
1610 1611 1612
	if (!(pos= *(char**) value))
	  pos= "";
	end= strend(pos);
1613 1614
	break;
      }
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1615
#ifdef HAVE_OPENSSL
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1616
	/* First group - functions relying on CTX */
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1617
      case SHOW_SSL_CTX_SESS_ACCEPT:
1618 1619 1620 1621
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_accept(ssl_acceptor_fd->
						      ssl_context_)),
			  buff, 10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1622 1623
        break;
      case SHOW_SSL_CTX_SESS_ACCEPT_GOOD:
1624 1625 1626 1627
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_accept_good(ssl_acceptor_fd->
							   ssl_context_)),
			  buff, 10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1628
        break;
1629
      case SHOW_SSL_CTX_SESS_CONNECT_GOOD:
1630 1631 1632 1633
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_connect_good(ssl_acceptor_fd->
							    ssl_context_)),
			  buff, 10);
1634
        break;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1635
      case SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE:
1636 1637 1638
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context_)),
			  buff, 10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1639
        break;
1640
      case SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE:
1641 1642 1643
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd-> ssl_context_)),
			  buff, 10);
1644
        break;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1645
      case SHOW_SSL_CTX_SESS_CB_HITS:
1646 1647 1648 1649
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_cb_hits(ssl_acceptor_fd->
						       ssl_context_)),
			  buff, 10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1650
        break;
1651
      case SHOW_SSL_CTX_SESS_HITS:
1652 1653 1654 1655
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_hits(ssl_acceptor_fd->
						    ssl_context_)),
			  buff, 10);
1656 1657
        break;
      case SHOW_SSL_CTX_SESS_CACHE_FULL:
1658 1659 1660 1661
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_cache_full(ssl_acceptor_fd->
							  ssl_context_)),
			  buff, 10);
1662 1663
        break;
      case SHOW_SSL_CTX_SESS_MISSES:
1664 1665 1666 1667
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_misses(ssl_acceptor_fd->
						      ssl_context_)),
			  buff, 10);
1668 1669
        break;
      case SHOW_SSL_CTX_SESS_TIMEOUTS:
1670 1671 1672
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context_)),
			  buff,10);
1673
        break;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1674
      case SHOW_SSL_CTX_SESS_NUMBER:
1675 1676 1677
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context_)),
			  buff,10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1678
        break;
1679
      case SHOW_SSL_CTX_SESS_CONNECT:
1680 1681 1682
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context_)),
			  buff,10);
1683
        break;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1684
      case SHOW_SSL_CTX_SESS_GET_CACHE_SIZE:
1685 1686 1687
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context_)),
				  buff,10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1688 1689
        break;
      case SHOW_SSL_CTX_GET_VERIFY_MODE:
1690 1691 1692
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context_)),
			  buff,10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1693 1694
        break;
      case SHOW_SSL_CTX_GET_VERIFY_DEPTH:
1695 1696 1697
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
				  SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context_)),
			  buff,10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1698 1699
        break;
      case SHOW_SSL_CTX_GET_SESSION_CACHE_MODE:
1700 1701
	if (!ssl_acceptor_fd)
	{
1702 1703
	  pos= "NONE";
	  end= pos+4;
1704 1705
	  break;
	}
1706
	switch (SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context_))
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1707 1708
	{
          case SSL_SESS_CACHE_OFF:
1709
            pos= "OFF";
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1710 1711
	    break;
          case SSL_SESS_CACHE_CLIENT:
1712
            pos= "CLIENT";
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1713 1714
	    break;
          case SSL_SESS_CACHE_SERVER:
1715
            pos= "SERVER";
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1716 1717
	    break;
          case SSL_SESS_CACHE_BOTH:
1718
            pos= "BOTH";
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1719 1720
	    break;
          case SSL_SESS_CACHE_NO_AUTO_CLEAR:
1721
            pos= "NO_AUTO_CLEAR";
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1722 1723
	    break;
          case SSL_SESS_CACHE_NO_INTERNAL_LOOKUP:
1724
            pos= "NO_INTERNAL_LOOKUP";
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1725 1726
	    break;
	  default:
1727
            pos= "Unknown";
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1728 1729
	    break;
	}
1730
	end= strend(pos);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1731
        break;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1732 1733
	/* First group - functions relying on SSL */
      case SHOW_SSL_GET_VERSION:
1734 1735
	pos= thd->net.vio->ssl_ ? SSL_get_version(thd->net.vio->ssl_) : "";
	end= strend(pos);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1736 1737
        break;
      case SHOW_SSL_SESSION_REUSED:
1738 1739 1740
	end= int10_to_str((long) (thd->net.vio->ssl_ ?
				  SSL_session_reused(thd->net.vio->ssl_):
				  0), buff, 10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1741 1742
        break;
      case SHOW_SSL_GET_DEFAULT_TIMEOUT:
1743 1744 1745
	end= int10_to_str((long) (thd->net.vio->ssl_ ?
				  SSL_get_default_timeout(thd->net.vio->ssl_):
				  0), buff, 10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1746 1747
        break;
      case SHOW_SSL_GET_VERIFY_MODE:
1748 1749 1750
	end= int10_to_str((long) (thd->net.vio->ssl_ ?
				  SSL_get_verify_mode(thd->net.vio->ssl_):
				  0), buff, 10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1751 1752
        break;
      case SHOW_SSL_GET_VERIFY_DEPTH:
1753 1754 1755
	end= int10_to_str((long) (thd->net.vio->ssl_ ?
				  SSL_get_verify_depth(thd->net.vio->ssl_):
				  0), buff, 10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1756 1757
        break;
      case SHOW_SSL_GET_CIPHER:
1758 1759
	pos= thd->net.vio->ssl_ ? SSL_get_cipher(thd->net.vio->ssl_) : "";
	end= strend(pos);
1760
	break;
1761
      case SHOW_SSL_GET_CIPHER_LIST:
1762
	if (thd->net.vio->ssl_)
1763
	{
1764
	  char *to= buff;
1765
	  for (int i=0 ; i++ ;)
1766
	  {
1767
	    const char *p= SSL_get_cipher_list(thd->net.vio->ssl_,i);
1768 1769
	    if (p == NULL) 
	      break;
1770 1771
	    to= strmov(to, p);
	    *to++= ':';
1772
	  }
1773 1774 1775
	  if (to != buff)
	    to--;				// Remove last ':'
	  end= to;
1776
        }
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1777
        break;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1778 1779

#endif /* HAVE_OPENSSL */
1780 1781
      case SHOW_UNDEF:				// Show never happen
      case SHOW_SYS:
1782
	break;					// Return empty string
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
1783 1784
      default:
	break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1785
      }
1786
      if (protocol->store(pos, (uint32) (end - pos), system_charset_info) ||
1787
	  protocol->write())
1788
        goto err;                               /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1789 1790 1791
    }
  }
  pthread_mutex_unlock(&LOCK_status);
1792
  /* pthread_mutex_unlock(&THR_LOCK_keycache); */
1793
  send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1794 1795 1796 1797
  DBUG_RETURN(0);

 err:
  pthread_mutex_unlock(&LOCK_status);
1798
  /* pthread_mutex_unlock(&THR_LOCK_keycache); */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1799 1800 1801 1802
  DBUG_RETURN(1);
}

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