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