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