mysqlshow.c 22.3 KB
Newer Older
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1 2
/* Copyright (C) 2000 MySQL AB

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.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
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.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
12

bk@work.mysql.com's avatar
bk@work.mysql.com committed
13 14 15 16 17 18
   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 */

/* Show databases, tables or columns */

19
#define SHOW_VERSION "9.5"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
20

21
#include "client_priv.h"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
22 23
#include <my_sys.h>
#include <m_string.h>
24 25
#include <mysql.h>
#include <mysqld_error.h>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
26 27
#include <signal.h>
#include <stdarg.h>
28
#include <sslopt-vars.h>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
29

30
static my_string host=0,opt_password=0,user=0;
31
static my_bool opt_show_keys= 0, opt_compress= 0, opt_count=0, opt_status= 0, 
32
  tty_password= 0, opt_table_type= 0;
33
static uint opt_verbose=0;
34
static char *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
35

36 37 38 39 40
#ifdef HAVE_SMEM 
static char *shared_memory_base_name=0;
#endif
static uint opt_protocol=0;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
static void get_options(int *argc,char ***argv);
static uint opt_mysql_port=0;
static int list_dbs(MYSQL *mysql,const char *wild);
static int list_tables(MYSQL *mysql,const char *db,const char *table);
static int list_table_status(MYSQL *mysql,const char *db,const char *table);
static int list_fields(MYSQL *mysql,const char *db,const char *table,
		       const char *field);
static void print_header(const char *header,uint head_length,...);
static void print_row(const char *header,uint head_length,...);
static void print_trailer(uint length,...);
static void print_res_header(MYSQL_RES *result);
static void print_res_top(MYSQL_RES *result);
static void print_res_row(MYSQL_RES *result,MYSQL_ROW cur);

static const char *load_default_groups[]= { "mysqlshow","client",0 };
static my_string opt_mysql_unix_port=0;

int main(int argc, char **argv)
{
  int error;
61
  my_bool first_argument_uses_wildcards=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
62 63 64 65 66 67 68
  char *wild;
  MYSQL mysql;
  MY_INIT(argv[0]);
  load_defaults("my",load_default_groups,&argc,&argv);
  get_options(&argc,&argv);

  wild=0;
69
  if (argc)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
70
  {
71 72 73
    char *pos= argv[argc-1], *to;
    for (to= pos ; *pos ; pos++, to++)
    {
74
      switch (*pos) {
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
      case '*':
	*pos= '%';
	first_argument_uses_wildcards= 1;
	break;
      case '?':
	*pos= '_';
	first_argument_uses_wildcards= 1;
	break;
      case '%':
      case '_':
	first_argument_uses_wildcards= 1;
	break;
      case '\\':
	pos++;
      default: break;
      }
      *to= *pos;
    }    
93
    *to= *pos; /* just to copy a '\0'  if '\\' was used */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
94
  }
95 96
  if (first_argument_uses_wildcards)
    wild= argv[--argc];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
97
  else if (argc == 3)			/* We only want one field */
98
    wild= argv[--argc];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
99 100 101 102 103 104 105 106 107 108 109 110

  if (argc > 2)
  {
    fprintf(stderr,"%s: Too many arguments\n",my_progname);
    exit(1);
  }
  mysql_init(&mysql);
  if (opt_compress)
    mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS);
#ifdef HAVE_OPENSSL
  if (opt_use_ssl)
    mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
111
		  opt_ssl_capath, opt_ssl_cipher);
112 113 114 115 116 117
#endif
  if (opt_protocol)
    mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
#ifdef HAVE_SMEM
  if (shared_memory_base_name)
    mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
118
#endif
119 120
  mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset);

121
  if (!(mysql_real_connect(&mysql,host,user,opt_password,
122
			   (first_argument_uses_wildcards) ? "" : argv[0],opt_mysql_port,opt_mysql_unix_port,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
123 124 125 126 127
			   0)))
  {
    fprintf(stderr,"%s: %s\n",my_progname,mysql_error(&mysql));
    exit(1);
  }
128
  mysql.reconnect= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
129 130 131 132 133 134 135 136 137 138 139 140 141 142

  switch (argc)
  {
  case 0:  error=list_dbs(&mysql,wild); break;
  case 1:
    if (opt_status)
      error=list_table_status(&mysql,argv[0],wild);
    else
      error=list_tables(&mysql,argv[0],wild);
    break;
  default:
    if (opt_status && ! wild)
      error=list_table_status(&mysql,argv[0],argv[1]);
    else
143 144
      error=list_fields(&mysql,argv[0],argv[1],wild);
    break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
145 146
  }
  mysql_close(&mysql);			/* Close & free connection */
147 148
  if (opt_password)
    my_free(opt_password,MYF(0));
149 150 151
#ifdef HAVE_SMEM
  my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR));
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
152 153 154 155 156
  my_end(0);
  exit(error ? 1 : 0);
  return 0;				/* No compiler warnings */
}

157
static struct my_option my_long_options[] =
bk@work.mysql.com's avatar
bk@work.mysql.com committed
158
{
159
  {"character-sets-dir", 'c', "Directory where character sets are.",
160 161
   (gptr*) &charsets_dir, (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0,
   0, 0, 0, 0, 0},
162 163 164
  {"default-character-set", OPT_DEFAULT_CHARSET,
   "Set the default character set.", (gptr*) &default_charset,
   (gptr*) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
165 166 167 168
  {"count", OPT_COUNT,
   "Show number of rows per table (may be slow for not MyISAM tables)",
   (gptr*) &opt_count, (gptr*) &opt_count, 0, GET_BOOL, NO_ARG, 0, 0, 0,
   0, 0, 0},
169
  {"compress", 'C', "Use compression in server/client protocol.",
170 171
   (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
   0, 0, 0},
172
  {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
173 174 175 176 177 178 179 180
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
  {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
   0, 0, 0, 0, 0, 0},
  {"host", 'h', "Connect to host.", (gptr*) &host, (gptr*) &host, 0, GET_STR,
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  {"status", 'i', "Shows a lot of extra information about each table.",
   (gptr*) &opt_status, (gptr*) &opt_status, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
   0, 0},
181
  {"keys", 'k', "Show keys for table.", (gptr*) &opt_show_keys,
182 183
   (gptr*) &opt_show_keys, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"password", 'p',
184
   "Password to use when connecting to server. If password is not given it's asked from the tty.",
185
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
186 187 188
  {"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port,
   (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0,
   0},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
189
#ifdef __WIN__
190 191
  {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
   NO_ARG, 0, 0, 0, 0, 0, 0},
192
#endif
193
  {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
194 195
   0, 0, 0, GET_STR,  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#ifdef HAVE_SMEM
196
  {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
197
   "Base name of shared memory.", (gptr*) &shared_memory_base_name, (gptr*) &shared_memory_base_name,
198
   0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
199
#endif
200 201 202
  {"show-table-type", 't', "Show table type column.",
   (gptr*) &opt_table_type, (gptr*) &opt_table_type, 0, GET_BOOL,
   NO_ARG, 0, 0, 0, 0, 0, 0},
203 204 205
  {"socket", 'S', "Socket file to use for connection.",
   (gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR,
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
206
#include <sslopt-longopts.h>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
207
#ifndef DONT_ALLOW_USER_CHANGE
208 209
  {"user", 'u', "User for login if not current user.", (gptr*) &user,
   (gptr*) &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
210
#endif
211 212 213 214 215 216
  {"verbose", 'v',
   "More verbose output; You can use this multiple times to get even more verbose output.",
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
   NO_ARG, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
217
};
218

219
  
monty@mysql.com's avatar
monty@mysql.com committed
220 221
#include <help_start.h>

bk@work.mysql.com's avatar
bk@work.mysql.com committed
222 223 224 225
static void print_version(void)
{
  printf("%s  Ver %s Distrib %s, for %s (%s)\n",my_progname,SHOW_VERSION,
	 MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
monty@mysql.com's avatar
monty@mysql.com committed
226
  NETWARE_SET_SCREEN_MODE(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
227 228
}

monty@mysql.com's avatar
monty@mysql.com committed
229

bk@work.mysql.com's avatar
bk@work.mysql.com committed
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
static void usage(void)
{
  print_version();
  puts("Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB");
  puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
  puts("Shows the structure of a mysql database (databases,tables and columns)\n");
  printf("Usage: %s [OPTIONS] [database [table [column]]]\n",my_progname);
  puts("\n\
If last argument contains a shell or SQL wildcard (*,?,% or _) then only\n\
what\'s matched by the wildcard is shown.\n\
If no database is given then all matching databases are shown.\n\
If no table is given then all matching tables in database are shown\n\
If no column is given then all matching columns and columntypes in table\n\
are shown");
  print_defaults("my",load_default_groups);
245 246
  my_print_help(my_long_options);
  my_print_variables(my_long_options);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
247 248
}

monty@mysql.com's avatar
monty@mysql.com committed
249 250
#include <help_end.h>

251 252 253
static my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
	       char *argument)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
254
{
255 256 257 258 259 260 261 262 263 264 265 266 267
  switch(optid) {
  case 'v':
    opt_verbose++;
    break;
  case 'p':
    if (argument)
    {
      char *start=argument;
      my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
      opt_password=my_strdup(argument,MYF(MY_FAE));
      while (*argument) *argument++= 'x';		/* Destroy argument */
      if (*start)
	start[1]=0;				/* Cut length of argument */
268
      tty_password= 0;
269 270 271 272 273
    }
    else
      tty_password=1;
    break;
  case 'W':
bk@work.mysql.com's avatar
bk@work.mysql.com committed
274
#ifdef __WIN__
275
    opt_protocol = MYSQL_PROTOCOL_PIPE;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
276
#endif
277
    break;
278 279
  case OPT_MYSQL_PROTOCOL:
  {
280
    if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0)
281 282 283 284 285 286
    {
      fprintf(stderr, "Unknown option to protocol: %s\n", argument);
      exit(1);
    }
    break;
  }
287 288 289
  case '#':
    DBUG_PUSH(argument ? argument : "d:t:o");
    break;
290
#include <sslopt-case.h>
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
  case 'V':
    print_version();
    exit(0);
    break;
  case '?':
  case 'I':					/* Info */
    usage();
    exit(0);
  }
  return 0;
}


static void
get_options(int *argc,char ***argv)
{
  int ho_error;

309
  if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
310
    exit(ho_error);
311
  
bk@work.mysql.com's avatar
bk@work.mysql.com committed
312
  if (tty_password)
313
    opt_password=get_tty_password(NullS);
314 315 316 317 318 319 320 321
  if (opt_count)
  {
    /*
      We need to set verbose to 2 as we need to change the output to include
      the number-of-rows column
    */
    opt_verbose= 2;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
322 323 324 325 326 327 328 329
  return;
}


static int
list_dbs(MYSQL *mysql,const char *wild)
{
  const char *header;
330 331 332 333
  uint length, counter = 0;
  ulong rowcount = 0L;
  char tables[NAME_LEN+1], rows[NAME_LEN+1];
  char query[255];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
334 335
  MYSQL_FIELD *field;
  MYSQL_RES *result;
336
  MYSQL_ROW row, rrow;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
337 338 339 340 341 342 343 344 345 346 347

  if (!(result=mysql_list_dbs(mysql,wild)))
  {
    fprintf(stderr,"%s: Cannot list databases: %s\n",my_progname,
	    mysql_error(mysql));
    return 1;
  }
  if (wild)
    printf("Wildcard: %s\n",wild);

  header="Databases";
348
  length=(uint) strlen(header);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
349 350 351 352
  field=mysql_fetch_field(result);
  if (length < field->max_length)
    length=field->max_length;

353 354 355 356 357 358 359
  if (!opt_verbose)
    print_header(header,length,NullS);
  else if (opt_verbose == 1)
    print_header(header,length,"Tables",6,NullS);
  else
    print_header(header,length,"Tables",6,"Total Rows",12,NullS);

bk@work.mysql.com's avatar
bk@work.mysql.com committed
360
  while ((row = mysql_fetch_row(result)))
361 362 363 364 365 366 367 368 369 370 371 372 373 374
  {
    counter++;

    if (opt_verbose)
    {
      if (!(mysql_select_db(mysql,row[0])))
      {
	MYSQL_RES *tresult = mysql_list_tables(mysql,(char*)NULL);
	if (mysql_affected_rows(mysql) > 0)
	{
	  sprintf(tables,"%6lu",(ulong) mysql_affected_rows(mysql));
	  rowcount = 0;
	  if (opt_verbose > 1)
	  {
375 376
            /* Print the count of tables and rows for each database */
            MYSQL_ROW trow;
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422
	    while ((trow = mysql_fetch_row(tresult)))
	    {
	      sprintf(query,"SELECT COUNT(*) FROM `%s`",trow[0]);
	      if (!(mysql_query(mysql,query)))
	      {
		MYSQL_RES *rresult;
		if ((rresult = mysql_store_result(mysql)))
		{
		  rrow = mysql_fetch_row(rresult);
		  rowcount += (ulong) strtoull(rrow[0], (char**) 0, 10);
		  mysql_free_result(rresult);
		}
	      }
	    }
	    sprintf(rows,"%12lu",rowcount);
	  }
	}
	else
	{
	  sprintf(tables,"%6d",0);
	  sprintf(rows,"%12d",0);
	}
	mysql_free_result(tresult);
      }
      else
      {
	strmov(tables,"N/A");
	strmov(rows,"N/A");
      }
    }

    if (!opt_verbose)
      print_row(row[0],length,0);
    else if (opt_verbose == 1)
      print_row(row[0],length,tables,6,NullS);
    else
      print_row(row[0],length,tables,6,rows,12,NullS);
  }

  print_trailer(length,
		(opt_verbose > 0 ? 6 : 0),
		(opt_verbose > 1 ? 12 :0),
		0);

  if (counter && opt_verbose)
    printf("%u row%s in set.\n",counter,(counter > 1) ? "s" : "");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
423 424 425 426 427 428 429 430 431
  mysql_free_result(result);
  return 0;
}


static int
list_tables(MYSQL *mysql,const char *db,const char *table)
{
  const char *header;
432
  uint head_length, counter = 0;
433
  char query[255], rows[NAME_LEN], fields[16];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
434 435
  MYSQL_FIELD *field;
  MYSQL_RES *result;
436
  MYSQL_ROW row, rrow;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
437 438 439 440 441 442 443

  if (mysql_select_db(mysql,db))
  {
    fprintf(stderr,"%s: Cannot connect to db %s: %s\n",my_progname,db,
	    mysql_error(mysql));
    return 1;
  }
444 445 446 447 448 449
  if (table)
  {
    /*
      We just hijack the 'rows' variable for a bit to store the escaped
      table name
    */
450
    mysql_real_escape_string(mysql, rows, table, (unsigned long)strlen(table));
451 452 453 454 455 456 457
    my_snprintf(query, sizeof(query), "show%s tables like '%s'",
                opt_table_type ? " full" : "", rows);
  }
  else
    my_snprintf(query, sizeof(query), "show%s tables",
                opt_table_type ? " full" : "");
  if (mysql_query(mysql, query) || !(result= mysql_store_result(mysql)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
458 459 460 461 462 463 464 465 466 467 468
  {
    fprintf(stderr,"%s: Cannot list tables in %s: %s\n",my_progname,db,
	    mysql_error(mysql));
    exit(1);
  }
  printf("Database: %s",db);
  if (table)
    printf("  Wildcard: %s",table);
  putchar('\n');

  header="Tables";
469
  head_length=(uint) strlen(header);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
470 471 472 473
  field=mysql_fetch_field(result);
  if (head_length < field->max_length)
    head_length=field->max_length;

474 475 476 477 478 479 480 481 482 483 484 485
  if (opt_table_type)
  {
    if (!opt_verbose)
      print_header(header,head_length,"table_type",10,NullS);
    else if (opt_verbose == 1)
      print_header(header,head_length,"table_type",10,"Columns",8,NullS);
    else
    {
      print_header(header,head_length,"table_type",10,"Columns",8,
		   "Total Rows",10,NullS);
    }
  }
486
  else
487 488 489 490 491 492 493 494
  {
    if (!opt_verbose)
      print_header(header,head_length,NullS);
    else if (opt_verbose == 1)
      print_header(header,head_length,"Columns",8,NullS);
    else
      print_header(header,head_length,"Columns",8, "Total Rows",10,NullS);
  }
495

bk@work.mysql.com's avatar
bk@work.mysql.com committed
496
  while ((row = mysql_fetch_row(result)))
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
  {
    counter++;
    if (opt_verbose > 0)
    {
      if (!(mysql_select_db(mysql,db)))
      {
	MYSQL_RES *rresult = mysql_list_fields(mysql,row[0],NULL);
	ulong rowcount=0L;
	if (!rresult)
	{
	  strmov(fields,"N/A");
	  strmov(rows,"N/A");
	}
	else
	{
	  sprintf(fields,"%8u",(uint) mysql_num_fields(rresult));
	  mysql_free_result(rresult);

	  if (opt_verbose > 1)
	  {
517
            /* Print the count of rows for each table */
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
	    sprintf(query,"SELECT COUNT(*) FROM `%s`",row[0]);
	    if (!(mysql_query(mysql,query)))
	    {
	      if ((rresult = mysql_store_result(mysql)))
	      {
		rrow = mysql_fetch_row(rresult);
		rowcount += (unsigned long) strtoull(rrow[0], (char**) 0, 10);
		mysql_free_result(rresult);
	      }
	      sprintf(rows,"%10lu",rowcount);
	    }
	    else
	      sprintf(rows,"%10d",0);
	  }
	}
      }
      else
      {
	strmov(fields,"N/A");
	strmov(rows,"N/A");
      }
    }
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
    if (opt_table_type)
    {
      if (!opt_verbose)
	print_row(row[0],head_length,row[1],10,NullS);
      else if (opt_verbose == 1)
	print_row(row[0],head_length,row[1],10,fields,8,NullS);
      else
	print_row(row[0],head_length,row[1],10,fields,8,rows,10,NullS);
    }
    else
    {
      if (!opt_verbose)
	print_row(row[0],head_length,NullS);
      else if (opt_verbose == 1)
	print_row(row[0],head_length, fields,8, NullS);
      else
	print_row(row[0],head_length, fields,8, rows,10, NullS);
    }
558 559 560
  }

  print_trailer(head_length,
561 562 563 564
		(opt_table_type ? 10 : opt_verbose > 0 ? 8 : 0),
		(opt_table_type ? (opt_verbose > 0 ? 8 : 0) 
		 : (opt_verbose > 1 ? 10 :0)),
		!opt_table_type ? 0 : opt_verbose > 1 ? 10 :0,
565 566 567 568 569
		0);

  if (counter && opt_verbose)
    printf("%u row%s in set.\n\n",counter,(counter > 1) ? "s" : "");

bk@work.mysql.com's avatar
bk@work.mysql.com committed
570 571 572 573
  mysql_free_result(result);
  return 0;
}

574

bk@work.mysql.com's avatar
bk@work.mysql.com committed
575 576 577 578 579 580 581
static int
list_table_status(MYSQL *mysql,const char *db,const char *wild)
{
  char query[1024],*end;
  MYSQL_RES *result;
  MYSQL_ROW row;

582
  end=strxmov(query,"show table status from `",db,"`",NullS);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607
  if (wild && wild[0])
    strxmov(end," like '",wild,"'",NullS);
  if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql)))
  {
    fprintf(stderr,"%s: Cannot get status for db: %s, table: %s: %s\n",
	    my_progname,db,wild ? wild : "",mysql_error(mysql));
    if (mysql_errno(mysql) == ER_PARSE_ERROR)
      fprintf(stderr,"This error probably means that your MySQL server doesn't support the\n\'show table status' command.\n");
    return 1;
  }

  printf("Database: %s",db);
  if (wild)
    printf("  Wildcard: %s",wild);
  putchar('\n');

  print_res_header(result);
  while ((row=mysql_fetch_row(result)))
    print_res_row(result,row);
  print_res_top(result);
  mysql_free_result(result);
  return 0;
}

/*
608 609
  list fields uses field interface as an example of how to parse
  a MYSQL FIELD
bk@work.mysql.com's avatar
bk@work.mysql.com committed
610 611 612 613 614 615 616 617 618
*/

static int
list_fields(MYSQL *mysql,const char *db,const char *table,
	    const char *wild)
{
  char query[1024],*end;
  MYSQL_RES *result;
  MYSQL_ROW row;
619
  ulong rows;
620
  LINT_INIT(rows);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
621 622 623 624 625 626 627

  if (mysql_select_db(mysql,db))
  {
    fprintf(stderr,"%s: Cannot connect to db: %s: %s\n",my_progname,db,
	    mysql_error(mysql));
    return 1;
  }
628 629

  if (opt_count)
630
  {
631 632 633 634 635 636 637 638 639 640
    sprintf(query,"select count(*) from `%s`", table);
    if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql)))
    {
      fprintf(stderr,"%s: Cannot get record count for db: %s, table: %s: %s\n",
              my_progname,db,table,mysql_error(mysql));
      return 1;
    }
    row= mysql_fetch_row(result);
    rows= (ulong) strtoull(row[0], (char**) 0, 10);
    mysql_free_result(result);
641 642
  }

643
  end=strmov(strmov(strmov(query,"show /*!32332 FULL */ columns from `"),table),"`");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
644 645 646 647 648 649 650 651 652
  if (wild && wild[0])
    strxmov(end," like '",wild,"'",NullS);
  if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql)))
  {
    fprintf(stderr,"%s: Cannot list columns in db: %s, table: %s: %s\n",
	    my_progname,db,table,mysql_error(mysql));
    return 1;
  }

653 654 655
  printf("Database: %s  Table: %s", db, table);
  if (opt_count)
    printf("  Rows: %lu", rows);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
656 657 658 659 660 661 662 663 664 665
  if (wild && wild[0])
    printf("  Wildcard: %s",wild);
  putchar('\n');

  print_res_header(result);
  while ((row=mysql_fetch_row(result)))
    print_res_row(result,row);
  print_res_top(result);
  if (opt_show_keys)
  {
666
    end=strmov(strmov(strmov(query,"show keys from `"),table),"`");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688
    if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql)))
    {
      fprintf(stderr,"%s: Cannot list keys in db: %s, table: %s: %s\n",
	      my_progname,db,table,mysql_error(mysql));
      return 1;
    }
    if (mysql_num_rows(result))
    {
      print_res_header(result);
      while ((row=mysql_fetch_row(result)))
	print_res_row(result,row);
      print_res_top(result);
    }
    else
      puts("Table has no keys");
  }
  mysql_free_result(result);
  return 0;
}


/*****************************************************************************
689
 General functions to print a nice ascii-table from data
bk@work.mysql.com's avatar
bk@work.mysql.com committed
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
*****************************************************************************/

static void
print_header(const char *header,uint head_length,...)
{
  va_list args;
  uint length,i,str_length,pre_space;
  const char *field;

  va_start(args,head_length);
  putchar('+');
  field=header; length=head_length;
  for (;;)
  {
    for (i=0 ; i < length+2 ; i++)
      putchar('-');
    putchar('+');
    if (!(field=va_arg(args,my_string)))
      break;
    length=va_arg(args,uint);
  }
  va_end(args);
  putchar('\n');

  va_start(args,head_length);
  field=header; length=head_length;
  putchar('|');
  for (;;)
  {
719
    str_length=(uint) strlen(field);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768
    if (str_length > length)
      str_length=length+1;
    pre_space=(uint) (((int) length-(int) str_length)/2)+1;
    for (i=0 ; i < pre_space ; i++)
      putchar(' ');
    for (i = 0 ; i < str_length ; i++)
      putchar(field[i]);
    length=length+2-str_length-pre_space;
    for (i=0 ; i < length ; i++)
      putchar(' ');
    putchar('|');
    if (!(field=va_arg(args,my_string)))
      break;
    length=va_arg(args,uint);
  }
  va_end(args);
  putchar('\n');

  va_start(args,head_length);
  putchar('+');
  field=header; length=head_length;
  for (;;)
  {
    for (i=0 ; i < length+2 ; i++)
      putchar('-');
    putchar('+');
    if (!(field=va_arg(args,my_string)))
      break;
    length=va_arg(args,uint);
  }
  va_end(args);
  putchar('\n');
}


static void
print_row(const char *header,uint head_length,...)
{
  va_list args;
  const char *field;
  uint i,length,field_length;

  va_start(args,head_length);
  field=header; length=head_length;
  for (;;)
  {
    putchar('|');
    putchar(' ');
    fputs(field,stdout);
769
    field_length=(uint) strlen(field);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812
    for (i=field_length ; i <= length ; i++)
      putchar(' ');
    if (!(field=va_arg(args,my_string)))
      break;
    length=va_arg(args,uint);
  }
  va_end(args);
  putchar('|');
  putchar('\n');
}


static void
print_trailer(uint head_length,...)
{
  va_list args;
  uint length,i;

  va_start(args,head_length);
  length=head_length;
  putchar('+');
  for (;;)
  {
    for (i=0 ; i < length+2 ; i++)
      putchar('-');
    putchar('+');
    if (!(length=va_arg(args,uint)))
      break;
  }
  va_end(args);
  putchar('\n');
}


static void print_res_header(MYSQL_RES *result)
{
  MYSQL_FIELD *field;

  print_res_top(result);
  mysql_field_seek(result,0);
  putchar('|');
  while ((field = mysql_fetch_field(result)))
  {
813
    printf(" %-*s|",(int) field->max_length+1,field->name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
814 815 816 817 818 819 820 821 822 823 824 825 826 827 828
  }
  putchar('\n');
  print_res_top(result);
}


static void print_res_top(MYSQL_RES *result)
{
  uint i,length;
  MYSQL_FIELD *field;

  putchar('+');
  mysql_field_seek(result,0);
  while((field = mysql_fetch_field(result)))
  {
829
    if ((length=(uint) strlen(field->name)) > field->max_length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854
      field->max_length=length;
    else
      length=field->max_length;
    for (i=length+2 ; i--> 0 ; )
      putchar('-');
    putchar('+');
  }
  putchar('\n');
}


static void print_res_row(MYSQL_RES *result,MYSQL_ROW cur)
{
  uint i,length;
  MYSQL_FIELD *field;
  putchar('|');
  mysql_field_seek(result,0);
  for (i=0 ; i < mysql_num_fields(result); i++)
  {
    field = mysql_fetch_field(result);
    length=field->max_length;
    printf(" %-*s|",length+1,cur[i] ? (char*) cur[i] : "");
  }
  putchar('\n');
}