sql_show.cc 57.6 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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
30 31 32 33 34
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 **),
35 36
                               "grant_types",
                               grant_names};
bk@work.mysql.com's avatar
bk@work.mysql.com committed
37 38

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

static int
42 43
store_create_info(THD *thd, TABLE *table, String *packet);

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

45 46 47 48
/*
  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
49

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

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

68
  if (protocol->send_fields(&field_list,1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
69 70 71
    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
72
  List_iterator_fast<char> it(files);
73

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

92

93
/***************************************************************************
94
  List all open tables in a database
95 96
***************************************************************************/

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

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

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

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

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

131

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

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

172 173 174 175 176 177 178
/***************************************************************************
** List all table types supported 
***************************************************************************/

int mysqld_show_table_types(THD *thd)
{
  List<Item> field_list;
179
  Protocol *protocol= thd->protocol;
180 181 182 183
  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));
184
  field_list.push_back(new Item_empty_string("Comment",80));
185

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

189 190
  const char *default_type_name= 
    ha_get_table_type((enum db_type)thd->variables.table_type);
191

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

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

211

212
/***************************************************************************
213
 List all privileges supported
214 215
***************************************************************************/

216 217 218 219
struct show_privileges_st {
  const char *privilege;
  const char *context;
  const char *comment;
220 221
};

222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245

/*
  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}
};


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 302 303 304 305 306 307 308 309 310 311 312
  {"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;
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 360 361
  DBUG_RETURN(0);
}


static int
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 368 369 370 371
{
  uint i;
  char *ext;
  MY_DIR *dirp;
  FILEINFO *file;
  uint col_access=thd->col_access;
  TABLE_LIST table_list;
  DBUG_ENTER("mysql_find_files");

372 373
  if (wild && !wild[0])
    wild=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
374 375 376 377 378
  bzero((char*) &table_list,sizeof(table_list));

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

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

436

bk@work.mysql.com's avatar
bk@work.mysql.com committed
437
/***************************************************************************
438
 Extended version of mysqld_show_tables
bk@work.mysql.com's avatar
bk@work.mysql.com committed
439 440 441 442 443 444 445 446 447 448
***************************************************************************/

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;
449 450
  Protocol *protocol= thd->protocol;
  TIME time;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
  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;
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
480
  field_list.push_back(item=new Item_empty_string("Collation",32));
481
  item->maybe_null=1;
serg@serg.mylan's avatar
serg@serg.mylan committed
482 483
  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
484 485 486
  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));
487
  item->maybe_null=1;
488
  if (protocol->send_fields(&field_list,1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
489 490 491 492
    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
493
  List_iterator_fast<char> it(files);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
494 495 496 497
  while ((file_name=it++))
  {
    TABLE_LIST table_list;
    bzero((char*) &table_list,sizeof(table_list));
498
    protocol->prepare_for_resend();
499
    protocol->store(file_name, system_charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
500
    table_list.db=(char*) db;
501
    table_list.real_name= table_list.alias= file_name;
502
    if (lower_case_table_names)
503
      my_casedn_str(files_charset_info, file_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
504 505
    if (!(table = open_ltable(thd, &table_list, TL_READ)))
    {
506
      for (uint i=2 ; i < field_list.elements ; i++)
507
        protocol->store_null();
508
      // Send error to Comment field
509
      protocol->store(thd->net.last_error, system_charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
510 511 512 513 514
      thd->net.last_error[0]=0;
    }
    else
    {
      struct tm tm_tmp;
515
      const char *str;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
516 517
      handler *file=table->file;
      file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_NO_LOCK);
518
      protocol->store(file->table_type(), system_charset_info);
519 520 521 522
      str= ((table->db_options_in_use & HA_OPTION_COMPRESS_RECORD) ?
	    "Compressed" :
	    (table->db_options_in_use & HA_OPTION_PACK_RECORD) ?
	    "Dynamic" : "Fixed");
523
      protocol->store(str, system_charset_info);
524 525 526
      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
527
      if (file->max_data_file_length)
528
        protocol->store((ulonglong) file->max_data_file_length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
529
      else
530 531 532
        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
533 534
      if (table->found_next_number_field)
      {
535 536 537
        table->next_number_field=table->found_next_number_field;
        table->next_number_field->reset();
        file->update_auto_increment();
538
        protocol->store(table->next_number_field->val_int());
539
        table->next_number_field=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
540 541
      }
      else
542
        protocol->store_null();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
543
      if (!file->create_time)
544
        protocol->store_null();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
545 546
      else
      {
547
        localtime_r(&file->create_time,&tm_tmp);
548 549
	localtime_to_TIME(&time, &tm_tmp);
        protocol->store(&time);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
550 551
      }
      if (!file->update_time)
552
        protocol->store_null();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
553 554
      else
      {
555
        localtime_r(&file->update_time,&tm_tmp);
556 557
	localtime_to_TIME(&time, &tm_tmp);
        protocol->store(&time);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
558 559
      }
      if (!file->check_time)
560
        protocol->store_null();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
561 562
      else
      {
563
        localtime_r(&file->check_time,&tm_tmp);
564 565
	localtime_to_TIME(&time, &tm_tmp);
        protocol->store(&time);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
566
      }
567
      str= (table->table_charset ? table->table_charset->name : "default");
568
      protocol->store(str, system_charset_info);
serg@serg.mylan's avatar
serg@serg.mylan committed
569 570 571 572
      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
573
      {
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
        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)
600
          ptr=strxmov(ptr, " row_format=", ha_row_type[(uint) table->row_type],
601 602 603 604 605 606 607 608
                      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);
        }
609
        protocol->store(option_buff+1,
610 611
			(ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1)
			, system_charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
612
      }
613 614
      {
	char *comment=table->file->update_table_comment(table->comment);
615
	protocol->store(comment, system_charset_info);
616 617 618
	if (comment != table->comment)
	  my_free(comment,MYF(0));
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
619 620
      close_thread_tables(thd,0);
    }
621
    if (protocol->write())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
622 623
      DBUG_RETURN(-1);
  }
624
  send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
625 626 627 628 629
  DBUG_RETURN(0);
}


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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
633
int
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
634 635
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
636 637 638 639
{
  TABLE *table;
  handler *file;
  char tmp[MAX_FIELD_WIDTH];
640
  Item *item;
641
  Protocol *protocol= thd->protocol;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
642 643
  DBUG_ENTER("mysqld_show_fields");
  DBUG_PRINT("enter",("db: %s  table: %s",table_list->db,
644
                      table_list->real_name));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
645 646 647

  if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
  {
648
    send_error(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
649 650 651 652
    DBUG_RETURN(1);
  }
  file=table->file;
  file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
hf@deer.(none)'s avatar
hf@deer.(none) committed
653
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bk@work.mysql.com's avatar
bk@work.mysql.com committed
654
  (void) get_table_grant(thd, table_list);
hf@deer.(none)'s avatar
hf@deer.(none) committed
655
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
656 657 658
  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));
659 660
  if (verbose)
    field_list.push_back(new Item_empty_string("Collation",40));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
661 662
  field_list.push_back(new Item_empty_string("Null",1));
  field_list.push_back(new Item_empty_string("Key",3));
663 664
  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
665
  field_list.push_back(new Item_empty_string("Extra",20));
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
666
  if (verbose)
667
  {
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
668
    field_list.push_back(new Item_empty_string("Privileges",80));
669 670
    field_list.push_back(new Item_empty_string("Comment",255));
  }
671
        // Send first number of fields and records
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
672 673
  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
674
    DBUG_RETURN(1);
675
  restore_record(table,default_values);      // Get empty record
bk@work.mysql.com's avatar
bk@work.mysql.com committed
676 677 678 679

  Field **ptr,*field;
  for (ptr=table->field; (field= *ptr) ; ptr++)
  {
680 681
    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
682 683 684
    {
#ifdef NOT_USED
      if (thd->col_access & TABLE_ACLS ||
685 686
          ! 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
687 688
#endif
      {
689 690
        byte *pos;
        uint flags=field->flags;
691
        String type(tmp,sizeof(tmp), system_charset_info);
692 693 694
        uint col_access;
        bool null_default_value=0;

695
	protocol->prepare_for_resend();
696
        protocol->store(field->field_name, system_charset_info);
697
        field->sql_type(type);
698
        protocol->store(type.ptr(), type.length(), system_charset_info);
699 700
	if (verbose)
	  protocol->store(field->has_charset() ? field->charset()->name : "NULL",
701
			system_charset_info);
702 703 704
        pos=(byte*) ((flags & NOT_NULL_FLAG) &&
                     field->type() != FIELD_TYPE_TIMESTAMP ?
                     "" : "YES");
705
        protocol->store((const char*) pos, system_charset_info);
706 707 708
        pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
                     (field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
                     (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
709
        protocol->store((char*) pos, system_charset_info);
710 711 712 713 714 715

        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
716
          type.set(tmp,sizeof(tmp),system_charset_info);
717
          field->val_str(&type,&type);
718
          protocol->store(type.ptr(),type.length(),type.charset());
719 720
        }
        else if (field->maybe_null() || null_default_value)
721
          protocol->store_null();                       // Null as default
722
        else
723
          protocol->store("",0, system_charset_info);	// empty string
724 725 726 727

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

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
730 731
	if (verbose)
	{
732
	  /* Add grant options & comments */
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
733
	  end=tmp;
hf@deer.(none)'s avatar
hf@deer.(none) committed
734
#ifndef NO_EMBEDDED_ACCESS_CHECKS
735
	  col_access= get_column_grant(thd,table_list,field) & COL_ACLS;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
736 737 738 739 740 741 742 743
	  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
744 745 746
#else
	  end=strmov(end,"");
#endif
747 748 749 750
	  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
751
	}
752
        if (protocol->write())
753
          DBUG_RETURN(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
754 755 756
      }
    }
  }
757
  send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
758 759 760
  DBUG_RETURN(0);
}

761

bk@work.mysql.com's avatar
bk@work.mysql.com committed
762 763 764 765
int
mysqld_show_create(THD *thd, TABLE_LIST *table_list)
{
  TABLE *table;
766 767 768
  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
769 770
  DBUG_ENTER("mysqld_show_create");
  DBUG_PRINT("enter",("db: %s  table: %s",table_list->db,
771
                      table_list->real_name));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
772

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
773
  /* Only one table for now */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
774 775
  if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
  {
776
    send_error(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
777 778 779
    DBUG_RETURN(1);
  }

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
780
  if (store_create_info(thd, table, &buffer))
781 782
    DBUG_RETURN(-1);

bk@work.mysql.com's avatar
bk@work.mysql.com committed
783 784
  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
785
  // 1024 is for not to confuse old clients
786
  field_list.push_back(new Item_empty_string("Create Table",
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
787
					     max(buffer.length(),1024)));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
788

789 790 791
  if (protocol->send_fields(&field_list, 1))
    DBUG_RETURN(1);
  protocol->prepare_for_resend();
792
  protocol->store(table->table_name, system_charset_info);
793
  buffer.length(0);
794 795
  if (store_create_info(thd, table, &buffer))
    DBUG_RETURN(-1);
796
  protocol->store(buffer.ptr(), buffer.length(), buffer.charset());
797
  if (protocol->write())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
798
    DBUG_RETURN(1);
799
  send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
800 801 802 803
  DBUG_RETURN(0);
}


tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
804 805 806
int
mysqld_show_logs(THD *thd)
{
807 808
  List<Item> field_list;
  Protocol *protocol= thd->protocol;
tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
809 810 811 812 813 814
  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));

815
  if (protocol->send_fields(&field_list,1))
tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
816 817
    DBUG_RETURN(1);

818
#ifdef HAVE_BERKELEY_DB
819
  if (!berkeley_skip && berkeley_show_logs(protocol))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
820
    DBUG_RETURN(-1);
821
#endif
tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
822

823
  send_eof(thd);
tim@cane.mysql.fi's avatar
tim@cane.mysql.fi committed
824 825 826 827
  DBUG_RETURN(0);
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
828 829 830 831
int
mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
{
  TABLE *table;
832
  Protocol *protocol= thd->protocol;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
833 834
  DBUG_ENTER("mysqld_show_keys");
  DBUG_PRINT("enter",("db: %s  table: %s",table_list->db,
835
                      table_list->real_name));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
836 837 838

  if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
  {
839
    send_error(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
840 841 842 843 844 845
    DBUG_RETURN(1);
  }

  List<Item> field_list;
  Item *item;
  field_list.push_back(new Item_empty_string("Table",NAME_LEN));
846
  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
847
  field_list.push_back(new Item_empty_string("Key_name",NAME_LEN));
848
  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
849 850 851
  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;
852
  field_list.push_back(item=new Item_int("Cardinality",0,21));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
853
  item->maybe_null=1;
854 855
  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
856 857 858
  item->maybe_null=1;
  field_list.push_back(item=new Item_empty_string("Packed",10));
  item->maybe_null=1;
859 860
  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
861 862 863
  field_list.push_back(new Item_empty_string("Comment",255));
  item->maybe_null=1;

864
  if (protocol->send_fields(&field_list,1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
865 866 867 868 869 870 871
    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;
872
    const char *str;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
873 874
    for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
    {
875
      protocol->prepare_for_resend();
876
      protocol->store(table->table_name, system_charset_info);
877
      protocol->store_tiny((longlong) ((key_info->flags & HA_NOSAME) ? 0 :1));
878
      protocol->store(key_info->name, system_charset_info);
879 880 881
      protocol->store_tiny((longlong) (j+1));
      str=(key_part->field ? key_part->field->field_name :
	   "?unknown field?");
882
      protocol->store(str, system_charset_info);
883
      if (table->file->index_flags(i) & HA_READ_ORDER)
884
        protocol->store(((key_part->key_part_flag & HA_REVERSE_SORT) ?
885
			 "D" : "A"), 1, system_charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
886
      else
887
        protocol->store_null(); /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
888 889 890
      KEY *key=table->key_info+i;
      if (key->rec_per_key[j])
      {
891
        ha_rows records=(table->file->records / key->rec_per_key[j]);
892
        protocol->store((ulonglong) records);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
893 894
      }
      else
895
        protocol->store_null();
896 897

      /* 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
898
      if (!key_part->field ||
899 900
          key_part->length !=
          table->field[key_part->fieldnr-1]->key_length())
901
        protocol->store_tiny((longlong) key_part->length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
902
      else
903 904
        protocol->store_null();
      protocol->store_null();                   // No pack_information yet
905 906 907

      /* Null flag */
      uint flags= key_part->field ? key_part->field->flags : 0;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
908
      char *pos=(char*) ((flags & NOT_NULL_FLAG) ? "" : "YES");
909 910
      protocol->store((const char*) pos, system_charset_info);
      protocol->store(table->file->index_type(i), system_charset_info);
911
      /* Comment */
912
      if (!table->keys_in_use.is_set(i))
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
913
	protocol->store("disabled",8, system_charset_info);
914
      else
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
915
        protocol->store("", 0, system_charset_info);
916
      if (protocol->write())
917
        DBUG_RETURN(1); /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
918 919
    }
  }
920
  send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
921 922 923 924 925
  DBUG_RETURN(0);
}


/****************************************************************************
926 927
  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
928 929 930 931 932 933 934 935 936 937 938
****************************************************************************/

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)))
  {
939
    send_error(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
940 941 942 943 944 945 946
    DBUG_VOID_RETURN;
  }
  List<Item> field_list;

  Field **ptr,*field;
  for (ptr=table->field ; (field= *ptr); ptr++)
  {
947 948
    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
949 950
      field_list.push_back(new Item_field(field));
  }
951
  restore_record(table,default_values);              // Get empty record
952
  if (thd->protocol->send_fields(&field_list,2))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
953
    DBUG_VOID_RETURN;
954
  net_flush(&thd->net);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
955 956 957
  DBUG_VOID_RETURN;
}

958

bk@work.mysql.com's avatar
bk@work.mysql.com committed
959 960 961
int
mysqld_dump_create_info(THD *thd, TABLE *table, int fd)
{
962 963
  Protocol *protocol= thd->protocol;
  String *packet= protocol->storage_packet();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
964 965
  DBUG_ENTER("mysqld_dump_create_info");
  DBUG_PRINT("enter",("table: %s",table->real_name));
966

967 968
  protocol->prepare_for_resend();
  if (store_create_info(thd, table, packet))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
969
    DBUG_RETURN(-1);
970

971 972
  //if (protocol->convert)
  //  protocol->convert->convert((char*) packet->ptr(), packet->length());
973
  if (fd < 0)
974
  {
975
    if (protocol->write())
976
      DBUG_RETURN(-1);
977
    net_flush(&thd->net);
978
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
979
  else
980
  {
981 982
    if (my_write(fd, (const byte*) packet->ptr(), packet->length(),
		 MYF(MY_WME)))
983 984
      DBUG_RETURN(-1);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
985 986
  DBUG_RETURN(0);
}
987

988

989 990
void
append_identifier(THD *thd, String *packet, const char *name, uint length)
991
{
992
  char qtype;
993
  if (thd->variables.sql_mode & MODE_ANSI_QUOTES)
994 995 996 997
    qtype= '\"';
  else
    qtype= '`';

998 999
  if (thd->options & OPTION_QUOTE_SHOW_CREATE)
  {
1000
    packet->append(&qtype, 1);
1001
    packet->append(name, length, system_charset_info);
1002
    packet->append(&qtype, 1);
1003 1004 1005
  }
  else
  {
1006
    packet->append(name, length, system_charset_info);
1007 1008 1009
  }
}

1010 1011 1012 1013 1014 1015 1016

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

static void append_directory(THD *thd, String *packet, const char *dir_type,
			     const char *filename)
{
  uint length;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1017
  if (filename && !(thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE))
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028
  {
    length= dirname_length(filename);
    packet->append(' ');
    packet->append(dir_type);
    packet->append(" DIRECTORY='", 12);
    packet->append(filename, length);
    packet->append('\'');
  }
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1029
#define LIST_PROCESS_HOST_LEN 64
1030

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1031
static int
1032
store_create_info(THD *thd, TABLE *table, String *packet)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1033
{
1034 1035
  List<Item> field_list;
  char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], *end;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1036
  String type(tmp, sizeof(tmp),&my_charset_bin);
1037 1038 1039 1040 1041
  Field **ptr,*field;
  uint primary_key;
  KEY *key_info;
  handler *file= table->file;
  HA_CREATE_INFO create_info;
1042 1043 1044 1045
  my_bool foreign_db_mode=    (thd->variables.sql_mode & (MODE_POSTGRESQL |
							  MODE_ORACLE |
							  MODE_MSSQL |
							  MODE_DB2 |
1046
							  MODE_MAXDB |
1047 1048 1049 1050
							  MODE_ANSI)) != 0;
  my_bool limited_mysql_mode= (thd->variables.sql_mode &
			       (MODE_NO_FIELD_OPTIONS | MODE_MYSQL323 |
				MODE_MYSQL40)) != 0;
1051

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

1055
  restore_record(table,default_values); // Get empty record
1056

1057 1058 1059 1060
  if (table->tmp_table)
    packet->append("CREATE TEMPORARY TABLE ", 23);
  else
    packet->append("CREATE TABLE ", 13);
1061
  append_identifier(thd,packet, table->real_name, strlen(table->real_name));
1062
  packet->append(" (\n", 3);
1063

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1064 1065
  for (ptr=table->field ; (field= *ptr); ptr++)
  {
1066 1067 1068
    bool has_default;
    uint flags = field->flags;

1069
    if (ptr != table->field)
1070
      packet->append(",\n", 2);
1071

1072
    packet->append("  ", 2);
1073
    append_identifier(thd,packet,field->field_name, strlen(field->field_name));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1074 1075
    packet->append(' ');
    // check for surprises from the previous call to Field::sql_type()
1076
    if (type.ptr() != tmp)
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
1077
      type.set(tmp, sizeof(tmp),&my_charset_bin);
1078

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1079 1080
    field->sql_type(type);
    packet->append(type.ptr(),type.length());
1081

1082
    if (field->has_charset())
1083
    {
1084
      if (field->charset() == &my_charset_bin)
1085
        packet->append(" binary", 7);
1086 1087 1088 1089
      else if (!limited_mysql_mode && !foreign_db_mode)
      {
	if (field->charset() != table->table_charset)
	{
1090
	  packet->append(" character set ", 15);
1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102
	  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);
	}
      }
1103
    }
1104

1105 1106
    if (flags & NOT_NULL_FLAG)
      packet->append(" NOT NULL", 9);
1107

1108 1109 1110
    has_default= (field->type() != FIELD_TYPE_BLOB &&
		  field->type() != FIELD_TYPE_TIMESTAMP &&
		  field->unireg_check != Field::NEXT_NUMBER);
1111

1112
    if (has_default)
1113 1114
    {
      packet->append(" default ", 9);
1115
      if (!field->is_null())
1116
      {                                             // Not null by default
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
1117
        type.set(tmp,sizeof(tmp),&my_charset_bin);
1118
        field->val_str(&type,&type);
1119
	if (type.length())
1120 1121 1122
          append_unescaped(packet, type.ptr(), type.length());
        else
	  packet->append("''",2);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1123
      }
1124
      else if (field->maybe_null())
1125 1126 1127 1128
        packet->append("NULL", 4);                    // Null as default
      else
        packet->append(tmp,0);
    }
1129

1130
    if (field->unireg_check == Field::NEXT_NUMBER && !foreign_db_mode)
1131 1132 1133 1134 1135 1136 1137
      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
1138 1139
  }

1140 1141
  key_info= table->key_info;
  file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME);
1142
  bzero((char*) &create_info, sizeof(create_info));
1143 1144
  file->update_create_info(&create_info);
  primary_key= table->primary_key;
1145

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1146 1147
  for (uint i=0 ; i < table->keys ; i++,key_info++)
  {
1148 1149
    KEY_PART_INFO *key_part= key_info->key_part;
    bool found_primary=0;
1150
    packet->append(",\n  ", 4);
1151

1152 1153 1154
    if (i == primary_key && !strcmp(key_info->name,"PRIMARY"))
    {
      found_primary=1;
1155
      packet->append("PRIMARY ", 8);
1156
    }
1157
    else if (key_info->flags & HA_NOSAME)
1158
      packet->append("UNIQUE ", 7);
1159
    else if (key_info->flags & HA_FULLTEXT)
1160
      packet->append("FULLTEXT ", 9);
1161 1162
    else if (key_info->flags & HA_SPATIAL)
      packet->append("SPATIAL ", 8);
1163
    packet->append("KEY ", 4);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1164

1165
    if (!found_primary)
1166
     append_identifier(thd, packet, key_info->name, strlen(key_info->name));
1167

1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179
    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);
    }
1180
    packet->append(" (", 2);
1181

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1182 1183
    for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
    {
1184
      if (j)
1185
        packet->append(',');
1186

1187
      if (key_part->field)
1188 1189
        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
1190
      if (!key_part->field ||
1191 1192 1193
          (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
1194
      {
1195
        buff[0] = '(';
1196 1197 1198
        char* end=int10_to_str((long) key_part->length / 
			       key_part->field->charset()->mbmaxlen,
			       buff + 1,10);
1199 1200
        *end++ = ')';
        packet->append(buff,(uint) (end-buff));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1201 1202 1203 1204
      }
    }
    packet->append(')');
  }
1205

1206 1207 1208 1209
  /*
    Get possible foreign key definitions stored in InnoDB and append them
    to the CREATE TABLE statement
  */
1210

1211
  if ((for_str= file->get_foreign_key_create_info()))
1212 1213 1214
  {
    packet->append(for_str, strlen(for_str));
    file->free_foreign_key_create_info(for_str);
1215 1216 1217
  }

  packet->append("\n)", 2);
1218
  if (!(thd->variables.sql_mode & MODE_NO_TABLE_OPTIONS) && !foreign_db_mode)
1219
  {
1220 1221 1222
    packet->append(" TYPE=", 6);
    packet->append(file->table_type());
    
1223 1224 1225
    if (table->table_charset &&
	!(thd->variables.sql_mode & MODE_MYSQL323) &&
	!(thd->variables.sql_mode & MODE_MYSQL40))
1226
    {
1227
      packet->append(" DEFAULT CHARSET=", 17);
1228 1229 1230
      packet->append(table->table_charset->csname);
      if (!(table->table_charset->state & MY_CS_PRIMARY))
      {
1231
	packet->append(" COLLATE=", 9);
1232 1233
	packet->append(table->table_charset->name);
      }
1234
    }
1235

1236 1237
    if (table->min_rows)
    {
1238
      packet->append(" MIN_ROWS=", 10);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1239 1240
      end= longlong10_to_str(table->min_rows, buff, 10);
      packet->append(buff, (uint) (end- buff));
1241
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1242

1243 1244
    if (table->max_rows)
    {
1245
      packet->append(" MAX_ROWS=", 10);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1246 1247
      end= longlong10_to_str(table->max_rows, buff, 10);
      packet->append(buff, (uint) (end - buff));
1248
    }
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1249

1250 1251
    if (table->avg_row_length)
    {
1252
      packet->append(" AVG_ROW_LENGTH=", 16);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1253 1254
      end= longlong10_to_str(table->avg_row_length, buff,10);
      packet->append(buff, (uint) (end - buff));
1255
    }
1256

1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277
    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
1278 1279 1280 1281 1282 1283
      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);
1284
    }
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1285 1286
    append_directory(thd, packet, "DATA",  create_info.data_file_name);
    append_directory(thd, packet, "INDEX", create_info.index_file_name);
1287
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1288 1289 1290 1291 1292
  DBUG_RETURN(0);
}


/****************************************************************************
1293 1294
  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
1295 1296 1297 1298
****************************************************************************/

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

monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1303 1304
  ulong thread_id;
  time_t start_time;
1305
  uint   command;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318
  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;
1319 1320
  ulong max_query_length= (verbose ? thd->variables.max_allowed_packet :
			   PROCESS_LIST_WIDTH);
1321
  Protocol *protocol= thd->protocol;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1322 1323
  DBUG_ENTER("mysqld_list_processes");

1324
  field_list.push_back(new Item_int("Id",0,11));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1325
  field_list.push_back(new Item_empty_string("User",16));
1326
  field_list.push_back(new Item_empty_string("Host",LIST_PROCESS_HOST_LEN));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1327 1328 1329
  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));
1330
  field_list.push_back(new Item_return_int("Time",7, FIELD_TYPE_LONG));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1331 1332 1333 1334
  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;
1335
  if (protocol->send_fields(&field_list,1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1336 1337 1338 1339 1340 1341 1342 1343 1344
    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++))
    {
1345
      struct st_my_thread_var *mysys_var;
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
1346
#ifndef EMBEDDED_LIBRARY
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1347
      if ((tmp->net.vio || tmp->system_thread) &&
1348
          (!user || (tmp->user && !strcmp(tmp->user,user))))
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
1349 1350 1351 1352
#else
      if (tmp->system_thread &&
          (!user || (tmp->user && !strcmp(tmp->user,user))))
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1353
      {
1354 1355 1356
        thread_info *thd_info=new thread_info;

        thd_info->thread_id=tmp->thread_id;
1357 1358 1359
        thd_info->user=thd->strdup(tmp->user ? tmp->user :
				   (tmp->system_thread ?
				    "system user" : "unauthenticated user"));
1360
	if (tmp->peer_port && (tmp->host || tmp->ip) && thd->host_or_ip[0])
1361 1362
	{
	  if ((thd_info->host= thd->alloc(LIST_PROCESS_HOST_LEN+1)))
1363
	    my_snprintf((char *) thd_info->host, LIST_PROCESS_HOST_LEN,
1364
			"%s:%u", tmp->host_or_ip, tmp->peer_port);
1365 1366
	}
	else
1367
	  thd_info->host= thd->strdup(tmp->host_or_ip);
1368 1369 1370
        if ((thd_info->db=tmp->db))             // Safe test
          thd_info->db=thd->strdup(thd_info->db);
        thd_info->command=(int) tmp->command;
1371 1372
        if ((mysys_var= tmp->mysys_var))
          pthread_mutex_lock(&mysys_var->mutex);
1373
        thd_info->proc_info= (char*) (tmp->killed ? "Killed" : 0);
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
1374
#ifndef EMBEDDED_LIBRARY
1375 1376 1377 1378 1379 1380 1381 1382 1383 1384
        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
1385 1386 1387
#else
        thd_info->state_info= (char*)"Writing to net";
#endif
1388 1389
        if (mysys_var)
          pthread_mutex_unlock(&mysys_var->mutex);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1390 1391

#if !defined(DONT_USE_THR_ALARM) && ! defined(SCO)
1392 1393
        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
1394
#endif
1395 1396 1397
#ifdef EXTRA_DEBUG
        thd_info->start_time= tmp->time_after_lock;
#else
1398
        thd_info->start_time= tmp->start_time;
1399
#endif
1400 1401 1402
        thd_info->query=0;
        if (tmp->query)
        {
1403 1404
	  /* query_length is always set before tmp->query */
          uint length= min(max_query_length, tmp->query_length);
1405 1406 1407 1408
          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
1409 1410 1411 1412 1413 1414
      }
    }
  }
  VOID(pthread_mutex_unlock(&LOCK_thread_count));

  thread_info *thd_info;
1415
  time_t now= time(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1416 1417
  while ((thd_info=thread_infos.get()))
  {
1418 1419
    protocol->prepare_for_resend();
    protocol->store((ulonglong) thd_info->thread_id);
1420 1421 1422
    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
1423
    if (thd_info->proc_info)
1424
      protocol->store(thd_info->proc_info, system_charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1425
    else
1426
      protocol->store(command_name[thd_info->command], system_charset_info);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1427
    if (thd_info->start_time)
1428
      protocol->store((uint32) (now - thd_info->start_time));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1429
    else
1430
      protocol->store_null();
1431 1432
    protocol->store(thd_info->state_info, system_charset_info);
    protocol->store(thd_info->query, system_charset_info);
1433
    if (protocol->write())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1434 1435
      break; /* purecov: inspected */
  }
1436
  send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1437 1438 1439 1440
  DBUG_VOID_RETURN;
}

/*****************************************************************************
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1441
  Status functions
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1442 1443
*****************************************************************************/

1444 1445 1446 1447
static bool write_collation(Protocol *protocol, CHARSET_INFO *cs)
{
  protocol->prepare_for_resend();
  protocol->store(cs->name, system_charset_info);
1448
  protocol->store(cs->csname, system_charset_info);
1449
  protocol->store_short((longlong) cs->number);
1450 1451
  protocol->store((cs->state & MY_CS_PRIMARY) ? "Yes" : "",system_charset_info);
  protocol->store((cs->state & MY_CS_COMPILED)? "Yes" : "",system_charset_info);
1452 1453 1454 1455 1456
  protocol->store_short((longlong) cs->strxfrm_multiply);
  return protocol->write();
}

int mysqld_show_collations(THD *thd, const char *wild)
1457 1458
{
  char buff[8192];
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
1459
  String packet2(buff,sizeof(buff),thd->charset());
1460
  List<Item> field_list;
1461
  CHARSET_INFO **cs;
1462
  Protocol *protocol= thd->protocol;
1463

1464 1465
  DBUG_ENTER("mysqld_show_charsets");

1466
  field_list.push_back(new Item_empty_string("Collation",30));
1467
  field_list.push_back(new Item_empty_string("Charset",30));
1468
  field_list.push_back(new Item_return_int("Id",11, FIELD_TYPE_SHORT));
1469 1470
  field_list.push_back(new Item_empty_string("Default",30));
  field_list.push_back(new Item_empty_string("Compiled",30));
1471
  field_list.push_back(new Item_return_int("Sortlen",3, FIELD_TYPE_SHORT));
1472

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

1476
  for ( cs= all_charsets ; cs < all_charsets+255 ; cs++ )
1477
  {
1478
    CHARSET_INFO **cl;
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
1479 1480 1481
    if (!cs[0] || !(cs[0]->state & MY_CS_AVAILABLE) || 
        !(cs[0]->state & MY_CS_PRIMARY))
      continue;
1482 1483
    for ( cl= all_charsets; cl < all_charsets+255 ;cl ++)
    {
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
1484 1485
      if (!cl[0] || !(cl[0]->state & MY_CS_AVAILABLE) || 
          !my_charset_same(cs[0],cl[0]))
1486
	continue;
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
1487
      if (!(wild && wild[0] &&
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
1488
	  wild_case_compare(system_charset_info,cl[0]->name,wild)))
1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504
      {
        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);
1505
  protocol->store(cs->comment ? cs->comment : "", system_charset_info);
1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521
  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));
1522
  field_list.push_back(new Item_empty_string("Description",60));
1523 1524 1525 1526 1527 1528 1529 1530
  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
1531 1532 1533 1534
    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)))
1535
    {
1536
      if (write_charset(protocol, cs[0]))
1537
	goto err;
1538 1539
    }
  }
1540
  send_eof(thd); 
1541 1542 1543 1544 1545
  DBUG_RETURN(0);
err:
  DBUG_RETURN(1);
}

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1546
  
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1547

1548
int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
1549 1550
		enum enum_var_type value_type,
		pthread_mutex_t *mutex)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1551
{
1552
  char buff[1024];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1553
  List<Item> field_list;
1554
  Protocol *protocol= thd->protocol;
1555
  LEX_STRING null_lex_str;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1556
  DBUG_ENTER("mysqld_show");
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1557

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1558 1559
  field_list.push_back(new Item_empty_string("Variable_name",30));
  field_list.push_back(new Item_empty_string("Value",256));
1560
  if (protocol->send_fields(&field_list,1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1561
    DBUG_RETURN(1); /* purecov: inspected */
1562
  null_lex_str.str= 0;				// For sys_var->value_ptr()
1563
  null_lex_str.length= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1564

1565
  pthread_mutex_lock(mutex);
1566
  for (; variables->name; variables++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1567
  {
1568
    if (!(wild && wild[0] && wild_case_compare(system_charset_info,
1569
					       variables->name,wild)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1570
    {
1571
      protocol->prepare_for_resend();
1572
      protocol->store(variables->name, system_charset_info);
1573 1574
      SHOW_TYPE show_type=variables->type;
      char *value=variables->value;
1575 1576 1577
      const char *pos, *end;
      long nr;

1578 1579 1580
      if (show_type == SHOW_SYS)
      {
	show_type= ((sys_var*) value)->type();
1581 1582
	value=     (char*) ((sys_var*) value)->value_ptr(thd, value_type,
							 &null_lex_str);
1583 1584
      }

1585
      pos= end= buff;
1586
      switch (show_type) {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1587 1588
      case SHOW_LONG:
      case SHOW_LONG_CONST:
1589
	end= int10_to_str(*(long*) value, buff, 10);
1590 1591
        break;
      case SHOW_LONGLONG:
1592
	end= longlong10_to_str(*(longlong*) value, buff, 10);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1593
	break;
1594
      case SHOW_HA_ROWS:
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1595
        end= longlong10_to_str((longlong) *(ha_rows*) value, buff, 10);
1596
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1597
      case SHOW_BOOL:
1598
	end= strmov(buff, *(bool*) value ? "ON" : "OFF");
1599
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1600
      case SHOW_MY_BOOL:
1601
	end= strmov(buff, *(my_bool*) value ? "ON" : "OFF");
1602
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1603 1604
      case SHOW_INT_CONST:
      case SHOW_INT:
1605
	end= int10_to_str((long) *(uint32*) value, buff, 10);
1606
        break;
1607 1608
      case SHOW_HAVE:
      {
1609
	SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) value;
1610 1611
	pos= show_comp_option_name[(int) tmp];
	end= strend(pos);
1612 1613
        break;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1614
      case SHOW_CHAR:
gluh@gluh.mysql.r18.ru's avatar
gluh@gluh.mysql.r18.ru committed
1615 1616 1617 1618
      {
        if (!(pos= value))
          pos= "";
        end= strend(pos);
1619
        break;
gluh@gluh.mysql.r18.ru's avatar
gluh@gluh.mysql.r18.ru committed
1620
       }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1621
      case SHOW_STARTTIME:
1622 1623
	nr= (long) (thd->query_start() - start_time);
	end= int10_to_str(nr, buff, 10);
1624
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1625
      case SHOW_QUESTION:
1626
	end= int10_to_str((long) thd->query_id, buff, 10);
1627
        break;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1628
#ifdef HAVE_REPLICATION
1629
      case SHOW_RPL_STATUS:
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
1630
	end= strmov(buff, rpl_status_type[(int)rpl_status]);
1631
	break;
1632 1633 1634
      case SHOW_SLAVE_RUNNING:
      {
	LOCK_ACTIVE_MI;
1635 1636
	end= strmov(buff, (active_mi->slave_running &&
			   active_mi->rli.slave_running) ? "ON" : "OFF");
1637 1638 1639
	UNLOCK_ACTIVE_MI;
	break;
      }
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1640
#endif /* HAVE_REPLICATION */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1641
      case SHOW_OPENTABLES:
1642
	end= int10_to_str((long) cached_tables(), buff, 10);
1643
        break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1644
      case SHOW_CHAR_PTR:
1645
      {
1646 1647 1648 1649
        if (!(pos= *(char**) value))
          pos= "";
        end= strend(pos);
        break;
1650
      }
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1651
#ifdef HAVE_OPENSSL
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1652
	/* First group - functions relying on CTX */
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1653
      case SHOW_SSL_CTX_SESS_ACCEPT:
1654 1655
	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
1656
						      ssl_context)),
1657
			  buff, 10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1658 1659
        break;
      case SHOW_SSL_CTX_SESS_ACCEPT_GOOD:
1660 1661
	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
1662
							   ssl_context)),
1663
			  buff, 10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1664
        break;
1665
      case SHOW_SSL_CTX_SESS_CONNECT_GOOD:
1666 1667
	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
1668
							    ssl_context)),
1669
			  buff, 10);
1670
        break;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1671
      case SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE:
1672
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1673
				  SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context)),
1674
			  buff, 10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1675
        break;
1676
      case SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE:
1677
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1678
				  SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd-> ssl_context)),
1679
			  buff, 10);
1680
        break;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1681
      case SHOW_SSL_CTX_SESS_CB_HITS:
1682 1683
	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
1684
						       ssl_context)),
1685
			  buff, 10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1686
        break;
1687
      case SHOW_SSL_CTX_SESS_HITS:
1688 1689
	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
1690
						    ssl_context)),
1691
			  buff, 10);
1692 1693
        break;
      case SHOW_SSL_CTX_SESS_CACHE_FULL:
1694 1695
	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
1696
							  ssl_context)),
1697
			  buff, 10);
1698 1699
        break;
      case SHOW_SSL_CTX_SESS_MISSES:
1700 1701
	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
1702
						      ssl_context)),
1703
			  buff, 10);
1704 1705
        break;
      case SHOW_SSL_CTX_SESS_TIMEOUTS:
1706
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1707
				  SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context)),
1708
			  buff,10);
1709
        break;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1710
      case SHOW_SSL_CTX_SESS_NUMBER:
1711
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1712
				  SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context)),
1713
			  buff,10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1714
        break;
1715
      case SHOW_SSL_CTX_SESS_CONNECT:
1716
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1717
				  SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context)),
1718
			  buff,10);
1719
        break;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1720
      case SHOW_SSL_CTX_SESS_GET_CACHE_SIZE:
1721
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1722
				  SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context)),
1723
				  buff,10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1724 1725
        break;
      case SHOW_SSL_CTX_GET_VERIFY_MODE:
1726
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1727
				  SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context)),
1728
			  buff,10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1729 1730
        break;
      case SHOW_SSL_CTX_GET_VERIFY_DEPTH:
1731
	end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1732
				  SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context)),
1733
			  buff,10);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1734 1735
        break;
      case SHOW_SSL_CTX_GET_SESSION_CACHE_MODE:
1736 1737
	if (!ssl_acceptor_fd)
	{
1738 1739
	  pos= "NONE";
	  end= pos+4;
1740 1741
	  break;
	}
1742
	switch (SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context))
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1743 1744
	{
          case SSL_SESS_CACHE_OFF:
1745
            pos= "OFF";
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1746 1747
	    break;
          case SSL_SESS_CACHE_CLIENT:
1748
            pos= "CLIENT";
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1749 1750
	    break;
          case SSL_SESS_CACHE_SERVER:
1751
            pos= "SERVER";
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1752 1753
	    break;
          case SSL_SESS_CACHE_BOTH:
1754
            pos= "BOTH";
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1755 1756
	    break;
          case SSL_SESS_CACHE_NO_AUTO_CLEAR:
1757
            pos= "NO_AUTO_CLEAR";
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1758 1759
	    break;
          case SSL_SESS_CACHE_NO_INTERNAL_LOOKUP:
1760
            pos= "NO_INTERNAL_LOOKUP";
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1761 1762
	    break;
	  default:
1763
            pos= "Unknown";
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1764 1765
	    break;
	}
1766
	end= strend(pos);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1767
        break;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1768 1769
	/* First group - functions relying on SSL */
      case SHOW_SSL_GET_VERSION:
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1770 1771
	pos= (thd->net.vio->ssl_arg ?
	      SSL_get_version((SSL*) thd->net.vio->ssl_arg) : "");
1772
	end= strend(pos);
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1773 1774
        break;
      case SHOW_SSL_SESSION_REUSED:
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1775 1776 1777 1778 1779
	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
1780 1781
        break;
      case SHOW_SSL_GET_DEFAULT_TIMEOUT:
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1782 1783 1784 1785 1786
	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
1787 1788
        break;
      case SHOW_SSL_GET_VERIFY_MODE:
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1789 1790 1791 1792 1793
	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
1794 1795
        break;
      case SHOW_SSL_GET_VERIFY_DEPTH:
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1796 1797 1798 1799 1800
	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
1801 1802
        break;
      case SHOW_SSL_GET_CIPHER:
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1803 1804
	pos= (thd->net.vio->ssl_arg ?
	      SSL_get_cipher((SSL*) thd->net.vio->ssl_arg) : "" );
1805
	end= strend(pos);
1806
	break;
1807
      case SHOW_SSL_GET_CIPHER_LIST:
1808
	if (thd->net.vio->ssl_arg)
1809
	{
1810
	  char *to= buff;
1811
	  for (int i=0 ; i++ ;)
1812
	  {
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1813
	    const char *p= SSL_get_cipher_list((SSL*) thd->net.vio->ssl_arg,i);
1814 1815
	    if (p == NULL) 
	      break;
1816 1817
	    to= strmov(to, p);
	    *to++= ':';
1818
	  }
1819 1820 1821
	  if (to != buff)
	    to--;				// Remove last ':'
	  end= to;
1822
        }
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1823
        break;
tonu@x153.internalnet's avatar
tonu@x153.internalnet committed
1824 1825

#endif /* HAVE_OPENSSL */
1826 1827 1828 1829
      case SHOW_KEY_CACHE_LONG:
	value= (value-(char*) &dflt_key_cache_var)+ (char*) sql_key_cache;
	end= int10_to_str(*(long*) value, buff, 10);
        break;
1830 1831
      case SHOW_UNDEF:				// Show never happen
      case SHOW_SYS:
1832
	break;					// Return empty string
hf@deer.mysql.r18.ru's avatar
SCRUM  
hf@deer.mysql.r18.ru committed
1833 1834
      default:
	break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1835
      }
1836
      if (protocol->store(pos, (uint32) (end - pos), system_charset_info) ||
1837
	  protocol->write())
1838
        goto err;                               /* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1839 1840
    }
  }
1841
  pthread_mutex_unlock(mutex);
1842
  send_eof(thd);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1843 1844 1845
  DBUG_RETURN(0);

 err:
1846
  pthread_mutex_unlock(mutex);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1847 1848 1849 1850
  DBUG_RETURN(1);
}

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