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