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