diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 18:00:34 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 18:00:34 +0000 |
commit | 3f619478f796eddbba6e39502fe941b285dd97b1 (patch) | |
tree | e2c7b5777f728320e5b5542b6213fd3591ba51e2 /client/mysqlshow.c | |
parent | Initial commit. (diff) | |
download | mariadb-upstream.tar.xz mariadb-upstream.zip |
Adding upstream version 1:10.11.6.upstream/1%10.11.6upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | client/mysqlshow.c | 964 |
1 files changed, 964 insertions, 0 deletions
diff --git a/client/mysqlshow.c b/client/mysqlshow.c new file mode 100644 index 00000000..aa606d61 --- /dev/null +++ b/client/mysqlshow.c @@ -0,0 +1,964 @@ +/* + Copyright (c) 2000, 2015, Oracle and/or its affiliates. + Copyright (c) 2010, 2019, MariaDB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA +*/ + +/* Show databases, tables or columns */ + +#define SHOW_VERSION "9.10" + +#include "client_priv.h" +#include <my_sys.h> +#include <m_string.h> +#include <mysql.h> +#include <mysqld_error.h> +#include <signal.h> +#include <stdarg.h> +#include <sslopt-vars.h> +#include <welcome_copyright_notice.h> /* ORACLE_WELCOME_COPYRIGHT_NOTICE */ + +static char * host=0, *opt_password=0, *user=0; +static my_bool opt_show_keys= 0, opt_compress= 0, opt_count=0, opt_status= 0; +static my_bool tty_password= 0, opt_table_type= 0; +static my_bool debug_info_flag= 0, debug_check_flag= 0; +static uint my_end_arg= 0; +static uint opt_verbose=0; +static char *default_charset= (char*) MYSQL_AUTODETECT_CHARSET_NAME; +static char *opt_plugin_dir= 0, *opt_default_auth= 0; + +static uint opt_protocol=0; + +static void get_options(int *argc,char ***argv); +static uint opt_mysql_port=0; +static int list_dbs(MYSQL *mysql,const char *wild); +static int list_tables(MYSQL *mysql,const char *db,const char *table); +static int list_table_status(MYSQL *mysql,const char *db,const char *table); +static int list_fields(MYSQL *mysql,const char *db,const char *table, + const char *field); +static void print_header(const char *header,size_t head_length,...); +static void print_row(const char *header,size_t head_length,...); +static void print_trailer(size_t length,...); +static void print_res_header(MYSQL_RES *result); +static void print_res_top(MYSQL_RES *result); +static void print_res_row(MYSQL_RES *result,MYSQL_ROW cur); + +static const char *load_default_groups[]= +{ "mysqlshow", "mariadb-show", "client", "client-server", "client-mariadb", + 0 }; +static char * opt_mysql_unix_port=0; + +int main(int argc, char **argv) +{ + int error; + my_bool first_argument_uses_wildcards=0; + char *wild; + MYSQL mysql; + my_bool reconnect; + static char **defaults_argv; + MY_INIT(argv[0]); + sf_leaking_memory=1; /* don't report memory leaks on early exits */ + + /* We need to know if protocol-related options originate from CLI args */ + my_defaults_mark_files = TRUE; + + load_defaults_or_exit("my", load_default_groups, &argc, &argv); + defaults_argv=argv; + + get_options(&argc,&argv); + + sf_leaking_memory=0; /* from now on we cleanup properly */ + wild=0; + if (argc) + { + char *pos= argv[argc-1], *to; + for (to= pos ; *pos ; pos++, to++) + { + switch (*pos) { + case '*': + *pos= '%'; + first_argument_uses_wildcards= 1; + break; + case '?': + *pos= '_'; + first_argument_uses_wildcards= 1; + break; + case '%': + case '_': + first_argument_uses_wildcards= 1; + break; + case '\\': + pos++; + default: break; + } + *to= *pos; + } + *to= *pos; /* just to copy a '\0' if '\\' was used */ + } + if (first_argument_uses_wildcards) + wild= argv[--argc]; + else if (argc == 3) /* We only want one field */ + wild= argv[--argc]; + + if (argc > 2) + { + fprintf(stderr,"%s: Too many arguments\n",my_progname); + exit(1); + } + mysql_init(&mysql); + if (opt_compress) + mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS); +#ifdef HAVE_OPENSSL + if (opt_use_ssl) + { + mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, + opt_ssl_capath, opt_ssl_cipher); + mysql_options(&mysql, MYSQL_OPT_SSL_CRL, opt_ssl_crl); + mysql_options(&mysql, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath); + mysql_options(&mysql, MARIADB_OPT_TLS_VERSION, opt_tls_version); + } + mysql_options(&mysql,MYSQL_OPT_SSL_VERIFY_SERVER_CERT, + (char*)&opt_ssl_verify_server_cert); +#endif + if (opt_protocol) + mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); + + if (!strcmp(default_charset,MYSQL_AUTODETECT_CHARSET_NAME)) + default_charset= (char *)my_default_csname(); + my_set_console_cp(default_charset); + mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset); + + if (opt_plugin_dir && *opt_plugin_dir) + mysql_options(&mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir); + + if (opt_default_auth && *opt_default_auth) + mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth); + + mysql_options(&mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0); + mysql_options4(&mysql, MYSQL_OPT_CONNECT_ATTR_ADD, + "program_name", "mysqlshow"); + if (!(mysql_real_connect(&mysql,host,user,opt_password, + (first_argument_uses_wildcards) ? "" : + argv[0],opt_mysql_port,opt_mysql_unix_port, + 0))) + { + fprintf(stderr,"%s: %s\n",my_progname,mysql_error(&mysql)); + error= 1; + goto error; + } + reconnect= 1; + mysql_options(&mysql, MYSQL_OPT_RECONNECT, &reconnect); + + switch (argc) { + case 0: error=list_dbs(&mysql,wild); break; + case 1: + if (opt_status) + error=list_table_status(&mysql,argv[0],wild); + else + error=list_tables(&mysql,argv[0],wild); + break; + default: + if (opt_status && ! wild) + error=list_table_status(&mysql,argv[0],argv[1]); + else + error=list_fields(&mysql,argv[0],argv[1],wild); + break; + } +error: + mysql_close(&mysql); /* Close & free connection */ + my_free(opt_password); + mysql_server_end(); + free_defaults(defaults_argv); + my_end(my_end_arg); + exit(error ? 1 : 0); + return 0; /* No compiler warnings */ +} + +static struct my_option my_long_options[] = +{ + {"character-sets-dir", 'c', "Directory for character set files.", + (char**) &charsets_dir, (char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, + 0, 0, 0, 0, 0}, + {"default-character-set", OPT_DEFAULT_CHARSET, + "Set the default character set.", &default_charset, + &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"count", OPT_COUNT, + "Show number of rows per table (may be slow for non-MyISAM tables).", + &opt_count, &opt_count, 0, GET_BOOL, NO_ARG, 0, 0, 0, + 0, 0, 0}, + {"compress", 'C', "Use compression in server/client protocol.", + &opt_compress, &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, + 0, 0, 0}, + {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", + 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.", + &debug_check_flag, &debug_check_flag, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.", + &debug_info_flag, &debug_info_flag, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"default_auth", OPT_DEFAULT_AUTH, + "Default authentication client-side plugin to use.", + &opt_default_auth, &opt_default_auth, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, + 0, 0, 0, 0, 0, 0}, + {"host", 'h', "Connect to host.", &host, &host, 0, GET_STR, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"status", 'i', "Shows a lot of extra information about each table.", + &opt_status, &opt_status, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + 0, 0}, + {"keys", 'k', "Show keys for table.", &opt_show_keys, + &opt_show_keys, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"password", 'p', + "Password to use when connecting to server. If password is not given, it's " + "solicited on the tty.", + 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.", + &opt_plugin_dir, &opt_plugin_dir, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"port", 'P', "Port number to use for connection or 0 for default to, in " + "order of preference, my.cnf, $MYSQL_TCP_PORT, " +#if MYSQL_PORT_DEFAULT == 0 + "/etc/services, " +#endif + "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", + &opt_mysql_port, + &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, + 0}, +#ifdef _WIN32 + {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG, + NO_ARG, 0, 0, 0, 0, 0, 0}, +#endif + {"protocol", OPT_MYSQL_PROTOCOL, + "The protocol to use for connection (tcp, socket, pipe).", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"show-table-type", 't', "Show table type column.", + &opt_table_type, &opt_table_type, 0, GET_BOOL, + NO_ARG, 0, 0, 0, 0, 0, 0}, + {"socket", 'S', "The socket file to use for connection.", + &opt_mysql_unix_port, &opt_mysql_unix_port, 0, GET_STR, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#include <sslopt-longopts.h> +#ifndef DONT_ALLOW_USER_CHANGE + {"user", 'u', "User for login if not current user.", &user, + &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#endif + {"verbose", 'v', + "More verbose output; you can use this multiple times to get even more " + "verbose output.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, + NO_ARG, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} +}; + + +static void print_version(void) +{ + printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,SHOW_VERSION, + MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE); +} + + +static void usage(void) +{ + print_version(); + puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000")); + puts("Shows the structure of a MariaDB database (databases, tables, and columns).\n"); + printf("Usage: %s [OPTIONS] [database [table [column]]]\n",my_progname); + puts("\n\ +If last argument contains a shell or SQL wildcard (*,?,% or _) then only\n\ +what\'s matched by the wildcard is shown.\n\ +If no database is given then all matching databases are shown.\n\ +If no table is given, then all matching tables in database are shown.\n\ +If no column is given, then all matching columns and column types in table\n\ +are shown."); + print_defaults("my",load_default_groups); + puts(""); + my_print_help(my_long_options); + my_print_variables(my_long_options); +} + + +static my_bool +get_one_option(const struct my_option *opt, const char *argument, + const char *filename) +{ + + switch(opt->id) { + case 'v': + opt_verbose++; + break; + case 'p': + if (argument == disabled_my_option) + argument= (char*) ""; /* Don't require password */ + if (argument) + { + /* + One should not really change the argument, but we make an + exception for passwords + */ + char *start= (char*) argument; + my_free(opt_password); + opt_password=my_strdup(PSI_NOT_INSTRUMENTED, argument, MYF(MY_FAE)); + while (*argument) + *(char*) argument++= 'x'; /* Destroy argument */ + if (*start) + start[1]=0; /* Cut length of argument */ + tty_password= 0; + } + else + tty_password=1; + break; + case 'W': +#ifdef _WIN32 + opt_protocol = MYSQL_PROTOCOL_PIPE; +#endif + break; + case OPT_MYSQL_PROTOCOL: + if ((opt_protocol= find_type_with_warning(argument, &sql_protocol_typelib, + opt->name)) <= 0) + { + sf_leaking_memory= 1; /* no memory leak reports here */ + exit(1); + } + break; + case 'P': + if (filename[0] == '\0') + { + /* Port given on command line, switch protocol to use TCP */ + opt_protocol= MYSQL_PROTOCOL_TCP; + } + break; + case 'S': + if (filename[0] == '\0') + { + /* + Socket given on command line, switch protocol to use SOCKETSt + Except on Windows if 'protocol= pipe' has been provided in + the config file or command line. + */ + if (opt_protocol != MYSQL_PROTOCOL_PIPE) + { + opt_protocol= MYSQL_PROTOCOL_SOCKET; + } + } + break; + break; + case '#': + DBUG_PUSH(argument ? argument : "d:t:o"); + debug_check_flag= 1; + break; +#include <sslopt-case.h> + case 'V': + print_version(); + exit(0); + break; + case '?': + case 'I': /* Info */ + usage(); + exit(0); + } + return 0; +} + + +static void +get_options(int *argc,char ***argv) +{ + int ho_error; + + if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option))) + exit(ho_error); + + if (tty_password) + opt_password=my_get_tty_password(NullS); + if (opt_count) + { + /* + We need to set verbose to 2 as we need to change the output to include + the number-of-rows column + */ + opt_verbose= 2; + } + if (debug_info_flag) + my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO; + if (debug_check_flag) + my_end_arg= MY_CHECK_ERROR; + return; +} + + +static int +list_dbs(MYSQL *mysql,const char *wild) +{ + const char *header; + size_t length = 0; + uint counter = 0; + ulong rowcount = 0L; + char tables[NAME_LEN+1], rows[NAME_LEN+1]; + char query[NAME_LEN + 100]; + MYSQL_FIELD *field; + MYSQL_RES *result; + MYSQL_ROW row= NULL, rrow; + + if (!(result=mysql_list_dbs(mysql,wild))) + { + fprintf(stderr,"%s: Cannot list databases: %s\n",my_progname, + mysql_error(mysql)); + return 1; + } + + /* + If a wildcard was used, but there was only one row and it's name is an + exact match, we'll assume they really wanted to see the contents of that + database. This is because it is fairly common for database names to + contain the underscore (_), like INFORMATION_SCHEMA. + */ + if (wild && mysql_num_rows(result) == 1) + { + row= mysql_fetch_row(result); + if (!my_strcasecmp(&my_charset_latin1, row[0], wild)) + { + mysql_free_result(result); + if (opt_status) + return list_table_status(mysql, wild, NULL); + else + return list_tables(mysql, wild, NULL); + } + } + + if (wild) + printf("Wildcard: %s\n",wild); + + header="Databases"; + length= strlen(header); + field=mysql_fetch_field(result); + if (length < field->max_length) + length=field->max_length; + + if (!opt_verbose) + print_header(header,length,NullS); + else if (opt_verbose == 1) + print_header(header,length,"Tables",6,NullS); + else + print_header(header,length,"Tables",6,"Total Rows",12,NullS); + + /* The first row may have already been read up above. */ + while (row || (row= mysql_fetch_row(result))) + { + counter++; + + if (opt_verbose) + { + if (!(mysql_select_db(mysql,row[0]))) + { + MYSQL_RES *tresult = mysql_list_tables(mysql,(char*)NULL); + if (mysql_affected_rows(mysql) > 0) + { + snprintf(tables, sizeof(tables), "%6lu",(ulong) mysql_affected_rows(mysql)); + rowcount = 0; + if (opt_verbose > 1) + { + /* Print the count of tables and rows for each database */ + MYSQL_ROW trow; + while ((trow = mysql_fetch_row(tresult))) + { + my_snprintf(query, sizeof(query), + "SELECT COUNT(*) FROM `%s`", trow[0]); + if (!(mysql_query(mysql,query))) + { + MYSQL_RES *rresult; + if ((rresult = mysql_store_result(mysql))) + { + rrow = mysql_fetch_row(rresult); + rowcount += (ulong) strtoull(rrow[0], (char**) 0, 10); + mysql_free_result(rresult); + } + } + } + snprintf(rows, sizeof(rows), "%12lu", rowcount); + } + } + else + { + snprintf(tables, sizeof(tables), "%6d" ,0); + snprintf(rows, sizeof(rows), "%12d", 0); + } + mysql_free_result(tresult); + } + else + { + strmov(tables,"N/A"); + strmov(rows,"N/A"); + } + } + + if (!opt_verbose) + print_row(row[0],length,0); + else if (opt_verbose == 1) + print_row(row[0],length,tables,6,NullS); + else + print_row(row[0],length,tables,6,rows,12,NullS); + + row= NULL; + } + + print_trailer(length, + (opt_verbose > 0 ? 6 : 0), + (opt_verbose > 1 ? 12 :0), + 0); + + if (counter && opt_verbose) + printf("%u row%s in set.\n",counter,(counter > 1) ? "s" : ""); + mysql_free_result(result); + return 0; +} + + +static int +list_tables(MYSQL *mysql,const char *db,const char *table) +{ + const char *header; + size_t head_length; + uint counter = 0; + char query[NAME_LEN + 100], rows[NAME_LEN], fields[16]; + MYSQL_FIELD *field; + MYSQL_RES *result; + MYSQL_ROW row, rrow; + + if (mysql_select_db(mysql,db)) + { + fprintf(stderr,"%s: Cannot connect to db %s: %s\n",my_progname,db, + mysql_error(mysql)); + return 1; + } + if (table) + { + /* + We just hijack the 'rows' variable for a bit to store the escaped + table name + */ + mysql_real_escape_string(mysql, rows, table, (unsigned long)strlen(table)); + my_snprintf(query, sizeof(query), "show%s tables like '%s'", + opt_table_type ? " full" : "", rows); + } + else + my_snprintf(query, sizeof(query), "show%s tables", + opt_table_type ? " full" : ""); + if (mysql_query(mysql, query) || !(result= mysql_store_result(mysql))) + { + fprintf(stderr,"%s: Cannot list tables in %s: %s\n",my_progname,db, + mysql_error(mysql)); + exit(1); + } + printf("Database: %s",db); + if (table) + printf(" Wildcard: %s",table); + putchar('\n'); + + header="Tables"; + head_length= strlen(header); + field=mysql_fetch_field(result); + if (head_length < field->max_length) + head_length=field->max_length; + + if (opt_table_type) + { + if (!opt_verbose) + print_header(header,head_length,"table_type",10,NullS); + else if (opt_verbose == 1) + print_header(header,head_length,"table_type",10,"Columns",8,NullS); + else + { + print_header(header,head_length,"table_type",10,"Columns",8, + "Total Rows",10,NullS); + } + } + else + { + if (!opt_verbose) + print_header(header,head_length,NullS); + else if (opt_verbose == 1) + print_header(header,head_length,"Columns",8,NullS); + else + print_header(header,head_length,"Columns",8, "Total Rows",10,NullS); + } + + while ((row = mysql_fetch_row(result))) + { + counter++; + if (opt_verbose > 0) + { + if (!(mysql_select_db(mysql,db))) + { + MYSQL_RES *rresult = mysql_list_fields(mysql,row[0],NULL); + ulong rowcount=0L; + if (!rresult) + { + strmov(fields,"N/A"); + strmov(rows,"N/A"); + } + else + { + snprintf(fields, sizeof(fields), "%8u", (uint) mysql_num_fields(rresult)); + mysql_free_result(rresult); + + if (opt_verbose > 1) + { + /* Print the count of rows for each table */ + my_snprintf(query, sizeof(query), "SELECT COUNT(*) FROM `%s`", + row[0]); + if (!(mysql_query(mysql,query))) + { + if ((rresult = mysql_store_result(mysql))) + { + rrow = mysql_fetch_row(rresult); + rowcount += (unsigned long) strtoull(rrow[0], (char**) 0, 10); + mysql_free_result(rresult); + } + snprintf(rows, sizeof(rows), "%10lu", rowcount); + } + else + snprintf(rows, sizeof(rows), "%10d", 0); + } + } + } + else + { + strmov(fields,"N/A"); + strmov(rows,"N/A"); + } + } + if (opt_table_type) + { + if (!opt_verbose) + print_row(row[0],head_length,row[1],10,NullS); + else if (opt_verbose == 1) + print_row(row[0],head_length,row[1],10,fields,8,NullS); + else + print_row(row[0],head_length,row[1],10,fields,8,rows,10,NullS); + } + else + { + if (!opt_verbose) + print_row(row[0],head_length,NullS); + else if (opt_verbose == 1) + print_row(row[0],head_length, fields,8, NullS); + else + print_row(row[0],head_length, fields,8, rows,10, NullS); + } + } + + print_trailer(head_length, + (opt_table_type ? 10 : opt_verbose > 0 ? 8 : 0), + (opt_table_type ? (opt_verbose > 0 ? 8 : 0) + : (opt_verbose > 1 ? 10 :0)), + !opt_table_type ? 0 : opt_verbose > 1 ? 10 :0, + 0); + + if (counter && opt_verbose) + printf("%u row%s in set.\n\n",counter,(counter > 1) ? "s" : ""); + + mysql_free_result(result); + return 0; +} + + +static int +list_table_status(MYSQL *mysql,const char *db,const char *wild) +{ + char query[NAME_LEN + 100]; + size_t len; + MYSQL_RES *result; + MYSQL_ROW row; + + len= sizeof(query); + len-= my_snprintf(query, len, "show table status from `%s`", db); + if (wild && wild[0] && len) + strxnmov(query + strlen(query), len - 1, " like '", wild, "'", NullS); + if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql))) + { + fprintf(stderr,"%s: Cannot get status for db: %s, table: %s: %s\n", + my_progname,db,wild ? wild : "",mysql_error(mysql)); + if (mysql_errno(mysql) == ER_PARSE_ERROR) + fprintf(stderr,"This error probably means that your MariaDB server doesn't support the\n\'show table status' command.\n"); + return 1; + } + + printf("Database: %s",db); + if (wild) + printf(" Wildcard: %s",wild); + putchar('\n'); + + print_res_header(result); + while ((row=mysql_fetch_row(result))) + print_res_row(result,row); + print_res_top(result); + mysql_free_result(result); + return 0; +} + +/* + list fields uses field interface as an example of how to parse + a MYSQL FIELD +*/ + +static int +list_fields(MYSQL *mysql,const char *db,const char *table, + const char *wild) +{ + char query[NAME_LEN + 100]; + size_t len; + MYSQL_RES *result; + MYSQL_ROW row; + ulong UNINIT_VAR(rows); + + if (mysql_select_db(mysql,db)) + { + fprintf(stderr,"%s: Cannot connect to db: %s: %s\n",my_progname,db, + mysql_error(mysql)); + return 1; + } + + if (opt_count) + { + my_snprintf(query, sizeof(query), "select count(*) from `%s`", table); + if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql))) + { + fprintf(stderr,"%s: Cannot get record count for db: %s, table: %s: %s\n", + my_progname,db,table,mysql_error(mysql)); + return 1; + } + row= mysql_fetch_row(result); + rows= (ulong) strtoull(row[0], (char**) 0, 10); + mysql_free_result(result); + } + + len= sizeof(query); + len-= my_snprintf(query, len, "show /*!32332 FULL */ columns from `%s`", + table); + if (wild && wild[0] && len) + strxnmov(query + strlen(query), len - 1, " like '", wild, "'", NullS); + if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql))) + { + fprintf(stderr,"%s: Cannot list columns in db: %s, table: %s: %s\n", + my_progname,db,table,mysql_error(mysql)); + return 1; + } + + printf("Database: %s Table: %s", db, table); + if (opt_count) + printf(" Rows: %lu", rows); + if (wild && wild[0]) + printf(" Wildcard: %s",wild); + putchar('\n'); + + print_res_header(result); + while ((row=mysql_fetch_row(result))) + print_res_row(result,row); + print_res_top(result); + if (opt_show_keys) + { + my_snprintf(query, sizeof(query), "show keys from `%s`", table); + if (mysql_query(mysql,query) || !(result=mysql_store_result(mysql))) + { + fprintf(stderr,"%s: Cannot list keys in db: %s, table: %s: %s\n", + my_progname,db,table,mysql_error(mysql)); + return 1; + } + if (mysql_num_rows(result)) + { + print_res_header(result); + while ((row=mysql_fetch_row(result))) + print_res_row(result,row); + print_res_top(result); + } + else + puts("Table has no keys"); + } + mysql_free_result(result); + return 0; +} + + +/***************************************************************************** + General functions to print a nice ascii-table from data +*****************************************************************************/ + +static void +print_header(const char *header,size_t head_length,...) +{ + va_list args; + size_t length,i,str_length,pre_space; + const char *field; + + va_start(args,head_length); + putchar('+'); + field=header; length=head_length; + for (;;) + { + for (i=0 ; i < length+2 ; i++) + putchar('-'); + putchar('+'); + if (!(field=va_arg(args,char *))) + break; + length=va_arg(args,uint); + } + va_end(args); + putchar('\n'); + + va_start(args,head_length); + field=header; length=head_length; + putchar('|'); + for (;;) + { + str_length= strlen(field); + if (str_length > length) + str_length=length+1; + pre_space= ((length- str_length)/2)+1; + for (i=0 ; i < pre_space ; i++) + putchar(' '); + for (i = 0 ; i < str_length ; i++) + putchar(field[i]); + length=length+2-str_length-pre_space; + for (i=0 ; i < length ; i++) + putchar(' '); + putchar('|'); + if (!(field=va_arg(args,char *))) + break; + length=va_arg(args,uint); + } + va_end(args); + putchar('\n'); + + va_start(args,head_length); + putchar('+'); + field=header; length=head_length; + for (;;) + { + for (i=0 ; i < length+2 ; i++) + putchar('-'); + putchar('+'); + if (!(field=va_arg(args,char *))) + break; + length=va_arg(args,uint); + } + va_end(args); + putchar('\n'); +} + + +static void +print_row(const char *header,size_t head_length,...) +{ + va_list args; + const char *field; + size_t i,length,field_length; + + va_start(args,head_length); + field=header; length=head_length; + for (;;) + { + putchar('|'); + putchar(' '); + fputs(field,stdout); + field_length= strlen(field); + for (i=field_length ; i <= length ; i++) + putchar(' '); + if (!(field=va_arg(args,char *))) + break; + length=va_arg(args,uint); + } + va_end(args); + putchar('|'); + putchar('\n'); +} + + +static void +print_trailer(size_t head_length,...) +{ + va_list args; + size_t length,i; + + va_start(args,head_length); + length=head_length; + putchar('+'); + for (;;) + { + for (i=0 ; i < length+2 ; i++) + putchar('-'); + putchar('+'); + if (!(length=va_arg(args,uint))) + break; + } + va_end(args); + putchar('\n'); +} + + +static void print_res_header(MYSQL_RES *result) +{ + MYSQL_FIELD *field; + + print_res_top(result); + mysql_field_seek(result,0); + putchar('|'); + while ((field = mysql_fetch_field(result))) + { + printf(" %-*s|",(int) field->max_length+1,field->name); + } + putchar('\n'); + print_res_top(result); +} + + +static void print_res_top(MYSQL_RES *result) +{ + size_t i,length; + MYSQL_FIELD *field; + + putchar('+'); + mysql_field_seek(result,0); + while((field = mysql_fetch_field(result))) + { + if ((length= strlen(field->name)) > field->max_length) + field->max_length=(ulong)length; + else + length=field->max_length; + for (i=length+2 ; i--> 0 ; ) + putchar('-'); + putchar('+'); + } + putchar('\n'); +} + + +static void print_res_row(MYSQL_RES *result,MYSQL_ROW cur) +{ + uint i,length; + MYSQL_FIELD *field; + putchar('|'); + mysql_field_seek(result,0); + for (i=0 ; i < mysql_num_fields(result); i++) + { + field = mysql_fetch_field(result); + length=field->max_length; + printf(" %-*s|",length+1,cur[i] ? (char*) cur[i] : ""); + } + putchar('\n'); +} |