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 | |
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 | #ifdef HAVE_SMEM |
43 | static char *shared_memory_base_name=0; |
44 | #endif |
45 | static uint opt_protocol=0; |
46 | |
47 | static void get_options(int *argc,char ***argv); |
48 | static uint opt_mysql_port=0; |
49 | static int list_dbs(MYSQL *mysql,const char *wild); |
50 | static int list_tables(MYSQL *mysql,const char *db,const char *table); |
51 | static int list_table_status(MYSQL *mysql,const char *db,const char *table); |
52 | static int list_fields(MYSQL *mysql,const char *db,const char *table, |
53 | const char *field); |
54 | static void print_header(const char *,size_t head_length,...); |
55 | static void print_row(const char *,size_t head_length,...); |
56 | static void print_trailer(size_t length,...); |
57 | static void print_res_header(MYSQL_RES *result); |
58 | static void print_res_top(MYSQL_RES *result); |
59 | static void print_res_row(MYSQL_RES *result,MYSQL_ROW cur); |
60 | |
61 | static const char *load_default_groups[]= |
62 | { "mysqlshow" ,"client" , "client-server" , "client-mariadb" , 0 }; |
63 | static char * opt_mysql_unix_port=0; |
64 | |
65 | int 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 | } |
176 | error: |
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 | |
189 | static 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 | |
275 | static 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 | |
282 | static 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\ |
289 | If last argument contains a shell or SQL wildcard (*,?,% or _) then only\n\ |
290 | what\'s matched by the wildcard is shown.\n\ |
291 | If no database is given then all matching databases are shown.\n\ |
292 | If no table is given, then all matching tables in database are shown.\n\ |
293 | If no column is given, then all matching columns and column types in table\n\ |
294 | are 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 | |
302 | static my_bool |
303 | get_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 | |
357 | static void |
358 | get_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 | |
383 | static int |
384 | list_dbs(MYSQL *mysql,const char *wild) |
385 | { |
386 | const char *; |
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 | |
510 | static int |
511 | list_tables(MYSQL *mysql,const char *db,const char *table) |
512 | { |
513 | const char *; |
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 | |
659 | static int |
660 | list_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 | |
698 | static int |
699 | list_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 | |
780 | static void |
781 | (const char *,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 | |
843 | static void |
844 | print_row(const char *,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 | |
870 | static void |
871 | print_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 | |
892 | static void (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 | |
908 | static 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 | |
929 | static 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 | |