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