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