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