From 835a75c97bbc31e35e25171db9c046ec1dae5b87 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 27 Jun 2002 11:27:04 +0300 Subject: [PATCH] Removed mysql_ssl_clear() Added statistics information for alarms (for bug tracking) Don't store "incomplete" in the xxx.cfg file if we are not using --restart. (Crash-me) Enlarged STACK_BUF_ALLOC becasue of failed crash-me test Aded new script mysql_tableinfo to make a system directory. Docs/manual.texi: Changelog and TODO include/mysql.h: Removed mysql_ssl_clear() (One should use mysql_close() instead) include/thr_alarm.h: Added info for alarms libmysql/libmysql.c: Made mysql_ssl_clear() static libmysql/libmysql.def: cleanup libmysqld/libmysqld.def: cleanup myisam/myisamchk.c: describe -> description myisam/myisampack.c: Fixed copyright. mysys/thr_alarm.c: Added statistics information for alarms (for bug tracking) scripts/Makefile.am: Added mysql_table_info sql-bench/crash-me.sh: Don't store "incomplete" in the xxx.cfg file if we are not using --restart. This was done becasue "incomplete" made it harder to quickly repeat a test that failed. sql-bench/limits/mysql.cfg: Update to 1.58 sql/hostname.cc: Remved compiler warning sql/item_func.cc: cleanup sql/item_func.h: Cleanup sql/mysql_priv.h: Enlarged STACK_BUF_ALLOC becasue of failed crash-me test sql/opt_range.cc: Removed purify warning sql/sql_parse.cc: cleanup sql/sql_test.cc: Added ala --- Docs/manual.texi | 11 +- include/mysql.h | 41 ++-- include/thr_alarm.h | 9 + libmysql/libmysql.c | 6 +- libmysql/libmysql.def | 2 +- libmysqld/libmysqld.def | 7 - myisam/myisamchk.c | 6 +- myisam/myisampack.c | 2 +- mysys/thr_alarm.c | 95 +++++--- scripts/Makefile.am | 2 + scripts/mysql_tableinfo.sh | 478 +++++++++++++++++++++++++++++++++++++ sql-bench/crash-me.sh | 35 ++- sql-bench/limits/mysql.cfg | 10 +- sql/hostname.cc | 4 +- sql/item_func.cc | 6 +- sql/item_func.h | 19 +- sql/mysql_priv.h | 2 +- sql/opt_range.cc | 4 +- sql/sql_parse.cc | 25 +- sql/sql_test.cc | 12 + 20 files changed, 674 insertions(+), 102 deletions(-) create mode 100644 scripts/mysql_tableinfo.sh diff --git a/Docs/manual.texi b/Docs/manual.texi index 178f60d08b2..9f40c285e1c 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -3951,10 +3951,6 @@ Automatic output from @code{mysql} to Netscape. @item @code{LOCK DATABASES} (with various options.) @item -@code{DECIMAL} and @code{NUMERIC} types can't read exponential numbers; -@code{Field_decimal::store(const char *from,uint len)} must be recoded -to fix this. -@item Functions: ADD_TO_SET(value,set) and REMOVE_FROM_SET(value,set). @item @@ -49368,6 +49364,9 @@ Emulation of @code{pthread_mutex()} for OS/2. @item Benjamin Pflugmann Extended @code{MERGE} tables to handle @code{INSERTS}. Active member on the MySQL mailing lists. +@item Guilhem Bichot +Fixed handling of exponents for @code{DECIMAL}. +Author of @code{mysql_tableinfo}. @end table Other contributors, bugfinders, and testers: James H. Thompson, Maurizio @@ -49496,6 +49495,10 @@ Our TODO section contains what we plan to have in 4.0. @xref{TODO MySQL 4.0}. @itemize @bullet @item +Removed @code{mysql_ssl_clear()}, as this was not needed. +@item +@code{DECIMAL} and @code{NUMERIC} types can now read exponential numbers. +@item Fixed bug in @code{innodb_log_group_home_dir} in @code{SHOW VARIABLES}. @item Fixed a bug in optimiser with merge tables when non-uniques values are diff --git a/include/mysql.h b/include/mysql.h index 5bcdca636c0..af3e8c773ef 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -122,17 +122,17 @@ struct st_mysql_options { my_bool use_ssl; /* if to use SSL or not */ my_bool compress,named_pipe; /* - on connect, find out the replication role of the server, and + On connect, find out the replication role of the server, and establish connections to all the peers */ my_bool rpl_probe; - /* - each call to mysql_real_query() will parse it to tell if it is a read - or a write, and direct it to the slave or the master + /* + Each call to mysql_real_query() will parse it to tell if it is a read + or a write, and direct it to the slave or the master */ my_bool rpl_parse; /* - if set, never read from a master,only from slave, when doing + If set, never read from a master,only from slave, when doing a read that is replication-aware */ my_bool no_master_reads; @@ -185,8 +185,10 @@ typedef struct st_mysql { added though mysql_rpl_probe() or mysql_set_master()/ mysql_add_slave() */ my_bool rpl_pivot; - /* pointers to the master, and the next slave - connections, points to itself if lone connection */ + /* + Pointers to the master, and the next slave connections, points to + itself if lone connection. + */ struct st_mysql* master, *next_slave; struct st_mysql* last_used_slave; /* needed for round-robin slave pick */ @@ -234,21 +236,27 @@ typedef struct st_mysql_manager char last_error[MAX_MYSQL_MANAGER_ERR]; } MYSQL_MANAGER; -/* Set up and bring down the server; to ensure that applications will - * work when linked against either the standard client library or the - * embedded server library, these functions should be called. */ +/* + Set up and bring down the server; to ensure that applications will + work when linked against either the standard client library or the + embedded server library, these functions should be called. +*/ int STDCALL mysql_server_init(int argc, char **argv, char **groups); void STDCALL mysql_server_end(void); -/* Set up and bring down a thread; these function should be called - * for each thread in an application which opens at least one MySQL - * connection. All uses of the connection(s) should be between these - * function calls. */ +/* + Set up and bring down a thread; these function should be called + for each thread in an application which opens at least one MySQL + connection. All uses of the connection(s) should be between these + function calls. +*/ my_bool STDCALL mysql_thread_init(void); void STDCALL mysql_thread_end(void); -/* Functions to get information from the MYSQL and MYSQL_RES structures */ -/* Should definitely be used if one uses shared libraries */ +/* + Functions to get information from the MYSQL and MYSQL_RES structures + Should definitely be used if one uses shared libraries. +*/ my_ulonglong STDCALL mysql_num_rows(MYSQL_RES *res); unsigned int STDCALL mysql_num_fields(MYSQL_RES *res); @@ -272,7 +280,6 @@ MYSQL * STDCALL mysql_init(MYSQL *mysql); int STDCALL mysql_ssl_set(MYSQL *mysql, const char *key, const char *cert, const char *ca, const char *capath, const char *cipher); -int STDCALL mysql_ssl_clear(MYSQL *mysql); my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, const char *passwd, const char *db); MYSQL * STDCALL mysql_real_connect(MYSQL *mysql, const char *host, diff --git a/include/thr_alarm.h b/include/thr_alarm.h index 5caf552718c..30825d49158 100644 --- a/include/thr_alarm.h +++ b/include/thr_alarm.h @@ -38,6 +38,15 @@ extern "C" { #define THR_SERVER_ALARM SIGALRM #endif +typedef struct st_alarm_info +{ + ulong next_alarm_time; + uint active_alarms; + uint max_used_alarms; +} ALARM_INFO; + +void thr_alarm_info(ALARM_INFO *info); + #if defined(DONT_USE_THR_ALARM) || !defined(THREAD) #define USE_ALARM_THREAD diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 646c165d512..fa505063deb 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1448,8 +1448,8 @@ mysql_ssl_set(MYSQL *mysql __attribute__((unused)) , NB! Errors are not reported until you do mysql_real_connect. **************************************************************************/ -int STDCALL -mysql_ssl_clear(MYSQL *mysql __attribute__((unused))) +static int +mysql_ssl_free(MYSQL *mysql __attribute__((unused))) { #ifdef HAVE_OPENSSL my_free(mysql->options.ssl_key, MYF(MY_ALLOW_ZERO_PTR)); @@ -2051,7 +2051,7 @@ mysql_close(MYSQL *mysql) my_free(mysql->options.charset_dir,MYF(MY_ALLOW_ZERO_PTR)); my_free(mysql->options.charset_name,MYF(MY_ALLOW_ZERO_PTR)); #ifdef HAVE_OPENSSL - mysql_ssl_clear(mysql); + mysql_ssl_free(mysql); #endif /* HAVE_OPENSSL */ /* Clear pointers for better safety */ mysql->host_info=mysql->user=mysql->passwd=mysql->db=0; diff --git a/libmysql/libmysql.def b/libmysql/libmysql.def index 9405ecd58ff..988f2b09195 100644 --- a/libmysql/libmysql.def +++ b/libmysql/libmysql.def @@ -90,7 +90,7 @@ EXPORTS mysql_real_escape_string mysql_ssl_set mysql_ssl_clear - mysql_real_connect + mysql_real_connect mysql_master_query mysql_master_send_query mysql_slave_query diff --git a/libmysqld/libmysqld.def b/libmysqld/libmysqld.def index 0e126aa9ceb..c6615ee971c 100644 --- a/libmysqld/libmysqld.def +++ b/libmysqld/libmysqld.def @@ -63,10 +63,3 @@ EXPORTS mysql_refresh mysql_odbc_escape_string myodbc_remove_escape - - - - - - - diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index c776c80e3ec..379b792059e 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -241,7 +241,7 @@ static struct my_option my_long_options[] = {"unpack", 'u', "Unpack file packed with myisampack.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"verbose", 'v', - "Print more information. This can be used with --describe and --check. Use many -v for more verbosity!", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, + "Print more information. This can be used with --description and --check. Use many -v for more verbosity!", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"version", 'V', "Print version and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -312,7 +312,7 @@ static void usage(void) -s, --silent Only print errors. One can use two -s to make\n\ myisamchk very silent\n\ -v, --verbose Print more information. This can be used with\n\ - --describe and --check. Use many -v for more verbosity!\n\ + --description and --check. Use many -v for more verbosity!\n\ -V, --version Print version and exit.\n\ -w, --wait Wait if table is locked.\n"); @@ -365,7 +365,7 @@ static void usage(void) puts("Other actions:\n\ -a, --analyze Analyze distribution of keys. Will make some joins in\n\ MySQL faster. You can check the calculated distribution\n\ - by using '--describe --verbose table_name'.\n\ + by using '--description --verbose table_name'.\n\ -d, --description Prints some information about table.\n\ -A, --set-auto-increment[=value]\n\ Force auto_increment to start at this or higher value\n\ diff --git a/myisam/myisampack.c b/myisam/myisampack.c index 0064b50348f..b7dd788821a 100644 --- a/myisam/myisampack.c +++ b/myisam/myisampack.c @@ -275,7 +275,7 @@ static void print_version(void) static void usage(void) { print_version(); - puts("Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB"); + puts("Copyright (C) 2002 MySQL AB"); puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,"); puts("and you are welcome to modify and redistribute it under the GPL license\n"); diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c index ef514efe39e..c75b43ad0fc 100644 --- a/mysys/thr_alarm.c +++ b/mysys/thr_alarm.c @@ -44,6 +44,7 @@ my_bool thr_alarm_inited=0; static pthread_mutex_t LOCK_alarm; static sigset_t full_signal_set; static QUEUE alarm_queue; +static uint max_used_alarms=0; pthread_t alarm_thread; #ifdef USE_ALARM_THREAD @@ -116,10 +117,10 @@ void init_thr_alarm(uint max_alarms) } /* -** Request alarm after sec seconds. -** A pointer is returned with points to a non-zero int when the alarm has been -** given. This can't be called from the alarm-handling thread. -** Returns 0 if no more alarms are allowed (aborted by process) + Request alarm after sec seconds. + A pointer is returned with points to a non-zero int when the alarm has been + given. This can't be called from the alarm-handling thread. + Returns 0 if no more alarms are allowed (aborted by process) */ bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data) @@ -140,13 +141,17 @@ bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data) pthread_sigmask(SIG_SETMASK,&old_mask,NULL); DBUG_RETURN(1); } - if (alarm_queue.elements == alarm_queue.max_elements) + if (alarm_queue.elements >= max_used_alarms) { - DBUG_PRINT("info", ("alarm queue full")); - fprintf(stderr,"Warning: thr_alarm queue is full\n"); - pthread_mutex_unlock(&LOCK_alarm); - pthread_sigmask(SIG_SETMASK,&old_mask,NULL); - DBUG_RETURN(1); + if (alarm_queue.elements == alarm_queue.max_elements) + { + DBUG_PRINT("info", ("alarm queue full")); + fprintf(stderr,"Warning: thr_alarm queue is full\n"); + pthread_mutex_unlock(&LOCK_alarm); + pthread_sigmask(SIG_SETMASK,&old_mask,NULL); + DBUG_RETURN(1); + } + max_used_alarms=alarm_queue.elements+1; } reschedule= (!alarm_queue.elements || (int) (((ALARM*) queue_top(&alarm_queue))->expire_time - now) > @@ -186,7 +191,7 @@ bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data) /* -** Remove alarm from list of alarms + Remove alarm from list of alarms */ void thr_end_alarm(thr_alarm_t *alarmed) @@ -227,13 +232,13 @@ void thr_end_alarm(thr_alarm_t *alarmed) DBUG_VOID_RETURN; } - /* - Come here when some alarm in queue is due. - Mark all alarms with are finnished in list. - Shedule alarms to be sent again after 1-10 sec (many alarms at once) - If alarm_aborted is set then all alarms are given and resent - every second. - */ +/* + Come here when some alarm in queue is due. + Mark all alarms with are finnished in list. + Shedule alarms to be sent again after 1-10 sec (many alarms at once) + If alarm_aborted is set then all alarms are given and resent + every second. +*/ sig_handler process_alarm(int sig __attribute__((unused))) { @@ -334,8 +339,8 @@ sig_handler process_alarm(int sig __attribute__((unused))) /* -** Shedule all alarms now. -** When all alarms are given, Free alarm memory and don't allow more alarms. + Shedule all alarms now. + When all alarms are given, Free alarm memory and don't allow more alarms. */ void end_thr_alarm(void) @@ -359,7 +364,7 @@ void end_thr_alarm(void) /* -** Remove another thread from the alarm + Remove another thread from the alarm */ void thr_alarm_kill(pthread_t thread_id) @@ -382,9 +387,25 @@ void thr_alarm_kill(pthread_t thread_id) } +void thr_alarm_info(ALARM_INFO *info) +{ + pthread_mutex_lock(&LOCK_alarm); + info->next_alarm_time= 0; + info->max_used_alarms= max_used_alarms; + if ((info->active_alarms= alarm_queue.elements)) + { + ulong now=(ulong) time((time_t*) 0); + long time_diff; + ALARM *alarm_data= (ALARM*) queue_top(&alarm_queue); + time_diff= (long) (alarm_data->expire_time - now); + info->next_alarm_time= (ulong) (time_diff < 0 ? 0 : time_diff); + } + pthread_mutex_unlock(&LOCK_alarm); +} + /* -** This is here for thread to get interruptet from read/write/fcntl -** ARGSUSED + This is here for thread to get interruptet from read/write/fcntl + ARGSUSED */ #if THR_CLIENT_ALARM != SIGALRM || defined(USE_ALARM_THREAD) @@ -459,7 +480,7 @@ static void *alarm_handler(void *arg __attribute__((unused))) #endif /* USE_ALARM_THREAD */ /***************************************************************************** -** thr_alarm for OS/2 + thr_alarm for OS/2 *****************************************************************************/ #elif defined(__EMX__) || defined(OS2) @@ -490,7 +511,7 @@ sig_handler process_alarm(int sig __attribute__((unused))) /* -** Remove another thread from the alarm + Remove another thread from the alarm */ void thr_alarm_kill(pthread_t thread_id) @@ -588,8 +609,14 @@ void init_thr_alarm(uint max_alarm) DBUG_VOID_RETURN; } +void thr_alarm_info(ALARM_INFO *info) +{ + bzero((char*) info, sizeof(*info)); +} + + /***************************************************************************** -** thr_alarm for win95 + thr_alarm for win95 *****************************************************************************/ #else /* __WIN__ */ @@ -661,13 +688,18 @@ void init_thr_alarm(uint max_alarm) DBUG_VOID_RETURN; } +void thr_alarm_info(ALARM_INFO *info) +{ + bzero((char*) info, sizeof(*info)); +} + #endif /* __WIN__ */ #endif /* THREAD */ /**************************************************************************** -** Handling of MAIN + Handling of test case (when compiled with -DMAIN) ***************************************************************************/ #ifdef MAIN @@ -867,6 +899,7 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused))) pthread_attr_t thr_attr; int i,*param,error; sigset_t set; + ALARM_INFO alarm_info; MY_INIT(argv[0]); if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '#') @@ -927,6 +960,10 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused))) pthread_attr_destroy(&thr_attr); pthread_mutex_lock(&LOCK_thread_count); + thr_alarm_info(&alarm_info); + printf("Main_thread: Alarms: %u max_alarms: %u next_alarm_time: %lu\n", + alarm_info.active_alarms, alarm_info.max_used_alarms, + alarm_info.next_alarm_time); while (thread_count) { VOID(pthread_cond_wait(&COND_thread_count,&LOCK_thread_count)); @@ -937,6 +974,10 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused))) } } pthread_mutex_unlock(&LOCK_thread_count); + thr_alarm_info(&alarm_info); + printf("Main_thread: Alarms: %u max_alarms: %u next_alarm_time: %lu\n", + alarm_info.active_alarms, alarm_info.max_used_alarms, + alarm_info.next_alarm_time); printf("Test succeeded\n"); return 0; } diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 913e62050fa..1469f3f2f2d 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -31,6 +31,7 @@ bin_SCRIPTS = @server_scripts@ \ mysqlhotcopy \ mysqldumpslow \ mysql_explain_log \ + mysql_tableinfo \ mysqld_multi EXTRA_SCRIPTS = make_binary_distribution.sh \ @@ -50,6 +51,7 @@ EXTRA_SCRIPTS = make_binary_distribution.sh \ mysqldumpslow.sh \ mysql_explain_log.sh \ mysqld_multi.sh \ + mysql_tableinfo.sh \ mysqld_safe.sh EXTRA_DIST = $(EXTRA_SCRIPTS) \ diff --git a/scripts/mysql_tableinfo.sh b/scripts/mysql_tableinfo.sh new file mode 100644 index 00000000000..bfe9be377c7 --- /dev/null +++ b/scripts/mysql_tableinfo.sh @@ -0,0 +1,478 @@ +#!@PERL@ -w + +use strict; +use Getopt::Long; +use DBI; + +=head1 NAME + +mysql_tableinfo - creates and populates information tables with +the output of SHOW DATABASES, SHOW TABLES (or SHOW TABLE STATUS), +SHOW COLUMNS and SHOW INDEX. + +This is version 1.0. + +=head1 SYNOPSIS + + mysql_tableinfo [OPTIONS] database_to_write [database_like_wild] [table_like_wild] + + Do not backquote (``) database_to_write, + and do not quote ('') database_like_wild or table_like_wild + + Examples: + + mysql_tableinfo info + + mysql_tableinfo info this_db + + mysql_tableinfo info %a% b% + + mysql_tableinfo info --clear-only + + mysql_tableinfo info --col --idx --table-status + +=cut + +# Documentation continued at end of file + + +sub usage { + die @_,"\nExecute 'perldoc $0' for documentation\n"; +} + +my %opt = ( + 'user' => scalar getpwuid($>), + 'host' => "localhost", + 'prefix' => "", #to avoid 'use of uninitialized value...' +); +Getopt::Long::Configure(qw(no_ignore_case)); # disambuguate -p and -P +GetOptions( \%opt, + "help", + "user|u=s", + "password|p=s", + "host|h=s", + "port|P=s", + "socket|S=s", + "tbl-status", + "col", + "idx", + "clear", + "clear-only", + "prefix=s", + "quiet|q", +) or usage("Invalid option"); + +if ($opt{help}) {usage();} + +my ($db_to_write,$db_like_wild,$tbl_like_wild); +if (@ARGV==0) +{ + usage("Not enough arguments"); +} +$db_to_write="`$ARGV[0]`"; shift @ARGV; +$db_like_wild=($ARGV[0])?$ARGV[0]:"%"; shift @ARGV; +$tbl_like_wild=($ARGV[0])?$ARGV[0]:"%"; shift @ARGV; +if (@ARGV>0) { usage("Too many arguments"); } + +my $info_db="`".$opt{'prefix'}."db`"; +my $info_tbl="`".$opt{'prefix'}."tbl". + (($opt{'tbl-status'})?"_status":"")."`"; +my $info_col="`".$opt{'prefix'}."col`"; +my $info_idx="`".$opt{'prefix'}."idx`"; + + +# --- connect to the database --- + +my $dsn = ";host=$opt{'host'}"; +$dsn .= ";port=$opt{port}" if $opt{port}; +$dsn .= ";mysql_socket=$opt{socket}" if $opt{socket}; + +my $dbh = DBI->connect("dbi:mysql:$dsn;mysql_read_default_group=perl", + $opt{user}, $opt{password}, +{ + RaiseError => 1, + PrintError => 0, + AutoCommit => 1, +}); + +$db_like_wild=$dbh->quote($db_like_wild); +$tbl_like_wild=$dbh->quote($tbl_like_wild); + +#Ask + +if (!$opt{'quiet'}) +{ + print "\n!! This program is doing to do:\n\n"; + print "**DROP** TABLE ...\n" if ($opt{'clear'} or $opt{'clear-only'}); + print "**DELETE** FROM ... WHERE `Database LIKE $db_like_wild AND `Table` LIKE $tbl_like_wild +**INSERT** INTO ... + +on the following tables :\n"; + my $i; + foreach $i (($info_db, $info_tbl), + (($opt{'col'})?$info_col:()), + (($opt{'idx'})?$info_idx:())) + { + print(" $db_to_write.$i\n"); + } + print "\nContinue (you can skip this confirmation step with --quiet) ? (y|n) [n]"; + my $answer=; + unless ($answer =~ /^\s*y\s*$/i) + { + print "Nothing done!\n";exit; + } +} + +if ($opt{'clear'} or $opt{'clear-only'}) +{ +#do not drop the $db_to_write database ! + my $i; + foreach $i (($info_db, $info_tbl), + (($opt{'col'})?$info_col:()), + (($opt{'idx'})?$info_idx:())) + { + $dbh->do("DROP TABLE IF EXISTS $db_to_write.$i"); + } + if ($opt{'clear-only'}) + { + print "Wrote to database $db_to_write .\n" unless ($opt{'quiet'}); + exit(); + } +} + + +my %sth; +my %extra_col_desc; +my %row; +my %done_create_table; + +#create the $db_to_write database +$dbh->do("CREATE DATABASE IF NOT EXISTS $db_to_write"); +$dbh->do("USE $db_to_write"); + +#get databases +$sth{db}=$dbh->prepare("SHOW DATABASES LIKE $db_like_wild"); +$sth{db}->execute; + +#create $info_db which will receive info about databases. +#Ensure that the first column to be called "Database" (as SHOW DATABASES LIKE +#returns a varying +#column name (of the form "Database (%...)") which is not suitable) +$extra_col_desc{db}=do_create_table("db",$info_db,undef,"`Database`"); +#we'll remember the type of the `Database` column (as returned by +#SHOW DATABASES), which we will need when creating the next tables. + +#clear out-of-date info from this table +$dbh->do("DELETE FROM $info_db WHERE `Database` LIKE $db_like_wild"); + + +while (@{$row{db}}=$sth{db}->fetchrow_array) #go through all databases +{ + +#insert the database name + $dbh->do("INSERT INTO $info_db VALUES(" + .join_quote(@{$row{db}}).")"); + +#for each database, get tables + + $sth{tbl}=$dbh->prepare("SHOW TABLE" + .( ($opt{'tbl-status'}) ? + " STATUS" + : "S" ) + ." from `${$row{db}}[0]` LIKE $tbl_like_wild"); + $sth{tbl}->execute; + unless ($done_create_table{$info_tbl}) + +#tables must be created only once, and out-of-date info must be +#cleared once + { + $done_create_table{$info_tbl}=1; + $extra_col_desc{table}= + do_create_table("tbl",$info_tbl, +#add an extra column (database name) at the left +#and ensure that the table name will be called "Table" +#(this is unncessesary with +#SHOW TABLE STATUS, but necessary with SHOW TABLES (which returns a column +#named "Tables_in_...")) + "`Database` ".$extra_col_desc{db},"`Table`"); + $dbh->do("DELETE FROM $info_tbl WHERE `Database` LIKE $db_like_wild AND `Table` LIKE $tbl_like_wild"); + } + + while (@{$row{tbl}}=$sth{tbl}->fetchrow_array) + { + $dbh->do("INSERT INTO $info_tbl VALUES(" + .$dbh->quote(${$row{db}}[0]).",".join_quote(@{$row{tbl}}).")"); + +#for each table, get columns... + + if ($opt{'col'}) + { + $sth{col}=$dbh->prepare("SHOW COLUMNS FROM `${$row{tbl}}[0]` FROM `${$row{db}}[0]`"); + $sth{col}->execute; + unless ($done_create_table{$info_col}) + { + $done_create_table{$info_col}=1; + do_create_table("col",$info_col, + "`Database` ".$extra_col_desc{db}."," + ."`Table` ".$extra_col_desc{table}."," + ."`Seq_in_table` BIGINT(3)"); +#We need to add a sequence number (1 for the first column of the table, +#2 for the second etc) so that users are able to retrieve columns in order +#if they want. This is not needed for INDEX +#(where there is already Seq_in_index) + $dbh->do("DELETE FROM $info_col WHERE `Database` + LIKE $db_like_wild + AND `Table` LIKE $tbl_like_wild"); + } + my $col_number=0; + while (@{$row{col}}=$sth{col}->fetchrow_array) + { + $dbh->do("INSERT INTO $info_col VALUES(" + .$dbh->quote(${$row{db}}[0])."," + .$dbh->quote(${$row{tbl}}[0])."," + .++$col_number."," + .join_quote(@{$row{col}}).")"); + } + } + +#and get index. + + if ($opt{'idx'}) + { + $sth{idx}=$dbh->prepare("SHOW INDEX FROM `${$row{tbl}}[0]` FROM `${$row{db}}[0]`"); + $sth{idx}->execute; + unless ($done_create_table{$info_idx}) + { + $done_create_table{$info_idx}=1; + do_create_table("idx",$info_idx, + "`Database` ".$extra_col_desc{db}); + $dbh->do("DELETE FROM $info_idx WHERE `Database` + LIKE $db_like_wild + AND `Table` LIKE $tbl_like_wild"); + } + while (@{$row{idx}}=$sth{idx}->fetchrow_array) + { + $dbh->do("INSERT INTO $info_idx VALUES(" + .$dbh->quote(${$row{db}}[0])."," + .join_quote(@{$row{idx}}).")"); + } + } + } +} + +print "Wrote to database $db_to_write .\n" unless ($opt{'quiet'}); +exit; + +sub join_quote +{ + my (@list)=@_; my $i; + foreach $i (@list) { $i=$dbh->quote($i); } + return (join ',',@list); +} + +sub do_create_table +{ + my ($sth_key,$target_tbl,$extra_col_desc,$first_col_name)=@_; + my $create_table_query=$extra_col_desc; + my ($i,$type,$first_col_desc,$col_desc); + + for ($i=0;$i<$sth{$sth_key}->{NUM_OF_FIELDS};$i++) + { + if ($create_table_query) { $create_table_query.=", "; } + $type=$sth{$sth_key}->{mysql_type_name}->[$i]; + $col_desc=$type; + if ($type =~ /char|int/i) + { + $col_desc.="($sth{$sth_key}->{PRECISION}->[$i])"; + } + elsif ($type =~ /decimal|numeric/i) #(never seen that) + { + $col_desc.= + "($sth{$sth_key}->{PRECISION}->[$i],$sth{$sth_key}->{SCALE}->[$i])"; + } + elsif ($type !~ /date/i) #date and datetime are OK, + #no precision or scale for them + { + warn "unexpected column type '$type' +(neither 'char','int','decimal|numeric') +when creating $target_tbl, hope table creation will go OK\n"; + } + if ($i==0) {$first_col_desc=$col_desc}; + $create_table_query.= + ( ($i==0 and $first_col_name) ? + "$first_col_name " :"`$sth{$sth_key}->{NAME}->[$i]` " ) + .$col_desc; + } +if ($create_table_query) +{ + $dbh->do("CREATE TABLE IF NOT EXISTS $target_tbl ($create_table_query)"); +} +return $first_col_desc; +} + +__END__ + + +=head1 DESCRIPTION + +mysql_tableinfo asks a MySQL server information about its +databases, tables, table columns and index, and stores this +in tables called `db`, `tbl` (or `tbl_status`), `col`, `idx` +(with an optional prefix specified with --prefix). +After that, you can query these information tables, for example +to build your admin scripts with SQL queries, like + +SELECT CONCAT("CHECK TABLE ",`database`,".",`table`," EXTENDED;") +FROM info.tbl WHERE ... ; + +as people usually do with some other RDBMS +(note: to increase the speed of your queries on the info tables, +you may add some index on them). + +The database_like_wild and table_like_wild instructs the program +to gather information only about databases and tables +whose names match these patterns. If the info +tables already exist, their rows matching the patterns are simply +deleted and replaced by the new ones. That is, +old rows not matching the patterns are not touched. +If the database_like_wild and table_like_wild arguments +are not specified on the command-line they default to "%". + +The program : + +- does CREATE DATABASE IF NOT EXISTS database_to_write +where database_to_write is the database name specified on the command-line. + +- does CREATE TABLE IF NOT EXISTS database_to_write.`db` + +- fills database_to_write.`db` with the output of +SHOW DATABASES LIKE database_like_wild + +- does CREATE TABLE IF NOT EXISTS database_to_write.`tbl` +(respectively database_to_write.`tbl_status` +if the --tbl-status option is on) + +- for every found database, +fills database_to_write.`tbl` (respectively database_to_write.`tbl_status`) +with the output of +SHOW TABLES FROM found_db LIKE table_like_wild +(respectively SHOW TABLE STATUS FROM found_db LIKE table_like_wild) + +- if the --col option is on, + * does CREATE TABLE IF NOT EXISTS database_to_write.`col` + * for every found table, + fills database_to_write.`col` with the output of + SHOW COLUMNS FROM found_tbl FROM found_db + +- if the --idx option is on, + * does CREATE TABLE IF NOT EXISTS database_to_write.`idx` + * for every found table, + fills database_to_write.`idx` with the output of + SHOW INDEX FROM found_tbl FROM found_db + +Some options may modify this general scheme (see below). + +As mentioned, the contents of the info tables are the output of +SHOW commands. In fact the contents are slightly more complete : + +- the `tbl` (or `tbl_status`) info table + has an extra column which contains the database name, + +- the `col` info table + has an extra column which contains the table name, + and an extra column which contains, for each described column, + the number of this column in the table owning it (this extra column + is called `Seq_in_table`). `Seq_in_table` makes it possible for you + to retrieve your columns in sorted order, when you are querying + the `col` table. + +- the `index` info table + has an extra column which contains the database name. + +Caution: info tables contain certain columns (e.g. +Database, Table, Null...) whose names, as they are MySQL reserved words, +need to be backquoted (`...`) when used in SQL statements. + +=head1 OPTIONS + +=over 4 + +=item --clear + +Does DROP TABLE on the info tables (only those that the program is +going to fill, for example if you do not use --col it won't drop +the `col` table) and processes normally. Does not drop database_to_write. + +=item --clear-only + +Same as --clear but exits after the DROPs. + +=item --col + +Adds columns information (into table `col`). + +=item --idx + +Adds index information (into table `idx`). + +=item --prefix prefix + +The info tables are named from the concatenation of prefix and, +respectively, db, tbl (or tbl_status), col, idx. Do not quote ('') +or backquote (``) prefix. + +=item -q, --quiet + +Does not warn you about what the script is going to do (DROP TABLE etc) +and does not ask for a confirmation before starting. + +=item --tbl-status + +Instead of using SHOW TABLES, uses SHOW TABLE STATUS +(much more complete information, but slower). + +=item --help + +Display helpscreen and exit + +=item -u, --user=# + +user for database login if not current user. Give a user +who has sufficient privileges (CREATE, ...). + +=item -p, --password=# + +password to use when connecting to server + +=item -h, --host=# + +host to connect to + +=item -P, --port=# + +port to use when connecting to server + +=item -S, --socket=# + +UNIX domain socket to use when connecting to server + +=head1 WARRANTY + +This software is free and comes without warranty of any kind. You +should never trust backup software without studying the code yourself. +Study the code inside this script and only rely on it if I believe +that it does the right thing for you. + +Patches adding bug fixes, documentation and new features are welcome. + +=head1 TO DO + +Use extended inserts to be faster (for servers with many databases +or tables). But to do that, must care about net-buffer-length. + +=head1 AUTHOR + +2002-06-18 Guilhem Bichot (guilhem.bichot@mines-paris.org) + +And all the authors of mysqlhotcopy, which served as a model for +the structure of the program. diff --git a/sql-bench/crash-me.sh b/sql-bench/crash-me.sh index 9572143ae53..d66e8f47d6a 100644 --- a/sql-bench/crash-me.sh +++ b/sql-bench/crash-me.sh @@ -38,7 +38,7 @@ # as such, and clarify ones such as "mediumint" with comments such as # "3-byte int" or "same as xxx". -$version="1.57"; +$version="1.58"; use DBI; use Getopt::Long; @@ -2186,20 +2186,20 @@ EOF print <{AutoCommit})}; if (!$@) { @@ -2579,7 +2577,7 @@ sub check_and_report print "$prompt: " if (!defined($skip_prompt)); if (!defined($limits{$limit})) { - save_config_data($limit,"incompleted",$prompt); + save_incomplete($limit,$prompt); $tmp=1-safe_query(\@$pre); $tmp=safe_query_result($query,$answer,$string_type) if (!$tmp); safe_query(\@$post); @@ -2615,7 +2613,7 @@ sub try_and_report if (!defined($limits{$limit})) { - save_config_data($limit,"incompleted",$prompt); + save_incomplete($limit,$prompt); $type="no"; # Not supported foreach $test (@tests) { @@ -2695,7 +2693,8 @@ sub safe_query_result $sth->finish; return ($result_type == 8) ? 0 : 1; } - if($result_type == 8) { + if ($result_type == 8) + { $sth->finish; return 1; } @@ -2787,7 +2786,7 @@ sub find_limit() print "$end (cache)\n"; return $end; } - save_config_data($limit,"incompleted",$prompt); + save_incomplete($limit,$prompt); if (defined($query->{'init'}) && !defined($end=$limits{'restart'}{'tohigh'})) { @@ -2961,6 +2960,16 @@ sub save_all_config_data close CONFIG_FILE; } +# +# Save 'incomplete' in the limits file to be able to continue if +# crash-me dies because of a bug in perl/DBI + +sub save_incomplete +{ + my ($limit,$prompt)= @_; + save_config_data($limit,"incompleted",$prompt) if ($opt_restart); +} + sub check_repeat { diff --git a/sql-bench/limits/mysql.cfg b/sql-bench/limits/mysql.cfg index cd4aea7dcf5..306ce2d7b33 100644 --- a/sql-bench/limits/mysql.cfg +++ b/sql-bench/limits/mysql.cfg @@ -1,4 +1,4 @@ -#This file is automaticly generated by crash-me 1.57 +#This file is automaticly generated by crash-me 1.58 NEG=yes # update of column= -column Need_cast_for_null=no # Need to cast NULL for arithmetic @@ -36,7 +36,7 @@ constraint_check=no # Column constraints constraint_check_table=no # Table constraints constraint_null=yes # NULL constraint (SyBase style) crash_me_safe=yes # crash me safe -crash_me_version=1.57 # crash me version +crash_me_version=1.58 # crash me version create_default=yes # default value for column create_default_func=no # default value function for column create_if_not_exists=yes # create table if not exists @@ -333,7 +333,7 @@ max_char_size=255 # max char() size max_column_name=64 # column name length max_columns=3398 # Columns in table max_conditions=85660 # OR and AND in WHERE -max_expressions=856 # simple expressions +max_expressions=686 # simple expressions max_index=32 # max index max_index_length=500 # index length max_index_name=64 # index name length @@ -343,7 +343,7 @@ max_index_varchar_part_length=255 # index varchar part length max_row_length=65534 # max table row length (without blobs) max_row_length_with_null=65502 # table row length with nulls (without blobs) max_select_alias_name=+512 # select alias name length -max_stack_expression=856 # stacked expressions +max_stack_expression=490 # stacked expressions max_table_alias_name=+512 # table alias name length max_table_name=64 # table name length max_text_size=1048543 # max text or blob size @@ -396,7 +396,7 @@ select_limit2=yes # SELECT with LIMIT #,# select_string_size=1048565 # constant string size in SELECT select_table_update=no # Update with sub select select_without_from=yes # SELECT without FROM -server_version=MySQL 4.0.2 alpha debug # server version +server_version=MySQL 4.0.2 alpha # server version simple_joins=yes # ANSI SQL simple joins storage_of_float=round # Storage of float values subqueries=no # subqueries diff --git a/sql/hostname.cc b/sql/hostname.cc index a93af8b273e..abccc466a22 100644 --- a/sql/hostname.cc +++ b/sql/hostname.cc @@ -57,8 +57,8 @@ void hostname_cache_refresh() bool hostname_cache_init() { - host_entry *tmp; - uint offset= (uint) ((char*) (&tmp->ip) - (char*) tmp); + host_entry tmp; + uint offset= (uint) ((char*) (&tmp.ip) - (char*) &tmp); (void) pthread_mutex_init(&LOCK_hostname,MY_MUTEX_INIT_SLOW); if (!(hostname_cache=new hash_filo(HOST_CACHE_SIZE, offset, diff --git a/sql/item_func.cc b/sql/item_func.cc index accc5219a71..2d800cddb0d 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2047,13 +2047,14 @@ err: return 0; } + void Item_func_match::init_search(bool no_order) { if (ft_handler) return; if (key == NO_SUCH_KEY) - concat=new Item_func_concat_ws (new Item_string(" ",1), fields); + concat= new Item_func_concat_ws(new Item_string(" ",1), fields); if (master) { @@ -2071,7 +2072,7 @@ void Item_func_match::init_search(bool no_order) // MATCH ... AGAINST (NULL) is meaningless, but possible if (!(ft_tmp=key_item()->val_str(&tmp2))) { - ft_tmp=&tmp2; + ft_tmp= &tmp2; tmp2.set("",0); } @@ -2087,6 +2088,7 @@ void Item_func_match::init_search(bool no_order) } } + bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist) { List_iterator li(fields); diff --git a/sql/item_func.h b/sql/item_func.h index 35f17d1686b..57147b6336f 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -171,9 +171,22 @@ class Item_num_op :public Item_func bool is_null() { (void) val(); return null_value; } Field *tmp_table_field(TABLE *t_arg) { - if (!t_arg) return result_field; - return args[0]->result_type() == INT_RESULT ? ((max_length > 11) ? (Field *)new Field_longlong(max_length,maybe_null,name, t_arg,unsigned_flag) : (Field *)new Field_long(max_length,maybe_null,name, t_arg,unsigned_flag)) : (Field *) new Field_double(max_length, maybe_null, name,t_arg,decimals); - } + Field *res; + if (!t_arg) + return result_field; + if (args[0]->result_type() == INT_RESULT) + { + if (max_length > 11) + res= new Field_longlong(max_length, maybe_null, name, t_arg, + unsigned_flag); + else + res= new Field_long(max_length, maybe_null, name, t_arg, + unsigned_flag); + } + else + res= new Field_double(max_length, maybe_null, name, t_arg, decimals); + return res; + } }; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 1637546e09c..a22299b0af0 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -75,7 +75,7 @@ char* query_table_status(THD *thd,const char *db,const char *table_name); #define MAX_FIELDS_BEFORE_HASH 32 #define USER_VARS_HASH_SIZE 16 #define STACK_MIN_SIZE 8192 // Abort if less stack during eval. -#define STACK_BUFF_ALLOC 32 // For stack overrun checks +#define STACK_BUFF_ALLOC 64 // For stack overrun checks #ifndef MYSQLD_NET_RETRY_COUNT #define MYSQLD_NET_RETRY_COUNT 10 // Abort read after this many int. #endif diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 33574a81431..2a76229ecf9 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -67,7 +67,9 @@ public: SEL_ARG(Field *field, uint8 part, char *min_value, char *max_value, uint8 min_flag, uint8 max_flag, uint8 maybe_flag); SEL_ARG(enum Type type_arg) - :elements(1),use_count(1),left(0),next_key_part(0),type(type_arg) {} + :elements(1),use_count(1),left(0),next_key_part(0),color(BLACK), + type(type_arg) + {} inline bool is_same(SEL_ARG *arg) { if (type != arg->type) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f3b5f45ae6b..b5d5e14f9aa 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -345,13 +345,12 @@ char uc_update_queries[SQLCOM_END]; static bool check_mqh(THD *thd, uint check_command) { bool error=0; - DBUG_ENTER("check_mqh"); + time_t check_time = thd->start_time ? thd->start_time : time(NULL); USER_CONN *uc=thd->user_connect; + DBUG_ENTER("check_mqh"); DBUG_ASSERT(uc != 0); - bool my_start = thd->start_time != 0; - time_t check_time = (my_start) ? thd->start_time : time(NULL); - + /* If more than a hour since last check, reset resource checking */ if (check_time - uc->intime >= 3600) { (void) pthread_mutex_lock(&LOCK_user_conn); @@ -361,6 +360,7 @@ static bool check_mqh(THD *thd, uint check_command) uc->intime=check_time; (void) pthread_mutex_unlock(&LOCK_user_conn); } + /* Check that we have not done too many questions / hour */ if (uc->user_resources.questions && uc->questions++ >= uc->user_resources.questions) { @@ -371,14 +371,15 @@ static bool check_mqh(THD *thd, uint check_command) } if (check_command < (uint) SQLCOM_END) { - if (uc->user_resources.updates && uc_update_queries[check_command] && - ++(uc->updates) > uc->user_resources.updates) - { - net_printf(&thd->net, ER_USER_LIMIT_REACHED, uc->user, "max_updates", - (long) uc->user_resources.updates); - error=1; - goto end; - } + /* Check that we have not done too many updates / hour */ + if (uc->user_resources.updates && uc_update_queries[check_command] && + uc->updates++ >= uc->user_resources.updates) + { + net_printf(&thd->net, ER_USER_LIMIT_REACHED, uc->user, "max_updates", + (long) uc->user_resources.updates); + error=1; + goto end; + } } end: DBUG_RETURN(error); diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 43c24da85a2..9c458c27b95 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -21,6 +21,7 @@ #include "mysql_priv.h" #include "sql_select.h" #include +#include /* Intern key cache variables */ extern "C" pthread_mutex_t THR_LOCK_keycache; @@ -239,6 +240,17 @@ Open streams: %10lu\n", (ulong) cached_tables(), (ulong) my_file_opened, (ulong) my_stream_opened); + + ALARM_INFO alarm_info; + thr_alarm_info(&alarm_info); + printf("\nAlarm status:\n\ +Active alarms: %u\n\ +Max used alarms: %u\n\ +Next alarm time: %lu\n", + alarm_info.active_alarms, + alarm_info.max_used_alarms, + alarm_info.next_alarm_time); + fflush(stdout); if (thd) thd->proc_info="malloc";