~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000-2006 MySQL AB
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
16
/* Show databases, tables or columns */
17
18
#define SHOW_VERSION "9.10"
19
20
#include "client_priv.h"
21
#include <my_sys.h>
22
#include <m_string.h>
23
#include <mysql.h>
24
#include <mysqld_error.h>
25
#include <signal.h>
26
#include <stdarg.h>
27
28
static char * host=0, *opt_password=0, *user=0;
29
static my_bool opt_show_keys= 0, opt_compress= 0, opt_count=0, opt_status= 0;
30
static my_bool tty_password= 0, opt_table_type= 0;
31
static my_bool debug_info_flag= 0, debug_check_flag= 0;
32
static uint my_end_arg= 0;
33
static uint opt_verbose=0;
34
static char *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME;
35
36
#ifdef HAVE_SMEM 
37
static char *shared_memory_base_name=0;
38
#endif
39
static uint opt_protocol=0;
40
41
static void get_options(int *argc,char ***argv);
42
static uint opt_mysql_port=0;
43
static int list_dbs(MYSQL *mysql,const char *wild);
44
static int list_tables(MYSQL *mysql,const char *db,const char *table);
45
static int list_table_status(MYSQL *mysql,const char *db,const char *table);
46
static int list_fields(MYSQL *mysql,const char *db,const char *table,
47
		       const char *field);
48
static void print_header(const char *header,uint head_length,...);
49
static void print_row(const char *header,uint head_length,...);
50
static void print_trailer(uint length,...);
51
static void print_res_header(MYSQL_RES *result);
52
static void print_res_top(MYSQL_RES *result);
53
static void print_res_row(MYSQL_RES *result,MYSQL_ROW cur);
54
55
static const char *load_default_groups[]= { "mysqlshow","client",0 };
56
static char * opt_mysql_unix_port=0;
57
58
int main(int argc, char **argv)
59
{
60
  int error;
61
  my_bool first_argument_uses_wildcards=0;
62
  char *wild;
63
  MYSQL mysql;
64
  MY_INIT(argv[0]);
65
  load_defaults("my",load_default_groups,&argc,&argv);
66
  get_options(&argc,&argv);
67
68
  wild=0;
69
  if (argc)
70
  {
71
    char *pos= argv[argc-1], *to;
72
    for (to= pos ; *pos ; pos++, to++)
73
    {
74
      switch (*pos) {
75
      case '*':
76
	*pos= '%';
77
	first_argument_uses_wildcards= 1;
78
	break;
79
      case '?':
80
	*pos= '_';
81
	first_argument_uses_wildcards= 1;
82
	break;
83
      case '%':
84
      case '_':
85
	first_argument_uses_wildcards= 1;
86
	break;
87
      case '\\':
88
	pos++;
89
      default: break;
90
      }
91
      *to= *pos;
92
    }    
93
    *to= *pos; /* just to copy a '\0'  if '\\' was used */
94
  }
95
  if (first_argument_uses_wildcards)
96
    wild= argv[--argc];
97
  else if (argc == 3)			/* We only want one field */
98
    wild= argv[--argc];
99
100
  if (argc > 2)
101
  {
102
    fprintf(stderr,"%s: Too many arguments\n",my_progname);
103
    exit(1);
104
  }
105
  mysql_init(&mysql);
106
  if (opt_compress)
107
    mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS);
108
#ifdef HAVE_OPENSSL
109
  if (opt_use_ssl)
110
    mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
111
		  opt_ssl_capath, opt_ssl_cipher);
112
  mysql_options(&mysql,MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
113
                (char*)&opt_ssl_verify_server_cert);
114
#endif
115
  if (opt_protocol)
116
    mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
117
#ifdef HAVE_SMEM
118
  if (shared_memory_base_name)
119
    mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
120
#endif
121
  mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset);
122
123
  if (!(mysql_real_connect(&mysql,host,user,opt_password,
124
			   (first_argument_uses_wildcards) ? "" :
125
                           argv[0],opt_mysql_port,opt_mysql_unix_port,
126
			   0)))
127
  {
128
    fprintf(stderr,"%s: %s\n",my_progname,mysql_error(&mysql));
129
    exit(1);
130
  }
131
  mysql.reconnect= 1;
132
133
  switch (argc) {
134
  case 0:  error=list_dbs(&mysql,wild); break;
135
  case 1:
136
    if (opt_status)
137
      error=list_table_status(&mysql,argv[0],wild);
138
    else
139
      error=list_tables(&mysql,argv[0],wild);
140
    break;
141
  default:
142
    if (opt_status && ! wild)
143
      error=list_table_status(&mysql,argv[0],argv[1]);
144
    else
145
      error=list_fields(&mysql,argv[0],argv[1],wild);
146
    break;
147
  }
148
  mysql_close(&mysql);			/* Close & free connection */
149
  if (opt_password)
150
    my_free(opt_password,MYF(0));
151
#ifdef HAVE_SMEM
152
  my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR));
153
#endif
154
  my_end(my_end_arg);
155
  exit(error ? 1 : 0);
156
  return 0;				/* No compiler warnings */
157
}
158
159
static struct my_option my_long_options[] =
160
{
161
#ifdef __NETWARE__
162
  {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.",
163
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
164
#endif
165
  {"character-sets-dir", 'c', "Directory where character sets are.",
166
   (uchar**) &charsets_dir, (uchar**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0,
167
   0, 0, 0, 0, 0},
168
  {"default-character-set", OPT_DEFAULT_CHARSET,
169
   "Set the default character set.", (uchar**) &default_charset,
170
   (uchar**) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
171
  {"count", OPT_COUNT,
172
   "Show number of rows per table (may be slow for not MyISAM tables)",
173
   (uchar**) &opt_count, (uchar**) &opt_count, 0, GET_BOOL, NO_ARG, 0, 0, 0,
174
   0, 0, 0},
175
  {"compress", 'C', "Use compression in server/client protocol.",
176
   (uchar**) &opt_compress, (uchar**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
177
   0, 0, 0},
178
  {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
179
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
180
  {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
181
   (uchar**) &debug_check_flag, (uchar**) &debug_check_flag, 0,
182
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
183
  {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
184
   (uchar**) &debug_info_flag, (uchar**) &debug_info_flag,
185
   0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
186
  {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
187
   0, 0, 0, 0, 0, 0},
188
  {"host", 'h', "Connect to host.", (uchar**) &host, (uchar**) &host, 0, GET_STR,
189
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
190
  {"status", 'i', "Shows a lot of extra information about each table.",
191
   (uchar**) &opt_status, (uchar**) &opt_status, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
192
   0, 0},
193
  {"keys", 'k', "Show keys for table.", (uchar**) &opt_show_keys,
194
   (uchar**) &opt_show_keys, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
195
  {"password", 'p',
196
   "Password to use when connecting to server. If password is not given it's asked from the tty.",
197
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
198
  {"port", 'P', "Port number to use for connection or 0 for default to, in "
199
   "order of preference, my.cnf, $MYSQL_TCP_PORT, "
200
#if MYSQL_PORT_DEFAULT == 0
201
   "/etc/services, "
202
#endif
203
   "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
204
   (uchar**) &opt_mysql_port,
205
   (uchar**) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0,
206
   0},
207
#ifdef __WIN__
208
  {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
209
   NO_ARG, 0, 0, 0, 0, 0, 0},
210
#endif
211
  {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
212
   0, 0, 0, GET_STR,  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
213
#ifdef HAVE_SMEM
214
  {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
215
   "Base name of shared memory.", (uchar**) &shared_memory_base_name, (uchar**) &shared_memory_base_name,
216
   0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
217
#endif
218
  {"show-table-type", 't', "Show table type column.",
219
   (uchar**) &opt_table_type, (uchar**) &opt_table_type, 0, GET_BOOL,
220
   NO_ARG, 0, 0, 0, 0, 0, 0},
221
  {"socket", 'S', "Socket file to use for connection.",
222
   (uchar**) &opt_mysql_unix_port, (uchar**) &opt_mysql_unix_port, 0, GET_STR,
223
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
224
#ifndef DONT_ALLOW_USER_CHANGE
225
  {"user", 'u', "User for login if not current user.", (uchar**) &user,
226
   (uchar**) &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
227
#endif
228
  {"verbose", 'v',
229
   "More verbose output; You can use this multiple times to get even more verbose output.",
230
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
231
  {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
232
   NO_ARG, 0, 0, 0, 0, 0, 0},
233
  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
234
};
235
236
  
237
#include <help_start.h>
238
239
static void print_version(void)
240
{
241
  printf("%s  Ver %s Distrib %s, for %s (%s)\n",my_progname,SHOW_VERSION,
242
	 MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
243
  NETWARE_SET_SCREEN_MODE(1);
244
}
245
246
247
static void usage(void)
248
{
249
  print_version();
250
  puts("Copyright (C) 2000-2006 MySQL AB");
251
  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");
252
  puts("Shows the structure of a mysql database (databases,tables and columns)\n");
253
  printf("Usage: %s [OPTIONS] [database [table [column]]]\n",my_progname);
254
  puts("\n\
255
If last argument contains a shell or SQL wildcard (*,?,% or _) then only\n\
256
what\'s matched by the wildcard is shown.\n\
257
If no database is given then all matching databases are shown.\n\
258
If no table is given then all matching tables in database are shown\n\
259
If no column is given then all matching columns and columntypes in table\n\
260
are shown");
261
  print_defaults("my",load_default_groups);
262
  my_print_help(my_long_options);
263
  my_print_variables(my_long_options);
264
}
265
266
#include <help_end.h>
267
268
static my_bool
269
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
270
	       char *argument)
271
{
272
  switch(optid) {
273
#ifdef __NETWARE__
274
  case OPT_AUTO_CLOSE:
275
    setscreenmode(SCR_AUTOCLOSE_ON_EXIT);
276
    break;
277
#endif
278
  case 'v':
279
    opt_verbose++;
280
    break;
281
  case 'p':
282
    if (argument)
283
    {
284
      char *start=argument;
285
      my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
286
      opt_password=my_strdup(argument,MYF(MY_FAE));
287
      while (*argument) *argument++= 'x';		/* Destroy argument */
288
      if (*start)
289
	start[1]=0;				/* Cut length of argument */
290
      tty_password= 0;
291
    }
292
    else
293
      tty_password=1;
294
    break;
295
  case OPT_MYSQL_PROTOCOL:
296
    opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib,
297
                                    opt->name);
298
    break;
299
  case '#':
300
    DBUG_PUSH(argument ? argument : "d:t:o");
301
    debug_check_flag= 1;
302
    break;
303
  case 'V':
304
    print_version();
305
    exit(0);
306
    break;
307
  case '?':
308
  case 'I':					/* Info */
309
    usage();
310
    exit(0);
311
  }
312
  return 0;
313
}
314
315
316
static void
317
get_options(int *argc,char ***argv)
318
{
319
  int ho_error;
320
321
  if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
322
    exit(ho_error);
323
  
324
  if (tty_password)
325
    opt_password=get_tty_password(NullS);
326
  if (opt_count)
327
  {
328
    /*
329
      We need to set verbose to 2 as we need to change the output to include
330
      the number-of-rows column
331
    */
332
    opt_verbose= 2;
333
  }
334
  if (debug_info_flag)
335
    my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
336
  if (debug_check_flag)
337
    my_end_arg= MY_CHECK_ERROR;
338
  return;
339
}
340
341
342
static int
343
list_dbs(MYSQL *mysql,const char *wild)
344
{
345
  const char *header;
346
  uint length, counter = 0;
347
  ulong rowcount = 0L;
348
  char tables[NAME_LEN+1], rows[NAME_LEN+1];
349
  char query[255];
350
  MYSQL_FIELD *field;
351
  MYSQL_RES *result;
352
  MYSQL_ROW row= NULL, rrow;
353
354
  if (!(result=mysql_list_dbs(mysql,wild)))
355
  {
356
    fprintf(stderr,"%s: Cannot list databases: %s\n",my_progname,
357
	    mysql_error(mysql));
358
    return 1;
359
  }
360
361
  /*
362
    If a wildcard was used, but there was only one row and it's name is an
363
    exact match, we'll assume they really wanted to see the contents of that
364
    database. This is because it is fairly common for database names to
365
    contain the underscore (_), like INFORMATION_SCHEMA.
366
   */
367
  if (wild && mysql_num_rows(result) == 1)
368
  {
369
    row= mysql_fetch_row(result);
370
    if (!my_strcasecmp(&my_charset_latin1, row[0], wild))
371
    {
372
      mysql_free_result(result);
373
      if (opt_status)
374
        return list_table_status(mysql, wild, NULL);
375
      else
376
        return list_tables(mysql, wild, NULL);
377
    }
378
  }
379
380
  if (wild)
381
    printf("Wildcard: %s\n",wild);
382
383
  header="Databases";
384
  length=(uint) strlen(header);
385
  field=mysql_fetch_field(result);
386
  if (length < field->max_length)
387
    length=field->max_length;
388
389
  if (!opt_verbose)
390
    print_header(header,length,NullS);
391
  else if (opt_verbose == 1)
392
    print_header(header,length,"Tables",6,NullS);
393
  else
394
    print_header(header,length,"Tables",6,"Total Rows",12,NullS);
395
396
  /* The first row may have already been read up above. */
397
  while (row || (row= mysql_fetch_row(result)))
398
  {
399
    counter++;
400
401
    if (opt_verbose)
402
    {
403
      if (!(mysql_select_db(mysql,row[0])))
404
      {
405
	MYSQL_RES *tresult = mysql_list_tables(mysql,(char*)NULL);
406
	if (mysql_affected_rows(mysql) > 0)
407
	{
408
	  sprintf(tables,"%6lu",(ulong) mysql_affected_rows(mysql));
409
	  rowcount = 0;
410
	  if (opt_verbose > 1)
411
	  {
412
            /* Print the count of tables and rows for each database */
413
            MYSQL_ROW trow;
414
	    while ((trow = mysql_fetch_row(tresult)))
415
	    {
416
	      sprintf(query,"SELECT COUNT(*) FROM `%s`",trow[0]);
417
	      if (!(mysql_query(mysql,query)))
418
	      {
419
		MYSQL_RES *rresult;
420
		if ((rresult = mysql_store_result(mysql)))
421
		{
422
		  rrow = mysql_fetch_row(rresult);
423
		  rowcount += (ulong) strtoull(rrow[0], (char**) 0, 10);
424
		  mysql_free_result(rresult);
425
		}
426
	      }
427
	    }
428
	    sprintf(rows,"%12lu",rowcount);
429
	  }
430
	}
431
	else
432
	{
433
	  sprintf(tables,"%6d",0);
434
	  sprintf(rows,"%12d",0);
435
	}
436
	mysql_free_result(tresult);
437
      }
438
      else
439
      {
440
	strmov(tables,"N/A");
441
	strmov(rows,"N/A");
442
      }
443
    }
444
445
    if (!opt_verbose)
446
      print_row(row[0],length,0);
447
    else if (opt_verbose == 1)
448
      print_row(row[0],length,tables,6,NullS);
449
    else
450
      print_row(row[0],length,tables,6,rows,12,NullS);
451
452
    row= NULL;
453
  }
454
455
  print_trailer(length,
456
		(opt_verbose > 0 ? 6 : 0),
457
		(opt_verbose > 1 ? 12 :0),
458
		0);
459
460
  if (counter && opt_verbose)
461
    printf("%u row%s in set.\n",counter,(counter > 1) ? "s" : "");
462
  mysql_free_result(result);
463
  return 0;
464
}
465
466
467
static int
468
list_tables(MYSQL *mysql,const char *db,const char *table)
469
{
470
  const char *header;
471
  uint head_length, counter = 0;
472
  char query[255], rows[NAME_LEN], fields[16];
473
  MYSQL_FIELD *field;
474
  MYSQL_RES *result;
475
  MYSQL_ROW row, rrow;
476
477
  if (mysql_select_db(mysql,db))
478
  {
479
    fprintf(stderr,"%s: Cannot connect to db %s: %s\n",my_progname,db,
480
	    mysql_error(mysql));
481
    return 1;
482
  }
483
  if (table)
484
  {
485
    /*
486
      We just hijack the 'rows' variable for a bit to store the escaped
487
      table name
488
    */
489
    mysql_real_escape_string(mysql, rows, table, (unsigned long)strlen(table));
490
    my_snprintf(query, sizeof(query), "show%s tables like '%s'",
491
                opt_table_type ? " full" : "", rows);
492
  }
493
  else
494
    my_snprintf(query, sizeof(query), "show%s tables",
495
                opt_table_type ? " full" : "");
496
  if (mysql_query(mysql, query) || !(result= mysql_store_result(mysql)))
497
  {
498
    fprintf(stderr,"%s: Cannot list tables in %s: %s\n",my_progname,db,
499
	    mysql_error(mysql));
500
    exit(1);
501
  }
502
  printf("Database: %s",db);
503
  if (table)
504
    printf("  Wildcard: %s",table);
505
  putchar('\n');
506
507
  header="Tables";
508
  head_length=(uint) strlen(header);
509
  field=mysql_fetch_field(result);
510
  if (head_length < field->max_length)
511
    head_length=field->max_length;
512
513
  if (opt_table_type)
514
  {
515
    if (!opt_verbose)
516
      print_header(header,head_length,"table_type",10,NullS);
517
    else if (opt_verbose == 1)
518
      print_header(header,head_length,"table_type",10,"Columns",8,NullS);
519
    else
520
    {
521
      print_header(header,head_length,"table_type",10,"Columns",8,
522
		   "Total Rows",10,NullS);
523
    }
524
  }
525
  else
526
  {
527
    if (!opt_verbose)
528
      print_header(header,head_length,NullS);
529
    else if (opt_verbose == 1)
530
      print_header(header,head_length,"Columns",8,NullS);
531
    else
532
      print_header(header,head_length,"Columns",8, "Total Rows",10,NullS);
533
  }
534
535
  while ((row = mysql_fetch_row(result)))
536
  {
537
    counter++;
538
    if (opt_verbose > 0)
539
    {
540
      if (!(mysql_select_db(mysql,db)))
541
      {
542
	MYSQL_RES *rresult = mysql_list_fields(mysql,row[0],NULL);
543
	ulong rowcount=0L;
544
	if (!rresult)
545
	{
546
	  strmov(fields,"N/A");
547
	  strmov(rows,"N/A");
548
	}
549
	else
550
	{
551
	  sprintf(fields,"%8u",(uint) mysql_num_fields(rresult));
552
	  mysql_free_result(rresult);
553
554
	  if (opt_verbose > 1)
555
	  {
556
            /* Print the count of rows for each table */
557
	    sprintf(query,"SELECT COUNT(*) FROM `%s`",row[0]);
558
	    if (!(mysql_query(mysql,query)))
559
	    {
560
	      if ((rresult = mysql_store_result(mysql)))
561
	      {
562
		rrow = mysql_fetch_row(rresult);
563
		rowcount += (unsigned long) strtoull(rrow[0], (char**) 0, 10);
564
		mysql_free_result(rresult);
565
	      }
566
	      sprintf(rows,"%10lu",rowcount);
567
	    }
568
	    else
569
	      sprintf(rows,"%10d",0);
570
	  }
571
	}
572
      }
573
      else
574
      {
575
	strmov(fields,"N/A");
576
	strmov(rows,"N/A");
577
      }
578
    }
579
    if (opt_table_type)
580
    {
581
      if (!opt_verbose)
582
	print_row(row[0],head_length,row[1],10,NullS);
583
      else if (opt_verbose == 1)
584
	print_row(row[0],head_length,row[1],10,fields,8,NullS);
585
      else
586
	print_row(row[0],head_length,row[1],10,fields,8,rows,10,NullS);
587
    }
588
    else
589
    {
590
      if (!opt_verbose)
591
	print_row(row[0],head_length,NullS);
592
      else if (opt_verbose == 1)
593
	print_row(row[0],head_length, fields,8, NullS);
594
      else
595
	print_row(row[0],head_length, fields,8, rows,10, NullS);
596
    }
597
  }
598
599
  print_trailer(head_length,
600
		(opt_table_type ? 10 : opt_verbose > 0 ? 8 : 0),
601
		(opt_table_type ? (opt_verbose > 0 ? 8 : 0) 
602
		 : (opt_verbose > 1 ? 10 :0)),
603
		!opt_table_type ? 0 : opt_verbose > 1 ? 10 :0,
604
		0);
605
606
  if (counter && opt_verbose)
607
    printf("%u row%s in set.\n\n",counter,(counter > 1) ? "s" : "");
608
609
  mysql_free_result(result);
610
  return 0;
611
}
612
613
614
static int
615
list_table_status(MYSQL *mysql,const char *db,const char *wild)
616
{
617
  char query[1024],*end;
618
  MYSQL_RES *result;
619
  MYSQL_ROW row;
620
621
  end=strxmov(query,"show table status from `",db,"`",NullS);
622
  if (wild && wild[0])
623
    strxmov(end," like '",wild,"'",NullS);
624
  if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql)))
625
  {
626
    fprintf(stderr,"%s: Cannot get status for db: %s, table: %s: %s\n",
627
	    my_progname,db,wild ? wild : "",mysql_error(mysql));
628
    if (mysql_errno(mysql) == ER_PARSE_ERROR)
629
      fprintf(stderr,"This error probably means that your MySQL server doesn't support the\n\'show table status' command.\n");
630
    return 1;
631
  }
632
633
  printf("Database: %s",db);
634
  if (wild)
635
    printf("  Wildcard: %s",wild);
636
  putchar('\n');
637
638
  print_res_header(result);
639
  while ((row=mysql_fetch_row(result)))
640
    print_res_row(result,row);
641
  print_res_top(result);
642
  mysql_free_result(result);
643
  return 0;
644
}
645
646
/*
647
  list fields uses field interface as an example of how to parse
648
  a MYSQL FIELD
649
*/
650
651
static int
652
list_fields(MYSQL *mysql,const char *db,const char *table,
653
	    const char *wild)
654
{
655
  char query[1024],*end;
656
  MYSQL_RES *result;
657
  MYSQL_ROW row;
658
  ulong rows= 0;
659
660
  if (mysql_select_db(mysql,db))
661
  {
662
    fprintf(stderr,"%s: Cannot connect to db: %s: %s\n",my_progname,db,
663
	    mysql_error(mysql));
664
    return 1;
665
  }
666
667
  if (opt_count)
668
  {
669
    sprintf(query,"select count(*) from `%s`", table);
670
    if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql)))
671
    {
672
      fprintf(stderr,"%s: Cannot get record count for db: %s, table: %s: %s\n",
673
              my_progname,db,table,mysql_error(mysql));
674
      return 1;
675
    }
676
    row= mysql_fetch_row(result);
677
    rows= (ulong) strtoull(row[0], (char**) 0, 10);
678
    mysql_free_result(result);
679
  }
680
681
  end=strmov(strmov(strmov(query,"show /*!32332 FULL */ columns from `"),table),"`");
682
  if (wild && wild[0])
683
    strxmov(end," like '",wild,"'",NullS);
684
  if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql)))
685
  {
686
    fprintf(stderr,"%s: Cannot list columns in db: %s, table: %s: %s\n",
687
	    my_progname,db,table,mysql_error(mysql));
688
    return 1;
689
  }
690
691
  printf("Database: %s  Table: %s", db, table);
692
  if (opt_count)
693
    printf("  Rows: %lu", rows);
694
  if (wild && wild[0])
695
    printf("  Wildcard: %s",wild);
696
  putchar('\n');
697
698
  print_res_header(result);
699
  while ((row=mysql_fetch_row(result)))
700
    print_res_row(result,row);
701
  print_res_top(result);
702
  if (opt_show_keys)
703
  {
704
    end=strmov(strmov(strmov(query,"show keys from `"),table),"`");
705
    if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql)))
706
    {
707
      fprintf(stderr,"%s: Cannot list keys in db: %s, table: %s: %s\n",
708
	      my_progname,db,table,mysql_error(mysql));
709
      return 1;
710
    }
711
    if (mysql_num_rows(result))
712
    {
713
      print_res_header(result);
714
      while ((row=mysql_fetch_row(result)))
715
	print_res_row(result,row);
716
      print_res_top(result);
717
    }
718
    else
719
      puts("Table has no keys");
720
  }
721
  mysql_free_result(result);
722
  return 0;
723
}
724
725
726
/*****************************************************************************
727
 General functions to print a nice ascii-table from data
728
*****************************************************************************/
729
730
static void
731
print_header(const char *header,uint head_length,...)
732
{
733
  va_list args;
734
  uint length,i,str_length,pre_space;
735
  const char *field;
736
737
  va_start(args,head_length);
738
  putchar('+');
739
  field=header; length=head_length;
740
  for (;;)
741
  {
742
    for (i=0 ; i < length+2 ; i++)
743
      putchar('-');
744
    putchar('+');
745
    if (!(field=va_arg(args,char *)))
746
      break;
747
    length=va_arg(args,uint);
748
  }
749
  va_end(args);
750
  putchar('\n');
751
752
  va_start(args,head_length);
753
  field=header; length=head_length;
754
  putchar('|');
755
  for (;;)
756
  {
757
    str_length=(uint) strlen(field);
758
    if (str_length > length)
759
      str_length=length+1;
760
    pre_space=(uint) (((int) length-(int) str_length)/2)+1;
761
    for (i=0 ; i < pre_space ; i++)
762
      putchar(' ');
763
    for (i = 0 ; i < str_length ; i++)
764
      putchar(field[i]);
765
    length=length+2-str_length-pre_space;
766
    for (i=0 ; i < length ; i++)
767
      putchar(' ');
768
    putchar('|');
769
    if (!(field=va_arg(args,char *)))
770
      break;
771
    length=va_arg(args,uint);
772
  }
773
  va_end(args);
774
  putchar('\n');
775
776
  va_start(args,head_length);
777
  putchar('+');
778
  field=header; length=head_length;
779
  for (;;)
780
  {
781
    for (i=0 ; i < length+2 ; i++)
782
      putchar('-');
783
    putchar('+');
784
    if (!(field=va_arg(args,char *)))
785
      break;
786
    length=va_arg(args,uint);
787
  }
788
  va_end(args);
789
  putchar('\n');
790
}
791
792
793
static void
794
print_row(const char *header,uint head_length,...)
795
{
796
  va_list args;
797
  const char *field;
798
  uint i,length,field_length;
799
800
  va_start(args,head_length);
801
  field=header; length=head_length;
802
  for (;;)
803
  {
804
    putchar('|');
805
    putchar(' ');
806
    fputs(field,stdout);
807
    field_length=(uint) strlen(field);
808
    for (i=field_length ; i <= length ; i++)
809
      putchar(' ');
810
    if (!(field=va_arg(args,char *)))
811
      break;
812
    length=va_arg(args,uint);
813
  }
814
  va_end(args);
815
  putchar('|');
816
  putchar('\n');
817
}
818
819
820
static void
821
print_trailer(uint head_length,...)
822
{
823
  va_list args;
824
  uint length,i;
825
826
  va_start(args,head_length);
827
  length=head_length;
828
  putchar('+');
829
  for (;;)
830
  {
831
    for (i=0 ; i < length+2 ; i++)
832
      putchar('-');
833
    putchar('+');
834
    if (!(length=va_arg(args,uint)))
835
      break;
836
  }
837
  va_end(args);
838
  putchar('\n');
839
}
840
841
842
static void print_res_header(MYSQL_RES *result)
843
{
844
  MYSQL_FIELD *field;
845
846
  print_res_top(result);
847
  mysql_field_seek(result,0);
848
  putchar('|');
849
  while ((field = mysql_fetch_field(result)))
850
  {
851
    printf(" %-*s|",(int) field->max_length+1,field->name);
852
  }
853
  putchar('\n');
854
  print_res_top(result);
855
}
856
857
858
static void print_res_top(MYSQL_RES *result)
859
{
860
  uint i,length;
861
  MYSQL_FIELD *field;
862
863
  putchar('+');
864
  mysql_field_seek(result,0);
865
  while((field = mysql_fetch_field(result)))
866
  {
867
    if ((length=(uint) strlen(field->name)) > field->max_length)
868
      field->max_length=length;
869
    else
870
      length=field->max_length;
871
    for (i=length+2 ; i--> 0 ; )
872
      putchar('-');
873
    putchar('+');
874
  }
875
  putchar('\n');
876
}
877
878
879
static void print_res_row(MYSQL_RES *result,MYSQL_ROW cur)
880
{
881
  uint i,length;
882
  MYSQL_FIELD *field;
883
  putchar('|');
884
  mysql_field_seek(result,0);
885
  for (i=0 ; i < mysql_num_fields(result); i++)
886
  {
887
    field = mysql_fetch_field(result);
888
    length=field->max_length;
889
    printf(" %-*s|",length+1,cur[i] ? (char*) cur[i] : "");
890
  }
891
  putchar('\n');
892
}