From b9f09fc58803745f2c9de6bd2033ef9db538469d Mon Sep 17 00:00:00 2001 From: "jani@hynda.(none)" <> Date: Wed, 14 May 2003 13:49:43 +0300 Subject: Fixed documentation for mysql_fix_privilege_tables man page. Bug ID: 384 --- man/mysql_fix_privilege_tables.1 | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/man/mysql_fix_privilege_tables.1 b/man/mysql_fix_privilege_tables.1 index bf4e0e15dfa..4ed81368098 100644 --- a/man/mysql_fix_privilege_tables.1 +++ b/man/mysql_fix_privilege_tables.1 @@ -2,7 +2,7 @@ .SH NAME mysql_fix_privilege_tables \- Fixes MySQL privilege tables. .SH SYNOPSIS -mysql_fix_privilege_tables [options] +mysql_fix_privilege_tables [mysql_root_password] .SH DESCRIPTION This scripts updates the mysql.user, mysql.db, mysql.host and the mysql.func tables to MySQL 3.22.14 and above. @@ -10,10 +10,9 @@ mysql.func tables to MySQL 3.22.14 and above. This is needed if you want to use the new GRANT functions, CREATE AGGREGATE FUNCTION or want to use the more secure passwords in 3.23 -If you get 'Access denied' errors, you should run this script again -and give the MySQL root user password as an argument! +If you get 'Access denied' errors, run the script again +and give the MySQL root user password as an argument. -For more information start the program with '--help'. .SH "SEE ALSO" mysql (1), mysqld (1) .SH AUTHOR -- cgit v1.2.1 From c9d76b51cf004a8dd559c350dd21c1499dd5dc7a Mon Sep 17 00:00:00 2001 From: "jani@hynda.(none)" <> Date: Wed, 14 May 2003 16:47:55 +0300 Subject: Fixed a bug with having comments after options in config files. Bug ID: 235 --- mysys/default.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/mysys/default.c b/mysys/default.c index c47d2719ab5..3ff240da3a1 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -72,6 +72,7 @@ static my_bool search_default_file(DYNAMIC_ARRAY *args,MEM_ROOT *alloc, const char *dir, const char *config_file, const char *ext, TYPELIB *group); +static char *remove_end_comment(char *ptr); void load_defaults(const char *conf_file, const char **groups, int *argc, char ***argv) @@ -297,9 +298,11 @@ static my_bool search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, } if (!read_values) continue; - if (!(end=value=strchr(ptr,'='))) - end=strend(ptr); /* Option without argument */ + end= remove_end_comment(ptr); + if ((value= strchr(ptr, '='))) + end= value; /* Option without argument */ for ( ; isspace(end[-1]) ; end--) ; + if (!value) { if (!(tmp=alloc_root(alloc,(uint) (end-ptr)+3))) @@ -368,6 +371,29 @@ static my_bool search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, } +static char *remove_end_comment(char *ptr) +{ + char quote= 0; + + for (; *ptr; ptr++) + { + if (*ptr == '\'' || *ptr == '\"') + { + if (!quote) + quote= *ptr; + else if (quote == *ptr) + quote= 0; + } + if (!quote && *ptr == '#') /* We are not inside a comment */ + { + *ptr= 0; + return ptr; + } + } + return ptr; +} + + void print_defaults(const char *conf_file, const char **groups) { #ifdef __WIN__ -- cgit v1.2.1 From 9556cb171aaad69dd7ac2f099fd3914ccd2c9517 Mon Sep 17 00:00:00 2001 From: "lenz@mysql.com" <> Date: Mon, 19 May 2003 16:36:50 +0200 Subject: - Tagged ChangeSet 1.1497 as "mysql-4.0.13" - Updated version number in configure.in to 4.0.14 now that 4.0.13 has been tagged --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index c7cf4f66b70..df83f7e715e 100644 --- a/configure.in +++ b/configure.in @@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! -AM_INIT_AUTOMAKE(mysql, 4.0.13) +AM_INIT_AUTOMAKE(mysql, 4.0.14) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 -- cgit v1.2.1 From 09348e271ac4b4333fc1e29d96ba402c505fc6c5 Mon Sep 17 00:00:00 2001 From: "vva@eagle.mysql.r18.ru" <> Date: Wed, 21 May 2003 14:54:02 -0400 Subject: fixed 'STARTING BY' in replication --- mysql-test/r/rpl_loaddata.result | 2 +- mysql-test/std_data/rpl_loaddata2.dat | 8 ++++---- mysql-test/t/rpl_loaddata.test | 3 +-- sql/log_event.cc | 12 ++++++++++-- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/rpl_loaddata.result b/mysql-test/r/rpl_loaddata.result index c1518e8e29a..62071a07d0c 100644 --- a/mysql-test/r/rpl_loaddata.result +++ b/mysql-test/r/rpl_loaddata.result @@ -7,7 +7,7 @@ slave start; create table t1(a int not null auto_increment, b int, primary key(a) ); load data infile '../../std_data/rpl_loaddata.dat' into table t1; create temporary table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60)); -load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by '\n##\n' ignore 1 lines; +load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by '\n##\n' starting by '>' ignore 1 lines; create table t3 (day date,id int(9),category enum('a','b','c'),name varchar(60)); insert into t3 select * from t2; select * from t1; diff --git a/mysql-test/std_data/rpl_loaddata2.dat b/mysql-test/std_data/rpl_loaddata2.dat index 7a3d4ea7695..b883d9dcd58 100644 --- a/mysql-test/std_data/rpl_loaddata2.dat +++ b/mysql-test/std_data/rpl_loaddata2.dat @@ -1,8 +1,8 @@ -2003-01-21,6328,%a%,%aaaaa% +>2003-01-21,6328,%a%,%aaaaa% ## -2003-02-22,2461,b,%a a a @@ @% @b ' " a% +>2003-02-22,2461,b,%a a a @@ @% @b ' " a% ## -2003-03-22,2161,%c%,%asdf% +>2003-03-22,2161,%c%,%asdf% ## -2003-04-22,2416,%a%,%bbbbb% +>2003-04-22,2416,%a%,%bbbbb% ## diff --git a/mysql-test/t/rpl_loaddata.test b/mysql-test/t/rpl_loaddata.test index 2acb67dfce2..1f34aa9d3f9 100644 --- a/mysql-test/t/rpl_loaddata.test +++ b/mysql-test/t/rpl_loaddata.test @@ -10,8 +10,7 @@ create table t1(a int not null auto_increment, b int, primary key(a) ); load data infile '../../std_data/rpl_loaddata.dat' into table t1; create temporary table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60)); -#load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields terminated by ',' optionaly enclosed by '%' escaped by '@' lines terminated by '\n%%\n' ignore 1 lines; - load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by '\n##\n' ignore 1 lines; +load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by '\n##\n' starting by '>' ignore 1 lines; create table t3 (day date,id int(9),category enum('a','b','c'),name varchar(60)); insert into t3 select * from t2; diff --git a/sql/log_event.cc b/sql/log_event.cc index 3b499b8d502..dfa44e19ffc 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -309,15 +309,19 @@ void Load_log_event::pack_info(String* packet) pretty_print_str(&tmp, sql_ex.escaped, sql_ex.escaped_len); } + bool line_lexem_added= false; if (sql_ex.line_term_len) { tmp.append(" LINES TERMINATED BY "); pretty_print_str(&tmp, sql_ex.line_term, sql_ex.line_term_len); + line_lexem_added= true; } if (sql_ex.line_start_len) { - tmp.append(" LINES STARTING BY "); + if (!line_lexem_added) + tmp.append(" LINES"); + tmp.append(" STARTING BY "); pretty_print_str(&tmp, sql_ex.line_start, sql_ex.line_start_len); } @@ -1299,15 +1303,19 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db) pretty_print_str(file, sql_ex.escaped, sql_ex.escaped_len); } + bool line_lexem_added= false; if (sql_ex.line_term) { fprintf(file," LINES TERMINATED BY "); pretty_print_str(file, sql_ex.line_term, sql_ex.line_term_len); + line_lexem_added= true; } if (sql_ex.line_start) { - fprintf(file," LINES STARTING BY "); + if (!line_lexem_added) + fprintf(file," LINES"); + fprintf(file," STARTING BY "); pretty_print_str(file, sql_ex.line_start, sql_ex.line_start_len); } -- cgit v1.2.1 From be9024e7cedd68a504478817e4b04815c0dc2fa3 Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Wed, 21 May 2003 21:58:12 +0300 Subject: repair_part2 is made repeatable --- mysql-test/mysql-test-run.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 7ce6ffe14af..65f40c5dc73 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -19,6 +19,8 @@ TZ=GMT-3; export TZ # for UNIX_TIMESTAMP tests to work # Program Definitions #-- +LC_COLLATE=C +export LC_COLLATE PATH=/bin:/usr/bin:/usr/local/bin:/usr/bsd:/usr/X11R6/bin:/usr/openwin/bin:/usr/bin/X11:$PATH MASTER_40_ARGS="--rpl-recovery-rank=1 --init-rpl-role=master" -- cgit v1.2.1 From 4ae8af4ae2e3d6ab37d0257133faf854fd37b520 Mon Sep 17 00:00:00 2001 From: "vva@eagle.mysql.r18.ru" <> Date: Wed, 21 May 2003 15:16:56 -0400 Subject: fixed "LINES STARTING" in load data replication --- BitKeeper/etc/logging_ok | 1 + sql/log_event.cc | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index a6699f7c515..705b336440b 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -35,5 +35,6 @@ serg@build.mysql2.com serg@serg.mysql.com serg@sergbook.mysql.com sinisa@rhols221.adsl.netsonic.fi +vva@eagle.mysql.r18.ru walrus@mysql.com zak@balfor.local diff --git a/sql/log_event.cc b/sql/log_event.cc index 7c4c893a823..9cf67e78029 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -697,15 +697,19 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db) pretty_print_char(file, sql_ex.escaped); } + bool line_lexem_added= false; if(!(sql_ex.empty_flags & LINE_TERM_EMPTY)) { fprintf(file," LINES TERMINATED BY "); pretty_print_char(file, sql_ex.line_term); + line_lexem_added= true; } if(!(sql_ex.empty_flags & LINE_START_EMPTY)) { - fprintf(file," LINES STARTING BY "); + if (!line_lexem_added) + fprintf(file," LINES"); + fprintf(file," STARTING BY "); pretty_print_char(file, sql_ex.line_start); } -- cgit v1.2.1 From 4ac8d7b9637c3a9325b5ecd8f77d95ca62d92971 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Thu, 22 May 2003 00:05:33 +0300 Subject: row0ins.c: Disable UNIQU KEY error reporting in SHOW INNODB STATUS until we know if it slows down REPLACE significantly --- innobase/row/row0ins.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index 3af9e1b752b..e96c08a715b 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -1275,6 +1275,10 @@ row_ins_unique_report_err( dtuple_t* entry, /* in: index entry to insert in the index */ dict_index_t* index) /* in: index */ { +#ifdef notdefined + /* Disable reporting to test if the slowdown of REPLACE in 4.0.13 was + caused by this! */ + char* buf = dict_unique_err_buf; /* The foreign err mutex protects also dict_unique_err_buf */ @@ -1303,6 +1307,7 @@ row_ins_unique_report_err( ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); mutex_exit(&dict_foreign_err_mutex); +#endif } /******************************************************************* -- cgit v1.2.1 From 5d097b431b6b50a8535d6284b4ebb2acb98c1717 Mon Sep 17 00:00:00 2001 From: "lenz@mysql.com" <> Date: Fri, 23 May 2003 11:38:37 +0200 Subject: - Portability fix: FreeBSD 4.8-STABLE (480101) and 5.0-CURRENT (500110) now have a thread safe realpath(3) implementation - added check to only define -DHAVE_BROKEN_REALPATH where required (thanks to Martin Blapp from the FreeBSD team for the patch) --- configure.in | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index df83f7e715e..8a5ab75a494 100644 --- a/configure.in +++ b/configure.in @@ -1025,8 +1025,16 @@ case $SYSTEM_TYPE in ;; *freebsd*) echo "Adding fix for interrupted reads" - CFLAGS="$CFLAGS -DHAVE_BROKEN_REALPATH" - CXXFLAGS="$CXXFLAGS -DMYSQLD_NET_RETRY_COUNT=1000000 -DHAVE_BROKEN_REALPATH" + OSVERSION=`sysctl -a | grep osreldate | awk '{ print $2 }'` + if test "$OSVERSION" -gt "480100" && \ + test "$OSVERSION" -lt "500000" || \ + test "$OSVERSION" -gt "500109" + then + CXXFLAGS="$CXXFLAGS -DMYSQLD_NET_RETRY_COUNT=1000000" + else + CFLAGS="$CFLAGS -DHAVE_BROKEN_REALPATH" + CXXFLAGS="$CXXFLAGS -DMYSQLD_NET_RETRY_COUNT=1000000 -DHAVE_BROKEN_REALPATH" + fi ;; *netbsd*) echo "Adding flag -Dunix" -- cgit v1.2.1 From 0b875e908ff703cb42853c22f255368e6ed673ec Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Fri, 23 May 2003 16:40:21 +0200 Subject: Fix for #468 [Ver]: SHOW VARIABLES trims innodb_data_file_path (this bug was already fixed in 4.0, I just copied and pasted two lines). --- sql/ha_innobase.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sql/ha_innobase.cc b/sql/ha_innobase.cc index b8a794a61a0..34ad45bfb18 100644 --- a/sql/ha_innobase.cc +++ b/sql/ha_innobase.cc @@ -107,6 +107,8 @@ my_bool innobase_log_archive = FALSE; my_bool innobase_use_native_aio = FALSE; my_bool innobase_fast_shutdown = TRUE; +static char *internal_innobase_data_file_path = NULL; + /* innodb_flush_log_at_trx_commit can now have 3 values: 0 : write to the log file once per second and flush it to disk; 1 : write to the log file at each commit and flush it to disk; @@ -522,8 +524,14 @@ innobase_init(void) srv_arch_dir = (innobase_log_arch_dir ? innobase_log_arch_dir : current_dir); - ret = (bool) - srv_parse_data_file_paths_and_sizes(innobase_data_file_path, + /* Since InnoDB edits the argument in the next call, we make another + copy of it: */ + + internal_innobase_data_file_path = my_strdup(innobase_data_file_path, + MYF(MY_WME)); + + ret = (bool) srv_parse_data_file_paths_and_sizes( + internal_innobase_data_file_path, &srv_data_file_names, &srv_data_file_sizes, &srv_data_file_is_raw_partition, -- cgit v1.2.1 From 319404ab94ad0f7f0ef8115385f21feb35c2a3d3 Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Fri, 23 May 2003 18:20:57 +0200 Subject: Outcome of discussions with Lenz and Monty about handling ccache in the build commands. --- BUILD/SETUP.sh | 18 +++++++++++++++++- configure.in | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index 55b82e38d63..150f9e28b41 100644 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -71,6 +71,22 @@ else make=make fi -if test -z $CXX ; then +if test -z "$CXX" ; then CXX=gcc fi + +# If ccache (a compiler cache which reduces build time) +# (http://samba.org/ccache) is installed, use it. +# We use 'grep' and hope 'grep' will work as expected +# (returns 0 if finds lines) +if ccache -V > /dev/null 2>&1 +then + if ! (echo "$CC" | grep "ccache" > /dev/null) + then + CC="ccache $CC" + fi + if ! (echo "$CXX" | grep "ccache" > /dev/null) + then + CXX="ccache $CXX" + fi +fi diff --git a/configure.in b/configure.in index c7cf4f66b70..5c794714889 100644 --- a/configure.in +++ b/configure.in @@ -361,7 +361,7 @@ then # we will gets some problems when linking static programs. # The following code is used to fix this problem. - if test "$CXX" = "gcc" + if test "$CXX" = "gcc" -o "$CXX" = "ccache gcc" then if $CXX -v 2>&1 | grep 'version 3' > /dev/null 2>&1 then -- cgit v1.2.1 From 8a1e18f4cb56e2c8a41e637e60186c1824f8ed16 Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Sat, 24 May 2003 16:43:53 +0200 Subject: Fix for bug #490 and #491 (see details below) --- mysql-test/r/insert_select.result | 14 ++++++++++++++ mysql-test/r/rpl_insert_id.result | 28 ++++++++++++++++++++++++++++ mysql-test/t/insert_select.test | 19 +++++++++++++++++++ mysql-test/t/rpl_insert_id.test | 33 +++++++++++++++++++++++++++------ sql/sql_insert.cc | 24 +++++++++++++++++++++--- 5 files changed, 109 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result index e24c3179a0c..b49ca3a6c2f 100644 --- a/mysql-test/r/insert_select.result +++ b/mysql-test/r/insert_select.result @@ -66,3 +66,17 @@ INSERT INTO crash1 (numeropost,icone,contenu,pseudo,date,signature,ip) SELECT 1718,icone,contenu,pseudo,date,signature,ip FROM crash2 WHERE numeropost=9 ORDER BY numreponse ASC; DROP TABLE IF EXISTS crash1,crash2; +drop table if exists t1; +drop table if exists t2; +create table t1(a int, unique(a)); +insert into t1 values(2); +create table t2(a int); +insert into t2 values(1),(2); +reset master; +insert into t1 select * from t2; +Duplicate entry '2' for key 1 +show binlog events; +Log_name Pos Event_type Server_id Orig_log_pos Info +master-bin.001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3 +master-bin.001 79 Query 1 79 use test; insert into t1 select * from t2 +drop table t1, t2; diff --git a/mysql-test/r/rpl_insert_id.result b/mysql-test/r/rpl_insert_id.result index d524818985e..6d996481a5c 100644 --- a/mysql-test/r/rpl_insert_id.result +++ b/mysql-test/r/rpl_insert_id.result @@ -39,3 +39,31 @@ b c 6 11 drop table t1; drop table t2; +create table t1(a int auto_increment, key(a)); +create table t2(b int auto_increment, c int, key(b)); +insert into t1 values (10); +insert into t1 values (null),(null),(null); +insert into t2 values (5,0); +insert into t2 (c) select * from t1; +select * from t2; +b c +5 0 +6 10 +7 11 +8 12 +9 13 +select * from t1; +a +10 +11 +12 +13 +select * from t2; +b c +5 0 +6 10 +7 11 +8 12 +9 13 +drop table t1; +drop table t2; diff --git a/mysql-test/t/insert_select.test b/mysql-test/t/insert_select.test index 42f65858d77..695f891f678 100644 --- a/mysql-test/t/insert_select.test +++ b/mysql-test/t/insert_select.test @@ -68,3 +68,22 @@ WHERE numeropost=9 ORDER BY numreponse ASC; DROP TABLE IF EXISTS crash1,crash2; + +# Addendum by Guilhem: +# Check if a partly-completed INSERT SELECT in a MyISAM table goes +# into the binlog +drop table if exists t1; +drop table if exists t2; +create table t1(a int, unique(a)); +insert into t1 values(2); +create table t2(a int); +insert into t2 values(1),(2); +reset master; +--error 1062 +insert into t1 select * from t2; +# The above should produce an error, but still be in the binlog; +# verify the binlog : +let $VERSION=`select version()`; +--replace_result $VERSION VERSION +show binlog events; +drop table t1, t2; diff --git a/mysql-test/t/rpl_insert_id.test b/mysql-test/t/rpl_insert_id.test index 3f3636d3082..3478aedf3eb 100644 --- a/mysql-test/t/rpl_insert_id.test +++ b/mysql-test/t/rpl_insert_id.test @@ -1,6 +1,7 @@ -#see if queries that use both -#auto_increment and LAST_INSERT_ID() -#are replicated well +# see if queries that use both +# auto_increment and LAST_INSERT_ID() +# are replicated well + source include/master-slave.inc; connection master; drop table if exists t1; @@ -15,9 +16,11 @@ sync_with_master; select * from t1; select * from t2; connection master; -#check if multi-line inserts, -#which set last_insert_id to the first id inserted, -#are replicated the same way + +# check if multi-line inserts, +# which set last_insert_id to the first id inserted, +# are replicated the same way + drop table t1; drop table t2; create table t1(a int auto_increment, key(a)); @@ -32,6 +35,24 @@ sync_with_master; select * from t1; select * from t2; connection master; + +# check if INSERT SELECT in auto_increment is well replicated (bug #490) + +drop table t1; +drop table t2; +create table t1(a int auto_increment, key(a)); +create table t2(b int auto_increment, c int, key(b)); +insert into t1 values (10); +insert into t1 values (null),(null),(null); +insert into t2 values (5,0); +insert into t2 (c) select * from t1; +select * from t2; +save_master_pos; +connection slave; +sync_with_master; +select * from t1; +select * from t2; +connection master; drop table t1; drop table t2; save_master_pos; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 33a13fabdc6..167ccf974c7 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1350,6 +1350,24 @@ void select_insert::send_error(uint errcode,const char *err) ::send_error(&thd->net,errcode,err); table->file->extra(HA_EXTRA_NO_CACHE); table->file->activate_all_index(thd); + /* + If at least one row has been inserted/modified and will stay in the table + (the table doesn't have transactions) (example: we got a duplicate key + error while inserting into a MyISAM table) we must write to the binlog (and + the error code will make the slave stop). + */ + if ((info.copied || info.deleted) && !table->file->has_transactions()) + { + if (last_insert_id) + thd->insert_id(last_insert_id); // For binary log + mysql_update_log.write(thd,thd->query,thd->query_length); + if (mysql_bin_log.is_open()) + { + Query_log_event qinfo(thd, thd->query, thd->query_length, + table->file->has_transactions()); + mysql_bin_log.write(&qinfo); + } + } ha_rollback_stmt(thd); if (info.copied || info.deleted) { @@ -1365,7 +1383,10 @@ bool select_insert::send_eof() error=table->file->activate_all_index(thd); table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); + if (last_insert_id) + thd->insert_id(last_insert_id); // For binary log /* Write to binlog before commiting transaction */ + mysql_update_log.write(thd,thd->query,thd->query_length); if (mysql_bin_log.is_open()) { Query_log_event qinfo(thd, thd->query, thd->query_length, @@ -1393,10 +1414,7 @@ bool select_insert::send_eof() else sprintf(buff,ER(ER_INSERT_INFO),info.records,info.deleted, thd->cuted_fields); - if (last_insert_id) - thd->insert_id(last_insert_id); // For update log ::send_ok(&thd->net,info.copied+info.deleted,last_insert_id,buff); - mysql_update_log.write(thd,thd->query,thd->query_length); return 0; } } -- cgit v1.2.1 From 11ae9595c74f05265ed98ea8d4346869dd65ce92 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Sun, 25 May 2003 23:37:32 +0300 Subject: log.cc: If FOREIGN_KEY_CHECKS=0, wrap in binlog SQL statements inside SET FOREIGN_...=0; ... ; SET FOREIGN_...=1 --- sql/log.cc | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/sql/log.cc b/sql/log.cc index 79ee59eedf8..8bf51100147 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1071,6 +1071,12 @@ bool MYSQL_LOG::write(Log_event* event_info) No check for auto events flag here - this write method should never be called if auto-events are enabled */ + + /* + 1. Write first log events which describe the 'run environment' + of the SQL command + */ + if (thd) { if (thd->last_insert_id_used) @@ -1109,11 +1115,50 @@ bool MYSQL_LOG::write(Log_event* event_info) if (e.write(file)) goto err; } + + /* If the user has set FOREIGN_KEY_CHECKS=0 we wrap every SQL + command in the binlog inside: + SET FOREIGN_KEY_CHECKS=0; + ; + SET FOREIGN_KEY_CHECKS=1; */ + + if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) + { + char buf[256], *p; + p= strmov(buf, "SET FOREIGN_KEY_CHECKS=0"); + Query_log_event e(thd, buf, (ulong) (p - buf), 0); + e.set_log_pos(this); + if (e.write(file)) + goto err; + } } + + /* + 2. Write the SQL command + */ + event_info->set_log_pos(this); if (event_info->write(file) || - file == &log_file && flush_io_cache(file)) + file == &log_file && flush_io_cache(file)) goto err; + + /* + 3. Write log events to reset the 'run environment' of the SQL command + */ + + if (thd && thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) + { + char buf[256], *p; + + p= strmov(buf, "SET FOREIGN_KEY_CHECKS=1"); + Query_log_event e(thd, buf, (ulong) (p - buf), 0); + e.set_log_pos(this); + + if (e.write(file) || + file == &log_file && flush_io_cache(file)) + goto err; + } + error=0; /* -- cgit v1.2.1 From 9ed9ad5374e230dc971cd25155f0baa42c4cdb94 Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Sun, 25 May 2003 23:09:46 +0200 Subject: - Fix for memory leak if the SQL slave thread is killed just after reading an event. - A few more mutex locks and unlocks of rli.log_space_lock for doing clean reads of rli.ignore_log_space_limit - Broadcast after unlock, not before (small speed optimisation). --- sql/slave.cc | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/sql/slave.cc b/sql/slave.cc index e6215356ad1..b620603dc63 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1322,6 +1322,8 @@ static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli) !rli->ignore_log_space_limit) { pthread_cond_wait(&rli->log_space_cond, &rli->log_space_lock); + /* Re-acquire the mutex as pthread_cond_wait released it */ + pthread_mutex_lock(&rli->log_space_lock); } thd->proc_info = save_proc_info; pthread_mutex_unlock(&rli->log_space_lock); @@ -2028,7 +2030,11 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) Log_event * ev = next_event(rli); DBUG_ASSERT(rli->sql_thd==thd); if (sql_slave_killed(thd,rli)) + { + /* do not forget to free ev ! */ + if (ev) delete ev; return 1; + } if (ev) { int type_code = ev->get_type_code(); @@ -2302,6 +2308,18 @@ reconnect done to recover from failed read"); goto err; } flush_master_info(mi); + /* + See if the relay logs take too much space. + We don't lock mi->rli.log_space_lock here; this dirty read saves time + and does not introduce any problem: + - if mi->rli.ignore_log_space_limit is 1 but becomes 0 just after (so + the clean value is 0), then we are reading only one more event as we + should, and we'll block only at the next event. No big deal. + - if mi->rli.ignore_log_space_limit is 0 but becomes 1 just after (so + the clean value is 1), then we are going into wait_for_relay_log_space() + for no reason, but this function will do a clean read, notice the clean + value and exit immediately. + */ if (mi->rli.log_space_limit && mi->rli.log_space_limit < mi->rli.log_space_total && !mi->rli.ignore_log_space_limit) @@ -2416,7 +2434,9 @@ slave_begin: rli->pending = 0; //tell the I/O thread to take relay_log_space_limit into account from now on + pthread_mutex_lock(&rli->log_space_lock); rli->ignore_log_space_limit= 0; + pthread_mutex_unlock(&rli->log_space_lock); if (init_relay_log_pos(rli, rli->relay_log_name, @@ -3122,9 +3142,14 @@ Log_event* next_event(RELAY_LOG_INFO* rli) pthread_mutex_lock(&rli->log_space_lock); // prevent the I/O thread from blocking next times rli->ignore_log_space_limit= 1; - // If the I/O thread is blocked, unblock it - pthread_cond_broadcast(&rli->log_space_cond); + /* + If the I/O thread is blocked, unblock it. + Ok to broadcast after unlock, because the mutex is only destroyed in + ~st_relay_log_info(), i.e. when rli is destroyed, and rli will not be + destroyed before we exit the present function. + */ pthread_mutex_unlock(&rli->log_space_lock); + pthread_cond_broadcast(&rli->log_space_cond); // Note that wait_for_update unlocks lock_log ! rli->relay_log.wait_for_update(rli->sql_thd); // re-acquire data lock since we released it earlier -- cgit v1.2.1 From d46b0aa018d363400b5e98430a7190f146c04b79 Mon Sep 17 00:00:00 2001 From: "monty@mashka.mysql.fi" <> Date: Mon, 26 May 2003 05:57:27 +0300 Subject: Remove not used flag --- include/mysql_com.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/mysql_com.h b/include/mysql_com.h index fcc9abc5bcd..4ea1a77c836 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -86,7 +86,6 @@ enum enum_server_command {COM_SLEEP,COM_QUIT,COM_INIT_DB,COM_QUERY, #define CLIENT_ODBC 64 /* Odbc client */ #define CLIENT_LOCAL_FILES 128 /* Can use LOAD DATA LOCAL */ #define CLIENT_IGNORE_SPACE 256 /* Ignore spaces before '(' */ -#define CLIENT_CHANGE_USER 512 /* Support the mysql_change_user() */ #define CLIENT_INTERACTIVE 1024 /* This is an interactive client */ #define CLIENT_SSL 2048 /* Switch to SSL after handshake */ #define CLIENT_IGNORE_SIGPIPE 4096 /* IGNORE sigpipes */ -- cgit v1.2.1 From 9f3ade0670a5e3e58131401220c6a1bde58c3bc9 Mon Sep 17 00:00:00 2001 From: "monty@mashka.mysql.fi" <> Date: Mon, 26 May 2003 06:16:50 +0300 Subject: Added missing free for last patch --- sql/ha_innobase.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/ha_innobase.cc b/sql/ha_innobase.cc index 34ad45bfb18..d1db50dfa89 100644 --- a/sql/ha_innobase.cc +++ b/sql/ha_innobase.cc @@ -637,6 +637,7 @@ innobase_end(void) err = innobase_shutdown_for_mysql(); hash_free(&innobase_open_tables); + my_free(internal_innobase_data_file_path,MYF(MY_ALLOW_ZERO_PTR)); if (err != DB_SUCCESS) { -- cgit v1.2.1 From 102c477760e26a927a01db3d47a7fd0c7d875eca Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Mon, 26 May 2003 11:47:03 +0300 Subject: Added testing of LOAD DATA ... STARTING BY Added read_only variable --- mysql-test/r/loaddata.result | 7 +++++++ mysql-test/t/loaddata.test | 8 ++++++++ sql/log_event.cc | 3 +-- sql/set_var.cc | 5 ++--- sql/sql_update.cc | 1 - 5 files changed, 18 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/loaddata.result b/mysql-test/r/loaddata.result index d121a4e6c40..59153f3353a 100644 --- a/mysql-test/r/loaddata.result +++ b/mysql-test/r/loaddata.result @@ -8,4 +8,11 @@ a b c d 0000-00-00 0000-00-00 0000-00-00 0000-00-00 2003-03-03 2003-03-03 2003-03-03 NULL 2003-03-03 2003-03-03 2003-03-03 NULL +truncate table t1; +load data infile '../../std_data/loaddata1.dat' into table t1 fields terminated by ',' LINES STARTING BY ',' (b,c,d); +SELECT * from t1; +a b c d +NULL NULL 0000-00-00 0000-00-00 +NULL 0000-00-00 0000-00-00 0000-00-00 +NULL 2003-03-03 2003-03-03 NULL drop table t1; diff --git a/mysql-test/t/loaddata.test b/mysql-test/t/loaddata.test index ceb5c47af11..e63f0780e3e 100644 --- a/mysql-test/t/loaddata.test +++ b/mysql-test/t/loaddata.test @@ -8,4 +8,12 @@ create table t1 (a date, b date, c date not null, d date); load data infile '../../std_data/loaddata1.dat' into table t1 fields terminated by ','; load data infile '../../std_data/loaddata1.dat' into table t1 fields terminated by ',' IGNORE 2 LINES; SELECT * from t1; +truncate table t1; + +load data infile '../../std_data/loaddata1.dat' into table t1 fields terminated by ',' LINES STARTING BY ',' (b,c,d); +SELECT * from t1; drop table t1; + + + + diff --git a/sql/log_event.cc b/sql/log_event.cc index bbea89bfd3f..76151026590 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1946,8 +1946,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, sql_error= ER_UNKNOWN_ERROR; slave_print_error(rli,sql_error, "Error '%s' running load data infile", - sql_error ? thd->net.last_error : - ER_SAFE(ER_UNKNOWN_ERROR)); + ER_SAFE(sql_error)); free_root(&thd->mem_root,0); return 1; } diff --git a/sql/set_var.cc b/sql/set_var.cc index 2ca12cdb802..1da187598c4 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -185,6 +185,7 @@ sys_var_thd_ulong sys_net_retry_count("net_retry_count", sys_var_thd_bool sys_new_mode("new", &SV::new_mode); sys_var_thd_ulong sys_read_buff_size("read_buffer_size", &SV::read_buff_size); +sys_var_bool_ptr sys_readonly("read_only", &opt_readonly); sys_var_thd_ulong sys_read_rnd_buff_size("read_rnd_buffer_size", &SV::read_rnd_buff_size); sys_var_long_ptr sys_rpl_recovery_rank("rpl_recovery_rank", @@ -204,8 +205,6 @@ sys_var_bool_ptr sys_slave_compressed_protocol("slave_compressed_protocol", &opt_slave_compressed_protocol); sys_var_long_ptr sys_slave_net_timeout("slave_net_timeout", &slave_net_timeout); -sys_var_bool_ptr sys_readonly("read_only", - &opt_readonly); sys_var_long_ptr sys_slow_launch_time("slow_launch_time", &slow_launch_time); sys_var_thd_ulong sys_sort_buffer("sort_buffer_size", @@ -516,6 +515,7 @@ struct show_var_st init_vars[]= { {"port", (char*) &mysql_port, SHOW_INT}, {"protocol_version", (char*) &protocol_version, SHOW_INT}, {sys_read_buff_size.name, (char*) &sys_read_buff_size, SHOW_SYS}, + {sys_readonly.name, (char*) &sys_readonly, SHOW_SYS}, {sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS}, {sys_rpl_recovery_rank.name,(char*) &sys_rpl_recovery_rank, SHOW_SYS}, #ifdef HAVE_QUERY_CACHE @@ -525,7 +525,6 @@ struct show_var_st init_vars[]= { #endif /* HAVE_QUERY_CACHE */ {sys_server_id.name, (char*) &sys_server_id, SHOW_SYS}, {sys_slave_net_timeout.name,(char*) &sys_slave_net_timeout, SHOW_SYS}, - {sys_readonly.name, (char*) &sys_readonly, SHOW_SYS}, {"skip_external_locking", (char*) &my_disable_locking, SHOW_MY_BOOL}, {"skip_networking", (char*) &opt_disable_networking, SHOW_BOOL}, {"skip_show_database", (char*) &opt_skip_show_db, SHOW_BOOL}, diff --git a/sql/sql_update.cc b/sql/sql_update.cc index ed4d6fd9b81..b4e7750addf 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -182,7 +182,6 @@ int mysql_update(THD *thd, */ uint length; SORT_FIELD *sortorder; - List fields; ha_rows examined_rows; table->io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE), -- cgit v1.2.1 From 48ecf0e8a7302ea4ab4e75307fc94da47bdc2017 Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Mon, 26 May 2003 13:10:08 +0300 Subject: Fixed core dump bug when shuting down mysqld --- include/thr_alarm.h | 2 +- mysys/thr_alarm.c | 75 +++++++++++++++++++++++++++++++++-------------------- sql/mysqld.cc | 7 ++--- 3 files changed, 52 insertions(+), 32 deletions(-) diff --git a/include/thr_alarm.h b/include/thr_alarm.h index 30825d49158..439f046252f 100644 --- a/include/thr_alarm.h +++ b/include/thr_alarm.h @@ -103,7 +103,7 @@ void init_thr_alarm(uint max_alarm); bool thr_alarm(thr_alarm_t *alarmed, uint sec, ALARM *buff); void thr_alarm_kill(pthread_t thread_id); void thr_end_alarm(thr_alarm_t *alarmed); -void end_thr_alarm(void); +void end_thr_alarm(my_bool free_structures); sig_handler process_alarm(int); #ifndef thr_got_alarm bool thr_got_alarm(thr_alarm_t *alrm); diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c index add5335a7af..1b58a0274ff 100644 --- a/mysys/thr_alarm.c +++ b/mysys/thr_alarm.c @@ -27,6 +27,7 @@ #include #include #include "thr_alarm.h" +#include #ifdef HAVE_SYS_SELECT_H #include /* AIX needs this for fd_set */ @@ -36,7 +37,7 @@ #define ETIME ETIMEDOUT #endif -static my_bool alarm_aborted=1; +static int alarm_aborted=1; /* No alarm thread */ my_bool thr_alarm_inited=0; static sig_handler process_alarm_part2(int sig); @@ -136,19 +137,24 @@ bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data) now=(ulong) time((time_t*) 0); pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask); pthread_mutex_lock(&LOCK_alarm); /* Lock from threads & alarms */ - if (alarm_aborted) + if (alarm_aborted > 0) { /* No signal thread */ DBUG_PRINT("info", ("alarm aborted")); + *alrm= 0; /* No alarm */ pthread_mutex_unlock(&LOCK_alarm); pthread_sigmask(SIG_SETMASK,&old_mask,NULL); DBUG_RETURN(1); } + if (alarm_aborted < 0) + sec= 1; /* Abort mode */ + if (alarm_queue.elements >= max_used_alarms) { if (alarm_queue.elements == alarm_queue.max_elements) { DBUG_PRINT("info", ("alarm queue full")); fprintf(stderr,"Warning: thr_alarm queue is full\n"); + *alrm= 0; /* No alarm */ pthread_mutex_unlock(&LOCK_alarm); pthread_sigmask(SIG_SETMASK,&old_mask,NULL); DBUG_RETURN(1); @@ -219,6 +225,7 @@ void thr_end_alarm(thr_alarm_t *alarmed) break; } } + DBUG_ASSERT(!*alarmed || found); if (!found) { #ifdef MAIN @@ -228,14 +235,7 @@ void thr_end_alarm(thr_alarm_t *alarmed) DBUG_PRINT("warning",("Didn't find alarm %lx in queue\n", (long) *alarmed)); } - if (alarm_aborted && !alarm_queue.elements) - { - delete_queue(&alarm_queue); - pthread_mutex_unlock(&LOCK_alarm); - pthread_mutex_destroy(&LOCK_alarm); - } - else - pthread_mutex_unlock(&LOCK_alarm); + pthread_mutex_unlock(&LOCK_alarm); pthread_sigmask(SIG_SETMASK,&old_mask,NULL); DBUG_VOID_RETURN; } @@ -365,31 +365,49 @@ static sig_handler process_alarm_part2(int sig __attribute__((unused))) /* - Shedule all alarms now. - When all alarms are given, Free alarm memory and don't allow more alarms. + Schedule all alarms now and optionally free all structures + + SYNPOSIS + end_thr_alarm() + free_structures Set to 1 if we should free memory used for + the alarm queue. + When we call this we should KNOW that there + is no active alarms + IMPLEMENTATION + Set alarm_abort to -1 which will change the behavior of alarms as follows: + - All old alarms will be rescheduled at once + - All new alarms will be rescheduled to one second */ -void end_thr_alarm(void) +void end_thr_alarm(my_bool free_structures) { DBUG_ENTER("end_thr_alarm"); - if (!alarm_aborted) + if (alarm_aborted != 1) { - my_bool deleted=0; pthread_mutex_lock(&LOCK_alarm); DBUG_PRINT("info",("Resheduling %d waiting alarms",alarm_queue.elements)); - alarm_aborted=1; /* mark aborted */ - if (!alarm_queue.elements) - { - deleted= 1; - delete_queue(&alarm_queue); - } + alarm_aborted= -1; /* mark aborted */ if (pthread_equal(pthread_self(),alarm_thread)) alarm(1); /* Shut down everything soon */ else reschedule_alarms(); - pthread_mutex_unlock(&LOCK_alarm); - if (deleted) - pthread_mutex_destroy(&LOCK_alarm); + if (free_structures) + { + /* + The following test is just for safety, the caller should not + depend on this + */ + DBUG_ASSERT(!alarm_queue.elements); + if (!alarm_queue.elements) + { + delete_queue(&alarm_queue); + alarm_aborted= 1; + pthread_mutex_unlock(&LOCK_alarm); + pthread_mutex_destroy(&LOCK_alarm); + } + } + else + pthread_mutex_unlock(&LOCK_alarm); } DBUG_VOID_RETURN; } @@ -629,7 +647,7 @@ void thr_end_alarm(thr_alarm_t *alrm_ptr) } } -void end_thr_alarm(void) +void end_thr_alarm(my_bool free_structures) { DBUG_ENTER("end_thr_alarm"); alarm_aborted=1; /* No more alarms */ @@ -708,7 +726,7 @@ void thr_end_alarm(thr_alarm_t *alrm_ptr) } } -void end_thr_alarm(void) +void end_thr_alarm(my_bool free_structures) { DBUG_ENTER("end_thr_alarm"); alarm_aborted=1; /* No more alarms */ @@ -907,7 +925,7 @@ static void *signal_hand(void *arg __attribute__((unused))) case SIGHUP: #endif printf("Aborting nicely\n"); - end_thr_alarm(); + end_thr_alarm(0); break; #ifdef SIGTSTP case SIGTSTP: @@ -1004,10 +1022,11 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused))) if (thread_count == 1) { printf("Calling end_thr_alarm. This should cancel the last thread\n"); - end_thr_alarm(); + end_thr_alarm(0); } } pthread_mutex_unlock(&LOCK_thread_count); + end_thr_alarm(1); 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, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 67fb7798ebd..2992fcfd908 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -596,7 +596,7 @@ static void close_connections(void) unix_sock= INVALID_SOCKET; } #endif - end_thr_alarm(); // Don't allow alarms + end_thr_alarm(0); // Abort old alarms. end_slave(); /* First signal all threads that it's time to die */ @@ -905,6 +905,7 @@ void clean_up(bool print_message) #endif (void) ha_panic(HA_PANIC_CLOSE); /* close all tables and logs */ end_key_cache(); + end_thr_alarm(1); /* Free allocated memory */ #ifdef USE_RAID end_raid(); #endif @@ -2313,14 +2314,14 @@ The server will not act as a slave."); if (opt_bootstrap) { int error=bootstrap(stdin); - end_thr_alarm(); // Don't allow alarms + end_thr_alarm(1); // Don't allow alarms unireg_abort(error ? 1 : 0); } if (opt_init_file) { if (read_init_file(opt_init_file)) { - end_thr_alarm(); // Don't allow alarms + end_thr_alarm(1); // Don't allow alarms unireg_abort(1); } } -- cgit v1.2.1 From 4ead61f87325563c9694f1d03eae26230cc8d884 Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Mon, 26 May 2003 15:08:17 +0300 Subject: code cleanup --- mysql-test/r/rpl_insert_id.result | 2 ++ mysql-test/t/rpl_insert_id.test | 10 ++++--- sql/log.cc | 57 +++++++++++++++++---------------------- 3 files changed, 34 insertions(+), 35 deletions(-) diff --git a/mysql-test/r/rpl_insert_id.result b/mysql-test/r/rpl_insert_id.result index d524818985e..70f9ff0de0f 100644 --- a/mysql-test/r/rpl_insert_id.result +++ b/mysql-test/r/rpl_insert_id.result @@ -23,10 +23,12 @@ drop table t1; drop table t2; create table t1(a int auto_increment, key(a)); create table t2(b int auto_increment, c int, key(b)); +SET FOREIGN_KEY_CHECKS=0; insert into t1 values (10); insert into t1 values (null),(null),(null); insert into t2 values (5,0); insert into t2 values (null,last_insert_id()); +SET FOREIGN_KEY_CHECKS=1; select * from t1; a 10 diff --git a/mysql-test/t/rpl_insert_id.test b/mysql-test/t/rpl_insert_id.test index 3f3636d3082..a9e4de21e5c 100644 --- a/mysql-test/t/rpl_insert_id.test +++ b/mysql-test/t/rpl_insert_id.test @@ -1,6 +1,8 @@ -#see if queries that use both -#auto_increment and LAST_INSERT_ID() -#are replicated well +# See if queries that use both auto_increment and LAST_INSERT_ID() +# are replicated well + +# We also check how the foreign_key_check variable is replicated + source include/master-slave.inc; connection master; drop table if exists t1; @@ -22,10 +24,12 @@ drop table t1; drop table t2; create table t1(a int auto_increment, key(a)); create table t2(b int auto_increment, c int, key(b)); +SET FOREIGN_KEY_CHECKS=0; insert into t1 values (10); insert into t1 values (null),(null),(null); insert into t2 values (5,0); insert into t2 values (null,last_insert_id()); +SET FOREIGN_KEY_CHECKS=1; save_master_pos; connection slave; sync_with_master; diff --git a/sql/log.cc b/sql/log.cc index 8bf51100147..99bc6ee32b4 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1116,50 +1116,38 @@ bool MYSQL_LOG::write(Log_event* event_info) goto err; } - /* If the user has set FOREIGN_KEY_CHECKS=0 we wrap every SQL - command in the binlog inside: - SET FOREIGN_KEY_CHECKS=0; - ; - SET FOREIGN_KEY_CHECKS=1; */ + /* + If the user has set FOREIGN_KEY_CHECKS=0 we wrap every SQL + command in the binlog inside: + SET FOREIGN_KEY_CHECKS=0; + ; + SET FOREIGN_KEY_CHECKS=1; + */ if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) { - char buf[256], *p; - p= strmov(buf, "SET FOREIGN_KEY_CHECKS=0"); - Query_log_event e(thd, buf, (ulong) (p - buf), 0); + Query_log_event e(thd, "SET FOREIGN_KEY_CHECKS=0", 24, 0); e.set_log_pos(this); if (e.write(file)) goto err; } } - /* - 2. Write the SQL command - */ + /* Write the SQL command */ event_info->set_log_pos(this); - if (event_info->write(file) || - file == &log_file && flush_io_cache(file)) + if (event_info->write(file)) goto err; - /* - 3. Write log events to reset the 'run environment' of the SQL command - */ + /* Write log events to reset the 'run environment' of the SQL command */ if (thd && thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) { - char buf[256], *p; - - p= strmov(buf, "SET FOREIGN_KEY_CHECKS=1"); - Query_log_event e(thd, buf, (ulong) (p - buf), 0); + Query_log_event e(thd, "SET FOREIGN_KEY_CHECKS=1", 24, 0); e.set_log_pos(this); - - if (e.write(file) || - file == &log_file && flush_io_cache(file)) + if (e.write(file)) goto err; } - - error=0; /* Tell for transactional table handlers up to which position in the @@ -1180,6 +1168,9 @@ bool MYSQL_LOG::write(Log_event* event_info) if (file == &log_file) // we are writing to the real log (disk) { + if (flush_io_cache(file)) + goto err; + if (opt_using_transactions && !my_b_tell(&thd->transaction.trans_log)) { /* @@ -1189,8 +1180,8 @@ bool MYSQL_LOG::write(Log_event* event_info) handler if the log event type is appropriate. */ - if (event_info->get_type_code() == QUERY_EVENT - || event_info->get_type_code() == EXEC_LOAD_EVENT) + if (event_info->get_type_code() == QUERY_EVENT || + event_info->get_type_code() == EXEC_LOAD_EVENT) { error = ha_report_binlog_offset_and_commit(thd, log_file_name, file->pos_in_file); @@ -1200,6 +1191,7 @@ bool MYSQL_LOG::write(Log_event* event_info) /* we wrote to the real log, check automatic rotation */ should_rotate= (my_b_tell(file) >= (my_off_t) max_binlog_size); } + error=0; err: if (error) @@ -1222,13 +1214,14 @@ err: pthread_mutex_unlock(&LOCK_log); - /* Flush the transactional handler log file now that we have released - LOCK_log; the flush is placed here to eliminate the bottleneck on the - group commit */ + /* + Flush the transactional handler log file now that we have released + LOCK_log; the flush is placed here to eliminate the bottleneck on the + group commit + */ - if (called_handler_commit) { + if (called_handler_commit) ha_commit_complete(thd); - } DBUG_RETURN(error); } -- cgit v1.2.1 From 01de316fc2eac29cace25b8c9e773b1e4fd6f82c Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Mon, 26 May 2003 17:24:16 +0300 Subject: Fixed problem with 'kill pid-of-mysqld' on Mac OS X --- sql/mysqld.cc | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 4e88a6fcb32..f729dcfd17a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1346,6 +1346,7 @@ information that should help you find out what is causing the crash\n"); static void init_signals(void) { sigset_t set; + struct sigaction sa; DBUG_ENTER("init_signals"); sigset(THR_KILL_SIGNAL,end_thread_signal); @@ -1353,7 +1354,6 @@ static void init_signals(void) if (!(test_flags & TEST_NO_STACKTRACE) || (test_flags & TEST_CORE_ON_SIGNAL)) { - struct sigaction sa; sa.sa_flags = SA_RESETHAND | SA_NODEFER; sigemptyset(&sa.sa_mask); sigprocmask(SIG_SETMASK,&sa.sa_mask,NULL); @@ -1378,15 +1378,22 @@ static void init_signals(void) sigaddset(&set,SIGQUIT); sigaddset(&set,SIGTERM); sigaddset(&set,SIGHUP); - sigset(SIGTERM,print_signal_warning); // If it's blocked by parent - signal(SIGHUP,print_signal_warning); // If it's blocked by parent + + /* Fix signals if blocked by parents (can happen on Mac OS X) */ + sa.sa_flags = 0; + sa.sa_handler = print_signal_warning; + sigaction(SIGTERM, &sa, (struct sigaction*) 0); + sa.sa_flags = 0; + sa.sa_handler = print_signal_warning; + sigaction(SIGHUP, &sa, (struct sigaction*) 0); #ifdef SIGTSTP sigaddset(&set,SIGTSTP); #endif sigaddset(&set,THR_SERVER_ALARM); sigdelset(&set,THR_KILL_SIGNAL); // May be SIGINT sigdelset(&set,THR_CLIENT_ALARM); // For alarms - (void) pthread_sigmask(SIG_SETMASK,&set,NULL); + sigprocmask(SIG_SETMASK,&set,NULL); + pthread_sigmask(SIG_SETMASK,&set,NULL); DBUG_VOID_RETURN; } -- cgit v1.2.1 From eedca52b23193e105196c0d6f7e7adb053f330be Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Mon, 26 May 2003 19:11:22 +0300 Subject: Fix for 64 bit machines (To remove warnings on Itanium) --- include/my_global.h | 5 +++++ mysys/thr_alarm.c | 1 + 2 files changed, 6 insertions(+) diff --git a/include/my_global.h b/include/my_global.h index 15495c60dd7..ca24c21c688 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -634,7 +634,12 @@ extern double my_atof(const char*); Max size that must be added to a so that we know Size to make adressable obj. */ +#if SIZEOF_CHARP == 4 typedef long my_ptrdiff_t; +#else +typedef long long my_ptrdiff_t; +#endif + #define MY_ALIGN(A,L) (((A) + (L) - 1) & ~((L) - 1)) #define ALIGN_SIZE(A) MY_ALIGN((A),sizeof(double)) /* Size to make adressable obj. */ diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c index 1b58a0274ff..ca8e4e8bcb6 100644 --- a/mysys/thr_alarm.c +++ b/mysys/thr_alarm.c @@ -169,6 +169,7 @@ bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data) if (!(alarm_data=(ALARM*) my_malloc(sizeof(ALARM),MYF(MY_WME)))) { DBUG_PRINT("info", ("failed my_malloc()")); + *alrm= 0; /* No alarm */ pthread_mutex_unlock(&LOCK_alarm); pthread_sigmask(SIG_SETMASK,&old_mask,NULL); DBUG_RETURN(1); -- cgit v1.2.1 From 873033932a5ac66fdbd5115f31380211e435df67 Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Mon, 26 May 2003 20:09:53 +0300 Subject: Fixed bug when installing mysqld as a service with 2 arguments (option + service-name) --- sql/mysqld.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f729dcfd17a..b0b9837dff3 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2230,9 +2230,12 @@ int main(int argc, char **argv) return 0; if (Service.IsService(argv[2])) { - /* start an optional service */ + /* + mysqld was started as + mysqld --defaults-file=my_path\my.ini service-name + */ use_opt_args=1; - opt_argc=argc; + opt_argc= 2; // Skip service-name opt_argv=argv; start_mode= 1; Service.Init(argv[2], mysql_service); -- cgit v1.2.1 From 381492093e6ec8d8afc0432347a890cdf452bf50 Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Tue, 27 May 2003 16:40:14 +0300 Subject: Fixed problem with mysql prompt when server disconnect. (Bug 356) Fixed problem with localtime -> gmt where some times resulted in different (but correct) timestamps. Now MySQL should use the smallest possible timestamp value in this case. (Bug 316) --- client/mysql.cc | 19 ++++++++--- client/mysqltest.c | 6 +++- mysql-test/mysql-test-run.sh | 12 ++++++- mysql-test/r/have_mest_timezone.require | 2 ++ mysql-test/r/timezone.result | 25 +++++++++++++++ mysql-test/t/raid.test | 2 ++ mysql-test/t/timezone-master.opt | 1 + mysql-test/t/timezone.test | 28 +++++++++++++++++ sql/field.cc | 3 +- sql/mysql_priv.h | 2 +- sql/mysqld.cc | 10 ------ sql/time.cc | 56 ++++++++++++++++++++------------- 12 files changed, 126 insertions(+), 40 deletions(-) create mode 100644 mysql-test/r/have_mest_timezone.require create mode 100644 mysql-test/r/timezone.result create mode 100644 mysql-test/t/timezone-master.opt create mode 100644 mysql-test/t/timezone.test diff --git a/client/mysql.cc b/client/mysql.cc index a237561d83d..9b0e85aa41a 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -40,7 +40,7 @@ #include #include -const char *VER= "12.20"; +const char *VER= "12.21"; /* Don't try to make a nice table if the data is too big */ #define MAX_COLUMN_LENGTH 1024 @@ -2613,14 +2613,18 @@ static const char* construct_prompt() add_int_to_prompt(++prompt_counter); break; case 'v': - processed_prompt.append(mysql_get_server_info(&mysql)); + if (connected) + processed_prompt.append(mysql_get_server_info(&mysql)); + else + processed_prompt.append("not_connected"); break; case 'd': processed_prompt.append(current_db ? current_db : "(none)"); break; case 'h': { - const char *prompt=mysql_get_host_info(&mysql); + const char *prompt; + prompt= connected ? mysql_get_host_info(&mysql) : "not_connected"; if (strstr(prompt, "Localhost")) processed_prompt.append("localhost"); else @@ -2631,8 +2635,13 @@ static const char* construct_prompt() break; } case 'p': - if (strstr(mysql_get_host_info(&mysql),"TCP/IP") || - ! mysql.unix_socket) + if (!connected) + { + processed_prompt.append("not_connected"); + break; + } + if (strstr(mysql_get_host_info(&mysql),"TCP/IP") || ! + mysql.unix_socket) add_int_to_prompt(mysql.port); else { diff --git a/client/mysqltest.c b/client/mysqltest.c index 4bc941e8b56..f6c999b18e4 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -515,8 +515,12 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char* fname) if (!my_stat(eval_file, &stat_info, MYF(MY_WME))) die(NullS); - if (!eval_result && stat_info.st_size != ds->length) + if (!eval_result && (uint) stat_info.st_size != ds->length) + { + DBUG_PRINT("info",("Size differs: result size: %u file size: %u", + ds->length, stat_info.st_size)); DBUG_RETURN(2); + } if (!(tmp = (char*) my_malloc(stat_info.st_size + 1, MYF(MY_WME)))) die(NullS); diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 65f40c5dc73..ab4a5354dae 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -13,7 +13,8 @@ DB=test DBPASSWD= VERBOSE="" USE_MANAGER=0 -TZ=GMT-3; export TZ # for UNIX_TIMESTAMP tests to work +MY_TZ=GMT-3 +TZ=$MY_TZ; export TZ # for UNIX_TIMESTAMP tests to work #++ # Program Definitions @@ -1161,9 +1162,18 @@ run_testcase () if [ -f $master_opt_file ] ; then EXTRA_MASTER_OPT=`$CAT $master_opt_file | $SED -e "s;\\$MYSQL_TEST_DIR;$MYSQL_TEST_DIR;"` + case "$EXTRA_MASTER_OPT" in + --timezone=*) + TZ=`$ECHO "$EXTRA_MASTER_OPT" | $SED -e "s;--timezone=;;"` + export TZ + # Note that this must be set to space, not "" for test-reset to work + EXTRA_MASTER_OPT=" " + ;; + esac stop_master echo "CURRENT_TEST: $tname" >> $MASTER_MYERR start_master + TZ=$MY_TZ; export TZ else if [ ! -z "$EXTRA_MASTER_OPT" ] || [ x$MASTER_RUNNING != x1 ] || [ -f $master_init_script ] then diff --git a/mysql-test/r/have_mest_timezone.require b/mysql-test/r/have_mest_timezone.require new file mode 100644 index 00000000000..2a219f39b7e --- /dev/null +++ b/mysql-test/r/have_mest_timezone.require @@ -0,0 +1,2 @@ +Variable_name Value +timezone MEST diff --git a/mysql-test/r/timezone.result b/mysql-test/r/timezone.result new file mode 100644 index 00000000000..b82b39da262 --- /dev/null +++ b/mysql-test/r/timezone.result @@ -0,0 +1,25 @@ +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (ts int); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 01:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 02:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 03:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 02:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 01:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 02:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2003-03-30 02:59:59')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2003-03-30 03:00:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2003-03-30 03:59:59')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2003-03-30 04:00:01')); +SELECT ts,from_unixtime(ts) FROM t1; +ts from_unixtime(ts) +1035673200 2002-10-27 01:00:00 +1035680400 2002-10-27 02:00:00 +1035684000 2002-10-27 03:00:00 +1035680400 2002-10-27 02:00:00 +1035673200 2002-10-27 01:00:00 +1035680400 2002-10-27 02:00:00 +1048986000 2003-03-30 03:00:00 +1048986000 2003-03-30 03:00:00 +1048989599 2003-03-30 03:59:59 +1048989601 2003-03-30 04:00:01 +DROP TABLE t1; diff --git a/mysql-test/t/raid.test b/mysql-test/t/raid.test index 4dbaf84a836..4032993f2da 100644 --- a/mysql-test/t/raid.test +++ b/mysql-test/t/raid.test @@ -1,5 +1,7 @@ -- require r/have_raid.require +disable_query_log; show variables like "have_raid"; +enable_query_log; # # Test of raided tables diff --git a/mysql-test/t/timezone-master.opt b/mysql-test/t/timezone-master.opt new file mode 100644 index 00000000000..0477f941e9d --- /dev/null +++ b/mysql-test/t/timezone-master.opt @@ -0,0 +1 @@ +--timezone=MET diff --git a/mysql-test/t/timezone.test b/mysql-test/t/timezone.test new file mode 100644 index 00000000000..14facc0374a --- /dev/null +++ b/mysql-test/t/timezone.test @@ -0,0 +1,28 @@ +# +# Test of timezone handling. This script must be run with TZ=MEST + +-- require r/have_mest_timezone.require +disable_query_log; +show variables like "timezone"; +enable_query_log; + +# Initialization +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + + +CREATE TABLE t1 (ts int); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 01:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 02:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 03:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 02:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 01:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 02:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2003-03-30 02:59:59')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2003-03-30 03:00:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2003-03-30 03:59:59')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2003-03-30 04:00:01')); + +SELECT ts,from_unixtime(ts) FROM t1; +DROP TABLE t1; diff --git a/sql/field.cc b/sql/field.cc index a2663626723..9babe069300 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2552,6 +2552,7 @@ void Field_timestamp::store(longlong nr) if ((nr=fix_datetime(nr))) { + long not_used; part1=(long) (nr/LL(1000000)); part2=(long) (nr - (longlong) part1*LL(1000000)); l_time.year= (int) (part1/10000L); part1%=10000L; @@ -2560,7 +2561,7 @@ void Field_timestamp::store(longlong nr) l_time.hour= (int) (part2/10000L); part2%=10000L; l_time.minute=(int) part2 / 100; l_time.second=(int) part2 % 100; - timestamp=my_gmt_sec(&l_time); + timestamp=my_gmt_sec(&l_time, ¬_used); } else timestamp=0; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2c28fcf03bb..614cb8cadf6 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -755,7 +755,7 @@ uint calc_days_in_year(uint year); void get_date_from_daynr(long daynr,uint *year, uint *month, uint *day); void init_time(void); -long my_gmt_sec(TIME *); +long my_gmt_sec(TIME *, long *current_timezone); time_t str_to_timestamp(const char *str,uint length); bool str_to_time(const char *str,uint length,TIME *l_time); longlong str_to_datetime(const char *str,uint length,bool fuzzy_date); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index e4f86a1818c..c2ee940af49 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -968,7 +968,6 @@ static void clean_up_mutexes() (void) pthread_mutex_destroy(&LOCK_crypt); (void) pthread_mutex_destroy(&LOCK_bytes_sent); (void) pthread_mutex_destroy(&LOCK_bytes_received); - (void) pthread_mutex_destroy(&LOCK_timezone); (void) pthread_mutex_destroy(&LOCK_user_conn); (void) pthread_mutex_destroy(&LOCK_rpl_status); (void) pthread_mutex_destroy(&LOCK_active_mi); @@ -1998,19 +1997,11 @@ int main(int argc, char **argv) } #endif #ifdef HAVE_TZNAME -#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT) { struct tm tm_tmp; localtime_r(&start_time,&tm_tmp); strmov(time_zone,tzname[tm_tmp.tm_isdst != 0 ? 1 : 0]); } -#else - { - struct tm *start_tm; - start_tm=localtime(&start_time); - strmov(time_zone,tzname[start_tm->tm_isdst != 0 ? 1 : 0]); - } -#endif #endif if (gethostname(glob_hostname,sizeof(glob_hostname)-4) < 0) @@ -2067,7 +2058,6 @@ int main(int argc, char **argv) (void) pthread_mutex_init(&LOCK_crypt,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_bytes_sent,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_bytes_received,MY_MUTEX_INIT_FAST); - (void) pthread_mutex_init(&LOCK_timezone,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_rpl_status, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST); diff --git a/sql/time.cc b/sql/time.cc index cc8cd4fbcf9..321a8ba16e5 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -28,7 +28,6 @@ uchar *days_in_month= (uchar*) "\037\034\037\036\037\036\037\037\036\037\036\037 /* Currently only my_time_zone is inited */ static long my_time_zone=0; -pthread_mutex_t LOCK_timezone; void init_time(void) { @@ -39,14 +38,14 @@ void init_time(void) seconds= (time_t) time((time_t*) 0); localtime_r(&seconds,&tm_tmp); l_time= &tm_tmp; - my_time_zone=0; + my_time_zone= 3600; /* Comp. for -3600 in my_gmt_sec */ my_time.year= (uint) l_time->tm_year+1900; my_time.month= (uint) l_time->tm_mon+1; my_time.day= (uint) l_time->tm_mday; my_time.hour= (uint) l_time->tm_hour; my_time.minute= (uint) l_time->tm_min; - my_time.second= (uint) l_time->tm_sec; - VOID(my_gmt_sec(&my_time)); /* Init my_time_zone */ + my_time.second= (uint) l_time->tm_sec; + my_gmt_sec(&my_time, &my_time_zone); /* Init my_time_zone */ } /* @@ -57,26 +56,39 @@ void init_time(void) */ -long my_gmt_sec(TIME *t) +long my_gmt_sec(TIME *t, long *my_timezone) { uint loop; time_t tmp; struct tm *l_time,tm_tmp; - long diff; + long diff, current_timezone; if (t->hour >= 24) { /* Fix for time-loop */ t->day+=t->hour/24; t->hour%=24; } - pthread_mutex_lock(&LOCK_timezone); - tmp=(time_t) ((calc_daynr((uint) t->year,(uint) t->month,(uint) t->day) - - (long) days_at_timestart)*86400L + (long) t->hour*3600L + - (long) (t->minute*60 + t->second)) + (time_t) my_time_zone; + + /* + Calculate the gmt time based on current time and timezone + The -1 on the end is to ensure that if have a date that exists twice + (like 2002-10-27 02:00:0 MET), we will find the initial date. + + By doing -3600 we will have to call localtime_r() several times, but + I couldn't come up with a better way to get a repeatable result :( + + We can't use mktime() as it's buggy on many platforms and not thread safe. + */ + tmp=(time_t) (((calc_daynr((uint) t->year,(uint) t->month,(uint) t->day) - + (long) days_at_timestart)*86400L + (long) t->hour*3600L + + (long) (t->minute*60 + t->second)) + (time_t) my_time_zone - + 3600); + current_timezone= my_time_zone; + localtime_r(&tmp,&tm_tmp); l_time=&tm_tmp; for (loop=0; - loop < 3 && + loop < 2 && (t->hour != (uint) l_time->tm_hour || t->minute != (uint) l_time->tm_min); loop++) @@ -89,14 +101,16 @@ long my_gmt_sec(TIME *t) days= -1; diff=(3600L*(long) (days*24+((int) t->hour - (int) l_time->tm_hour)) + (long) (60*((int) t->minute - (int) l_time->tm_min))); - my_time_zone+=diff; - tmp+=(time_t) diff; + current_timezone+= diff+3600; // Compensate for -3600 above + tmp+= (time_t) diff; localtime_r(&tmp,&tm_tmp); l_time=&tm_tmp; } - /* Fix that if we are in the not existing daylight saving time hour - we move the start of the next real hour */ - if (loop == 3 && t->hour != (uint) l_time->tm_hour) + /* + Fix that if we are in the not existing daylight saving time hour + we move the start of the next real hour + */ + if (loop == 2 && t->hour != (uint) l_time->tm_hour) { int days= t->day - l_time->tm_mday; if (days < -1) @@ -108,11 +122,9 @@ long my_gmt_sec(TIME *t) if (diff == 3600) tmp+=3600 - t->minute*60 - t->second; // Move to next hour else if (diff == -3600) - tmp-=t->minute*60 + t->second; // Move to next hour + tmp-=t->minute*60 + t->second; // Move to previous hour } - if ((my_time_zone >=0 ? my_time_zone: -my_time_zone) > 3600L*12) - my_time_zone=0; /* Wrong date */ - pthread_mutex_unlock(&LOCK_timezone); + *my_timezone= current_timezone; return (long) tmp; } /* my_gmt_sec */ @@ -399,6 +411,8 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date) time_t str_to_timestamp(const char *str,uint length) { TIME l_time; + long not_used; + if (str_to_TIME(str,length,&l_time,0) == TIMESTAMP_NONE) return(0); if (l_time.year >= TIMESTAMP_MAX_YEAR || l_time.year < 1900+YY_PART_YEAR) @@ -406,7 +420,7 @@ time_t str_to_timestamp(const char *str,uint length) current_thd->cuted_fields++; return(0); } - return(my_gmt_sec(&l_time)); + return(my_gmt_sec(&l_time, ¬_used)); } -- cgit v1.2.1 From cf3cda27784dd9e095a8e5c6b3b118d4201ed37e Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Tue, 27 May 2003 18:16:50 +0200 Subject: Removed bad mutex locking --- sql/slave.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sql/slave.cc b/sql/slave.cc index b620603dc63..b655b17c258 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1320,11 +1320,7 @@ static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli) while (rli->log_space_limit < rli->log_space_total && !(slave_killed=io_slave_killed(thd,mi)) && !rli->ignore_log_space_limit) - { pthread_cond_wait(&rli->log_space_cond, &rli->log_space_lock); - /* Re-acquire the mutex as pthread_cond_wait released it */ - pthread_mutex_lock(&rli->log_space_lock); - } thd->proc_info = save_proc_info; pthread_mutex_unlock(&rli->log_space_lock); DBUG_RETURN(slave_killed); -- cgit v1.2.1 From a612eeb783807c6780cd10a3d83d1c097ab7777c Mon Sep 17 00:00:00 2001 From: "lenz@mysql.com" <> Date: Tue, 27 May 2003 18:34:03 +0200 Subject: - removed internals.texi (has been moved to the "mysqldoc" BK tree) --- Docs/internals.texi | 694 ---------------------------------------------------- 1 file changed, 694 deletions(-) delete mode 100644 Docs/internals.texi diff --git a/Docs/internals.texi b/Docs/internals.texi deleted file mode 100644 index 2195b42d9a0..00000000000 --- a/Docs/internals.texi +++ /dev/null @@ -1,694 +0,0 @@ -\input texinfo @c -*-texinfo-*- -@c Copyright 1998 TcX AB, Detron HB and Monty Program KB -@c -@c %**start of header -@setfilename internals.info -@c We want the types in the same index -@c @synindex tp fn cp -@synindex cp fn -@iftex -@c Well this is normal in Europe. Maybe this should go into the include.texi? -@afourpaper -@end iftex -@c Get version and other info -@include include.texi -@ifclear tex-debug -@c This removes the black squares in the right margin -@finalout -@end ifclear -@c Set background for HTML -@set _body_tags BGCOLOR=#FFFFFF TEXT=#000000 LINK=#101090 VLINK=#7030B0 -@settitle @strong{MySQL} internals Manual for version @value{mysql_version}. -@setchapternewpage off -@paragraphindent 0 -@c %**end of header - -@ifinfo -@format -START-INFO-DIR-ENTRY -* mysql-internals: (mysql-internals). @strong{MySQL} internals. -END-INFO-DIR-ENTRY -@end format -@end ifinfo - -@titlepage -@sp 10 -@center @titlefont{@strong{MySQL} Internals Manual} -@sp 10 -@center Copyright @copyright{} 1998 TcX AB, Detron HB and Monty Program KB -@end titlepage - -@node Top, Introduction, (dir), (dir) - -@ifinfo -This is a manual about @strong{MySQL} internals. -@end ifinfo - -@menu -@end menu - -@node caching,,, -@chapter How MySQL handles caching - -@strong{MySQL} has the following caches: -(Note that the some of the filename have a wrong spelling of cache. :) - -@itemize @bullet - -@item Key cache -A shared cache for all B-tree index blocks in the different NISAM -files. Uses hashing and reverse linked lists for quick caching of the -last used blocks and quick flushing of changed entries for a specific -table. (@file{mysys/mf_keycash.c}) - -@item Record cache -This is used for quick scanning of all records in a table. -(@file{mysys/mf_iocash.c} and @file{isam/_cash.c}) - -@item Table cache -This holds the last used tables. (@file{sql/sql_base.cc}) - -@item Hostname cache -For quick lookup (with reverse name resolving). Is a must when one has a -slow DNS. -(@file{sql/hostname.cc}) - -@item Privilege cache -To allow quick change between databases the last used privileges are -cached for each user/database combination. -(@file{sql/sql_acl.cc}) - -@item Heap table cache -Many use of GROUP BY or DISTINCT caches all found -rows in a HEAP table (this is a very quick in-memory table with hash index) - -@item Join row cache. -For every full join in a SELECT statement (a full join here means there -were no keys that one could use to find the next table in a list), the -found rows are cached in a join cache. One SELECT query can use many -join caches in the worst case. -@end itemize - -@node flush tables,,, -@chapter How MySQL handles flush tables - -@itemize @bullet - -@item -Flush tables is handled in @code{sql/sql_base.cc::close_cached_tables()}. - -@item -The idea of flush tables is to force all tables to be closed. This -is mainly to ensure that if someone adds a new table outside of -@strong{MySQL} (for example with @code{cp}) all threads will start using -the new table. This will also ensure that all table changes are flushed -to disk (but of course not as optimally as simple calling a sync on -all tables)! - -@item -When one does a @code{FLUSH TABLES}, the variable @code{refresh_version} -will be incremented. Every time a thread releases a table it checks if -the refresh version of the table (updated at open) is the same as -the current refresh_version. If not it will close it and broadcast -a signal on COND_refresh (to wait any thread that is waiting for -all instanses of a table to be closed). - -@item -The current @code{refresh_version} is also compared to the open -@code{refresh_version} after a thread gets a lock on a table. If the -refresh version is different the thread will free all locks, reopen the -table and try to get the locks again; This is just to quickly get all -tables to use the newest version. This is handled by -@code{sql/lock.cc::mysql_lock_tables()} and -@code{sql/sql_base.cc::wait_for_tables()}. - -@item -When all tables has been closed @code{FLUSH TABLES} will return an ok -to client. - -@item -If the thread that is doing @code{FLUSH TABLES} has a lock on some tables, -it will first close the locked tables, then wait until all other threads -have also closed them, and then reopen them and get the locks. -After this it will give other threads a chance to open the same tables. - -@end itemize - -@node Filesort,,, -@chapter How MySQL does sorting (filesort) - -@itemize @bullet - -@item -Read all rows according to key or by table scanning. - -@item -Store the sort-key in a buffer (@code{sort_buffer}). - -@item -When the buffer gets full, run a qsort on it and store the result -in a temporary file. Save a pointer to the sorted block. - -@item -Repeat the above until all rows have been read. - -@item -Repeat the following until there is less than @code{MERGEBUFF2} (15) -blocks left. - -@item -Do a multi-merge of up to @code{MERGEBUFF} (7) regions to one block in -another temporary file. Repeat until all blocks from the first file -are in the second file. - -@item -On the last multi-merge, only the pointer to the row (last part of -the sort-key) is written to a result file. - -@item -Now the code in @file{sql/records.cc} will be used to read through them -in sorted order by using the row pointers in the result file. -To optimize this, we read in a big block of row pointers, sort these -and then we read the rows in the sorted order into a row buffer -(@code{record_buffer}) . - -@end itemize - -@node Coding guidelines,,, -@chapter Coding guidelines - -@itemize @bullet - -@item -We are using @uref{http://www.bitkeeper.com/, BitKeeper} for source management. - -@item -You should use the @strong{MySQL} 3.23 or 4.0 source for all developments. - -@item -If you have any questions about the @strong{MySQL} source, you can post these -to @email{developers@@mysql.com} and we will answer them. -Note that we will shortly change the name of this list to -@email{internals@@mysql.com}, to more accurately reflect what should be -posted to this list. - -@item -Try to write code in a lot of black boxes that can be reused or at -least have a clean interface. - -@item -Reuse code; There is already a lot of algorithms in MySQL for list handling, -queues, dynamic and hashed arrays, sorting, etc. that can be reused. - -@item -Try to always write optimized code, so that you don't have to -go back and rewrite it a couple of months later. It's better to -spend 3 times as much time designing and writing an optimal function than -having to do it all over again later on. - -@item -Avoid CPU wasteful code, even where it does not matter, so that -you will not develop sloppy coding habits. - -@item -If you can write it in fewer lines, do it (as long as the code will not -be slower or much harder to read). - -@item -Don't use two commands on the same line. - -@item -Do not check the same pointer for @code{NULL} more than once. - -@item -Use long function and variable names in English; This makes your code -easier to read. Use the 'varible_name' style instead of 'VariableName'. - -@item -Think assembly - make it easier for the compiler to optimize your code. - -@item -Comment your code when you do something that someone else may think -is not ''trivial''. - -@item -Use the @code{my_*} functions like @code{my_read()}/@code{my_write()}/ -@code{my_malloc()} that you can find in the @code{mysys} library instead -of the direct system calls; This will make your code easier to debug and -more portable. - -@item -Use @code{libstring} functions instead of standard libc string functions -whenever possible. - -@item -Avoid using @code{malloc()} (its REAL slow); For memory allocations -that only need to live for the lifetime of one thread, one should use -@code{sql_alloc()} instead. - -@item -Before making big design decisions, please first post a summary of -what you want to do, why you want to do it, and how you plan to do -it. This way we can easily provide you with feedback and also -easily discuss it thoroughly if some other developer thinks there is better -way to do the same thing! - -@item -Use my_var as opposed to myVar or MyVar (@samp{_} rather than dancing SHIFT -to seperate words in identifiers). - -@item -Class names start with a capital letter. - -@item -Structure types are @code{typedef}'ed to an all-caps identifier. - -@item -Any @code{#define}'s are in all-caps. - -@item -Matching @samp{@{} are in the same column. - -@item -Put the @samp{@{} after a 'switch' on the same line - -@example -switch (arg) { -@end example - -Because this gives better overall indentation for the switch statement. - -@item -In all other cases, @{ and @} should be on their own line, except -if there is nothing inside @{ @}. - -@item -Have a space after 'if' - -@item -Put a space after ',' for function arguments - -@item -Functions return 0 on success, and non-zero on error, so you can do: - -@example -if(a() || b() || c()) { error("something went wrong"); } -@end example - -@item -Using @code{goto} is okay if not abused. - -@item -Avoid default variable initalizations, use @code{LINT_INIT()} if the -compiler complains after making sure that there is really no way -the variable can be used uninitialized. - -@item -Do not instantiate a class if you do not have to. - -@item -Use pointers rather than array indexing when operating on strings. - -@end itemize - -Suggested mode in emacs: - -@example -(load "cc-mode") -(setq c-mode-common-hook '(lambda () - (turn-on-font-lock) - (setq comment-column 48))) -(setq c-style-alist - (cons - '("MY" - (c-basic-offset . 2) - (c-comment-only-line-offset . 0) - (c-offsets-alist . ((statement-block-intro . +) - (knr-argdecl-intro . 0) - (substatement-open . 0) - (label . -) - (statement-cont . +) - (arglist-intro . c-lineup-arglist-intro-after-paren) - (arglist-close . c-lineup-arglist) - )) - ) - c-style-alist)) -(c-set-style "MY") -(setq c-default-style "MY") -@end example - -@node mysys functions,,, -@chapter mysys functions - -Functions i mysys: (For flags se my_sys.h) - - int my_copy _A((const char *from,const char *to,myf MyFlags)); - - Copy file - - int my_delete _A((const char *name,myf MyFlags)); - - Delete file - - int my_getwd _A((string buf,uint size,myf MyFlags)); - int my_setwd _A((const char *dir,myf MyFlags)); - - Get and set working directory - - string my_tempnam _A((const char *pfx,myf MyFlags)); - - Make a uniq temp file name by using dir and adding something after - pfx to make name uniq. Name is made by adding a uniq 6 length-string - and TMP_EXT after pfx. - Returns pointer to malloced area for filename. Should be freed by - free(). - - File my_open _A((const char *FileName,int Flags,myf MyFlags)); - File my_create _A((const char *FileName,int CreateFlags, - int AccsesFlags, myf MyFlags)); - int my_close _A((File Filedes,myf MyFlags)); - uint my_read _A((File Filedes,byte *Buffer,uint Count,myf MyFlags)); - uint my_write _A((File Filedes,const byte *Buffer,uint Count, - myf MyFlags)); - ulong my_seek _A((File fd,ulong pos,int whence,myf MyFlags)); - ulong my_tell _A((File fd,myf MyFlags)); - - Use instead of open,open-with-create-flag, close read and write - to get automatic error-messages (flag: MYF_WME) and only have - to test for != 0 if error (flag: MY_NABP). - - int my_rename _A((const char *from,const char *to,myf MyFlags)); - - Rename file - - FILE *my_fopen _A((const char *FileName,int Flags,myf MyFlags)); - FILE *my_fdopen _A((File Filedes,int Flags,myf MyFlags)); - int my_fclose _A((FILE *fd,myf MyFlags)); - uint my_fread _A((FILE *stream,byte *Buffer,uint Count,myf MyFlags)); - uint my_fwrite _A((FILE *stream,const byte *Buffer,uint Count, - myf MyFlags)); - ulong my_fseek _A((FILE *stream,ulong pos,int whence,myf MyFlags)); - ulong my_ftell _A((FILE *stream,myf MyFlags)); - - Same read-interface for streams as for files - - gptr _mymalloc _A((uint uSize,const char *sFile, - uint uLine, myf MyFlag)); - gptr _myrealloc _A((string pPtr,uint uSize,const char *sFile, - uint uLine, myf MyFlag)); - void _myfree _A((gptr pPtr,const char *sFile,uint uLine)); - int _sanity _A((const char *sFile,unsigned int uLine)); - gptr _myget_copy_of_memory _A((const byte *from,uint length, - const char *sFile, uint uLine, - myf MyFlag)); - - malloc(size,myflag) is mapped to this functions if not compiled - with -DSAFEMALLOC - - void TERMINATE _A((void)); - - Writes malloc-info on stdout if compiled with -DSAFEMALLOC. - - int my_chsize _A((File fd,ulong newlength,myf MyFlags)); - - Change size of file - - void my_error _D((int nr,myf MyFlags, ...)); - - Writes message using error number (se mysys/errors.h) on - stdout or curses if MYSYS_PROGRAM_USES_CURSES() is called. - - void my_message _A((const char *str,myf MyFlags)); - - Writes message-string on - stdout or curses if MYSYS_PROGRAM_USES_CURSES() is called. - - void my_init _A((void )); - - Start each program (in main) with this. - void my_end _A((int infoflag)); - - Gives info about program. - - If infoflag & MY_CHECK_ERROR prints if some files are left open - - If infoflag & MY_GIVE_INFO prints timing info and malloc info - about prog. - - int my_redel _A((const char *from, const char *to, int MyFlags)); - - Delete from before rename of to to from. Copyes state from old - file to new file. If MY_COPY_TIME is set sets old time. - - int my_copystat _A((const char *from, const char *to, int MyFlags)); - - Copye state from old file to new file. - If MY_COPY_TIME is set sets copy also time. - - string my_filename _A((File fd)); - - Give filename of open file. - - int dirname _A((string to,const char *name)); - - Copy name of directory from filename. - - int test_if_hard_path _A((const char *dir_name)); - - Test if dirname is a hard path (Starts from root) - - void convert_dirname _A((string name)); - - Convert dirname acording to system. - - In MSDOS changes all caracters to capitals and changes '/' to - '\' - string fn_ext _A((const char *name)); - - Returns pointer to extension in filename - string fn_format _A((string to,const char *name,const char *dsk, - const char *form,int flag)); - format a filename with replace of library and extension and - converts between different systems. - params to and name may be identicall - function dosn't change name if name != to - Flag may be: 1 force replace filnames library with 'dsk' - 2 force replace extension with 'form' */ - 4 force Unpack filename (replace ~ with home) - 8 Pack filename as short as possibly for output to - user. - All open requests should allways use at least: - "open(fn_format(temp_buffe,name,"","",4),...)" to unpack home and - convert filename to system-form. - - string fn_same _A((string toname,const char *name,int flag)); - - Copys directory and extension from name to toname if neaded. - copy can be forced by same flags that in fn_format. - - int wild_compare _A((const char *str,const char *wildstr)); - - Compare if str matches wildstr. Wildstr can contain "*" and "?" - as match-characters. - Returns 0 if match. - - void get_date _A((string to,int timeflag)); - - Get current date in a form ready for printing. - - void soundex _A((string out_pntr, string in_pntr)) - - Makes in_pntr to a 5 chars long string. All words that sounds - alike have the same string. - - int init_key_cache _A((ulong use_mem,ulong leave_this_much_mem)); - - Use cacheing of keys in MISAM, PISAM, and ISAM. - KEY_CACHE_SIZE is a good size. - - Remember to lock databases for optimal cacheing - - void end_key_cache _A((void)); - - End key-cacheing. - -@node protocol,,, -@chapter MySQL client/server protocol - -Raw packet without compression -============================== -------------------------------------------------- -| Packet Length | Packet no | Data | -| 3 Bytes | 1 Byte | n Bytes | -------------------------------------------------- - -3 Byte packet length - The length is calculated with int3store - See include/global.h for details. - The max packetsize can be 16 MB. -1 Byte packet no - -If no compression is used the first 4 bytes of each paket -is the header of the paket. -The packet number is incremented for each sent packet. The first -packet starts with 0 - -n Byte data - -The packet length can be recalculated with: -length = byte1 + (256 * byte2) + (256 * 256 * byte3) - -Raw packet with compression -=========================== ------------------------------------------------------ -| Packet Length | Packet no | Uncomp. Packet Length | -| 3 Bytes | 1 Byte | 3 Bytes | ------------------------------------------------------ - -3 Byte packet length - The length is calculated with int3store - See include/global.h for details. - The max packetsize can be 16 MB. -1 Byte packet no -3 Byte uncompressed packet length - -If compression is used the first 7 bytes of each paket -is the header of the paket. - -Basic packets -============== -OK-packet - For details see sql/net_pkg.cc - function send_ok - ------------------------------------------------- - | Header | No of Rows | Affected Rows | - | | 1 Byte | 1-8 Byte | - ------------------------------------------------- - | ID (last_insert_id) | Status | Length | - | 1-8 Byte | 2 Byte | 1-8 Byte | - ------------------------------------------------- - | Messagetext | - | n Byte | - ------------------------------------------------- - - Header - 1 byte number of rows ? (always 0 ?) - 1-8 bytes affected rows - 1-8 byte id (last_insert_id) - 2 byte Status (usually 0) - If the OK-packege includes a message: - 1-8 bytes length of message - n bytes messagetext - -Error-packet - ------------------------------------------------- - | Header | Statuscode | Error no | - | | 1 Byte | 2 Byte | - ------------------------------------------------- - | Messagetext | 0x00 | - | n Byte | 1 Byte | - ------------------------------------------------- - - Header - 1 byte status code (0xFF = ERROR) - 2 byte error number (is only sent to new 3.23 clients. - n byte errortext - 1 byte 0x00 - - - -The communication -================= - -> Packet from server to client -< Paket from client tor server - - Login - ------ - > 1. packet - Header - 1 byte protocolversion - n byte serverversion - 1 byte 0x00 - 4 byte threadnumber - 8 byte crypt seed - 1 byte 0x00 - 2 byte CLIENT_xxx options (see include/mysql_com.h - that is supported by the server - 1 byte number of current server charset - 2 byte server status variables (SERVER_STATUS_xxx flags) - 13 byte 0x00 (not used yet). - - < 2. packet - Header - 2 byte CLIENT_xxx options - 3 byte max_allowed_packet for the client - n byte username - 1 byte 0x00 - 8 byte crypted password - 1 byte 0x00 - n byte databasename - 1 byte 0x00 - - > 3. packet - OK-packet - - - Command - -------- - < 1. packet - Header - 1 byte command type (e.g.0x03 = query) - n byte query - - Result set (after command) - -------------------------- - > 2. packet - Header - 1-8 byte field_count (packed with net_store_length()) - - If field_count == 0 (command): - 1-8 byte affected rows - 1-8 byte insert id - 2 bytes server_status (SERVER_STATUS_xx) - - If field_count == NULL_LENGTH (251) - LOAD DATA LOCAL INFILE - - If field_count > 0 Result Set: - - > n packets - Header Info - Column description: 5 data object /column - (See code in unpack_fields()) - - Columninfo for each column: - 1 data block table_name - 1 byte length of block - n byte data - 1 data block field_name - 1 byte length of block... - n byte data - 1 data block display length of field - 1 byte length of block - 3 bytes display length of filed - 1 data block type field of type (enum_field_types) - 1 byte length of block - 1 bytexs field of type - 1 data block flags - 1 byte length of block - 2 byte flags for the columns (NOT_NULL_FLAG, ZEROFILL_FLAG....) - 1 byte decimals - - if table definition: - 1 data block default value - - Actual result (one packet per row): - 4 byte header - 1-8 byte length of data - n data - - -Fieldtype Codes: -================ - - display_length |enum_field_type |flags - ---------------------------------------------------- -Blob 03 FF FF 00 |01 FC |03 90 00 00 -Mediumblob 03 FF FF FF |01 FC |03 90 00 00 -Tinyblob 03 FF 00 00 |01 FC |03 90 00 00 -Text 03 FF FF 00 |01 FC |03 10 00 00 -Mediumtext 03 FF FF FF |01 FC |03 10 00 00 -Tinytext 03 FF 00 00 |01 FC |03 10 00 00 -Integer 03 0B 00 00 |01 03 |03 03 42 00 -Mediumint 03 09 00 00 |01 09 |03 00 00 00 -Smallint 03 06 00 00 |01 02 |03 00 00 00 -Tinyint 03 04 00 00 |01 01 |03 00 00 00 -Varchar 03 XX 00 00 |01 FD |03 00 00 00 -Enum 03 05 00 00 |01 FE |03 00 01 00 -Datetime 03 13 00 00 |01 0C |03 00 00 00 -Timestamp 03 0E 00 00 |01 07 |03 61 04 00 -Time 03 08 00 00 |01 0B |03 00 00 00 -Date 03 0A 00 00 |01 0A |03 00 00 00 - - -@c The Index was empty, and ugly, so I removed it. (jcole, Sep 7, 2000) - -@c @node Index -@c @unnumbered Index - -@c @printindex fn - -@summarycontents -@contents - -@bye -- cgit v1.2.1 From 4bd32cae4c3bcea00ec849ae09f163f13ef57dca Mon Sep 17 00:00:00 2001 From: "lenz@mysql.com" <> Date: Tue, 27 May 2003 18:47:50 +0200 Subject: - removed internals.texi (has been moved to mysqldoc BK tree) --- Docs/Makefile.am | 47 - Docs/internals.texi | 5707 --------------------------------------------------- 2 files changed, 5754 deletions(-) delete mode 100644 Docs/internals.texi diff --git a/Docs/Makefile.am b/Docs/Makefile.am index 00eb936c408..f3df055a7dd 100644 --- a/Docs/Makefile.am +++ b/Docs/Makefile.am @@ -157,53 +157,6 @@ manual_letter.de.ps: manual.de.texi include.texi touch $@ -# -# Internals Manual -# - -# GNU Info -internals.info: internals.texi include.texi - cd $(srcdir) && $(MAKEINFO) --no-split -I $(srcdir) $< - -# Plain Text -internals.txt: internals.texi include.texi - cd $(srcdir) && \ - $(MAKEINFO) -I $(srcdir) --no-headers --no-split --output $@ $< - -# HTML, all in one file -internals.html: internals.texi include.texi $(srcdir)/Support/texi2html - cd $(srcdir) && @PERL@ $(srcdir)/Support/texi2html $(TEXI2HTML_FLAGS) $< -internals_toc.html: internals.html - -# PDF, Portable Document Format -internals.pdf: internals.texi - sed -e 's|@image{[^}]*} *||g' <$< >internals-tmp.texi - pdftex --interaction=nonstopmode internals-tmp.texi - texindex internals-tmp.?? - pdftex --interaction=nonstopmode internals-tmp.texi - texindex internals-tmp.?? - pdftex --interaction=nonstopmode internals-tmp.texi - mv internals-tmp.pdf $@ - rm -f internals-tmp.* - touch $@ - -# Postscript, A4 Paper -internals_a4.ps: internals.texi include.texi - TEXINPUTS=$(srcdir):$$TEXINPUTS \ - MAKEINFO='$(MAKEINFO) -I $(srcdir)' \ - $(TEXI2DVI) --batch --texinfo --quiet '@afourpaper' $< - $(DVIPS) -t a4 internals.dvi -o $@ - touch $@ - -# Postscript, US Letter Paper -internals_letter.ps: internals.texi include.texi - TEXINPUTS=$(srcdir):$$TEXINPUTS \ - MAKEINFO='$(MAKEINFO) -I $(srcdir)' \ - $(TEXI2DVI) --batch $< - $(DVIPS) -t letter internals.dvi -o $@ - touch $@ - - # # Miscellaneous # diff --git a/Docs/internals.texi b/Docs/internals.texi deleted file mode 100644 index a54f5098e5d..00000000000 --- a/Docs/internals.texi +++ /dev/null @@ -1,5707 +0,0 @@ -\input texinfo @c -*-texinfo-*- -@c Copyright 2002 MySQL AB -@c -@c %**start of header -@setfilename internals.info - -@c We want the types in the same index -@synindex cp fn - -@iftex -@afourpaper -@end iftex - -@c Get version and other info -@include include.texi - -@ifclear tex-debug -@c This removes the black squares in the right margin -@finalout -@end ifclear - -@c Set background for HTML -@set _body_tags BGCOLOR=#FFFFFF TEXT=#000000 LINK=#101090 VLINK=#7030B0 -@settitle @strong{MySQL} Internals Manual for version @value{mysql_version}. -@setchapternewpage odd -@paragraphindent 0 - -@c %**end of header - -@ifinfo -@format -START-INFO-DIR-ENTRY -* mysql-internals: (mysql-internals). @strong{MySQL} internals. -END-INFO-DIR-ENTRY -@end format -@end ifinfo - -@titlepage -@sp 10 -@center @titlefont{@strong{MySQL} Internals Manual} -@sp 10 -@center Copyright @copyright{} 1998-2002 MySQL AB -@page -@end titlepage - -@node Top, coding guidelines, (dir), (dir) - -@ifinfo -This is a manual about @strong{MySQL} internals. -@end ifinfo - -@menu -* coding guidelines:: Coding Guidelines -* caching:: How MySQL Handles Caching -* join_buffer_size:: -* flush tables:: How MySQL Handles @code{FLUSH TABLES} -* Algorithms:: -* mysys functions:: Functions In The @code{mysys} Library -* DBUG:: DBUG Tags To Use -* protocol:: MySQL Client/Server Protocol -* Fulltext Search:: Fulltext Search in MySQL -* MyISAM Record Structure:: MyISAM Record Structure -* InnoDB Record Structure:: InnoDB Record Structure -* InnoDB Page Structure:: InnoDB Page Structure -* Files in MySQL Sources:: Annotated List Of Files in the MySQL Source Code Distribution -* Files in InnoDB Sources:: Annotated List Of Files in the InnoDB Source Code Distribution -@end menu - - -@node coding guidelines, caching, Top, Top -@chapter Coding Guidelines - -@itemize @bullet - -@item -We use @uref{http://www.bitkeeper.com/, BitKeeper} for source management. - -@item -You should use the @strong{MySQL} 4.1 source for all developments. - -@item -If you have any questions about the @strong{MySQL} source, you can post these -to @email{internals@@mysql.com} and we will answer them. - -@item -Try to write code in a lot of black boxes that can be reused or use at -least a clean, easy to change interface. - -@item -Reuse code; There is already a lot of algorithms in MySQL for list handling, -queues, dynamic and hashed arrays, sorting, etc. that can be reused. - -@item -Use the @code{my_*} functions like @code{my_read()}/@code{my_write()}/ -@code{my_malloc()} that you can find in the @code{mysys} library instead -of the direct system calls; This will make your code easier to debug and -more portable. - -@item -Try to always write optimized code, so that you don't have to -go back and rewrite it a couple of months later. It's better to -spend 3 times as much time designing and writing an optimal function than -having to do it all over again later on. - -@item -Avoid CPU wasteful code, even where it does not matter, so that -you will not develop sloppy coding habits. - -@item -If you can write it in fewer lines, do it (as long as the code will not -be slower or much harder to read). - -@item -Don't use two commands on the same line. - -@item -Do not check the same pointer for @code{NULL} more than once. - -@item -Use long function and variable names in English. This makes your code -easier to read. - -@item -Use @code{my_var} as opposed to @code{myVar} or @code{MyVar} (@samp{_} -rather than dancing SHIFT to seperate words in identifiers). - -@item -Think assembly - make it easier for the compiler to optimize your code. - -@item -Comment your code when you do something that someone else may think -is not ``trivial''. - -@item -Use @code{libstring} functions (in the @file{strings} directory) -instead of standard @code{libc} string functions whenever possible. - -@item -Avoid using @code{malloc()} (its REAL slow); For memory allocations -that only need to live for the lifetime of one thread, one should use -@code{sql_alloc()} instead. - -@item -Before making big design decisions, please first post a summary of -what you want to do, why you want to do it, and how you plan to do -it. This way we can easily provide you with feedback and also -easily discuss it thoroughly if some other developer thinks there is better -way to do the same thing! - -@item -Class names start with a capital letter. - -@item -Structure types are @code{typedef}'ed to an all-caps identifier. - -@item -Any @code{#define}'s are in all-caps. - -@item -Matching @samp{@{} are in the same column. - -@item -Put the @samp{@{} after a @code{switch} on the same line, as this gives -better overall indentation for the switch statement: - -@example -switch (arg) @{ -@end example - -@item -In all other cases, @samp{@{} and @samp{@}} should be on their own line, except -if there is nothing inside @samp{@{} and @samp{@}}. - -@item -Have a space after @code{if} - -@item -Put a space after @samp{,} for function arguments - -@item -Functions return @samp{0} on success, and non-zero on error, so you can do: - -@example -if(a() || b() || c()) @{ error("something went wrong"); @} -@end example - -@item -Using @code{goto} is okay if not abused. - -@item -Avoid default variable initalizations, use @code{LINT_INIT()} if the -compiler complains after making sure that there is really no way -the variable can be used uninitialized. - -@item -Do not instantiate a class if you do not have to. - -@item -Use pointers rather than array indexing when operating on strings. - -@end itemize - -Suggested mode in emacs: - -@example -(load "cc-mode") -(setq c-mode-common-hook '(lambda () - (turn-on-font-lock) - (setq comment-column 48))) -(setq c-style-alist - (cons - '("MY" - (c-basic-offset . 2) - (c-comment-only-line-offset . 0) - (c-offsets-alist . ((statement-block-intro . +) - (knr-argdecl-intro . 0) - (substatement-open . 0) - (label . -) - (statement-cont . +) - (arglist-intro . c-lineup-arglist-intro-after-paren) - (arglist-close . c-lineup-arglist) - )) - ) - c-style-alist)) -(c-set-style "MY") -(setq c-default-style "MY") -@end example - -@node caching, join_buffer_size, coding guidelines, Top -@chapter How MySQL Handles Caching - -@strong{MySQL} has the following caches: -(Note that the some of the filename have a wrong spelling of cache. :) - -@table @strong - -@item Key Cache -A shared cache for all B-tree index blocks in the different NISAM -files. Uses hashing and reverse linked lists for quick caching of the -last used blocks and quick flushing of changed entries for a specific -table. (@file{mysys/mf_keycash.c}) - -@item Record Cache -This is used for quick scanning of all records in a table. -(@file{mysys/mf_iocash.c} and @file{isam/_cash.c}) - -@item Table Cache -This holds the last used tables. (@file{sql/sql_base.cc}) - -@item Hostname Cache -For quick lookup (with reverse name resolving). Is a must when one has a -slow DNS. -(@file{sql/hostname.cc}) - -@item Privilege Cache -To allow quick change between databases the last used privileges are -cached for each user/database combination. -(@file{sql/sql_acl.cc}) - -@item Heap Table Cache -Many use of @code{GROUP BY} or @code{DISTINCT} caches all found rows in -a @code{HEAP} table. (This is a very quick in-memory table with hash index.) - -@item Join buffer Cache -For every full join in a @code{SELECT} statement (a full join here means -there were no keys that one could use to find the next table in a list), -the found rows are cached in a join cache. One @code{SELECT} query can -use many join caches in the worst case. -@end table - -@node join_buffer_size, flush tables, caching, Top -@chapter How MySQL uses the join_buffer cache - -Basic information about @code{join_buffer_size}: - -@itemize @bullet -@item -It's only used in the case when join type is of type @code{ALL} or -@code{index}; In other words: no possible keys can be used. -@item -A join buffer is never allocated for the first not-const table, -even it it would be of type @code{ALL}/@code{index}. -@item -The buffer is allocated when we need to do a each full join between two -tables and freed after the query is done. -@item -Accepted row combinations of tables before the @code{ALL}/@code{index} -able is stored in the cache and is used to compare against each read -row in the @code{ALL} table. -@item -We only store the used fields in the join_buffer cache, not the -whole rows. -@end itemize - -Assume you have the following join: - -@example -Table name Type -t1 range -t2 ref -t3 @code{ALL} -@end example - -The join is then done as follows: - -@example -- While rows in t1 matching range - - Read through all rows in t2 according to reference key - - Store used fields form t1,t2 in cache - - If cache is full - - Read through all rows in t3 - - Compare t3 row against all t1,t2 combination in cache - - If rows satisfying join condition, send it to client - - Empty cache - -- Read through all rows in t3 - - Compare t3 row against all stored t1,t2 combinations in cache - - If rows satisfying join condition, send it to client -@end example - -The above means that table t3 is scanned - -@example -(size-of-stored-row(t1,t2) * accepted-row-cominations(t1,t2))/ -join_buffer_size+1 -@end example -times. - -Some conclusions: - -@itemize @bullet -@item -The larger the join_buff_size, the fewer scans of t3. -If @code{join_buff_size} is already large enough to hold all previous row -combinations then there is no speed to gain by making it bigger. -@item -If there is several tables of @code{ALL}/@code{index} then the we -allocate one @code{join_buffer_size buffer} for each of them and use the -same algorithm described above to handle it. (In other words, we store -the same row combination several times into different buffers) -@end itemize - -@node flush tables, Algorithms, join_buffer_size, Top -@chapter How MySQL Handles @code{FLUSH TABLES} - -@itemize @bullet - -@item -Flush tables is handled in @file{sql/sql_base.cc::close_cached_tables()}. - -@item -The idea of flush tables is to force all tables to be closed. This -is mainly to ensure that if someone adds a new table outside of -@strong{MySQL} (for example with @code{cp}) all threads will start using -the new table. This will also ensure that all table changes are flushed -to disk (but of course not as optimally as simple calling a sync on -all tables)! - -@item -When one does a @code{FLUSH TABLES}, the variable @code{refresh_version} -will be incremented. Every time a thread releases a table it checks if -the refresh version of the table (updated at open) is the same as -the current @code{refresh_version}. If not it will close it and broadcast -a signal on @code{COND_refresh} (to wait any thread that is waiting for -all instanses of a table to be closed). - -@item -The current @code{refresh_version} is also compared to the open -@code{refresh_version} after a thread gets a lock on a table. If the -refresh version is different the thread will free all locks, reopen the -table and try to get the locks again; This is just to quickly get all -tables to use the newest version. This is handled by -@file{sql/lock.cc::mysql_lock_tables()} and -@file{sql/sql_base.cc::wait_for_tables()}. - -@item -When all tables has been closed @code{FLUSH TABLES} will return an ok -to client. - -@item -If the thread that is doing @code{FLUSH TABLES} has a lock on some tables, -it will first close the locked tables, then wait until all other threads -have also closed them, and then reopen them and get the locks. -After this it will give other threads a chance to open the same tables. - -@end itemize - -@node Algorithms, mysys functions, flush tables, Top -@chapter Different algoritms used in MySQL - -MySQL uses a lot of different algorithms. This chapter tries to describe -some of these: - -@menu -* filesort:: -* bulk-insert:: -@end menu - -@node filesort, bulk-insert, Algorithms, Algorithms -@section How MySQL Does Sorting (@code{filesort}) - -@itemize @bullet - -@item -Read all rows according to key or by table scanning. - -@item -Store the sort-key in a buffer (@code{sort_buffer}). - -@item -When the buffer gets full, run a @code{qsort} on it and store the result -in a temporary file. Save a pointer to the sorted block. - -@item -Repeat the above until all rows have been read. - -@item -Repeat the following until there is less than @code{MERGEBUFF2} (15) -blocks left. - -@item -Do a multi-merge of up to @code{MERGEBUFF} (7) regions to one block in -another temporary file. Repeat until all blocks from the first file -are in the second file. - -@item -On the last multi-merge, only the pointer to the row (last part of -the sort-key) is written to a result file. - -@item -Now the code in @file{sql/records.cc} will be used to read through them -in sorted order by using the row pointers in the result file. -To optimize this, we read in a big block of row pointers, sort these -and then we read the rows in the sorted order into a row buffer -(@code{record_buffer}). - -@end itemize - -@node bulk-insert, , filesort, Algorithms -@section Bulk insert - -Logic behind bulk insert optimisation is simple. - -Instead of writing each key value to b-tree (that is to keycache, but -bulk insert code doesn't know about keycache) keys are stored in -balanced binary (red-black) tree, in memory. When this tree reaches its -memory limit it's writes all keys to disk (to keycache, that is). But -as key stream coming from the binary tree is already sorted inserting -goes much faster, all the necessary pages are already in cache, disk -access is minimized, etc. - -@node mysys functions, DBUG, Algorithms, Top -@chapter Functions In The @code{mysys} Library - -Functions in @code{mysys}: (For flags see @file{my_sys.h}) - -@table @code -@item int my_copy _A((const char *from, const char *to, myf MyFlags)); -Copy file from @code{from} to @code{to}. - -@item int my_delete _A((const char *name, myf MyFlags)); -Delete file @code{name}. - -@item int my_getwd _A((string buf, uint size, myf MyFlags)); -@item int my_setwd _A((const char *dir, myf MyFlags)); -Get and set working directory. - -@item string my_tempnam _A((const char *pfx, myf MyFlags)); -Make a unique temporary file name by using dir and adding something after -@code{pfx} to make name unique. The file name is made by adding a unique -six character string and @code{TMP_EXT} after @code{pfx}. -Returns pointer to @code{malloc()}'ed area for filename. Should be freed by -@code{free()}. - -@item File my_open _A((const char *FileName,int Flags,myf MyFlags)); -@item File my_create _A((const char *FileName, int CreateFlags, int AccsesFlags, myf MyFlags)); -@item int my_close _A((File Filedes, myf MyFlags)); -@item uint my_read _A((File Filedes, byte *Buffer, uint Count, myf MyFlags)); -@item uint my_write _A((File Filedes, const byte *Buffer, uint Count, myf MyFlags)); -@item ulong my_seek _A((File fd,ulong pos,int whence,myf MyFlags)); -@item ulong my_tell _A((File fd,myf MyFlags)); -Use instead of open, open-with-create-flag, close, read, and write -to get automatic error messages (flag @code{MYF_WME}) and only have -to test for != 0 if error (flag @code{MY_NABP}). - -@item int my_rename _A((const char *from, const char *to, myf MyFlags)); -Rename file from @code{from} to @code{to}. - -@item FILE *my_fopen _A((const char *FileName,int Flags,myf MyFlags)); -@item FILE *my_fdopen _A((File Filedes,int Flags,myf MyFlags)); -@item int my_fclose _A((FILE *fd,myf MyFlags)); -@item uint my_fread _A((FILE *stream,byte *Buffer,uint Count,myf MyFlags)); -@item uint my_fwrite _A((FILE *stream,const byte *Buffer,uint Count, myf MyFlags)); -@item ulong my_fseek _A((FILE *stream,ulong pos,int whence,myf MyFlags)); -@item ulong my_ftell _A((FILE *stream,myf MyFlags)); -Same read-interface for streams as for files. - -@item gptr _mymalloc _A((uint uSize,const char *sFile,uint uLine, myf MyFlag)); -@item gptr _myrealloc _A((string pPtr,uint uSize,const char *sFile,uint uLine, myf MyFlag)); -@item void _myfree _A((gptr pPtr,const char *sFile,uint uLine)); -@item int _sanity _A((const char *sFile,unsigned int uLine)); -@item gptr _myget_copy_of_memory _A((const byte *from,uint length,const char *sFile, uint uLine,myf MyFlag)); -@code{malloc(size,myflag)} is mapped to these functions if not compiled -with @code{-DSAFEMALLOC}. - -@item void TERMINATE _A((void)); -Writes @code{malloc()} info on @code{stdout} if compiled with -@code{-DSAFEMALLOC}. - -@item int my_chsize _A((File fd, ulong newlength, myf MyFlags)); -Change size of file @code{fd} to @code{newlength}. - -@item void my_error _D((int nr, myf MyFlags, ...)); -Writes message using error number (see @file{mysys/errors.h}) on @code{stdout}, -or using curses, if @code{MYSYS_PROGRAM_USES_CURSES()} has been called. - -@item void my_message _A((const char *str, myf MyFlags)); -Writes @code{str} on @code{stdout}, or using curses, if -@code{MYSYS_PROGRAM_USES_CURSES()} has been called. - -@item void my_init _A((void )); -Start each program (in @code{main()}) with this. - -@item void my_end _A((int infoflag)); -Gives info about program. -If @code{infoflag & MY_CHECK_ERROR}, prints if some files are left open. -If @code{infoflag & MY_GIVE_INFO}, prints timing info and malloc info -about program. - -@item int my_redel _A((const char *from, const char *to, int MyFlags)); -Delete @code{from} before rename of @code{to} to @code{from}. Copies state -from old file to new file. If @code{MY_COPY_TIME} is set, sets old time. - -@item int my_copystat _A((const char *from, const char *to, int MyFlags)); -Copy state from old file to new file. If @code{MY_COPY_TIME} is set, -sets old time. - -@item string my_filename _A((File fd)); -Returns filename of open file. - -@item int dirname _A((string to, const char *name)); -Copy name of directory from filename. - -@item int test_if_hard_path _A((const char *dir_name)); -Test if @code{dir_name} is a hard path (starts from root). - -@item void convert_dirname _A((string name)); -Convert dirname according to system. -In MSDOS, changes all characters to capitals and changes @samp{/} to @samp{\}. - -@item string fn_ext _A((const char *name)); -Returns pointer to extension in filename. - -@item string fn_format _A((string to,const char *name,const char *dsk,const char *form,int flag)); - format a filename with replace of library and extension and - converts between different systems. - params to and name may be identicall - function dosn't change name if name != to - Flag may be: 1 force replace filnames library with 'dsk' - 2 force replace extension with 'form' */ - 4 force Unpack filename (replace ~ with home) - 8 Pack filename as short as possibly for output to - user. - All open requests should allways use at least: - "open(fn_format(temp_buffe,name,"","",4),...)" to unpack home and - convert filename to system-form. - -@item string fn_same _A((string toname, const char *name, int flag)); -Copys directory and extension from @code{name} to @code{toname} if neaded. -Copying can be forced by same flags used in @code{fn_format()}. - -@item int wild_compare _A((const char *str, const char *wildstr)); -Compare if @code{str} matches @code{wildstr}. @code{wildstr} can contain -@samp{*} and @samp{?} as wildcard characters. -Returns 0 if @code{str} and @code{wildstr} match. - -@item void get_date _A((string to, int timeflag)); -Get current date in a form ready for printing. - -@item void soundex _A((string out_pntr, string in_pntr)) -Makes @code{in_pntr} to a 5 char long string. All words that sound -alike have the same string. - -@item int init_key_cache _A((ulong use_mem, ulong leave_this_much_mem)); -Use caching of keys in MISAM, PISAM, and ISAM. -@code{KEY_CACHE_SIZE} is a good size. -Remember to lock databases for optimal caching. - -@item void end_key_cache _A((void)); -End key caching. -@end table - - - -@node DBUG, protocol, mysys functions, Top -@chapter DBUG Tags To Use - -Here is some of the tags we now use: -(We should probably add a couple of new ones) - -@table @code -@item enter -Arguments to the function. - -@item exit -Results from the function. - -@item info -Something that may be interesting. - -@item warning -When something doesn't go the usual route or may be wrong. - -@item error -When something went wrong. - -@item loop -Write in a loop, that is probably only useful when debugging -the loop. These should normally be deleted when one is -satisfied with the code and it has been in real use for a while. -@end table - -Some specific to mysqld, because we want to watch these carefully: - -@table @code -@item trans -Starting/stopping transactions. - -@item quit -@code{info} when mysqld is preparing to die. - -@item query -Print query. -@end table - - -@node protocol, Fulltext Search, DBUG, Top -@chapter MySQL Client/Server Protocol - -@menu -* raw packet without compression:: -* raw packet with compression:: -* basic packets:: -* communication:: -* fieldtype codes:: -* protocol functions:: -* protocol version 2:: -* 4.1 protocol changes:: -* 4.1 field packet:: -* 4.1 field desc:: -* 4.1 ok packet:: -* 4.1 end packet:: -* 4.1 error packet:: -* 4.1 prep init:: -* 4.1 long data:: -* 4.1 execute:: -* 4.1 binary result:: -@end menu - -@node raw packet without compression, raw packet with compression, protocol, protocol -@section Raw Packet Without Compression - -@example -+-----------------------------------------------+ -| Packet Length | Packet no | Data | -| 3 Bytes | 1 Byte | n Bytes | -+-----------------------------------------------+ -@end example - -@table @asis -@item 3 Byte packet length -The length is calculated with int3store -See include/global.h for details. -The max packetsize can be 16 MB. - -@item 1 Byte packet no -If no compression is used the first 4 bytes of each packet is the header -of the packet. The packet number is incremented for each sent packet. -The first packet starts with 0. -@item n Byte data - -@end table - -The packet length can be recalculated with: - -@example -length = byte1 + (256 * byte2) + (256 * 256 * byte3) -@end example - - -@node raw packet with compression, basic packets, raw packet without compression, protocol -@section Raw Packet With Compression - -@example -+---------------------------------------------------+ -| Packet Length | Packet no | Uncomp. Packet Length | -| 3 Bytes | 1 Byte | 3 Bytes | -+---------------------------------------------------+ -@end example - -@table @asis -@item 3 Byte packet length -The length is calculated with int3store -See include/global.h for details. -The max packetsize can be 16 MB. - -@item 1 Byte packet no -@item 3 Byte uncompressed packet length -@end table - -If compression is used the first 7 bytes of each packet -is the header of the packet. - - -@node basic packets, communication, raw packet with compression, protocol -@section Basic Packets - -@menu -* ok packet:: -* error packet:: -@end menu - - -@node ok packet, error packet, basic packets, basic packets -@subsection OK Packet - -For details, see @file{sql/net_pkg.cc::send_ok()}. - -@example -+-----------------------------------------------+ -| Header | No of Rows | Affected Rows | -| | 1 Byte | 1-8 Byte | -|-----------------------------------------------| -| ID (last_insert_id) | Status | Length | -| 1-8 Byte | 2 Byte | 1-8 Byte | -|-----------------------------------------------| -| Messagetext | -| n Byte | -+-----------------------------------------------+ -@end example - -@table @asis -@item Header -@item 1 byte number of rows ? (always 0 ?) -@item 1-8 bytes affected rows -@item 1-8 byte id (last_insert_id) -@item 2 byte Status (usually 0) -@item If the OK-packege includes a message: -@item 1-8 bytes length of message -@item n bytes messagetext -@end table - - -@node error packet, , ok packet, basic packets -@subsection Error Packet - -@example -+-----------------------------------------------+ -| Header | Status code | Error no | -| | 1 Byte | 2 Byte | -|-----------------------------------------------| -| Messagetext | 0x00 | -| n Byte | 1 Byte | -+-----------------------------------------------+ -@end example - -@table @asis -@item Header -@item 1 byte status code (0xFF = ERROR) -@item 2 byte error number (is only sent to new 3.23 clients. -@item n byte errortext -@item 1 byte 0x00 -@end table - - -@node communication, fieldtype codes, basic packets, protocol -@section Communication - -@example -> Packet from server to client -< Paket from client tor server - - Login - ------ - > 1. packet - Header - 1 byte protocolversion - n byte serverversion - 1 byte 0x00 - 4 byte threadnumber - 8 byte crypt seed - 1 byte 0x00 - 2 byte CLIENT_xxx options (see include/mysql_com.h - that is supported by the server - 1 byte number of current server charset - 2 byte server status variables (SERVER_STATUS_xxx flags) - 13 byte 0x00 (not used yet). - - < 2. packet - Header - 2 byte CLIENT_xxx options - 3 byte max_allowed_packet for the client - n byte username - 1 byte 0x00 - 8 byte crypted password - 1 byte 0x00 - n byte databasename - 1 byte 0x00 - - > 3. packet - OK-packet - - - Command - -------- - < 1. packet - Header - 1 byte command type (e.g.0x03 = query) - n byte query - - Result set (after command) - -------------------------- - > 2. packet - Header - 1-8 byte field_count (packed with net_store_length()) - - If field_count == 0 (command): - 1-8 byte affected rows - 1-8 byte insert id - 2 bytes server_status (SERVER_STATUS_xx) - - If field_count == NULL_LENGTH (251) - LOAD DATA LOCAL INFILE - - If field_count > 0 Result Set: - - > n packets - Header Info - Column description: 5 data object /column - (See code in unpack_fields()) - - Columninfo for each column: - 1 data block table_name - 1 byte length of block - n byte data - 1 data block field_name - 1 byte length of block... - n byte data - 1 data block display length of field - 1 byte length of block - 3 bytes display length of filed - 1 data block type field of type (enum_field_types) - 1 byte length of block - 1 bytexs field of type - 1 data block flags - 1 byte length of block - 2 byte flags for the columns (NOT_NULL_FLAG, ZEROFILL_FLAG....) - 1 byte decimals - - if table definition: - 1 data block default value - - Actual result (one packet per row): - 4 byte header - 1-8 byte length of data - n data -@end example - -@node fieldtype codes, protocol functions, communication, protocol -@section Fieldtype Codes - -@example - display_length |enum_field_type |flags - ---------------------------------------------------- -Blob 03 FF FF 00 |01 FC |03 90 00 00 -Mediumblob 03 FF FF FF |01 FC |03 90 00 00 -Tinyblob 03 FF 00 00 |01 FC |03 90 00 00 -Text 03 FF FF 00 |01 FC |03 10 00 00 -Mediumtext 03 FF FF FF |01 FC |03 10 00 00 -Tinytext 03 FF 00 00 |01 FC |03 10 00 00 -Integer 03 0B 00 00 |01 03 |03 03 42 00 -Mediumint 03 09 00 00 |01 09 |03 00 00 00 -Smallint 03 06 00 00 |01 02 |03 00 00 00 -Tinyint 03 04 00 00 |01 01 |03 00 00 00 -Varchar 03 XX 00 00 |01 FD |03 00 00 00 -Enum 03 05 00 00 |01 FE |03 00 01 00 -Datetime 03 13 00 00 |01 0C |03 00 00 00 -Timestamp 03 0E 00 00 |01 07 |03 61 04 00 -Time 03 08 00 00 |01 0B |03 00 00 00 -Date 03 0A 00 00 |01 0A |03 00 00 00 -@end example - -@node protocol functions, protocol version 2, fieldtype codes, protocol -@section Functions used to implement the protocol - -@c This should be merged with the above one and changed to texi format - -@example - -Raw packets ------------ - -- The my_net_xxxx() functions handles the packaging of a stream of data - into a raw packet that contains a packet number, length and data. - -- This is implemented for the server in sql/net_serv.cc. - The client file, libmysql/net.c, is symlinked to this file - -The important functions are: - -my_net_write() Store a packet (= # number of bytes) to be sent -net_flush() Send the packets stored in the buffer -net_write_command() Send a command (1 byte) + packet to the server. -my_net_read() Read a packet - - -Include files -------------- - -- include/mysql.h is included by all MySQL clients. It includes the - MYSQL and MYSQL_RES structures. -- include/mysql_com.h is include by mysql.h and mysql_priv.h (the - server) and includes a lot of common functions and structures to - handle the client/server protocol. - - -Packets from server to client: ------------------------------ - -sql/net_pkg.cc: - - - Sending of error packets - - Sending of OK packets (= end of data) - - Storing of values in a packet - - -sql/sql_base.cc: - - - Function send_fields() sends the field description to the client. - -sql/sql_show.cc: - - - Sends results for a lot of SHOW commands, including: - SHOW DATABASES [like 'wildcard'] - SHOW TABLES [like 'wildcard'] - - -Packets from client to server: ------------------------------- - -This is done in libmysql/libmysql.c - -The important ones are: - -- mysql_real_connect() Connects to a mysqld server -- mysql_real_query() Sends a query to the server and - reads the ok packet or columns header. -- mysql_store_result() Read a result set from the server to memory -- mysql_use_result() Read a result set row by row from the server. - -- net_safe_read() Read a packet from the server with - error handling. -- net_field_length() Reads the length of a packet string. -- simple_command() Sends a command/query to the server. - - - -Connecting to mysqld (the MySQL server) ---------------------------------------- - -- On the client side: libmysql/libmysql.c::mysql_real_connect(). -- On the server side: sql/sql_parse.cc::check_connections() - -The packets sent during a connection are as follows - -Server: Send greeting package (includes server capabilites, server - version and a random string of bytes to be used to scramble - the password. -Client: Sends package with client capabilites, user name, scrambled - password, database name - -Server: Sends ok package or error package. - -Client: If init command specified, send it t the server and read - ok/error package. - - -Password functions ------------------- - -The passwords are scrambled to a random number and are stored in hex -format on the server. - -The password handling is done in sql/password.c. The important -function is 'scramble()', which takes the a password in clear text -and uses this to 'encrypt' the random string sent by the server -to a new message. - -The encrypted message is sent to the server which uses the stored -random number password to encrypt the random string sent to the -client. If this is equal to the new message the client sends to the -server then the password is accepted. -@end example - -@node protocol version 2, 4.1 protocol changes, protocol functions, protocol -@section Another description of the protocol - -@c This should be merged with the above one and changed to texi format. - -@example -***************************** -* -* PROTOCOL OVERVIEW -* -***************************** - -The MySQL protocol is relatively simple, and is designed for high performance -through minimisation of overhead, and extensibility through versioning and -options flags. It is a request-response protocol, and does not allow -multitasking or multiplexing over a single connection. There are two packet -formats, 'raw' and 'compressed' (which is used when both client and -server support zlib compression, and the client requests that data be -compressed): - -* RAW PACKET, shorter than 16 M * - -+-----------------------------------------------+ -| Packet Length | Packet no | Data | -| 3 Bytes | 1 Byte | n Bytes | -+-----------------------------------------------+ -^ ^ -| 'HEADER' | -+-------------------------------+ - - - * Packet Length: Calculated with int3store. See include/global.h for - details. The basic computation is length = byte1 + - (256 * byte2) + (256 * 256 * byte3). The max packetsize - can be 16 MB. - - * Packet no: The packet number is incremented for each sent packet. - The first packet for each query from the client - starts with 0. - - * Data: Specific to the operation being performed. Most often - used to send string data, such as a SQL query. - -* COMPRESSED PACKET * - -+---------------------------------------------------+-----------------+ -| Packet Length | Packet no | Uncomp. Packet Length | Compressed Data | -| 3 Bytes | 1 Byte | 3 Bytes | n bytes | -+---------------------------------------------------+-----------------+ -^ ^ -| 'HEADER' | -+---------------------------------------------------+ - - * Packet Length: Calculated with int3store. See include/my_global.h for - details. The basic computation is length = byte1 + - (256 * byte2) + (256 * 256 * byte3). The max packetsize - can be 16 MB. - - * Packet no: The packet number is incremented for each sent packet. - The first packet starts with 0. - - * Uncomp. Packet Length: The length of the original, uncompressed packet - If this is zero then the data is not compressed. - - * Compressed Data: The original packet, compressed with zlib compression - - -When using the compressed protocol, the client/server will only compress -send packets where the new packet is smaller than the not compressed one. -In other words, some packets may be compressed while others will not. - -The 'compressed data' is one or more packets in *RAW PACKET* format. - -***************************** -* -* FLOW OF EVENTS -* -***************************** - -To understand how a client communicates with a MySQL server, it is easiest -to start with a high-level flow of events. Each event section will then be -followed by details of the exact contents of each type of packet involved -in the event flow. - -* * -* CONNECTION ESTABLISHMENT * -* * - -Clients connect to the server via a TCP/IP socket (port 3306 by default), a -Unix Domain Socket, or named pipes (on Windows). Once connected, the -following connection establishment sequence is followed: - -+--------+ +--------+ -| Client | | Server | -+--------+ +--------+ - | | - | Handshake initialisation, including MySQL server version, | - | protocol version and options supported, as well as the seed | - | for the password hash | - | | - | <-------------------------------------------------------------- | - | | - | Client options supported, max packet size for client | - | username, password crypted with seed from server, database | - | name. | - | | - | --------------------------------------------------------------> | - | | - | 'OK' packet if authentication succeeds, 'ERROR' packet if | - | authentication fails. | - | | - | <-------------------------------------------------------------- | - | | - - - -* HANDSHAKE INITIALISATION PACKET * - - -+--------------------------------------------------------------------+ -| Header | Prot. Version | Server Version String | 0x00 | -| | 1 Byte | n bytes | 1 byte | -|--------------------------------------------------------------------| -| Thread Number | Crypt Seed | 0x00 | CLIENT_xxx options | -| | | | supported by server | -| 4 Bytes | 8 Bytes | 1 Byte | 2 Bytes | -|--------------------------------------------------------------------| -| Server charset no. | Server status variables | 0x00 padding | -| 1 Byte | 2 Bytes | 13 bytes | -+--------------------------------------------------------------------+ - - * Protocol version (currently '10') - * Server Version String (e.g. '4.0.5-beta-log'). Can be any length as - it's followed by a 0 byte. - * Thread Number - ID of server thread handling this connection - * Crypt seed - seed used to crypt password in auth packet from client - * CLIENT_xxx options - see include/mysql_com.h - * Server charset no. - Index of charset in use by server - * Server status variables - see include/mysql_com.h - * The padding bytes are reserverd for future extensions to the protocol - -* CLIENT AUTH PACKET * - - -+--------------------------------------------------------------------+ -| Header | CLIENT_xxx options supported | max_allowed_packet | -| | by client | for client | -| | 2 Bytes | 3 bytes | -|--------------------------------------------------------------------| -| User Name | 0x00 | Crypted Password | 0x00 | Database Name | -| n Bytes | 1 Byte | 8 Bytes | 1 Byte | n Bytes | -|--------------------------------------------------------------------| -| 0x00 | -| 1 Byte | -+--------------------------------------------------------------------+ - - * CLIENT_xxx options that this client supports: - -#define CLIENT_LONG_PASSWORD 1 /* new more secure passwords */ -#define CLIENT_FOUND_ROWS 2 /* Found instead of affected rows */ -#define CLIENT_LONG_FLAG 4 /* Get all column flags */ -#define CLIENT_CONNECT_WITH_DB 8 /* One can specify db on connect */ -#define CLIENT_NO_SCHEMA 16 /* Don't allow database.table.column */ -#define CLIENT_COMPRESS 32 /* Can use compression protocol */ -#define CLIENT_ODBC 64 /* Odbc client */ -#define CLIENT_LOCAL_FILES 128 /* Can use LOAD DATA LOCAL */ -#define CLIENT_IGNORE_SPACE 256 /* Ignore spaces before '(' */ -#define CLIENT_INTERACTIVE 1024 /* This is an interactive client */ -#define CLIENT_SSL 2048 /* Switch to SSL after handshake */ -#define CLIENT_IGNORE_SIGPIPE 4096 /* IGNORE sigpipes */ -#define CLIENT_TRANSACTIONS 8192 /* Client knows about transactions */ - - * max_allowed_packet for the client (in 'int3store' form) - * User Name - user to authenticate as. Is followed by a null byte. - * Crypted Password - password crypted with seed given in packet from - server, see scramble() in sql/password.c - * Database name (optional) - initial database to use once connected - Is followed by a null byte - -At the end of every client/server exchange there is either an 'OK' packet -or an 'ERROR' packet sent from the server. To determine whether a packet is -an 'OK' packet, or an 'ERROR' packet, check if the first byte (after the -header) is 0xFF. If it has the value of 0xFF, the packet is an 'ERROR' -packet. - - -* OK PACKET * - -For details, see sql/net_pkg.cc::send_ok() - -+-----------------------------------------------+ -| Header | No of Rows | Affected Rows | -| | 1 Byte | 1-9 Byte | -|-----------------------------------------------| -| ID (last_insert_id) | Status | Length | -| 1-9 Byte | 2 Byte | 1-9 Byte | -|-----------------------------------------------| -| Messagetext | -| n Byte | -+-----------------------------------------------+ - - * Number of rows, always 0 - * Affected rows - * ID (last_insert_id) - value for auto_increment column (if any) - * Status (usually 0) - -In general, in the MySQL protocol, fields in a packet that that -represent numeric data, such as lengths, that are labeled as '1-9' -bytes can be decoded by the following logic: - - If the first byte is '251', the - corresponding column value is NULL (only appropriate in - 'ROW DATA' packets). - - If the first byte is '252', the value stored can be read - from the following 2 bytes as a 16-bit integer. - - - If the first byte is '253' the value stored can be read - from the following 4 bytes as a 32-bit long integer - - - If the first byte is '254', the value stored can be read - from the following 8 bytes as a 64-byte long - - Otherwise (values 0-250), the value stored is the value of the - first byte itself. - - -If the OK-packet includes a message: - - * Length of message - * Message Text - - -* ERROR PACKET * - -+-----------------------------------------------+ -| Header | Status code | Error no | -| | 1 Byte | 2 Byte | -|-----------------------------------------------| -| Messagetext | | -| n Byte | | -+-----------------------------------------------+ - - * Status code (0xFF = ERROR) - * Error number (is only sent to 3.23 and newer clients) - * Error message text (ends at end of packet) - -Note that the error message is not null terminated. -The client code can however assume that the packet ends with a null -as my_net_read() will always add an end-null to all read packets to -make things easier for the client. - -Example: - -Packet dump of client connecting to server: - -+------------------------- Protocol Version (10) -| -| +---------------------- Server Version String (0x00 terminated) -| | -| | -0a 34 2e 30 2e 35 2d 62 . 4 . 0 . 5 - b -65 74 61 2d 6c 6f 67 00 e t a - l o g . -15 00 00 00 2b 5a 65 6c . . . . + Z e l - | | - | +------------ First 4 bytes of crypt seed - | - +------------------------ Thread Number - -+------------------------- Last 4 bytes of crypt seed -| -| +-------- CLIENT_XXX Options supported by server -| | -| +-+--+ +--- Server charset index -| | | | -6f 69 41 46 00 2c 28 08 o i A F . , ( . -02 00 00 00 00 00 00 00 . . . . . . . . -| | -| +---------------------- 0x00 padding begins -| -+------------------------- Server status (0x02 = - SERVER_STATUS_AUTOCOMMIT) - -00 00 00 00 00 00 00 00 . . . . . . . . - -* Client Authentication Response (Username 'test', no database - selected) * - - +--------------------- Packet Length (0x13 = 19 bytes) - | - | +--------------- Packet Sequence # - | | - | | +----------- CLIENT_XXX Options supported by client - | | -+---+---+ | +-+-+ -| | | | | -13 00 00 01 03 00 1e 00 . . . . . . . . -00 74 65 73 74 00 48 5e . t e s t . H ^ - | | | - +----+-----+ +------- Scrambled password, 0x00 terminated - | - +----------------- Username, 0x00 terminated - -57 4a 4e 41 4a 4e 00 00 W J N A J N . . -00 . - - ->From this point on, the server waits for 'commands' from the client -which include queries, database shutdown, quit, change user, etc (see -the COM_xxxx values in include/mysql_com.h for the latest -command codes). - -* * -* COMMAND PROCESSING * -* * - -+--------+ +--------+ -| Client | | Server | -+--------+ +--------+ - | | - | A command packet, with a command code, and string data | - | when appropriate (e.g. a query), (see the COM_xxxx values | - | in include/mysql_com.h for the command codes) | - | | - | --------------------------------------------------------------> | - | | - | A 'RESULT' packet if the command completed successfully, | - | an 'ERROR' packet if the command failed. 'RESULT' packets | - | take different forms (see the details following this chart) | - | depending on whether or not the command returns rows. | - | | - | <-------------------------------------------------------------- | - | | - | n 'FIELD PACKET's (if rows are returned) | - | | - | <-------------------------------------------------------------- | - | | - | 'LAST DATA' packet | - | | - | <-------------------------------------------------------------- | - | | - | n 'ROW PACKET's (if rows are returned) | - | | - | <-------------------------------------------------------------- | - | | - | 'LAST DATA' packet | - | | - | <-------------------------------------------------------------- | - | | - - -* Command Packet * - -+------------------------------------------------------+ -| Header | Command type | Query (if applicable) | -| | 1 Byte | n Bytes | -+------------------------------------------------------+ - - * Command type: (e.g.0x03 = query, see the COM_xxxx values in - include/mysql_com.h) - * Query (if applicable) - -Note that my_net_read() null-terminates all packets on the -receiving side of the channel to make it easier for the code -examining the packets. - -The current command codes are: - - 0x00 COM_SLEEP - 0x01 COM_QUIT - 0x02 COM_INIT_DB - 0x03 COM_QUERY - 0x04 COM_FIELD_LIST - 0x05 COM_CREATE_DB - 0x06 COM_DROP_DB - 0x07 COM_REFRESH - 0x08 COM_SHUTDOWN - 0x09 COM_STATISTICS - 0x0a COM_PROCESS_INFO - 0x0b COM_CONNECT - 0x0c COM_PROCESS_KILL - 0x0d COM_DEBUG - 0x0e COM_PING - 0x0f COM_TIME - 0x10 COM_DELAYED_INSERT - 0x11 COM_CHANGE_USER - 0x12 COM_BINLOG_DUMP - 0x13 COM_TABLE_DUMP - 0x14 COM_CONNECT_OUT - 0x15 COM_REGISTER_SLAVE - -* Result Packet * - -Result packet for a command returning _no_ rows: - -+-----------------------------------------------+ -| Header | Field Count | Affected Rows | -| | 1-9 Bytes | 1-9 Bytes | -|-----------------------------------------------| -| ID (last_insert_id) | Server Status | -| 1-9 Bytes | 2 Bytes | -+-----------------------------------------------+ - - * Field Count: Has value of '0' for commands returning _no_ rows - * Affected rows: Count of rows affected by INSERT/UPDATE/DELETE, etc. - * ID: value of auto_increment column in row (if any). 0 if - * Server Status: Usually 0 - -Result packet for a command returning rows: - -+-------------------------------+ -| Header | Field Count | -| | 1-9 Bytes | -+-------------------------------+ - - * Field Count: number of columns/fields in result set, - (packed with net_store_length() in sql/net_pkg.cc) - -This is followed by as many packets as the number of fields ('Field Count') -that contain the metadata for each column/field (see unpack_fields() in -libmysql/libmysql.c): - - -* FIELD PACKET * - -+-----------------------------------------------+ -| Header | Table Name | -| | length-coded-string | -|-----------------------------------------------| -| Field Name | -| length-code-string | -|-----------------------------------------------| -| Display length of field -| length-coded-binary (4 bytes) | -|-----------------------------------------------| -| Field Type (enum_field_types in mysql_com.h) | -| length-coded-binary (2 bytes) | -|-----------------------------------------------| -| Field Flags | Decimal Places| -| length-coded-binary (3 bytes) | 1 Byte | -+--------------+-------------+------------------+ - - * A length coded string is a string where we first have a packet - length (1-9 bytes, packed_with net_store_length()) followed - by a string. - * A length coded binary is a length (1 byte) followed by an integer - value in low-byte-first order. For the moment this type is always - fixed length in this packet. - - * Table Name - the name of the table the column comes from - * Field Name - the name of the column/field - * Display length of field - length of field - * Field Type - Type of field, see enum_field_types in - include/mysql_com.h - - Current field types are: - - 0x00 FIELD_TYPE_DECIMAL - 0x01 FIELD_TYPE_TINY - 0x02 FIELD_TYPE_SHORT - 0x03 FIELD_TYPE_LONG - 0x04 FIELD_TYPE_FLOAT - 0x05 FIELD_TYPE_DOUBLE - 0x06 FIELD_TYPE_NULL - 0x07 FIELD_TYPE_TIMESTAMP - 0x08 FIELD_TYPE_LONGLONG - 0x09 FIELD_TYPE_INT24 - 0x0a FIELD_TYPE_DATE - 0x0b FIELD_TYPE_TIME - 0x0c FIELD_TYPE_DATETIME - 0x0d FIELD_TYPE_YEAR - 0x0e FIELD_TYPE_NEWDATE - 0xf7 FIELD_TYPE_ENUM - 0xf8 FIELD_TYPE_SET - 0xf9 FIELD_TYPE_TINY_BLOB - 0xfa FIELD_TYPE_MEDIUM_BLOB - 0xfb FIELD_TYPE_LONG_BLOB - 0xfc FIELD_TYPE_BLOB - 0xfd FIELD_TYPE_VAR_STRING - 0xfe FIELD_TYPE_STRING - 0xff FIELD_TYPE_GEOMETRY - - * Field Flags - NOT_NULL_FLAG, PRI_KEY_FLAG, xxx_FLAG in - include/mysql_com.h - - -Note that the packet format in 4.1 has slightly changed to allow more values. - - -* ROW PACKET * - -+-----------------------------------------------+ -| Header | Data Length | Column Data | ....for each column -| | 1-9 Bytes | n Bytes | -+-----------------------------------------------+ - - * Data Length: (packed with net_store_length() in sql/net_pkg.cc) - - If 'Data Length' == 0, this is an 'ERROR PACKET'. - - * Column Data: String representation of data. MySQL always sends result set - data as strings. - -* LAST DATA PACKET * - -Packet length is < 9 bytes, and first byte is 0xFE - -+--------+ -| 0xFE | -| 1 Byte | -+--------+ - -Examples: - -*********** -* -* INITDB Command -* -*********** - -A client issuing an 'INITDB' (select the database to use) command, -followed by an 'OK' packet with no rows and no affected rows from -the server: - -* INITDB (select database to use) 'COMMAND' Packet * - - +--------------------- Packet Length (5 bytes) - | - | +--------------- Packet Sequence # - | | - | | +------------ Command # (INITDB = 0x02) - | | -+---+---+ | | +---------- Beginning of query data -| | | | | -05 00 00 00 02 74 65 73 . . . . . t e s -74 t - -* 'OK' Packet with no rows, and no rows affected * - - +--------------------- Packet Length (3 bytes) - | - | +--------------- Packet Sequence # - | | -+---+---+ | -| | | -03 00 00 01 00 00 00 . . . . . . . - - -*********** -* -* SELECT query example -* -*********** - -Client issuing a 'SELECT *' query on the following table: - - CREATE TABLE number_test (minBigInt bigint, - maxBigInt bigint, - testBigInt bigint) - -* 'COMMAND' Packet with QUERY (select ...) * - - +--------------------- Packet Length (26) - | - | +--------------- Packet Sequence # - | | - | | +------------ Command # (QUERY = 0x03) - | | -+---+---+ | | +---------- Beginning of query data -| | | | | -1a 00 00 00 03 53 45 4c . . . . . S E L -45 43 54 20 2a 20 66 72 E C T . * . f r -6f 6d 20 6e 75 6d 62 65 o m . n u m b e -72 5f 74 65 73 74 r _ t e s t - - -and receiving an 'OK' packet with a 'FIELD COUNT' of 3 - - -* 'OK' Packet with 3 fields * - - +--------------------- Packet Length (3 bytes) - | - | +--------------- Packet Sequence # - | | -+---+---+ | -| | | -01 00 00 01 03 . . . . . - -Followed immediately by 3 'FIELD' Packets. Note, the individual packets -are delimitted by =======, so that all fields can be annotated in the first -'FIELD' packet example: - -============================================================= - - +--------------------- Packet Length (0x1f = 31 bytes) - | - | +--------------- Packet Sequence # - | | - | | +------------ Block Length (0x0b = 11 bytes) - | | | -+---+---+ | | +--------- Table Name (11 bytes long) -| | | | | -1f 00 00 02 0b 6e 75 6d . . . . . n u m -62 65 72 5f 74 65 73 74 b e r _ t e s t - - +------------------------ Block Length (9 bytes) - | - | +--------------------- Column Name (9 bytes long) - | | -09 6d 69 6e 42 69 67 49 . m i n B i g I -6e 74 03 14 00 00 01 08 n t . . . . . . - | | | | | - | +---+---+ | +--- Field Type (0x08 = FIELD_TYPE_LONGLONG) - | | | - | | +------ Block Length (1) - | | - | +--------------- Display Length (0x14 = 20 chars) - | - +------------------ Block Length (3) - - +------------------------ Block Length (2) - | - | +-------------------- Field Flags (0 - no flags set) - | | - | +---+ +--------------- Decimal Places (0) - | | | | -02 00 00 00 . . . . - -============================================================= - -'FIELD' packet for the 'number_Test.maxBigInt' column - -1f 00 00 03 0b 6e 75 6d . . . . . n u m -62 65 72 5f 74 65 73 74 b e r _ t e s t -09 6d 61 78 42 69 67 49 . m a x B i g I -6e 74 03 14 00 00 01 08 n t . . . . . . -02 00 00 00 . . . . - -============================================================= - -'FIELD' packet for the 'number_test.testBigInt' column - -20 00 00 04 0b 6e 75 6d . . . . . n u m -62 65 72 5f 74 65 73 74 b e r _ t e s t -0a 74 65 73 74 42 69 67 . t e st B i g -49 6e 74 03 14 00 00 01 I n t . . . . . -08 02 00 00 00 . . . . . -============================================================= - -Followed immediately by one 'LAST DATA' packet: - -fe 00 . . - -Followed immediately by 'n' row packets (in this case, only -one packet is sent from the server, for simplicity's sake): - - - +--------------------- Packet Length (0x52 = 82 bytes) - | - | +--------------- Packet Sequence # - | | - | | +------------ Data Length (0x14 = 20 bytes) - | | | -+---+---+ | | +--------- String Data '-9223372036854775808' -| | | | | (repeat Data Length/Data sequence) - -52 00 00 06 14 2d 39 32 . . . . . - 9 2 -32 33 33 37 32 30 33 36 2 3 3 7 2 0 3 6 -38 35 34 37 37 35 38 30 8 5 4 7 7 5 8 0 -38 13 39 32 32 33 33 37 8 . 9 2 2 3 3 7 -32 30 33 36 38 35 34 37 2 0 3 6 8 5 4 7 -37 35 38 30 37 0a 36 31 7 5 8 0 7 . 6 1 -34 37 34 38 33 36 34 37 4 7 4 8 3 6 4 7 - -Followed immediately by one 'LAST DATA' packet: - -fe 00 . . -@end example - - -@c The Index was empty, and ugly, so I removed it. (jcole, Sep 7, 2000) - -@c @node Index -@c @unnumbered Index - -@c @printindex fn - -@c @node 4.1 protocol,,, -@c @chapter MySQL 4.1 protocol - -@node 4.1 protocol changes, 4.1 field packet, protocol version 2, protocol -@section Changes to 4.0 protocol in 4.1 - -All basic packet handling is identical to 4.0. When communication -with an old 4.0 or 3.x client we will use the old protocol. - -The new things that we support with 4.1 are: - -@itemize @bullet -@item -Warnings -@item -Prepared statements -@item -Binary protocol (will be faster than the current protocol that -converts everything to strings) -@end itemize - - -What has changed in 4.1 are: - -@itemize @bullet -@item -A lot of new field information (database, real table name etc) -@item -The 'ok' packet has more status fields -@item -The 'end' packet (send last for each result set) now contains some -extra information -@item -New protocol for prepared statements. In this case all parameters and -results will sent as binary (low-byte-first). -@end itemize - - -@node 4.1 field packet, 4.1 field desc, 4.1 protocol changes, protocol -@section 4.1 field description packet - -The field description packet is sent as a response to a query that -contains a result set. It can be distinguished from a ok packet by -the fact that the first byte can't be 0 for a field packet. -@xref{4.1 ok packet}. - -The header packet has the following structure: - -@multitable @columnfractions .10 .90 -@item Size @tab Comment -@item 1-9 @tab Number of columns in result set (never 0) -@item 1-9 @tab Extra information sent be some command (SHOW COLUMNS -uses this to send the number of rows in the table) -@end multitable - -This packet is always followed by a field description set. -@xref{4.1 field desc}. - -@node 4.1 field desc, 4.1 ok packet, 4.1 field packet, protocol -@section 4.1 field description result set - -The field description result set contains the meta info for a result set. - -@multitable @columnfractions .20 .80 -@item Type @tab Comment -@item string @tab Database name -@item string @tab Table name alias (or table name if no alias) -@item string @tab Real table name -@item string @tab Alias for column name (or column name if not used) -@item 3 byte int @tab Length of column definition -@item 1 byte int @tab Enum value for field type -@item 3 byte int @tab 2 byte column flags (NOT_NULL_FLAG etc..) + 1 byte number of decimals. -@item string int @tab Default value, only set when using mysql_list_fields(). -@end multitable - - -@node 4.1 ok packet, 4.1 end packet, 4.1 field desc, protocol -@section 4.1 ok packet - -The ok packet is the first that is sent as an response for a query -that didn't return a result set. - -The ok packet has the following structure: - -@multitable @columnfractions .10 .90 -@item Size @tab Comment -@item 1 @tab 0 ; Marker for ok packet -@item 1-9 @tab Affected rows -@item 1-9 @tab Last insert id (0 if one wasn't used) -@item 2 @tab Server status; Can be used by client to check if we are inside an transaction -@item 2 @tab Warning count -@item 1-9 @tab Message length (optional) -@item xxx @tab Message (optional) -@end multitable - -Size 1-9 means that the parameter is packed in to 1-9 bytes depending on -the value. (See function sql/net_pkg.cc::net_store_length). - -The message is optional. For example for multi line INSERT it -contains a string for how many rows was inserted / deleted. - - -@node 4.1 end packet, 4.1 error packet, 4.1 ok packet, protocol -@section 4.1 end packet - -The end packet is sent as the last packet for - -@itemize @bullet -@item -End of field information -@item -End of parameter type information -@item -End of result set -@end itemize - -The end packet has the following structure: - -@multitable @columnfractions .10 .90 -@item Size @tab Comment -@item 1 @tab 254 ; Marker for EOF packet -@item 2 @tab Warning count -@item 2 @tab Status flags (For flags like SERVER_STATUS_MORE_RESULTS) -@end multitable - -Note that a normal packet may start with byte 254, which means -'length stored in 9 bytes'. One can different between these cases -by checking the packet length < 9 bytes (in which case it's and end -packet). - - -@node 4.1 error packet, 4.1 prep init, 4.1 end packet, protocol -@section 4.1 error packet. - -The error packet is sent when something goes wrong. -The error packet has the following structure: - -@multitable @columnfractions .10 .90 -@item Size @tab Comment -@item 1 @tab 255 Error packet marker -@item 2 @tab Error code -@item 1-255 @tab Null terminated error message -@end multitable - -The client/server protocol is designed in such a way that a packet -can only start with 255 if it's an error packet. - - -@node 4.1 prep init, 4.1 long data, 4.1 error packet, protocol -@section 4.1 prepared statement init packet - -This is the return packet when one sends a query with the COM_PREPARE -command. - -@multitable @columnfractions .10 .90 -@item Size @tab Comment -@item 4 @tab Statement handler id -@item 2 @tab Number of columns in result set -@item 2 @tab Number of parameters in query -@end multitable - -After this, there is a packet that contains the following for each -parameter in the query: - -@multitable @columnfractions .10 .90 -@item Size @tab Comment -@item 2 @tab Enum value for field type. (MYSQL_TYPE_UNKNOWN if not known) -@item 2 @tab 2 byte column flags (NOT_NULL_FLAG etc) -@item 1 @tab Number of decimals -@item 4 @tab Max column length. -@end multitable - -Note that the above is not yet in 4.1 but will be added this month. - -As MySQL can have a parameter 'anywhere' it will in many cases not be -able to provide the optimal information for all parameters. - -If number of columns, in the header packet, is not 0 then the -prepared statement will contain a result set. In this case the packet -is followed by a field description result set. @xref{4.1 field desc}. - - -@node 4.1 long data, 4.1 execute, 4.1 prep init, protocol -@section 4.1 long data handling - -This is used by mysql_send_long_data() to set any parameter to a string -value. One can call mysql_send_long_data() multiple times for the -same parameter; The server will concatenate the results to a one big -string. - -The server will not require an end packet for the string. -mysql_send_long_data() is responsible updating a flag that all data -has been sent. (Ie; That the last call to mysql_send_long_data() has -the 'last_data' flag set). - -This packet is sent from client -> server: - -@multitable @columnfractions .10 .90 -@item Size @tab Comment -@item 4 @tab Statement handler -@item 2 @tab Parameter number -@item 2 @tab Type of parameter (not used at this point) -@item # @tab data (Rest of packet) -@end multitable - -The server will NOT send an @code{ok} or @code{error} packet in -responce for this. If there is any errors (like to big string), one -will get the error when calling execute. - -@node 4.1 execute, 4.1 binary result, 4.1 long data, protocol -@section 4.1 execute - -On execute we send all parameters to the server in a COM_EXECUTE -packet. - -The packet contains the following information: - -@multitable @columnfractions .30 .70 -@item Size @tab Comment -@item (param_count+9)/8 @tab Null bit map (2 bits reserved for protocol) -@item 1 @tab new_parameter_bound flag. Is set to 1 for first -execute or if one has rebound the parameters. -@item 2*param_count @tab Type of parameters (only given if new_parameter_bound flag is 1) -@item # @tab Parameter data, repeated for each parameter that are -NOT NULL and not used with mysql_send_long_data(). -@end multitable - -The null-bit-map is for all parameters (including parameters sent with -'mysql_send_long_data). If parameter 0 is NULL, then bit 0 in the -null-bit-map should be 1 (ie: first byte should be 1) - -The parameters are stored the following ways: - -@multitable @columnfractions .20 .10 .70 -@item Type @tab Size @tab Comment -@item tinyint @tab 1 @tab One byte integer -@item short @tab 2 @tab -@item int @tab 4 @tab -@item longlong @tab 8 @tab -@item float @tab 4 @tab -@item double @tab 8 @tab -@item string @tab 1-9 + # @tab Packed string length + string -@end multitable - -The result for this will be either an ok packet or a binary result -set. - -@node 4.1 binary result, , 4.1 execute, protocol -@section 4.1 binary result set - -A binary result are sent the following way. - -For each result row: - -@itemize -@item -null bit map with first two bits set to 01 (bit 0,1 value 1) -@item -parameter data, repeated for each not null result column. -@end itemize - -The idea with the reserving two bits in the null map is that we can -use standard error (first byte 255) and ok packets (first byte 0) -to end a result sets. - -Except that the null-bit-map is shifted two steps, the server is -sending the data to the client the same way that the server is sending -bound parameters to the client. The server is always sending the data -as type given for 'column type' for respective column. It's up to the -client to convert the parameter to the requested type. - -DATETIME, DATE and TIME are sent to the server in a binary format as follows: - -@multitable @columnfractions .20 .10 .70 -@item Type @tab Size @tab Comment -@item date @tab 1 + 0-11 @tab Length + 2 byte year, 1 byte MMDDHHMMSS, 4 byte billionth of a second -@item datetime @tab 1 + 0-11 @tab Length + 2 byte year, 1 byte MMDDHHMMSS, 4 byte billionth of a second -@item time @tab 1 + 0-14 @tab Length + sign (0 = pos, 1= neg), 4 byte days, 1 byte HHMMDD, 4 byte billionth of a second -@end multitable - -The first byte is a length byte and then comes all parameters that are -not 0. (Always counted from the beginning). - -@node Fulltext Search, MyISAM Record Structure, protocol, Top -@chapter Fulltext Search in MySQL - -Hopefully, sometime there will be complete description of -fulltext search algorithms. -Now it's just unsorted notes. - -@menu -* Weighting in boolean mode:: -@end menu - -@node Weighting in boolean mode, , Fulltext Search, Fulltext Search -@section Weighting in boolean mode - -The basic idea is as follows: in expression -@code{A or B or (C and D and E)}, either @code{A} or @code{B} alone -is enough to match the whole expression. While @code{C}, -@code{D}, and @code{E} should @strong{all} match. So it's -reasonable to assign weight 1 to @code{A}, @code{B}, and -@code{(C and D and E)}. And @code{C}, @code{D}, and @code{E} -should get a weight of 1/3. - -Things become more complicated when considering boolean -operators, as used in MySQL FTB. Obvioulsy, @code{+A +B} -should be treated as @code{A and B}, and @code{A B} - -as @code{A or B}. The problem is, that @code{+A B} can @strong{not} -be rewritten in and/or terms (that's the reason why this - extended - -set of operators was chosen). Still, aproximations can be used. -@code{+A B C} can be approximated as @code{A or (A and (B or C))} -or as @code{A or (A and B) or (A and C) or (A and B and C)}. -Applying the above logic (and omitting mathematical -transformations and normalization) one gets that for -@code{+A_1 +A_2 ... +A_N B_1 B_2 ... B_M} the weights -should be: @code{A_i = 1/N}, @code{B_j=1} if @code{N==0}, and, -otherwise, in the first rewritting approach @code{B_j = 1/3}, -and in the second one - @code{B_j = (1+(M-1)*2^M)/(M*(2^(M+1)-1))}. - -The second expression gives somewhat steeper increase in total -weight as number of matched B's increases, because it assigns -higher weights to individual B's. Also the first expression in -much simplier. So it is the first one, that is implemented in MySQL. - - -@node MyISAM Record Structure, InnoDB Record Structure, Fulltext Search, Top -@chapter MyISAM Record Structure - -@section Introduction - -When you say: -@* - -@strong{CREATE TABLE Table1 ...} -@* - -MySQL creates files named Table1.MYD ("MySQL Data"), Table1.MYI -("MySQL Index"), and Table1.frm ("Format"). These files will be in the -directory: @* -/// -@* - -For example, if you use Linux, you might find the files here (assume -your database name is "test"): @* -/usr/local/var/test -@* - -And if you use Windows, you might find the files in this directory: @* -\mysql\data\test\ -@*@* - -Let's look at the .MYD Data file (MyISAM SQL Data file) more closely. -There are three possible formats -- fixed, dynamic, and packed. First, -let's discuss the fixed format. - - -@table @strong -@item Page Size -Unlike most DBMSs, MySQL doesn't store on disk using pages. Therefore -you will not see filler space between rows. (Reminder: This does not -refer to BDB and InnoDB tables, which do use pages). -@* - -@item Record Header -The minimal record header is a set of flags: -@itemize @bullet -@item -"X bit" = 0 if row is deleted, = 1 if row is not deleted -@item -"Null Bits" = 0 if column is not NULL, = 1 if column is NULL -@item -"Filler Bits" = 1 -@end itemize -@end table -@* - -The length of the record header is thus:@* -(1 + number of NULL columns + 7) / 8 bytes@* -After the header, all columns are stored in -the order that they were created, which is the -same order that you would get from SHOW COLUMNS. - -Here's an example. Suppose you say: -@* - -@strong{CREATE TABLE Table1 (column1 CHAR(1), column2 CHAR(1), column3 CHAR(1))} -@* - -@strong{INSERT INTO Table1 VALUES ('a', 'b', 'c')} -@* - -@strong{INSERT INTO Table1 VALUES ('d', NULL, 'e')} -@* - -A CHAR(1) column takes precisely one byte (plus one bit of overhead -that is assigned to every column -- I'll describe the details of -column storage later). So the file Table1.MYD looks like this: -@* - -@strong{Hexadecimal Display of Table1.MYD file}@* -@code{ -F1 61 62 63 00 F5 64 00 66 00 ... .abc..d e. -} -@* - -Here's how to read this hexadecimal-dump display:@* -@itemize @bullet -@item -The hexadecimal numbers @code{F1 61 62 63 00 F5 64 20 66 00} are byte -values and the column on the right is an attempt to show the -same bytes in ASCII. -@item -The @code{F1} byte means that there are no null fields in the first row. -@item -The @code{F5} byte means that the second column of the second row is NULL. -@end itemize - -(It's probably easier to understand the flag setting if you restate -@code{F5} as @code{11110101 binary}, and (a) notice that the third flag bit from the -right is @code{on}, and (b) remember that the first flag bit is the X bit.) -@* - -There are complications -- the record header is more complex if there -are variable-length fields -- but the simple display shown in the -example is exactly what you'd see if you looked at the MySQL Data file -with a debugger or a hexadecimal file dumper. -@* - -So much for the fixed format. Now, let's discuss the dynamic format. -@* - -The dynamic file format is necessary if rows can vary in size. That will -be the case if there are BLOB columns, or "true" VARCHAR columns. (Remember -that MySQL may treat VARCHAR columns as if they're CHAR columns, in which -case the fixed format is used.) A dynamic row has more fields in the header. -The important ones are "the actual length", "the unused length", and "the -overflow pointer". The actual length is the total number of bytes in all the -columns. The unused length is the total number of bytes between one physical -record and the next one. The overflow pointer is the location of the rest of -the record if there are multiple parts. -@* - -For example, here is a dynamic row: -@* -@example -03, 00 start of header -04 actual length -0c unused length -01, fc flags + overflow pointer -**** data in the row -************ unused bytes - <-- next row starts here) -@end example - -In the example, the actual length and the unused length -are short (one byte each) because the table definition -says that the columns are short -- if the columns were -potentially large, then the actual length and the unused -length could be two bytes each, three bytes each, and so -on. In this case, actual length plus unused length is 10 -hexadecimal (sixteen decimal), which is a minimum. - -As for the third format -- packed -- we will only say -briefly that: -@itemize @bullet -@item -Numeric values are stored in a form that depends on the -range (start/end values) for the data type. -@item -All columns are packed using either Huffman or enum coding. -@end itemize - -For details, see the source files /myisam/mi_statrec.c -(for fixed format), /myisam/mi_dynrec.c (for dynamic -format), and /myisam/mi_packrec.c (for packed format). - -Note: Internally, MySQL uses a format much like the fixed format -which it uses for disk storage. The main differences are: -@enumerate -@item -BLOBs have a length and a memory pointer rather than being stored inline. -@item -"True VARCHAR" (a column storage which will be fully implemented in -version 5.0) will have a 16-bit length plus the data. -@item -All integer or floating-point numbers are stored with the low byte first. -Point (3) does not apply for ISAM storage or internals. -@end enumerate -@* - - -@section Physical Attributes of Columns - -Next I'll describe the physical attributes of each column in a row. -The format depends entirely on the data type and the size of the -column, so, for every data type, I'll give a description and an example. -@* - -@table @strong -@item The character data types - -@strong{CHAR} -@itemize @bullet -@item -Storage: fixed-length string with space padding on the right. -@item -Example: a CHAR(5) column containing the value 'A' looks like:@* -@code{hexadecimal 41 20 20 20 20} -- (length = 5, value = @code{'A '}) -@end itemize - -@strong{VARCHAR} -@itemize @bullet -@item -Storage: variable-length string with a preceding length. -@item -Example: a VARCHAR(7) column containing 'A' looks like:@* -@code{hexadecimal 01 41} -- (length = 1, value = @code{'A'}) -@end itemize - -@item The numeric data types - -Important: MySQL almost always stores multi-byte binary numbers with -the low byte first. This is called "little-endian" numeric storage; -it's normal on Intel x86 machines; MySQL uses it even for non-Intel -machines so that databases will be portable. -@* - -@strong{TINYINT} -@itemize @bullet -@item -Storage: fixed-length binary, always one byte. -@item -Example: a TINYINT column containing 65 looks like:@* -@code{hexadecimal 41} -- (length = 1, value = 65) -@end itemize - -@strong{SMALLINT} -@itemize @bullet -@item -Storage: fixed-length binary, always two bytes. -@item -Example: a SMALLINT column containing 65 looks like:@* -@code{hexadecimal 41 00} -- (length = 2, value = 65) -@end itemize - -@strong{MEDIUMINT} -@itemize @bullet -@item -Storage: fixed-length binary, always three bytes. -@item -Example: a MEDIUMINT column containing 65 looks like:@* -@code{hexadecimal 41 00 00} -- (length = 3, value = 65) -@end itemize - -@strong{INT} -@itemize @bullet -@item -Storage: fixed-length binary, always four bytes. -@item -Example: an INT column containing 65 looks like:@* -@code{hexadecimal 41 00 00 00} -- (length = 4, value = 65) -@end itemize - -@strong{BIGINT} -@itemize @bullet -@item -Storage: fixed-length binary, always eight bytes. -@item -Example: a BIGINT column containing 65 looks like:@* -@code{hexadecimal 41 00 00 00 00 00 00 00} -- (length = 8, value = 65) -@end itemize - -@strong{FLOAT} -@itemize @bullet -@item -Storage: fixed-length binary, always four bytes. -@item -Example: a FLOAT column containing approximately 65 looks like:@* -@code{hexadecimal 00 00 82 42} -- (length = 4, value = 65) -@end itemize - -@strong{DOUBLE PRECISION} -@itemize @bullet -@item -Storage: fixed-length binary, always eight bytes. -@item -Example: a DOUBLE PRECISION column containing approximately 65 looks like:@* -@code{hexadecimal 00 00 00 00 00 40 50 40} -- (length = 8, value = 65) -@end itemize - -@strong{REAL} -@itemize @bullet -@item -Storage: same as FLOAT, or same as DOUBLE PRECISION, depending on setting of the --ansi switch. -@end itemize - -@strong{DECIMAL} -@itemize @bullet -@item -Storage: fixed-length string, with a leading byte for the sign, if any. -@item -Example: a DECIMAL(2) column containing 65 looks like:@* -@code{hexadecimal 20 36 35} -- (length = 3, value = @code{' 65'}) -@item -Example: a DECIMAL(2) UNSIGNED column containing 65 looks like:@* -@code{hexadecimal 36 35} -- (length = 2, value = @code{'65'}) -@item -Example: a DECIMAL(4,2) UNSIGNED column containing 65 looks like:@* -@code{hexadecimal 36 35 2E 30 30} -- (length = 5, value = @code{'65.00'}) -@end itemize - -@strong{NUMERIC} -@itemize @bullet -@item -Storage: same as DECIMAL. -@end itemize - -@strong{BOOL} -@itemize @bullet -@item -Storage: same as TINYINT. -@end itemize - -@item The temporal data types - -@strong{DATE} -@itemize @bullet -@item -Storage: 3 byte integer, low byte first. -Packed as: 'day + month*32 + year*16*32' -@item -Example: a DATE column containing '1962-01-02' looks like:@* -@code{hexadecimal 22 54 0F} -@end itemize - -@strong{DATETIME} -@itemize @bullet -@item -Storage: eight bytes. -@item -Part 1 is a 32-bit integer containing year*10000 + month*100 + day. -@item -Part 2 is a 32-bit integer containing hour*10000 + minute*100 + second. -@item -Example: a DATETIME column for '0001-01-01 01:01:01' looks like:@* -@code{hexadecimal B5 2E 11 5A 02 00 00 00} -@end itemize - -@strong{TIME} -@itemize @bullet -@item -Storage: 3 bytes, low byte first. -This is stored as seconds: days*24*3600+hours*3600+minutes*60+seconds -@item -Example: a TIME column containing '1 02:03:04' (1 day 2 hour 3 minutes and 4 seconds) looks like:@* -@code{hexadecimal 58 6E 01} -@end itemize - -@strong{TIMESTAMP} -@itemize @bullet -@item -Storage: 4 bytes, low byte first. -Stored as unix @code{time()}, which is seconds since the Epoch -(00:00:00 UTC, January 1, 1970). -@item -Example: a TIMESTAMP column containing '2003-01-01 01:01:01' looks like:@* -@code{hexadecimal 4D AE 12 23} -@end itemize - -@strong{YEAR} -@itemize @bullet -@item -Storage: same as unsigned TINYINT with a base value of 0 = 1901. -@end itemize - -@item Others - -@strong{SET} -@itemize @bullet -@item -Storage: one byte for each eight members in the set. -@item -Maximum length: eight bytes (for maximum 64 members). -@item -This is a bit list. The least significant bit corresponds to the -first listed member of the set. -@item -Example: a SET('A','B','C') column containing 'A' looks like:@* -@code{01} -- (length = 1, value = 'A') -@end itemize - -@strong{ENUM} -@itemize @bullet -@item -Storage: one byte if less than 256 alternatives, else two bytes. -@item -This is an index. The value 1 corresponds to the first listed -alternative. (Note: ENUM always reserves 0 for an erroneous value. This -explains why 'A' is 1 instead of 0.) -@item -Example: an ENUM('A','B','C') column containing 'A' looks like:@* -@code{01} -- (length = 1, value = 'A') -@end itemize - -@item The Large-Object data types - -Warning: Because TINYBLOB's preceding length is one byte long (the -size of a TINYINT) and MEDIUMBLOB's preceding length is three bytes -long (the size of a MEDIUMINT), it's easy to think there's some sort -of correspondence between the BLOB and the INT types. There isn't -- a -BLOB's preceding length is not four bytes long (the size of an INT). -@* - -@strong{TINYBLOB} -@itemize @bullet -@item -Storage: variable-length string with a preceding one-byte length. -@item -Example: a TINYBLOB column containing 'A' looks like:@* -@code{hexadecimal 01 41} -- (length = 2, value = 'A') -@end itemize - -@strong{TINYTEXT} -@itemize @bullet -@item -Storage: same as TINYBLOB. -@end itemize - -@strong{BLOB} -@itemize @bullet -@item -Storage: variable-length string with a preceding two-byte length. -@item -Example: a BLOB column containing 'A' looks like:@* -@code{hexadecimal 01 00 41} -- (length = 2, value = 'A') -@end itemize - -@strong{TEXT} -@itemize @bullet -@item -Storage: same as BLOB. -@end itemize - -@strong{MEDIUMBLOB} -@itemize @bullet -@item -Storage: variable-length string with a preceding length. -@item -Example: a MEDIUMBLOB column containing 'A' looks like:@* -@code{hexadecimal 01 00 00 41} -- (length = 4, value = 'A') -@end itemize - -@strong{MEDIUMTEXT} -@itemize @bullet -@item -Storage: same as MEDIUMBLOB. -@end itemize - -@strong{LONGBLOB} -@itemize @bullet -@item -Storage: variable-length string with a preceding four-byte length. -@item -Example: a LONGBLOB column containing 'A' looks like:@* -@code{hexadecimal 01 00 00 00 41} -- (length = 5, value = 'A') -@end itemize - -@strong{LONGTEXT} -@itemize @bullet -@item -Storage: same as LONGBLOB. -@end itemize - -@end table - -@section Where to Look For More Information - -@strong{References:} @* -Most of the formatting work for MyISAM columns is visible -in the program /sql/field.cc in the source code directory. -And in the MyISAM directory, the files that do formatting -work for different record formats are: /myisam/mi_statrec.c, -/myisam/mi_dynrec.c, and /myisam/mi_packrec.c. -@* - -@node InnoDB Record Structure, InnoDB Page Structure, MyISAM Record Structure, Top -@chapter InnoDB Record Structure - -This page contains: -@itemize @bullet -@item -A high-altitude "summary" picture of the parts of a MySQL/InnoDB -record structure. -@item -A description of each part. -@item -An example. -@end itemize - -After reading this page, you will know how MySQL/InnoDB stores a -physical record. -@* - -@section High-Altitude Picture - -The chart below shows the three parts of a physical record. - -@multitable @columnfractions .10 .35 - -@item @strong{Name} @tab @strong{Size} -@item Field Start Offsets -@tab (F*1) or (F*2) bytes -@item Extra Bytes -@tab 6 bytes -@item Field Contents -@tab depends on content - -@end multitable - -Legend: The letter 'F' stands for 'Number Of Fields'. - -The meaning of the parts is as follows: -@itemize @bullet -@item -The FIELD START OFFSETS is a list of numbers containing the -information "where a field starts". -@item -The EXTRA BYTES is a fixed-size header. -@item -The FIELD CONTENTS contains the actual data. -@end itemize - -@strong{An Important Note About The Word "Origin"}@* -The "Origin" or "Zero Point" of a record is the first byte of the -Field Contents -- not the first byte of the Field Start Offsets. If -there is a pointer to a record, that pointer is pointing to the -Origin. Therefore the first two parts of the record are addressed by -subtracting from the pointer, and only the third part is addressed by -adding to the pointer. - -@subsection FIELD START OFFSETS - -The Field Start Offsets is a list in which each entry is the -position, relative to the Origin, of the start of the next field. The -entries are in reverse order, that is, the first field's offset is at -the end of the list. -@* - -An example: suppose there are three columns. The first column's length -is 1, the second column's length is 2, and the third column's length is 4. -In this case, the offset values are, respectively, 1, 3 (1+2), and 7 (1+2+4). -Because values are reversed, a core dump of the Field Start Offsets -would look like this: @code{07,03,01}. -@* - -There are two complications for special cases: -@itemize @bullet -@item -Complication #1: The size of each offset can be either one byte or -two bytes. One-byte offsets are only usable if the total record size -is less than 127. There is a flag in the "Extra Bytes" part which will -tell you whether the size is one byte or two bytes. -@item -Complication #2: The most significant bits of an offset may contain -flag values. The next two paragraphs explain what the contents are. -@end itemize - -@strong{When The Size Of Each Offset Is One Byte} -@itemize @bullet -@item -1 bit = 0 if field is non-NULL, = 1 if field is NULL -@item -7 bits = the actual offset, a number between 0 and 127 -@end itemize - -@strong{When The Size Of Each Offset Is Two Bytes} -@itemize @bullet -@item -1 bit = 0 if field is non-NULL, = 1 if field is NULL -@item -1 bit = 0 if field is on same page as offset, = 1 if field and offset are on different pages -@item -14 bits = the actual offset, a number between 0 and 16383 -@end itemize - -It is unlikely that the "field and offset are on different pages" -unless the record contains a large BLOB. - -@subsection EXTRA BYTES - -The Extra Bytes are a fixed six-byte header. - -@multitable @columnfractions .10 .25 .35 - -@item @strong{Name} @tab @strong{Size} @tab @strong{Description} -@item @strong{info_bits:} -@item () -@tab 1 bit -@tab unused or unknown -@item () -@tab 1 bit -@tab unused or unknown -@item deleted_flag -@tab 1 bit -@tab 1 if record is deleted -@item min_rec_flag -@tab 1 bit -@tab 1 if record is predefined minimum record -@item n_owned -@tab 4 bits -@tab number of records owned by this record -@item heap_no -@tab 13 bits -@tab record's order number in heap of index page -@item n_fields -@tab 10 bits -@tab number of fields in this record, 1 to 1023 -@item 1byte_offs_flag -@tab 1 bit -@tab 1 if each Field Start Offsets is 1 byte long (this item is also called the "short" flag) -@item @strong{next 16 bits} -@tab 16 bits -@tab pointer to next record in page -@item @strong{TOTAL} -@tab 48 bits - -@end multitable - -Total size is 48 bits, which is six bytes. -@* - -If you're just trying to read the record, the key bit in the Extra -Bytes is 1byte_offs_flag -- you need to know if 1byte_offs_flag is 1 -(i.e.: "short 1-byteoffsets") or 0 (i.e.: "2-byte offsets"). -@* - -Given a pointer to the Origin, InnoDB finds the start of the record as follows: -@itemize @bullet -@item -Let X = n_fields (the number of fields is by definition equal to the -number of entries in the Field Start Offsets Table). -@item -If 1byte_offs_flag equals 0, then let X = X * 2 because there are -two bytes for each entry instead of just one. -@item -Let X = X + 6, because the fixed size of Extra Bytes is 6. -@item -The start of the record is at (pointer value minus X). -@end itemize - -@subsection FIELD CONTENTS - -The Field Contents part of the record has all the data. Fields are -stored in the order they were defined in. -@* - -There are no markers between fields, and there is no marker or filler -at the end of a record. -@* - -Here's an example. -@itemize @bullet -@item -I made a table with this definition: -@*@* - -@strong{CREATE TABLE T - (FIELD1 VARCHAR(3), FIELD2 VARCHAR(3), FIELD3 VARCHAR(3)) - Type=InnoDB;} -@*@* - -To understand what follows, you must know that table T has six columns --- not three -- because InnoDB automatically added three "system -columns" at the start for its own housekeeping. It happens that these -system columns are the row ID, the transaction ID, and the rollback -pointer, but their values don't matter now. Regard them as three black -boxes. -@*@* - -@item -I put some rows in the table. My last three INSERTs were: -@*@* - -@strong{INSERT INTO T VALUES ('PP', 'PP', 'PP')} -@*@* - -@strong{INSERT INTO T VALUES ('Q', 'Q', 'Q')} -@*@* - -@strong{INSERT INTO T VALUES ('R', NULL, NULL)} -@*@* - -@item -I ran Borland's TDUMP to get a hexadecimal dump of -the contents of \mysql\data\ibdata1, which (in my case) is the -MySQL/InnoDB data file (on Windows). -@end itemize - -Here is an extract of the dump: - -@multitable @columnfractions .05 .95 - -@item @strong{Address Values In Hexadecimal} @tab @strong{Values In ASCII} -@item @code{0D4280: 00 00 2D 00 84 4F 4F 4F 4F 4F 4F 4F 4F 4F 19 17} -@tab @code{..-..OOOOOOOOO..} -@item @code{0D4290: 15 13 0C 06 00 00 78 0D 02 BF 00 00 00 00 04 21} -@tab @code{......x........!} -@item @code{0D42A0: 00 00 00 00 09 2A 80 00 00 00 2D 00 84 50 50 50} -@tab @code{.....*....-..PPP} -@item @code{0D42B0: 50 50 50 16 15 14 13 0C 06 00 00 80 0D 02 E1 00} -@tab @code{PPP.............} -@item @code{0D42C0: 00 00 00 04 22 00 00 00 00 09 2B 80 00 00 00 2D} -@tab @code{....".....+....-} -@item @code{0D42D0: 00 84 51 51 51 94 94 14 13 0C 06 00 00 88 0D 00} -@tab @code{..QQQ...........} -@item @code{0D42E0: 74 00 00 00 00 04 23 00 00 00 00 09 2C 80 00 00} -@tab @code{t.....#.....,...} -@item @code{0D42F0: 00 2D 00 84 52 00 00 00 00 00 00 00 00 00 00 00} -@tab @code{.-..R...........} - -@end multitable - -A reformatted version of the dump, showing only the relevant bytes, -looks like this (I've put a line break after each field and added labels): - -@strong{Reformatted Hexadecimal Dump}@* -@code{ - 19 17 15 13 0C 06 Field Start Offsets /* First Row */@* - 00 00 78 0D 02 BF Extra Bytes@* - 00 00 00 00 04 21 System Column #1@* - 00 00 00 00 09 2A System Column #2@* - 80 00 00 00 2D 00 84 System Column #3@* - 50 50 Field1 'PP'@* - 50 50 Field2 'PP'@* - 50 50 Field3 'PP'}@* - -@code{ - 16 15 14 13 0C 06 Field Start Offsets /* Second Row */@* - 00 00 80 0D 02 E1 Extra Bytes@* - 00 00 00 00 04 22 System Column #1@* - 00 00 00 00 09 2B 80 System Column #2@* - 00 00 00 2D 00 84 System Column #3@* - 51 Field1 'Q'@* - 51 Field2 'Q'@* - 51 Field3 'Q'}@* - -@code{ - 94 94 14 13 0C 06 Field Start Offsets /* Third Row */@* - 00 00 88 0D 00 74 Extra Bytes@* - 00 00 00 00 04 23 System Column #1@* - 00 00 00 00 09 2C System Column #2@* - 80 00 00 00 2D 00 84 System Column #3@* - 52 Field1 'R'}@* -@* - -You won't need explanation if you followed everything I've said, but -I'll add helpful notes for the three trickiest details. -@itemize @bullet -@item -Helpful Notes About "Field Start Offsets": @* -Notice that the sizes of the record's fields, in forward order, are: -6, 6, 7, 2, 2, 2. Since each offset is for the start of the "next" -field, the hexadecimal offsets are 06, 0c (6+6), 13 (6+6+7), 15 -(6+6+7+2), 17 (6+6+7+2+2), 19 (6+6+7+2+2+2). Reversing the order, the -Field Start Offsets of the first record are: @code{19,17,15,13,0c,06}. -@item -Helpful Notes About "Extra Bytes": @* -Look at the Extra Bytes of the first record: @code{00 00 78 0D 02 BF}. The -fourth byte is @code{0D hexadecimal}, which is @code{1101 binary} ... the 110 is the -last bits of n_fields (@code{110 binary} is 6 which is indeed the number of -fields in the record) and the final 1 bit is 1byte_offs_flag. The -fifth and sixth bytes, which contain @code{02 BF}, constitute the "next" -field. Looking at the original hexadecimal dump, at address -@code{0D42BF} (which is position @code{02BF} within the page), you'll see the beginning bytes of -System Column #1 of the second row. In other words, the "next" field -points to the "Origin" of the following row. -@item -Helpful Notes About NULLs:@* -For the third row, I inserted NULLs in FIELD2 and FIELD3. Therefore in -the Field Start Offsets the top bit is @code{on} for these fields (the -values are @code{94 hexadecimal}, @code{94 hexadecimal}, instead of -@code{14 hexadecimal}, @code{14 hexadecimal}). And the row is -shorter because the NULLs take no space. -@end itemize - -@section Where to Look For More Information - -@strong{References:} @* -The most relevant InnoDB source-code files are rem0rec.c, rem0rec.ic, -and rem0rec.h in the rem ("Record Manager") directory. - -@node InnoDB Page Structure, Files in MySQL Sources, InnoDB Record Structure, Top -@chapter InnoDB Page Structure - -InnoDB stores all records inside a fixed-size unit which is commonly called a -"page" (though InnoDB sometimes calls it a "block" instead). -Currently all pages are the same size, 16KB. -@* - -A page contains records, but it also contains headers and trailers. -I'll start this description with a high-altitude view of a page's parts, -then I'll describe each part of a page. Finally, I'll show an example. This -discussion deals only with the most common format, for the leaf page of a data file. -@* - -@section High-Altitude View - -An InnoDB page has seven parts: -@itemize @bullet -@item -Fil Header -@item -Page Header -@item -Infimum + Supremum Records -@item -User Records -@item -Free Space -@item -Page Directory -@item -Fil Trailer -@end itemize - -As you can see, a page has two header/trailer pairs. The inner pair, "Page Header" and -"Page Directory", are mostly the concern of the \page program group, -while the outer pair, "Fil Header" and "Fil Trailer", are mostly the -concern of the \fil program group. The "Fil" header also goes goes by -the name of "File Page Header". -@* - -Sandwiched between the headers and trailers, are the records and -the free (unused) space. A page always begins with two unchanging -records called the Infimum and the Supremum. Then come the user -records. Between the user records (which grow downwards) and the page -directory (which grows upwards) there is space for new records. -@* - -@subsection Fil Header - -The Fil Header has eight parts, as follows: - -@multitable @columnfractions .10 .30 .35 - -@item @strong{Name} @tab @strong{Size} @tab @strong{Remarks} -@item FIL_PAGE_SPACE -@tab 4 -@tab 4 ID of the space the page is in -@item FIL_PAGE_OFFSET -@tab 4 -@tab ordinal page number from start of space -@item FIL_PAGE_PREV -@tab 4 -@tab offset of previous page in key order -@item FIL_PAGE_NEXT -@tab 4 -@tab offset of next page in key order -@item FIL_PAGE_LSN -@tab 8 -@tab log serial number of page's latest log record -@item FIL_PAGE_TYPE -@tab 2 -@tab current defined types are: FIL_PAGE_INDEX, FIL_PAGE_UNDO_LOG, FIL_PAGE_INODE, FIL_PAGE_IBUF_FREE_LIST -@item FIL_PAGE_FILE_FLUSH_LSN -@tab 8 -@tab "the file has been flushed to disk at least up to this lsn" (log serial number), - valid only on the first page of the file -@item FIL_PAGE_ARCH_LOG_NO -@tab 4 -@tab the latest archived log file number at the time that FIL_PAGE_FILE_FLUSH_LSN was written (in the log) -@end multitable - -@itemize -@item -FIL_PAGE_SPACE is a necessary identifier because different pages might belong to -different (table) spaces within the same file. The word -"space" is generic jargon for either "log" or "tablespace". -@*@* - -@item -FIL_PAGE_PREV and FIL_PAGE_NEXT are the page's "backward" and -"forward" pointers. To show what they're about, I'll draw a two-level -B-tree. -@*@* - -@example - -------- - - root - - -------- - | - ---------------------- - | | - | | - -------- -------- - - leaf - <--> - leaf - - -------- -------- -@end example -@* - -Everyone has seen a B-tree and knows that the entries in the root page -point to the leaf pages. (I indicate those pointers with vertical '|' -bars in the drawing.) But sometimes people miss the detail that leaf -pages can also point to each other (I indicate those pointers with a horizontal -two-way pointer '<-->' in the drawing). This feature allows InnoDB to navigate from -leaf to leaf without having to back up to the root level. This is a -sophistication which you won't find in the classic B-tree, which is -why InnoDB should perhaps be called a B+-tree instead. -@*@* - -@item -The fields FIL_PAGE_FILE_FLUSH_LSN, FIL_PAGE_PREV, and FIL_PAGE_NEXT -all have to do with logs, so I'll refer you to my article "How Logs -Work With MySQL And InnoDB" on devarticles.com. -@*@* - -@item -FIL_PAGE_FILE_FLUSH_LSN and FIL_PAGE_ARCH_LOG_NO are only valid for -the first page of a data file. -@end itemize - -@subsection Page Header - -The Page Header has 14 parts, as follows: -@*@* - -@multitable @columnfractions .10 .20 .30 - -@item @strong{Name} @tab @strong{Size} @tab @strong{Remarks} -@item PAGE_N_DIR_SLOTS -@tab 2 -@tab number of directory slots in the Page Directory part; initial value = 2 -@item PAGE_HEAP_TOP -@tab 2 -@tab record pointer to first record in heap -@item PAGE_N_HEAP -@tab 2 -@tab number of heap records; initial value = 2 -@item PAGE_FREE -@tab 2 -@tab record pointer to first free record -@item PAGE_GARBAGE -@tab 2 -@tab "number of bytes in deleted records" -@item PAGE_LAST_INSERT -@tab 2 -@tab record pointer to the last inserted record -@item PAGE_DIRECTION -@tab 2 -@tab either PAGE_LEFT, PAGE_RIGHT, or PAGE_NO_DIRECTION -@item PAGE_N_DIRECTION -@tab 2 -@tab number of consecutive inserts in the same direction, e.g. "last 5 were all to the left" -@item PAGE_N_RECS -@tab 2 -@tab number of user records -@item PAGE_MAX_TRX_ID -@tab 8 -@tab the highest ID of a transaction which might have changed a record on the page (only set for secondary indexes) -@item PAGE_LEVEL -@tab 2 -@tab level within the index (0 for a leaf page) -@item PAGE_INDEX_ID -@tab 8 -@tab identifier of the index the page belongs to -@item PAGE_BTR_SEG_LEAF -@tab 10 -@tab "file segment header for the leaf pages in a B-tree" (this is irrelevant here) -@item PAGE_BTR_SEG_TOP -@tab 10 -@tab "file segment header for the non-leaf pages in a B-tree" (this is irrelevant here) - -@end multitable -@* - -(Note: I'll clarify what a "heap" is when I discuss the User Records part of the page.) -@*@* - -Some of the Page Header parts require further explanation: -@itemize @bullet -@item -PAGE_FREE: @* -Records which have been freed (due to deletion or migration) are in a -one-way linked list. The PAGE_FREE pointer in the page header points -to the first record in the list. The "next" pointer in the record -header (specifically, in the record's Extra Bytes) points to the next -record in the list. -@item -PAGE_DIRECTION and PAGE_N_DIRECTION: @* -It's useful to know whether inserts are coming in a constantly -ascending sequence. That can affect InnoDB's efficiency. -@item -PAGE_HEAP_TOP and PAGE_FREE and PAGE_LAST_INSERT: @* -Warning: Like all record pointers, these point not to the beginning of the -record but to its Origin (see the earlier discussion of Record -Structure). -@item -PAGE_BTR_SEG_LEAF and PAGE_BTR_SEG_TOP: @* -These variables contain information (space ID, page number, and byte offset) about -index node file segments. InnoDB uses the information for allocating new pages. -There are two different variables because InnoDB allocates separately for leaf -pages and upper-level pages. -@end itemize - -@subsection The Infimum And Supremum Records - -"Infimum" and "supremum" are real English words but they are found -only in arcane mathematical treatises, and in InnoDB comments. To -InnoDB, an infimum is lower than the the lowest possible real value -(negative infinity) and a supremum is greater than the greatest -possible real value (positive infinity). InnoDB sets up an infimum -record and a supremum record automatically at page-create time, and -never deletes them. They make a useful barrier to navigation so that -"get-prev" won't pass the beginning and "get-next" won't pass the end. -Also, the infimum record can be a dummy target for temporary record -locks. -@*@* - -The InnoDB code comments distinguish between "the infimum and supremum -records" and the "user records" (all other kinds). -@*@* - -It's sometimes unclear whether InnoDB considers the infimum and -supremum to be part of the header or not. Their size is fixed and -their position is fixed, so I guess so. - -@subsection User Records - -In the User Records part of a page, you'll find all the records that the user -inserted. -@*@* - -There are two ways to navigate through the user records, depending -whether you want to think of their organization as an unordered or an -ordered list. -@*@* - -An unordered list is often called a "heap". If you make a pile of -stones by saying "whichever one I happen to pick up next will go on -top" -- rather than organizing them according to size and colour -- -then you end up with a heap. Similarly, InnoDB does not want to insert -new rows according to the B-tree's key order (that would involve -expensive shifting of large amounts of data), so it inserts new rows -right after the end of the existing rows (at the -top of the Free Space part) or wherever there's space left by a -deleted row. -@*@* - -But by definition the records of a B-tree must be accessible in order -by key value, so there is a record pointer in each record (the "next" -field in the Extra Bytes) which points to the next record in key -order. In other words, the records are a one-way linked list. So -InnoDB can access rows in key order when searching. - -@subsection Free Space - -I think it's clear what the Free Space part of a page is, from the discussion of -other parts. - -@subsection Page Directory - -The Page Directory part of a page has a variable number of record pointers. -Sometimes the record pointers are called "slots" or "directory slots". -Unlike other DBMSs, InnoDB does not have a slot for every record in -the page. Instead it keeps a sparse directory. In a fullish page, -there will be one slot for every six records. -@*@* - -The slots track the records' logical order (the order by key rather -than the order by placement on the heap). Therefore, if the records -are @code{'A' 'B' 'F' 'D'} the slots will be @code{(pointer to 'A') (pointer to -'B') (pointer to 'D') (pointer to 'F')}. Because the slots are in key -order, and each slot has a fixed size, it's easy to do a binary -search of the records on the page via the slots. -@*@* - -(Since the Page Directory does not have a slot for every record, -binary search can only give a rough position and then InnoDB must -follow the "next" record pointers. InnoDB's "sparse slots" policy also -accounts for the n_owned field in the Extra Bytes part of a record: -n_owned indicates how many more records must be gone through because -they don't have their own slots.) - -@subsection Fil Trailer - -The Fil Trailer has one part, as follows: -@*@* - -@multitable @columnfractions .10 .35 .40 - -@item @strong{Name} @tab @strong{Size} @tab @strong{Remarks} -@item FIL_PAGE_END_LSN -@tab 8 -@tab low 4 bytes = checksum of page, last 4 bytes = same as FIL_PAGE_LSN -@end multitable -@* - -The final part of a page, the fil trailer (or File Page Trailer), -exists because InnoDB's architect worried about integrity. It's -impossible for a page to be only half-written, or corrupted by -crashes, because the log-recovery mechanism restores to a consistent -state. But if something goes really wrong, then it's nice to have a -checksum, and to have a value at the very end of the page which must -be the same as a value at the very beginning of the page. - -@section Example - -For this example, I used Borland's TDUMP again, as I did for the earlier chapter on -Record Format. This is what a page looked like: -@*@* - -@multitable @columnfractions .05 .95 - -@item @strong{Address Values In Hexadecimal} @tab @strong{Values In ASCII} -@item @code{0D4000: 00 00 00 00 00 00 00 35 FF FF FF FF FF FF FF FF} -@tab @code{.......5........} -@item @code{0D4010: 00 00 00 00 00 00 E2 64 45 BF 00 00 00 00 00 00} -@tab @code{.......dE.......} -@item @code{0D4020: 00 00 00 00 00 00 00 05 02 F5 00 12 00 00 00 00} -@tab @code{................} -@item @code{0D4030: 02 E1 00 02 00 0F 00 10 00 00 00 00 00 00 00 00} -@tab @code{................} -@item @code{0D4040: 00 00 00 00 00 00 00 00 00 14 00 00 00 00 00 00} -@tab @code{................} -@item @code{0D4050: 00 02 16 B2 00 00 00 00 00 00 00 02 15 F2 08 01} -@tab @code{................} -@item @code{0D4060: 00 00 03 00 89 69 6E 66 69 6D 75 6D 00 09 05 00} -@tab @code{.....infimum....} -@item @code{0D4070: 08 03 00 00 73 75 70 72 65 6D 75 6D 00 22 1D 18} -@tab @code{....supremum."..} -@item @code{0D4080: 13 0C 06 00 00 10 0D 00 B7 00 00 00 00 04 14 00} -@tab @code{................} -@item @code{0D4090: 00 00 00 09 1D 80 00 00 00 2D 00 84 41 41 41 41} -@tab @code{.........-..AAAA} -@item @code{0D40A0: 41 41 41 41 41 41 41 41 41 41 41 1F 1B 17 13 0C} -@tab @code{AAAAAAAAAAA.....} -@item @code{ ... } -@item @code{ ... } -@item @code{0D7FE0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 74} -@tab @code{...............t} -@item @code{0D7FF0: 02 47 01 AA 01 0A 00 65 3A E0 AA 71 00 00 E2 64} -@tab @code{.G.....e:..q...d} -@end multitable -@*@* - -Let's skip past the first 38 bytes, which are Fil Header. The bytes -of the Page Header start at location @code{0d4026 hexadecimal}: -@*@* - -@multitable @columnfractions .10 .45 .60 - -@item @strong{Location} @tab @strong{Name} @tab @strong{Description} -@item @code{00 05} -@tab PAGE_N_DIR_SLOTS -@tab There are 5 directory slots. -@item @code{02 F5} -@tab PAGE_HEAP_TOP -@tab At location @code{0402F5}, not shown, is the beginning of free space. -Maybe a better name would have been PAGE_HEAP_END -@item @code{00 12} -@tab PAGE_N_HEAP -@tab There are 18 (hexadecimal 12) records in the page. -@item @code{00 00} -@tab PAGE_FREE -@tab There are zero free (deleted) records. -@item @code{00 00} -@tab PAGE_GARBAGE -@tab There are zero bytes in deleted records. -@item @code{02 E1} -@tab PAGE_LAST_INSERT -@tab The last record was inserted at location @code{02E1}, not shown, within the page. -@item @code{00 02} -@tab PAGE_DIRECTION -@tab A glance at page0page.h will tell you that 2 is the #defined value for PAGE_RIGHT. -@item @code{00 0F} -@tab PAGE_N_DIRECTION -@tab The last 15 (hexadecimal 0F) inserts were all done "to the right" -because I was inserting in ascending order. -@item @code{00 10} -@tab PAGE_N_RECS -@tab There are 16 (hexadecimal 10) user records. Notice that PAGE_N_RECS is -smaller than the earlier field, PAGE_N_HEAP. -@item @code{00 00 00 00 00 00 00} -@tab PAGE_MAX_TRX_ID -@item @code{00 00} -@tab PAGE_LEVEL -@tab Zero because this is a leaf page. -@item @code{00 00 00 00 00 00 00 14} -@tab PAGE_INDEX_ID -@tab This is index number 20. -@item @code{00 00 00 00 00 00 00 02 16 B2} -@tab PAGE_BTR_SEG_LEAF -@item @code{00 00 00 00 00 00 00 02 15 F2} -@tab PAGE_BTR_SEG_TOP -@end multitable -@* - -Immediately after the page header are the infimum and supremum -records. Looking at the "Values In ASCII" column in the hexadecimal -dump, you will see that the contents are in fact the words "infimum" -and "supremum" respectively. -@*@* - -Skipping past the User Records and the Free Space, many bytes later, -is the end of the 16KB page. The values shown there are the two trailers. -@itemize @bullet -@item -The first trailer (@code{00 74, 02 47, 01 AA, 01 0A, 00 65}) is the page -directory. It has 5 entries, because the header field PAGE_N_DIR_SLOTS -says there are 5. -@item -The next trailer (@code{3A E0 AA 71, 00 00 E2 64}) is the fil trailer. Notice -that the last four bytes, @code{00 00 E2 64}, appeared before in the fil -header. -@end itemize - -@section Where to Look For More Information - -@strong{References:} @* -The most relevant InnoDB source-code files are page0page.c, -page0page.ic, and page0page.h in \page directory. - -@node Files in MySQL Sources, Files in InnoDB Sources, InnoDB Page Structure, Top -@chapter Annotated List Of Files in the MySQL Source Code Distribution - -This is a description of the files that you get when you download the -source code of MySQL. This description begins with a list -of the main directories and a short comment about each one. Then, for -each directory, in alphabetical order, a longer description is -supplied. When a directory contains significant program files, a list of each C -program is given along with an explanation of its intended function. - -@section Directory Listing - -@strong{Directory -- Short Comment} -@itemize @bullet -@item -bdb -- The Berkeley Database table handler -@item -BitKeeper -- BitKeeper administration (not part of the source distribution) -@item -BUILD -- Frequently used build scripts -@item -Build-tools -- Build tools (not part of the source distribution) -@item -client -- Client library -@item -cmd-line-utils -- Command-line utilities (libedit and readline) -@item -dbug -- Fred Fish's dbug library -@item -Docs -- Preliminary documents about internals and new modules; will eventually be moved to the mysqldoc repository -@item -extra -- Some minor standalone utility programs -@item -heap -- The HEAP table handler -@item -include -- Header (*.h) files for most libraries; includes all header files distributed with the MySQL binary distribution -@item -innobase -- The Innobase (InnoDB) table handler -@item -libmysql -- For producing MySQL as a library (e.g. a Windows .DLL) -@item -libmysql_r -- For building a thread-safe libmysql library -@item -libmysqld -- The MySQL Server as an embeddable library -@item -man -- Some user-contributed manual pages -@item -myisam -- The MyISAM table handler -@item -myisammrg -- The MyISAM Merge table handler -@item -mysql-test -- A test suite for mysqld -@item -mysys -- MySQL system library (Low level routines for file access etc.) -@item -netware -- Files related to the Novell NetWare version of MySQL -@item -NEW-RPMS -- Directory to place RPMs while making a distribution -@item -os2 -- Routines for working with the OS/2 operating system -@item -pstack -- Process stack display (not currently used) -@item -regex -- Henry Spencer's Regular Expression library for support of REGEXP function -@item -SCCS -- Source Code Control System (not part of source distribution) -@item -scripts -- SQL batches, e.g. mysqlbug and mysql_install_db -@item -sql -- Programs for handling SQL commands; the "core" of MySQL -@item -sql-bench -- The MySQL benchmarks -@item -SSL -- Secure Sockets Layer; includes an example certification one can use to test an SSL (secure) database connection -@item -strings -- Library for C string routines, e.g. atof, strchr -@item -support-files -- Files used to build MySQL on different systems -@item -tests -- Tests in Perl and in C -@item -tools -- mysqlmanager.c (tool under development, not yet useful) -@item -VC++Files -- Includes this entire directory, repeated for VC++ (Windows) use -@item -vio -- Virtual I/O Library -@item -zlib -- Data compression library, used on Windows -@end itemize - -@subsection bdb - -The Berkeley Database table handler. -@*@* - -The Berkeley Database (BDB) is maintained by Sleepycat Software. -MySQL AB maintains only a few small patches to make BDB work -better with MySQL. -@*@* - -The documentation for BDB is available at -http://www.sleepycat.com/docs/. Since it's reasonably thorough -documentation, a description of the BDB program files is not included -in this document. -@*@* - -@subsection BitKeeper - -BitKeeper administration. -@*@* - -Bitkeeper administration is not part of the source distribution. This -directory may be present if you downloaded the MySQL source using -BitKeeper rather than via the mysql.com site. The files in the -BitKeeper directory are for maintenance purposes only -- they are not -part of the MySQL package. -@*@* - -The MySQL Reference Manual explains how to use Bitkeeper to get the -MySQL source. Please see @url{http://www.mysql.com/doc/en/Installing_source_tree.html} -for more information. -@*@* - -@subsection BUILD - -Frequently used build scripts. -@*@* - -This directory contains the build switches for compilation on various -platforms. There is a subdirectory for each set of options. The main -ones are: -@itemize @bullet -@item -alpha -@item -ia64 -@item -pentium (with and without debug or bdb, etc.) -@item -solaris -@end itemize -@*@* - -@subsection Build-tools - -Build tools. -@*@* - -Build-tools is not part of the source distribution. This directory -contains batch files for extracting, making directories, and making -programs from source files. There are several subdirectories with -different scripts -- for building Linux executables, for compiling, -for performing all build steps, and so on. -@*@* - -@subsection client - -Client library. -@*@* - -The client library includes mysql.cc (the source of the 'mysql' -executable) and other utilities. Most of the utilities are mentioned -in the MySQL Reference Manual. Generally these are standalone C -programs which one runs in "client mode", that is, they call the -server. -@*@* - -The C program files in the directory are: -@itemize @bullet -@item -get_password.c -- ask for a password from the console -@item -mysql.cc -- "The MySQL command tool" -@item -mysqladmin.c -- maintenance of MySQL databases -@item -mysqlcheck.c -- check all databases, check connect, etc. -@item -mysqldump.c -- dump table's contents as SQL statements, suitable to backup a MySQL database -@item -mysqlimport.c -- import text files in different formats into tables -@item -mysqlmanager-pwgen.c -- pwgen stands for "password generation" (not currently maintained) -@item -mysqlmanagerc.c -- entry point for mysql manager (not currently maintained) -@item -mysqlshow.c -- show databases, tables or columns -@item -mysqltest.c -- test program used by the mysql-test suite, mysql-test-run -@item -password.c -- password checking routines (version 4.1 and up) -@end itemize -@*@* - -@subsection cmd-line-utils - -Command-line utilities (libedit and readline). -@*@* - -There are two subdirectories: \readline and \libedit. All the files -here are "non-MySQL" files, in the sense that MySQL AB didn't produce -them, it just uses them. It should be unnecessary to study the -programs in these files unless you are writing or debugging a tty-like -client for MySQL, such as mysql.exe. -@*@* - -The \readline subdirectory contains the files of the GNU Readline -Library, "a library for reading lines of text with interactive input -and history editing". The programs are copyrighted by the Free -Software Foundation. -@*@* - -The \libedit (library of edit functions) subdirectory has files -written by Christos Zoulas. They are distributed and modifed under -the BSD License. These files are for editing the line contents. -@*@* - -These are the program files in the \libedit subdirectory: -@itemize @bullet -@item -chared.c -- character editor -@item -common.c -- common editor functions -@item -el.c -- editline interface functions -@item -emacs.c -- emacs functions -@item -fgetln.c -- get line -@item -hist.c -- history access functions -@item -history.c -- more history access functions -@item -key.c -- procedures for maintaining the extended-key map -@item -map.c -- editor function definitions -@item -parse.c -- parse an editline extended command -@item -prompt.c -- prompt printing functions -@item -read.c -- terminal read functions -@item -readline.c -- read line -@item -refresh.c -- "lower level screen refreshing functions" -@item -search.c -- "history and character search functions" -@item -sig.c -- for signal handling -@item -strlcpy.c -- string copy -@item -term.c -- "editor/termcap-curses interface" -@item -tokenizer.c -- Bourne shell line tokenizer -@item -tty.c -- for a tty interface -@item -vi.c -- commands used when in the vi (editor) mode -@end itemize -@*@* - -@subsection dbug - -Fred Fish's dbug library. -@*@* - -This is not really part of the MySQL package. Rather, it's a set of -public-domain routines which are useful for debugging MySQL programs. -The MySQL Server and all .c and .cc programs support the use of this -package. -@*@* - -How it works: One inserts a function call that begins with DBUG_* in -one of the regular MYSQL programs. For example, in get_password.c, you -will find this line: @* -DBUG_ENTER("get_tty_password"); @* -at the start of a routine, and this line: @* -DBUG_RETURN(my_strdup(to,MYF(MY_FAE))); @* -at the end of the routine. These lines don't affect production code. -Features of the dbug library include extensive reporting and profiling -(the latter has not been used by the MySQL team). -@*@* - -The C programs in this directory are: -@itemize @bullet -@item -dbug.c -- The main module -@item -dbug_analyze.c -- Reads a file produced by trace functions -@item -example1.c -- A tiny example -@item -example2.c -- A tiny example -@item -example3.c -- A tiny example -@item -factorial.c -- A tiny example -@item -main.c -- A tiny example -@item -sanity.c -- Declaration of a variable -@end itemize -@*@* - -@subsection Docs - -Preliminary documents about internals and new modules, which will eventually -be moved to the mysqldoc repository. -@*@* - -This directory doesn't have much at present that's very useful to the -student, but the plan is that some documentation related to the source -files and the internal workings of MySQL, including perhaps some -documentation from developers themselves, will be placed here. Files in -this directory will eventually be moved to the MySQL documentation repository. -@*@* - -These sub-directories are part of this directory: -@itemize @bullet -@item -books -- .gif images and empty .txt files; no real information -@item -flags -- images of flags of countries -@item -images -- flag backgrounds and the MySQL dolphin logo -@item -mysql-logos -- more MySQL-related logos, some of them moving -@item -raw-flags -- more country flags, all .gif files -@item -support -- various files for generating texinfo/docbook documentation -@item -to-be-included... -- contains a MySQL-for-dummies file -@item -translations -- some Portuguese myodbc documentation -@end itemize -@*@* - -In the main directory, you'll find some .txt files related to the -methods that MySQL uses to produce its printed and html documents, odd -bits in various languages, and the single file in the directory which -has any importance -- internals.texi -- The "MySQL Internals" -document. -@*@* - -Despite the name, internals.texi is not yet much of a description of MySQL -internals although work is in progress to make it so. However, there is -some useful description of the functions in the mysys directory (see below), -and of the structure of client/server messages (doubtless very useful for -eople who want to make their own JDBC drivers, or just sniff). -@*@* - -@subsection extra - -Some minor standalone utility programs. -@*@* - -These programs are all standalone utilities, that is, they have -a main() function and their main role is to show information that the -MySQL server needs or produces. Most are unimportant. They are as -follows: -@itemize @bullet -@item -my_print_defaults.c -- print parameters from my.ini files. Can also be used in scripts to enable processing of my.ini files. -@item -mysql_waitpid.c -- wait for a program to terminate. Useful for shell scripts when one needs to wait until a process terminates. -@item -perror.c -- "print error" -- given error number, display message -@item -replace.c -- replace strings in text files or pipe -@item -resolve_stack_dump.c -- show symbolic information from a MySQL stack dump, normally found in the mysql.err file -@item -resolveip.c -- convert an IP address to a hostname, or vice versa -@end itemize -@*@* - -@subsection heap - -The HEAP table handler. -@*@* - -All the MySQL table handlers (i.e. the handlers that MySQL itself -produces) have files with similar names and functions. Thus, this -(heap) directory contains a lot of duplication of the myisam directory -(for the MyISAM table handler). Such duplicates have been marked with -an "*" in the following list. For example, you will find that -\heap\hp_extra.c has a close equivalent in the myisam directory -(\myisam\mi_extra.c) with the same descriptive comment. (Some of the -differences arise because HEAP has different structures. HEAP does not -need to use the sort of B-tree indexing that ISAM and MyISAM use; instead -there is a hash index. Most importantly, HEAP is entirely in memory. -File-I/O routines lose some of their vitality in such a context.) -@*@* - -@itemize -@item -hp_block.c -- Read/write a block (i.e. a page) -@item -hp_clear.c -- Remove all records in the table -@item -hp_close.c -- * close database -@item -hp_create.c -- * create a table -@item -hp_delete.c -- * delete a row -@item -hp_extra.c -- * for setting options and buffer sizes when optimizing -@item -hp_hash.c -- Hash functions used for saving keys -@item -hp_info.c -- * Information about database status -@item -hp_open.c -- * open database -@item -hp_panic.c -- * the hp_panic routine, for shutdowns and flushes -@item -hp_rename.c -- * rename a table -@item -hp_rfirst.c -- * read first row through a specific key (very short) -@item -hp_rkey.c -- * read record using a key -@item -hp_rlast.c -- * read last row with same key as previously-read row -@item -hp_rnext.c -- * read next row with same key as previously-read row -@item -hp_rprev.c -- * read previous row with same key as previously-read row -@item -hp_rrnd.c -- * read a row based on position -@item -hp_rsame.c -- * find current row using positional read or key-based -read -@item -hp_scan.c -- * read all rows sequentially -@item -hp_static.c -- * static variables (very short) -@item -hp_test1.c -- * testing basic functions -@item -hp_test2.c -- * testing database and storing results -@item -hp_update.c -- * update an existing row -@item -hp_write.c -- * insert a new row -@end itemize -@*@* - -There are fewer files in the heap directory than in the myisam -directory, because fewer are necessary. For example, there is no need -for a \myisam\mi_cache.c equivalent (to cache reads) or a -\myisam\log.c equivalent (to log statements). -@*@* - -@subsection include - -Header (*.h) files for most libraries; includes all header files distributed -with the MySQL binary distribution. -@*@* - -These files may be included in C program files. Note that each -individual directory will also have its own *.h files, for including -in its own *.c programs. The *.h files in the include directory are -ones that might be included from more than one place. -@*@* - -For example, the mysys directory contains a C file named rijndael.c, -but does not include rijndael.h. The include directory contains -rijndael.h. Looking further, you'll find that rijndael.h is also -included in other places: by my_aes.c and my_aes.h. -@*@* - -The include directory contains 51 *.h (header) files. -@*@* - -@subsection innobase - -The Innobase (InnoDB) table handler. -@*@* - -A full description of these files can be found elsewhere in this -document. -@*@* - -@subsection libmysql - -The MySQL Library, Part 1. -@*@* - -The files here are for producing MySQL as a library (e.g. a Windows -DLL). The idea is that, instead of producing separate mysql (client) -and mysqld (server) programs, one produces a library. Instead of -sending messages, the client part merely calls the server part. -@*@* - -The libmysql files are split into three directories: libmysql (this -one), libmysql_r (the next one), and libmysqld (the next one after -that). -@*@* - -The "library of mysql" has some client-connection -modules. For example, as described in an earlier -section of this manual, there is a discussion of -libmysql/libmysql.c which sends packets from the -client to the server. Many of the entries in the -libmysql directory (and in the following libmysqld -directory) are 'symlinks' on Linux, that is, they -are in fact pointers to files in other directories. -@*@* - -The program files on this directory are: -@itemize @bullet -@item -conf_to_src.c -- has to do with charsets -@item -dll.c -- initialization of the dll library -@item -errmsg.c -- English error messages, compare \mysys\errors.c -@item -get_password.c -- get password -@item -libmysql.c -- the code that implements the MySQL API, i.e. the functions a client that wants to connect to MySQL will call -@item -manager.c -- initialize/connect/fetch with MySQL manager -@end itemize -@*@* - -@subsection libmysql_r - -The MySQL Library, Part 2. -@*@* - -There is only one file here, used to build a thread-safe libmysql library: -@itemize @bullet -@item -makefile.am -@end itemize -@*@* - -@subsection libmysqld - -The MySQL library, Part 3. -@*@* - -The Embedded MySQL Server Library. The product of libmysqld -is not a client/server affair, but a library. There is a wrapper -to emulate the client calls. The program files on this directory -are: -@itemize @bullet -@item -libmysqld.c -- The called side, compare the mysqld.exe source -@item -lib_vio.c -- Emulate the vio directory's communication buffer -@end itemize -@*@* - -@subsection man - -Some user-contributed manual pages -@*@* - -These are user-contributed "man" (manual) pages in a special markup -format. The format is described in a document with a heading like -"man page for man" or "macros to format man pages" which you can find -in a Linux directory or on the Internet. -@*@* - -@subsection myisam - -The MyISAM table handler. -@*@* - -The C files in this subdirectory come in six main groups: -@itemize @bullet -@item -ft*.c files -- ft stands for "Full Text", code contributed by Sergei Golubchik -@item -mi*.c files -- mi stands for "My Isam", these are the main programs for Myisam -@item -myisam*.c files -- for example, "myisamchk" utility routine functions source -@item -rt*.c files -- rt stands for "rtree", some code was written by Alexander Barkov -@item -sp*.c files -- sp stands for "spatial", some code was written by Ramil Kalimullin -@item -sort.c -- this is a single file that sorts keys for index-create purposes -@end itemize -@*@* - -The "full text" and "rtree" and "spatial" program sets are for special -purposes, so this document focuses only on the mi*.c "myisam" C -programs. They are: -@itemize @bullet -@item -mi_cache.c -- for reading records from a cache -@item -mi_changed.c -- a single routine for setting a "changed" flag (very short) -@item -mi_check.c -- for checking and repairing tables. Used by the myisamchk program and by the MySQL server. -@item -mi_checksum.c -- calculates a checksum for a row -@item -mi_close.c -- close database -@item -mi_create.c -- create a table -@item -mi_dbug.c -- support routines for use with "dbug" (see \dbug description) -@item -mi_delete.c -- delete a row -@item -mi_delete_all.c -- delete all rows -@item -mi_delete_table.c -- delete a table (very short) -@item -mi_dynrec.c -- functions to handle space-packed records and blobs -@item -mi_extra.c -- setting options and buffer sizes when optimizing -@item -mi_info.c -- return useful base information for an open table -@item -mi_key.c -- for handling keys -@item -mi_locking.c -- lock database -@item -mi_log.c -- save commands in a log file which myisamlog program can read. Can be used to exactly replay a set of changes to a table. -@item -mi_open.c -- open database -@item -mi_packrec.c -- read from a data file compresed with myisampack -@item -mi_page.c -- read and write pages containing keys -@item -mi_panic.c -- the mi_panic routine, probably for sudden shutdowns -@item -mi_range.c -- approximate count of how many records lie between two keys -@item -mi_rename.c -- rename a table -@item -mi_rfirst.c -- read first row through a specific key (very short) -@item -mi_rkey.c -- read a record using a key -@item -mi_rlast.c -- read last row with same key as previously-read row -@item -mi_rnext.c -- read next row with same key as previously-read row -@item -mi_rnext_same.c -- same as mi_rnext.c, but abort if the key changes -@item -mi_rprev.c -- read previous row with same key as previously-read row -@item -mi_rrnd.c -- read a row based on position -@item -mi_rsame.c -- find current row using positional read or key-based read -@item -mi_rsamepos.c -- positional read -@item -mi_scan.c -- read all rows sequentially -@item -mi_search.c -- key-handling functions -@item -mi_static.c -- static variables (very short) -@item -mi_statrec.c -- functions to handle fixed-length records -@item -mi_test1.c -- testing basic functions -@item -mi_test2.c -- testing database and storing results -@item -mi_test3.c -- testing locking -@item -mi_unique.c -- functions to check if a row is unique -@item -mi_update.c -- update an existing row -@item -mi_write.c -- insert a new row -@end itemize -@*@* - -@subsection myisammrg - -MyISAM Merge table handler. -@*@* - -As with other table handlers, you'll find that the *.c files in the -myissammrg directory have counterparts in the myisam directory. In -fact, this general description of a myisammrg program is almost always -true: The myisammrg -function checks an argument, the myisammrg function formulates an -expression for passing to a myisam function, the myisammrg calls a -myisam function, the myisammrg function returns. -@*@* - -These are the 21 files in the myisammrg directory, with notes about -the myisam functions or programs they're connected with: -@itemize @bullet -@item -myrg_close.c -- mi_close.c -@item -myrg_create.c -- mi_create.c -@item -myrg_delete.c -- mi_delete.c / delete last-read record -@item -myrg_extra.c -- mi_extra.c / "extra functions we want to do ..." -@item -myrg_info.c -- mi_info.c / display information about a mymerge file -@item -myrg_locking.c -- mi_locking.c / lock databases -@item -myrg_open.c -- mi_open.c / open a MyISAM MERGE table -@item -myrg_panic.c -- mi_panic.c / close in a hurry -@item -myrg_queue.c -- read record based on a key -@item -myrg_range.c -- mi_range.c / find records in a range -@item -myrg_rfirst.c -- mi_rfirst.c / read first record according to -specific key -@item -myrg_rkey.c -- mi_rkey.c / read record based on a key -@item -myrg_rlast.c -- mi_rlast.c / read last row with same key as previous -read -@item -myrg_rnext.c -- mi_rnext.c / read next row with same key as previous -read -@item -myrg_rnext_same.c -- mi_rnext_same.c / read next row with same key -@item -myrg_rprev.c -- mi_rprev.c / read previous row with same key -@item -myrg_rrnd.c -- mi_rrnd.c / read record with random access -@item -myrg_rsame.c -- mi_rsame.c / call mi_rsame function, see -\myisam\mi_rsame.c -@item -myrg_static.c -- mi_static.c / static variable declaration -@item -myrg_update.c -- mi_update.c / call mi_update function, see -\myisam\mi_update.c -@item -myrg_write.c -- mi_write.c / call mi_write function, see -\myisam\mi_write.c -@end itemize -@*@* - -@subsection mysql-test - -A test suite for mysqld. -@*@* - -The directory has a README file which explains how to run the tests, -how to make new tests (in files with the filename extension "*.test"), -and how to report errors. -@*@* - -There are four subdirectories: -@itemize @bullet -@item -\misc -- contains one minor Perl program -@item -\r -- contains *.result, i.e. "what happened" files and -*.required, i.e. "what should happen" file -@item -\std_data -- contains standard data for input to tests -@item -\t -- contains tests -@end itemize -@*@* - -There are 186 *.test files in the \t subdirectory. Primarily these are -SQL scripts which try out a feature, output a result, and compare the -result with what's required. Some samples of what the test files check -are: latin1_de comparisons, date additions, the HAVING clause, outer -joins, openSSL, load data, logging, truncate, and UNION. -@*@* - -There are other tests in these directories: -@itemize @bullet -@item -sql-bench -@item -tests -@end itemize - -@subsection mysys - -MySQL system library. Low level routines for file access and so on. -@*@* - -There are 115 *.c programs in this directory: -@itemize @bullet -@item -array.c -- Dynamic array handling -@item -charset.c -- Using dynamic character sets, set default character set, ... -@item -charset2html.c -- Check what character set a browser is using -@item -checksum.c -- Calculate checksum for a memory block, used for pack_isam -@item -default.c -- Find defaults from *.cnf or *.ini files -@item -errors.c -- English text of global errors -@item -hash.c -- Hash search/compare/free functions "for saving keys" -@item -list.c -- Double-linked lists -@item -make-conf.c -- "Make a charset .conf file out of a ctype-charset.c file" -@item -md5.c -- MD5 ("Message Digest 5") algorithm from RSA Data Security -@item -mf_brkhant.c -- Prevent user from doing a Break during critical execution (not used in MySQL; can be used by standalone MyISAM applications) -@item -mf_cache.c -- "Open a temporary file and cache it with io_cache" -@item -mf_dirname.c -- Parse/convert directory names -@item -mf_fn_ext.c -- Get filename extension -@item -mf_format.c -- Format a filename -@item -mf_getdate.c -- Get date, return in yyyy-mm-dd hh:mm:ss format -@item -mf_iocache.c -- Cached read/write of files in fixed-size units -@item -mf_iocache2.c -- Continuation of mf_iocache.c -@item -mf_keycache.c -- Key block caching for certain file types -@item -mf_loadpath.c -- Return full path name (no ..\ stuff) -@item -mf_pack.c -- Packing/unpacking directory names for create purposes -@item -mf_path.c -- Determine where a program can find its files -@item -mf_qsort.c -- Quicksort -@item -mf_qsort2.c -- Quicksort, part 2 (allows the passing of an extra argument to the sort-compare routine) -@item -mf_radix.c -- Radix sort -@item -mf_same.c -- Determine whether filenames are the same -@item -mf_sort.c -- Sort with choice of Quicksort or Radix sort -@item -mf_soundex.c -- Soundex algorithm derived from EDN Nov. 14, 1985 (pg. 36) -@item -mf_strip.c -- Strip trail spaces from a string -@item -mf_tempdir.c -- Initialize/find/free temporary directory -@item -mf_tempfile.c -- Create a temporary file -@item -mf_unixpath.c -- Convert filename to UNIX-style filename -@item -mf_util.c -- Routines, #ifdef'd, which may be missing on some -machines -@item -mf_wcomp.c -- Comparisons with wildcards -@item -mf_wfile.c -- Finding files with wildcards -@item -mulalloc.c -- Malloc many pointers at the same time -@item -my_aes.c -- AES encryption -@item -my_alarm.c -- Set a variable value when an alarm is received -@item -my_alloc.c -- malloc of results which will be freed simultaneously -@item -my_append.c -- one file to another -@item -my_bit.c -- smallest X where 2^X >= value, maybe useful for -divisions -@item -my_bitmap.c -- Handle uchar arrays as large bitmaps -@item -my_chsize.c -- Truncate file if shorter, else fill with a filler -character -@item -my_clock.c -- Time-of-day ("clock()") function, with OS-dependent -#ifdef's -@item -my_compress.c -- Compress packet (see also description of \zlib -directory) -@item -my_copy.c -- Copy files -@item -my_create.c -- Create file -@item -my_delete.c -- Delete file -@item -my_div.c -- Get file's name -@item -my_dup.c -- Open a duplicated file -@item -my_error.c -- Return formatted error to user -@item -my_fopen.c -- File open -@item -my_fstream.c -- Streaming file read/write -@item -my_getwd.c -- Get working directory -@item -my_gethostbyname.c -- Thread-safe version of standard net -gethostbyname() func -@item -my_getopt.c -- Find out what options are in effect -@item -my_handler.c -- Compare two keys in various possible formats -@item -my_init.c -- Initialize variables and functions in the mysys library -@item -my_lib.c -- Compare/convert directory names and file names -@item -my_lock.c -- Lock part of a file -@item -my_lockmem.c -- "Allocate a block of locked memory" -@item -my_lread.c -- Read a specified number of bytes from a file into -memory -@item -my_lwrite.c -- Write a specified number of bytes from memory into a -file -@item -my_malloc.c -- Malloc (memory allocate) and dup functions -@item -my_messnc.c -- Put out a message on stderr with "no curses" -@item -my_mkdir.c -- Make directory -@item -my_net.c -- Thread-safe version of net inet_ntoa function -@item -my_netware.c -- Functions used only with the Novell Netware version -of MySQL -@item -my_once.c -- Allocation / duplication for "things we don't need to -free" -@item -my_open.c -- Open a file -@item -my_os2cond.c -- OS2-specific: "A simple implementation of posix conditions" -@item -my_os2dirsrch.c -- OS2-specific: Emulate a Win32 directory search -@item -my_os2dlfcn.c -- OS2-specific: Emulate UNIX dynamic loading -@item -my_os2file64.c -- OS2-specific: For File64bit setting -@item -my_os2mutex.c -- OS2-specific: For mutex handling -@item -my_os2thread.c -- OS2-specific: For thread handling -@item -my_os2tls.c -- OS2-specific: For thread-local storage -@item -my_port.c -- OS/machine-dependent porting functions, e.g. AIX-specific my_ulonglong2double() -@item -my_pread.c -- Read a specified number of bytes from a file -@item -my_pthread.c -- A wrapper for thread-handling functions in different OSs -@item -my_quick.c -- Read/write (labelled a "quicker" interface, perhaps -obsolete) -@item -my_read.c -- Read a specified number of bytes from a file, possibly -retry -@item -my_realloc.c -- Reallocate memory allocated with my_alloc.c -(probably) -@item -my_redel.c -- Rename and delete file -@item -my_rename.c -- Rename without delete -@item -my_seek.c -- Seek, i.e. point to a spot within a file -@item -my_semaphore.c -- Semaphore routines, for use on OS that doesn't support them -@item -my_sleep.c -- Wait n microseconds -@item -my_static.c -- Static variables used by the mysys library -@item -my_symlink.c -- Read a symbolic link (symlinks are a UNIX thing, I guess) -@item -my_symlink2.c -- Part 2 of my_symlink.c -@item -my_tempnam.c -- Obsolete temporary-filename routine used by ISAM table handler -@item -my_thr_init.c -- initialize/allocate "all mysys & debug thread variables" -@item -my_wincond.c -- Windows-specific: emulate Posix conditions -@item -my_winsem.c -- Windows-specific: emulate Posix threads -@item -my_winthread.c -- Windows-specific: emulate Posix threads -@item -my_write.c -- Write a specified number of bytes to a file -@item -ptr_cmp.c -- Point to an optimal byte-comparison function -@item -queues.c -- Handle priority queues as in Robert Sedgewick's book -@item -raid2.c -- RAID support (the true implementation is in raid.cc) -@item -rijndael.c -- "Optimised ANSI C code for the Rijndael cipher (now AES") -@item -safemalloc.c -- A version of the standard malloc() with safety checking -@item -sha1.c -- Implementation of Secure Hashing Algorithm 1 -@item -string.c -- Initialize/append/free dynamically-sized strings; see also sql_string.cc in the /sql directory -@item -testhash.c -- Standalone program: test the hash library routines -@item -test_charset.c -- Standalone program: display character set information -@item -test_dir.c -- Standalone program: placeholder for "test all functions" idea -@item -test_fn.c -- Standalone program: apparently tests a function -@item -test_xml.c -- Standalone program: test XML routines -@item -thr_alarm.c -- Thread alarms and signal handling -@item -thr_lock.c -- "Read and write locks for Posix threads" -@item -thr_mutex.c -- A wrapper for mutex functions -@item -thr_rwlock.c -- Synchronizes the readers' thread locks with the writer's lock -@item -tree.c -- Initialize/search/free binary trees -@item -typelib.c -- Find a string in a set of strings; returns the offset to the string found -@end itemize -@*@* - -You can find documentation for the main functions in these files -elsewhere in this document. For example, the main functions in my_getwd.c -are described thus: -@*@* - -@example -"int my_getwd _A((string buf, uint size, myf MyFlags)); @* - int my_setwd _A((const char *dir, myf MyFlags)); @* - Get and set working directory." @* -@end example - -@subsection netware - -Files related to the Novell NetWare version of MySQL. -@*@* - -There are 39 files on this directory. Most have filename extensions of -*.def, *.sql, or *.c. -@*@* - -The twenty-five *.def files are all from Novell Inc. They contain import or -export symbols. (".def" is a common filename extension for -"definition".) -@*@* - -The two *.sql files are short scripts of SQL statements used in -testing. -@*@* - -These are the five *.c files, all from Novell Inc.: -@itemize @bullet -@item -libmysqlmain.c -- Only one function: init_available_charsets() -@item -my_manage.c -- Standalone management utility -@item -mysql_install_db.c -- Compare \scripts\mysql_install_db.sh -@item -mysql_test_run.c -- Short test program -@item -mysqld_safe.c -- Compare \scripts\mysqld_safe.sh -@end itemize - -Perhaps the most important file is: -@itemize @bullet -@item -netware.patch -- NetWare-specific build instructions and switches -(compare \mysql-4.1\ltmain.sh) -@end itemize -@*@* - -For instructions about basic installation, see "Deployment Guide For -NetWare AMP" at: -@url{http://developer.novell.com/ndk/whitepapers/namp.htm} -@* - -@subsection NEW-RPMS - -Directory to place RPMs while making a distribution. -@*@* - -This directory is not part of the Windows distribution. It is -a temporary directory used during RPM builds with Linux distributions. -@*@* - -@subsection os2 - -Routines for working with the OS2 operating system. -@*@* - -The files in this directory are the product of the efforts of three -people from outside MySQL: Yuri Dario, Timo Maier, and John M -Alfredsson. There are no .C program files in this directory. -@*@* - -The contents of \os2 are: -@itemize @bullet -@item -A Readme.Txt file -@item -An \include subdirectory containing .h files which are for OS/2 only -@item -Files used in the build process (configuration, switches, and one -.obj) -@end itemize -@*@* - -The README file refers to MySQL version 3.23, which suggests that -there have been no updates for MySQL 4.0 for this section. -@*@* - -@subsection pstack - -Process stack display (not currently used). -@*@* - -This is a set of publicly-available debugging aids which all do pretty -well the same thing: display the contents of the stack, along with -symbolic information, for a running process. There are versions for -various object file formats (such as ELF and IEEE-695). Most of the -programs are copyrighted by the Free Software Foundation and are -marked as "part of GNU Binutils". -@*@* - -In other words, the pstack files are not really part of the MySQL -library. They are merely useful when you re-program some MYSQL code -and it crashes. -@*@* - -@subsection regex - -Henry Spencer's Regular Expression library for support of REGEXP function. -@*@* - -This is the copyrighted product of Henry Spencer from the University -of Toronto. It's a fairly-well-known implementation of the -requirements of POSIX 1003.2 Section 2.8. The library is bundled with -Apache and is the default implementation for regular-expression -handling in BSD Unix. MySQL's Monty Widenius has made minor changes in -three programs (debug.c, engine.c, regexec.c) but this is not a MySQL -package. MySQL calls it only in order to support two MySQL functions: -REGEXP and RLIKE. -@*@* - -Some of Mr Spencer's documentation for the regex library can be found -in the README and WHATSNEW files. -@*@* - -One MySQL program which uses regex is \cmd-line-utils\libedit\search.c -@*@* - -This program calls the 'regcomp' function, which is the entry point in -\regex\regexp.c. -@*@* - -@subsection SCCS - -Source Code Control System (not part of source distribution). -@*@* - -You will see this directory if and only if you used BitKeeper for -downloading the source. The files here are for BitKeeper -administration and are not of interest to application programmers. -@*@* - -@subsection scripts - -SQL batches, e.g. mysqlbug and mysql_install_db. -@*@* - -The *.sh filename extension stands for "shell script". Linux -programmers use it where Windows programmers would use a *.bat -(batch filename extension). -@*@* - -The *.sh files on this directory are: -@itemize @bullet -@item -fill_help_tables.sh -- Create help-information tables and insert -@item -make_binary_distribution.sh -- Get configure information, make, produce tar -@item -msql2mysql.sh -- Convert (partly) mSQL programs and scripts to MySQL -@item -mysqlbug.sh -- Create a bug report and mail it -@item -mysqld_multi.sh -- Start/stop any number of mysqld instances -@item -mysqld_safe-watch.sh -- Start/restart in safe mode -@item -mysqld_safe.sh -- Start/restart in safe mode -@item -mysqldumpslow.sh -- Parse and summarize the slow query log -@item -mysqlhotcopy.sh -- Hot backup -@item -mysql_config.sh -- Get configuration information that might be needed to compile a client -@item -mysql_convert_table_format.sh -- Conversion, e.g. from ISAM to MyISAM -@item -mysql_explain_log.sh -- Put a log (made with --log) into a MySQL table -@item -mysql_find_rows.sh -- Search for queries containing -@item -mysql_fix_extensions.sh -- Renames some file extensions, not recommended -@item -mysql_fix_privilege_tables.sh -- Fix mysql.user etc. when upgrading. Can be safely run during any upgrade to get the newest -MySQL privilege tables -@item -mysql_install_db.sh -- Create privilege tables and func table -@item -mysql_secure_installation.sh -- Disallow remote root login, eliminate test, etc. -@item -mysql_setpermission.sh -- Aid to add users or databases, sets privileges -@item -mysql_tableinfo.sh -- Puts info re MySQL tables into a MySQL table -@item -mysql_zap.sh -- Kill processes which match pattern -@end itemize -@*@* - -@subsection sql - -Programs for handling SQL commands. The "core" of MySQL. -@*@* - -These are the .c and .cc files in the sql directory: -@itemize @bullet -@item -convert.cc -- convert tables between different character sets -@item -derror.cc -- read language-dependent message file -@item -des_key_file.cc -- load DES keys from plaintext file -@item -field.cc -- "implement classes defined in field.h" (long); defines all storage methods MySQL uses to store field information -into records that are then passed to handlers -@item -field_conv.cc -- functions to copy data between fields -@item -filesort.cc -- sort a result set, using memory or temporary files -@item -frm_crypt.cc -- contains only one short function: get_crypt_for_frm -@item -gen_lex_hash.cc -- Knuth's algorithm from Vol 3 Sorting and Searching, Chapter 6.3; used to search for SQL keywords in a query -@item -gstream.cc -- GTextReadStream, used to read GIS objects -@item -handler.cc -- handler-calling functions -@item -hash_filo.cc -- static-sized hash tables, used to store info like hostname -> ip tables in a FIFO manner -@item -ha_berkeley.cc -- Handler: BDB -@item -ha_heap.cc -- Handler: Heap -@item -ha_innodb.cc -- Handler: InnoDB -@item -ha_isam.cc -- Handler: ISAM -@item -ha_isammrg.cc -- Handler: (ISAM MERGE) -@item -ha_myisam.cc -- Handler: MyISAM -@item -ha_myisammrg.cc -- Handler: (MyISAM MERGE) -@item -hostname.cc -- Given IP, return hostname -@item -init.cc -- Init and dummy functions for interface with unireg -@item -item.cc -- Item functions -@item -item_buff.cc -- Buffers to save and compare item values -@item -item_cmpfunc.cc -- Definition of all compare functions -@item -item_create.cc -- Create an item. Used by lex.h. -@item -item_func.cc -- Numerical functions -@item -item_row.cc -- Row items for comparing rows and for IN on rows -@item -item_sum.cc -- Set functions (SUM, AVG, etc.) -@item -item_strfunc.cc -- String functions -@item -item_subselect.cc -- Item subselect -@item -item_timefunc.cc -- Date/time functions, e.g. week of year -@item -item_uniq.cc -- Empty file, here for compatibility reasons -@item -key.cc -- Functions to create keys from records and compare a key to a key in a record -@item -lock.cc -- Locks -@item -log.cc -- Logs -@item -log_event.cc -- Log event (a binary log consists of a stream of log events) -@item -matherr.c -- Handling overflow, underflow, etc. -@item -mf_iocache.cc -- Caching of (sequential) reads and writes -@item -mini_client.cc -- Client included in server for server-server messaging; used by the replication code -@item -mysqld.cc -- Source of mysqld.exe; includes the main() program that starts mysqld, handling of signals and connections -@item -my_lock.c -- Lock part of a file (like /mysys/my_lock.c, but with timeout handling for threads) -@item -net_serv.cc -- Read/write of packets on a network socket -@item -nt_servc.cc -- Initialize/register/remove an NT service -@item -opt_ft.cc -- Create a FT or QUICK RANGE based on a key (very short) -@item -opt_range.cc -- Range of keys -@item -opt_sum.cc -- Optimize functions in presence of (implied) GROUP BY -@item -password.c -- Password checking -@item -procedure.cc -- Procedure interface, as used in SELECT * FROM Table_name PROCEDURE ANALYSE -@item -protocol.cc -- Low level functions for PACKING data that is sent to client; actual sending done with net_serv.cc -@item -records.cc -- Functions for easy reading of records, possible through a cache -@item -repl_failsafe.cc -- Replication fail-save (not yet implemented) -@item -set_var.cc -- Set and retrieve MySQL user variables -@item -slave.cc -- Procedures for a slave in a master/slave (replication) relation -@item -spatial.cc -- Geometry stuff (lines, points, etc.) -@item -sql_acl.cc -- Functions related to ACL security; checks, stores, retrieves, and deletes MySQL user level privileges -@item -sql_analyse.cc -- Implements the PROCEDURE analyse, which analyses a query result and returns the 'optimal' data type for each result column -@item -sql_base.cc -- Basic functions needed by many modules, like opening and closing tables with table cache management -@item -sql_cache.cc -- SQL query cache, with long comments about how caching works -@item -sql_class.cc -- SQL class; implements the SQL base classes, of which THD (THREAD object) is the most important -@item -sql_crypt.cc -- Encode / decode, very short -@item -sql_db.cc -- Create / drop database -@item -sql_delete.cc -- The DELETE statement -@item -sql_derived.cc -- Derived tables, with long comments -@item -sql_do.cc -- The DO statement -@item -sql_error.cc -- Errors and warnings -@item -sql_handler.cc -- Implements the HANDLER interface, which gives direct access to rows in MyISAM and InnoDB -@item -sql_help.cc -- The HELP statement -@item -sql_insert.cc -- The INSERT statement -@item -sql_lex.cc -- Does lexical analysis of a query; i.e. breaks a query string into pieces and determines the basic type (number, -string, keyword, etc.) of each piece -@item -sql_list.cc -- Only list_node_end_of_list, short (the rest of the list class is implemented in sql_list.h) -@item -sql_load.cc -- The LOAD DATA statement -@item -sql_map.cc -- Memory-mapped files (not yet in use) -@item -sql_manager.cc -- Maintenance tasks, e.g. flushing the buffers periodically; used with BDB table logs -@item -sql_olap.cc -- ROLLUP -@item -sql_parse.cc -- Parse an SQL statement; do initial checks and then jump to the function that should execute the statement -@item -sql_prepare.cc -- Prepare an SQL statement, or use a prepared statement -@item -sql_repl.cc -- Replication -@item -sql_rename.cc -- Rename table -@item -sql_select.cc -- Select and join optimisation -@item -sql_show.cc -- The SHOW statement -@item -sql_string.cc -- String functions: alloc, realloc, copy, convert, etc. -@item -sql_table.cc -- The DROP TABLE and ALTER TABLE statements -@item -sql_test.cc -- Some debugging information -@item -sql_udf.cc -- User-defined functions -@item -sql_union.cc -- The UNION operator -@item -sql_update.cc -- The UPDATE statement -@item -stacktrace.c -- Display stack trace (Linux/Intel only) -@item -table.cc -- Table metadata retrieval; read the table definition from a .frm file and store it in a TABLE object -@item -thr_malloc.cc -- Thread-safe interface to /mysys/my_alloc.c -@item -time.cc -- Date and time functions -@item -udf_example.cc -- Example file of user-defined functions -@item -uniques.cc -- Function to handle quick removal of duplicates -@item -unireg.cc -- Create a unireg form file (.frm) from a FIELD and field-info struct -@end itemize -@*@* - -@subsection sql-bench - -The MySQL Benchmarks. -@*@* - -This directory has the programs and input files which MySQL uses for -its comparisons of MySQL, PostgreSQL, mSQL, Solid, etc. Since MySQL -publishes the comparative results, it's only right that it should make -available all the material necessary to reproduce all the tests. -@*@* - -There are five subdirectories and sub-subdirectories: -@itemize @bullet -@item -\Comments -- Comments about results from tests of Access, Adabas, etc. -@item -\Data\ATIS -- .txt files containing input data for the "ATIS" tests -@item -\Data\Wisconsin -- .txt files containing input data for the "Wisconsin" tests -@item -\Results -- old test results -@item -\Results-win32 -- old test results from Windows 32-bit tests -@end itemize -@*@* - -There are twenty-four *.sh (shell script) files, which involve Perl -programs. -@*@* - -There are three *.bat (batch) files. -@*@* - -There is one README file and one TODO file. -@*@* - -@subsection SSL - -Secure Sockets Layer; includes an example certification one can use -test an SSL (secure) database connection. -@*@* - -This isn't a code directory. It contains a short note from Tonu Samuel -(the NOTES file) and seven *.pem files. PEM stands for "Privacy -Enhanced Mail" and is an Internet standard for adding security to -electronic mail. Finally, there are two short scripts for running -clients and servers over SSL connections. -@*@* - -@subsection strings - -The string library. -@*@* - -Many of the files in this subdirectory are equivalent to well-known -functions that appear in most C string libraries. For those, there is -documentation available in most compiler handbooks. -@*@* - -On the other hand, some of the files are MySQL additions or -improvements. Often the MySQL changes are attempts to optimize the -standard libraries. It doesn't seem that anyone tried to optimize for -recent Pentium class processors, though. -@*@* - -The .C files are: -@itemize @bullet -@item -atof.c -- ascii-to-float, MySQL version -@item -bchange.c -- short replacement routine written by Monty Widenius in -1987 -@item -bcmp.c -- binary compare, rarely used -@item -bcopy-duff.c -- block copy: attempt to copy memory blocks faster -than cmemcpy -@item -bfill.c -- byte fill, to fill a buffer with (length) copies of a -byte -@item -bmove.c -- block move -@item -bmove512.c -- "should be the fastest way to move a multiple of 512 -bytes" -@item -bmove_upp.c -- bmove.c variant, starting with last byte -@item -bzero.c -- something like bfill with an argument of 0 -@item -conf_to_src.c -- reading a configuration file -@item -ctype*.c -- string handling programs for each char type MySQL -handles -@item -do_ctype.c -- display case-conversion and sort-conversion tables -@item -int2str.c -- integer-to-string -@item -is_prefix.c -- checks whether string1 starts with string2 -@item -llstr.c -- convert long long to temporary-buffer string, return -pointer -@item -longlong2str.c -- ditto, but to argument-buffer -@item -memcmp.c -- memory compare -@item -memset.c -- memory set -@item -my_vsnprintf.c -- variant of printf -@item -r_strinstr.c -- see if one string is within another -@item -str2int.c -- convert string to integer -@item -strappend.c -- fill up a string to n characters -@item -strcat.c -- concatenate strings -@item -strcend.c -- point to where a character C occurs within str, or NULL -@item -strchr.c -- point to first place in string where character occurs -@item -strcmp.c -- compare two strings -@item -strcont.c -- point to where any one of a set of characters appears -@item -strend.c -- point to the '\0' byte which terminates str -@item -strfill.c -- fill a string with n copies of a byte -@item -strinstr.c -- find string within string -@item -strlen.c -- return length of string in bytes -@item -strmake.c -- create new string from old string with fixed length, append end \0 if needed -@item -strmov.c -- move source to dest and return pointer to end -@item -strnlen.c -- return min(length of string, n) -@item -strnmov.c -- move source to dest for source size, or for n bytes -@item -strrchr.c -- find a character within string, searching from end -@item -strstr.c -- find an instance of pattern within source -@item -strto.c -- string to long, to long long, to unsigned long, etc. -@item -strtol.c -- string to long -@item -strtoll.c -- string to long long -@item -strtoul.c -- string to unsigned long -@item -strtoull.c -- string to unsigned long long -@item -strxmov.c -- move a series of concatenated source strings to dest -@item -strxnmov.c -- like strxmov.c but with a maximum length n -@item -str_test.c -- test of all the string functions encoded in assembler -@item -udiv.c -- unsigned long divide, for operating systems that don't support these -@item -xml.c -- read and parse XML strings; used to read character definition information stored in /sql/share/charsets -@end itemize -@*@* - -There are also four .ASM files -- macros.asm, ptr_cmp.asm, -strings.asm, and strxmov.asm -- which can replace some of the -C-program functions. But again, they look like optimizations for old -members of the Intel processor family. -@*@* - -@subsection support-files - -Files used to build MySQL on different systems. -@*@* - -The files here are for building ("making") MySQL given a package -manager, compiler, linker, and other build tools. The support files -provide instructions and switches for the build processes. They -include example my.cnf files one can use as a default setup for -MySQL. -@*@* - -@subsection tests - -Tests in Perl and in C. -@*@* - -The files in this directory are test programs that can be used -as a base to write a program to simulate problems in MySQL in various -scenarios: forks, locks, big records, exporting, truncating, and so on. -Some examples are: -@itemize @bullet -@item -connect_test.c -- test that a connect is possible -@item -insert_test.c -- test that an insert is possible -@item -list_test.c -- test that a select is possible -@item -select_test.c -- test that a select is possible -@item -showdb_test.c -- test that a show-databases is possible -@item -ssl_test.c -- test that SSL is possible -@item -thread_test.c -- test that threading is possible -@end itemize -@*@* - -@subsection tools - -Tools -- well, actually, one tool. -@*@* - -The only file is: -@itemize @bullet -@item -mysqlmanager.c -- A "server management daemon" by Sasha Pachev. This -is a tool under development and is not yet useful. Related to fail-safe -replication. -@end itemize -@*@* - -@subsection VC++Files - -Visual C++ Files. -@*@* - -Includes this entire directory, repeated for VC++ (Windows) use. -@*@* - -VC++Files includes a complete environment to compile MySQL with the VC++ -compiler. To use it, just copy the files on this directory; the make_win_src_distribution.sh -script uses these files to create a Windows source installation. -@*@* - -This directory has subdirectories which are copies of the main directories. -For example, there is a subdirectory \VC++Files\heap, which has the Microsoft -developer studio project file to compile \heap with VC++. So for a description -of the files in \VC++Files\heap, see the description of the files in \heap. The -same applies for almost all of VC++Files's subdirectories (bdb, client, -isam, libmysql, etc.). The difference is that the \VC++Files variants -are specifically for compilation with Microsoft Visual C++ in 32-bit -Windows environments. -@*@* - -In addition to the "subdirectories which are duplicates of -directories", VC++Files contains these subdirectories, which are not -duplicates: -@itemize @bullet -@item -comp_err -- (nearly empty) -@item -contrib -- (nearly empty) -@item -InstallShield -- script files -@item -isamchk -- (nearly empty) -@item -libmysqltest -- one small non-MySQL test program: mytest.c -@item -myisamchk -- (nearly empty) -@item -myisamlog -- (nearly empty) -@item -myisammrg -- (nearly empty) -@item -mysqlbinlog -- (nearly empty) -@item -mysqlmanager -- MFC foundation class files created by AppWizard -@item -mysqlserver -- (nearly empty) -@item -mysqlshutdown -- one short program, mysqlshutdown.c -@item -mysqlwatch.c -- Windows service initialization and monitoring -@item -my_print_defaults -- (nearly empty) -@item -pack_isam -- (nearly empty) -@item -perror -- (nearly empty) -@item -prepare -- (nearly empty) -@item -replace -- (nearly empty) -@item -SCCS -- source code control system -@item -test1 -- tests connecting via X threads -@item -thr_insert_test -- (nearly empty) -@item -thr_test -- one short program used to test for memory-allocation bug -@item -winmysqladmin -- the winmysqladmin.exe source -@end itemize -@*@* - -The "nearly empty" subdirectories noted above (e.g. comp_err and isamchk) -are needed because VC++ requires one directory per project (i.e. executable). -We are trying to keep to the MySQL standard source layout and compile only -to different directories. -@*@* - -@subsection vio - -Virtual I/O Library. -@*@* - -The VIO routines are wrappers for the various network I/O calls that -happen with different protocols. The idea is that in the main modules -one won't have to write separate bits of code for each protocol. Thus -vio's purpose is somewhat like the purpose of Microsoft's winsock -library. -@*@* - -The underlying protocols at this moment are: TCP/IP, Named Pipes (for -WindowsNT), Shared Memory, and Secure Sockets (SSL). -@*@* - -The C programs are: -@itemize @bullet -@item -test-ssl.c -- Short standalone test program: SSL -@item -test-sslclient.c -- Short standalone test program: clients -@item -test-sslserver.c -- Short standalone test program: server -@item -vio.c -- Declarations + open/close functions -@item -viosocket.c -- Send/retrieve functions -@item -viossl.c -- SSL variations for the above -@item -viosslfactories.c -- Certification / Verification -@item -viotest.cc -- Short standalone test program: general -@item -viotest-ssl.c -- Short standalone test program: SSL -@item -viotest-sslconnect.cc -- Short standalone test program: SSL connect -@end itemize -@*@* - -The older functions -- raw_net_read, raw_net_write -- are now -obsolete. -@*@* - -@subsection zlib - -Data compression library, used on Windows. -@*@* - -zlib is a data compression library used to support the compressed -protocol and the COMPRESS/UNCOMPRESS functions under Windows. -On Unix, MySQL uses the system libgz.a library for this purpose. -@*@* - -Zlib -- which presumably stands for "Zip Library" -- is not a MySQL -package. It was produced by the GNU Zip (gzip.org) people. Zlib is a -variation of the famous "Lempel-Ziv" method, which is also used by -"Zip". The method for reducing the size of any arbitrary string of -bytes is as follows: -@itemize @bullet -@item -Find a substring which occurs twice in the string. -@item -Replace the second occurrence of the substring with (a) a pointer to -the first occurrence, plus (b) an indication of the length of the -first occurrence. -@end itemize - -There is a full description of the library's functions in the gzip -manual at: @* -@url{http://www.gzip.org/zlib/manual.html} @* -There is therefore no need to list the modules in this document. -@*@* - -The MySQL program \mysys\my_compress.c uses zlib for packet compression. -The client sends messages to the server which are compressed by zlib. -See also: \sql\net_serv.cc. - -@node Files in InnoDB Sources, , Files in MySQL Sources, Top -@chapter Annotated List Of Files in the InnoDB Source Code Distribution - -ERRATUM BY HEIKKI TUURI (START) -@*@* - -Errata about InnoDB row locks:@*@* - -@example - #define LOCK_S 4 /* shared */ - #define LOCK_X 5 /* exclusive */ -... -@strong{/* Waiting lock flag */} - #define LOCK_WAIT 256 -/* this wait bit should be so high that it can be ORed to the lock -mode and type; when this bit is set, it means that the lock has not -yet been granted, it is just waiting for its turn in the wait queue */ -... -@strong{/* Precise modes */} - #define LOCK_ORDINARY 0 -/* this flag denotes an ordinary next-key lock in contrast to LOCK_GAP -or LOCK_REC_NOT_GAP */ - #define LOCK_GAP 512 -/* this gap bit should be so high that it can be ORed to the other -flags; when this bit is set, it means that the lock holds only on the -gap before the record; for instance, an x-lock on the gap does not -give permission to modify the record on which the bit is set; locks of -this type are created when records are removed from the index chain of -records */ - #define LOCK_REC_NOT_GAP 1024 -/* this bit means that the lock is only on the index record and does -NOT block inserts to the gap before the index record; this is used in -the case when we retrieve a record with a unique key, and is also used -in locking plain SELECTs (not part of UPDATE or DELETE) when the user -has set the READ COMMITTED isolation level */ - #define LOCK_INSERT_INTENTION 2048 -/* this bit is set when we place a waiting gap type record lock -request in order to let an insert of an index record to wait until -there are no conflicting locks by other transactions on the gap; note -that this flag remains set when the waiting lock is granted, or if the -lock is inherited to a neighboring record */ -@end example -@* - -ERRATUM BY HEIKKI TUURI (END) -@*@* - -The InnoDB source files are the best place to look for information -about internals of the file structure that MySQLites can optionally -use for transaction support. But when you first look at all the -subdirectories and file names you'll wonder: Where Do I Start? It can -be daunting. -@*@* - -Well, I've been through that phase, so I'll pass on what I had to -learn on the first day that I looked at InnoDB source files. I am very -sure that this will help you grasp, in overview, the organization of -InnoDB modules. I'm also going to add comments about what is going on --- which you should mistrust! These comments are reasonable working -hypotheses; nevertheless, they have not been subjected to expert peer -review. -@*@* - -Here's how I'm going to organize the discussion. I'll take each of the -32 InnoDB subdirectories that come with the MySQL 4.0 source code in -\mysql\innobase (on my Windows directory). The format of each section -will be like this every time: -@*@* - -@strong{\subdirectory-name (LONGER EXPLANATORY NAME)}@* -@multitable @columnfractions .10 .20 .40 .50 -@item @strong{File Name} @tab @strong{What Name Stands For} @tab @strong{Size} @tab @strong{Comment Inside File} -@item file-name -@tab my-own-guess -@tab in-bytes -@tab from-the-file-itself -@end multitable -...@* -My-Comments@* -@* - -For example: @* -@example -" -@strong{\ha (HASHING)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - ha0ha.c Hashing/Hashing 7,452 Hash table with external chains - - Comments about hashing will be here. -" -@end example -@* - -The "Comment Inside File" column is a direct copy from the first /* -comment */ line inside the file. All other comments are mine. After -I've discussed each directory, I'll finish with some notes about -naming conventions and a short list of URLs that you can use for -further reference. -@*@* - -Now let's begin. -@*@* - -@example - -@strong{\ha (HASHING)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - ha0ha.c Hashing / Hashing 7,452 Hash table with external chains - -I'll hold my comments until the next section, \hash (HASHING). - -@strong{\hash (HASHING)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - hash0hash.c Hashing / Hashing 3,257 Simple hash table utility - -The two C programs in the \ha and \hashing directories -- ha0ha.c and -hash0hash.c -- both refer to a "hash table" but hash0hash.c is -specialized, it is mostly about accessing points in the table under -mutex control. - -When a "database" is so small that InnoDB can load it all into memory -at once, it's more efficient to access it via a hash table. After all, -no disk i/o can be saved by using an index lookup, if there's no disk. - -@strong{\os (OPERATING SYSTEM)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - os0shm.c OS / Shared Memory 3,150 To shared memory primitives - os0file.c OS / File 64,412 To i/o primitives - os0thread.c OS / Thread 6,827 To thread control primitives - os0proc.c OS / Process 3,700 To process control primitives - os0sync.c OS / Synchronization 10,208 To synchronization primitives - -This is a group of utilities that other modules may call whenever they -want to use an operating-system resource. For example, in os0file.c -there is a public InnoDB function named os_file_create_simple(), which -simply calls the Windows-API function CreateFile. Naturally the -contents of this group are somewhat different for other operating systems. - -The "Shared Memory" functions in os0shm.c are only called from the -communications program com0shm.c (see \com COMMUNICATIONS). The i/o -and thread-control primitives are called extensively. The word -"synchronization" in this context refers to the mutex-create and -mutex-wait functionality. - -@strong{\ut (UTILITIES)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - ut0ut.c Utilities / Utilities 7,041 Various utilities - ut0byte.c Utilities / Debug 1,856 Byte utilities - ut0rnd.c Utilities / Random 1,475 Random numbers and hashing - ut0mem.c Utilities / Memory 5,530 Memory primitives - ut0dbg.c Utilities / Debug 642 Debug utilities - -The two functions in ut0byte.c are just for lower/upper case -conversion and comparison. The single function in ut0rnd.c is for -finding a prime slightly greater than the given argument, which is -useful for hash functions, but unrelated to randomness. The functions -in ut0mem.c are wrappers for "malloc" and "free" calls -- for the -real "memory" module see section \mem (MEMORY). Finally, the -functions in ut0ut.c are a miscellany that didn't fit better elsewhere: -get_high_bytes, clock, time, difftime, get_year_month_day, and "sprintf" -for various diagnostic purposes. - -In short: the \ut group is trivial. - -@strong{\buf (BUFFERING)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - buf0buf.c Buffering / Buffering 53,246 The database buffer buf_pool - buf0flu.c Buffering / Flush 23,711 ... flush algorithm - buf0lru.c / least-recently-used 20,245 ... replacement algorithm - buf0rea.c Buffering / read 17,399 ... read - -There is a separate file group (\mem MEMORY) which handles memory -requests in general.A "buffer" usually has a more specific -definition, as a memory area which contains copies of pages that -ordinarily are in the main data file. The "buffer pool" is the set -of all buffers (there are lots of them because InnoDB doesn't -depend on the OS's caching to make things faster). - -The pool size is fixed (at the time of this writing) but the rest of -the buffering architecture is sophisticated, involving a host of -control structures. In general: when InnoDB needs to access a new page -it looks first in the buffer pool; InnoDB reads from disk to a new -buffer when the page isn't there; InnoDB chucks old buffers (basing -its decision on a conventional Least-Recently-Used algorithm) when it -has to make space for a new buffer. - -There are routines for checking a page's validity, and for read-ahead. -An example of "read-ahead" use: if a sequential scan is going on, then -a DBMS can read more than one page at a time, which is efficient -because reading 32,768 bytes (two pages) takes less than twice as long -as reading 16,384 bytes (one page). - -@strong{\btr (B-TREE)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - btr0btr.c B-tree / B-tree 74,255 B-tree - btr0cur.c B-tree / Cursor 94,950 index tree cursor - btr0sea.c B-tree / Search 36,580 index tree adaptive search - btr0pcur.c B-tree / persistent cursor 14,548 index tree persistent cursor - -If you total up the sizes of the C files, you'll see that \btr is the -second-largest file group in InnoDB. This is understandable because -maintaining a B-tree is a relatively complex task. Luckily, there has -been a lot of work done to describe efficient management of B-tree and -B+-tree structures, much of it open-source or public-domain, since -their original invention over thirty years ago. - -InnoDB likes to put everything in B-trees. This is what I'd call a -"distinguishing characteristic" because in all the major DBMSs (like -IBM DB2, Microsoft SQL Server, and Oracle), the main or default or -classic structure is the heap-and-index. In InnoDB the main structure -is just the index. To put it another way: InnoDB keeps the rows in the -leaf node of the index, rather than in a separate file. Compare -Oracle's Index Organized Tables, and Microsoft SQL Server's Clustered -Indexes. - -This, by the way, has some consequences. For example, you may as well -have a primary key since otherwise InnoDB will make one anyway. And -that primary key should be the shortest of the candidate keys, since -InnoDB -will use it as a pointer if there are secondary indexes. - -Most importantly, it means that rows have no fixed address. Therefore -the routines for managing file pages should be good. We'll see about -that when we look at the \row (ROW) program group later. - -@strong{\com (COMMUNCATION)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - com0com.c Communication 6,913 Communication primitives - com0shm.c Communication / 24,633 ... through shared memory - Shared Memory - -The communication primitives in com0com.c are said to be modelled -after the ones in Microsoft's winsock library (the Windows Sockets -interface). The communication primitives in com0shm.c are at a -slightly lower level, and are called from the routines in com0com.c. - -I was interested in seeing how InnoDB would handle inter-process -communication, since there are many options -- named pipes, TCP/IP, -Windows messaging, and Shared Memory being the main ones that come to -mind. It appears that InnoDB prefers Shared Memory. The main idea is: -there is an area of memory which two different processes (or threads, -of course) can both access. To communicate, a thread gets an -appropriate mutex, puts in a request, and waits for a response. Thread -interaction is also a subject for the os0thread.c program in another -program group, \os (OPERATING SYSTEM). - -@strong{\dyn (DYNAMICALLY ALLOCATED ARRAY)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - dyn0dyn.c Dynamic / Dynamic 994 dynamically allocated array - -There is a single function in the dyn0dyn.c program, for adding a -block to the dynamically allocated array. InnoDB might use the array -for managing concurrency between threads. - -At the moment, the \dyn program group is trivial. - -@strong{\fil (FILE)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - fil0fil.c File / File 39,725 The low-level file system - -The reads and writes to the database files happen here, in -co-ordination with the low-level file i/o routines (see os0file.h in -the \os program group). - -Briefly: a table's contents are in pages, which are in files, which -are in tablespaces. Files do not grow; instead one can add new files -to the tablespace. As we saw earlier (discussing the \btr program group) -the pages are nodes of B-trees. Since that's the case, new additions can -happen at various places in the logical file structure, not -necessarily at the end. Reads and writes are asynchronous, and go into -buffers, which are set up by routines in the \buf program group. - -@strong{\fsp (FILE SPACE)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - fsp0fsp.c File Space Management 100,271 File space management - -I would have thought that the \fil (FILE) and \fsp (FILE SPACE) -MANAGEMENT programs would fit together in the same program group; -however, I guess the InnoDB folk are splitters rather than lumpers. - -It's in fsp0fsp.c that one finds some of the descriptions and comments -of extents, segments, and headers. For example, the "descriptor bitmap -of the pages in the extent" is in here, and you can find as well how -the free-page list is maintained, what's in the bitmaps, and what -various header fields' contents are. - -@strong{\fut (FILE UTILITY)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - fut0fut.c File Utility / Utility 293 File-based utilities - fut0lst.c File Utility / List 14,129 File-based list utilities - -Mainly these small programs affect only file-based lists, so maybe -saying "File Utility" is too generic. The real work with data files -goes on in the \fsp program group. - -@strong{\log (LOGGING)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - log0log.c Logging / Logging 77,834 Database log - log0recv.c Logging / Recovery 80,701 Recovery - -I've already written about the \log program group, so here's a link to -my previous article: "How Logs work with MySQL and InnoDB": -@url{http://www.devarticles.com/art/1/181/2} - -@strong{\mem (MEMORY)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - mem0mem.c Memory / Memory 9,971 The memory management - mem0dbg.c Memory / Debug 21,297 ... the debug code - mem0pool.c Memory / Pool 16,293 ... the lowest level - -There is a long comment at the start of the mem0pool.c program, which -explains what the memory-consumers are, and how InnoDB tries to -satisfy them. The main thing to know is that there are really three -pools: the buffer pool (see the \buf program group), the log pool (see the \log -program group), and the common pool, which is where everything that's -not in the buffer or log pools goes (for example the parsed SQL -statements and the data dictionary cache). - -@strong{\mtr (MINI-TRANSACTION)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - mtr0mtr.c Mini-transaction / 12,433 Mini-transaction buffer - mtr0log.c Mini-transaction / Log 8,180 ... log routines - -The mini-transaction routines are called from most of the other -program groups. I'd describe this as a low-level utility set. - -@strong{\que (QUERY GRAPH)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - que0que.c Query Graph / Query 35,964 Query graph - -The program que0que.c ostensibly is about the execution of stored -procedures which contain commit/rollback statements. I took it that -this has little importance for the average MySQL user. - -@strong{\rem (RECORD MANAGER)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - rem0rec.c Record Manager 14,961 Record Manager - rem0cmp.c Record Manager / 25,263 Comparison services for records - Comparison - -There's an extensive comment near the start of rem0rec.c title -"Physical Record" and it's recommended reading. At some point you'll -ask what are all those bits that surround the data in the rows on a page, -and this is where you'll find the answer. - -@strong{\row (ROW)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - row0row.c Row / Row 16,764 General row routines - row0uins.c Row / Undo Insert 7,199 Fresh insert undo - row0umod.c Row / Undo Modify 17,147 Undo modify of a row - row0undo.c Row / Undo 10,254 Row undo - row0vers.c Row / Version 12,288 Row versions - row0mysql.c Row / MySQL 63,556 Interface [to MySQL] - row0ins.c Row / Insert 42,829 Insert into a table - row0sel.c Row / Select 85,923 Select - row0upd.c Row / Update 44,456 Update of a row - row0purge.c Row / Purge 14,961 Purge obsolete records - -Rows can be selected, inserted, updated/deleted, or purged (a -maintenance activity). These actions have ancillary actions, for -example after insert there can be an index-update test, but it seems -to me that sometimes the ancillary action has no MySQL equivalent (yet) -and so is inoperative. - -Speaking of MySQL, notice that one of the larger programs in the \row -program group is the "interface between Innobase row operations and -MySQL" (row0mysql.c) -- information interchange happens at this level -because rows in InnoDB and in MySQL are analogous, something which -can't be said for pages and other levels. - -@strong{\srv (Server)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - srv0srv.c Server / Server 79,058 Server main program - srv0que.c Server / Query 2,361 Server query execution - srv0start.c Server / Start 34,586 Starts the server - -This is where the server reads the initial configuration files, splits -up the threads, and gets going. There is a long comment deep in the -program (you might miss it at first glance) titled "IMPLEMENTATION OF -THE SERVER MAIN PROGRAM" in which you'll find explanations about -thread priority, and about what the responsibiities are for various -thread types. - -InnoDB has many threads, for example "user threads" (which wait for -client requests and reply to them), "parallel communication threads" -(which take part of a user thread's job if a query process can be -split), "utility threads" (background priority), and a "master thread" -(high priority, usually asleep). - -@strong{\thr (Thread Local Storage)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - thr0loc.c Thread / Local 5,261 The thread local storage - -InnoDB doesn't use the Windows-API thread-local-storage functions, -perhaps because they're not portable enough. - -@strong{\trx (Transaction)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - trx0trx.c Transaction / 37,447 The transaction - trx0purge.c Transaction / Purge 26,782 ... Purge old versions - trx0rec.c Transaction / Record 36,525 ... Undo log record - trx0sys.c Transaction / System 20,671 ... System - trx0rseg.c / Rollback segment 6,214 ... Rollback segment - trx0undo.c Transaction / Undo 46,595 ... Undo log - -InnoDB's transaction management is supposedly "in the style of Oracle" -and that's close to true but can mislead you. -@itemize -@item -First: InnoDB uses rollback segments like Oracle8i does -- but -Oracle9i uses a different name -@item -Second: InnoDB uses multi-versioning like Oracle does -- but I see -nothing that looks like an Oracle ITL being stored in the InnoDB data -pages. -@item -Third: InnoDB and Oracle both have short (back-to-statement-start) -versioning for the READ COMMITTED isolation level and long -(back-to-transaction-start) versioning for higher levels -- but InnoDB -and Oracle have different "default" isolation levels. -@item -Finally: InnoDB's documentation says it has to lock "the gaps before -index keys" to prevent phantoms -- but any Oracle user will tell you that -phantoms are impossible anyway at the SERIALIZABLE isolation level, so -key-locks are unnecessary. -@end itemize - -The main idea, though, is that InnoDB has multi-versioning. So does -Oracle. This is very different from the way that DB2 and SQL Server do -things. - -@strong{\usr (USER)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - usr0sess.c User / Session 27,415 Sessions - -One user can have multiple sessions (the session being all the things -that happen betweeen a connect and disconnect). This is where InnoDB -tracks session IDs, and server/client messaging. It's another of those -items which is usually MySQL's job, though. - -@strong{\data (DATA)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - data0data.c Data / Data 26,002 SQL data field and tuple - data0type.c Data / Type 2,122 Data types - -This is a collection of minor utility routines affecting rows. - -@strong{\dict (DICTIONARY)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - dict0dict.c Dictionary / Dictionary 84,667 Data dictionary system - dict0boot.c Dictionary / boot 12,134 ... creation and booting - dict0load.c Dictionary / load 26,546 ... load to memory cache - dict0mem.c Dictionary / memory 8,221 ... memory object creation - -The data dictionary (known in some circles as the catalog) has the -metadata information about objects in the database -- column sizes, -table names, and the like. - -@strong{\eval (EVALUATING)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - eval0eval.c Evaluating/Evaluating 15,682 SQL evaluator - eval0proc.c Evaluating/Procedures 5,000 Executes SQL procedures - -The evaluating step is a late part of the process of interpreting an -SQL statement -- parsing has already occurred during \pars (PARSING). - -The ability to execute SQL stored procedures is an InnoDB feature, but -not a MySQL feature, so the eval0proc.c program is unimportant. - -@strong{\ibuf (INSERT BUFFER)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - ibuf0ibuf.c Insert Buffer / 69,884 Insert buffer - -The words "Insert Buffer" mean not "buffer used for INSERT" but -"insertion of a buffer into the buffer pool" (see the \buf BUFFER -program group description). The matter is complex due to possibilities -for deadlocks, a problem to which the comments in the ibuf0ibuf.c -program devote considerable attention. - -@strong{\mach (MACHINE FORMAT)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - mach0data.c Machine/Data 2,319 Utilities for converting - -The mach0data.c program has two small routines for reading compressed -ulints (unsigned long integers). - -@strong{\lock (LOCKING)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - lock0lock.c Lock / Lock 127,646 The transaction lock system - -If you've used DB2 or SQL Server, you might think that locks have their -own in-memory table, that row locks might need occasional escalation to -table locks, and that there are three lock types: Shared, Update, Exclusive. - -All those things are untrue with InnoDB! Locks are kept in the database -pages. A bunch of row locks can't be rolled together into a single table -lock. And most importantly there's only one lock type. I call this type -"Update" because it has the characteristics of DB2 / SQL Server Update -locks, that is, it blocks other updates but doesn't block reads. -Unfortunately, InnoDB comments refer to them as "x-locks" etc. - -To sum it up: if your background is Oracle you won't find too much -surprising, but if your background is DB2 or SQL Server the locking -concepts and terminology will probably confuse you at first. - -You can find an online article about the differences between -Oracle-style and DB2/SQL-Server-style locks at: -@url{http://dbazine.com/gulutzan6.html} - -@strong{\odbc (ODBC)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - odbc0odbc.c ODBC / ODBC 16,865 ODBC client library - -The odbc0odbc.c program has a small selection of old ODBC-API -functions: SQLAllocEnv, SQLAllocConnect, SQLAllocStmt, SQLConnect, -SQLError, SQLPrepare, SQLBindParameter, SQLExecute. - -@strong{\page (PAGE)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - page0page.c Page / Page 44,309 Index page routines - page0cur.c Page / Cursor 30,305 The page cursor - -It's in the page0page.c program that you'll learn as follows: index -pages start with a header, entries in the page are in order, at the -end of the page is a sparse "page directory" (what I would have called -a slot table) which makes binary searches easier. - -Incidentally, the program comments refer to "a page size of 8 kB" -which seems obsolete. In univ.i (a file containing universal -constants) the page size is now #defined as 16KB. - -@strong{\pars (PARSING)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - pars0pars.c Parsing/Parsing 49,947 SQL parser - pars0grm.c Parsing/Grammar 62,685 A Bison parser - pars0opt.c Parsing/Optimizer 30,809 Simple SQL Optimizer - pars0sym.c Parsing/Symbol Table 5,541 SQL parser symbol table - lexyy.c ?/Lexer 59,948 Lexical scanner - -The job is to input a string containing an SQL statement and output an -in-memory parse tree. The EVALUATING (subdirectory \eval) programs -will use the tree. - -As is common practice, the Bison and Flex tools were used -- pars0grm.c -is what the Bison parser produced from an original file named pars0grm.y -(not supplied), and lexyy.c is what Flex produced. - -Since InnoDB is a DBMS by itself, it's natural to find SQL parsing in -it. But in the MySQL/InnoDB combination, MySQL handles most of the -parsing. These files are unimportant. - -@strong{\read (READ)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - read0read.c Read / Read 6,244 Cursor read - -The read0read.c program opens a "read view" of a query result, using -some functions in the \trx program group. - -@strong{\sync (SYNCHRONIZATION)} - File Name What Name Stands For Size Comment Inside File - --------- -------------------- ------ ------------------- - sync0sync.c Synchronization / 35,918 Mutex, the basic sync primitive - sync0arr.c ... / array 26,461 Wait array used in primitives - sync0ipm.c ... / interprocess 4,027 for interprocess sync - sync0rw.c ... / read-write 22,220 read-write lock for thread sync - -A mutex (Mutual Exclusion) is an object which only one thread/process -can hold at a time. Any modern operating system API has some functions -for mutexes; however, as the comments in the sync0sync.c code indicate, it -can be faster to write one's own low-level mechanism. In fact the old -assembly-language XCHG trick is in here -- this is the only program -that contains any assembly code. -@end example -@* -@* - -This is the end of the section-by-section account of InnoDB -subdirectories. -@*@* - -@strong{A Note About File Naming} @*@* - -There appears to be a naming convention. The first letters of the file -name are the same as the subdirectory name, then there is a '0' -separator, then there is an individual name. For the main program in a -subdirectory, the individual name may be a repeat of the subdirectory -name. For example, there is a file named ha0ha.c (the first two -letters ha mean "it's in in subdirectory ..\ha", the next letter 0 -means "0 separator", the next two letters mean "this is the main ha -program"). This naming convention is not strict, though: for example -the file lexyy.c is in the \pars subdirectory. -@*@* - -@strong{A Note About Copyrights} @*@* - -Most of the files begin with a copyright notice or a creation date, -for example "Created 10/25/1995 Heikki Tuuri". I don't know a great -deal about the history of InnoDB, but found it interesting that most -creation dates were between 1994 and 1998. -@*@* - -@strong{References} @*@* - -Ryan Bannon, Alvin Chin, Faryaaz Kassam and Andrew Roszko @* -"InnoDB Concrete Architecture" @* -@url{http://www.swen.uwaterloo.ca/~mrbannon/cs798/assignment_02/innodb.pdf} - -A student paper. It's an interesting attempt to figure out InnoDB's -architecture using tools, but I didn't end up using it for the specific -purposes of this article. -@*@* - -Peter Gulutzan @* -"How Logs Work With MySQL And InnoDB" @* -@url{http://www.devarticles.com/art/1/181/2} -@*@* - -Heikki Tuuri @* -"InnoDB Engine in MySQL-Max-3.23.54 / MySQL-4.0.9: The Up-to-Date -Reference Manual of InnoDB" @* -@url{http://www.innodb.com/ibman.html} - -This is the natural starting point for all InnoDB information. Mr -Tuuri also appears frequently on MySQL forums. -@*@* - -@summarycontents -@contents - -@bye -- cgit v1.2.1 From 9864ac66c69e14441cd9378b0bf6ef8b90d45344 Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Tue, 27 May 2003 23:07:32 +0200 Subject: A trick (a useless update) to force the slave to wait for TWO rotate events before stopping. This is to make the test's result predictable (depending on the machine the results could formerly be slightly different, though everything is sane in the code; it's not a bug). --- mysql-test/r/rpl_log.result | 22 ++++++++++++++-------- mysql-test/t/rpl_log.test | 22 ++++++++++++++++++++++ 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/rpl_log.result b/mysql-test/r/rpl_log.result index 5415a153a98..425c376af1e 100644 --- a/mysql-test/r/rpl_log.result +++ b/mysql-test/r/rpl_log.result @@ -36,6 +36,8 @@ show binlog events from 79 limit 2,1; Log_name Pos Event_type Server_id Orig_log_pos Info master-bin.001 200 Query 1 200 use test; insert into t1 values (NULL) flush logs; +create table t5 (a int); +drop table t5; slave start; flush logs; slave stop; @@ -56,9 +58,11 @@ master-bin.001 1079 Query 1 1079 use test; drop table t1 master-bin.001 1127 Rotate 1 1127 master-bin.002;pos=4 show binlog events in 'master-bin.002'; Log_name Pos Event_type Server_id Orig_log_pos Info -master-bin.002 4 Query 1 4 use test; create table t1 (n int) -master-bin.002 62 Query 1 62 use test; insert into t1 values (1) -master-bin.002 122 Query 1 122 use test; drop table t1 +master-bin.002 4 Query 1 4 use test; create table t5 (a int) +master-bin.002 62 Query 1 62 use test; drop table t5 +master-bin.002 110 Query 1 110 use test; create table t1 (n int) +master-bin.002 168 Query 1 168 use test; insert into t1 values (1) +master-bin.002 228 Query 1 228 use test; drop table t1 show master logs; Log_name master-bin.001 @@ -79,14 +83,16 @@ slave-bin.001 311 Query 1 311 use test; create table t1 (word char(20) not null) slave-bin.001 386 Create_file 1 386 db=test;table=t1;file_id=1;block_len=581 slave-bin.001 1065 Exec_load 1 1056 ;file_id=1 slave-bin.001 1088 Query 1 1079 use test; drop table t1 -slave-bin.001 1136 Rotate 2 1136 slave-bin.002;pos=4 +slave-bin.001 1136 Query 1 4 use test; create table t5 (a int) +slave-bin.001 1194 Query 1 62 use test; drop table t5 +slave-bin.001 1242 Rotate 2 1242 slave-bin.002;pos=4 show binlog events in 'slave-bin.002' from 4; Log_name Pos Event_type Server_id Orig_log_pos Info -slave-bin.002 4 Query 1 4 use test; create table t1 (n int) -slave-bin.002 62 Query 1 62 use test; insert into t1 values (1) -slave-bin.002 122 Query 1 122 use test; drop table t1 +slave-bin.002 4 Query 1 110 use test; create table t1 (n int) +slave-bin.002 62 Query 1 168 use test; insert into t1 values (1) +slave-bin.002 122 Query 1 228 use test; drop table t1 show slave status; Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.002 170 slave-relay-bin.002 1457 master-bin.002 Yes Yes 0 0 170 1461 +127.0.0.1 root MASTER_PORT 1 master-bin.002 276 slave-relay-bin.002 1522 master-bin.002 Yes Yes 0 0 276 1526 show binlog events in 'slave-bin.005' from 4; Error when executing command SHOW BINLOG EVENTS: Could not find target log diff --git a/mysql-test/t/rpl_log.test b/mysql-test/t/rpl_log.test index 85782e78142..8cd9d21a087 100644 --- a/mysql-test/t/rpl_log.test +++ b/mysql-test/t/rpl_log.test @@ -22,10 +22,32 @@ show binlog events from 79 limit 2; show binlog events from 79 limit 2,1; flush logs; +# We need an extra update before doing save_master_pos. +# Otherwise, an unlikely scenario may occur: +# * When the master's binlog_dump thread reads the end of master-bin.001, +# it send the rotate event which is at this end, plus a fake rotate event +# because it's starting to read a new binlog. +# save_master_pos will record the position of the first of the two rotate +# (because the fake one is not in the master's binlog anyway). +# * Later the slave waits for the position of the first rotate event, +# and it may quickly stop (in 'slave stop') without having received the fake +# one. +# So, depending on a few milliseconds, we end up with 2 rotate events in the +# relay log or one, which influences the output of SHOW SLAVE STATUS, making +# it not predictable and causing random test failures. +# To make it predictable, we do a useless update now, but which has the interest +# of making the slave catch both rotate events. + +create table t5 (a int); +drop table t5; + # Sync slave and force it to start on another binary log save_master_pos; connection slave; +# Note that the above 'slave start' will cause a 3rd rotate event (a fake one) +# to go into the relay log (the master always sends a fake one when replication +# starts). slave start; sync_with_master; flush logs; -- cgit v1.2.1 From 0688cf904b51b3e69102a598de1f26bbc19a9d05 Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Wed, 28 May 2003 03:36:44 +0300 Subject: Removed not used variable --- libmysqld/lib_sql.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 83f398ca50b..7682d60d991 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -436,7 +436,6 @@ int STDCALL mysql_server_init(int argc, char **argv, char **groups) (void) pthread_mutex_init(&LOCK_crypt,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_bytes_sent,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_bytes_received,MY_MUTEX_INIT_FAST); - (void) pthread_mutex_init(&LOCK_timezone,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_rpl_status, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST); -- cgit v1.2.1 From e546f33a1dced22586a6132be262d305a538ccba Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Wed, 28 May 2003 11:24:48 +0500 Subject: item_cmpfunc.cc: Fix for multibyte charsets --- sql/item_cmpfunc.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index d96069a17aa..3344f2bc01d 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1454,7 +1454,11 @@ bool Item_func_like::fix_fields(THD *thd,struct st_table_list *tlist) { const char* tmp = first + 1; for (; *tmp != wild_many && *tmp != wild_one && *tmp != escape; tmp++) ; +#ifdef USE_MB + canDoTurboBM = (tmp == last) && !use_mb(default_charset_info); +#else canDoTurboBM = tmp == last; +#endif } if (canDoTurboBM) -- cgit v1.2.1 From 8a29324cafc52affec97188cc9d27e3c8ad91cb3 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Wed, 28 May 2003 20:31:33 +0300 Subject: srv0srv.c: Prevent the InnoDB main thread from hogging CPU if a table lingers in the background drop queue (though it is essentially a bug if a table end up there at all) --- innobase/srv/srv0srv.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index 84d48bebf97..ac2622df78a 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -2790,6 +2790,15 @@ background_loop: n_tables_to_drop = row_drop_tables_for_mysql_in_background(); + if (n_tables_to_drop > 0) { + /* Do not monopolize the CPU even if there are tables waiting + in the background drop queue. (It is essentially a bug if + MySQL tries to drop a table while there are still open handles + to it and we had to put it to the background drop queue.) */ + + os_thread_sleep(100000); + } + srv_main_thread_op_info = (char*)""; srv_main_thread_op_info = (char*)"flushing buffer pool pages"; -- cgit v1.2.1 From 450f168bd4a74ab9cd16813895416f07dbb4c3f6 Mon Sep 17 00:00:00 2001 From: "gluh@gluh.mysql.r18.ru" <> Date: Thu, 29 May 2003 14:52:25 +0500 Subject: Fix for bug #529 ("x509" no allowed as field name) --- sql/sql_yacc.yy | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 340fbc1b3dc..c79750c8014 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3397,6 +3397,7 @@ keyword: | USE_FRM {} | VARIABLES {} | WORK_SYM {} + | X509_SYM {} | YEAR_SYM {}; /* Option functions */ -- cgit v1.2.1 From 3317cfdc7d756a54d53712ede7e68fcd98a71ade Mon Sep 17 00:00:00 2001 From: "gluh@gluh.mysql.r18.ru" <> Date: Fri, 30 May 2003 18:41:19 +0500 Subject: Fix for compiling MySQL-4.0.13 with SSL support on OpenBSD --- include/my_global.h | 2 +- sql/mysql_priv.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/my_global.h b/include/my_global.h index ca24c21c688..d892d843edc 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -246,7 +246,7 @@ C_MODE_END # endif #endif /* TIME_WITH_SYS_TIME */ #ifdef HAVE_UNISTD_H -#if defined(HAVE_OPENSSL) && !defined(__FreeBSD__) && !defined(NeXT) +#if defined(HAVE_OPENSSL) && !defined(__FreeBSD__) && !defined(NeXT) && !defined(__OpenBSD__) #define crypt unistd_crypt #endif #include diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 614cb8cadf6..b191a702efe 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -458,6 +458,7 @@ Field *find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables); Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, bool check_grant,bool allow_rowid); #ifdef HAVE_OPENSSL +#include struct st_des_keyblock { des_cblock key1, key2, key3; -- cgit v1.2.1 From d1759530d3c018de0f9cda544b32bc94bfb48400 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Fri, 30 May 2003 22:44:37 +0300 Subject: Many files: Exit all threads created by innoDB at shutdown --- innobase/include/os0file.h | 7 ++++++ innobase/include/os0sync.h | 12 ++++++++- innobase/include/os0thread.h | 8 +++--- innobase/log/log0log.c | 27 ++++++++++++--------- innobase/os/os0file.c | 45 +++++++++++++++++++++++++++++++++- innobase/os/os0sync.c | 27 +++++++++++++++++++-- innobase/os/os0thread.c | 30 +++++++++++++++++++++-- innobase/srv/srv0srv.c | 13 ++++++++++ innobase/srv/srv0start.c | 58 ++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 205 insertions(+), 22 deletions(-) diff --git a/innobase/include/os0file.h b/innobase/include/os0file.h index a7624a90d5e..86f27a2d3eb 100644 --- a/innobase/include/os0file.h +++ b/innobase/include/os0file.h @@ -301,6 +301,13 @@ os_aio( are ignored */ void* message2); /**************************************************************************** +Wakes up all async i/o threads so that they know to exit themselves in +shutdown. */ + +void +os_aio_wake_all_threads_at_shutdown(void); +/*=====================================*/ +/**************************************************************************** Waits until there are no pending writes in os_aio_write_array. There can be other, synchronous, pending writes. */ diff --git a/innobase/include/os0sync.h b/innobase/include/os0sync.h index b2d613c4619..d52444d02ec 100644 --- a/innobase/include/os0sync.h +++ b/innobase/include/os0sync.h @@ -38,6 +38,13 @@ typedef os_mutex_str_t* os_mutex_t; #define OS_SYNC_TIME_EXCEEDED 1 +/* Mutex protecting the thread count */ +extern os_mutex_t os_thread_count_mutex; + +/* This is incremented by 1 in os_thread_create and decremented by 1 in +os_thread_exit */ +extern ulint os_thread_count; + /************************************************************* Creates an event semaphore, i.e., a semaphore which may just have two states: signaled and nonsignaled. @@ -85,7 +92,10 @@ os_event_free( /*==========*/ os_event_t event); /* in: event to free */ /************************************************************** -Waits for an event object until it is in the signaled state. */ +Waits for an event object until it is in the signaled state. If +srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS this also exits the +waiting thread when the event becomes signaled (or immediately if the +event is already in the signaled state). */ void os_event_wait( diff --git a/innobase/include/os0thread.h b/innobase/include/os0thread.h index 629cfef23a8..29154a9e7cf 100644 --- a/innobase/include/os0thread.h +++ b/innobase/include/os0thread.h @@ -11,6 +11,7 @@ Created 9/8/1995 Heikki Tuuri #define os0thread_h #include "univ.i" +#include "os0sync.h" /* Maximum number of threads which can be created in the program; this is also the size of the wait slot array for MySQL threads which @@ -41,7 +42,6 @@ typedef os_thread_t os_thread_id_t; /* In Unix we use the thread the thread */ #endif - /* Define a function pointer type to use in a typecast */ typedef void* (*os_posix_f_t) (void*); @@ -83,12 +83,13 @@ os_thread_create( os_thread_id_t* thread_id); /* out: id of the created thread */ /********************************************************************* -A thread calling this function ends its execution. */ +Exits the current thread. */ void os_thread_exit( /*===========*/ - ulint code); /* in: exit code */ + void* exit_value); /* in: exit value; in Windows this void* + is cast as a DWORD */ /********************************************************************* Returns the thread identifier of current thread. */ @@ -144,7 +145,6 @@ ulint os_thread_get_last_error(void); /*==========================*/ - #ifndef UNIV_NONINL #include "os0thread.ic" #endif diff --git a/innobase/log/log0log.c b/innobase/log/log0log.c index 25cc666e802..e15812e03af 100644 --- a/innobase/log/log0log.c +++ b/innobase/log/log0log.c @@ -375,7 +375,7 @@ log_pad_current_log_block(void) log_close(); log_release(); - ut_a((ut_dulint_get_low(lsn) % OS_FILE_LOG_BLOCK_SIZE) + ut_ad((ut_dulint_get_low(lsn) % OS_FILE_LOG_BLOCK_SIZE) == LOG_BLOCK_HDR_SIZE); } @@ -998,6 +998,8 @@ log_group_file_header_flush( { byte* buf; ulint dest_offset; + + UT_NOT_USED(type); ut_ad(mutex_own(&(log_sys->mutex))); @@ -1068,8 +1070,8 @@ log_group_write_buf( ulint i; ut_ad(mutex_own(&(log_sys->mutex))); - ut_a(len % OS_FILE_LOG_BLOCK_SIZE == 0); - ut_a(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); + ut_ad(len % OS_FILE_LOG_BLOCK_SIZE == 0); + ut_ad(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); if (new_data_offset == 0) { write_header = TRUE; @@ -2901,10 +2903,9 @@ logs_empty_and_mark_files_at_shutdown(void) dulint lsn; ulint arch_log_no; - if (srv_print_verbose_log) - { - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Starting shutdown...\n"); + if (srv_print_verbose_log) { + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: Starting shutdown...\n"); } /* Wait until the master thread and all other operations are idle: our algorithm only works if the server is idle at shutdown */ @@ -3006,15 +3007,17 @@ loop: goto loop; } + /* Make some checks that the server really is quiet */ + ut_a(buf_all_freed()); + ut_a(0 == ut_dulint_cmp(lsn, log_sys->lsn)); + fil_write_flushed_lsn_to_data_files(lsn, arch_log_no); fil_flush_file_spaces(FIL_TABLESPACE); - if (srv_print_verbose_log) - { - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Shutdown completed\n"); - } + /* Make some checks that the server really is quiet */ + ut_a(buf_all_freed()); + ut_a(0 == ut_dulint_cmp(lsn, log_sys->lsn)); } /********************************************************** diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index c7f95d79104..640ffec122f 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -1295,7 +1295,6 @@ os_aio_array_create( #endif ut_a(n > 0); ut_a(n_segments > 0); - ut_a(n % n_segments == 0); array = ut_malloc(sizeof(os_aio_array_t)); @@ -1404,6 +1403,50 @@ os_aio_init( pthread_sigmask(SIG_BLOCK, &sigset, NULL); */ #endif } + +#ifdef WIN_ASYNC_IO +/**************************************************************************** +Wakes up all async i/o threads in the array in Windows async i/o at +shutdown. */ +static +void +os_aio_array_wake_win_aio_at_shutdown( +/*==================================*/ + os_aio_array_t* array) /* in: aio array */ +{ + ulint i; + + for (i = 0; i < array->n_slots; i++) { + + os_event_set(*(array->events + i)); + } +} +#endif + +/**************************************************************************** +Wakes up all async i/o threads so that they know to exit themselves in +shutdown. */ + +void +os_aio_wake_all_threads_at_shutdown(void) +/*=====================================*/ +{ + ulint i; + +#ifdef WIN_ASYNC_IO + /* This code wakes up all ai/o threads in Windows native aio */ + os_aio_array_wake_win_aio_at_shutdown(os_aio_read_array); + os_aio_array_wake_win_aio_at_shutdown(os_aio_write_array); + os_aio_array_wake_win_aio_at_shutdown(os_aio_ibuf_array); + os_aio_array_wake_win_aio_at_shutdown(os_aio_log_array); +#endif + /* This loop wakes up all simulated ai/o threads */ + + for (i = 0; i < os_aio_n_segments; i++) { + + os_event_set(os_aio_segment_wait_events[i]); + } +} /**************************************************************************** Waits until there are no pending writes in os_aio_write_array. There can diff --git a/innobase/os/os0sync.c b/innobase/os/os0sync.c index 407b280f805..abcfa254710 100644 --- a/innobase/os/os0sync.c +++ b/innobase/os/os0sync.c @@ -17,6 +17,7 @@ Created 9/6/1995 Heikki Tuuri #endif #include "ut0mem.h" +#include "srv0start.h" /* Type definition for an operating system mutex struct */ struct os_mutex_struct{ @@ -26,9 +27,16 @@ struct os_mutex_struct{ recursively lock the mutex: we do not assume that the OS mutex supports recursive locking, though - NT seems to do that */ + NT seems to do that */ }; +/* Mutex protecting the thread count */ +os_mutex_t os_thread_count_mutex; + +/* This is incremented by 1 in os_thread_create and decremented by 1 in +os_thread_exit */ +ulint os_thread_count = 0; + /************************************************************* Creates an event semaphore, i.e., a semaphore which may just have two states: signaled and nonsignaled. @@ -190,7 +198,10 @@ os_event_free( } /************************************************************** -Waits for an event object until it is in the signaled state. */ +Waits for an event object until it is in the signaled state. If +srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS this also exits the +waiting thread when the event becomes signaled (or immediately if the +event is already in the signaled state). */ void os_event_wait( @@ -206,12 +217,20 @@ os_event_wait( err = WaitForSingleObject(event, INFINITE); ut_a(err == WAIT_OBJECT_0); + + if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { + os_thread_exit(NULL); + } #else os_fast_mutex_lock(&(event->os_mutex)); loop: if (event->is_set == TRUE) { os_fast_mutex_unlock(&(event->os_mutex)); + if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { + + os_thread_exit(NULL); + } /* Ok, we may return */ return; @@ -299,6 +318,10 @@ os_event_wait_multiple( ut_a(index >= WAIT_OBJECT_0); ut_a(index < WAIT_OBJECT_0 + n); + if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { + os_thread_exit(NULL); + } + return(index - WAIT_OBJECT_0); #else ut_a(n == 0); diff --git a/innobase/os/os0thread.c b/innobase/os/os0thread.c index b0076921e43..a68f6a3b8bc 100644 --- a/innobase/os/os0thread.c +++ b/innobase/os/os0thread.c @@ -1,6 +1,5 @@ /****************************************************** -The interface to the operating system -process and thread control primitives +The interface to the operating system thread control primitives (c) 1995 Innobase Oy @@ -102,6 +101,10 @@ os_thread_create( os_thread_t thread; ulint win_thread_id; + os_mutex_enter(os_thread_count_mutex); + os_thread_count++; + os_mutex_exit(os_thread_count_mutex); + thread = CreateThread(NULL, /* no security attributes */ 0, /* default size stack */ (LPTHREAD_START_ROUTINE)start_f, @@ -144,6 +147,9 @@ os_thread_create( exit(1); } #endif + os_mutex_enter(os_thread_count_mutex); + os_thread_count++; + os_mutex_exit(os_thread_count_mutex); #if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10) ret = pthread_create(&pthread, pthread_attr_default, start_f, arg); @@ -170,6 +176,26 @@ os_thread_create( #endif } +/********************************************************************* +Exits the current thread. */ + +void +os_thread_exit( +/*===========*/ + void* exit_value) /* in: exit value; in Windows this void* + is cast as a DWORD */ +{ + os_mutex_enter(os_thread_count_mutex); + os_thread_count--; + os_mutex_exit(os_thread_count_mutex); + +#ifdef __WIN__ + ExitThread((DWORD)exit_value); +#else + pthread_exit(exit_value); +#endif +} + /********************************************************************* Returns handle to the current thread. */ diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index ef50a4ca261..a44bc0147e4 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -1702,6 +1702,8 @@ void srv_general_init(void) /*==================*/ { + os_thread_count_mutex = os_mutex_create(NULL); + sync_init(); mem_init(srv_mem_pool_size); thr_local_init(); @@ -1720,6 +1722,8 @@ srv_general_free(void) /*==================*/ { sync_close(); + + os_mutex_free(os_thread_count_mutex); } #endif /* __NETWARE__ */ @@ -2700,6 +2704,8 @@ loop: srv_error_monitor_active = FALSE; + os_thread_exit(NULL); + #ifndef __WIN__ return(NULL); #else @@ -3139,6 +3145,13 @@ suspend_thread: os_event_wait(event); + if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { + /* This is only extra safety, the thread should exit + already when the event wait ends */ + + os_thread_exit(NULL); + } + /* When there is user activity, InnoDB will set the event and the main thread goes back to loop: */ diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index d47af68d663..3d98e116905 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -1470,6 +1470,8 @@ innobase_shutdown_for_mysql(void) /*=============================*/ /* out: DB_SUCCESS or error code */ { + ulint i; + if (!srv_was_started) { if (srv_is_being_started) { ut_print_timestamp(stderr); @@ -1494,6 +1496,58 @@ innobase_shutdown_for_mysql(void) srv_conc_n_threads); } + /* Now we will exit all threads InnoDB created */ + + srv_shutdown_state = SRV_SHUTDOWN_EXIT_THREADS; + + /* All threads end up waiting for certain events. Put those events + to the signaled state. Then the threads will exit themselves in + os_thread_event_wait(). */ + + for (i = 0; i < 1000; i++) { + /* NOTE: IF YOU CREATE THREADS IN INNODB, YOU MUST EXIT THEM + HERE OR EARLIER */ + + /* 1. Let the lock timeout thread exit */ + os_event_set(srv_lock_timeout_thread_event); + + /* 2. srv error monitor thread exits automatically, no need + to do anything here */ + + /* 3. We wake the master thread so that it exits */ + srv_wake_master_thread(); + + /* 4. Exit the i/o threads */ + + os_aio_wake_all_threads_at_shutdown(); + + os_mutex_enter(os_thread_count_mutex); + + if (os_thread_count == 0) { + /* All the threads have exited or are just exiting; + NOTE that the threads may not have completed their + exit yet. Should we use pthread_join() to make sure + they have exited? Now we just sleep 0.1 seconds and + hope that is enough! */ + + os_mutex_exit(os_thread_count_mutex); + + os_thread_sleep(100000); + + break; + } + + os_mutex_exit(os_thread_count_mutex); + + os_thread_sleep(100000); + } + + if (i == 1000) { + fprintf(stderr, +"InnoDB: Warning: %lu threads created by InnoDB had not exited at shutdown!\n", + os_thread_count); + } + #if defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY) /* TODO: Fix this temporary solution @@ -1518,6 +1572,10 @@ innobase_shutdown_for_mysql(void) /* NetWare requires this free */ ut_free_all_mem(); #endif + if (srv_print_verbose_log) { + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: Shutdown completed\n"); + } return((int) DB_SUCCESS); } -- cgit v1.2.1 From cfda0a16ffc759b0f96ae96e6092b72b9b3d5741 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Fri, 30 May 2003 23:00:37 +0300 Subject: srv0start.c: Cleanup --- innobase/srv/srv0start.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index 3d98e116905..d34c18b1a25 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -1549,13 +1549,6 @@ innobase_shutdown_for_mysql(void) } #if defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY) - /* - TODO: Fix this temporary solution - We are having a race condition occure with io_handler_thread threads. - When they yield in os_aio_simulated_handle during shutdown, this - thread was able to free the memory early. - */ - os_thread_yield(); /* TODO: Where should this be called? */ srv_free(); @@ -1563,11 +1556,7 @@ innobase_shutdown_for_mysql(void) /* TODO: Where should this be called? */ srv_general_free(); #endif - /* - TODO: We should exit the i/o-handler and other utility threads - before freeing all memory. Now this can potentially cause a seg - fault! - */ + #if defined(NOT_WORKING_YET) || defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY) /* NetWare requires this free */ ut_free_all_mem(); -- cgit v1.2.1 From 2848e6c0d4f5c3b646fc346140eb6f4bb4d94e83 Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Sat, 31 May 2003 01:41:11 +0300 Subject: fixed bug 549 - incorect query cache memory formating on very small query cache sizes --- mysql-test/r/query_cache.result | 60 ++++++++++++++++++++++++++++++++++------- mysql-test/t/query_cache.test | 35 +++++++++++++++++------- sql/sql_cache.cc | 16 +++++------ 3 files changed, 83 insertions(+), 28 deletions(-) diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index a55e05578e0..6abd572b3d9 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -501,22 +501,62 @@ drop table t1; show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 0 +create table t1 (a int); set GLOBAL query_cache_size=1000; show global variables like "query_cache_size"; Variable_name Value query_cache_size 0 -set GLOBAL query_cache_size=1100; -set GLOBAL query_cache_size=1200; -set GLOBAL query_cache_size=1300; -set GLOBAL query_cache_size=1400; -set GLOBAL query_cache_size=1500; -set GLOBAL query_cache_size=1600; -set GLOBAL query_cache_size=1700; -set GLOBAL query_cache_size=1800; -set GLOBAL query_cache_size=1900; +select * from t1; +a +set GLOBAL query_cache_size=1024; +show global variables like "query_cache_size"; +Variable_name Value +query_cache_size 0 +select * from t1; +a +set GLOBAL query_cache_size=10240; +show global variables like "query_cache_size"; +Variable_name Value +query_cache_size 0 +select * from t1; +a +set GLOBAL query_cache_size=20480; +show global variables like "query_cache_size"; +Variable_name Value +query_cache_size 0 +select * from t1; +a +set GLOBAL query_cache_size=40960; +show global variables like "query_cache_size"; +Variable_name Value +query_cache_size 0 +select * from t1; +a +set GLOBAL query_cache_size=51200; +show global variables like "query_cache_size"; +Variable_name Value +query_cache_size 51200 +select * from t1; +a +set GLOBAL query_cache_size=61440; show global variables like "query_cache_size"; Variable_name Value -query_cache_size 1024 +query_cache_size 61440 +select * from t1; +a +set GLOBAL query_cache_size=81920; +show global variables like "query_cache_size"; +Variable_name Value +query_cache_size 81920 +select * from t1; +a +set GLOBAL query_cache_size=102400; +show global variables like "query_cache_size"; +Variable_name Value +query_cache_size 102400 +select * from t1; +a +drop table t1; set GLOBAL query_cache_size=1048576; create table t1 (i int not null); create table t2 (i int not null); diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index 33f226f9253..f0f3063c00d 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -343,18 +343,35 @@ show status like "Qcache_queries_in_cache"; # # Test of query cache resizing # +create table t1 (a int); set GLOBAL query_cache_size=1000; show global variables like "query_cache_size"; -set GLOBAL query_cache_size=1100; -set GLOBAL query_cache_size=1200; -set GLOBAL query_cache_size=1300; -set GLOBAL query_cache_size=1400; -set GLOBAL query_cache_size=1500; -set GLOBAL query_cache_size=1600; -set GLOBAL query_cache_size=1700; -set GLOBAL query_cache_size=1800; -set GLOBAL query_cache_size=1900; +select * from t1; +set GLOBAL query_cache_size=1024; +show global variables like "query_cache_size"; +select * from t1; +set GLOBAL query_cache_size=10240; +show global variables like "query_cache_size"; +select * from t1; +set GLOBAL query_cache_size=20480; +show global variables like "query_cache_size"; +select * from t1; +set GLOBAL query_cache_size=40960; +show global variables like "query_cache_size"; +select * from t1; +set GLOBAL query_cache_size=51200; +show global variables like "query_cache_size"; +select * from t1; +set GLOBAL query_cache_size=61440; +show global variables like "query_cache_size"; +select * from t1; +set GLOBAL query_cache_size=81920; show global variables like "query_cache_size"; +select * from t1; +set GLOBAL query_cache_size=102400; +show global variables like "query_cache_size"; +select * from t1; +drop table t1; # # Temporary tables diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 59430d6a486..1fcd0d1456b 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -731,7 +731,7 @@ ulong Query_cache::resize(ulong query_cache_size_arg) query_cache_size_arg)); free_cache(0); query_cache_size= query_cache_size_arg; - DBUG_RETURN(init_cache()); + DBUG_RETURN(::query_cache_size= init_cache()); } @@ -1282,6 +1282,12 @@ ulong Query_cache::init_cache() mem_bin_steps = 1; mem_bin_size = max_mem_bin_size >> QUERY_CACHE_MEM_BIN_STEP_PWR2; prev_size = 0; + if (mem_bin_size <= min_allocation_unit) + { + DBUG_PRINT("qcache", ("too small query cache => query cache disabled")); + // TODO here (and above) should be warning in 4.1 + goto err; + } while (mem_bin_size > min_allocation_unit) { mem_bin_num += mem_bin_count; @@ -1308,14 +1314,6 @@ ulong Query_cache::init_cache() query_cache_size -= additional_data_size; STRUCT_LOCK(&structure_guard_mutex); - if (max_mem_bin_size <= min_allocation_unit) - { - DBUG_PRINT("qcache", - (" max bin size (%lu) <= min_allocation_unit => cache disabled", - max_mem_bin_size)); - STRUCT_UNLOCK(&structure_guard_mutex); - goto err; - } if (!(cache = (byte *) my_malloc_lock(query_cache_size+additional_data_size, MYF(0)))) -- cgit v1.2.1 From 42671d18aed8d98b445a1abea8de56c0a2613b7c Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Sat, 31 May 2003 03:12:03 +0300 Subject: Many files: Free all OS sync primitives and allocated memory in InnoDB shutdown --- innobase/include/os0sync.h | 36 +++++++++--- innobase/include/srv0srv.h | 6 ++ innobase/include/srv0start.h | 7 ++- innobase/os/os0sync.c | 128 ++++++++++++++++++++++++++++++++++++++++--- innobase/os/os0thread.c | 12 ++-- innobase/srv/srv0srv.c | 69 ++++------------------- innobase/srv/srv0start.c | 32 +++++------ innobase/sync/sync0sync.c | 27 +++++++-- innobase/ut/ut0mem.c | 2 + 9 files changed, 213 insertions(+), 106 deletions(-) diff --git a/innobase/include/os0sync.h b/innobase/include/os0sync.h index d52444d02ec..3096c9256ed 100644 --- a/innobase/include/os0sync.h +++ b/innobase/include/os0sync.h @@ -10,15 +10,16 @@ Created 9/6/1995 Heikki Tuuri #define os0sync_h #include "univ.i" +#include "ut0lst.h" #ifdef __WIN__ - #define os_fast_mutex_t CRITICAL_SECTION -typedef void* os_event_t; - +typedef HANDLE os_event_t; #else - typedef pthread_mutex_t os_fast_mutex_t; + +typedef struct os_event_struct os_event_struct_t; +typedef os_event_struct_t* os_event_t; struct os_event_struct { os_fast_mutex_t os_mutex; /* this mutex protects the next fields */ @@ -26,9 +27,9 @@ struct os_event_struct { not reserved */ pthread_cond_t cond_var; /* condition variable is used in waiting for the event */ + UT_LIST_NODE_T(os_event_struct_t) os_event_list; + /* list of all created events */ }; -typedef struct os_event_struct os_event_struct_t; -typedef os_event_struct_t* os_event_t; #endif typedef struct os_mutex_struct os_mutex_str_t; @@ -38,13 +39,30 @@ typedef os_mutex_str_t* os_mutex_t; #define OS_SYNC_TIME_EXCEEDED 1 -/* Mutex protecting the thread count */ -extern os_mutex_t os_thread_count_mutex; +/* Mutex protecting the thread count and event and OS 'slow' mutex lists */ +extern os_mutex_t os_sync_mutex; /* This is incremented by 1 in os_thread_create and decremented by 1 in os_thread_exit */ -extern ulint os_thread_count; +extern ulint os_thread_count; +/* The following are approximate counters for debugging in Unix */ +extern ulint os_event_count; +extern ulint os_mutex_count; + +/************************************************************* +Initializes global event and OS 'slow' mutex lists. */ + +void +os_sync_init(void); +/*==============*/ +/************************************************************* +Frees created events (not in Windows) and OS 'slow' mutexes. OS 'fast' +mutexes must be freed with sync_free() before this. */ + +void +os_sync_free(void); +/*==============*/ /************************************************************* Creates an event semaphore, i.e., a semaphore which may just have two states: signaled and nonsignaled. diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h index 8355496762c..24e692dedab 100644 --- a/innobase/include/srv0srv.h +++ b/innobase/include/srv0srv.h @@ -209,6 +209,12 @@ void srv_init(void); /*==========*/ /************************************************************************* +Frees the OS fast mutex created in srv_init(). */ + +void +srv_free(void); +/*==========*/ +/************************************************************************* Initializes the synchronization primitives, memory system, and the thread local storage. */ diff --git a/innobase/include/srv0start.h b/innobase/include/srv0start.h index aec3ebfeea9..8d2c3fa12c5 100644 --- a/innobase/include/srv0start.h +++ b/innobase/include/srv0start.h @@ -86,11 +86,12 @@ extern ibool srv_startup_is_before_trx_rollback_phase; extern ibool srv_is_being_shut_down; /* At a shutdown the value first climbs from 0 to SRV_SHUTDOWN_CLEANUP -and then to SRV_SHUTDOWN_LAST_PHASE */ +and then to SRV_SHUTDOWN_LAST_PHASE, and so on */ extern ulint srv_shutdown_state; -#define SRV_SHUTDOWN_CLEANUP 1 -#define SRV_SHUTDOWN_LAST_PHASE 2 +#define SRV_SHUTDOWN_CLEANUP 1 +#define SRV_SHUTDOWN_LAST_PHASE 2 +#define SRV_SHUTDOWN_EXIT_THREADS 3 #endif diff --git a/innobase/os/os0sync.c b/innobase/os/os0sync.c index abcfa254710..ce9f21ec9a1 100644 --- a/innobase/os/os0sync.c +++ b/innobase/os/os0sync.c @@ -28,14 +28,74 @@ struct os_mutex_struct{ do not assume that the OS mutex supports recursive locking, though NT seems to do that */ + UT_LIST_NODE_T(os_mutex_str_t) os_mutex_list; + /* list of all 'slow' OS mutexes created */ }; -/* Mutex protecting the thread count */ -os_mutex_t os_thread_count_mutex; +/* Mutex protecting the thread count and the lists of OS mutexes +and events */ +os_mutex_t os_sync_mutex; +ibool os_sync_mutex_inited = FALSE; /* This is incremented by 1 in os_thread_create and decremented by 1 in os_thread_exit */ -ulint os_thread_count = 0; +ulint os_thread_count = 0; + +/* The list of all events created (not in Windows) */ +UT_LIST_BASE_NODE_T(os_event_struct_t) os_event_list; + +/* The list of all OS 'slow' mutexes */ +UT_LIST_BASE_NODE_T(os_mutex_str_t) os_mutex_list; + +/* The following are approximate counters for debugging in Unix */ +ulint os_event_count = 0; +ulint os_mutex_count = 0; + + +/************************************************************* +Initializes global event and OS 'slow' mutex lists. */ + +void +os_sync_init(void) +/*==============*/ +{ + UT_LIST_INIT(os_event_list); + UT_LIST_INIT(os_mutex_list); + + os_sync_mutex = os_mutex_create(NULL); + + os_sync_mutex_inited = TRUE; +} + +/************************************************************* +Frees created events (not in Windows) and OS 'slow' mutexes. OS 'fast' +mutexes must be freed with sync_free() before this. */ + +void +os_sync_free(void) +/*==============*/ +{ + os_event_t event; + os_mutex_t mutex; + + event = UT_LIST_GET_FIRST(os_event_list); + + while (event) { + + os_event_free(event); + + event = UT_LIST_GET_FIRST(os_event_list); + } + + mutex = UT_LIST_GET_FIRST(os_mutex_list); + + while (mutex) { + + os_mutex_free(mutex); + + mutex = UT_LIST_GET_FIRST(os_mutex_list); + } +} /************************************************************* Creates an event semaphore, i.e., a semaphore which may @@ -51,8 +111,8 @@ os_event_create( the event is created without a name */ { #ifdef __WIN__ - HANDLE event; - + os_event_t event; + event = CreateEvent(NULL, /* No security attributes */ TRUE, /* Manual reset */ FALSE, /* Initial state nonsignaled */ @@ -83,6 +143,14 @@ os_event_create( #endif event->is_set = FALSE; + os_mutex_enter(os_sync_mutex); + + UT_LIST_ADD_FIRST(os_event_list, os_event_list, event); + + os_event_count++; + + os_mutex_exit(os_sync_mutex); + return(event); #endif } @@ -100,7 +168,7 @@ os_event_create_auto( the event is created without a name */ { #ifdef __WIN__ - HANDLE event; + os_event_t event; event = CreateEvent(NULL, /* No security attributes */ FALSE, /* Auto-reset */ @@ -114,6 +182,8 @@ os_event_create_auto( UT_NOT_USED(name); + ut_a(0); + return(NULL); #endif } @@ -193,6 +263,14 @@ os_event_free( os_fast_mutex_free(&(event->os_mutex)); ut_a(0 == pthread_cond_destroy(&(event->cond_var))); + os_mutex_enter(os_sync_mutex); + + UT_LIST_REMOVE(os_event_list, os_event_list, event); + + os_event_count--; + + os_mutex_exit(os_sync_mutex); + ut_free(event); #endif } @@ -310,8 +388,7 @@ os_event_wait_multiple( ut_a(event_array); ut_a(n > 0); - index = WaitForMultipleObjects(n, - event_array, + index = WaitForMultipleObjects(n, event_array, FALSE, /* Wait for any 1 event */ INFINITE); /* Infinite wait time limit */ @@ -360,6 +437,16 @@ os_mutex_create( mutex_str->handle = mutex; mutex_str->count = 0; + if (os_sync_mutex_inited) { + os_mutex_enter(os_sync_mutex); + } + + UT_LIST_ADD_FIRST(os_mutex_list, os_mutex_list, mutex_str); + + if (os_sync_mutex_inited) { + os_mutex_exit(os_sync_mutex); + } + return(mutex_str); #else os_fast_mutex_t* os_mutex; @@ -376,6 +463,16 @@ os_mutex_create( mutex_str->handle = os_mutex; mutex_str->count = 0; + if (os_sync_mutex_inited) { + os_mutex_enter(os_sync_mutex); + } + + UT_LIST_ADD_FIRST(os_mutex_list, os_mutex_list, mutex_str); + + if (os_sync_mutex_inited) { + os_mutex_exit(os_sync_mutex); + } + return(mutex_str); #endif } @@ -447,9 +544,22 @@ os_mutex_free( #ifdef __WIN__ ut_a(mutex); + os_mutex_enter(os_sync_mutex); + + UT_LIST_REMOVE(os_mutex_list, os_mutex_list, mutex); + + os_mutex_exit(os_sync_mutex); + ut_a(CloseHandle(mutex->handle)); + ut_free(mutex); #else + os_mutex_enter(os_sync_mutex); + + UT_LIST_REMOVE(os_mutex_list, os_mutex_list, mutex); + + os_mutex_exit(os_sync_mutex); + os_fast_mutex_free(mutex->handle); ut_free(mutex->handle); ut_free(mutex); @@ -474,6 +584,7 @@ os_fast_mutex_init( #else ut_a(0 == pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST)); #endif + os_mutex_count++; #endif } @@ -521,5 +632,6 @@ os_fast_mutex_free( DeleteCriticalSection((LPCRITICAL_SECTION) fast_mutex); #else ut_a(0 == pthread_mutex_destroy(fast_mutex)); + os_mutex_count--; #endif } diff --git a/innobase/os/os0thread.c b/innobase/os/os0thread.c index a68f6a3b8bc..1722051a841 100644 --- a/innobase/os/os0thread.c +++ b/innobase/os/os0thread.c @@ -101,9 +101,9 @@ os_thread_create( os_thread_t thread; ulint win_thread_id; - os_mutex_enter(os_thread_count_mutex); + os_mutex_enter(os_sync_mutex); os_thread_count++; - os_mutex_exit(os_thread_count_mutex); + os_mutex_exit(os_sync_mutex); thread = CreateThread(NULL, /* no security attributes */ 0, /* default size stack */ @@ -147,9 +147,9 @@ os_thread_create( exit(1); } #endif - os_mutex_enter(os_thread_count_mutex); + os_mutex_enter(os_sync_mutex); os_thread_count++; - os_mutex_exit(os_thread_count_mutex); + os_mutex_exit(os_sync_mutex); #if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10) ret = pthread_create(&pthread, pthread_attr_default, start_f, arg); @@ -185,9 +185,9 @@ os_thread_exit( void* exit_value) /* in: exit value; in Windows this void* is cast as a DWORD */ { - os_mutex_enter(os_thread_count_mutex); + os_mutex_enter(os_sync_mutex); os_thread_count--; - os_mutex_exit(os_thread_count_mutex); + os_mutex_exit(os_sync_mutex); #ifdef __WIN__ ExitThread((DWORD)exit_value); diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index a44bc0147e4..da2966a7124 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -1693,80 +1693,33 @@ srv_init(void) ut_a(conc_slot->event); } } - + /************************************************************************* -Initializes the synchronization primitives, memory system, and the thread -local storage. */ +Frees the OS fast mutex created in srv_init(). */ void -srv_general_init(void) -/*==================*/ +srv_free(void) +/*==========*/ { - os_thread_count_mutex = os_mutex_create(NULL); - - sync_init(); - mem_init(srv_mem_pool_size); - thr_local_init(); + os_fast_mutex_free(&srv_conc_mutex); } - -#if defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY) -/* NetWare requires some cleanup of mutexes */ - /************************************************************************* -Deinitializes the synchronization primitives, memory system, and the thread +Initializes the synchronization primitives, memory system, and the thread local storage. */ void -srv_general_free(void) +srv_general_init(void) /*==================*/ { - sync_close(); - - os_mutex_free(os_thread_count_mutex); + os_sync_init(); + sync_init(); + mem_init(srv_mem_pool_size); + thr_local_init(); } -#endif /* __NETWARE__ */ - /*======================= InnoDB Server FIFO queue =======================*/ -#if defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY) -/* NetWare requires some cleanup of mutexes */ - -/************************************************************************* -Deinitializes the server. */ - -void -srv_free(void) -/*==========*/ -{ - srv_conc_slot_t* conc_slot; - srv_slot_t* slot; - ulint i; - - for (i = 0; i < OS_THREAD_MAX_N; i++) - { - slot = srv_table_get_nth_slot(i); - os_event_free(slot->event); - } - - /* TODO: free(srv_sys->threads); */ - - for (i = 0; i < OS_THREAD_MAX_N; i++) - { - slot = srv_mysql_table + i; - os_event_free(slot->event); - } - - /* TODO: free(srv_mysql_table); */ - - for (i = 0; i < OS_THREAD_MAX_N; i++) - { - conc_slot = srv_conc_slots + i; - os_event_free(conc_slot->event); - } -} -#endif /* __NETWARE__ */ /************************************************************************* Puts an OS thread to wait if there are too many concurrent threads diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index d34c18b1a25..f03355b825c 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -1442,9 +1442,7 @@ innobase_start_or_create_for_mysql(void) os_fast_mutex_unlock(&srv_os_test_mutex); -#if defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY) - os_fast_mutex_free(&srv_os_test_mutex); /* all platforms? */ -#endif /* __NETWARE__ */ + os_fast_mutex_free(&srv_os_test_mutex); if (srv_print_verbose_log) { ut_print_timestamp(stderr); @@ -1484,7 +1482,7 @@ innobase_shutdown_for_mysql(void) return(DB_SUCCESS); } - /* Flush buffer pool to disk, write the current lsn to + /* 1. Flush buffer pool to disk, write the current lsn to the tablespace header(s), and copy all log data to archive */ logs_empty_and_mark_files_at_shutdown(); @@ -1496,7 +1494,7 @@ innobase_shutdown_for_mysql(void) srv_conc_n_threads); } - /* Now we will exit all threads InnoDB created */ + /* 2. Make all threads created by InnoDB to exit */ srv_shutdown_state = SRV_SHUTDOWN_EXIT_THREADS; @@ -1521,7 +1519,7 @@ innobase_shutdown_for_mysql(void) os_aio_wake_all_threads_at_shutdown(); - os_mutex_enter(os_thread_count_mutex); + os_mutex_enter(os_sync_mutex); if (os_thread_count == 0) { /* All the threads have exited or are just exiting; @@ -1530,14 +1528,14 @@ innobase_shutdown_for_mysql(void) they have exited? Now we just sleep 0.1 seconds and hope that is enough! */ - os_mutex_exit(os_thread_count_mutex); + os_mutex_exit(os_sync_mutex); os_thread_sleep(100000); break; } - os_mutex_exit(os_thread_count_mutex); + os_mutex_exit(os_sync_mutex); os_thread_sleep(100000); } @@ -1548,19 +1546,21 @@ innobase_shutdown_for_mysql(void) os_thread_count); } -#if defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY) + /* 3. Free all InnoDB's own mutexes */ + + sync_close(); + + /* 4. Free all OS synchronization primitives (in Windows currently + events are not freed) */ - /* TODO: Where should this be called? */ srv_free(); + os_sync_free(); - /* TODO: Where should this be called? */ - srv_general_free(); -#endif + /* 5. Free all allocated memory (and the os_fast_mutex created in + ut0mem.c */ -#if defined(NOT_WORKING_YET) || defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY) - /* NetWare requires this free */ ut_free_all_mem(); -#endif + if (srv_print_verbose_log) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Shutdown completed\n"); diff --git a/innobase/sync/sync0sync.c b/innobase/sync/sync0sync.c index 20d68ba5a9f..32615ce88ac 100644 --- a/innobase/sync/sync0sync.c +++ b/innobase/sync/sync0sync.c @@ -235,8 +235,7 @@ mutex_create_func( mutex->cline = cline; /* Check that lock_word is aligned; this is important on Intel */ - - ut_a(((ulint)(&(mutex->lock_word))) % 4 == 0); + ut_ad(((ulint)(&(mutex->lock_word))) % 4 == 0); /* NOTE! The very first mutexes are not put to the mutex list */ @@ -266,11 +265,14 @@ mutex_free( ut_a(mutex_get_lock_word(mutex) == 0); ut_a(mutex_get_waiters(mutex) == 0); - mutex_enter(&mutex_list_mutex); + if (mutex != &mutex_list_mutex && mutex != &sync_thread_mutex) { - UT_LIST_REMOVE(list, mutex_list, mutex); + mutex_enter(&mutex_list_mutex); - mutex_exit(&mutex_list_mutex); + UT_LIST_REMOVE(list, mutex_list, mutex); + + mutex_exit(&mutex_list_mutex); + } #if !defined(_WIN32) || !defined(UNIV_CAN_USE_X86_ASSEMBLER) os_fast_mutex_free(&(mutex->os_fast_mutex)); @@ -1230,13 +1232,26 @@ sync_init(void) } /********************************************************************** -Frees the resources in synchronization data structures. */ +Frees the resources in InnoDB's own synchronization data structures. Use +os_sync_free() after calling this. */ void sync_close(void) /*===========*/ { + mutex_t* mutex; + sync_array_free(sync_primary_wait_array); + + mutex = UT_LIST_GET_FIRST(mutex_list); + + while (mutex) { + mutex_free(mutex); + mutex = UT_LIST_GET_FIRST(mutex_list); + } + + mutex_free(&mutex_list_mutex); + mutex_free(&sync_thread_mutex); } /*********************************************************************** diff --git a/innobase/ut/ut0mem.c b/innobase/ut/ut0mem.c index dbd3e7e4737..174ae4cc6bb 100644 --- a/innobase/ut/ut0mem.c +++ b/innobase/ut/ut0mem.c @@ -190,6 +190,8 @@ ut_free_all_mem(void) os_fast_mutex_unlock(&ut_list_mutex); ut_a(ut_total_allocated_memory == 0); + + os_fast_mutex_free(&ut_list_mutex); } /************************************************************************** -- cgit v1.2.1 From dcdc6ffadcb709b30ba049e10c992a84f3a3be12 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Sat, 31 May 2003 03:23:42 +0300 Subject: os0thread.c, os0thread.h, os0sync.h: Cleanup os0sync.c: Free all OS sync primitives and allocated memory in InnoDB shutdown --- innobase/include/os0sync.h | 3 +-- innobase/include/os0thread.h | 1 - innobase/os/os0sync.c | 3 +-- innobase/os/os0thread.c | 1 + 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/innobase/include/os0sync.h b/innobase/include/os0sync.h index 3096c9256ed..bad8e6e120a 100644 --- a/innobase/include/os0sync.h +++ b/innobase/include/os0sync.h @@ -57,8 +57,7 @@ void os_sync_init(void); /*==============*/ /************************************************************* -Frees created events (not in Windows) and OS 'slow' mutexes. OS 'fast' -mutexes must be freed with sync_free() before this. */ +Frees created events (not in Windows) and OS 'slow' mutexes. */ void os_sync_free(void); diff --git a/innobase/include/os0thread.h b/innobase/include/os0thread.h index 29154a9e7cf..92187f315c2 100644 --- a/innobase/include/os0thread.h +++ b/innobase/include/os0thread.h @@ -11,7 +11,6 @@ Created 9/8/1995 Heikki Tuuri #define os0thread_h #include "univ.i" -#include "os0sync.h" /* Maximum number of threads which can be created in the program; this is also the size of the wait slot array for MySQL threads which diff --git a/innobase/os/os0sync.c b/innobase/os/os0sync.c index ce9f21ec9a1..4f322ee82b2 100644 --- a/innobase/os/os0sync.c +++ b/innobase/os/os0sync.c @@ -68,8 +68,7 @@ os_sync_init(void) } /************************************************************* -Frees created events (not in Windows) and OS 'slow' mutexes. OS 'fast' -mutexes must be freed with sync_free() before this. */ +Frees created events (not in Windows) and OS 'slow' mutexes. */ void os_sync_free(void) diff --git a/innobase/os/os0thread.c b/innobase/os/os0thread.c index 1722051a841..02ea2c227a7 100644 --- a/innobase/os/os0thread.c +++ b/innobase/os/os0thread.c @@ -16,6 +16,7 @@ Created 9/8/1995 Heikki Tuuri #endif #include "srv0srv.h" +#include "os0sync.h" /******************************************************************* Compares two thread ids for equality. */ -- cgit v1.2.1 From 373a9caa8258978ce542d6db34086354b964958a Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Sat, 31 May 2003 18:44:37 +0300 Subject: Fixed compiler optimization problem with doubleget() (Casused problems in GIS functions in 4.1) --- include/global.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/global.h b/include/global.h index 1737c60db30..94b0f5bab03 100644 --- a/include/global.h +++ b/include/global.h @@ -795,8 +795,11 @@ typedef union { double v; long m[2]; } doubleget_union; -#define doubleget(V,M) { ((doubleget_union *)&V)->m[0] = *((long*) M); \ - ((doubleget_union *)&V)->m[1] = *(((long*) M)+1); } +#define doubleget(V,M) \ +{ doubleget_union _tmp; \ + _tmp.m[0] = *((long*)(M)); \ + _tmp.m[1] = *(((long*) (M))+1); \ + (V) = _tmp.v; } #define doublestore(T,V) { *((long *) T) = ((doubleget_union *)&V)->m[0]; \ *(((long *) T)+1) = ((doubleget_union *)&V)->m[1]; } #define float4get(V,M) { *((long *) &(V)) = *((long*) (M)); } -- cgit v1.2.1 From 02adbe659991af851a51c225059011a20d5cd47c Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Sun, 1 Jun 2003 12:32:53 +0300 Subject: Fixed bug in ALTER TABLE DISABLE KEYS and INSERT DELAYED. Bug #478 --- mysql-test/r/alter_table.result | 5 ++ mysql-test/r/lowercase_table.result | 12 ++++ mysql-test/t/alter_table.test | 9 +++ mysql-test/t/lowercase_table.test | 11 +++ sql/mysql_priv.h | 1 - sql/sql_table.cc | 133 ++++++++++++++++++++++-------------- 6 files changed, 118 insertions(+), 53 deletions(-) diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index cfbc46bc78f..e2d9cc30ad9 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -276,3 +276,8 @@ t1 0 a 1 a A 3 NULL NULL YES BTREE t1 0 a 2 b A 300 NULL NULL YES BTREE t1 1 b 1 b A 100 NULL NULL YES BTREE drop table t1; +CREATE TABLE t1 (i int(10), index(i) ); +ALTER TABLE t1 DISABLE KEYS; +INSERT DELAYED INTO t1 VALUES(1),(2),(3); +ALTER TABLE t1 ENABLE KEYS; +drop table t1; diff --git a/mysql-test/r/lowercase_table.result b/mysql-test/r/lowercase_table.result index 1caaf317c96..d32228216b8 100644 --- a/mysql-test/r/lowercase_table.result +++ b/mysql-test/r/lowercase_table.result @@ -13,3 +13,15 @@ show tables like 't_'; Tables_in_test (t_) t3 drop table t3; +create table t1 (a int); +select count(*) from T1; +count(*) +0 +select count(*) from t1; +count(*) +0 +select count(T1.a) from t1; +Unknown table 'T1' in field list +select count(bags.a) from t1 as Bags; +Unknown table 'bags' in field list +drop table t1; diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index 96f969c8776..a3ab62afc69 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -133,3 +133,12 @@ analyze table t1; show keys from t1; drop table t1; +# +# Test of ALTER TABLE DELAYED +# + +CREATE TABLE t1 (i int(10), index(i) ); +ALTER TABLE t1 DISABLE KEYS; +INSERT DELAYED INTO t1 VALUES(1),(2),(3); +ALTER TABLE t1 ENABLE KEYS; +drop table t1; diff --git a/mysql-test/t/lowercase_table.test b/mysql-test/t/lowercase_table.test index 0d04e6c7df7..b3453dfd3c4 100644 --- a/mysql-test/t/lowercase_table.test +++ b/mysql-test/t/lowercase_table.test @@ -12,3 +12,14 @@ ALTER TABLE T2 RENAME T3; show tables like 't_'; drop table t3; +# +# Test alias +# +create table t1 (a int); +select count(*) from T1; +select count(*) from t1; +--error 1109 +select count(T1.a) from t1; +--error 1109 +select count(bags.a) from t1 as Bags; +drop table t1; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 614cb8cadf6..41a39f0d24c 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -422,7 +422,6 @@ bool mysql_rename_table(enum db_type base, const char * old_name, const char *new_db, const char * new_name); -bool close_cached_table(THD *thd,TABLE *table); int mysql_create_index(THD *thd, TABLE_LIST *table_list, List &keys); int mysql_drop_index(THD *thd, TABLE_LIST *table_list, List &drop_list); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 07ec1d67538..f3620b860a7 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -912,58 +912,76 @@ mysql_rename_table(enum db_type base, } /* - close table in this thread and force close + reopen in other threads - This assumes that the calling thread has lock on LOCK_open - Win32 clients must also have a WRITE LOCK on the table ! + Force all other threads to stop using the table + + SYNOPSIS + wait_while_table_is_used() + thd Thread handler + table Table to remove from cache + + NOTES + When returning, the table will be unusable for other threads until + the table is closed. + + PREREQUISITES + Lock on LOCK_open + Win32 clients must also have a WRITE LOCK on the table ! */ -static void safe_remove_from_cache(THD *thd,TABLE *table) +static void wait_while_table_is_used(THD *thd,TABLE *table) { - DBUG_ENTER("safe_remove_from_cache"); - if (table) - { - DBUG_PRINT("enter",("table: %s", table->real_name)); - VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Close all data files - /* Mark all tables that are in use as 'old' */ - mysql_lock_abort(thd,table); // end threads waiting on lock + DBUG_PRINT("enter",("table: %s", table->real_name)); + DBUG_ENTER("wait_while_table_is_used"); + safe_mutex_assert_owner(&LOCK_open); -#if defined(USING_TRANSACTIONS) || defined( __WIN__) || defined( __EMX__) || !defined(OS2) - /* Wait until all there are no other threads that has this table open */ - while (remove_table_from_cache(thd,table->table_cache_key, - table->real_name)) - { - dropping_tables++; - (void) pthread_cond_wait(&COND_refresh,&LOCK_open); - dropping_tables--; - } -#else - (void) remove_table_from_cache(thd,table->table_cache_key, - table->real_name); -#endif - /* When lock on LOCK_open is freed other threads can continue */ - pthread_cond_broadcast(&COND_refresh); + VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Close all data files + /* Mark all tables that are in use as 'old' */ + mysql_lock_abort(thd, table); // end threads waiting on lock + + /* Wait until all there are no other threads that has this table open */ + while (remove_table_from_cache(thd,table->table_cache_key, + table->real_name)) + { + dropping_tables++; + (void) pthread_cond_wait(&COND_refresh,&LOCK_open); + dropping_tables--; } DBUG_VOID_RETURN; } +/* + Close a cached table + + SYNOPSIS + clsoe_cached_table() + thd Thread handler + table Table to remove from cache -bool close_cached_table(THD *thd,TABLE *table) + NOTES + Function ends by signaling threads waiting for the table to try to + reopen the table. + + PREREQUISITES + Lock on LOCK_open + Win32 clients must also have a WRITE LOCK on the table ! +*/ + +static bool close_cached_table(THD *thd, TABLE *table) { DBUG_ENTER("close_cached_table"); - safe_mutex_assert_owner(&LOCK_open); - - if (table) + + wait_while_table_is_used(thd,table); + /* Close lock if this is not got with LOCK TABLES */ + if (thd->lock) { - safe_remove_from_cache(thd,table); - /* Close lock if this is not got with LOCK TABLES */ - if (thd->lock) - { - mysql_unlock_tables(thd, thd->lock); - thd->lock=0; // Start locked threads - } - /* Close all copies of 'table'. This also frees all LOCK TABLES lock */ - thd->open_tables=unlink_open_table(thd,thd->open_tables,table); + mysql_unlock_tables(thd, thd->lock); + thd->lock=0; // Start locked threads } + /* Close all copies of 'table'. This also frees all LOCK TABLES lock */ + thd->open_tables=unlink_open_table(thd,thd->open_tables,table); + + /* When lock on LOCK_open is freed other threads can continue */ + pthread_cond_broadcast(&COND_refresh); DBUG_RETURN(0); } @@ -1094,10 +1112,13 @@ static int prepare_for_repair(THD* thd, TABLE_LIST *table_list, sprintf(tmp,"%s-%lx_%lx", from, current_pid, thd->thread_id); - pthread_mutex_lock(&LOCK_open); - close_cached_table(thd,table_list->table); - pthread_mutex_unlock(&LOCK_open); - + /* If we could open the table, close it */ + if (table_list->table) + { + pthread_mutex_lock(&LOCK_open); + close_cached_table(thd, table); + pthread_mutex_unlock(&LOCK_open); + } if (lock_and_wait_for_table_name(thd,table_list)) { error= -1; @@ -1494,11 +1515,10 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, else { *fn_ext(new_name)=0; - close_cached_table(thd,table); + close_cached_table(thd, table); if (mysql_rename_table(old_db_type,db,table_name,new_db,new_name)) error= -1; } - VOID(pthread_cond_broadcast(&COND_refresh)); VOID(pthread_mutex_unlock(&LOCK_open)); } if (!error) @@ -1507,12 +1527,18 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, case LEAVE_AS_IS: break; case ENABLE: - safe_remove_from_cache(thd,table); - error= table->file->activate_all_index(thd); + VOID(pthread_mutex_lock(&LOCK_open)); + wait_while_table_is_used(thd, table); + VOID(pthread_mutex_unlock(&LOCK_open)); + error= table->file->activate_all_index(thd); + /* COND_refresh will be signaled in close_thread_tables() */ break; case DISABLE: - safe_remove_from_cache(thd,table); + VOID(pthread_mutex_lock(&LOCK_open)); + wait_while_table_is_used(thd, table); + VOID(pthread_mutex_unlock(&LOCK_open)); table->file->deactivate_non_unique_index(HA_POS_ERROR); + /* COND_refresh will be signaled in close_thread_tables() */ break; } } @@ -1936,7 +1962,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, close the original table at before doing the rename */ table_name=thd->strdup(table_name); // must be saved - if (close_cached_table(thd,table)) + if (close_cached_table(thd, table)) { // Aborted VOID(quick_rm_table(new_db_type,new_db,tmp_name)); VOID(pthread_mutex_unlock(&LOCK_open)); @@ -1970,7 +1996,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, This shouldn't happen. We solve this the safe way by closing the locked table. */ - close_cached_table(thd,table); + if (table) + close_cached_table(thd,table); VOID(pthread_mutex_unlock(&LOCK_open)); goto err; } @@ -1980,7 +2007,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, Not table locking or alter table with rename free locks and remove old table */ - close_cached_table(thd,table); + if (table) + close_cached_table(thd,table); VOID(quick_rm_table(old_db_type,db,old_name)); } else @@ -2000,7 +2028,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, if (close_data_tables(thd,db,table_name) || reopen_tables(thd,1,0)) { // This shouldn't happen - close_cached_table(thd,table); // Remove lock for table + if (table) + close_cached_table(thd,table); // Remove lock for table VOID(pthread_mutex_unlock(&LOCK_open)); goto err; } -- cgit v1.2.1 From f6a365a53218c4ba8d3b6c03088090f5878115ff Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Sun, 1 Jun 2003 23:40:01 +0300 Subject: Small fixes (nothing nameworthy) --- include/my_global.h | 5 ++++- innobase/os/os0file.c | 37 ++++++++++++++++++++++++------------- mysql-test/r/err000001.result | 25 ------------------------- mysql-test/r/errors.result | 25 +++++++++++++++++++++++++ mysql-test/t/err000001.test | 19 ------------------- mysql-test/t/errors.test | 32 ++++++++++++++++++++++++++++++++ mysys/thr_alarm.c | 41 +++++++++++++++++++++++++++++++---------- sql/mysqld.cc | 14 ++++---------- 8 files changed, 120 insertions(+), 78 deletions(-) delete mode 100644 mysql-test/r/err000001.result create mode 100644 mysql-test/r/errors.result delete mode 100644 mysql-test/t/err000001.test create mode 100644 mysql-test/t/errors.test diff --git a/include/my_global.h b/include/my_global.h index d892d843edc..90c4801e807 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000-2003 MySQL AB 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 @@ -640,6 +640,9 @@ typedef long my_ptrdiff_t; typedef long long my_ptrdiff_t; #endif +/* typedef used for length of string; Should be unsigned! */ +typedef ulong size_str; + #define MY_ALIGN(A,L) (((A) + (L) - 1) & ~((L) - 1)) #define ALIGN_SIZE(A) MY_ALIGN((A),sizeof(double)) /* Size to make adressable obj. */ diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index 640ffec122f..00e29121ece 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -295,7 +295,8 @@ os_file_handle_error( /* out: TRUE if we should retry the operation */ os_file_t file, /* in: file pointer */ - char* name) /* in: name of a file or NULL */ + char* name, /* in: name of a file or NULL */ + const char* operation) /* in: type of operation */ { ulint err; @@ -337,7 +338,8 @@ os_file_handle_error( if (name) { fprintf(stderr, "InnoDB: File name %s\n", name); } - + fprintf(stderr, "InnoDB: system call %s\n", operation); + fprintf(stderr, "InnoDB: Cannot continue operation.\n"); fflush(stderr); @@ -419,7 +421,9 @@ try_again: if (file == INVALID_HANDLE_VALUE) { *success = FALSE; - retry = os_file_handle_error(file, name); + retry = os_file_handle_error(file, name, + create_mode == OS_FILE_OPEN ? + "open" : "create"); if (retry) { goto try_again; @@ -460,7 +464,10 @@ try_again: if (file == -1) { *success = FALSE; - retry = os_file_handle_error(file, name); + retry = os_file_handle_error(file, name, + create_mode == OS_FILE_OPEN ? + "open" : "create"); + if (retry) { goto try_again; @@ -568,7 +575,9 @@ try_again: if (file == INVALID_HANDLE_VALUE) { *success = FALSE; - retry = os_file_handle_error(file, name); + retry = os_file_handle_error(file, name, + create_mode == OS_FILE_OPEN ? + "open" : "create"); if (retry) { goto try_again; @@ -615,7 +624,9 @@ try_again: if (file == -1) { *success = FALSE; - retry = os_file_handle_error(file, name); + retry = os_file_handle_error(file, name, + create_mode == OS_FILE_OPEN ? + "open" : "create"); if (retry) { goto try_again; @@ -649,7 +660,7 @@ os_file_close( return(TRUE); } - os_file_handle_error(file, NULL); + os_file_handle_error(file, NULL, "close"); return(FALSE); #else int ret; @@ -657,7 +668,7 @@ os_file_close( ret = close(file); if (ret == -1) { - os_file_handle_error(file, NULL); + os_file_handle_error(file, NULL, "close"); return(FALSE); } @@ -825,7 +836,7 @@ os_file_flush( return(TRUE); } - os_file_handle_error(file, NULL); + os_file_handle_error(file, NULL, "flush"); /* It is a fatal error if a file flush does not succeed, because then the database can get corrupt on disk */ @@ -858,7 +869,7 @@ os_file_flush( fprintf(stderr, " InnoDB: Error: the OS said file flush did not succeed\n"); - os_file_handle_error(file, NULL); + os_file_handle_error(file, NULL, "flush"); /* It is a fatal error if a file flush does not succeed, because then the database can get corrupt on disk */ @@ -1099,7 +1110,7 @@ try_again: #ifdef __WIN__ error_handling: #endif - retry = os_file_handle_error(file, NULL); + retry = os_file_handle_error(file, NULL, "read"); if (retry) { goto try_again; @@ -2014,7 +2025,7 @@ try_again: os_aio_array_free_slot(array, slot); - retry = os_file_handle_error(file, name); + retry = os_file_handle_error(file, name, "aio"); if (retry) { @@ -2113,7 +2124,7 @@ os_aio_windows_handle( ut_a(TRUE == os_file_flush(slot->file)); } } else { - os_file_handle_error(slot->file, slot->name); + os_file_handle_error(slot->file, slot->name, "aio"); ret_val = FALSE; } diff --git a/mysql-test/r/err000001.result b/mysql-test/r/err000001.result deleted file mode 100644 index 5afecc6d600..00000000000 --- a/mysql-test/r/err000001.result +++ /dev/null @@ -1,25 +0,0 @@ -drop table if exists t1; -insert into t1 values(1); -Table 'test.t1' doesn't exist -delete from t1; -Table 'test.t1' doesn't exist -update t1 set a=1; -Table 'test.t1' doesn't exist -create table t1 (a int); -select count(test.t1.b) from t1; -Unknown column 'test.t1.b' in 'field list' -select count(not_existing_database.t1) from t1; -Unknown table 'not_existing_database' in field list -select count(not_existing_database.t1.a) from t1; -Unknown table 'not_existing_database.t1' in field list -select count(not_existing_database.t1.a) from not_existing_database.t1; -Got one of the listed errors -select 1 from t1 order by 2; -Unknown column '2' in 'order clause' -select 1 from t1 group by 2; -Unknown column '2' in 'group statement' -select 1 from t1 order by t1.b; -Unknown column 't1.b' in 'order clause' -select count(*),b from t1; -Unknown column 'b' in 'field list' -drop table t1; diff --git a/mysql-test/r/errors.result b/mysql-test/r/errors.result new file mode 100644 index 00000000000..5afecc6d600 --- /dev/null +++ b/mysql-test/r/errors.result @@ -0,0 +1,25 @@ +drop table if exists t1; +insert into t1 values(1); +Table 'test.t1' doesn't exist +delete from t1; +Table 'test.t1' doesn't exist +update t1 set a=1; +Table 'test.t1' doesn't exist +create table t1 (a int); +select count(test.t1.b) from t1; +Unknown column 'test.t1.b' in 'field list' +select count(not_existing_database.t1) from t1; +Unknown table 'not_existing_database' in field list +select count(not_existing_database.t1.a) from t1; +Unknown table 'not_existing_database.t1' in field list +select count(not_existing_database.t1.a) from not_existing_database.t1; +Got one of the listed errors +select 1 from t1 order by 2; +Unknown column '2' in 'order clause' +select 1 from t1 group by 2; +Unknown column '2' in 'group statement' +select 1 from t1 order by t1.b; +Unknown column 't1.b' in 'order clause' +select count(*),b from t1; +Unknown column 'b' in 'field list' +drop table t1; diff --git a/mysql-test/t/err000001.test b/mysql-test/t/err000001.test deleted file mode 100644 index d9898054a83..00000000000 --- a/mysql-test/t/err000001.test +++ /dev/null @@ -1,19 +0,0 @@ -# -# Test some error conditions -# - -drop table if exists t1; -!$1146 insert into t1 values(1); -!$1146 delete from t1; -!$1146 update t1 set a=1; -create table t1 (a int); -!$1054 select count(test.t1.b) from t1; -!$1109 select count(not_existing_database.t1) from t1; -!$1109 select count(not_existing_database.t1.a) from t1; ---error 1044,1146 -select count(not_existing_database.t1.a) from not_existing_database.t1; -!$1054 select 1 from t1 order by 2; -!$1054 select 1 from t1 group by 2; -!$1054 select 1 from t1 order by t1.b; -!$1054 select count(*),b from t1; -drop table t1; diff --git a/mysql-test/t/errors.test b/mysql-test/t/errors.test new file mode 100644 index 00000000000..afb0cce9005 --- /dev/null +++ b/mysql-test/t/errors.test @@ -0,0 +1,32 @@ +# +# Test some error conditions +# + +drop table if exists t1; +--error 1146 +insert into t1 values(1); +--error 1146 +delete from t1; +--error 1146 +update t1 set a=1; + +# + +create table t1 (a int); +--error 1054 +select count(test.t1.b) from t1; +--error 1109 +select count(not_existing_database.t1) from t1; +--error 1109 + select count(not_existing_database.t1.a) from t1; +--error 1044,1146 +select count(not_existing_database.t1.a) from not_existing_database.t1; +--error 1054 +select 1 from t1 order by 2; +--error 1054 +select 1 from t1 group by 2; +--error 1054 +select 1 from t1 order by t1.b; +--error 1054 +select count(*),b from t1; +drop table t1; diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c index ca8e4e8bcb6..a2647ec7399 100644 --- a/mysys/thr_alarm.c +++ b/mysys/thr_alarm.c @@ -38,20 +38,21 @@ #endif static int alarm_aborted=1; /* No alarm thread */ -my_bool thr_alarm_inited=0; +my_bool thr_alarm_inited= 0; +volatile my_bool alarm_thread_running= 0; static sig_handler process_alarm_part2(int sig); #if !defined(__WIN__) && !defined(__EMX__) && !defined(OS2) static pthread_mutex_t LOCK_alarm; +static pthread_cond_t COND_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 -static pthread_cond_t COND_alarm; static void *alarm_handler(void *arg); #define reschedule_alarms() pthread_cond_signal(&COND_alarm) #else @@ -78,6 +79,7 @@ void init_thr_alarm(uint max_alarms) compare_ulong,NullS); sigfillset(&full_signal_set); /* Neaded to block signals */ pthread_mutex_init(&LOCK_alarm,MY_MUTEX_INIT_FAST); + pthread_cond_init(&COND_alarm,NULL); #if THR_CLIENT_ALARM != SIGALRM || defined(USE_ALARM_THREAD) #if defined(HAVE_mit_thread) sigset(THR_CLIENT_ALARM,thread_alarm); /* int. thread system calls */ @@ -97,7 +99,6 @@ void init_thr_alarm(uint max_alarms) { pthread_attr_t thr_attr; pthread_attr_init(&thr_attr); - pthread_cond_init(&COND_alarm,NULL); pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS); pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED); pthread_attr_setstacksize(&thr_attr,8196); @@ -383,28 +384,45 @@ static sig_handler process_alarm_part2(int sig __attribute__((unused))) void end_thr_alarm(my_bool free_structures) { DBUG_ENTER("end_thr_alarm"); - if (alarm_aborted != 1) + if (alarm_aborted != 1) /* If memory not freed */ { pthread_mutex_lock(&LOCK_alarm); DBUG_PRINT("info",("Resheduling %d waiting alarms",alarm_queue.elements)); alarm_aborted= -1; /* mark aborted */ - if (pthread_equal(pthread_self(),alarm_thread)) - alarm(1); /* Shut down everything soon */ - else - reschedule_alarms(); + if (alarm_queue.elements || (alarm_thread_running && free_structures)) + { + if (pthread_equal(pthread_self(),alarm_thread)) + alarm(1); /* Shut down everything soon */ + else + reschedule_alarms(); + } if (free_structures) { + struct timespec abstime; /* The following test is just for safety, the caller should not depend on this */ DBUG_ASSERT(!alarm_queue.elements); + /* Wait until alarm thread dies */ + + set_timespec(abstime, 10); /* Wait up to 10 seconds */ + while (alarm_thread_running) + { + int error= pthread_cond_timedwait(&COND_alarm, &LOCK_alarm, &abstime); + if (error == ETIME || error == ETIMEDOUT) + break; /* Don't wait forever */ + } if (!alarm_queue.elements) { delete_queue(&alarm_queue); alarm_aborted= 1; pthread_mutex_unlock(&LOCK_alarm); - pthread_mutex_destroy(&LOCK_alarm); + if (!alarm_thread_running) /* Safety */ + { + pthread_mutex_destroy(&LOCK_alarm); + pthread_cond_destroy(&COND_alarm); + } } } else @@ -490,6 +508,7 @@ static void *alarm_handler(void *arg __attribute__((unused))) puts("Starting alarm thread"); #endif my_thread_init(); + alarm_thread_running= 1; pthread_mutex_lock(&LOCK_alarm); for (;;) { @@ -514,7 +533,7 @@ static void *alarm_handler(void *arg __attribute__((unused))) } } } - else if (alarm_aborted) + else if (alarm_aborted == -1) break; else if ((error=pthread_cond_wait(&COND_alarm,&LOCK_alarm))) { @@ -526,6 +545,8 @@ static void *alarm_handler(void *arg __attribute__((unused))) process_alarm(0); } bzero((char*) &alarm_thread,sizeof(alarm_thread)); /* For easy debugging */ + alarm_thread_running= 0; + pthread_cond_signal(&COND_alarm); pthread_mutex_unlock(&LOCK_alarm); pthread_exit(0); return 0; /* Impossible */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index c2ee940af49..1492d6ddb68 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1520,7 +1520,6 @@ the problem, but since we have already crashed, something is definitely wrong\n\ and this may fail.\n\n"); fprintf(stderr, "key_buffer_size=%lu\n", (ulong) keybuff_size); fprintf(stderr, "read_buffer_size=%ld\n", global_system_variables.read_buff_size); - fprintf(stderr, "sort_buffer_size=%ld\n", thd->variables.sortbuff_size); fprintf(stderr, "max_used_connections=%ld\n", max_used_connections); fprintf(stderr, "max_connections=%ld\n", max_connections); fprintf(stderr, "threads_connected=%d\n", thread_count); @@ -1528,7 +1527,7 @@ and this may fail.\n\n"); key_buffer_size + (read_buffer_size + sort_buffer_size)*max_connections = %ld K\n\ bytes of memory\n", ((ulong) keybuff_size + (global_system_variables.read_buff_size + - thd->variables.sortbuff_size) * + global_system_variables.sortbuff_size) * max_connections)/ 1024); fprintf(stderr, "Hope that's ok; if not, decrease some variables in the equation.\n\n"); @@ -1557,14 +1556,9 @@ the thread stack. Please read http://www.mysql.com/doc/L/i/Linux.html\n\n", Some pointers may be invalid and cause the dump to abort...\n"); safe_print_str("thd->query", thd->query, 1024); fprintf(stderr, "thd->thread_id=%ld\n", thd->thread_id); - fprintf(stderr, "\n\ -Successfully dumped variables, if you ran with --log, take a look at the\n\ -details of what thread %ld did to cause the crash. In some cases of really\n\ -bad corruption, the values shown above may be invalid.\n\n", - thd->thread_id); } fprintf(stderr, "\ -The manual page at http://www.mysql.com/doc/C/r/Crashing.html contains\n\ +The manual page at http://www.mysql.com/doc/en/Crashing.html contains\n\ information that should help you find out what is causing the crash.\n"); fflush(stderr); #endif /* HAVE_STACKTRACE */ @@ -1639,6 +1633,7 @@ static void init_signals(void) sigaddset(&set,SIGHUP); /* Fix signals if blocked by parents (can happen on Mac OS X) */ + sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = print_signal_warning; sigaction(SIGTERM, &sa, (struct sigaction*) 0); @@ -2279,7 +2274,7 @@ int main(int argc, char **argv) #endif /* init_slave() must be called after the thread keys are created */ init_slave(); - + DBUG_ASSERT(current_thd == 0); if (opt_bin_log && !server_id) { @@ -2307,7 +2302,6 @@ The server will not act as a slave."); using_update_log=1; } - if (opt_bootstrap) { int error=bootstrap(stdin); -- cgit v1.2.1 From e8e98d05f998aeba8adc311ee6ae58ec70d7617a Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Mon, 2 Jun 2003 13:11:20 +0300 Subject: os0thread.h, os0sync.ic, os0sync.h, os0thread.c, os0sync.c, os0file.c: Release all event semaphores at shutdown also in Windows srv0start.c, srv0srv.c: make test sometimes failed because lock timeout thread exited without decrementing the InnoDB thread counter --- innobase/include/os0sync.h | 51 +++++++----- innobase/include/os0sync.ic | 1 - innobase/include/os0thread.h | 4 +- innobase/os/os0file.c | 83 ++++++++++--------- innobase/os/os0sync.c | 184 ++++++++++++++++++++----------------------- innobase/os/os0thread.c | 4 + innobase/srv/srv0srv.c | 44 ++++++++++- innobase/srv/srv0start.c | 32 ++++++-- 8 files changed, 234 insertions(+), 169 deletions(-) diff --git a/innobase/include/os0sync.h b/innobase/include/os0sync.h index bad8e6e120a..634507467f9 100644 --- a/innobase/include/os0sync.h +++ b/innobase/include/os0sync.h @@ -13,13 +13,26 @@ Created 9/6/1995 Heikki Tuuri #include "ut0lst.h" #ifdef __WIN__ + #define os_fast_mutex_t CRITICAL_SECTION -typedef HANDLE os_event_t; + +typedef HANDLE os_native_event_t; + +typedef struct os_event_struct os_event_struct_t; +typedef os_event_struct_t* os_event_t; + +struct os_event_struct { + os_native_event_t handle; + /* Windows event */ + UT_LIST_NODE_T(os_event_struct_t) os_event_list; + /* list of all created events */ +}; #else typedef pthread_mutex_t os_fast_mutex_t; typedef struct os_event_struct os_event_struct_t; typedef os_event_struct_t* os_event_t; + struct os_event_struct { os_fast_mutex_t os_mutex; /* this mutex protects the next fields */ @@ -39,16 +52,16 @@ typedef os_mutex_str_t* os_mutex_t; #define OS_SYNC_TIME_EXCEEDED 1 -/* Mutex protecting the thread count and event and OS 'slow' mutex lists */ +/* Mutex protecting counts and the event and OS 'slow' mutex lists */ extern os_mutex_t os_sync_mutex; /* This is incremented by 1 in os_thread_create and decremented by 1 in os_thread_exit */ extern ulint os_thread_count; -/* The following are approximate counters for debugging in Unix */ extern ulint os_event_count; extern ulint os_mutex_count; +extern ulint os_fast_mutex_count; /************************************************************* Initializes global event and OS 'slow' mutex lists. */ @@ -57,15 +70,14 @@ void os_sync_init(void); /*==============*/ /************************************************************* -Frees created events (not in Windows) and OS 'slow' mutexes. */ +Frees created events and OS 'slow' mutexes. */ void os_sync_free(void); /*==============*/ -/************************************************************* -Creates an event semaphore, i.e., a semaphore which may -just have two states: signaled and nonsignaled. -The created event is manual reset: it must be reset +/************************************************************* +Creates an event semaphore, i.e., a semaphore which may just have two states: +signaled and nonsignaled. The created event is manual reset: it must be reset explicitly by calling sync_os_reset_event. */ os_event_t @@ -74,10 +86,10 @@ os_event_create( /* out: the event handle */ char* name); /* in: the name of the event, if NULL the event is created without a name */ +#ifdef __WIN__ /************************************************************* -Creates an auto-reset event semaphore, i.e., an event -which is automatically reset when a single thread is -released. */ +Creates an auto-reset event semaphore, i.e., an event which is automatically +reset when a single thread is released. Works only in Windows. */ os_event_t os_event_create_auto( @@ -85,6 +97,7 @@ os_event_create_auto( /* out: the event handle */ char* name); /* in: the name of the event, if NULL the event is created without a name */ +#endif /************************************************************** Sets an event semaphore to the signaled state: lets waiting threads proceed. */ @@ -120,7 +133,7 @@ os_event_wait( os_event_t event); /* in: event to wait */ /************************************************************** Waits for an event object until it is in the signaled state or -a timeout is exceeded. */ +a timeout is exceeded. In Unix the timeout is always infinite. */ ulint os_event_wait_time( @@ -131,8 +144,9 @@ os_event_wait_time( os_event_t event, /* in: event to wait */ ulint time); /* in: timeout in microseconds, or OS_SYNC_INFINITE_TIME */ +#ifdef __WIN__ /************************************************************** -Waits for any event in an event array. Returns if even a single +Waits for any event in an OS native event array. Returns if even a single one is signaled or becomes signaled. */ ulint @@ -140,14 +154,15 @@ os_event_wait_multiple( /*===================*/ /* out: index of the event which was signaled */ - ulint n, /* in: number of events in the + ulint n, /* in: number of events in the array */ - os_event_t* event_array); /* in: pointer to an array of event + os_native_event_t* native_event_array); + /* in: pointer to an array of event handles */ +#endif /************************************************************* -Creates an operating system mutex semaphore. -Because these are slow, the mutex semaphore of the database -itself (sync_mutex_t) should be used where possible. */ +Creates an operating system mutex semaphore. Because these are slow, the +mutex semaphore of InnoDB itself (mutex_t) should be used where possible. */ os_mutex_t os_mutex_create( diff --git a/innobase/include/os0sync.ic b/innobase/include/os0sync.ic index 10b85c435e3..1337e97152a 100644 --- a/innobase/include/os0sync.ic +++ b/innobase/include/os0sync.ic @@ -44,4 +44,3 @@ os_fast_mutex_trylock( #endif #endif } - diff --git a/innobase/include/os0thread.h b/innobase/include/os0thread.h index 92187f315c2..491d8866af4 100644 --- a/innobase/include/os0thread.h +++ b/innobase/include/os0thread.h @@ -65,7 +65,9 @@ os_thread_pf( /******************************************************************** Creates a new thread of execution. The execution starts from the function given. The start function takes a void* parameter -and returns a ulint. */ +and returns a ulint. +NOTE: We count the number of threads in os_thread_exit(). A created +thread should always use that to exit and not use return() to exit. */ os_thread_t os_thread_create( diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index 00e29121ece..eaea6688462 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -80,6 +80,8 @@ struct os_aio_slot_struct{ which pending aio operation was completed */ #ifdef WIN_ASYNC_IO + os_event_t event; /* event object we need in the + OVERLAPPED struct */ OVERLAPPED control; /* Windows control block for the aio request */ #elif defined(POSIX_ASYNC_IO) @@ -107,11 +109,14 @@ struct os_aio_array_struct{ ulint n_reserved;/* Number of reserved slots in the aio array outside the ibuf segment */ os_aio_slot_t* slots; /* Pointer to the slots in the array */ - os_event_t* events; /* Pointer to an array of event handles - where we copied the handles from slots, - in the same order. This can be used in - WaitForMultipleObjects; used only in +#ifdef __WIN__ + os_native_event_t* native_events; + /* Pointer to an array of OS native event + handles where we copied the handles from + slots, in the same order. This can be used + in WaitForMultipleObjects; used only in Windows */ +#endif }; /* Array of events used in simulated aio */ @@ -295,8 +300,7 @@ os_file_handle_error( /* out: TRUE if we should retry the operation */ os_file_t file, /* in: file pointer */ - char* name, /* in: name of a file or NULL */ - const char* operation) /* in: type of operation */ + char* name) /* in: name of a file or NULL */ { ulint err; @@ -338,8 +342,7 @@ os_file_handle_error( if (name) { fprintf(stderr, "InnoDB: File name %s\n", name); } - fprintf(stderr, "InnoDB: system call %s\n", operation); - + fprintf(stderr, "InnoDB: Cannot continue operation.\n"); fflush(stderr); @@ -421,9 +424,7 @@ try_again: if (file == INVALID_HANDLE_VALUE) { *success = FALSE; - retry = os_file_handle_error(file, name, - create_mode == OS_FILE_OPEN ? - "open" : "create"); + retry = os_file_handle_error(file, name); if (retry) { goto try_again; @@ -464,10 +465,7 @@ try_again: if (file == -1) { *success = FALSE; - retry = os_file_handle_error(file, name, - create_mode == OS_FILE_OPEN ? - "open" : "create"); - + retry = os_file_handle_error(file, name); if (retry) { goto try_again; @@ -575,9 +573,7 @@ try_again: if (file == INVALID_HANDLE_VALUE) { *success = FALSE; - retry = os_file_handle_error(file, name, - create_mode == OS_FILE_OPEN ? - "open" : "create"); + retry = os_file_handle_error(file, name); if (retry) { goto try_again; @@ -624,9 +620,7 @@ try_again: if (file == -1) { *success = FALSE; - retry = os_file_handle_error(file, name, - create_mode == OS_FILE_OPEN ? - "open" : "create"); + retry = os_file_handle_error(file, name); if (retry) { goto try_again; @@ -660,7 +654,7 @@ os_file_close( return(TRUE); } - os_file_handle_error(file, NULL, "close"); + os_file_handle_error(file, NULL); return(FALSE); #else int ret; @@ -668,7 +662,7 @@ os_file_close( ret = close(file); if (ret == -1) { - os_file_handle_error(file, NULL, "close"); + os_file_handle_error(file, NULL); return(FALSE); } @@ -836,7 +830,7 @@ os_file_flush( return(TRUE); } - os_file_handle_error(file, NULL, "flush"); + os_file_handle_error(file, NULL); /* It is a fatal error if a file flush does not succeed, because then the database can get corrupt on disk */ @@ -869,7 +863,7 @@ os_file_flush( fprintf(stderr, " InnoDB: Error: the OS said file flush did not succeed\n"); - os_file_handle_error(file, NULL, "flush"); + os_file_handle_error(file, NULL); /* It is a fatal error if a file flush does not succeed, because then the database can get corrupt on disk */ @@ -1110,7 +1104,7 @@ try_again: #ifdef __WIN__ error_handling: #endif - retry = os_file_handle_error(file, NULL, "read"); + retry = os_file_handle_error(file, NULL); if (retry) { goto try_again; @@ -1319,19 +1313,22 @@ os_aio_array_create( array->n_segments = n_segments; array->n_reserved = 0; array->slots = ut_malloc(n * sizeof(os_aio_slot_t)); - array->events = ut_malloc(n * sizeof(os_event_t)); - +#ifdef __WIN__ + array->native_events = ut_malloc(n * sizeof(os_native_event_t)); +#endif for (i = 0; i < n; i++) { slot = os_aio_array_get_nth_slot(array, i); slot->pos = i; slot->reserved = FALSE; #ifdef WIN_ASYNC_IO + slot->event = os_event_create(NULL); + over = &(slot->control); - over->hEvent = os_event_create(NULL); + over->hEvent = slot->event->handle; - *((array->events) + i) = over->hEvent; + *((array->native_events) + i) = over->hEvent; #endif } @@ -1429,7 +1426,7 @@ os_aio_array_wake_win_aio_at_shutdown( for (i = 0; i < array->n_slots; i++) { - os_event_set(*(array->events + i)); + os_event_set((array->slots + i)->event); } } #endif @@ -1689,7 +1686,7 @@ loop: control = &(slot->control); control->Offset = (DWORD)offset; control->OffsetHigh = (DWORD)offset_high; - os_event_reset(control->hEvent); + os_event_reset(slot->event); #elif defined(POSIX_ASYNC_IO) @@ -1747,7 +1744,7 @@ os_aio_array_free_slot( } #ifdef WIN_ASYNC_IO - os_event_reset(slot->control.hEvent); + os_event_reset(slot->event); #endif os_mutex_exit(array->mutex); } @@ -1916,7 +1913,8 @@ os_aio( wait in the Windows case. */ if (type == OS_FILE_READ) { - return(os_file_read(file, buf, offset, offset_high, n)); + return(os_file_read(file, buf, offset, + offset_high, n)); } ut_a(type == OS_FILE_WRITE); @@ -1994,8 +1992,7 @@ try_again: #ifdef WIN_ASYNC_IO if (os_aio_use_native_aio) { if ((ret && len == n) - || (!ret && GetLastError() == ERROR_IO_PENDING)) { - + || (!ret && GetLastError() == ERROR_IO_PENDING)) { /* aio was queued successfully! */ if (mode == OS_AIO_SYNC) { @@ -2025,7 +2022,7 @@ try_again: os_aio_array_free_slot(array, slot); - retry = os_file_handle_error(file, name, "aio"); + retry = os_file_handle_error(file, name); if (retry) { @@ -2091,15 +2088,15 @@ os_aio_windows_handle( n = array->n_slots / array->n_segments; if (array == os_aio_sync_array) { - srv_io_thread_op_info[orig_seg] = "wait Windows aio for 1 page"; - - ut_ad(pos < array->n_slots); - os_event_wait(array->events[pos]); + srv_io_thread_op_info[orig_seg] = + "wait Windows aio for 1 page"; + os_event_wait(os_aio_array_get_nth_slot(array, pos)->event); i = pos; } else { srv_io_thread_op_info[orig_seg] = "wait Windows aio"; - i = os_event_wait_multiple(n, (array->events) + segment * n); + i = os_event_wait_multiple(n, + (array->native_events) + segment * n); } os_mutex_enter(array->mutex); @@ -2124,7 +2121,7 @@ os_aio_windows_handle( ut_a(TRUE == os_file_flush(slot->file)); } } else { - os_file_handle_error(slot->file, slot->name, "aio"); + os_file_handle_error(slot->file, slot->name); ret_val = FALSE; } diff --git a/innobase/os/os0sync.c b/innobase/os/os0sync.c index 4f322ee82b2..0fe61fe570d 100644 --- a/innobase/os/os0sync.c +++ b/innobase/os/os0sync.c @@ -32,24 +32,23 @@ struct os_mutex_struct{ /* list of all 'slow' OS mutexes created */ }; -/* Mutex protecting the thread count and the lists of OS mutexes -and events */ +/* Mutex protecting counts and the lists of OS mutexes and events */ os_mutex_t os_sync_mutex; ibool os_sync_mutex_inited = FALSE; /* This is incremented by 1 in os_thread_create and decremented by 1 in os_thread_exit */ -ulint os_thread_count = 0; +ulint os_thread_count = 0; -/* The list of all events created (not in Windows) */ +/* The list of all events created */ UT_LIST_BASE_NODE_T(os_event_struct_t) os_event_list; /* The list of all OS 'slow' mutexes */ UT_LIST_BASE_NODE_T(os_mutex_str_t) os_mutex_list; -/* The following are approximate counters for debugging in Unix */ -ulint os_event_count = 0; -ulint os_mutex_count = 0; +ulint os_event_count = 0; +ulint os_mutex_count = 0; +ulint os_fast_mutex_count = 0; /************************************************************* @@ -68,7 +67,7 @@ os_sync_init(void) } /************************************************************* -Frees created events (not in Windows) and OS 'slow' mutexes. */ +Frees created events and OS 'slow' mutexes. */ void os_sync_free(void) @@ -97,10 +96,9 @@ os_sync_free(void) } /************************************************************* -Creates an event semaphore, i.e., a semaphore which may -just have two states: signaled and nonsignaled. -The created event is manual reset: it must be reset -explicitly by calling sync_os_reset_event. */ +Creates an event semaphore, i.e., a semaphore which may just have two +states: signaled and nonsignaled. The created event is manual reset: it +must be reset explicitly by calling sync_os_reset_event. */ os_event_t os_event_create( @@ -112,20 +110,18 @@ os_event_create( #ifdef __WIN__ os_event_t event; - event = CreateEvent(NULL, /* No security attributes */ + event = ut_malloc(sizeof(struct os_event_struct)); + + event->handle = CreateEvent(NULL,/* No security attributes */ TRUE, /* Manual reset */ FALSE, /* Initial state nonsignaled */ name); - if (!event) { + if (!event->handle) { fprintf(stderr, "InnoDB: Could not create a Windows event semaphore; Windows error %lu\n", (ulint)GetLastError()); } - - ut_a(event); - - return(event); -#else +#else /* Unix */ os_event_t event; UT_NOT_USED(name); @@ -141,7 +137,9 @@ os_event_create( ut_a(0 == pthread_cond_init(&(event->cond_var), NULL)); #endif event->is_set = FALSE; +#endif /* __WIN__ */ + /* Put to the list of events */ os_mutex_enter(os_sync_mutex); UT_LIST_ADD_FIRST(os_event_list, os_event_list, event); @@ -151,13 +149,12 @@ os_event_create( os_mutex_exit(os_sync_mutex); return(event); -#endif } +#ifdef __WIN__ /************************************************************* -Creates an auto-reset event semaphore, i.e., an event -which is automatically reset when a single thread is -released. */ +Creates an auto-reset event semaphore, i.e., an event which is automatically +reset when a single thread is released. Works only in Windows. */ os_event_t os_event_create_auto( @@ -166,26 +163,33 @@ os_event_create_auto( char* name) /* in: the name of the event, if NULL the event is created without a name */ { -#ifdef __WIN__ os_event_t event; - event = CreateEvent(NULL, /* No security attributes */ + event = ut_malloc(sizeof(struct os_event_struct)); + + event->handle = CreateEvent(NULL,/* No security attributes */ FALSE, /* Auto-reset */ FALSE, /* Initial state nonsignaled */ name); - ut_a(event); - return(event); -#else - /* Does nothing in Posix because we do not need this with MySQL */ + if (!event->handle) { + fprintf(stderr, +"InnoDB: Could not create a Windows auto event semaphore; Windows error %lu\n", + (ulint)GetLastError()); + } - UT_NOT_USED(name); + /* Put to the list of events */ + os_mutex_enter(os_sync_mutex); + + UT_LIST_ADD_FIRST(os_event_list, os_event_list, event); - ut_a(0); + os_event_count++; - return(NULL); -#endif + os_mutex_exit(os_sync_mutex); + + return(event); } +#endif /************************************************************** Sets an event semaphore to the signaled state: lets waiting threads @@ -198,7 +202,7 @@ os_event_set( { #ifdef __WIN__ ut_a(event); - ut_a(SetEvent(event)); + ut_a(SetEvent(event->handle)); #else ut_a(event); @@ -227,7 +231,7 @@ os_event_reset( #ifdef __WIN__ ut_a(event); - ut_a(ResetEvent(event)); + ut_a(ResetEvent(event->handle)); #else ut_a(event); @@ -255,12 +259,14 @@ os_event_free( #ifdef __WIN__ ut_a(event); - ut_a(CloseHandle(event)); + ut_a(CloseHandle(event->handle)); #else ut_a(event); os_fast_mutex_free(&(event->os_mutex)); ut_a(0 == pthread_cond_destroy(&(event->cond_var))); +#endif + /* Remove from the list of events */ os_mutex_enter(os_sync_mutex); @@ -271,7 +277,6 @@ os_event_free( os_mutex_exit(os_sync_mutex); ut_free(event); -#endif } /************************************************************** @@ -291,7 +296,7 @@ os_event_wait( ut_a(event); /* Specify an infinite time limit for waiting */ - err = WaitForSingleObject(event, INFINITE); + err = WaitForSingleObject(event->handle, INFINITE); ut_a(err == WAIT_OBJECT_0); @@ -324,7 +329,7 @@ loop: /************************************************************** Waits for an event object until it is in the signaled state or -a timeout is exceeded. */ +a timeout is exceeded. In Unix the timeout is always infinite. */ ulint os_event_wait_time( @@ -341,9 +346,9 @@ os_event_wait_time( ut_a(event); if (time != OS_SYNC_INFINITE_TIME) { - err = WaitForSingleObject(event, time / 1000); + err = WaitForSingleObject(event->handle, time / 1000); } else { - err = WaitForSingleObject(event, INFINITE); + err = WaitForSingleObject(event->handle, INFINITE); } if (err == WAIT_OBJECT_0) { @@ -367,8 +372,9 @@ os_event_wait_time( #endif } +#ifdef __WIN__ /************************************************************** -Waits for any event in an event array. Returns if even a single +Waits for any event in an OS native event array. Returns if even a single one is signaled or becomes signaled. */ ulint @@ -376,18 +382,18 @@ os_event_wait_multiple( /*===================*/ /* out: index of the event which was signaled */ - ulint n, /* in: number of events in the + ulint n, /* in: number of events in the array */ - os_event_t* event_array) /* in: pointer to an array of event + os_native_event_t* native_event_array) + /* in: pointer to an array of event handles */ { -#ifdef __WIN__ DWORD index; - ut_a(event_array); + ut_a(native_event_array); ut_a(n > 0); - index = WaitForMultipleObjects(n, event_array, + index = WaitForMultipleObjects(n, native_event_array, FALSE, /* Wait for any 1 event */ INFINITE); /* Infinite wait time limit */ @@ -399,21 +405,12 @@ os_event_wait_multiple( } return(index - WAIT_OBJECT_0); -#else - ut_a(n == 0); - - /* In Posix we can only wait for a single event */ - - os_event_wait(*event_array); - - return(0); -#endif } +#endif /************************************************************* -Creates an operating system mutex semaphore. -Because these are slow, the mutex semaphore of the database -itself (sync_mutex_t) should be used where possible. */ +Creates an operating system mutex semaphore. Because these are slow, the +mutex semaphore of InnoDB itself (mutex_t) should be used where possible. */ os_mutex_t os_mutex_create( @@ -430,50 +427,35 @@ os_mutex_create( FALSE, /* Initial state: no owner */ name); ut_a(mutex); - - mutex_str = ut_malloc(sizeof(os_mutex_str_t)); - - mutex_str->handle = mutex; - mutex_str->count = 0; - - if (os_sync_mutex_inited) { - os_mutex_enter(os_sync_mutex); - } - - UT_LIST_ADD_FIRST(os_mutex_list, os_mutex_list, mutex_str); - - if (os_sync_mutex_inited) { - os_mutex_exit(os_sync_mutex); - } - - return(mutex_str); #else - os_fast_mutex_t* os_mutex; + os_fast_mutex_t* mutex; os_mutex_t mutex_str; UT_NOT_USED(name); - os_mutex = ut_malloc(sizeof(os_fast_mutex_t)); - - os_fast_mutex_init(os_mutex); + mutex = ut_malloc(sizeof(os_fast_mutex_t)); + os_fast_mutex_init(mutex); +#endif mutex_str = ut_malloc(sizeof(os_mutex_str_t)); - mutex_str->handle = os_mutex; + mutex_str->handle = mutex; mutex_str->count = 0; if (os_sync_mutex_inited) { + /* When creating os_sync_mutex itself we cannot reserve it */ os_mutex_enter(os_sync_mutex); } UT_LIST_ADD_FIRST(os_mutex_list, os_mutex_list, mutex_str); + os_mutex_count++; + if (os_sync_mutex_inited) { os_mutex_exit(os_sync_mutex); } return(mutex_str); -#endif } /************************************************************** @@ -513,21 +495,14 @@ os_mutex_exit( /*==========*/ os_mutex_t mutex) /* in: mutex to release */ { -#ifdef __WIN__ ut_a(mutex); ut_a(mutex->count == 1); (mutex->count)--; - +#ifdef __WIN__ ut_a(ReleaseMutex(mutex->handle)); #else - ut_a(mutex); - - ut_a(mutex->count == 1); - - (mutex->count)--; - os_fast_mutex_unlock(mutex->handle); #endif } @@ -540,25 +515,21 @@ os_mutex_free( /*==========*/ os_mutex_t mutex) /* in: mutex to free */ { -#ifdef __WIN__ ut_a(mutex); os_mutex_enter(os_sync_mutex); UT_LIST_REMOVE(os_mutex_list, os_mutex_list, mutex); + + os_mutex_count--; os_mutex_exit(os_sync_mutex); +#ifdef __WIN__ ut_a(CloseHandle(mutex->handle)); ut_free(mutex); #else - os_mutex_enter(os_sync_mutex); - - UT_LIST_REMOVE(os_mutex_list, os_mutex_list, mutex); - - os_mutex_exit(os_sync_mutex); - os_fast_mutex_free(mutex->handle); ut_free(mutex->handle); ut_free(mutex); @@ -583,8 +554,19 @@ os_fast_mutex_init( #else ut_a(0 == pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST)); #endif - os_mutex_count++; #endif + if (os_sync_mutex_inited) { + /* When creating os_sync_mutex itself (in Unix) we cannot + reserve it */ + + os_mutex_enter(os_sync_mutex); + } + + os_fast_mutex_count++; + + if (os_sync_mutex_inited) { + os_mutex_exit(os_sync_mutex); + } } /************************************************************** @@ -631,6 +613,10 @@ os_fast_mutex_free( DeleteCriticalSection((LPCRITICAL_SECTION) fast_mutex); #else ut_a(0 == pthread_mutex_destroy(fast_mutex)); - os_mutex_count--; #endif + os_mutex_enter(os_sync_mutex); + + os_fast_mutex_count--; + + os_mutex_exit(os_sync_mutex); } diff --git a/innobase/os/os0thread.c b/innobase/os/os0thread.c index 02ea2c227a7..9af98760ad1 100644 --- a/innobase/os/os0thread.c +++ b/innobase/os/os0thread.c @@ -186,6 +186,10 @@ os_thread_exit( void* exit_value) /* in: exit value; in Windows this void* is cast as a DWORD */ { +#ifdef UNIV_DEBUG_THREAD_CREATION + printf("A thread exits.\n"); + printf("Thread id %lu\n", os_thread_pf(os_thread_get_curr_id())); +#endif os_mutex_enter(os_sync_mutex); os_thread_count--; os_mutex_exit(os_sync_mutex); diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index da2966a7124..2a93ca966eb 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -856,6 +856,7 @@ srv_release_max_if_no_queries(void) mutex_exit(&kernel_mutex); } +#ifdef notdefined /*********************************************************************** Releases one utility thread if no queries are active and the high-water mark 2 for the utility is exceeded. */ @@ -890,7 +891,6 @@ srv_release_one_if_no_queries(void) mutex_exit(&kernel_mutex); } -#ifdef notdefined /*********************************************************************** Decrements the utility meter by the value given and suspends the calling thread, which must be an utility thread of the type given, if necessary. */ @@ -1000,6 +1000,8 @@ srv_communication_init( ut_a(ret == 0); } + +#ifdef notdefined /************************************************************************* Implements the recovery utility. */ @@ -1060,6 +1062,7 @@ srv_purge_thread( return(0); } +#endif /* notdefined */ /************************************************************************* Creates the utility threads. */ @@ -1090,6 +1093,7 @@ srv_create_utility_threads(void) ut_a(thread); */ } +#ifdef notdefined /************************************************************************* Implements the communication threads. */ static @@ -1139,6 +1143,7 @@ srv_com_thread( return(0); } +#endif /************************************************************************* Creates the communication threads. */ @@ -1159,6 +1164,7 @@ srv_create_com_threads(void) } } +#ifdef notdefined /************************************************************************* Implements the worker threads. */ static @@ -1203,6 +1209,7 @@ srv_worker_thread( return(0); } +#endif /************************************************************************* Creates the worker threads. */ @@ -2456,6 +2463,10 @@ srv_lock_timeout_and_monitor_thread( char* buf; ulint i; +#ifdef UNIV_DEBUG_THREAD_CREATION + printf("Lock timeout thread starts\n"); + printf("Thread id %lu\n", os_thread_pf(os_thread_get_curr_id())); +#endif UT_NOT_USED(arg); srv_last_monitor_time = time(NULL); last_table_monitor_time = time(NULL); @@ -2596,6 +2607,10 @@ loop: exit_func: srv_lock_timeout_and_monitor_active = FALSE; + /* We count the number of threads in os_thread_exit(). A created + thread should always use that to exit and not use return() to exit. */ + + os_thread_exit(NULL); #ifndef __WIN__ return(NULL); #else @@ -2621,6 +2636,10 @@ srv_error_monitor_thread( ulint cnt = 0; UT_NOT_USED(arg); +#ifdef UNIV_DEBUG_THREAD_CREATION + printf("Error monitor thread starts\n"); + printf("Thread id %lu\n", os_thread_pf(os_thread_get_curr_id())); +#endif loop: srv_error_monitor_active = TRUE; @@ -2657,6 +2676,9 @@ loop: srv_error_monitor_active = FALSE; + /* We count the number of threads in os_thread_exit(). A created + thread should always use that to exit and not use return() to exit. */ + os_thread_exit(NULL); #ifndef __WIN__ @@ -2737,6 +2759,10 @@ srv_master_thread( UT_NOT_USED(arg); +#ifdef UNIV_DEBUG_THREAD_CREATION + printf("Master thread starts\n"); + printf("Thread id %lu\n", os_thread_pf(os_thread_get_curr_id())); +#endif srv_main_thread_process_no = os_proc_get_number(); srv_main_thread_id = os_thread_pf(os_thread_get_curr_id()); @@ -2972,6 +2998,15 @@ background_loop: n_tables_to_drop = row_drop_tables_for_mysql_in_background(); + if (n_tables_to_drop > 0) { + /* Do not monopolize the CPU even if there are tables waiting + in the background drop queue. (It is essentially a bug if + MySQL tries to drop a table while there are still open handles + to it and we had to put it to the background drop queue.) */ + + os_thread_sleep(100000); + } + srv_main_thread_op_info = (char*)"purging"; if (srv_fast_shutdown && srv_shutdown_state > 0) { @@ -3110,6 +3145,13 @@ suspend_thread: goto loop; + /* We count the number of threads in os_thread_exit(). A created + thread should always use that to exit and not use return() to exit. + The thread actually never comes here because it is exited in an + os_event_wait(). */ + + os_thread_exit(NULL); + #ifndef __WIN__ return(NULL); #else diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index f03355b825c..1f278d82bc0 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -414,8 +414,10 @@ io_handler_thread( segment = *((ulint*)arg); -/* printf("Io handler thread %lu starts\n", segment); */ - +#ifdef UNIV_DEBUG_THREAD_CREATION + printf("Io handler thread %lu starts\n", segment); + printf("Thread id %lu\n", os_thread_pf(os_thread_get_curr_id())); +#endif for (i = 0;; i++) { fil_aio_wait(segment); @@ -424,6 +426,13 @@ io_handler_thread( mutex_exit(&ios_mutex); } + /* We count the number of threads in os_thread_exit(). A created + thread should always use that to exit and not use return() to exit. + The thread actually never comes here because it is exited in an + os_event_wait(). */ + + os_thread_exit(NULL); + #ifndef __WIN__ return(NULL); #else @@ -1546,21 +1555,32 @@ innobase_shutdown_for_mysql(void) os_thread_count); } - /* 3. Free all InnoDB's own mutexes */ + /* 3. Free all InnoDB's own mutexes and the os_fast_mutexes inside + them */ sync_close(); - /* 4. Free all OS synchronization primitives (in Windows currently - events are not freed) */ + /* 4. Free the os_conc_mutex and all os_events and os_mutexes */ srv_free(); os_sync_free(); - /* 5. Free all allocated memory (and the os_fast_mutex created in + /* 5. Free all allocated memory and the os_fast_mutex created in ut0mem.c */ ut_free_all_mem(); + if (os_thread_count != 0 + || os_event_count != 0 + || os_mutex_count != 0 + || os_fast_mutex_count != 0) { + fprintf(stderr, +"InnoDB: Warning: some resources were not cleaned up in shutdown:\n" +"InnoDB: threads %lu, events %lu, os_mutexes %lu, os_fast_mutexes %lu\n", + os_thread_count, os_event_count, os_mutex_count, + os_fast_mutex_count); + } + if (srv_print_verbose_log) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Shutdown completed\n"); -- cgit v1.2.1 From eebdcd0c5f0cdde4c70cc68a383f73d309b85d5a Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Mon, 2 Jun 2003 13:45:45 +0300 Subject: os0file.c: Put back Monty's patch which the previous push accidentally erased: print also operation type in os_file_handle_error() --- innobase/os/os0file.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index eaea6688462..2f32b9347dc 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -300,7 +300,8 @@ os_file_handle_error( /* out: TRUE if we should retry the operation */ os_file_t file, /* in: file pointer */ - char* name) /* in: name of a file or NULL */ + char* name, /* in: name of a file or NULL */ + const char* operation)/* in: operation */ { ulint err; @@ -343,6 +344,7 @@ os_file_handle_error( fprintf(stderr, "InnoDB: File name %s\n", name); } + fprintf(stderr, "InnoDB: System call %s.\n", operation); fprintf(stderr, "InnoDB: Cannot continue operation.\n"); fflush(stderr); @@ -424,8 +426,9 @@ try_again: if (file == INVALID_HANDLE_VALUE) { *success = FALSE; - retry = os_file_handle_error(file, name); - + retry = os_file_handle_error(file, name, + create_mode == OS_FILE_OPEN ? + "open" : "create"); if (retry) { goto try_again; } @@ -465,8 +468,9 @@ try_again: if (file == -1) { *success = FALSE; - retry = os_file_handle_error(file, name); - + retry = os_file_handle_error(file, name, + create_mode == OS_FILE_OPEN ? + "open" : "create"); if (retry) { goto try_again; } @@ -573,8 +577,9 @@ try_again: if (file == INVALID_HANDLE_VALUE) { *success = FALSE; - retry = os_file_handle_error(file, name); - + retry = os_file_handle_error(file, name, + create_mode == OS_FILE_OPEN ? + "open" : "create"); if (retry) { goto try_again; } @@ -620,8 +625,9 @@ try_again: if (file == -1) { *success = FALSE; - retry = os_file_handle_error(file, name); - + retry = os_file_handle_error(file, name, + create_mode == OS_FILE_OPEN ? + "open" : "create"); if (retry) { goto try_again; } @@ -654,7 +660,7 @@ os_file_close( return(TRUE); } - os_file_handle_error(file, NULL); + os_file_handle_error(file, NULL, "close"); return(FALSE); #else int ret; @@ -662,7 +668,7 @@ os_file_close( ret = close(file); if (ret == -1) { - os_file_handle_error(file, NULL); + os_file_handle_error(file, NULL, "close"); return(FALSE); } @@ -830,7 +836,7 @@ os_file_flush( return(TRUE); } - os_file_handle_error(file, NULL); + os_file_handle_error(file, NULL, "flush"); /* It is a fatal error if a file flush does not succeed, because then the database can get corrupt on disk */ @@ -863,7 +869,7 @@ os_file_flush( fprintf(stderr, " InnoDB: Error: the OS said file flush did not succeed\n"); - os_file_handle_error(file, NULL); + os_file_handle_error(file, NULL, "flush"); /* It is a fatal error if a file flush does not succeed, because then the database can get corrupt on disk */ @@ -1104,7 +1110,7 @@ try_again: #ifdef __WIN__ error_handling: #endif - retry = os_file_handle_error(file, NULL); + retry = os_file_handle_error(file, NULL, "read"); if (retry) { goto try_again; @@ -1869,7 +1875,7 @@ os_aio( offset where to read or write */ ulint offset_high, /* in: most significant 32 bits of offset */ - ulint n, /* in: number of bytes to read or write */ + ulint n, /* in: number of bytes to read or write */ void* message1,/* in: messages for the aio handler (these can be used to identify a completed aio operation); if mode is OS_AIO_SYNC, these @@ -2022,8 +2028,8 @@ try_again: os_aio_array_free_slot(array, slot); - retry = os_file_handle_error(file, name); - + retry = os_file_handle_error(file, name, + type == OS_FILE_READ ? "aio read" : "aio write"); if (retry) { goto try_again; @@ -2121,7 +2127,7 @@ os_aio_windows_handle( ut_a(TRUE == os_file_flush(slot->file)); } } else { - os_file_handle_error(slot->file, slot->name); + os_file_handle_error(slot->file, slot->name, "Windows aio"); ret_val = FALSE; } -- cgit v1.2.1 From 5eaa3c4e341dca7b87b9a36fca0c108ce6c18f5c Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Mon, 2 Jun 2003 16:11:06 +0300 Subject: com0shm.c: Removed auto event creation because it is not needed in any MySQL/InnoDB code --- innobase/com/com0shm.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/innobase/com/com0shm.c b/innobase/com/com0shm.c index 72ab23b9be8..ed185ccdf47 100644 --- a/innobase/com/com0shm.c +++ b/innobase/com/com0shm.c @@ -103,7 +103,8 @@ struct com_shm_endpoint_struct{ the area currently may contain a datagram; NOTE: automatic event */ os_event_t empty; /* this is in the signaled state if the area - currently may be empty; NOTE: automatic event */ + currently may be empty; NOTE: automatic + event */ ip_mutex_hdl_t* ip_mutex; /* handle to the interprocess mutex protecting the shared memory */ UT_LIST_NODE_T(com_shm_endpoint_t) list; /* If the endpoint struct @@ -793,16 +794,18 @@ com_shm_create_or_open( ut_strcpy(buf + len, (char*)"_IBSHM_EV_NE"), - event_ne = os_event_create_auto(buf); + event_ne = os_event_create(buf); ut_ad(event_ne); ut_strcpy(buf + len, (char*)"_IBSHM_EV_EM"), - event_em = os_event_create_auto(buf); + event_em = os_event_create(buf); ut_ad(event_em); + ut_a(0); /* event_ne and event_em should be auto events! */ + com_shm_endpoint_set_shm(ep, shm); com_shm_endpoint_set_map(ep, map); -- cgit v1.2.1 From ce8e0aa0c41f9c68cc6d5101ba58236d7cb63f31 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Mon, 2 Jun 2003 17:58:18 +0300 Subject: os0sync.c: Do not try to reserve os_sync_mutex in shutdown after it has been freed --- innobase/os/os0sync.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/innobase/os/os0sync.c b/innobase/os/os0sync.c index 0fe61fe570d..bf5fc57bf57 100644 --- a/innobase/os/os0sync.c +++ b/innobase/os/os0sync.c @@ -88,6 +88,12 @@ os_sync_free(void) mutex = UT_LIST_GET_FIRST(os_mutex_list); while (mutex) { + if (mutex == os_sync_mutex) { + /* Set the flag to FALSE so that we do not try to + reserve os_sync_mutex any more in remaining freeing + operations in shutdown */ + os_sync_mutex_inited = FALSE; + } os_mutex_free(mutex); @@ -517,13 +523,17 @@ os_mutex_free( { ut_a(mutex); - os_mutex_enter(os_sync_mutex); + if (os_sync_mutex_inited) { + os_mutex_enter(os_sync_mutex); + } UT_LIST_REMOVE(os_mutex_list, os_mutex_list, mutex); os_mutex_count--; - os_mutex_exit(os_sync_mutex); + if (os_sync_mutex_inited) { + os_mutex_exit(os_sync_mutex); + } #ifdef __WIN__ ut_a(CloseHandle(mutex->handle)); @@ -614,9 +624,16 @@ os_fast_mutex_free( #else ut_a(0 == pthread_mutex_destroy(fast_mutex)); #endif - os_mutex_enter(os_sync_mutex); + if (os_sync_mutex_inited) { + /* When freeing the last mutexes, we have + already freed os_sync_mutex */ + + os_mutex_enter(os_sync_mutex); + } os_fast_mutex_count--; - os_mutex_exit(os_sync_mutex); + if (os_sync_mutex_inited) { + os_mutex_exit(os_sync_mutex); + } } -- cgit v1.2.1 From 4d5ae1d37c22cd6dea442571f5936e86b6cbc109 Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Mon, 2 Jun 2003 17:30:47 +0200 Subject: Clearer error message (in the customer's case, the relay log was corrupted, not the master's binlog) (SW 1571). --- sql/slave.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sql/slave.cc b/sql/slave.cc index b655b17c258..ec1041894bd 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2081,8 +2081,13 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) else { sql_print_error("\ -Could not parse log event entry, check the master for binlog corruption\n\ -This may also be a network problem, or just a bug in the master or slave code.\ +Could not parse relay log event entry. The possible reasons are: the master's \ +binary log is corrupted (you can check this by running 'mysqlbinlog' on the \ +binary log), the slave's relay log is corrupted (you can check this by running \ +'mysqlbinlog' on the relay log), a network problem, or a bug in the master's \ +or slave's MySQL code. If you want to check the master's binary log or slave's \ +relay log, you will be able to know their names by issuing 'SHOW SLAVE STATUS' \ +on this slave.\ "); return 1; } -- cgit v1.2.1 From 3b974039f7ba1a35c9767ed0382bd1901f1415fb Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Tue, 3 Jun 2003 15:47:29 +0200 Subject: -- Waiting for Monty's approval before push -- Bug 571: play LOAD DATA INFILE the same way on the slave as it was on the master: if it was with IGNORE, do it with IGNORE, if it was with REPLACE, do it with REPLACE, and (the change) if it was with nothing, do it with nothing (not with IGNORE !!). Bug 573: print a proper error message in case of duplicate entry in LOAD DATA INFILE on the slave, i.e. a message where the keyname and key value appear : 'Duplicate entry '1' for key 1' and not 'Duplicate entry '%-.64s' for key %d' --- mysql-test/r/rpl_loaddata.result | 6 ++++++ mysql-test/t/rpl_loaddata.test | 17 +++++++++++++++++ sql/log_event.cc | 37 +++++++++++++++++++++++++++++++------ 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/rpl_loaddata.result b/mysql-test/r/rpl_loaddata.result index 62071a07d0c..844a9d66cb3 100644 --- a/mysql-test/r/rpl_loaddata.result +++ b/mysql-test/r/rpl_loaddata.result @@ -22,3 +22,9 @@ day id category name drop table t1; drop table t2; drop table t3; +create table t1(a int, b int, unique(b)); +insert into t1 values(1,10); +load data infile '../../std_data/rpl_loaddata.dat' into table t1; +show status like 'slave_running'; +Variable_name Value +Slave_running OFF diff --git a/mysql-test/t/rpl_loaddata.test b/mysql-test/t/rpl_loaddata.test index 1f34aa9d3f9..dc4eadda192 100644 --- a/mysql-test/t/rpl_loaddata.test +++ b/mysql-test/t/rpl_loaddata.test @@ -4,6 +4,9 @@ # # check replication of load data for temporary tables with additional parameters # +# check if duplicate entries trigger an error (they should unless IGNORE or +# REPLACE was used on the master) (bug 571). + source include/master-slave.inc; create table t1(a int not null auto_increment, b int, primary key(a) ); @@ -27,7 +30,21 @@ connection master; drop table t1; drop table t2; drop table t3; +create table t1(a int, b int, unique(b)); save_master_pos; connection slave; sync_with_master; +insert into t1 values(1,10); + +connection master; +load data infile '../../std_data/rpl_loaddata.dat' into table t1; + +save_master_pos; +connection slave; +# don't sync_with_master because the slave SQL thread should be stopped because +# of the error so MASTER_POS_WAIT() will not return; just sleep and hope the +# slave SQL thread will have had time to stop. + +sleep 1; +show status like 'slave_running'; diff --git a/sql/log_event.cc b/sql/log_event.cc index cda2e50c53d..369ef940af2 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1886,9 +1886,27 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, else { char llbuff[22]; - enum enum_duplicates handle_dup = DUP_IGNORE; + enum enum_duplicates handle_dup; if (sql_ex.opt_flags & REPLACE_FLAG) handle_dup= DUP_REPLACE; + else if (sql_ex.opt_flags & IGNORE_FLAG) + handle_dup= DUP_IGNORE; + else + /* + Note that when replication is running fine, if it was DUP_ERROR on the + master then we could choose DUP_IGNORE here, because if DUP_ERROR + suceeded on master, and data is identical on the master and slave, + then there should be no uniqueness errors on slave, so DUP_IGNORE is + the same as DUP_ERROR. But in the unlikely case of uniqueness errors + (because the data on the master and slave happen to be different (user + error or bug), we want LOAD DATA to print an error message on the + slave to discover the problem. + + If reading from net (a 3.23 master), mysql_load() will change this + to DUP_IGNORE. + */ + handle_dup= DUP_ERROR; + sql_exchange ex((char*)fname, sql_ex.opt_flags & DUMPFILE_FLAG); String field_term(sql_ex.field_term,sql_ex.field_term_len); String enclosed(sql_ex.enclosed,sql_ex.enclosed_len); @@ -1949,12 +1967,19 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, close_thread_tables(thd); if (thd->query_error) { - int sql_error= thd->net.last_errno; - if (!sql_error) - sql_error= ER_UNKNOWN_ERROR; - slave_print_error(rli,sql_error, + /* this err/sql_errno code is copy-paste from send_error() */ + const char *err; + int sql_errno; + if ((err=thd->net.last_error)[0]) + sql_errno=thd->net.last_errno; + else + { + sql_errno=ER_UNKNOWN_ERROR; + err=ER(sql_errno); + } + slave_print_error(rli,sql_errno, "Error '%s' running load data infile", - ER_SAFE(sql_error)); + err); free_root(&thd->mem_root,0); return 1; } -- cgit v1.2.1 From 4a80a6c7b9a7f81e239a667145e71e6d4e40212a Mon Sep 17 00:00:00 2001 From: "guilhem@mysql.com" <> Date: Tue, 3 Jun 2003 23:13:06 +0200 Subject: One-line fix for bug 576 (DBUG_ASSERT failure when using CHANGE MASTER TO RELAY_LOG_POS=4). Plus a changeset which I had committed but forgot to push (and this changeset is lost on another computer, so I recreate it here). This changeset is "user-friendly SHOW BINLOG EVENTS and CHANGE MASTER TO when log positions < 4 are used. --- sql/slave.cc | 2 +- sql/sql_repl.cc | 8 +------- sql/sql_yacc.yy | 14 ++++++++++++++ sql/unireg.h | 8 ++++++-- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/sql/slave.cc b/sql/slave.cc index ec1041894bd..c2762dbd6f4 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -269,7 +269,7 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log, goto err; rli->cur_log = &rli->cache_buf; } - if (pos > BIN_LOG_HEADER_SIZE) + if (pos >= BIN_LOG_HEADER_SIZE) my_b_seek(rli->cur_log,(off_t)pos); err: diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 283dd20a56c..ca993c053a1 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -961,7 +961,7 @@ int show_binlog_events(THD* thd) { LEX_MASTER_INFO *lex_mi = &thd->lex.mi; ha_rows event_count, limit_start, limit_end; - my_off_t pos = lex_mi->pos; + my_off_t pos = max(BIN_LOG_HEADER_SIZE, lex_mi->pos); // user-friendly char search_file_name[FN_REFLEN], *name; const char *log_file_name = lex_mi->log_file_name; pthread_mutex_t *log_lock = mysql_bin_log.get_log_lock(); @@ -989,12 +989,6 @@ int show_binlog_events(THD* thd) if ((file=open_binlog(&log, linfo.log_file_name, &errmsg)) < 0) goto err; - if (pos < 4) - { - errmsg = "Invalid log position"; - goto err; - } - pthread_mutex_lock(log_lock); my_b_seek(&log, pos); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c79750c8014..b0c81d6f6b0 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -706,6 +706,18 @@ master_def: MASTER_LOG_POS_SYM EQ ulonglong_num { Lex->mi.pos = $3; + /* + If the user specified a value < BIN_LOG_HEADER_SIZE, adjust it + instead of causing subsequent errors. + We need to do it in this file, because only there we know that + MASTER_LOG_POS has been explicitely specified. On the contrary + in change_master() (sql_repl.cc) we cannot distinguish between 0 + (MASTER_LOG_POS explicitely specified as 0) and 0 (unspecified), + whereas we want to distinguish (specified 0 means "read the binlog + from 0" (4 in fact), unspecified means "don't change the position + (keep the preceding value)"). + */ + Lex->mi.pos = max(BIN_LOG_HEADER_SIZE, Lex->mi.pos); } | MASTER_CONNECT_RETRY_SYM EQ ULONG_NUM @@ -721,6 +733,8 @@ master_def: RELAY_LOG_POS_SYM EQ ULONG_NUM { Lex->mi.relay_log_pos = $3; + /* Adjust if < BIN_LOG_HEADER_SIZE (same comment as Lex->mi.pos) */ + Lex->mi.relay_log_pos = max(BIN_LOG_HEADER_SIZE, Lex->mi.relay_log_pos); }; diff --git a/sql/unireg.h b/sql/unireg.h index f69d67455dd..f2cace51fa7 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -130,9 +130,13 @@ bfill((A)->null_flags,(A)->null_bytes,255);\ */ #define MIN_TURBOBM_PATTERN_LEN 3 -/* Defines for binary logging */ +/* + Defines for binary logging. + Do not decrease the value of BIN_LOG_HEADER_SIZE. + Do not even increase it before checking code. +*/ -#define BIN_LOG_HEADER_SIZE 4 +#define BIN_LOG_HEADER_SIZE 4 /* Include prototypes for unireg */ -- cgit v1.2.1 From 100a66e6cbb6598039fdd0c0b5e9f8ed6e1d025d Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Wed, 4 Jun 2003 16:05:27 +0300 Subject: Added [mysqld-base-version] as a default group for the mysqld server Portability fix for Windows 64 --- include/config-win.h | 8 +++++++- include/my_global.h | 2 +- include/mysql_version.h.in | 1 + innobase/include/univ.i | 4 ++++ sql/mysqld.cc | 2 +- 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/include/config-win.h b/include/config-win.h index 9931d2c4b95..096c00e4574 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -130,6 +130,11 @@ typedef uint rf_SetTimer; #define SIZEOF_LONG 4 #define SIZEOF_LONG_LONG 8 #define SIZEOF_OFF_T 8 +#ifdef _WIN64 +#define SIZEOF_CHARP 8 +#else +#define SIZEOF_CHARP 4 +#endif #define HAVE_BROKEN_NETINET_INCLUDES #ifdef __NT__ #define HAVE_NAMED_PIPE /* We can only create pipes on NT */ @@ -196,6 +201,7 @@ inline double ulonglong2double(ulonglong value) /* Optimized store functions for Intel x86 */ +#ifndef _WIN64 #define sint2korr(A) (*((int16 *) (A))) #define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \ (((uint32) 255L << 24) | \ @@ -236,7 +242,7 @@ inline double ulonglong2double(ulonglong value) #define float8get(V,M) doubleget((V),(M)) #define float4store(V,M) memcpy((byte*) V,(byte*) (&M),sizeof(float)) #define float8store(V,M) doublestore((V),(M)) - +#endif /* _WIN64 */ #define HAVE_PERROR #define HAVE_VFPRINT diff --git a/include/my_global.h b/include/my_global.h index 90c4801e807..1026e8e3940 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -848,7 +848,7 @@ typedef char bool; /* Ordinary boolean values 0 1 */ */ /* Optimized store functions for Intel x86 */ -#ifdef __i386__ +#if defined(__i386__) && !defined(_WIN64) #define sint2korr(A) (*((int16 *) (A))) #define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \ (((uint32) 255L << 24) | \ diff --git a/include/mysql_version.h.in b/include/mysql_version.h.in index 793bf36e9fe..da184665f6e 100644 --- a/include/mysql_version.h.in +++ b/include/mysql_version.h.in @@ -10,6 +10,7 @@ #else #define PROTOCOL_VERSION @PROTOCOL_VERSION@ #define MYSQL_SERVER_VERSION "@VERSION@" +#define MYSQL_BASE_VERSION "mysqld-@MYSQL_BASE_VERSION@" #ifndef MYSQL_SERVER_SUFFIX #define MYSQL_SERVER_SUFFIX "@MYSQL_SERVER_SUFFIX@" #endif diff --git a/innobase/include/univ.i b/innobase/include/univ.i index e29f3ec92e1..4854e5a7b78 100644 --- a/innobase/include/univ.i +++ b/innobase/include/univ.i @@ -187,7 +187,11 @@ management to ensure correct alignment for doubles etc. */ /* Another basic type we use is unsigned long integer which is intended to be equal to the word size of the machine. */ +#ifdef _WIN64 +typedef unsigned __int64 ulint; +#else typedef unsigned long int ulint; +#endif typedef long int lint; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 1492d6ddb68..7289d0e72cf 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1923,7 +1923,7 @@ extern "C" pthread_handler_decl(handle_shutdown,arg) #endif -const char *load_default_groups[]= { "mysqld","server",0 }; +const char *load_default_groups[]= { "mysqld","server",MYSQL_BASE_VERSION,0 }; bool open_log(MYSQL_LOG *log, const char *hostname, const char *opt_name, const char *extension, -- cgit v1.2.1 From 42c80c81f79d5376089a14ede88749a3ae625317 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Wed, 4 Jun 2003 17:58:41 +0300 Subject: handler.cc: If the autocommit is on, let handler.cc commit or rollback the whole transaction at an updating SQL statement end. This probably fixes bug number 578. The problem was that when explicit LOCK TABLES is used, then the lock count method in autocommit does not work. --- sql/handler.cc | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/sql/handler.cc b/sql/handler.cc index 45c83355c94..6ee0b1f9c55 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -208,23 +208,45 @@ void ha_close_connection(THD* thd) } /* - This is used to commit or rollback a single statement depending - on the value of error + This is used to commit or rollback a single statement depending on the value + of error. If the autocommit is on, then we will commit or rollback the whole + transaction (= the statement). The autocommit mechanism built into handlers + is based on counting locks, but if the user has used LOCK TABLES then that + mechanism does not know to do the commit. */ int ha_autocommit_or_rollback(THD *thd, int error) { + bool do_autocommit=FALSE; + DBUG_ENTER("ha_autocommit_or_rollback"); #ifdef USING_TRANSACTIONS + + if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) + do_autocommit=TRUE; /* We can commit or rollback the whole transaction */ + if (opt_using_transactions) { if (!error) { - if (ha_commit_stmt(thd)) - error=1; + if (do_autocommit) + { + if (ha_commit(thd)) + error=1; + } + else + { + if (ha_commit_stmt(thd)) + error=1; + } } else - (void) ha_rollback_stmt(thd); + { + if (do_autocommit) + (void) ha_rollback(thd); + else + (void) ha_rollback_stmt(thd); + } thd->variables.tx_isolation=thd->session_tx_isolation; } -- cgit v1.2.1 From 6217b578b9b9a6f65b6891b888be357d3148f4d0 Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Wed, 4 Jun 2003 18:22:48 +0300 Subject: Fixed (not fatal) buffer overflow --- libmysql/libmysql.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index af74182eb22..c008d625900 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1646,7 +1646,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, net->vio = vio_new(sock, VIO_TYPE_SOCKET, TRUE); bzero((char*) &UNIXaddr,sizeof(UNIXaddr)); UNIXaddr.sun_family = AF_UNIX; - strmov(UNIXaddr.sun_path, unix_socket); + strmake(UNIXaddr.sun_path, unix_socket, sizeof(UNIXaddr.sun_path)-1); if (my_connect(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr), mysql->options.connect_timeout) <0) { -- cgit v1.2.1 From 23145cfed72954c29f5a47e82af22898164be4b0 Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Wed, 4 Jun 2003 18:28:51 +0300 Subject: Added SQLSTATE to client/server protocol bmove_allign -> bmove_align Added OLAP function ROLLUP Split mysql_fix_privilege_tables to a script and a .sql data file Added new (MEMROOT*) functions to avoid calling current_thd() when creating some common objects. Added table_alias_charset, for easier --lower-case-table-name handling Better SQL_MODE handling (Setting complex options also sets sub options) New (faster) assembler string functions for x86 --- .bzrignore | 2 + client/mysql.cc | 39 ++- client/mysqltest.c | 6 +- dbug/dbug.c | 24 +- include/m_string.h | 10 +- include/mysql.h | 3 +- include/mysql_com.h | 1 + include/sql_state.h | 164 ++++++++++ libmysql/libmysql.c | 192 +++++------ libmysqld/Makefile.am | 3 +- libmysqld/libmysqld.c | 11 +- mysql-test/r/analyse.result | 30 +- mysql-test/r/ansi.result | 10 +- mysql-test/r/auto_increment.result | 4 +- mysql-test/r/bdb-deadlock.result | 2 +- mysql-test/r/bdb.result | 18 +- mysql-test/r/comments.result | 2 +- mysql-test/r/create.result | 42 +-- mysql-test/r/ctype_collate.result | 12 +- mysql-test/r/delayed.result | 2 +- mysql-test/r/delete.result | 2 +- mysql-test/r/derived.result | 27 +- mysql-test/r/distinct.result | 4 +- mysql-test/r/drop.result | 6 +- mysql-test/r/err000001.result | 20 +- mysql-test/r/explain.result | 4 +- mysql-test/r/flush.result | 2 +- mysql-test/r/fulltext.result | 6 +- mysql-test/r/func_gconcat.result | 4 +- mysql-test/r/func_system.result | 4 +- mysql-test/r/grant_cache.result | 12 +- mysql-test/r/group_by.result | 6 +- mysql-test/r/handler.result | 12 +- mysql-test/r/heap.result | 4 +- mysql-test/r/heap_btree.result | 4 +- mysql-test/r/heap_hash.result | 4 +- mysql-test/r/innodb.result | 20 +- mysql-test/r/innodb_handler.result | 8 +- mysql-test/r/insert_select.result | 2 +- mysql-test/r/insert_update.result | 2 +- mysql-test/r/join.result | 2 +- mysql-test/r/join_outer.result | 12 +- mysql-test/r/key.result | 2 +- mysql-test/r/lock.result | 4 +- mysql-test/r/lock_multi.result | 2 +- mysql-test/r/merge.result | 4 +- mysql-test/r/multi_update.result | 10 +- mysql-test/r/myisam.result | 10 +- mysql-test/r/null.result | 16 +- mysql-test/r/olap.result | 283 +++++++++++++++-- mysql-test/r/order_by.result | 14 +- mysql-test/r/packet.result | 2 +- mysql-test/r/query_cache.result | 4 +- mysql-test/r/row.result | 14 +- mysql-test/r/rpl000001.result | 2 +- mysql-test/r/rpl000009.result | 2 +- mysql-test/r/rpl_empty_master_crash.result | 4 +- mysql-test/r/rpl_log.result | 2 +- mysql-test/r/rpl_replicate_do.result | 2 +- mysql-test/r/rpl_rotate_logs.result | 4 +- mysql-test/r/select.result | 12 +- mysql-test/r/select_safe.result | 16 +- mysql-test/r/show_check.result | 2 +- mysql-test/r/sql_mode.result | 8 +- mysql-test/r/subselect.result | 121 +++---- mysql-test/r/temp_table.result | 6 +- mysql-test/r/truncate.result | 4 +- mysql-test/r/type_blob.result | 6 +- mysql-test/r/type_decimal.result | 6 +- mysql-test/r/type_float.result | 2 +- mysql-test/r/type_ranges.result | 2 +- mysql-test/r/union.result | 26 +- mysql-test/r/update.result | 6 +- mysql-test/r/user_var.result | 2 +- mysql-test/r/varbinary.result | 4 +- mysql-test/r/variables.result | 36 +-- mysql-test/t/ansi.test | 5 + mysql-test/t/derived.test | 9 + mysql-test/t/func_system.test | 2 +- mysql-test/t/lowercase_table.test | 1 - mysql-test/t/olap.test | 96 ++++-- mysql-test/t/sql_mode.test | 4 +- mysql-test/t/subselect.test | 14 +- scripts/Makefile.am | 2 +- scripts/mysql_fix_privilege_tables.sh | 344 +++++++++----------- scripts/mysql_fix_privilege_tables.sql | 89 ++++++ sql/Makefile.am | 3 +- sql/item.cc | 34 +- sql/item.h | 2 + sql/item_sum.cc | 160 ++++++++-- sql/item_sum.h | 79 ++--- sql/item_uniq.h | 2 +- sql/mysql_priv.h | 10 +- sql/mysqld.cc | 68 ++-- sql/net_serv.cc | 7 + sql/protocol.cc | 7 +- sql/set_var.cc | 133 ++++++-- sql/set_var.h | 6 +- sql/sql_base.cc | 27 +- sql/sql_cache.cc | 3 +- sql/sql_list.h | 3 + sql/sql_prepare.cc | 2 +- sql/sql_select.cc | 489 +++++++++++++++++++++++------ sql/sql_select.h | 49 ++- sql/sql_show.cc | 27 +- sql/sql_state.c | 53 ++++ sql/sql_string.cc | 4 - sql/sql_string.h | 5 +- sql/sql_table.cc | 5 +- sql/sql_union.cc | 2 +- sql/sql_yacc.yy | 19 +- sql/unireg.h | 4 +- strings/Makefile.am | 2 +- strings/ctype.c | 2 - strings/str_test.c | 4 +- strings/strings-x86.s | 86 ++--- strings/strings.asm | 16 +- 117 files changed, 2205 insertions(+), 1058 deletions(-) create mode 100644 include/sql_state.h create mode 100644 scripts/mysql_fix_privilege_tables.sql create mode 100644 sql/sql_state.c diff --git a/.bzrignore b/.bzrignore index 82adbf625f3..43e8c9c85b7 100644 --- a/.bzrignore +++ b/.bzrignore @@ -617,3 +617,5 @@ vio/test-sslclient vio/test-sslserver vio/viotest-ssl include/readline/*.h +strings/str_test +libmysqld/sql_state.c diff --git a/client/mysql.cc b/client/mysql.cc index 812673d34c2..c8fed137344 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -200,7 +200,9 @@ static int com_nopager(String *str, char*), com_pager(String *str, char*), static int read_lines(bool execute_commands); static int sql_connect(char *host,char *database,char *user,char *password, uint silent); -static int put_info(const char *str,INFO_TYPE info,uint error=0); +static int put_info(const char *str,INFO_TYPE info,uint error=0, + const char *sql_state=0); +static int put_error(MYSQL *mysql); static void safe_put_field(const char *pos,ulong length); static void xmlencode_print(const char *src, uint length); static void init_pager(); @@ -1437,7 +1439,7 @@ int mysql_real_query_for_lazy(const char *buf, int length) { if (!mysql_real_query(&mysql,buf,length)) return 0; - uint error=put_info(mysql_error(&mysql),INFO_ERROR, mysql_errno(&mysql)); + int error= put_error(&mysql); if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR || retry > 1 || !opt_reconnect) return error; @@ -1452,8 +1454,7 @@ int mysql_store_result_for_lazy(MYSQL_RES **result) return 0; if (mysql_error(&mysql)[0]) - return put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql)); - + return put_error(&mysql); return 0; } @@ -1653,9 +1654,7 @@ com_go(String *buffer,char *line __attribute__((unused))) if (quick) { if (!(result=mysql_use_result(&mysql)) && mysql_field_count(&mysql)) - { - return put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql)); - } + return put_error(&mysql); } else { @@ -1717,7 +1716,7 @@ com_go(String *buffer,char *line __attribute__((unused))) put_info("",INFO_RESULT); // Empty row if (result && !mysql_eof(result)) /* Something wrong when using quick */ - error=put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql)); + error= put_error(&mysql); else if (unbuffered) fflush(stdout); mysql_free_result(result); @@ -2431,12 +2430,12 @@ com_use(String *buffer __attribute__((unused)), char *line) if (mysql_select_db(&mysql,tmp)) { if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR) - return put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql)); + return put_error(&mysql); if (reconnect()) return opt_reconnect ? -1 : 1; // Fatal error if (mysql_select_db(&mysql,tmp)) - return put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql)); + return put_error(&mysql); } my_free(current_db,MYF(MY_ALLOW_ZERO_PTR)); current_db=my_strdup(tmp,MYF(MY_WME)); @@ -2557,7 +2556,7 @@ sql_real_connect(char *host,char *database,char *user,char *password, (mysql_errno(&mysql) != CR_CONN_HOST_ERROR && mysql_errno(&mysql) != CR_CONNECTION_ERROR)) { - put_info(mysql_error(&mysql),INFO_ERROR,mysql_errno(&mysql)); + (void) put_error(&mysql); (void) fflush(stdout); return ignore_errors ? -1 : 1; // Abort } @@ -2707,7 +2706,7 @@ select_limit, max_join_size); static int -put_info(const char *str,INFO_TYPE info_type,uint error) +put_info(const char *str,INFO_TYPE info_type, uint error, const char *sqlstate) { FILE *file= (info_type == INFO_ERROR ? stderr : stdout); static int inited=0; @@ -2752,7 +2751,12 @@ put_info(const char *str,INFO_TYPE info_type,uint error) putchar('\007'); /* This should make a bell */ vidattr(A_STANDOUT); if (error) - (void) tee_fprintf(file, "ERROR %d: ", error); + { + if (sqlstate) + (void) tee_fprintf(file, "ERROR %d (%s): ", error, sqlstate); + else + (void) tee_fprintf(file, "ERROR %d: ", error); + } else tee_puts("ERROR: ", file); } @@ -2767,6 +2771,14 @@ put_info(const char *str,INFO_TYPE info_type,uint error) } +static int +put_error(MYSQL *mysql) +{ + return put_info(mysql_error(mysql), INFO_ERROR, mysql_errno(mysql), + mysql_sqlstate(mysql)); +} + + static void remove_cntrl(String &buffer) { char *start,*end; @@ -3085,4 +3097,3 @@ void sql_element_free(void *ptr) my_free((gptr) ptr,MYF(0)); } #endif /* EMBEDDED_LIBRARY */ - diff --git a/client/mysqltest.c b/client/mysqltest.c index 9889d365335..84ff41d73a6 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -42,7 +42,7 @@ **********************************************************************/ -#define MTEST_VERSION "1.27" +#define MTEST_VERSION "1.28" #include #include @@ -2147,6 +2147,10 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags) if (i == 0 && q->expected_errors == 1) { /* Only log error if there is one possible error */ + dynstr_append_mem(ds,"ERROR ",6); + replace_dynstr_append_mem(ds, mysql_sqlstate(mysql), + strlen(mysql_sqlstate(mysql))); + dynstr_append_mem(ds,": ",2); replace_dynstr_append_mem(ds,mysql_error(mysql), strlen(mysql_error(mysql))); dynstr_append_mem(ds,"\n",1); diff --git a/dbug/dbug.c b/dbug/dbug.c index a4f9d5ecd4b..f7b2fb75ba0 100644 --- a/dbug/dbug.c +++ b/dbug/dbug.c @@ -280,7 +280,7 @@ static BOOLEAN Writable(char *pathname); static void ChangeOwner(char *pathname); /* Allocate memory for runtime support */ #endif -static char *DbugMalloc(int size); +static char *DbugMalloc(size_t size); /* Remove leading pathname components */ static char *BaseName(const char *pathname); static void DoPrefix(uint line); @@ -1120,7 +1120,7 @@ static void PushState () init_done=TRUE; } (void) code_state(); /* Alloc memory */ - new_malloc = (struct state *) DbugMalloc (sizeof (struct state)); + new_malloc = (struct state *) DbugMalloc(sizeof (struct state)); new_malloc -> flags = 0; new_malloc -> delay = 0; new_malloc -> maxdepth = MAXDEPTH; @@ -1341,11 +1341,10 @@ struct link *linkp) */ -static char *StrDup ( -const char *str) +static char *StrDup (const char *str) { reg1 char *new_malloc; - new_malloc = DbugMalloc ((int) strlen (str) + 1); + new_malloc = DbugMalloc((size_t) strlen (str) + 1); (void) strcpy (new_malloc, str); return (new_malloc); } @@ -1606,14 +1605,13 @@ static void DbugExit (const char *why) * */ -static char *DbugMalloc ( -int size) +static char *DbugMalloc (size_t size) { - register char *new_malloc; + register char *new_malloc; - if (!(new_malloc = (char*) malloc ((unsigned int) size))) - DbugExit ("out of memory"); - return (new_malloc); + if (!(new_malloc = (char*) malloc((size_t) size))) + DbugExit ("out of memory"); + return (new_malloc); } @@ -1622,9 +1620,7 @@ int size) * separator (to allow directory-paths in dos). */ -static char *static_strtok ( -char *s1, -pchar separator) +static char *static_strtok (char *s1, pchar separator) { static char *end = NULL; reg1 char *rtnval,*cpy; diff --git a/include/m_string.h b/include/m_string.h index 15a488fe72a..5863bb51b73 100644 --- a/include/m_string.h +++ b/include/m_string.h @@ -74,14 +74,14 @@ /* Unixware 7 */ #if !defined(HAVE_BFILL) # define bfill(A,B,C) memset((A),(C),(B)) -# define bmove_allign(A,B,C) memcpy((A),(B),(C)) +# define bmove_align(A,B,C) memcpy((A),(B),(C)) #endif #if !defined(HAVE_BCMP) # define bcopy(s, d, n) memcpy((d), (s), (n)) # define bcmp(A,B,C) memcmp((A),(B),(C)) # define bzero(A,B) memset((A),0,(B)) -# define bmove_allign(A,B,C) memcpy((A),(B),(C)) +# define bmove_align(A,B,C) memcpy((A),(B),(C)) #endif #if defined(__cplusplus) && !defined(OS2) @@ -111,11 +111,11 @@ extern char NEAR _dig_vec[]; /* Declared in int2str() */ #endif #ifdef MSDOS -#undef bmove_allign -#define bmove512(A,B,C) bmove_allign(A,B,C) +#undef bmove_align +#define bmove512(A,B,C) bmove_align(A,B,C) #define my_itoa(A,B,C) itoa(A,B,C) #define my_ltoa(A,B,C) ltoa(A,B,C) -extern void bmove_allign(gptr dst,const gptr src,uint len); +extern void bmove_align(gptr dst,const gptr src,uint len); #endif #if (!defined(USE_BMOVE512) || defined(HAVE_purify)) && !defined(bmove512) diff --git a/include/mysql.h b/include/mysql.h index 94f2152655d..d903c2c3e67 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -268,7 +268,8 @@ typedef struct st_mysql my_bool free_me; /* If free in mysql_close */ my_ulonglong insert_id; /* id if insert on table with NEXTNR */ unsigned int last_errno; - char *last_error; + char *last_error; /* Used by embedded server */ + char sqlstate[SQLSTATE_LENGTH+1]; /* Used by embedded server */ } MYSQL; #endif diff --git a/include/mysql_com.h b/include/mysql_com.h index e2fa30e3a18..2ed5038b275 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -324,6 +324,7 @@ my_bool check_scramble(const char *, const char *message, unsigned long *salt,my_bool old_ver); char *get_tty_password(char *opt_message); void hash_password(unsigned long *result, const char *password); +const char *mysql_errno_to_sqlstate(uint mysql_errno); /* Some other useful functions */ diff --git a/include/sql_state.h b/include/sql_state.h new file mode 100644 index 00000000000..cc0fab7bfce --- /dev/null +++ b/include/sql_state.h @@ -0,0 +1,164 @@ +/* Copyright (C) 2000-2003 MySQL AB + + 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; either version 2 of the License, or + (at your option) any later version. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + This file includes a mapping from mysql_errno.h to sql_state (as used by + MyODBC) and jdbc_state. + It's suitable to include into a C struct for further processing + + The first column is the mysqld server error (declared in mysqld_error.h), + the second column is the ODBC state (which the 4.1 server sends out by + default) and the last is the state used by the JDBC driver. + If the last column is "" then it means that the JDBC driver is using the + ODBC state + + The errors in this file is sorted in the same order as in mysqld_error.h + to allow on to do binary searches for the sqlstate. +*/ + +ER_DUP_KEY, "23000", "", +ER_OUTOFMEMORY, "HY001", "S1001", +ER_OUT_OF_SORTMEMORY, "HY001", "S1001", +ER_CON_COUNT_ERROR, "08004", "", +ER_BAD_HOST_ERROR, "08S01", "", +ER_HANDSHAKE_ERROR, "08S01", "", +ER_DBACCESS_DENIED_ERROR, "42000", "", +ER_ACCESS_DENIED_ERROR, "42000", "28000", +ER_NO_DB_ERROR, "42000", "", +ER_UNKNOWN_COM_ERROR, "08S01", "", +ER_BAD_NULL_ERROR, "23000", "", +ER_BAD_DB_ERROR, "42000", "", +ER_TABLE_EXISTS_ERROR, "42S01", "", +ER_BAD_TABLE_ERROR, "42S02", "", +ER_NON_UNIQ_ERROR, "23000", "", +ER_SERVER_SHUTDOWN, "08S01", "", +ER_BAD_FIELD_ERROR, "42S22", "S0022", +ER_WRONG_FIELD_WITH_GROUP, "42000", "S1009", +ER_WRONG_GROUP_FIELD, "42000", "S1009", +ER_WRONG_SUM_SELECT, "42000", "S1009", +ER_WRONG_VALUE_COUNT, "21S01", "", +ER_TOO_LONG_IDENT, "42000", "S1009", +ER_DUP_FIELDNAME, "42S21", "S1009", +ER_DUP_KEYNAME, "42000", "S1009", +ER_DUP_ENTRY, "23000", "S1009", +ER_WRONG_FIELD_SPEC, "42000", "S1009", +ER_PARSE_ERROR, "42000", "", +ER_EMPTY_QUERY, "42000" , "", +ER_NONUNIQ_TABLE, "42000", "S1009", +ER_INVALID_DEFAULT, "42000", "S1009", +ER_MULTIPLE_PRI_KEY, "42000", "S1009", +ER_TOO_MANY_KEYS, "42000", "S1009", +ER_TOO_MANY_KEY_PARTS, "42000", "S1009", +ER_TOO_LONG_KEY, "42000", "S1009", +ER_KEY_COLUMN_DOES_NOT_EXITS, "42000", "S1009", +ER_BLOB_USED_AS_KEY, "42000", "S1009", +ER_TOO_BIG_FIELDLENGTH, "42000", "S1009", +ER_WRONG_AUTO_KEY, "42000", "S1009", +ER_FORCING_CLOSE, "08S01", "", +ER_IPSOCK_ERROR, "088S01", "", +ER_NO_SUCH_INDEX, "42S12", "S1009", +ER_WRONG_FIELD_TERMINATORS, "42000", "S1009", +ER_BLOBS_AND_NO_TERMINATED, "42000", "S1009", +ER_CANT_REMOVE_ALL_FIELDS, "42000", "", +ER_CANT_DROP_FIELD_OR_KEY, "42000", "", +ER_BLOB_CANT_HAVE_DEFAULT, "42000", "", +ER_WRONG_DB_NAME, "42000", "", +ER_WRONG_TABLE_NAME, "42000", "", +ER_TOO_BIG_SELECT, "42000", "", +ER_UNKNOWN_PROCEDURE, "42000", "", +ER_WRONG_PARAMCOUNT_TO_PROCEDURE, "42000", "", +ER_UNKNOWN_TABLE, "42S02", "", +ER_FIELD_SPECIFIED_TWICE, "42000", "", +ER_UNSUPPORTED_EXTENSION, "42000", "", +ER_TABLE_MUST_HAVE_COLUMNS, "42000", "", +ER_UNKNOWN_CHARACTER_SET, "42000", "", +ER_TOO_BIG_ROWSIZE, "42000", "", +ER_STACK_OVERRUN, "HY000", "", +ER_WRONG_OUTER_JOIN, "42000", "", +ER_NULL_COLUMN_IN_INDEX, "42000", "", +ER_PASSWORD_ANONYMOUS_USER, "42000", "", +ER_PASSWORD_NOT_ALLOWED, "42000", "", +ER_PASSWORD_NO_MATCH, "42000", "", +ER_WRONG_VALUE_COUNT_ON_ROW, "21S01", "", +ER_INVALID_USE_OF_NULL, "42000", "", +ER_REGEXP_ERROR, "42000", "", +ER_MIX_OF_GROUP_FUNC_AND_FIELDS,"42000", "", +ER_NONEXISTING_GRANT, "42000", "", +ER_TABLEACCESS_DENIED_ERROR, "42000", "", +ER_COLUMNACCESS_DENIED_ERROR, "42000", "", +ER_ILLEGAL_GRANT_FOR_TABLE, "42000", "", +ER_GRANT_WRONG_HOST_OR_USER, "42000", "", +ER_NO_SUCH_TABLE, "42S02", "", +ER_NONEXISTING_TABLE_GRANT, "42000", "", +ER_NOT_ALLOWED_COMMAND, "42000", "", +ER_SYNTAX_ERROR, "42000", "", +ER_ABORTING_CONNECTION, "08S01", "", +ER_NET_PACKET_TOO_LARGE, "08S01", "", +ER_NET_READ_ERROR_FROM_PIPE, "08S01", "", +ER_NET_FCNTL_ERROR, "08S01", "", +ER_NET_PACKETS_OUT_OF_ORDER, "08S01", "", +ER_NET_UNCOMPRESS_ERROR, "08S01", "", +ER_NET_READ_ERROR, "08S01", "", +ER_NET_READ_INTERRUPTED, "08S01", "", +ER_NET_ERROR_ON_WRITE, "08S01", "", +ER_NET_WRITE_INTERRUPTED, "08S01", "", +ER_TOO_LONG_STRING, "42000", "", +ER_TABLE_CANT_HANDLE_BLOB, "42000", "", +ER_TABLE_CANT_HANDLE_AUTO_INCREMENT, "42000", "", +ER_WRONG_COLUMN_NAME, "42000", "", +ER_WRONG_KEY_COLUMN, "42000", "", +ER_DUP_UNIQUE, "23000", "", +ER_BLOB_KEY_WITHOUT_LENGTH, "42000", "", +ER_PRIMARY_CANT_HAVE_NULL, "42000", "", +ER_TOO_MANY_ROWS, "42000", "", +ER_REQUIRES_PRIMARY_KEY, "42000", "", +ER_CHECK_NO_SUCH_TABLE, "42000", "", +ER_CHECK_NOT_IMPLEMENTED, "42000", "", +ER_CANT_DO_THIS_DURING_AN_TRANSACTION, "25000", "", +ER_ERROR_DURING_COMMIT, "HY000", "", +ER_ERROR_DURING_ROLLBACK, "HY000", "", +ER_NEW_ABORTING_CONNECTION, "08S01", "", +ER_MASTER_NET_READ, "08S01", "", +ER_MASTER_NET_WRITE, "08S01", "", +ER_TOO_MANY_USER_CONNECTIONS, "42000", "", +ER_READ_ONLY_TRANSACTION, "25000", "", +ER_NO_PERMISSION_TO_CREATE_USER,"42000", "", +ER_LOCK_DEADLOCK, "40001", "", +ER_NO_REFERENCED_ROW, "23000", "", +ER_ROW_IS_REFERENCED, "23000", "", +ER_CONNECT_TO_MASTER, "08S01", "", +ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,"21000", "", +ER_USER_LIMIT_REACHED, "42000", "", +ER_NO_DEFAULT, "42000", "", +ER_WRONG_VALUE_FOR_VAR, "42000", "", +ER_WRONG_TYPE_FOR_VAR, "42000", "", +ER_CANT_USE_OPTION_HERE, "42000", "", +ER_NOT_SUPPORTED_YET, "42000", "", +ER_WRONG_FK_DEF, "42000", "", +ER_CARDINALITY_COL, "21000", "", +ER_SUBSELECT_NO_1_ROW, "21000", "", +ER_ILLEGAL_REFERENCE, "42S22", "", +ER_DERIVED_MUST_HAVE_ALIAS, "42000", "", +ER_SELECT_REDUCED, "01000", "", +ER_TABLENAME_NOT_ALLOWED_HERE, "42000", "", +ER_NOT_SUPPORTED_AUTH_MODE, "08004", "", +ER_SPATIAL_CANT_HAVE_NULL, "42000", "", +ER_COLLATION_CHARSET_MISMATCH, "42000", "", +ER_WARN_TOO_FEW_RECORDS, "01000", "", +ER_WARN_TOO_MANY_RECORDS, "01000", "", +ER_WARN_NULL_TO_NOTNULL, "01000", "", +ER_WARN_DATA_OUT_OF_RANGE, "01000", "", +ER_WARN_DATA_TRUNCATED, "01000", "", diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 514de2a87a6..c28ee6bbfed 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -64,7 +64,8 @@ ulong net_buffer_length=8192; ulong max_allowed_packet= 1024L*1024L*1024L; ulong net_read_timeout= NET_READ_TIMEOUT; ulong net_write_timeout= NET_WRITE_TIMEOUT; -const char *unknown_sqlstate= "000000"; +const char *unknown_sqlstate= "HY000"; +const char *not_error_sqlstate= "00000"; #define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG \ | CLIENT_LOCAL_FILES | CLIENT_TRANSACTIONS \ @@ -91,9 +92,9 @@ const char *def_shared_memory_base_name=default_shared_memory_base_name; #endif const char *sql_protocol_names_lib[] = -{ "TCP", "SOCKET", "PIPE", "MEMORY",NullS }; +{ "TCP", "SOCKET", "PIPE", "MEMORY", NullS }; TYPELIB sql_protocol_typelib = {array_elements(sql_protocol_names_lib)-1,"", - sql_protocol_names_lib}; + sql_protocol_names_lib}; /* If allowed through some configuration, then this needs to be changed @@ -141,16 +142,16 @@ void STDCALL mysql_server_end() my_bool STDCALL mysql_thread_init() { #ifdef THREAD - return my_thread_init(); + return my_thread_init(); #else - return 0; + return 0; #endif } void STDCALL mysql_thread_end() { #ifdef THREAD - my_thread_end(); + my_thread_end(); #endif } @@ -160,7 +161,7 @@ void STDCALL mysql_thread_end() */ #if !defined(__WIN__) && defined(SIGPIPE) && !defined(THREAD) -#define init_sigpipe_variables sig_return old_signal_handler=(sig_return) 0; +#define init_sigpipe_variables sig_return old_signal_handler=(sig_return) 0 #define set_sigpipe(mysql) if ((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE) old_signal_handler=signal(SIGPIPE,pipe_sig_handler) #define reset_sigpipe(mysql) if ((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE) signal(SIGPIPE,old_signal_handler); #else @@ -409,13 +410,14 @@ HANDLE create_shared_memory(MYSQL *mysql,NET *net, uint connect_timeout) DWORD error_code = 0; char *shared_memory_base_name = mysql->options.shared_memory_base_name; -/* - The name of event and file-mapping events create agree next rule: - shared_memory_base_name+unique_part - Where: + /* + The name of event and file-mapping events create agree next rule: + shared_memory_base_name+unique_part + + Where: shared_memory_base_name is unique value for each server unique_part is uniquel value for each object (events and file-mapping) -*/ + */ suffix_pos = strxmov(tmp,shared_memory_base_name,"_",NullS); strmov(suffix_pos, "CONNECT_REQUEST"); if (!(event_connect_request= OpenEvent(EVENT_ALL_ACCESS,FALSE,tmp))) @@ -441,36 +443,34 @@ HANDLE create_shared_memory(MYSQL *mysql,NET *net, uint connect_timeout) error_allow = CR_SHARED_MEMORY_CONNECT_MAP_ERROR; goto err; } - /* - Send to server request of connection - */ + + /* Send to server request of connection */ if (!SetEvent(event_connect_request)) { error_allow = CR_SHARED_MEMORY_CONNECT_SET_ERROR; goto err; } - /* - Wait of answer from server - */ + + /* Wait of answer from server */ if (WaitForSingleObject(event_connect_answer,connect_timeout*1000) != WAIT_OBJECT_0) { error_allow = CR_SHARED_MEMORY_CONNECT_ABANDODED_ERROR; goto err; } - /* - Get number of connection - */ + + /* Get number of connection */ connect_number = uint4korr(handle_connect_map);/*WAX2*/ p= int2str(connect_number, connect_number_char, 10); /* The name of event and file-mapping events create agree next rule: shared_memory_base_name+unique_part+number_of_connection + Where: - shared_memory_base_name is uniquel value for each server - unique_part is uniquel value for each object (events and file-mapping) - number_of_connection is number of connection between server and client + shared_memory_base_name is uniquel value for each server + unique_part is uniquel value for each object (events and file-mapping) + number_of_connection is number of connection between server and client */ suffix_pos = strxmov(tmp,shared_memory_base_name,"_",connect_number_char, "_",NullS); @@ -579,7 +579,7 @@ net_safe_read(MYSQL *mysql) { NET *net= &mysql->net; ulong len=0; - init_sigpipe_variables + init_sigpipe_variables; /* Don't give sigpipe errors if the client doesn't want them */ set_sigpipe(mysql); @@ -645,7 +645,7 @@ advanced_command(MYSQL *mysql, enum enum_server_command command, { NET *net= &mysql->net; my_bool result= 1; - init_sigpipe_variables + init_sigpipe_variables; /* Don't give sigpipe errors if the client doesn't want them */ set_sigpipe(mysql); @@ -663,8 +663,8 @@ advanced_command(MYSQL *mysql, enum enum_server_command command, } net->last_error[0]=0; - net->last_errno=0; - strmov(net->sqlstate, unknown_sqlstate); + net->last_errno= 0; + strmov(net->sqlstate, not_error_sqlstate); mysql->info=0; mysql->affected_rows= ~(my_ulonglong) 0; net_clear(&mysql->net); /* Clear receive buffer */ @@ -695,7 +695,7 @@ advanced_command(MYSQL *mysql, enum enum_server_command command, if (!skip_check) result= ((mysql->packet_length=net_safe_read(mysql)) == packet_error ? 1 : 0); - end: +end: reset_sigpipe(mysql); return result; } @@ -870,7 +870,7 @@ end_server(MYSQL *mysql) DBUG_ENTER("end_server"); if (mysql->net.vio != 0) { - init_sigpipe_variables + init_sigpipe_variables; DBUG_PRINT("info",("Net: %s", vio_description(mysql->net.vio))); set_sigpipe(mysql); vio_delete(mysql->net.vio); @@ -1402,7 +1402,7 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths) /* perform query on master */ my_bool STDCALL mysql_master_query(MYSQL *mysql, const char *q, - unsigned long length) + unsigned long length) { DBUG_ENTER("mysql_master_query"); if (mysql_master_send_query(mysql, q, length)) @@ -1449,7 +1449,7 @@ my_bool STDCALL mysql_slave_send_query(MYSQL *mysql, const char *q, */ mysql->last_used_con = mysql->last_used_slave = slave_to_use; if (!slave_to_use->net.vio && !mysql_real_connect(slave_to_use, 0,0,0, - 0,0,0,0)) + 0,0,0,0)) DBUG_RETURN(1); DBUG_RETURN(simple_command(slave_to_use, COM_QUERY, q, length, 1)); } @@ -1586,7 +1586,7 @@ static my_bool get_slaves_from_master(MYSQL* mysql) } if (!(slave = spawn_init(mysql, row[1], atoi(row[port_ind]), - tmp_user, tmp_pass))) + tmp_user, tmp_pass))) goto err; /* Now add slave into the circular linked list */ @@ -1596,7 +1596,7 @@ static my_bool get_slaves_from_master(MYSQL* mysql) error = 0; err: if (res) - mysql_free_result(res); + mysql_free_result(res); DBUG_RETURN(error); } @@ -1966,7 +1966,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, #ifdef HAVE_SYS_UN_H struct sockaddr_un UNIXaddr; #endif - init_sigpipe_variables + init_sigpipe_variables; DBUG_ENTER("mysql_real_connect"); LINT_INIT(host_info); @@ -2529,7 +2529,7 @@ static my_bool mysql_reconnect(MYSQL *mysql) if (!mysql->reconnect || (mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info) { - /* Allow reconnect next time */ + /* Allow reconnect next time */ mysql->server_status&= ~SERVER_STATUS_IN_TRANS; strmov(mysql->net.sqlstate, unknown_sqlstate); mysql->net.last_errno=CR_SERVER_GONE_ERROR; @@ -2575,7 +2575,7 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, if (!passwd) passwd=""; - /* Store user into the buffer */ + /* Store user into the buffer */ end=strmov(end,user)+1; /* @@ -2592,15 +2592,15 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, *end=0; } - else /* For empty password*/ - *end=0; /* Store zero length scramble */ + else /* For empty password */ + *end=0; /* zero length scramble */ } else { - /* - Real scramble is only sent to old servers. This can be blocked - by calling mysql_options(MYSQL *, MYSQL_SECURE_CONNECT, (char*) &1); - */ + /* + Real scramble is only sent to old servers. This can be blocked + by calling mysql_options(MYSQL *, MYSQL_SECURE_CONNECT, (char*) &1); + */ end=scramble(end, mysql->scramble_buff, passwd, (my_bool) (mysql->protocol_version == 9)); } @@ -2793,9 +2793,9 @@ STDCALL mysql_set_master(MYSQL* mysql, const char* host, int STDCALL mysql_add_slave(MYSQL* mysql, const char* host, - unsigned int port, - const char* user, - const char* passwd) + unsigned int port, + const char* user, + const char* passwd) { MYSQL* slave; if (!(slave = spawn_init(mysql, host, port, user, passwd))) @@ -3670,7 +3670,7 @@ mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to, if (use_mb_flag && (l = my_ismbchar(charset_info, from, end))) { while (l--) - *to++ = *from++; + *to++ = *from++; from--; continue; } @@ -4045,13 +4045,15 @@ unsigned int alloc_stmt_fields(MYSQL_STMT *stmt) like SHOW and DESCRIBE commands */ if (!(stmt->fields= (MYSQL_FIELD *) alloc_root(alloc, - sizeof(MYSQL_FIELD) * stmt->field_count)) || + sizeof(MYSQL_FIELD) * + stmt->field_count)) || !(stmt->bind= (MYSQL_BIND *) alloc_root(alloc, - sizeof(MYSQL_BIND ) * stmt->field_count))) + sizeof(MYSQL_BIND) * + stmt->field_count))) return 0; for (fields= mysql->fields, end= fields+stmt->field_count, - field= stmt->fields; + field= stmt->fields; field && fields < end; fields++, field++) { field->db = strdup_root(alloc,fields->db); @@ -4781,7 +4783,7 @@ static void send_data_long(MYSQL_BIND *param, longlong value) { char *buffer= param->buffer; - switch(param->buffer_type) { + switch (param->buffer_type) { case MYSQL_TYPE_NULL: /* do nothing */ break; case MYSQL_TYPE_TINY: @@ -4797,33 +4799,34 @@ static void send_data_long(MYSQL_BIND *param, longlong value) int8store(buffer, value); break; case MYSQL_TYPE_FLOAT: - { - float data= (float)value; - float4store(buffer, data); - break; - } + { + float data= (float)value; + float4store(buffer, data); + break; + } case MYSQL_TYPE_DOUBLE: - { - double data= (double)value; - float8store(buffer, data); - break; - } + { + double data= (double)value; + float8store(buffer, data); + break; + } default: - { - char tmp[NAME_LEN]; - uint length= (uint)(longlong10_to_str(value,(char *)tmp,10)-tmp); - ulong copy_length= min((ulong)length-param->offset, param->buffer_length); - memcpy(buffer, (char *)tmp+param->offset, copy_length); - *param->length= length; + { + char tmp[NAME_LEN]; + uint length= (uint)(longlong10_to_str(value,(char *)tmp,10)-tmp); + ulong copy_length= min((ulong)length-param->offset, param->buffer_length); + memcpy(buffer, (char *)tmp+param->offset, copy_length); + *param->length= length; - if (copy_length != param->buffer_length) - *(buffer+copy_length)= '\0'; - } - } + if (copy_length != param->buffer_length) + *(buffer+copy_length)= '\0'; + } + } } /* Convert Double to buffer types */ + static void send_data_double(MYSQL_BIND *param, double value) { char *buffer= param->buffer; @@ -4969,7 +4972,7 @@ static void send_data_time(MYSQL_BIND *param, MYSQL_TIME ltime, switch (ltime.time_type) { case MYSQL_TIMESTAMP_DATE: length= my_sprintf(buff,(buff, "%04d-%02d-%02d", ltime.year, - ltime.month,ltime.day)); + ltime.month,ltime.day)); break; case MYSQL_TIMESTAMP_FULL: length= my_sprintf(buff,(buff, "%04d-%02d-%02d %02d:%02d:%02d", @@ -4978,7 +4981,7 @@ static void send_data_time(MYSQL_BIND *param, MYSQL_TIME ltime, break; case MYSQL_TIMESTAMP_TIME: length= my_sprintf(buff, (buff, "%02d:%02d:%02d", - ltime.hour,ltime.minute,ltime.second)); + ltime.hour,ltime.minute,ltime.second)); break; default: length= 0; @@ -4990,8 +4993,8 @@ static void send_data_time(MYSQL_BIND *param, MYSQL_TIME ltime, } - /* Fetch data to buffers */ + static void fetch_results(MYSQL_BIND *param, uint field_type, uchar **row, my_bool field_is_unsigned) { @@ -5001,8 +5004,8 @@ static void fetch_results(MYSQL_BIND *param, uint field_type, uchar **row, case MYSQL_TYPE_TINY: { char value= (char) **row; - longlong data= (field_is_unsigned) ? (longlong) (unsigned char) value: - (longlong) value; + longlong data= ((field_is_unsigned) ? (longlong) (unsigned char) value: + (longlong) value); send_data_long(param,data); length= 1; break; @@ -5011,8 +5014,8 @@ static void fetch_results(MYSQL_BIND *param, uint field_type, uchar **row, case MYSQL_TYPE_YEAR: { short value= sint2korr(*row); - longlong data= (field_is_unsigned) ? (longlong) (unsigned short) value: - (longlong) value; + longlong data= ((field_is_unsigned) ? (longlong) (unsigned short) value: + (longlong) value); send_data_long(param,data); length= 2; break; @@ -5020,8 +5023,8 @@ static void fetch_results(MYSQL_BIND *param, uint field_type, uchar **row, case MYSQL_TYPE_LONG: { long value= sint4korr(*row); - longlong data= (field_is_unsigned) ? (longlong) (unsigned long) value: - (longlong) value; + longlong data= ((field_is_unsigned) ? (longlong) (unsigned long) value: + (longlong) value); send_data_long(param,data); length= 4; break; @@ -5316,8 +5319,8 @@ static int stmt_fetch_row(MYSQL_STMT *stmt, uchar *row) /* Copy complete row to application buffers */ for (bind= stmt->bind, end= (MYSQL_BIND *) bind + stmt->field_count, - field= stmt->fields, - field_end= (MYSQL_FIELD *)stmt->fields+stmt->field_count; + field= stmt->fields, + field_end= (MYSQL_FIELD *)stmt->fields+stmt->field_count; bind < end && field < field_end; bind++, field++) { @@ -5509,7 +5512,7 @@ no_data: } -/* +/* Read all rows of data from server (binary format) */ @@ -5578,6 +5581,7 @@ static MYSQL_DATA *read_binary_rows(MYSQL_STMT *stmt) DBUG_RETURN(result); } + /* Store or buffer the binary results to stmt */ @@ -5599,9 +5603,9 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt) } mysql->status= MYSQL_STATUS_READY; /* server is ready */ if (!(result= (MYSQL_RES*) my_malloc((uint) (sizeof(MYSQL_RES)+ - sizeof(ulong) * - stmt->field_count), - MYF(MY_WME | MY_ZEROFILL)))) + sizeof(ulong) * + stmt->field_count), + MYF(MY_WME | MY_ZEROFILL)))) { set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate); DBUG_RETURN(1); @@ -5620,6 +5624,7 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt) DBUG_RETURN(0); /* Data buffered, must be fetched with mysql_fetch() */ } + /* Seek to desired row in the statement result set */ @@ -5642,6 +5647,7 @@ mysql_stmt_row_seek(MYSQL_STMT *stmt, MYSQL_ROW_OFFSET row) DBUG_RETURN(0); } + /* Return the current statement row cursor position */ @@ -5842,16 +5848,16 @@ my_bool STDCALL mysql_autocommit(MYSQL * mysql, my_bool auto_mode) my_bool STDCALL mysql_more_results(MYSQL *mysql) { - my_bool result; + my_bool res; DBUG_ENTER("mysql_more_results"); - result= (mysql->last_used_con->server_status & SERVER_MORE_RESULTS_EXISTS) ? - 1: 0; - - DBUG_PRINT("exit",("More results exists ? %d", result)); - DBUG_RETURN(result); + res= ((mysql->last_used_con->server_status & SERVER_MORE_RESULTS_EXISTS) ? + 1: 0); + DBUG_PRINT("exit",("More results exists ? %d", res)); + DBUG_RETURN(res); } + /* Reads and returns the next query results */ @@ -5862,7 +5868,7 @@ my_bool STDCALL mysql_next_result(MYSQL *mysql) mysql->net.last_error[0]= 0; mysql->net.last_errno= 0; - strmov(mysql->net.sqlstate, unknown_sqlstate); + strmov(mysql->net.sqlstate, not_error_sqlstate); mysql->affected_rows= ~(my_ulonglong) 0; if (mysql->last_used_con->server_status & SERVER_MORE_RESULTS_EXISTS) diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index 93702e5b6d0..48055ff6050 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -44,7 +44,8 @@ sqlsources = derror.cc field.cc field_conv.cc filesort.cc \ item_func.cc item_strfunc.cc item_sum.cc item_timefunc.cc \ item_uniq.cc item_subselect.cc item_row.cc\ key.cc lock.cc log.cc log_event.cc mf_iocache.cc\ - mini_client.cc protocol.cc net_serv.cc opt_ft.cc opt_range.cc \ + mini_client.cc protocol.cc net_serv.cc sql_state.c \ + opt_ft.cc opt_range.cc \ opt_sum.cc procedure.cc records.cc sql_acl.cc \ repl_failsafe.cc slave.cc sql_load.cc sql_olap.cc \ sql_analyse.cc sql_base.cc sql_cache.cc sql_class.cc \ diff --git a/libmysqld/libmysqld.c b/libmysqld/libmysqld.c index e6166f6bbe5..a2d69b30c0d 100644 --- a/libmysqld/libmysqld.c +++ b/libmysqld/libmysqld.c @@ -450,6 +450,7 @@ static inline int mysql_init_charset(MYSQL *mysql) if (!mysql->charset) { mysql->last_errno=CR_CANT_READ_CHARSET; + strmov(mysql->sqlstate, "HY0000"); if (mysql->options.charset_dir) sprintf(mysql->last_error,ER(mysql->last_errno), charset_name ? charset_name : "unknown", @@ -1130,6 +1131,7 @@ mysql_stat(MYSQL *mysql) if (!mysql->net.read_pos[0]) { mysql->net.last_errno=CR_WRONG_HOST_INFO; + strmov(mysql->sqlstate, unknown_sqlstate); strmov(mysql->net.last_error, ER(mysql->net.last_errno)); return mysql->net.last_error; } @@ -1284,12 +1286,12 @@ unsigned int STDCALL mysql_field_count(MYSQL *mysql) my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql) { - return (mysql)->affected_rows; + return mysql->affected_rows; } my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql) { - return (mysql)->insert_id; + return mysql->insert_id; } uint STDCALL mysql_errno(MYSQL *mysql) @@ -1297,6 +1299,11 @@ uint STDCALL mysql_errno(MYSQL *mysql) return mysql->last_errno; } +const char *STDCALL mysql_sqlstate(MYSQL *mysql) +{ + return mysql->sqlstate; +} + const char * STDCALL mysql_error(MYSQL *mysql) { return mysql->last_error; diff --git a/mysql-test/r/analyse.result b/mysql-test/r/analyse.result index 60764494417..f18b925460c 100644 --- a/mysql-test/r/analyse.result +++ b/mysql-test/r/analyse.result @@ -6,26 +6,26 @@ Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_ count(*) 4 4 1 1 0 0 4.0000 0.0000 ENUM('4') NOT NULL select * from t1 procedure analyse(); Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype -t1.i 1 7 1 1 0 0 4.0000 2.2361 ENUM('1','3','5','7') NOT NULL -t1.j 2 8 1 1 0 0 5.0000 2.2361 ENUM('2','4','6','8') NOT NULL -t1.empty_string 0 0 4 0 0.0000 NULL CHAR(0) NOT NULL -t1.bool N Y 1 1 0 0 1.0000 NULL ENUM('N','Y') NOT NULL -t1.d 2002-03-03 2002-03-05 10 10 0 0 10.0000 NULL ENUM('2002-03-03','2002-03-04','2002-03-05') NOT NULL +test.t1.i 1 7 1 1 0 0 4.0000 2.2361 ENUM('1','3','5','7') NOT NULL +test.t1.j 2 8 1 1 0 0 5.0000 2.2361 ENUM('2','4','6','8') NOT NULL +test.t1.empty_string 0 0 4 0 0.0000 NULL CHAR(0) NOT NULL +test.t1.bool N Y 1 1 0 0 1.0000 NULL ENUM('N','Y') NOT NULL +test.t1.d 2002-03-03 2002-03-05 10 10 0 0 10.0000 NULL ENUM('2002-03-03','2002-03-04','2002-03-05') NOT NULL select * from t1 procedure analyse(2); Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype -t1.i 1 7 1 1 0 0 4.0000 2.2361 TINYINT(1) UNSIGNED NOT NULL -t1.j 2 8 1 1 0 0 5.0000 2.2361 TINYINT(1) UNSIGNED NOT NULL -t1.empty_string 0 0 4 0 0.0000 NULL CHAR(0) NOT NULL -t1.bool N Y 1 1 0 0 1.0000 NULL ENUM('N','Y') NOT NULL -t1.d 2002-03-03 2002-03-05 10 10 0 0 10.0000 NULL ENUM('2002-03-03','2002-03-04','2002-03-05') NOT NULL +test.t1.i 1 7 1 1 0 0 4.0000 2.2361 TINYINT(1) UNSIGNED NOT NULL +test.t1.j 2 8 1 1 0 0 5.0000 2.2361 TINYINT(1) UNSIGNED NOT NULL +test.t1.empty_string 0 0 4 0 0.0000 NULL CHAR(0) NOT NULL +test.t1.bool N Y 1 1 0 0 1.0000 NULL ENUM('N','Y') NOT NULL +test.t1.d 2002-03-03 2002-03-05 10 10 0 0 10.0000 NULL ENUM('2002-03-03','2002-03-04','2002-03-05') NOT NULL create table t2 select * from t1 procedure analyse(); select * from t2; Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype -t1.i 1 7 1 1 0 0 4.0000 2.2361 ENUM('1','3','5','7') NOT NULL -t1.j 2 8 1 1 0 0 5.0000 2.2361 ENUM('2','4','6','8') NOT NULL -t1.empty_string 0 0 4 0 0.0000 NULL CHAR(0) NOT NULL -t1.bool N Y 1 1 0 0 1.0000 NULL ENUM('N','Y') NOT NULL -t1.d 2002-03-03 2002-03-05 10 10 0 0 10.0000 NULL ENUM('2002-03-03','2002-03-04','2002-03-05') NOT NULL +test.t1.i 1 7 1 1 0 0 4.0000 2.2361 ENUM('1','3','5','7') NOT NULL +test.t1.j 2 8 1 1 0 0 5.0000 2.2361 ENUM('2','4','6','8') NOT NULL +test.t1.empty_string 0 0 4 0 0.0000 NULL CHAR(0) NOT NULL +test.t1.bool N Y 1 1 0 0 1.0000 NULL ENUM('N','Y') NOT NULL +test.t1.d 2002-03-03 2002-03-05 10 10 0 0 10.0000 NULL ENUM('2002-03-03','2002-03-04','2002-03-05') NOT NULL drop table t1,t2; EXPLAIN SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(); id select_type table type possible_keys key key_len ref rows Extra diff --git a/mysql-test/r/ansi.result b/mysql-test/r/ansi.result index f9f96310b73..6ec909f84bb 100644 --- a/mysql-test/r/ansi.result +++ b/mysql-test/r/ansi.result @@ -6,5 +6,13 @@ CREATE TABLE t1 (id INT, id2 int); SELECT id,NULL,1,1.1,'a' FROM t1 GROUP BY id; id NULL 1 1.1 a SELECT id FROM t1 GROUP BY id2; -'t1.id' isn't in GROUP BY +ERROR 42000: 'test.t1.id' isn't in GROUP BY drop table t1; +set sql_mode="MySQL40"; +select @@sql_mode; +@@sql_mode +NO_FIELD_OPTIONS,MYSQL40 +set sql_mode="ANSI"; +select @@sql_mode; +@@sql_mode +REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ONLY_FULL_GROUP_BY,ANSI diff --git a/mysql-test/r/auto_increment.result b/mysql-test/r/auto_increment.result index c993a47198a..bd15c913d2e 100644 --- a/mysql-test/r/auto_increment.result +++ b/mysql-test/r/auto_increment.result @@ -112,7 +112,7 @@ select last_insert_id(); last_insert_id() 255 insert into t1 set i = null; -Duplicate entry '255' for key 1 +ERROR 23000: Duplicate entry '255' for key 1 select last_insert_id(); last_insert_id() 255 @@ -140,7 +140,7 @@ select last_insert_id(); last_insert_id() 2 insert into t1 values (NULL, 10); -Duplicate entry '10' for key 2 +ERROR 23000: Duplicate entry '10' for key 2 select last_insert_id(); last_insert_id() 3 diff --git a/mysql-test/r/bdb-deadlock.result b/mysql-test/r/bdb-deadlock.result index 55b3d3ea2a5..6606b0d9b38 100644 --- a/mysql-test/r/bdb-deadlock.result +++ b/mysql-test/r/bdb-deadlock.result @@ -9,7 +9,7 @@ set autocommit=0; update t2 set x = 1 where id = 0; select x from t1 where id = 0; select x from t2 where id = 0; -Deadlock found when trying to get lock; Try restarting transaction +ERROR 40001: Deadlock found when trying to get lock; Try restarting transaction commit; x 1 diff --git a/mysql-test/r/bdb.result b/mysql-test/r/bdb.result index 7f0612a011f..b0566011996 100644 --- a/mysql-test/r/bdb.result +++ b/mysql-test/r/bdb.result @@ -48,7 +48,7 @@ id parent_id level 15 102 2 update t1 set id=id+1000; update t1 set id=1024 where id=1009; -Duplicate entry '1024' for key 1 +ERROR 23000: Duplicate entry '1024' for key 1 select * from t1; id parent_id level 1001 100 0 @@ -270,7 +270,7 @@ n after commit commit; insert into t1 values (5); insert into t1 values (4); -Duplicate entry '4' for key 1 +ERROR 23000: Duplicate entry '4' for key 1 commit; select n, "after commit" from t1; n after commit @@ -279,7 +279,7 @@ n after commit set autocommit=1; insert into t1 values (6); insert into t1 values (4); -Duplicate entry '4' for key 1 +ERROR 23000: Duplicate entry '4' for key 1 select n from t1; n 4 @@ -309,7 +309,7 @@ drop table t1; CREATE TABLE t1 (id char(8) not null primary key, val int not null) type=bdb; insert into t1 values ('pippo', 12); insert into t1 values ('pippo', 12); -Duplicate entry 'pippo' for key 1 +ERROR 23000: Duplicate entry 'pippo' for key 1 delete from t1; delete from t1 where id = 'pippo'; select * from t1; @@ -464,9 +464,9 @@ UNIQUE ggid (ggid) insert into t1 (ggid,passwd) values ('test1','xxx'); insert into t1 (ggid,passwd) values ('test2','yyy'); insert into t1 (ggid,passwd) values ('test2','this will fail'); -Duplicate entry 'test2' for key 2 +ERROR 23000: Duplicate entry 'test2' for key 2 insert into t1 (ggid,id) values ('this will fail',1); -Duplicate entry '1' for key 1 +ERROR 23000: Duplicate entry '1' for key 1 select * from t1 where ggid='test1'; id ggid email passwd 1 test1 xxx @@ -479,7 +479,7 @@ id ggid email passwd replace into t1 (ggid,id) values ('this will work',1); replace into t1 (ggid,passwd) values ('test2','this will work'); update t1 set id=100,ggid='test2' where id=1; -Duplicate entry 'test2' for key 2 +ERROR 23000: Duplicate entry 'test2' for key 2 select * from t1; id ggid email passwd 1 this will work @@ -1008,7 +1008,7 @@ create table t1 (id int NOT NULL,id2 int NOT NULL,id3 int NOT NULL,dummy1 char(3 insert into t1 values (0,0,0,'ABCDEFGHIJ'),(2,2,2,'BCDEFGHIJK'),(1,1,1,'CDEFGHIJKL'); LOCK TABLES t1 WRITE; insert into t1 values (99,1,2,'D'),(1,1,2,'D'); -Duplicate entry '1-1' for key 1 +ERROR 23000: Duplicate entry '1-1' for key 1 select id from t1; id 0 @@ -1026,7 +1026,7 @@ insert into t1 values (0,0,0,'ABCDEFGHIJ'),(2,2,2,'BCDEFGHIJK'),(1,1,1,'CDEFGHIJ LOCK TABLES t1 WRITE; begin; insert into t1 values (99,1,2,'D'),(1,1,2,'D'); -Duplicate entry '1-1' for key 1 +ERROR 23000: Duplicate entry '1-1' for key 1 select id from t1; id 0 diff --git a/mysql-test/r/comments.result b/mysql-test/r/comments.result index 8092f789954..a9106ce0538 100644 --- a/mysql-test/r/comments.result +++ b/mysql-test/r/comments.result @@ -6,7 +6,7 @@ multi line comment */; 1 1 ; -Query was empty +ERROR 42000: Query was empty select 1 /*!32301 +1 */; 1 /*!32301 +1 2 diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index bd8343428c2..42a525796a2 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -17,29 +17,29 @@ b drop table t1; create table t2 type=heap select * from t1; -Table 'test.t1' doesn't exist +ERROR 42S02: Table 'test.t1' doesn't exist create table t2 select auto+1 from t1; -Table 'test.t1' doesn't exist +ERROR 42S02: Table 'test.t1' doesn't exist drop table if exists t1,t2; Warnings: Note 1051 Unknown table 't1' Note 1051 Unknown table 't2' create table t1 (b char(0) not null, index(b)); -The used storage engine can't index column 'b' +ERROR 42000: The used storage engine can't index column 'b' create table t1 (a int not null auto_increment,primary key (a)) type=heap; create table t1 (a int not null,b text) type=heap; -The used table type doesn't support BLOB/TEXT columns +ERROR 42000: The used table type doesn't support BLOB/TEXT columns drop table if exists t1; create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid)) type=heap; -Incorrect table definition; There can only be one auto column and it must be defined as a key +ERROR 42000: Incorrect table definition; There can only be one auto column and it must be defined as a key create table not_existing_database.test (a int); Got one of the listed errors create table `a/a` (a int); -Incorrect table name 'a/a' +ERROR 42000: Incorrect table name 'a/a' create table `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa int); -Incorrect table name 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +ERROR 42000: Incorrect table name 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' create table a (`aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` int); -Identifier name 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' is too long +ERROR 42000: Identifier name 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' is too long create table 1ea10 (1a20 int,1e int); insert into 1ea10 values(1,1); select 1ea10.1a20,1e+ 1e+10 from 1ea10; @@ -61,11 +61,11 @@ create table test_$1.test2$ (a int); drop table test_$1.test2$; drop database test_$1; create table `` (a int); -Incorrect table name '' +ERROR 42000: Incorrect table name '' drop table if exists ``; -Incorrect table name '' +ERROR 42000: Incorrect table name '' create table t1 (`` int); -Incorrect column name '' +ERROR 42000: Incorrect column name '' drop table if exists t1; Warnings: Note 1051 Unknown table 't1' @@ -115,17 +115,17 @@ Field Type Collation Null Key Default Extra a int(11) NULL YES NULL drop table if exists t2; create table t2 (a int, a float) select * from t1; -Duplicate column name 'a' +ERROR 42S21: Duplicate column name 'a' drop table if exists t2; Warnings: Note 1051 Unknown table 't2' create table t2 (a int) select a as b, a+1 as b from t1; -Duplicate column name 'b' +ERROR 42S21: Duplicate column name 'b' drop table if exists t2; Warnings: Note 1051 Unknown table 't2' create table t2 (b int) select a as b, a+1 as b from t1; -Duplicate column name 'b' +ERROR 42S21: Duplicate column name 'b' drop table if exists t1,t2; Warnings: Note 1051 Unknown table 't2' @@ -204,11 +204,11 @@ drop table t1; create table t1 ( k1 varchar(2), k2 int, primary key(k1,k2)); insert into t1 values ("a", 1), ("b", 2); insert into t1 values ("c", NULL); -Column 'k2' cannot be null +ERROR 23000: Column 'k2' cannot be null insert into t1 values (NULL, 3); -Column 'k1' cannot be null +ERROR 23000: Column 'k1' cannot be null insert into t1 values (NULL, NULL); -Column 'k1' cannot be null +ERROR 23000: Column 'k1' cannot be null drop table t1; create table t1 (a int, key(a)); create table t2 (b int, foreign key(b) references t1(a), key(b)); @@ -273,15 +273,15 @@ select * from t2; id name create table t3 like t1; create table t3 like test_$1.t3; -Table 't3' already exists +ERROR 42S01: Table 't3' already exists create table non_existing_database.t1 like t1; Got one of the listed errors create table t3 like non_existing_table; -Unknown table 'non_existing_table' +ERROR 42S02: Unknown table 'non_existing_table' create temporary table t3 like t1; -Table 't3' already exists +ERROR 42S01: Table 't3' already exists create table t3 like `a/a`; -Incorrect table name 'a/a' +ERROR 42000: Incorrect table name 'a/a' drop table t1, t2, t3; drop table t3; drop database test_$1; diff --git a/mysql-test/r/ctype_collate.result b/mysql-test/r/ctype_collate.result index d2ae3950eaf..6da7561bb8c 100644 --- a/mysql-test/r/ctype_collate.result +++ b/mysql-test/r/ctype_collate.result @@ -6,7 +6,7 @@ latin1_f CHAR(32) CHARACTER SET latin1 NOT NULL CREATE TABLE t2 ( latin1_f CHAR(32) CHARACTER SET latin1 COLLATE koi8r_general_ci NOT NULL ); -COLLATION 'koi8r_general_ci' is not valid for CHARACTER SET 'latin1' +ERROR 42000: COLLATION 'koi8r_general_ci' is not valid for CHARACTER SET 'latin1' INSERT INTO t1 (latin1_f) VALUES (_latin1'A'); INSERT INTO t1 (latin1_f) VALUES (_latin1'a'); INSERT INTO t1 (latin1_f) VALUES (_latin1'AD'); @@ -180,7 +180,7 @@ z å ü SELECT latin1_f FROM t1 ORDER BY latin1_f COLLATE koi8r_general_ci; -COLLATION 'koi8r_general_ci' is not valid for CHARACTER SET 'latin1' +ERROR 42000: COLLATION 'koi8r_general_ci' is not valid for CHARACTER SET 'latin1' SELECT latin1_f COLLATE latin1_swedish_ci AS latin1_f_as FROM t1 ORDER BY latin1_f_as; latin1_f_as A @@ -298,7 +298,7 @@ z å ü SELECT latin1_f COLLATE koi8r_general_ci AS latin1_f_as FROM t1 ORDER BY latin1_f_as; -COLLATION 'koi8r_general_ci' is not valid for CHARACTER SET 'latin1' +ERROR 42000: COLLATION 'koi8r_general_ci' is not valid for CHARACTER SET 'latin1' SELECT latin1_f,count(*) FROM t1 GROUP BY latin1_f; latin1_f count(*) A 2 @@ -390,7 +390,7 @@ z 1 å 1 ü 1 SELECT latin1_f,count(*) FROM t1 GROUP BY latin1_f COLLATE koi8r_general_ci; -COLLATION 'koi8r_general_ci' is not valid for CHARACTER SET 'latin1' +ERROR 42000: COLLATION 'koi8r_general_ci' is not valid for CHARACTER SET 'latin1' SELECT DISTINCT latin1_f FROM t1; latin1_f A @@ -482,7 +482,7 @@ y Z z SELECT DISTINCT latin1_f COLLATE koi8r FROM t1; -COLLATION 'koi8r' is not valid for CHARACTER SET 'latin1' +ERROR 42000: COLLATION 'koi8r' is not valid for CHARACTER SET 'latin1' SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -524,5 +524,5 @@ SELECT charset('a'),collation('a'),coercibility('a'),'a'='A'; charset('a') collation('a') coercibility('a') 'a'='A' latin1 latin1_swedish_ci 3 1 SET CHARACTER SET 'DEFAULT'; -Unknown character set: 'DEFAULT' +ERROR 42000: Unknown character set: 'DEFAULT' DROP TABLE t1; diff --git a/mysql-test/r/delayed.result b/mysql-test/r/delayed.result index 8e4b52a8366..ceb511a7891 100644 --- a/mysql-test/r/delayed.result +++ b/mysql-test/r/delayed.result @@ -21,7 +21,7 @@ insert delayed into t1 values (1,"b"); insert delayed into t1 values (null,"c"); insert delayed into t1 values (3,"d"),(null,"e"); insert delayed into t1 values (3,"this will give an","error"); -Column count doesn't match value count at row 1 +ERROR 21S01: Column count doesn't match value count at row 1 select * from t1; a b 1 b diff --git a/mysql-test/r/delete.result b/mysql-test/r/delete.result index c87fa8fb927..cd45cf03853 100644 --- a/mysql-test/r/delete.result +++ b/mysql-test/r/delete.result @@ -30,7 +30,7 @@ CREATE TABLE `t1` ( PRIMARY KEY (`i`) ); DELETE FROM t1 USING t1 WHERE post='1'; -Unknown column 'post' in 'where clause' +ERROR 42S22: Unknown column 'post' in 'where clause' drop table t1; CREATE TABLE t1 ( bool char(0) default NULL, diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result index bfd4c544131..5f405d83fa5 100644 --- a/mysql-test/r/derived.result +++ b/mysql-test/r/derived.result @@ -3,9 +3,9 @@ select * from (select 2 from DUAL) b; 2 2 SELECT 1 as a FROM (SELECT 1 UNION SELECT a) b; -Unknown column 'a' in 'field list' +ERROR 42S22: Unknown column 'a' in 'field list' SELECT 1 as a FROM (SELECT a UNION SELECT 1) b; -Unknown column 'a' in 'field list' +ERROR 42S22: Unknown column 'a' in 'field list' CREATE TABLE t1 (a int not null, b char (10) not null); insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c'); CREATE TABLE t2 (a int not null, b char (10) not null); @@ -25,18 +25,18 @@ a y 3 3 3 3 SELECT a FROM (SELECT 1 FROM (SELECT 1) a HAVING a=1) b; -Unknown column 'a' in 'having clause' +ERROR 42S22: Unknown column 'a' in 'having clause' SELECT a,b as a FROM (SELECT '1' as a,'2' as b) b HAVING a=1; -Column: 'a' in having clause is ambiguous +ERROR 23000: Column: 'a' in having clause is ambiguous SELECT a,2 as a FROM (SELECT '1' as a) b HAVING a=2; a a 1 2 SELECT a,2 as a FROM (SELECT '1' as a) b HAVING a=1; a a SELECT 1 FROM (SELECT 1) a WHERE a=2; -Unknown column 'a' in 'where clause' +ERROR 42S22: Unknown column 'a' in 'where clause' SELECT (SELECT 1) as a FROM (SELECT 1 FROM t1 HAVING a=1) as a; -Unknown column 'a' in 'having clause' +ERROR 42S22: Unknown column 'a' in 'having clause' select * from t1 as x1, (select * from t1) as x2; a b a b 1 a 1 a @@ -146,10 +146,17 @@ select * from (select 1 as a) b left join (select 2 as a) c using(a); a a 1 NULL SELECT * FROM (SELECT 1 UNION SELECT a) b; -Unknown column 'a' in 'field list' +ERROR 42S22: Unknown column 'a' in 'field list' SELECT 1 as a FROM (SELECT a UNION SELECT 1) b; -Unknown column 'a' in 'field list' +ERROR 42S22: Unknown column 'a' in 'field list' SELECT 1 as a FROM (SELECT 1 UNION SELECT a) b; -Unknown column 'a' in 'field list' +ERROR 42S22: Unknown column 'a' in 'field list' select 1 from (select 2) a order by 0; -Unknown column '0' in 'order clause' +ERROR 42S22: Unknown column '0' in 'order clause' +create table t1 (id int); +insert into t1 values (1),(2),(3); +describe select * from (select * from t1 group by id) bar; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL NULL NULL NULL NULL 3 +2 DERIVED t1 ALL NULL NULL NULL NULL 3 Using temporary; Using filesort +drop table t1; diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result index 1f459faa8f4..9ebcd1fb915 100644 --- a/mysql-test/r/distinct.result +++ b/mysql-test/r/distinct.result @@ -175,7 +175,7 @@ explain SELECT distinct t3.a FROM t3,t2,t1 WHERE t3.a=t1.b AND t1.a=t2.a; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t3 index a a 5 NULL 6 Using index; Using temporary 1 SIMPLE t2 index a a 4 NULL 5 Using index; Distinct -1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 t2.a 1 Using where; Distinct +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 Using where; Distinct SELECT distinct t3.a FROM t3,t2,t1 WHERE t3.a=t1.b AND t1.a=t2.a; a 1 @@ -190,7 +190,7 @@ insert into t3 select * from t4; explain select distinct t1.a from t1,t3 where t1.a=t3.a; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 2 Using index; Using temporary -1 SIMPLE t3 ref a a 5 t1.a 10 Using where; Using index; Distinct +1 SIMPLE t3 ref a a 5 test.t1.a 10 Using where; Using index; Distinct select distinct t1.a from t1,t3 where t1.a=t3.a; a 1 diff --git a/mysql-test/r/drop.result b/mysql-test/r/drop.result index a9048b65d51..2b878455bea 100644 --- a/mysql-test/r/drop.result +++ b/mysql-test/r/drop.result @@ -1,12 +1,12 @@ drop table if exists t1; drop table t1; -Unknown table 't1' +ERROR 42S02: Unknown table 't1' create table t1(n int); insert into t1 values(1); create temporary table t1( n int); insert into t1 values(2); create table t1(n int); -Table 't1' already exists +ERROR 42S01: Table 't1' already exists drop table t1; select * from t1; n @@ -48,4 +48,4 @@ Database mysql test drop database mysqltest; -Can't drop database 'mysqltest'. Database doesn't exist +ERROR HY000: Can't drop database 'mysqltest'. Database doesn't exist diff --git a/mysql-test/r/err000001.result b/mysql-test/r/err000001.result index 5afecc6d600..d0011c8deb6 100644 --- a/mysql-test/r/err000001.result +++ b/mysql-test/r/err000001.result @@ -1,25 +1,25 @@ drop table if exists t1; insert into t1 values(1); -Table 'test.t1' doesn't exist +ERROR 42S02: Table 'test.t1' doesn't exist delete from t1; -Table 'test.t1' doesn't exist +ERROR 42S02: Table 'test.t1' doesn't exist update t1 set a=1; -Table 'test.t1' doesn't exist +ERROR 42S02: Table 'test.t1' doesn't exist create table t1 (a int); select count(test.t1.b) from t1; -Unknown column 'test.t1.b' in 'field list' +ERROR 42S22: Unknown column 'test.t1.b' in 'field list' select count(not_existing_database.t1) from t1; -Unknown table 'not_existing_database' in field list +ERROR 42S02: Unknown table 'not_existing_database' in field list select count(not_existing_database.t1.a) from t1; -Unknown table 'not_existing_database.t1' in field list +ERROR 42S02: Unknown table 'not_existing_database.t1' in field list select count(not_existing_database.t1.a) from not_existing_database.t1; Got one of the listed errors select 1 from t1 order by 2; -Unknown column '2' in 'order clause' +ERROR 42S22: Unknown column '2' in 'order clause' select 1 from t1 group by 2; -Unknown column '2' in 'group statement' +ERROR 42S22: Unknown column '2' in 'group statement' select 1 from t1 order by t1.b; -Unknown column 't1.b' in 'order clause' +ERROR 42S22: Unknown column 't1.b' in 'order clause' select count(*),b from t1; -Unknown column 'b' in 'field list' +ERROR 42S22: Unknown column 'b' in 'field list' drop table t1; diff --git a/mysql-test/r/explain.result b/mysql-test/r/explain.result index 63e4f4030d3..02e1ace71e1 100644 --- a/mysql-test/r/explain.result +++ b/mysql-test/r/explain.result @@ -24,9 +24,9 @@ explain select * from t1 use key (str,str) where str="foo"; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 const str str 11 const 1 explain select * from t1 use key (str,str,foo) where str="foo"; -Key column 'foo' doesn't exist in table +ERROR 42000: Key column 'foo' doesn't exist in table explain select * from t1 ignore key (str,str,foo) where str="foo"; -Key column 'foo' doesn't exist in table +ERROR 42000: Key column 'foo' doesn't exist in table drop table t1; explain select 1; id select_type table type possible_keys key key_len ref rows Extra diff --git a/mysql-test/r/flush.result b/mysql-test/r/flush.result index 4e7e4769f1b..bab9b543307 100644 --- a/mysql-test/r/flush.result +++ b/mysql-test/r/flush.result @@ -8,7 +8,7 @@ n 3 flush tables with read lock; drop table t2; -Table 't2' was locked with a READ lock and can't be updated +ERROR HY000: Table 't2' was locked with a READ lock and can't be updated drop table t2; unlock tables; create database mysqltest; diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result index 5b410396390..caf93e7e973 100644 --- a/mysql-test/r/fulltext.result +++ b/mysql-test/r/fulltext.result @@ -162,11 +162,11 @@ KEY tig (ticket), fulltext index tix (inhalt) ); select * from t2 where MATCH inhalt AGAINST (t2.inhalt); -Wrong arguments to AGAINST +ERROR HY000: Wrong arguments to AGAINST select * from t2 where MATCH ticket AGAINST ('foobar'); -Can't find FULLTEXT index matching the column list +ERROR HY000: Can't find FULLTEXT index matching the column list select * from t2,t3 where MATCH (t2.inhalt,t3.inhalt) AGAINST ('foobar'); -Wrong arguments to MATCH +ERROR HY000: Wrong arguments to MATCH drop table t1,t2,t3; CREATE TABLE t1 ( id int(11) auto_increment, diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index 0dc84f090f1..51b61dbb3e6 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -155,7 +155,7 @@ show warnings; Level Code Message Warning 1258 1 line(s) was(were) cut by group_concat() select group_concat(sum(a)) from t1 group by grp; -Invalid use of group function +ERROR HY000: Invalid use of group function select grp,group_concat(c order by 2) from t1 group by grp; -Unknown column '2' in 'group statement' +ERROR 42S22: Unknown column '2' in 'group statement' drop table if exists t1; diff --git a/mysql-test/r/func_system.result b/mysql-test/r/func_system.result index 15ff34a6d80..cde21ead33c 100644 --- a/mysql-test/r/func_system.result +++ b/mysql-test/r/func_system.result @@ -37,13 +37,13 @@ version()>=_latin1"3.23.29" select charset(version()); charset(version()) utf8 -create table t1 select database(), user(), version(); +create table t1 (version char(40)) select database(), user(), version() as 'version'; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `database()` char(102) character set utf8 NOT NULL default '', `user()` char(231) character set utf8 NOT NULL default '', - `version()` char(21) character set utf8 NOT NULL default '' + `version` char(40) character set utf8 default NULL ) TYPE=MyISAM CHARSET=latin1 drop table t1; select TRUE,FALSE,NULL; diff --git a/mysql-test/r/grant_cache.result b/mysql-test/r/grant_cache.result index 3892765f587..0ffc48ad879 100644 --- a/mysql-test/r/grant_cache.result +++ b/mysql-test/r/grant_cache.result @@ -84,7 +84,7 @@ a b c a 1 1 1 test.t1 2 2 2 test.t1 select * from t2; -select command denied to user: 'mysqltest_2@localhost' for table 't2' +ERROR 42000: select command denied to user: 'mysqltest_2@localhost' for table 't2' show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 6 @@ -98,17 +98,17 @@ select "user3"; user3 user3 select * from t1; -select command denied to user: 'mysqltest_3@localhost' for column 'b' in table 't1' +ERROR 42000: select command denied to user: 'mysqltest_3@localhost' for column 'b' in table 't1' select a from t1; a 1 2 select c from t1; -SELECT command denied to user: 'mysqltest_3@localhost' for column 'c' in table 't1' +ERROR 42000: SELECT command denied to user: 'mysqltest_3@localhost' for column 'c' in table 't1' select * from t2; -select command denied to user: 'mysqltest_3@localhost' for table 't2' +ERROR 42000: select command denied to user: 'mysqltest_3@localhost' for table 't2' select mysqltest.t1.c from test.t1,mysqltest.t1; -SELECT command denied to user: 'mysqltest_3@localhost' for column 'c' in table 't1' +ERROR 42000: SELECT command denied to user: 'mysqltest_3@localhost' for column 'c' in table 't1' show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 6 @@ -122,7 +122,7 @@ select "user4"; user4 user4 select a from t1; -No Database Selected +ERROR 42000: No Database Selected select * from mysqltest.t1,test.t1; a b c a 1 1 1 test.t1 diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 9e89f2c0e5a..23f82532d06 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -1,6 +1,6 @@ drop table if exists t1,t2,t3; SELECT 1 FROM (SELECT 1) as a GROUP BY SUM(1); -Invalid use of group function +ERROR HY000: Invalid use of group function CREATE TABLE t1 ( spID int(10) unsigned, userID int(10) unsigned, @@ -56,7 +56,7 @@ userid MIN(t1.score+0.0) EXPLAIN SELECT t2.userid, MIN(t1.score+0.0) FROM t1, t2 WHERE t1.userID=t2.userID AND t1.spID=2 GROUP BY t2.userid ORDER BY NULL; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where; Using temporary -1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 t1.userID 1 Using index +1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.userID 1 Using index drop table t1,t2; CREATE TABLE t1 ( PID int(10) unsigned NOT NULL auto_increment, @@ -79,7 +79,7 @@ KEY payDate (payDate) ); INSERT INTO t1 VALUES (1,'1970-01-01','1997-10-17 00:00:00',2529,1,21000,11886,'check',0,'F',16200,6); SELECT COUNT(P.URID),SUM(P.amount),P.method, MIN(PP.recdate+0) > 19980501000000 AS IsNew FROM t1 AS P JOIN t1 as PP WHERE P.URID = PP.URID GROUP BY method,IsNew; -Can't group on 'IsNew' +ERROR 42000: Can't group on 'IsNew' drop table t1; CREATE TABLE t1 ( cid mediumint(9) NOT NULL auto_increment, diff --git a/mysql-test/r/handler.result b/mysql-test/r/handler.result index d8381ccc626..26b3c700d59 100644 --- a/mysql-test/r/handler.result +++ b/mysql-test/r/handler.result @@ -6,7 +6,7 @@ insert into t1 values (20,"ggg"),(21,"hhh"),(22,"iii"); handler t1 open as t2; handler t2 read a=(SELECT 1); -You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near 'SELECT 1)' at line 1 +ERROR 42000: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near 'SELECT 1)' at line 1 handler t2 read a first; a b 14 aaa @@ -51,7 +51,7 @@ handler t2 read a=(16); a b 16 ccc handler t2 read a=(19,"fff"); -Too many key parts specified. Max 1 parts allowed +ERROR 42000: Too many key parts specified. Max 1 parts allowed handler t2 read b=(19,"fff"); a b 19 fff @@ -62,7 +62,7 @@ handler t2 read b=(19); a b 19 fff handler t1 read a last; -Unknown table 't1' in HANDLER +ERROR 42S02: Unknown table 't1' in HANDLER handler t2 read a=(11); a b handler t2 read a>=(11); @@ -135,16 +135,16 @@ handler t2 read next; a b 19 fff handler t2 read last; -You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1 +ERROR 42000: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1 handler t2 close; handler t1 open as t2; drop table t1; create table t1 (a int); insert into t1 values (17); handler t2 read first; -Unknown table 't2' in HANDLER +ERROR 42S02: Unknown table 't2' in HANDLER handler t1 open as t2; alter table t1 type=MyISAM; handler t2 read first; -Unknown table 't2' in HANDLER +ERROR 42S02: Unknown table 't2' in HANDLER drop table t1; diff --git a/mysql-test/r/heap.result b/mysql-test/r/heap.result index ab5870357f9..7d929f50801 100644 --- a/mysql-test/r/heap.result +++ b/mysql-test/r/heap.result @@ -86,7 +86,7 @@ x y x y explain select * from t1,t1 as t2 where t1.x=t2.y; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL x NULL NULL NULL 6 -1 SIMPLE t2 eq_ref y y 4 t1.x 1 +1 SIMPLE t2 eq_ref y y 4 test.t1.x 1 drop table t1; create table t1 (a int) type=heap; insert into t1 values(1); @@ -201,7 +201,7 @@ SELECT * FROM t1 WHERE b<=>NULL; a b 99 NULL INSERT INTO t1 VALUES (1,3); -Duplicate entry '3' for key 1 +ERROR 23000: Duplicate entry '3' for key 1 DROP TABLE t1; CREATE TABLE t1 (a int not null, primary key(a)) type=heap; INSERT into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11); diff --git a/mysql-test/r/heap_btree.result b/mysql-test/r/heap_btree.result index 7f6c9f8e591..6ae00c89a3a 100644 --- a/mysql-test/r/heap_btree.result +++ b/mysql-test/r/heap_btree.result @@ -89,7 +89,7 @@ x y x y explain select * from t1,t1 as t2 where t1.x=t2.y; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL x NULL NULL NULL 6 -1 SIMPLE t2 eq_ref y y 4 t1.x 1 +1 SIMPLE t2 eq_ref y y 4 test.t1.x 1 drop table t1; create table t1 (a int) type=heap; insert into t1 values(1); @@ -217,7 +217,7 @@ SELECT * FROM t1 WHERE b<=>NULL; a b 99 NULL INSERT INTO t1 VALUES (1,3); -Duplicate entry '3' for key 1 +ERROR 23000: Duplicate entry '3' for key 1 DROP TABLE t1; CREATE TABLE t1 (a int, b int, c int, key using BTREE (a, b, c)) type=heap; INSERT INTO t1 VALUES (1, NULL, NULL), (1, 1, NULL), (1, NULL, 1); diff --git a/mysql-test/r/heap_hash.result b/mysql-test/r/heap_hash.result index 9554990aa34..72278c5da67 100644 --- a/mysql-test/r/heap_hash.result +++ b/mysql-test/r/heap_hash.result @@ -86,7 +86,7 @@ x y x y explain select * from t1,t1 as t2 where t1.x=t2.y; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL x NULL NULL NULL 6 -1 SIMPLE t2 eq_ref y y 4 t1.x 1 +1 SIMPLE t2 eq_ref y y 4 test.t1.x 1 drop table t1; create table t1 (a int) type=heap; insert into t1 values(1); @@ -201,7 +201,7 @@ SELECT * FROM t1 WHERE b<=>NULL; a b 99 NULL INSERT INTO t1 VALUES (1,3); -Duplicate entry '3' for key 1 +ERROR 23000: Duplicate entry '3' for key 1 DROP TABLE t1; CREATE TABLE t1 (a int not null, primary key using HASH (a)) type=heap; INSERT into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11); diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 0f65c8b0fe3..77c96a32c73 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -224,7 +224,7 @@ n after commit commit; insert into t1 values (5); insert into t1 values (4); -Duplicate entry '4' for key 1 +ERROR 23000: Duplicate entry '4' for key 1 commit; select n, "after commit" from t1; n after commit @@ -233,7 +233,7 @@ n after commit set autocommit=1; insert into t1 values (6); insert into t1 values (4); -Duplicate entry '4' for key 1 +ERROR 23000: Duplicate entry '4' for key 1 select n from t1; n 4 @@ -263,7 +263,7 @@ drop table t1; CREATE TABLE t1 (id char(8) not null primary key, val int not null) type=innodb; insert into t1 values ('pippo', 12); insert into t1 values ('pippo', 12); -Duplicate entry 'pippo' for key 1 +ERROR 23000: Duplicate entry 'pippo' for key 1 delete from t1; delete from t1 where id = 'pippo'; select * from t1; @@ -427,9 +427,9 @@ UNIQUE ggid (ggid) insert into t1 (ggid,passwd) values ('test1','xxx'); insert into t1 (ggid,passwd) values ('test2','yyy'); insert into t1 (ggid,passwd) values ('test2','this will fail'); -Duplicate entry 'test2' for key 2 +ERROR 23000: Duplicate entry 'test2' for key 2 insert into t1 (ggid,id) values ('this will fail',1); -Duplicate entry '1' for key 1 +ERROR 23000: Duplicate entry '1' for key 1 select * from t1 where ggid='test1'; id ggid email passwd 1 test1 xxx @@ -442,7 +442,7 @@ id ggid email passwd replace into t1 (ggid,id) values ('this will work',1); replace into t1 (ggid,passwd) values ('test2','this will work'); update t1 set id=100,ggid='test2' where id=1; -Duplicate entry 'test2' for key 2 +ERROR 23000: Duplicate entry 'test2' for key 2 select * from t1; id ggid email passwd 1 this will work @@ -753,7 +753,7 @@ create table t1 (id int NOT NULL,id2 int NOT NULL,id3 int NOT NULL,dummy1 char(3 insert into t1 values (0,0,0,'ABCDEFGHIJ'),(2,2,2,'BCDEFGHIJK'),(1,1,1,'CDEFGHIJKL'); LOCK TABLES t1 WRITE; insert into t1 values (99,1,2,'D'),(1,1,2,'D'); -Duplicate entry '1-1' for key 1 +ERROR 23000: Duplicate entry '1-1' for key 1 select id from t1; id 0 @@ -771,7 +771,7 @@ insert into t1 values (0,0,0,'ABCDEFGHIJ'),(2,2,2,'BCDEFGHIJK'),(1,1,1,'CDEFGHIJ LOCK TABLES t1 WRITE; begin; insert into t1 values (99,1,2,'D'),(1,1,2,'D'); -Duplicate entry '1-1' for key 1 +ERROR 23000: Duplicate entry '1-1' for key 1 select id from t1; id 0 @@ -788,7 +788,7 @@ id id3 UNLOCK TABLES; DROP TABLE t1; create table t1 (a char(20), unique (a(5))) type=innodb; -Incorrect sub part key. The used key part isn't a string, the used length is longer than the key part or the store engine doesn't support unique sub keys +ERROR HY000: Incorrect sub part key. The used key part isn't a string, the used length is longer than the key part or the store engine doesn't support unique sub keys create table t1 (a char(20), index (a(5))) type=innodb; show create table t1; Table Create Table @@ -851,7 +851,7 @@ set autocommit=0; create table t1 (a int not null) type= innodb; insert into t1 values(1),(2); truncate table t1; -Can't execute the given command because you have active locked tables or an active transaction +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction commit; truncate table t1; select * from t1; diff --git a/mysql-test/r/innodb_handler.result b/mysql-test/r/innodb_handler.result index 38c39e2936f..1fadc3a61de 100644 --- a/mysql-test/r/innodb_handler.result +++ b/mysql-test/r/innodb_handler.result @@ -49,7 +49,7 @@ handler t2 read a=(16); a b 16 ccc handler t2 read a=(19,"fff"); -Too many key parts specified. Max 1 parts allowed +ERROR 42000: Too many key parts specified. Max 1 parts allowed handler t2 read b=(19,"fff"); a b 19 fff @@ -60,7 +60,7 @@ handler t2 read b=(19); a b 19 fff handler t1 read a last; -Unknown table 't1' in HANDLER +ERROR 42S02: Unknown table 't1' in HANDLER handler t2 read a=(11); a b handler t2 read a>=(11); @@ -130,7 +130,7 @@ handler t2 read next; a b 18 eee handler t2 read last; -You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1 +ERROR 42000: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1 handler t2 close; handler t1 open as t2; handler t2 read first; @@ -138,7 +138,7 @@ a b 17 ddd alter table t1 type=innodb; handler t2 read first; -Unknown table 't2' in HANDLER +ERROR 42S02: Unknown table 't2' in HANDLER drop table t1; CREATE TABLE t1 ( no1 smallint(5) NOT NULL default '0', no2 int(10) NOT NULL default '0', PRIMARY KEY (no1,no2)) TYPE=InnoDB; INSERT INTO t1 VALUES (1,274),(1,275),(2,6),(2,8),(4,1),(4,2); diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result index 9a65eaee573..3325995f2bd 100644 --- a/mysql-test/r/insert_select.result +++ b/mysql-test/r/insert_select.result @@ -4,7 +4,7 @@ insert into t1 (bandID,payoutID) VALUES (1,6),(2,6),(3,4),(4,9),(5,10),(6,1),(7, create table t2 (payoutID SMALLINT UNSIGNED NOT NULL PRIMARY KEY); insert into t2 (payoutID) SELECT DISTINCT payoutID FROM t1; insert into t2 (payoutID) SELECT payoutID+10 FROM t1; -Duplicate entry '16' for key 1 +ERROR 23000: Duplicate entry '16' for key 1 insert ignore into t2 (payoutID) SELECT payoutID+10 FROM t1; select * from t2; payoutID diff --git a/mysql-test/r/insert_update.result b/mysql-test/r/insert_update.result index 068f7c68286..4ef25781331 100644 --- a/mysql-test/r/insert_update.result +++ b/mysql-test/r/insert_update.result @@ -26,7 +26,7 @@ a b c 3 4 1020 5 6 130 INSERT t1 VALUES (1,9,70) ON DUPLICATE KEY UPDATE c=c+100000, b=4; -Duplicate entry '4' for key 2 +ERROR 23000: Duplicate entry '4' for key 2 SELECT * FROM t1; a b c 1 2 10010 diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result index 4bc045aa2f7..05dac389ada 100644 --- a/mysql-test/r/join.result +++ b/mysql-test/r/join.result @@ -128,7 +128,7 @@ a 1 2 select t1.a from t1 as t1 left join t1 as t2 using (a) left join t1 as t3 using (a) left join t1 as t4 using (a) left join t1 as t5 using (a) left join t1 as t6 using (a) left join t1 as t7 using (a) left join t1 as t8 using (a) left join t1 as t9 using (a) left join t1 as t10 using (a) left join t1 as t11 using (a) left join t1 as t12 using (a) left join t1 as t13 using (a) left join t1 as t14 using (a) left join t1 as t15 using (a) left join t1 as t16 using (a) left join t1 as t17 using (a) left join t1 as t18 using (a) left join t1 as t19 using (a) left join t1 as t20 using (a) left join t1 as t21 using (a) left join t1 as t22 using (a) left join t1 as t23 using (a) left join t1 as t24 using (a) left join t1 as t25 using (a) left join t1 as t26 using (a) left join t1 as t27 using (a) left join t1 as t28 using (a) left join t1 as t29 using (a) left join t1 as t30 using (a) left join t1 as t31 using (a) left join t1 as t32 using (a) left join t1 as t33 using (a) left join t1 as t34 using (a) left join t1 as t35 using (a) left join t1 as t36 using (a) left join t1 as t37 using (a) left join t1 as t38 using (a) left join t1 as t39 using (a) left join t1 as t40 using (a) left join t1 as t41 using (a) left join t1 as t42 using (a) left join t1 as t43 using (a) left join t1 as t44 using (a) left join t1 as t45 using (a) left join t1 as t46 using (a) left join t1 as t47 using (a) left join t1 as t48 using (a) left join t1 as t49 using (a) left join t1 as t50 using (a) left join t1 as t51 using (a) left join t1 as t52 using (a) left join t1 as t53 using (a) left join t1 as t54 using (a) left join t1 as t55 using (a) left join t1 as t56 using (a) left join t1 as t57 using (a) left join t1 as t58 using (a) left join t1 as t59 using (a) left join t1 as t60 using (a) left join t1 as t61 using (a) left join t1 as t62 using (a) left join t1 as t63 using (a) left join t1 as t64 using (a) left join t1 as t65 using (a); -Too many tables. MySQL can only use XX tables in a join +ERROR HY000: Too many tables. MySQL can only use XX tables in a join drop table t1; CREATE TABLE t1 ( a int(11) NOT NULL, diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index 123de82fe09..9e494fc88c2 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -95,7 +95,7 @@ id select_type table type possible_keys key key_len ref rows Extra explain select t1.*,t2.* from t1 left join t2 on t1.a=t2.a where isnull(t2.a)=1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 7 -1 SIMPLE t2 eq_ref PRIMARY PRIMARY 8 t1.a 1 Using where +1 SIMPLE t2 eq_ref PRIMARY PRIMARY 8 test.t1.a 1 Using where select t1.*,t2.*,t3.a from t1 left join t2 on (t1.a=t2.a) left join t1 as t3 on (t2.a=t3.a); grp a c id a c d a 1 1 a 1 1 a 1 1 @@ -106,11 +106,11 @@ grp a c id a c d a 3 6 D 3 6 C 6 6 NULL NULL NULL NULL NULL NULL NULL explain select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t1.a=t3.a); -Cross dependency found in OUTER JOIN. Examine your ON conditions +ERROR 42000: Cross dependency found in OUTER JOIN. Examine your ON conditions select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t1.a=t3.a); -Cross dependency found in OUTER JOIN. Examine your ON conditions +ERROR 42000: Cross dependency found in OUTER JOIN. Examine your ON conditions select t1.*,t2.*,t3.a from t1 left join t2 on (t3.a=t2.a) left join t1 as t3 on (t2.a=t3.a); -Cross dependency found in OUTER JOIN. Examine your ON conditions +ERROR 42000: Cross dependency found in OUTER JOIN. Examine your ON conditions select t1.*,t2.* from t1 inner join t2 using (a); grp a c id a c d 1 1 a 1 1 a 1 @@ -169,7 +169,7 @@ usr_id uniq_id increment usr2_id c_amount max 3 4 84676 NULL NULL NULL INSERT INTO t2 VALUES (2,3,3000,6000,0,0,746584,837484,'yes'); INSERT INTO t2 VALUES (2,3,3000,6000,0,0,746584,837484,'yes'); -Duplicate entry '2-3' for key 1 +ERROR 23000: Duplicate entry '2-3' for key 1 INSERT INTO t2 VALUES (7,3,1000,2000,0,0,746294,937484,'yes'); SELECT t1.usr_id,t1.uniq_id,t1.increment,t2.usr2_id,t2.c_amount,t2.max FROM t1 LEFT JOIN t2 ON t2.id = t1.uniq_id WHERE t1.uniq_id = 4 ORDER BY t2.c_amount; usr_id uniq_id increment usr2_id c_amount max @@ -406,7 +406,7 @@ insert into t3 values (1); insert into t4 values (1,1); insert into t5 values (1,1); explain select * from t3 left join t4 on t4.seq_1_id = t2.t2_id left join t1 on t1.t1_id = t4.seq_0_id left join t5 on t5.seq_0_id = t1.t1_id left join t2 on t2.t2_id = t5.seq_1_id where t3.t3_id = 23; -Cross dependency found in OUTER JOIN. Examine your ON conditions +ERROR 42000: Cross dependency found in OUTER JOIN. Examine your ON conditions drop table t1,t2,t3,t4,t5; create table t1 (n int, m int, o int, key(n)); create table t2 (n int not null, m int, o int, primary key(n)); diff --git a/mysql-test/r/key.result b/mysql-test/r/key.result index 5060fbff5e8..e0b2b84ac16 100644 --- a/mysql-test/r/key.result +++ b/mysql-test/r/key.result @@ -127,7 +127,7 @@ primary key (SEQNO, MOTYPEID, MOINSTANCEID, ATTRID, VALUE ) INSERT INTO t1 VALUES (1, 1, 1, 1, 'a'); INSERT INTO t1 VALUES (1, 1, 1, 1, 'b'); INSERT INTO t1 VALUES (1, 1, 1, 1, 'a'); -Duplicate entry '1-1-1-1-a' for key 1 +ERROR 23000: Duplicate entry '1-1-1-1-a' for key 1 drop table t1; CREATE TABLE t1 ( a tinytext NOT NULL, diff --git a/mysql-test/r/lock.result b/mysql-test/r/lock.result index ad5251b9110..68feb9c44d7 100644 --- a/mysql-test/r/lock.result +++ b/mysql-test/r/lock.result @@ -8,9 +8,9 @@ NULL 1 update t1 set id=-1 where id=1; LOCK TABLE t1 READ; update t1 set id=1 where id=1; -Table 't1' was locked with a READ lock and can't be updated +ERROR HY000: Table 't1' was locked with a READ lock and can't be updated create table t2 SELECT * from t1; -Table 't2' was not locked with LOCK TABLES +ERROR HY000: Table 't2' was not locked with LOCK TABLES create temporary table t2 SELECT * from t1; drop table if exists t2; unlock tables; diff --git a/mysql-test/r/lock_multi.result b/mysql-test/r/lock_multi.result index b808fca0acf..a0efce727d3 100644 --- a/mysql-test/r/lock_multi.result +++ b/mysql-test/r/lock_multi.result @@ -22,5 +22,5 @@ create table t2 (a int); lock table t1 write, t2 write; insert t1 select * from t2; drop table t2; -Table 'test.t2' doesn't exist +ERROR 42S02: Table 'test.t2' doesn't exist drop table t1; diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index b28607218d1..323931ae3eb 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -177,9 +177,9 @@ t3 CREATE TABLE `t3` ( ) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(t1,t2) create table t4 (a int not null, b char(10), key(a)) type=MERGE UNION=(t1,t2); select * from t4; -Can't open file: 't4.MRG'. (errno: 143) +ERROR HY000: Can't open file: 't4.MRG'. (errno: 143) create table t5 (a int not null, b char(10), key(a)) type=MERGE UNION=(test.t1,test_2.t2); -Incorrect table definition; All MERGE tables must be in the same database +ERROR HY000: Incorrect table definition; All MERGE tables must be in the same database drop table if exists t5,t4,t3,t1,t2; Warnings: Note 1051 Unknown table 't5' diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index 2aa7db1599e..15d04422f9d 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -147,11 +147,11 @@ insert into t1 values(1,1); insert into t2 values(1,10),(2,20); LOCK TABLES t1 write, t2 read; DELETE t1.*, t2.* FROM t1,t2 where t1.n=t2.n; -Table 't2' was locked with a READ lock and can't be updated +ERROR HY000: Table 't2' was locked with a READ lock and can't be updated UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n; -Table 't2' was locked with a READ lock and can't be updated +ERROR HY000: Table 't2' was locked with a READ lock and can't be updated UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n; -Table 't2' was locked with a READ lock and can't be updated +ERROR HY000: Table 't2' was locked with a READ lock and can't be updated unlock tables; LOCK TABLES t1 write, t2 write; UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n; @@ -172,7 +172,7 @@ create table t2 (n int(10), d int(10)); insert into t1 values(1,1); insert into t2 values(1,10),(2,20); UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n; -You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column +ERROR HY000: You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column set sql_safe_updates=0; drop table t1,t2; set timestamp=1038401397; @@ -190,7 +190,7 @@ n d unix_timestamp(t) 1 10 1038401397 2 20 1038401397 UPDATE t1,t2 SET 1=2 WHERE t1.n=t2.n; -You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '1=2 WHERE t1.n=t2.n' at line 1 +ERROR 42000: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '1=2 WHERE t1.n=t2.n' at line 1 drop table t1,t2; set timestamp=0; set sql_safe_updates=0; diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 5cfd1afd867..fd9ff2c90cf 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -339,10 +339,10 @@ Table Op Msg_type Msg_text test.t1 check status OK drop table t1; CREATE TABLE t1 (a varchar(255), b varchar(255), c varchar(255), KEY t1 (a, b, c)); -Specified key was too long. Max key length is 500 +ERROR 42000: Specified key was too long. Max key length is 500 CREATE TABLE t1 (a varchar(255), b varchar(255), c varchar(255)); ALTER TABLE t1 ADD INDEX t1 (a, b, c); -Specified key was too long. Max key length is 500 +ERROR 42000: Specified key was too long. Max key length is 500 DROP TABLE t1; CREATE TABLE t1 (a int not null, b int, c int, key(b), key(c), key(a,b), key(c,a)); INSERT into t1 values (0, null, 0), (0, null, 1), (0, null, 2), (0, null,3), (1,1,4); @@ -370,11 +370,11 @@ id select_type table type possible_keys key key_len ref rows Extra explain select * from t1 force index(a),t2 force index(a) where t1.a=t2.a; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL a NULL NULL NULL 2 -1 SIMPLE t1 ref a a 4 t2.a 3 +1 SIMPLE t1 ref a a 4 test.t2.a 3 explain select * from t1,t2 where t1.b=t2.b; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL b NULL NULL NULL 2 -1 SIMPLE t1 ref b b 5 t2.b 1 Using where +1 SIMPLE t1 ref b b 5 test.t2.b 1 Using where explain select * from t1,t2 force index(c) where t1.a=t2.a; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL a NULL NULL NULL 5 @@ -393,7 +393,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where drop table t1,t2; CREATE TABLE t1 (`a` int(11) NOT NULL default '0', `b` int(11) NOT NULL default '0', UNIQUE KEY `a` USING RTREE (`a`,`b`)) TYPE=MyISAM; -This version of MySQL doesn't yet support 'RTREE INDEX' +ERROR 42000: This version of MySQL doesn't yet support 'RTREE INDEX' DROP TABLE IF EXISTS t1; Warnings: Note 1051 Unknown table 't1' diff --git a/mysql-test/r/null.result b/mysql-test/r/null.result index d6dfb4621ab..fd621d06c2b 100644 --- a/mysql-test/r/null.result +++ b/mysql-test/r/null.result @@ -82,33 +82,33 @@ UPDATE t1 SET d=NULL; Warnings: Warning 1261 Data truncated, NULL supplied to NOT NULL column 'd' at row 1 INSERT INTO t1 (a) values (null); -Column 'a' cannot be null +ERROR 23000: Column 'a' cannot be null INSERT INTO t1 (a) values (1/null); -Column 'a' cannot be null +ERROR 23000: Column 'a' cannot be null INSERT INTO t1 (a) values (null),(null); Warnings: Warning 1261 Data truncated, NULL supplied to NOT NULL column 'a' at row 1 Warning 1261 Data truncated, NULL supplied to NOT NULL column 'a' at row 2 INSERT INTO t1 (b) values (null); -Column 'b' cannot be null +ERROR 23000: Column 'b' cannot be null INSERT INTO t1 (b) values (1/null); -Column 'b' cannot be null +ERROR 23000: Column 'b' cannot be null INSERT INTO t1 (b) values (null),(null); Warnings: Warning 1261 Data truncated, NULL supplied to NOT NULL column 'b' at row 1 Warning 1261 Data truncated, NULL supplied to NOT NULL column 'b' at row 2 INSERT INTO t1 (c) values (null); -Column 'c' cannot be null +ERROR 23000: Column 'c' cannot be null INSERT INTO t1 (c) values (1/null); -Column 'c' cannot be null +ERROR 23000: Column 'c' cannot be null INSERT INTO t1 (c) values (null),(null); Warnings: Warning 1261 Data truncated, NULL supplied to NOT NULL column 'c' at row 1 Warning 1261 Data truncated, NULL supplied to NOT NULL column 'c' at row 2 INSERT INTO t1 (d) values (null); -Column 'd' cannot be null +ERROR 23000: Column 'd' cannot be null INSERT INTO t1 (d) values (1/null); -Column 'd' cannot be null +ERROR 23000: Column 'd' cannot be null INSERT INTO t1 (d) values (null),(null); Warnings: Warning 1261 Data truncated, NULL supplied to NOT NULL column 'd' at row 1 diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index 428d1052d19..0b7a98e3fb3 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -1,27 +1,256 @@ -drop table if exists t1; -create table t1 ( product varchar(32), country varchar(32), year int, profit int); -insert into t1 values ( 'Computer', 'India',2000, 1200), -( 'TV', 'United States', 1999, 150), -( 'Calculator', 'United States', 1999,50), -( 'Computer', 'United States', 1999,1500), -( 'Computer', 'United States', 2000,1500), -( 'TV', 'United States', 2000, 150), -( 'TV', 'India', 2000, 100), -( 'TV', 'India', 2000, 100), -( 'Calculator', 'United States', 2000,75), -( 'Calculator', 'India', 2000,75), -( 'TV', 'India', 1999, 100), -( 'Computer', 'India', 1999,1200), -( 'Computer', 'United States', 2000,1500), -( 'Calculator', 'United States', 2000,75); -select product, country , year, sum(profit) from t1 group by product, country, year with cube; -This version of MySQL doesn't yet support 'CUBE' -explain select product, country , year, sum(profit) from t1 group by product, country, year with cube; -This version of MySQL doesn't yet support 'CUBE' -select product, country , year, sum(profit) from t1 group by product, country, year with rollup; -This version of MySQL doesn't yet support 'ROLLUP' -explain select product, country , year, sum(profit) from t1 group by product, country, year with rollup; -This version of MySQL doesn't yet support 'ROLLUP' -select product, country , year, sum(profit) from t1 group by product, country, year with cube union all select product, country , year, sum(profit) from t1 group by product, country, year with rollup; -This version of MySQL doesn't yet support 'CUBE' -drop table t1; +drop table if exists t1,t2; +create table t1 (product varchar(32), country_id int not null, year int, profit int); +insert into t1 values ( 'Computer', 2,2000, 1200), +( 'TV', 1, 1999, 150), +( 'Calculator', 1, 1999,50), +( 'Computer', 1, 1999,1500), +( 'Computer', 1, 2000,1500), +( 'TV', 1, 2000, 150), +( 'TV', 2, 2000, 100), +( 'TV', 2, 2000, 100), +( 'Calculator', 1, 2000,75), +( 'Calculator', 2, 2000,75), +( 'TV', 1, 1999, 100), +( 'Computer', 1, 1999,1200), +( 'Computer', 2, 2000,1500), +( 'Calculator', 2, 2000,75), +( 'Phone', 3, 2003,10) +; +create table t2 (country_id int primary key, country char(20) not null); +insert into t2 values (1, 'USA'),(2,'India'), (3,'Finland'); +select product, sum(profit) from t1 group by product; +product sum(profit) +Calculator 275 +Computer 6900 +Phone 10 +TV 600 +select product, sum(profit) from t1 group by product with rollup; +product sum(profit) +Calculator 275 +Computer 6900 +Phone 10 +TV 600 +NULL 7785 +select product, sum(profit) from t1 group by 1 with rollup; +product sum(profit) +Calculator 275 +Computer 6900 +Phone 10 +TV 600 +NULL 7785 +select product, sum(profit),avg(profit) from t1 group by product with rollup; +product sum(profit) avg(profit) +Calculator 275 68.7500 +Computer 6900 1380.0000 +Phone 10 10.0000 +TV 600 120.0000 +NULL 7785 519.0000 +select product, country_id , year, sum(profit) from t1 group by product, country_id, year; +product country_id year sum(profit) +Calculator 1 1999 50 +Calculator 1 2000 75 +Calculator 2 2000 150 +Computer 1 1999 2700 +Computer 1 2000 1500 +Computer 2 2000 2700 +Phone 3 2003 10 +TV 1 1999 250 +TV 1 2000 150 +TV 2 2000 200 +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup; +product country_id year sum(profit) +Calculator 1 1999 50 +Calculator 1 2000 75 +Calculator 1 NULL 125 +Calculator 2 2000 150 +Calculator 2 NULL 150 +Calculator NULL NULL 275 +Computer 1 1999 2700 +Computer 1 2000 1500 +Computer 1 NULL 4200 +Computer 2 2000 2700 +Computer 2 NULL 2700 +Computer NULL NULL 6900 +Phone 3 2003 10 +Phone 3 NULL 10 +Phone NULL NULL 10 +TV 1 1999 250 +TV 1 2000 150 +TV 1 NULL 400 +TV 2 2000 200 +TV 2 NULL 200 +TV NULL NULL 600 +NULL NULL NULL 7785 +explain select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 15 Using temporary; Using filesort +select product, country_id , sum(profit) from t1 group by product desc, country_id with rollup; +product country_id sum(profit) +TV 1 400 +TV 2 200 +TV NULL 600 +Phone 3 10 +Phone NULL 10 +Computer 1 4200 +Computer 2 2700 +Computer NULL 6900 +Calculator 1 125 +Calculator 2 150 +Calculator NULL 275 +NULL NULL 7785 +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup limit 5; +product country_id year sum(profit) +Calculator 1 1999 50 +Calculator 1 2000 75 +Calculator 1 NULL 125 +Calculator 2 2000 150 +Calculator 2 NULL 150 +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup limit 3,3; +product country_id year sum(profit) +Calculator 2 2000 150 +Calculator 2 NULL 150 +Calculator NULL NULL 275 +select product, country_id, count(*), count(distinct year) from t1 group by product, country_id; +product country_id count(*) count(distinct year) +Calculator 1 2 2 +Calculator 2 2 1 +Computer 1 3 2 +Computer 2 2 1 +Phone 3 1 1 +TV 1 3 2 +TV 2 2 1 +select product, country_id, count(*), count(distinct year) from t1 group by product, country_id with rollup; +product country_id count(*) count(distinct year) +Calculator 1 2 2 +Calculator 2 2 1 +Calculator NULL 4 2 +Computer 1 3 2 +Computer 2 2 1 +Computer NULL 5 2 +Phone 3 1 1 +Phone NULL 1 1 +TV 1 3 2 +TV 2 2 1 +TV NULL 5 2 +NULL NULL 15 3 +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup having country_id = 1; +product country_id year sum(profit) +Calculator 1 1999 50 +Calculator 1 2000 75 +Calculator 1 NULL 125 +Computer 1 1999 2700 +Computer 1 2000 1500 +Computer 1 NULL 4200 +TV 1 1999 250 +TV 1 2000 150 +TV 1 NULL 400 +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup having sum(profit) > 200; +product country_id year sum(profit) +Calculator NULL NULL 275 +Computer 1 1999 2700 +Computer 1 2000 1500 +Computer 1 NULL 4200 +Computer 2 2000 2700 +Computer 2 NULL 2700 +Computer NULL NULL 6900 +TV 1 1999 250 +TV 1 NULL 400 +TV NULL NULL 600 +NULL NULL NULL 7785 +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup having sum(profit) > 7000; +product country_id year sum(profit) +NULL NULL NULL 7785 +select concat(product,':',country_id) as 'prod', concat(":",year,":") as 'year',1+1, sum(profit)/count(*) from t1 group by 1,2 with rollup; +prod year 1+1 sum(profit)/count(*) +Calculator:1 :1999: 2 50.00 +Calculator:1 :2000: 2 75.00 +Calculator:1 NULL 2 62.50 +Calculator:2 :2000: 2 75.00 +Calculator:2 NULL 2 75.00 +Computer:1 :1999: 2 1350.00 +Computer:1 :2000: 2 1500.00 +Computer:1 NULL 2 1400.00 +Computer:2 :2000: 2 1350.00 +Computer:2 NULL 2 1350.00 +Phone:3 :2003: 2 10.00 +Phone:3 NULL 2 10.00 +TV:1 :1999: 2 125.00 +TV:1 :2000: 2 150.00 +TV:1 NULL 2 133.33 +TV:2 :2000: 2 100.00 +TV:2 NULL 2 100.00 +NULL NULL 2 519.00 +select product, sum(profit)/count(*) from t1 group by product with rollup; +product sum(profit)/count(*) +Calculator 68.75 +Computer 1380.00 +Phone 10.00 +TV 120.00 +NULL 519.00 +select left(product,4) as prod, sum(profit)/count(*) from t1 group by prod with rollup; +prod sum(profit)/count(*) +Calc 68.75 +Comp 1380.00 +Phon 10.00 +TV 120.00 +NULL 519.00 +select concat(product,':',country_id), 1+1, sum(profit)/count(*) from t1 group by concat(product,':',country_id) with rollup; +concat(product,':',country_id) 1+1 sum(profit)/count(*) +Calculator:1 2 62.50 +Calculator:2 2 75.00 +Computer:1 2 1400.00 +Computer:2 2 1350.00 +Phone:3 2 10.00 +TV:1 2 133.33 +TV:2 2 100.00 +NULL 2 519.00 +select product, country , year, sum(profit) from t1,t2 where t1.country_id=t2.country_id group by product, country, year with rollup; +product country year sum(profit) +Calculator India 2000 150 +Calculator India NULL 150 +Calculator USA 1999 50 +Calculator USA 2000 75 +Calculator USA NULL 125 +Calculator NULL NULL 275 +Computer India 2000 2700 +Computer India NULL 2700 +Computer USA 1999 2700 +Computer USA 2000 1500 +Computer USA NULL 4200 +Computer NULL NULL 6900 +Phone Finland 2003 10 +Phone Finland NULL 10 +Phone NULL NULL 10 +TV India 2000 200 +TV India NULL 200 +TV USA 1999 250 +TV USA 2000 150 +TV USA NULL 400 +TV NULL NULL 600 +NULL NULL NULL 7785 +select product, `sum` from (select product, sum(profit) as 'sum' from t1 group by product with rollup) as tmp where product is null; +product sum +NULL 7785 +select product from t1 where exists (select product, country_id , sum(profit) from t1 as t2 where t1.product=t2.product group by product, country_id with rollup having sum(profit) > 6000); +product +Computer +Computer +Computer +Computer +Computer +select product, country_id , year, sum(profit) from t1 group by product, country_id, year having country_id is NULL; +product country_id year sum(profit) +select concat(':',product,':'), sum(profit),avg(profit) from t1 group by product with rollup; +concat(':',product,':') sum(profit) avg(profit) +:Calculator: 275 68.7500 +:Computer: 6900 1380.0000 +:Phone: 10 10.0000 +:TV: 600 120.0000 +:TV: 7785 519.0000 +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with cube; +ERROR 42000: This version of MySQL doesn't yet support 'CUBE' +explain select product, country_id , year, sum(profit) from t1 group by product, country_id, year with cube; +ERROR 42000: This version of MySQL doesn't yet support 'CUBE' +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with cube union all select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup; +ERROR 42000: This version of MySQL doesn't yet support 'CUBE' +drop table t1,t2; diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 3524b38e659..1e940351a4a 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -466,25 +466,25 @@ gid sid uid EXPLAIN select t1.gid, t2.sid, t3.uid from t3, t2, t1 where t2.gid = t1.gid and t2.uid = t3.uid order by t1.gid, t3.uid; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 6 Using index -1 SIMPLE t2 eq_ref PRIMARY,uid PRIMARY 4 t1.gid 1 -1 SIMPLE t3 eq_ref PRIMARY PRIMARY 2 t2.uid 1 Using where; Using index +1 SIMPLE t2 eq_ref PRIMARY,uid PRIMARY 4 test.t1.gid 1 +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 2 test.t2.uid 1 Using where; Using index EXPLAIN SELECT t1.gid, t3.uid from t1, t3 where t1.gid = t3.uid order by t1.gid,t3.skr; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 6 Using index -1 SIMPLE t3 eq_ref PRIMARY PRIMARY 2 t1.gid 1 Using where +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 2 test.t1.gid 1 Using where EXPLAIN SELECT t1.gid, t2.sid, t3.uid from t2, t1, t3 where t2.gid = t1.gid and t2.uid = t3.uid order by t3.uid, t1.gid; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 6 Using index; Using temporary; Using filesort -1 SIMPLE t2 eq_ref PRIMARY,uid PRIMARY 4 t1.gid 1 -1 SIMPLE t3 eq_ref PRIMARY PRIMARY 2 t2.uid 1 Using where; Using index +1 SIMPLE t2 eq_ref PRIMARY,uid PRIMARY 4 test.t1.gid 1 +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 2 test.t2.uid 1 Using where; Using index EXPLAIN SELECT t1.gid, t3.uid from t1, t3 where t1.gid = t3.uid order by t3.skr,t1.gid; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 6 Using index; Using temporary; Using filesort -1 SIMPLE t3 eq_ref PRIMARY PRIMARY 2 t1.gid 1 Using where +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 2 test.t1.gid 1 Using where EXPLAIN SELECT t1.gid, t3.uid from t1, t3 where t1.skr = t3.uid order by t1.gid,t3.skr; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using temporary; Using filesort -1 SIMPLE t3 eq_ref PRIMARY PRIMARY 2 t1.skr 1 Using where +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 2 test.t1.skr 1 Using where drop table t1,t2,t3; CREATE TABLE t1 ( `titre` char(80) NOT NULL default '', diff --git a/mysql-test/r/packet.result b/mysql-test/r/packet.result index e994e4d63da..6e3c459b39d 100644 --- a/mysql-test/r/packet.result +++ b/mysql-test/r/packet.result @@ -12,7 +12,7 @@ select @@net_buffer_length, @@max_allowed_packet; @@net_buffer_length @@max_allowed_packet 1024 80 SELECT length("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") as len; -Got a packet bigger than 'max_allowed_packet' +ERROR 08S01: Got a packet bigger than 'max_allowed_packet' set global max_allowed_packet=default; set max_allowed_packet=default; set global net_buffer_length=default; diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index 1d46d1dcf25..4622bb231a2 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -615,10 +615,10 @@ id 2 alter table t1 rename to t2; select * from t1 where id=2; -Table 'test.t1' doesn't exist +ERROR 42S02: Table 'test.t1' doesn't exist drop table t2; select * from t1 where id=2; -Table 'test.t1' doesn't exist +ERROR 42S02: Table 'test.t1' doesn't exist create table t1 (word char(20) not null); select * from t1; word diff --git a/mysql-test/r/row.result b/mysql-test/r/row.result index 79eb6cc7e59..94186f254c4 100644 --- a/mysql-test/r/row.result +++ b/mysql-test/r/row.result @@ -36,7 +36,7 @@ select (1,2,(3,4)) IN ((3,2,(3,4)), (1,2,(3,4))); (1,2,(3,4)) IN ((3,2,(3,4)), (1,2,(3,4))) 1 select row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,4)); -Cardinality error (more/less than 2 columns) +ERROR 21000: Cardinality error (more/less than 2 columns) select row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,row(3,NULL))); row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,row(3,NULL))) NULL @@ -86,7 +86,7 @@ SELECT ROW('test',2,3.33)=ROW('test',2,3.33); ROW('test',2,3.33)=ROW('test',2,3.33) 1 SELECT ROW('test',2,3.33)=ROW('test',2,3.33,4); -Cardinality error (more/less than 3 columns) +ERROR 21000: Cardinality error (more/less than 3 columns) SELECT ROW('test',2,ROW(3,33))=ROW('test',2,ROW(3,33)); ROW('test',2,ROW(3,33))=ROW('test',2,ROW(3,33)) 1 @@ -97,7 +97,7 @@ SELECT ROW('test',2,ROW(3,33))=ROW('test',2,ROW(3,NULL)); ROW('test',2,ROW(3,33))=ROW('test',2,ROW(3,NULL)) NULL SELECT ROW('test',2,ROW(3,33))=ROW('test',2,4); -Cardinality error (more/less than 2 columns) +ERROR 21000: Cardinality error (more/less than 2 columns) create table t1 ( a int, b int, c int); insert into t1 values (1,2,3), (2,3,1), (3,2,1), (1,2,NULL); select * from t1 where ROW(1,2,3)=ROW(a,b,c); @@ -135,14 +135,14 @@ ROW(1,2,3) IN(row(a,b,c), row(1,2,3)) 1 drop table t1; select ROW(1,1); -Cardinality error (more/less than 1 columns) +ERROR 21000: Cardinality error (more/less than 1 columns) create table t1 (i int); select 1 from t1 where ROW(1,1); -Cardinality error (more/less than 1 columns) +ERROR 21000: Cardinality error (more/less than 1 columns) select count(*) from t1 order by ROW(1,1); -Cardinality error (more/less than 1 columns) +ERROR 21000: Cardinality error (more/less than 1 columns) select count(*) from t1 having (1,1) order by i; -Cardinality error (more/less than 1 columns) +ERROR 21000: Cardinality error (more/less than 1 columns) drop table t1; create table t1 (a int, b int); insert into t1 values (1, 4); diff --git a/mysql-test/r/rpl000001.result b/mysql-test/r/rpl000001.result index 8aa667df063..79438f8fa40 100644 --- a/mysql-test/r/rpl000001.result +++ b/mysql-test/r/rpl000001.result @@ -55,7 +55,7 @@ select (@id := id) - id from t2; 0 kill @id; drop table t2; -Server shutdown in progress +ERROR 08S01: Server shutdown in progress set global sql_slave_skip_counter=1; start slave; select count(*) from t1; diff --git a/mysql-test/r/rpl000009.result b/mysql-test/r/rpl000009.result index 06f34842577..dc1d8c4872e 100644 --- a/mysql-test/r/rpl000009.result +++ b/mysql-test/r/rpl000009.result @@ -21,7 +21,7 @@ n m drop database mysqltest; drop database if exists mysqltest2; drop database mysqltest; -Can't drop database 'mysqltest'. Database doesn't exist +ERROR HY000: Can't drop database 'mysqltest'. Database doesn't exist drop database mysqltest2; set sql_log_bin = 0; create database mysqltest2; diff --git a/mysql-test/r/rpl_empty_master_crash.result b/mysql-test/r/rpl_empty_master_crash.result index 8818029ab99..39ab1c2d9b4 100644 --- a/mysql-test/r/rpl_empty_master_crash.result +++ b/mysql-test/r/rpl_empty_master_crash.result @@ -7,6 +7,6 @@ start slave; show slave status; Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space load table t1 from master; -Error connecting to master: Master is not configured +ERROR 08S01: Error connecting to master: Master is not configured load table t1 from master; -Error from master: 'Table 'test.t1' doesn't exist' +ERROR HY000: Error from master: 'Table 'test.t1' doesn't exist' diff --git a/mysql-test/r/rpl_log.result b/mysql-test/r/rpl_log.result index 6f438c6c34a..948a755c3db 100644 --- a/mysql-test/r/rpl_log.result +++ b/mysql-test/r/rpl_log.result @@ -89,4 +89,4 @@ show slave status; Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space 127.0.0.1 root MASTER_PORT 1 master-bin.000002 170 slave-relay-bin.000002 1469 master-bin.000002 Yes Yes 0 0 170 1473 show binlog events in 'slave-bin.000005' from 4; -Error when executing command SHOW BINLOG EVENTS: Could not find target log +ERROR HY000: Error when executing command SHOW BINLOG EVENTS: Could not find target log diff --git a/mysql-test/r/rpl_replicate_do.result b/mysql-test/r/rpl_replicate_do.result index 9ae292c2709..a91a0a2b819 100644 --- a/mysql-test/r/rpl_replicate_do.result +++ b/mysql-test/r/rpl_replicate_do.result @@ -24,5 +24,5 @@ select * from t2; n 4 select * from t11; -Table 'test.t11' doesn't exist +ERROR 42S02: Table 'test.t11' doesn't exist drop table if exists t1,t2,t11; diff --git a/mysql-test/r/rpl_rotate_logs.result b/mysql-test/r/rpl_rotate_logs.result index c4023832921..66209d2b852 100644 --- a/mysql-test/r/rpl_rotate_logs.result +++ b/mysql-test/r/rpl_rotate_logs.result @@ -1,9 +1,9 @@ drop table if exists t1, t2, t3, t4; drop table if exists t1, t2, t3, t4; start slave; -Could not initialize master info structure, check permisions on master.info +ERROR HY000: Could not initialize master info structure, check permisions on master.info start slave; -Could not initialize master info structure, check permisions on master.info +ERROR HY000: Could not initialize master info structure, check permisions on master.info change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root'; Could not initialize master info reset slave; diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 8be189752ea..fbce0e9290a 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -1341,9 +1341,9 @@ explain select fld3 from t2 use index (fld1,fld3) where fld3 = 'honeysuckle'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ref fld3 fld3 30 const 1 Using where; Using index explain select fld3 from t2 ignore index (fld3,not_used); -Key column 'not_used' doesn't exist in table +ERROR 42000: Key column 'not_used' doesn't exist in table explain select fld3 from t2 use index (not_used); -Key column 'not_used' doesn't exist in table +ERROR 42000: Key column 'not_used' doesn't exist in table select t2.fld3 from t2 where fld3 >= 'honeysuckle' and fld3 <= 'honoring' order by fld3; fld3 honeysuckle @@ -1807,19 +1807,19 @@ fld3 explain select t3.t2nr,fld3 from t2,t3 where t2.companynr = 34 and t2.fld1=t3.t2nr order by t3.t2nr,fld3; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL fld1 NULL NULL NULL 1199 Using where; Using temporary; Using filesort -1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 t2.fld1 1 Using where; Using index +1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.fld1 1 Using where; Using index explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL period NULL NULL NULL 41810 Using temporary; Using filesort -1 SIMPLE t3 ref period period 4 t1.period 4181 +1 SIMPLE t3 ref period period 4 test.t1.period 4181 explain select * from t3 as t1,t3 where t1.period=t3.period order by t3.period limit 10; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t3 index period period 4 NULL 41810 -1 SIMPLE t1 ref period period 4 t3.period 4181 +1 SIMPLE t1 ref period period 4 test.t3.period 4181 explain select * from t3 as t1,t3 where t1.period=t3.period order by t1.period limit 10; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index period period 4 NULL 41810 -1 SIMPLE t3 ref period period 4 t1.period 4181 +1 SIMPLE t3 ref period period 4 test.t1.period 4181 select period from t1; period 9410 diff --git a/mysql-test/r/select_safe.result b/mysql-test/r/select_safe.result index 3303f19d9c7..e73161996b8 100644 --- a/mysql-test/r/select_safe.result +++ b/mysql-test/r/select_safe.result @@ -20,17 +20,17 @@ select 1 from t1,t1 as t2,t1 as t3,t1 as t4; 1 1 update t1 set b="a"; -You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column +ERROR HY000: You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column update t1 set b="a" where b="test"; -You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column +ERROR HY000: You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column delete from t1; -You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column +ERROR HY000: You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column delete from t1 where b="test"; -You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column +ERROR HY000: You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column delete from t1 where a+0=1; -You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column +ERROR HY000: You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column select 1 from t1,t1 as t2,t1 as t3,t1 as t4,t1 as t5; -The SELECT would examine more rows than MAX_JOIN_SIZE. Check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is ok +ERROR 42000: The SELECT would examine more rows than MAX_JOIN_SIZE. Check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is ok update t1 set b="a" limit 1; update t1 set b="a" where b="b" limit 2; delete from t1 where b="test" limit 1; @@ -41,7 +41,7 @@ SELECT @@MAX_JOIN_SIZE, @@SQL_BIG_SELECTS; 2 0 insert into t1 values (null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"); SELECT * from t1; -The SELECT would examine more rows than MAX_JOIN_SIZE. Check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is ok +ERROR 42000: The SELECT would examine more rows than MAX_JOIN_SIZE. Check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is ok SET SQL_BIG_SELECTS=1; SELECT * from t1; a b @@ -51,7 +51,7 @@ a b 5 a SET MAX_JOIN_SIZE=2; SELECT * from t1; -The SELECT would examine more rows than MAX_JOIN_SIZE. Check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is ok +ERROR 42000: The SELECT would examine more rows than MAX_JOIN_SIZE. Check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is ok SET MAX_JOIN_SIZE=DEFAULT; SELECT * from t1; a b diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result index c1f2adc1e31..ea5f13192f7 100644 --- a/mysql-test/r/show_check.result +++ b/mysql-test/r/show_check.result @@ -26,7 +26,7 @@ t1 0 PRIMARY 1 a A 5 NULL NULL BTREE t1 1 b 1 b A 1 NULL NULL BTREE t1 1 b 2 c A 5 NULL NULL BTREE insert into t1 values (5,5,5); -Duplicate entry '5' for key 1 +ERROR 23000: Duplicate entry '5' for key 1 optimize table t1; Table Op Msg_type Msg_text test.t1 optimize status OK diff --git a/mysql-test/r/sql_mode.result b/mysql-test/r/sql_mode.result index 8ded3daf114..9b80b965d10 100644 --- a/mysql-test/r/sql_mode.result +++ b/mysql-test/r/sql_mode.result @@ -71,10 +71,10 @@ t1 CREATE TABLE `t1` ( PRIMARY KEY (`a`), UNIQUE KEY `email` (`email`) ) TYPE=HEAP ROW_FORMAT=DYNAMIC -set @@sql_mode="postgresql,oracle,mssql,db2,sapdb"; -show variables like 'sql_mode'; -Variable_name Value -sql_mode POSTGRESQL,ORACLE,MSSQL,DB2,SAPDB +set sql_mode="postgresql,oracle,mssql,db2,sapdb"; +select @@sql_mode; +@@sql_mode +PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,POSTGRESQL,ORACLE,MSSQL,DB2,SAPDB,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS show create table t1; Table Create Table t1 CREATE TABLE "t1" ( diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 41620bb6e7f..982b70ff3e6 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -29,14 +29,14 @@ id select_type table type possible_keys key key_len ref rows Extra Warnings: Note 1247 Select 2 was reduced during optimisation SELECT (SELECT 1 FROM (SELECT 1) as b HAVING a=1) as a; -Reference 'a' not supported (forward reference in item list) +ERROR 42S22: Reference 'a' not supported (forward reference in item list) SELECT (SELECT 1 FROM (SELECT 1) as b HAVING b=1) as a,(SELECT 1 FROM (SELECT 1) as c HAVING a=1) as b; -Reference 'b' not supported (forward reference in item list) +ERROR 42S22: Reference 'b' not supported (forward reference in item list) SELECT (SELECT 1),MAX(1) FROM (SELECT 1) as a; (SELECT 1) MAX(1) 1 1 SELECT (SELECT a) as a; -Reference 'a' not supported (forward reference in item list) +ERROR 42S22: Reference 'a' not supported (forward reference in item list) EXPLAIN SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY system NULL NULL NULL NULL 1 @@ -46,17 +46,17 @@ SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1; 1 1 SELECT (SELECT 1), a; -Unknown column 'a' in 'field list' +ERROR 42S22: Unknown column 'a' in 'field list' SELECT 1 as a FROM (SELECT 1) as b HAVING (SELECT a)=1; a 1 SELECT 1 FROM (SELECT (SELECT a) b) c; -Unknown column 'a' in 'field list' +ERROR 42S22: Unknown column 'a' in 'field list' SELECT * FROM (SELECT 1 as id) b WHERE id IN (SELECT * FROM (SELECT 1 as id) c ORDER BY id); id 1 SELECT * FROM (SELECT 1) a WHERE 1 IN (SELECT 1,1); -Cardinality error (more/less than 1 columns) +ERROR 21000: Cardinality error (more/less than 1 columns) SELECT 1 IN (SELECT 1); 1 IN (SELECT 1) 1 @@ -64,9 +64,9 @@ SELECT 1 FROM (SELECT 1 as a) b WHERE 1 IN (SELECT (SELECT a)); 1 1 select (SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(1)); -Wrong usage of PROCEDURE and subquery +ERROR HY000: Wrong usage of PROCEDURE and subquery SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE((SELECT 1)); -Incorrect parameters to procedure 'ANALYSE' +ERROR HY000: Incorrect parameters to procedure 'ANALYSE' SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NULL; a SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NOT NULL; @@ -121,19 +121,19 @@ SELECT (SELECT 1.5,'c','a') = ROW(1.5,2,'a'); (SELECT 1.5,'c','a') = ROW(1.5,2,'a') 0 SELECT (SELECT * FROM (SELECT 'test' a,'test' b) a); -Cardinality error (more/less than 1 columns) +ERROR 21000: Cardinality error (more/less than 1 columns) SELECT 1 as a,(SELECT a+a) b,(SELECT b); a b (SELECT b) 1 2 2 create table t1 (a int); create table t2 (a int, b int); create table t3 (a int); -create table t4 (a int, b int); +create table t4 (a int not null, b int not null); insert into t1 values (2); insert into t2 values (1,7),(2,7); insert into t4 values (4,8),(3,8),(5,9); select (select a from t1 where t1.a = a1) as a2, (select b from t2 where t2.b=a2) as a1; -Reference 'a1' not supported (forward reference in item list) +ERROR 42S22: Reference 'a1' not supported (forward reference in item list) select (select a from t1 where t1.a=t2.a), a from t2; (select a from t1 where t1.a=t2.a) a NULL 1 @@ -252,15 +252,18 @@ a 7 delete from t2 where a=100; select * from t3 where a in (select a,b from t2); -Cardinality error (more/less than 1 columns) +ERROR 21000: Cardinality error (more/less than 1 columns) select * from t3 where a in (select * from t2); -Cardinality error (more/less than 1 columns) -insert into t4 values (12,7),(1,7),(10,9),(9,6),(7,6),(3,9); -select b,max(a) as ma from t4 group by b having b < (select max(t2.a) -from t2 where t2.b=t4.b); +ERROR 21000: Cardinality error (more/less than 1 columns) +insert into t4 values (12,7),(1,7),(10,9),(9,6),(7,6),(3,9),(1,10); +select b,max(a) as ma from t4 group by b having b < (select max(t2.a) from t2 where t2.b=t4.b); b ma -select b,max(a) as ma from t4 group by b having b >= (select max(t2.a) -from t2 where t2.b=t4.b); +insert into t2 values (2,10); +select b,max(a) as ma from t4 group by b having ma < (select max(t2.a) from t2 where t2.b=t4.b); +b ma +10 1 +delete from t2 where a=2 and b=10; +select b,max(a) as ma from t4 group by b having b >= (select max(t2.a) from t2 where t2.b=t4.b); b ma 7 12 create table t5 (a int); @@ -284,7 +287,7 @@ id select_type table type possible_keys key key_len ref rows Extra 2 DEPENDENT SUBQUERY t1 system NULL NULL NULL NULL 1 3 DEPENDENT UNION t5 ALL NULL NULL NULL NULL 2 Using where select (select a from t1 where t1.a=t2.a union all select a from t5 where t5.a=t2.a), a from t2; -Subselect returns more than 1 record +ERROR 21000: Subselect returns more than 1 record create table t6 (patient_uq int, clinic_uq int, index i1 (clinic_uq)); create table t7( uq int primary key, name char(25)); insert into t7 values(1,"Oblastnaia bolnitsa"),(2,"Bolnitsa Krasnogo Kresta"); @@ -297,9 +300,9 @@ patient_uq clinic_uq explain select * from t6 where exists (select * from t7 where uq = clinic_uq); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t6 ALL NULL NULL NULL NULL 4 Using where -2 DEPENDENT SUBQUERY t7 eq_ref PRIMARY PRIMARY 4 t6.clinic_uq 1 +2 DEPENDENT SUBQUERY t7 eq_ref PRIMARY PRIMARY 4 test.t6.clinic_uq 1 select * from t1 where a= (select a from t2,t4 where t2.b=t4.b); -Column: 'a' in field list is ambiguous +ERROR 23000: Column: 'a' in field list is ambiguous drop table if exists t1,t2,t3; CREATE TABLE t3 (a varchar(20),b char(1) NOT NULL default '0'); INSERT INTO t3 VALUES ('W','a'),('A','c'),('J','b'); @@ -333,15 +336,15 @@ id select_type table type possible_keys key key_len ref rows Extra 3 SUBQUERY t8 const PRIMARY PRIMARY 35 1 SELECT pseudo FROM t8 WHERE pseudo=(SELECT pseudo,email FROM t8 WHERE pseudo='joce'); -Cardinality error (more/less than 1 columns) +ERROR 21000: Cardinality error (more/less than 1 columns) SELECT pseudo FROM t8 WHERE pseudo=(SELECT * FROM t8 WHERE pseudo='joce'); -Cardinality error (more/less than 1 columns) +ERROR 21000: Cardinality error (more/less than 1 columns) SELECT pseudo FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce'); pseudo joce SELECT pseudo FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo LIKE '%joce%'); -Subselect returns more than 1 record +ERROR 21000: Subselect returns more than 1 record drop table if exists t1,t2,t3,t4,t5,t6,t7,t8; CREATE TABLE `t1` ( `topic` mediumint(8) unsigned NOT NULL default '0', @@ -371,7 +374,7 @@ SELECT 1 FROM t1 WHERE 1=(SELECT 1 UNION SELECT 1) UNION ALL SELECT 1; 1 1 SELECT 1 FROM t1 WHERE 1=(SELECT 1 UNION ALL SELECT 1) UNION SELECT 1; -Subselect returns more than 1 record +ERROR 21000: Subselect returns more than 1 record EXPLAIN SELECT 1 FROM t1 WHERE 1=(SELECT 1 UNION SELECT 1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL topic 3 NULL 2 Using index @@ -401,9 +404,9 @@ numeropost maxnumrep 43506 2 40143 1 SELECT (SELECT 1) as a FROM (SELECT 1 FROM t1 HAVING a=1) b; -Unknown column 'a' in 'having clause' +ERROR 42S22: Unknown column 'a' in 'having clause' SELECT 1 IN (SELECT 1 FROM t2 HAVING a); -Unknown column 'a' in 'having clause' +ERROR 42S22: Unknown column 'a' in 'having clause' SELECT * from t2 where topic IN (SELECT topic FROM t2 GROUP BY topic); mot topic date pseudo joce 40143 2002-10-22 joce @@ -458,9 +461,9 @@ UNIQUE KEY `maxnumrep` (`maxnumrep`) ) TYPE=MyISAM ROW_FORMAT=FIXED; INSERT INTO t1 (numeropost,maxnumrep) VALUES (1,0),(2,1); select numeropost as a FROM t1 GROUP BY (SELECT 1 FROM t1 HAVING a=1); -Subselect returns more than 1 record +ERROR 21000: Subselect returns more than 1 record select numeropost as a FROM t1 ORDER BY (SELECT 1 FROM t1 HAVING a=1); -Subselect returns more than 1 record +ERROR 21000: Subselect returns more than 1 record drop table t1; create table t1 (a int); insert into t1 values (1),(2),(3); @@ -473,7 +476,7 @@ drop table t1; CREATE TABLE t1 (field char(1) NOT NULL DEFAULT 'b'); INSERT INTO t1 VALUES (); SELECT field FROM t1 WHERE 1=(SELECT 1 UNION ALL SELECT 1 FROM (SELECT 1) a HAVING field='b'); -Subselect returns more than 1 record +ERROR 21000: Subselect returns more than 1 record drop table t1; CREATE TABLE `t1` ( `numeropost` mediumint(8) unsigned NOT NULL default '0', @@ -484,14 +487,14 @@ UNIQUE KEY `numreponse` (`numreponse`), KEY `pseudo` (`pseudo`,`numeropost`) ) TYPE=MyISAM; SELECT (SELECT numeropost FROM t1 HAVING numreponse=a),numreponse FROM (SELECT * FROM t1) as a; -Reference 'numreponse' not supported (forward reference in item list) +ERROR 42S22: Reference 'numreponse' not supported (forward reference in item list) SELECT numreponse, (SELECT numeropost FROM t1 HAVING numreponse=a) FROM (SELECT * FROM t1) as a; -Unknown column 'a' in 'having clause' +ERROR 42S22: Unknown column 'a' in 'having clause' SELECT numreponse, (SELECT numeropost FROM t1 HAVING numreponse=1) FROM (SELECT * FROM t1) as a; numreponse (SELECT numeropost FROM t1 HAVING numreponse=1) INSERT INTO t1 (numeropost,numreponse,pseudo) VALUES (1,1,'joce'),(1,2,'joce'),(1,3,'test'); EXPLAIN SELECT numreponse FROM t1 WHERE numeropost='1' AND numreponse=(SELECT 1 FROM t1 WHERE numeropost='1'); -Subselect returns more than 1 record +ERROR 21000: Subselect returns more than 1 record EXPLAIN SELECT MAX(numreponse) FROM t1 WHERE numeropost='1'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away @@ -516,9 +519,9 @@ a b 1 11 2 12 update t1 set b= (select b from t1); -You can't specify target table 't1' for update in FROM clause +ERROR HY000: You can't specify target table 't1' for update in FROM clause update t1 set b= (select b from t2); -Subselect returns more than 1 record +ERROR 21000: Subselect returns more than 1 record update t1 set b= (select b from t2 where t1.a = t2.a); select * from t1; a b @@ -539,9 +542,9 @@ select * from t1 where b = (select b from t2 where t1.a = t2.a); a b 2 12 delete from t1 where b = (select b from t1); -You can't specify target table 't1' for update in FROM clause +ERROR HY000: You can't specify target table 't1' for update in FROM clause delete from t1 where b = (select b from t2); -Subselect returns more than 1 record +ERROR 21000: Subselect returns more than 1 record delete from t1 where b = (select b from t2 where t1.a = t2.a); select * from t1; a b @@ -565,9 +568,9 @@ a b 22 11 2 12 delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t12 where t11.a = t12.a); -You can't specify target table 't12' for update in FROM clause +ERROR HY000: You can't specify target table 't12' for update in FROM clause delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t2); -Subselect returns more than 1 record +ERROR 21000: Subselect returns more than 1 record delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t2 where t11.a = t2.a); select * from t11; a b @@ -584,9 +587,9 @@ create table t3 (a int); insert into t2 values (1); insert into t3 values (1),(2); INSERT INTO t1 (x) VALUES ((SELECT x FROM t1)); -You can't specify target table 't1' for update in FROM clause +ERROR HY000: You can't specify target table 't1' for update in FROM clause INSERT INTO t1 (x) VALUES ((SELECT a FROM t3)); -Subselect returns more than 1 record +ERROR 21000: Subselect returns more than 1 record INSERT INTO t1 (x) VALUES ((SELECT a FROM t2)); select * from t1; x @@ -605,7 +608,7 @@ x 3 3 INSERT INTO t1 (x) select (SELECT SUM(x)+2 FROM t1) FROM t2; -You can't specify target table 't1' for update in FROM clause +ERROR HY000: You can't specify target table 't1' for update in FROM clause INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2)); select * from t1; x @@ -623,9 +626,9 @@ insert into t3 values (1),(2); select * from t1; x y replace into t1 (x, y) VALUES ((SELECT x FROM t1), (SELECT a+1 FROM t2)); -You can't specify target table 't1' for update in FROM clause +ERROR HY000: You can't specify target table 't1' for update in FROM clause replace into t1 (x, y) VALUES ((SELECT a FROM t3), (SELECT a+1 FROM t2)); -Subselect returns more than 1 record +ERROR 21000: Subselect returns more than 1 record replace into t1 (x, y) VALUES ((SELECT a FROM t2), (SELECT a+1 FROM t2)); select * from t1; x y @@ -652,7 +655,7 @@ x y 2 1 drop table t1, t2, t3; SELECT * FROM (SELECT 1) b WHERE 1 IN (SELECT *); -No tables used +ERROR HY000: No tables used CREATE TABLE t2 (id int(11) default NULL, KEY id (id)) TYPE=MyISAM CHARSET=latin1; INSERT INTO t2 VALUES (1),(2); SELECT * FROM t2 WHERE id IN (SELECT 1); @@ -687,9 +690,9 @@ SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 2); id 2 INSERT INTO t2 VALUES ((SELECT * FROM t2)); -You can't specify target table 't2' for update in FROM clause +ERROR HY000: You can't specify target table 't2' for update in FROM clause INSERT INTO t2 VALUES ((SELECT id FROM t2)); -You can't specify target table 't2' for update in FROM clause +ERROR HY000: You can't specify target table 't2' for update in FROM clause SELECT * FROM t2; id 1 @@ -697,7 +700,7 @@ id CREATE TABLE t1 (id int(11) default NULL, KEY id (id)) TYPE=MyISAM CHARSET=latin1; INSERT INTO t1 values (1),(1); UPDATE t2 SET id=(SELECT * FROM t1); -Subselect returns more than 1 record +ERROR 21000: Subselect returns more than 1 record drop table t2, t1; create table t1 (a int); insert into t1 values (1),(2),(3); @@ -828,9 +831,9 @@ id select_type table type possible_keys key key_len ref rows Extra drop table t1,t2; create table t1 (a float); select 10.5 IN (SELECT * from t1 LIMIT 1); -This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' +ERROR 42000: This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' select 10.5 IN (SELECT * from t1 LIMIT 1 UNION SELECT 1.5); -This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' +ERROR 42000: This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' drop table t1; create table t1 (a int, b int, c varchar(10)); create table t2 (a int); @@ -882,7 +885,7 @@ select ROW(1, 1, 'a') IN (select b,a,c from t1 where c='b' or c='a'); ROW(1, 1, 'a') IN (select b,a,c from t1 where c='b' or c='a') 1 select ROW(1, 1, 'a') IN (select b,a,c from t1 limit 2); -This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' +ERROR 42000: This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' drop table t1; create table t1 (a int); insert into t1 values (1); @@ -897,13 +900,13 @@ select @a; 1 drop table t1; do (SELECT a from t1); -Table 'test.t1' doesn't exist +ERROR 42S02: Table 'test.t1' doesn't exist set @a:=(SELECT a from t1); -Table 'test.t1' doesn't exist +ERROR 42S02: Table 'test.t1' doesn't exist CREATE TABLE t1 (a int, KEY(a)); HANDLER t1 OPEN; HANDLER t1 READ a=((SELECT 1)); -You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use +ERROR 42000: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use HANDLER t1 CLOSE; drop table t1; create table t1 (a int); @@ -926,7 +929,7 @@ drop table t1, t2; CREATE TABLE `t1` (`i` int(11) NOT NULL default '0',PRIMARY KEY (`i`)) TYPE=MyISAM CHARSET=latin1; INSERT INTO t1 VALUES (1); UPDATE t1 SET i=i+1 WHERE i=(SELECT MAX(i)); -Invalid use of group function +ERROR HY000: Invalid use of group function drop table t1; CREATE TABLE t1 (a int(1)); EXPLAIN SELECT (SELECT RAND() FROM t1) FROM t1; @@ -1033,7 +1036,7 @@ id select_type table type possible_keys key key_len ref rows Extra 3 UNCACHEABLE SUBQUERY t1 ALL NULL NULL NULL NULL 3 drop table t1; select t1.Continent, t2.Name, t2.Population from t1 LEFT JOIN t2 ON t1.Code = t2.Country where t2.Population IN (select max(t2.Population) AS Population from t2, t1 where t2.Country = t1.Code group by Continent); -Table 'test.t1' doesn't exist +ERROR 42S02: Table 'test.t1' doesn't exist CREATE TABLE t1 ( ID int(11) NOT NULL auto_increment, name char(35) NOT NULL default '', @@ -1098,11 +1101,11 @@ PRIMARY KEY (`i`) ) TYPE=MyISAM CHARSET=latin1; INSERT INTO t1 VALUES (1); UPDATE t1 SET i=i+(SELECT MAX(i) FROM (SELECT 1) t) WHERE i=(SELECT MAX(i)); -Invalid use of group function +ERROR HY000: Invalid use of group function UPDATE t1 SET i=i+1 WHERE i=(SELECT MAX(i)); -Invalid use of group function +ERROR HY000: Invalid use of group function UPDATE t1 SET t.i=i+(SELECT MAX(i) FROM (SELECT 1) t); -Unknown table 't' in field list +ERROR 42S02: Unknown table 't' in field list drop table t1; CREATE TABLE t1 ( id int(11) default NULL diff --git a/mysql-test/r/temp_table.result b/mysql-test/r/temp_table.result index 5568e5b25d8..fbc5c234256 100644 --- a/mysql-test/r/temp_table.result +++ b/mysql-test/r/temp_table.result @@ -24,9 +24,9 @@ a b create TEMPORARY TABLE t2 type=heap select * from t1; create TEMPORARY TABLE IF NOT EXISTS t2 (a int) type=heap; CREATE TEMPORARY TABLE t1 (a int not null, b char (10) not null); -Table 't1' already exists +ERROR 42S01: Table 't1' already exists ALTER TABLE t1 RENAME t2; -Table 't2' already exists +ERROR 42S01: Table 't2' already exists select * from t2; a b 4 e @@ -74,7 +74,7 @@ drop table t1,t2; create temporary table t1 (a int not null); insert into t1 values (1),(1); alter table t1 add primary key (a); -Duplicate entry '1' for key 1 +ERROR 23000: Duplicate entry '1' for key 1 drop table t1; CREATE TABLE t1 ( d datetime default NULL diff --git a/mysql-test/r/truncate.result b/mysql-test/r/truncate.result index ad390c9fa92..0e256c1bf8e 100644 --- a/mysql-test/r/truncate.result +++ b/mysql-test/r/truncate.result @@ -14,7 +14,7 @@ select * from t1; a b c1 drop table t1; select count(*) from t1; -Table 'test.t1' doesn't exist +ERROR 42S02: Table 'test.t1' doesn't exist create temporary table t1 (n int); insert into t1 values (1),(2),(3); truncate table t1; @@ -22,4 +22,4 @@ select * from t1; n drop table t1; truncate non_existing_table; -Table 'test.non_existing_table' doesn't exist +ERROR 42S02: Table 'test.non_existing_table' doesn't exist diff --git a/mysql-test/r/type_blob.result b/mysql-test/r/type_blob.result index f97e2bc06b5..52d5480d63c 100644 --- a/mysql-test/r/type_blob.result +++ b/mysql-test/r/type_blob.result @@ -27,9 +27,9 @@ t3 CREATE TABLE `t3` ( drop table t1,t2,t3 #; CREATE TABLE t1 (a char(257) default "hello"); -Too big column length for column 'a' (max = 255). Use BLOB instead +ERROR 42000: Too big column length for column 'a' (max = 255). Use BLOB instead CREATE TABLE t2 (a blob default "hello"); -BLOB column 'a' can't have a default value +ERROR 42000: BLOB column 'a' can't have a default value drop table if exists t1,t2; create table t1 (nr int(5) not null auto_increment,b blob,str char(10), primary key (nr)); insert into t1 values (null,"a","A"); @@ -347,7 +347,7 @@ a 1 hello 1 drop table t1; create table t1 (a text, key (a(300))); -Incorrect sub part key. The used key part isn't a string, the used length is longer than the key part or the store engine doesn't support unique sub keys +ERROR HY000: Incorrect sub part key. The used key part isn't a string, the used length is longer than the key part or the store engine doesn't support unique sub keys create table t1 (a text, key (a(255))); drop table t1; CREATE TABLE t1 ( diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index c0e48fb42d8..57df0c67ac9 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -436,8 +436,8 @@ a 99999999999 drop table t1; CREATE TABLE t1 (a_dec DECIMAL(-1,0)); -Too big column length for column 'a_dec' (max = 255). Use BLOB instead +ERROR 42000: Too big column length for column 'a_dec' (max = 255). Use BLOB instead CREATE TABLE t1 (a_dec DECIMAL(-2,1)); -Too big column length for column 'a_dec' (max = 255). Use BLOB instead +ERROR 42000: Too big column length for column 'a_dec' (max = 255). Use BLOB instead CREATE TABLE t1 (a_dec DECIMAL(-1,1)); -Too big column length for column 'a_dec' (max = 255). Use BLOB instead +ERROR 42000: Too big column length for column 'a_dec' (max = 255). Use BLOB instead diff --git a/mysql-test/r/type_float.result b/mysql-test/r/type_float.result index 92cf4f70843..76f82feb50e 100644 --- a/mysql-test/r/type_float.result +++ b/mysql-test/r/type_float.result @@ -100,5 +100,5 @@ min(a) -0.010 drop table t1; create table t1 (f float(54)); -Incorrect column specifier for column 'f' +ERROR 42000: Incorrect column specifier for column 'f' drop table if exists t1; diff --git a/mysql-test/r/type_ranges.result b/mysql-test/r/type_ranges.result index c059d5b58a0..34ae1086e2c 100644 --- a/mysql-test/r/type_ranges.result +++ b/mysql-test/r/type_ranges.result @@ -285,7 +285,7 @@ create table t1 (c int); insert into t1 values(1),(2); create table t2 select * from t1; create table t3 select * from t1, t2; -Duplicate column name 'c' +ERROR 42S21: Duplicate column name 'c' create table t3 select t1.c AS c1, t2.c AS c2,1 as "const" from t1, t2; show full columns from t3; Field Type Collation Null Key Default Extra Privileges Comment diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 272ffdd330e..5b7b26bc1bb 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -85,7 +85,7 @@ a b 2 b 1 a (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by t1.b; -Table 't1' from one of SELECT's can not be used in global ORDER clause +ERROR 42000: Table 't1' from one of SELECT's can not be used in global ORDER clause explain (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by b desc; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 4 @@ -95,7 +95,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 4 2 UNION t2 ALL NULL NULL NULL NULL 4 explain select xx from t1 union select 1; -Unknown column 'xx' in 'field list' +ERROR 42S22: Unknown column 'xx' in 'field list' explain select a,b from t1 union select 1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 4 @@ -110,38 +110,38 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE 2 UNION NULL NULL NULL NULL NULL NULL NULL Impossible WHERE select a,b from t1 into outfile 'skr' union select a,b from t2; -Wrong usage of UNION and INTO +ERROR HY000: Wrong usage of UNION and INTO select a,b from t1 order by a union select a,b from t2; -Wrong usage of UNION and ORDER BY +ERROR HY000: Wrong usage of UNION and ORDER BY insert into t3 select a from t1 order by a union select a from t2; -Wrong usage of UNION and ORDER BY +ERROR HY000: Wrong usage of UNION and ORDER BY create table t3 select a,b from t1 union select a from t2; -The used SELECT statements have a different number of columns +ERROR 21000: The used SELECT statements have a different number of columns select a,b from t1 union select a from t2; -The used SELECT statements have a different number of columns +ERROR 21000: The used SELECT statements have a different number of columns select * from t1 union select a from t2; -The used SELECT statements have a different number of columns +ERROR 21000: The used SELECT statements have a different number of columns select a from t1 union select * from t2; -The used SELECT statements have a different number of columns +ERROR 21000: The used SELECT statements have a different number of columns select * from t1 union select SQL_BUFFER_RESULT * from t2; -Wrong usage/placement of 'SQL_BUFFER_RESULT' +ERROR 42000: Wrong usage/placement of 'SQL_BUFFER_RESULT' create table t3 select a,b from t1 union all select a,b from t2; insert into t3 select a,b from t1 union all select a,b from t2; replace into t3 select a,b as c from t1 union all select a,b from t2; drop table t1,t2,t3; select * union select 1; -No tables used +ERROR HY000: No tables used select 1 as a,(select a union select a); a (select a union select a) 1 1 (select 1) union (select 2) order by 0; -Unknown column '0' in 'order clause' +ERROR 42S22: Unknown column '0' in 'order clause' SELECT @a:=1 UNION SELECT @a:=@a+1; @a:=1 1 2 (SELECT 1) UNION (SELECT 2) ORDER BY (SELECT a); -Unknown column 'a' in 'field list' +ERROR 42S22: Unknown column 'a' in 'field list' (SELECT 1,3) UNION (SELECT 2,1) ORDER BY (SELECT 2); 1 3 1 3 diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result index 1d483da2c77..a0370272396 100644 --- a/mysql-test/r/update.result +++ b/mysql-test/r/update.result @@ -5,11 +5,11 @@ update t1 set a=a+10 where a > 34; update t1 set a=a+100 where a > 0; update t1 set a=a+100 where a=1 and a=2; update t1 set a=b+100 where a=1 and a=2; -Unknown column 'b' in 'field list' +ERROR 42S22: Unknown column 'b' in 'field list' update t1 set a=b+100 where c=1 and a=2; -Unknown column 'c' in 'where clause' +ERROR 42S22: Unknown column 'c' in 'where clause' update t1 set d=a+100 where a=1; -Unknown column 'd' in 'field list' +ERROR 42S22: Unknown column 'd' in 'field list' select * from t1; a 101 diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result index 6e3b9309351..3a53dbdded0 100644 --- a/mysql-test/r/user_var.result +++ b/mysql-test/r/user_var.result @@ -1,6 +1,6 @@ drop table if exists t1,t2; set @a := foo; -Unknown column 'foo' in 'field list' +ERROR 42S22: Unknown column 'foo' in 'field list' set @a := connection_id() + 3; select @a - connection_id(); @a - connection_id() diff --git a/mysql-test/r/varbinary.result b/mysql-test/r/varbinary.result index 2d04da31caa..5464d741f70 100644 --- a/mysql-test/r/varbinary.result +++ b/mysql-test/r/varbinary.result @@ -16,9 +16,9 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 const UNIQ UNIQ 8 const 1 drop table t1; select x'hello'; -You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near 'x'hello'' at line 1 +ERROR 42000: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near 'x'hello'' at line 1 select 0xfg; -Unknown column '0xfg' in 'field list' +ERROR 42S22: Unknown column '0xfg' in 'field list' create table t1 select 1 as x, 2 as xx; select x,xx from t1; x xx diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index b5e05cf6953..1a773acd23e 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -164,42 +164,42 @@ select ROUND(RAND(),5); ROUND(RAND(),5) 0.02887 set big_tables=OFFF; -Variable 'big_tables' can't be set to the value of 'OFFF' +ERROR 42000: Variable 'big_tables' can't be set to the value of 'OFFF' set big_tables="OFFF"; -Variable 'big_tables' can't be set to the value of 'OFFF' +ERROR 42000: Variable 'big_tables' can't be set to the value of 'OFFF' set unknown_variable=1; -Unknown system variable 'unknown_variable' +ERROR HY000: Unknown system variable 'unknown_variable' set max_join_size="hello"; -Wrong argument type to variable 'max_join_size' +ERROR 42000: Wrong argument type to variable 'max_join_size' set table_type=UNKNOWN_TABLE_TYPE; -Variable 'table_type' can't be set to the value of 'UNKNOWN_TABLE_TYPE' +ERROR 42000: Variable 'table_type' can't be set to the value of 'UNKNOWN_TABLE_TYPE' set table_type=INNODB, big_tables=2; -Variable 'big_tables' can't be set to the value of '2' +ERROR 42000: Variable 'big_tables' can't be set to the value of '2' show local variables like 'table_type'; Variable_name Value table_type HEAP set SESSION query_cache_size=10000; -Variable 'query_cache_size' is a GLOBAL variable and should be set with SET GLOBAL +ERROR HY000: Variable 'query_cache_size' is a GLOBAL variable and should be set with SET GLOBAL set GLOBAL table_type=DEFAULT; -Variable 'table_type' doesn't have a default value +ERROR 42000: Variable 'table_type' doesn't have a default value set character_set_client=UNKNOWN_CHARACTER_SET; -Unknown character set: 'UNKNOWN_CHARACTER_SET' +ERROR 42000: Unknown character set: 'UNKNOWN_CHARACTER_SET' set global autocommit=1; -Variable 'autocommit' is a LOCAL variable and can't be used with SET GLOBAL +ERROR HY000: Variable 'autocommit' is a LOCAL variable and can't be used with SET GLOBAL select @@global.timestamp; -Variable 'timestamp' is a LOCAL variable and can't be used with SET GLOBAL +ERROR HY000: Variable 'timestamp' is a LOCAL variable and can't be used with SET GLOBAL set @@version=''; -Unknown system variable 'version' +ERROR HY000: Unknown system variable 'version' set @@concurrent_insert=1; -Variable 'concurrent_insert' is a GLOBAL variable and should be set with SET GLOBAL +ERROR HY000: Variable 'concurrent_insert' is a GLOBAL variable and should be set with SET GLOBAL set @@global.sql_auto_is_null=1; -Variable 'sql_auto_is_null' is a LOCAL variable and can't be used with SET GLOBAL +ERROR HY000: Variable 'sql_auto_is_null' is a LOCAL variable and can't be used with SET GLOBAL select @@global.sql_auto_is_null; -Variable 'sql_auto_is_null' is a LOCAL variable and can't be used with SET GLOBAL +ERROR HY000: Variable 'sql_auto_is_null' is a LOCAL variable and can't be used with SET GLOBAL set myisam_max_sort_file_size=100; -Variable 'myisam_max_sort_file_size' is a GLOBAL variable and should be set with SET GLOBAL +ERROR HY000: Variable 'myisam_max_sort_file_size' is a GLOBAL variable and should be set with SET GLOBAL set myisam_max_extra_sort_file_size=100; -Variable 'myisam_max_extra_sort_file_size' is a GLOBAL variable and should be set with SET GLOBAL +ERROR HY000: Variable 'myisam_max_extra_sort_file_size' is a GLOBAL variable and should be set with SET GLOBAL set autocommit=1; set big_tables=1; select @@autocommit, @@big_tables; @@ -325,7 +325,7 @@ test.t2 check status OK select max(a) +1, max(a) +2 into @xx,@yy from t1; drop table t1,t2; select @@xxxxxxxxxx; -Unknown system variable 'xxxxxxxxxx' +ERROR HY000: Unknown system variable 'xxxxxxxxxx' select 1; 1 1 diff --git a/mysql-test/t/ansi.test b/mysql-test/t/ansi.test index da82b7a9e31..f4aef5c3f8e 100644 --- a/mysql-test/t/ansi.test +++ b/mysql-test/t/ansi.test @@ -17,3 +17,8 @@ SELECT id,NULL,1,1.1,'a' FROM t1 GROUP BY id; --error 1055 SELECT id FROM t1 GROUP BY id2; drop table t1; + +set sql_mode="MySQL40"; +select @@sql_mode; +set sql_mode="ANSI"; +select @@sql_mode; diff --git a/mysql-test/t/derived.test b/mysql-test/t/derived.test index 2ce90c93bd9..4f0af1edbaa 100644 --- a/mysql-test/t/derived.test +++ b/mysql-test/t/derived.test @@ -65,3 +65,12 @@ SELECT 1 as a FROM (SELECT a UNION SELECT 1) b; SELECT 1 as a FROM (SELECT 1 UNION SELECT a) b; --error 1054 select 1 from (select 2) a order by 0; + +# +# Test of explain (bug #251) +# + +create table t1 (id int); +insert into t1 values (1),(2),(3); +describe select * from (select * from t1 group by id) bar; +drop table t1; diff --git a/mysql-test/t/func_system.test b/mysql-test/t/func_system.test index 41b776719dc..998b2a5c3f4 100644 --- a/mysql-test/t/func_system.test +++ b/mysql-test/t/func_system.test @@ -18,7 +18,7 @@ select version()>=_utf8"3.23.29"; select version()>=_latin1"3.23.29"; select charset(version()); -create table t1 select database(), user(), version(); +create table t1 (version char(40)) select database(), user(), version() as 'version'; show create table t1; drop table t1; diff --git a/mysql-test/t/lowercase_table.test b/mysql-test/t/lowercase_table.test index f3a747c4d61..348116b02f2 100644 --- a/mysql-test/t/lowercase_table.test +++ b/mysql-test/t/lowercase_table.test @@ -14,4 +14,3 @@ ALTER TABLE T2 ADD new_col int not null; ALTER TABLE T2 RENAME T3; show tables like 't_'; drop table t3; - diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index 99bb2656001..3b1e3fac7c2 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -1,31 +1,79 @@ --disable_warnings -drop table if exists t1; +drop table if exists t1,t2; --enable_warnings -create table t1 ( product varchar(32), country varchar(32), year int, profit int); -insert into t1 values ( 'Computer', 'India',2000, 1200), -( 'TV', 'United States', 1999, 150), -( 'Calculator', 'United States', 1999,50), -( 'Computer', 'United States', 1999,1500), -( 'Computer', 'United States', 2000,1500), -( 'TV', 'United States', 2000, 150), -( 'TV', 'India', 2000, 100), -( 'TV', 'India', 2000, 100), -( 'Calculator', 'United States', 2000,75), -( 'Calculator', 'India', 2000,75), -( 'TV', 'India', 1999, 100), -( 'Computer', 'India', 1999,1200), -( 'Computer', 'United States', 2000,1500), -( 'Calculator', 'United States', 2000,75); ---error 1235 -select product, country , year, sum(profit) from t1 group by product, country, year with cube; ---error 1235 -explain select product, country , year, sum(profit) from t1 group by product, country, year with cube; +create table t1 (product varchar(32), country_id int not null, year int, profit int); +insert into t1 values ( 'Computer', 2,2000, 1200), +( 'TV', 1, 1999, 150), +( 'Calculator', 1, 1999,50), +( 'Computer', 1, 1999,1500), +( 'Computer', 1, 2000,1500), +( 'TV', 1, 2000, 150), +( 'TV', 2, 2000, 100), +( 'TV', 2, 2000, 100), +( 'Calculator', 1, 2000,75), +( 'Calculator', 2, 2000,75), +( 'TV', 1, 1999, 100), +( 'Computer', 1, 1999,1200), +( 'Computer', 2, 2000,1500), +( 'Calculator', 2, 2000,75), +( 'Phone', 3, 2003,10) +; + +create table t2 (country_id int primary key, country char(20) not null); +insert into t2 values (1, 'USA'),(2,'India'), (3,'Finland'); + +# First simple rollups, with just grand total +select product, sum(profit) from t1 group by product; +select product, sum(profit) from t1 group by product with rollup; +select product, sum(profit) from t1 group by 1 with rollup; +select product, sum(profit),avg(profit) from t1 group by product with rollup; + +# Sub totals +select product, country_id , year, sum(profit) from t1 group by product, country_id, year; +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup; +explain select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup; +select product, country_id , sum(profit) from t1 group by product desc, country_id with rollup; + +# limit +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup limit 5; +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup limit 3,3; + +select product, country_id, count(*), count(distinct year) from t1 group by product, country_id; +select product, country_id, count(*), count(distinct year) from t1 group by product, country_id with rollup; + +# Test of having +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup having country_id = 1; +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup having sum(profit) > 200; +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup having sum(profit) > 7000; + +# Functions +select concat(product,':',country_id) as 'prod', concat(":",year,":") as 'year',1+1, sum(profit)/count(*) from t1 group by 1,2 with rollup; +select product, sum(profit)/count(*) from t1 group by product with rollup; +select left(product,4) as prod, sum(profit)/count(*) from t1 group by prod with rollup; +select concat(product,':',country_id), 1+1, sum(profit)/count(*) from t1 group by concat(product,':',country_id) with rollup; + +# Joins +select product, country , year, sum(profit) from t1,t2 where t1.country_id=t2.country_id group by product, country, year with rollup; + +# Derived tables and sub selects +select product, `sum` from (select product, sum(profit) as 'sum' from t1 group by product with rollup) as tmp where product is null; +select product from t1 where exists (select product, country_id , sum(profit) from t1 as t2 where t1.product=t2.product group by product, country_id with rollup having sum(profit) > 6000); + +# The following doesn't return the expected answer, but this is a limitation +# in the implementation so we should just document it +select product, country_id , year, sum(profit) from t1 group by product, country_id, year having country_id is NULL; +select concat(':',product,':'), sum(profit),avg(profit) from t1 group by product with rollup; + +# Error handling + +# Cube is not yet implemented --error 1235 -select product, country , year, sum(profit) from t1 group by product, country, year with rollup; +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with cube; --error 1235 -explain select product, country , year, sum(profit) from t1 group by product, country, year with rollup; +explain select product, country_id , year, sum(profit) from t1 group by product, country_id, year with cube; --error 1235 -select product, country , year, sum(profit) from t1 group by product, country, year with cube union all select product, country , year, sum(profit) from t1 group by product, country, year with rollup; -drop table t1; +select product, country_id , year, sum(profit) from t1 group by product, country_id, year with cube union all select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup; + +drop table t1,t2; diff --git a/mysql-test/t/sql_mode.test b/mysql-test/t/sql_mode.test index fd464f74de4..d3531f0c440 100644 --- a/mysql-test/t/sql_mode.test +++ b/mysql-test/t/sql_mode.test @@ -24,7 +24,7 @@ show create table t1; set @@sql_mode="no_field_options,mysql323,mysql40"; show variables like 'sql_mode'; show create table t1; -set @@sql_mode="postgresql,oracle,mssql,db2,sapdb"; -show variables like 'sql_mode'; +set sql_mode="postgresql,oracle,mssql,db2,sapdb"; +select @@sql_mode; show create table t1; drop table t1; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 8377a756c5b..c116d03e274 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -59,7 +59,7 @@ SELECT 1 as a,(SELECT a+a) b,(SELECT b); create table t1 (a int); create table t2 (a int, b int); create table t3 (a int); -create table t4 (a int, b int); +create table t4 (a int not null, b int not null); insert into t1 values (2); insert into t2 values (1,7),(2,7); insert into t4 values (4,8),(3,8),(5,9); @@ -106,11 +106,13 @@ delete from t2 where a=100; select * from t3 where a in (select a,b from t2); -- error 1239 select * from t3 where a in (select * from t2); -insert into t4 values (12,7),(1,7),(10,9),(9,6),(7,6),(3,9); -select b,max(a) as ma from t4 group by b having b < (select max(t2.a) -from t2 where t2.b=t4.b); -select b,max(a) as ma from t4 group by b having b >= (select max(t2.a) -from t2 where t2.b=t4.b); +insert into t4 values (12,7),(1,7),(10,9),(9,6),(7,6),(3,9),(1,10); +-- empty set +select b,max(a) as ma from t4 group by b having b < (select max(t2.a) from t2 where t2.b=t4.b); +insert into t2 values (2,10); +select b,max(a) as ma from t4 group by b having ma < (select max(t2.a) from t2 where t2.b=t4.b); +delete from t2 where a=2 and b=10; +select b,max(a) as ma from t4 group by b having b >= (select max(t2.a) from t2 where t2.b=t4.b); create table t5 (a int); select (select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a), a from t2; insert into t5 values (5); diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 88f561e0e6d..7d256a70b10 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -60,7 +60,7 @@ EXTRA_DIST = $(EXTRA_SCRIPTS) \ mysqlaccess.conf \ mysqlbug -pkgdata_DATA = fill_help_tables.sql +pkgdata_DATA = fill_help_tables.sql mysql_fix_privilege_tables.sql # mysqlbug should be distributed built so that people can report build # failures with it. diff --git a/scripts/mysql_fix_privilege_tables.sh b/scripts/mysql_fix_privilege_tables.sh index 05d6f3ffb71..5d392f719f0 100644 --- a/scripts/mysql_fix_privilege_tables.sh +++ b/scripts/mysql_fix_privilege_tables.sh @@ -1,212 +1,166 @@ #!/bin/sh +# This script is a wrapper to pipe the mysql_fix_privilege_tables.sql +# through the mysql client program to the mysqld server -root_password="$1" +# Default values (Can be changed in my.cnf) +password="" host="localhost" user="root" - -if test -z $1 ; then - cmd="@bindir@/mysql -f --user=$user --host=$host mysql" +sql_only=0 +basedir="" +verbose=0 +args="" + +file=mysql_fix_privilege_tables.sql + +# The following code is almost identical to the code in mysql_install_db.sh + +parse_arguments() { + # We only need to pass arguments through to the server if we don't + # handle them here. So, we collect unrecognized options (passed on + # the command line) into the args variable. + pick_args= + if test "$1" = PICK-ARGS-FROM-ARGV + then + pick_args=1 + shift + fi + + for arg do + case "$arg" in + --basedir=*) basedir=`echo "$arg" | sed -e 's/^[^=]*=//'` ;; + --user=*) user=`echo "$arg" | sed -e 's/^[^=]*=//'` ;; + --password=*) password=`echo "$arg" | sed -e 's/^[^=]*=//'` ;; + --host=*) host=`echo "$arg" | sed -e 's/^[^=]*=//'` ;; + --sql|--sql-only) sql_only=1;; + --verbose) verbose=1 ;; + *) + if test -n "$pick_args" + then + # This sed command makes sure that any special chars are quoted, + # so the arg gets passed exactly to the server. + args="$args "`echo "$arg" | sed -e 's,\([^a-zA-Z0-9_.-]\),\\\\\1,g'` + fi + ;; + esac + done +} + +# Get first arguments from the my.cfg file, groups [mysqld] and +# [mysql_install_db], and then merge with the command line arguments +if test -x ./bin/my_print_defaults +then + print_defaults="./bin/my_print_defaults" +elif test -x @bindr@/my_print_defaults +then + print_defaults="@bindir@/my_print_defaults" +elif test -x @bindir@/mysql_print_defaults +then + print_defaults="@bindir@/mysql_print_defaults" else - root_password="$1" - cmd="@bindir@/mysql -f --user=$user --password=$root_password --host=$host mysql" + print_defaults="my_print_defaults" fi -# Debian addition -if [ "$1" = "--sql-only" ]; then - root_password="" - cmd="/usr/share/mysql/echo_stderr" -fi +parse_arguments `$print_defaults $defaults mysql_install_db mysql_fix_privilege_tables` +parse_arguments PICK-ARGS-FROM-ARGV "$@" -echo "This scripts updates the mysql.user, mysql.db, mysql.host and the" -echo "mysql.func tables to MySQL 3.22.14 and above." -echo "" -echo "This is needed if you want to use the new GRANT functions," -echo "CREATE AGGREGATE FUNCTION or want to use the more secure passwords in 3.23" -echo "" -echo "If you get 'Access denied' errors, you should run this script again" -echo "and give the MySQL root user password as an argument!" - -echo "Converting all privilege tables to MyISAM format" -$cmd < Grant -# and Create -> Alter, Index, References - -if test $res = 0 +if test -z "$basedir" then - echo "Setting default privileges for the new grant, index and alter privileges" - $cmd < Column_priv from MySQL 3.22.12 -# - -echo "Changing name of columns_priv.Type -> columns_priv.Column_priv" -echo "You can ignore any Unknown column errors from this" - -$cmd <""; -END_OF_DATA - echo "" + password=`echo $args | sed -e 's/ *//g'` fi -# Add fields that can be used to limit number of questions and connections -# for some users. - -$cmd < /dev/null 2>&1 +else + cat $sql_file | $cmd > /dev/null +fi +if test $? = 0 +then + s_echo "done" +else + s_echo "Got a failure from command:" + s_echo "$cmd" + s_echo "Please check the above output and try again." + if test $verbose = 0 + then + s_echo "" + s_echo "Running the script with the --verbose option may give you some information" + s_echo "of what went wrong." + fi + s_echo "" + s_echo "If you get an 'Access denied' error, you should run this script again and" + s_echo "give the MySQL root user password as an argument with the --password= option" +fi diff --git a/scripts/mysql_fix_privilege_tables.sql b/scripts/mysql_fix_privilege_tables.sql new file mode 100644 index 00000000000..3466e3cf799 --- /dev/null +++ b/scripts/mysql_fix_privilege_tables.sql @@ -0,0 +1,89 @@ +ALTER TABLE user type=MyISAM; +ALTER TABLE db type=MyISAM; +ALTER TABLE host type=MyISAM; +ALTER TABLE func type=MyISAM; +ALTER TABLE columns_priv type=MyISAM; +ALTER TABLE tables_priv type=MyISAM; +ALTER TABLE user change password password char(45) not null; +ALTER TABLE user add File_priv enum('N','Y') NOT NULL; +CREATE TABLE IF NOT EXISTS func ( + name char(64) DEFAULT '' NOT NULL, + ret tinyint(1) DEFAULT '0' NOT NULL, + dl char(128) DEFAULT '' NOT NULL, + type enum ('function','aggregate') NOT NULL, + PRIMARY KEY (name) +); + +-- Detect whether or not we had the Grant_priv column +SET @hadGrantPriv:=0; +SELECT @hadGrantPriv:=1 FROM user WHERE Grant_priv LIKE '%'; + +ALTER TABLE user add Grant_priv enum('N','Y') NOT NULL,add References_priv enum('N','Y') NOT NULL,add Index_priv enum('N','Y') NOT NULL,add Alter_priv enum('N','Y') NOT NULL; +ALTER TABLE host add Grant_priv enum('N','Y') NOT NULL,add References_priv enum('N','Y') NOT NULL,add Index_priv enum('N','Y') NOT NULL,add Alter_priv enum('N','Y') NOT NULL; +ALTER TABLE db add Grant_priv enum('N','Y') NOT NULL,add References_priv enum('N','Y') NOT NULL,add Index_priv enum('N','Y') NOT NULL,add Alter_priv enum('N','Y') NOT NULL; + +--- Fix privileges for old tables +UPDATE user SET Grant_priv=File_priv,References_priv=Create_priv,Index_priv=Create_priv,Alter_priv=Create_priv WHERE @hadGrantPriv = 0; +UPDATE db SET References_priv=Create_priv,Index_priv=Create_priv,Alter_priv=Create_priv WHERE @hadGrantPriv = 0; +UPDATE host SET References_priv=Create_priv,Index_priv=Create_priv,Alter_priv=Create_priv WHERE @hadGrantPriv = 0; + +ALTER TABLE user +ADD ssl_type enum('','ANY','X509', 'SPECIFIED') NOT NULL, +ADD ssl_cipher BLOB NOT NULL, +ADD x509_issuer BLOB NOT NULL, +ADD x509_subject BLOB NOT NULL; +ALTER TABLE user MODIFY ssl_type enum('','ANY','X509', 'SPECIFIED') NOT NULL; + +CREATE TABLE IF NOT EXISTS tables_priv ( + Host char(60) DEFAULT '' NOT NULL, + Db char(60) DEFAULT '' NOT NULL, + User char(16) DEFAULT '' NOT NULL, + Table_name char(60) DEFAULT '' NOT NULL, + Grantor char(77) DEFAULT '' NOT NULL, + Timestamp timestamp(14), + Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter') DEFAULT '' NOT NULL, + Column_priv set('Select','Insert','Update','References') DEFAULT '' NOT NULL, + PRIMARY KEY (Host,Db,User,Table_name) +); + +CREATE TABLE IF NOT EXISTS columns_priv ( + Host char(60) DEFAULT '' NOT NULL, + Db char(60) DEFAULT '' NOT NULL, + User char(16) DEFAULT '' NOT NULL, + Table_name char(60) DEFAULT '' NOT NULL, + Column_name char(59) DEFAULT '' NOT NULL, + Timestamp timestamp(14), + Column_priv set('Select','Insert','Update','References') DEFAULT '' NOT NULL, + PRIMARY KEY (Host,Db,User,Table_name,Column_name) +); + +ALTER TABLE columns_priv change Type Column_priv set('Select','Insert','Update','References') DEFAULT '' NOT NULL; + +ALTER TABLE func add type enum ('function','aggregate') NOT NULL; + +# Detect whether we had Show_db_priv +SET @hadShowDbPriv:=0; +SELECT @hadShowDbPriv:=1 FROM user WHERE Show_db_priv LIKE '%'; + +ALTER TABLE user +ADD Show_db_priv enum('N','Y') DEFAULT 'N' NOT NULL AFTER alter_priv, +ADD Super_priv enum('N','Y') DEFAULT 'N' NOT NULL AFTER Show_db_priv, +ADD Create_tmp_table_priv enum('N','Y') DEFAULT 'N' NOT NULL AFTER Super_priv, +ADD Lock_tables_priv enum('N','Y') DEFAULT 'N' NOT NULL AFTER Create_tmp_table_priv, +ADD Execute_priv enum('N','Y') DEFAULT 'N' NOT NULL AFTER Lock_tables_priv, +ADD Repl_slave_priv enum('N','Y') DEFAULT 'N' NOT NULL AFTER Execute_priv, +ADD Repl_client_priv enum('N','Y') DEFAULT 'N' NOT NULL AFTER Repl_slave_priv; + +UPDATE user SET show_db_priv= select_priv, super_priv=process_priv, execute_priv=process_priv, create_tmp_table_priv='Y', Lock_tables_priv='Y', Repl_slave_priv=file_priv, Repl_client_priv=file_priv where user<>"" AND @hadShowDbPriv = 0; + +ALTER TABLE user +ADD max_questions int(11) NOT NULL AFTER x509_subject, +ADD max_updates int(11) unsigned NOT NULL AFTER max_questions, +ADD max_connections int(11) unsigned NOT NULL AFTER max_updates; + +ALTER TABLE db +ADD Create_tmp_table_priv enum('N','Y') DEFAULT 'N' NOT NULL, +ADD Lock_tables_priv enum('N','Y') DEFAULT 'N' NOT NULL; +ALTER TABLE host +ADD Create_tmp_table_priv enum('N','Y') DEFAULT 'N' NOT NULL, +ADD Lock_tables_priv enum('N','Y') DEFAULT 'N' NOT NULL; diff --git a/sql/Makefile.am b/sql/Makefile.am index 608b959a8b9..1d8e8cde2db 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -64,7 +64,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \ thr_malloc.cc item_create.cc item_subselect.cc \ item_row.cc \ field.cc key.cc sql_class.cc sql_list.cc \ - net_serv.cc protocol.cc lock.cc my_lock.c \ + net_serv.cc protocol.cc sql_state.c \ + lock.cc my_lock.c \ sql_string.cc sql_manager.cc sql_map.cc \ mysqld.cc password.c hash_filo.cc hostname.cc \ set_var.cc sql_parse.cc sql_yacc.yy \ diff --git a/sql/item.cc b/sql/item.cc index 636cefb511b..bdf180b4828 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -117,7 +117,9 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs) /* - This function is only called when comparing items in the WHERE clause + This function is called when: + - Comparing items in the WHERE clause (when doing where optimization) + - When trying to find an ORDER BY/GROUP BY item in the SELECT part */ bool Item::eq(const Item *item, bool binary_cmp) const @@ -243,6 +245,7 @@ void Item_field::set_field(Field *field_par) decimals= field->decimals(); table_name=field_par->table_name; field_name=field_par->field_name; + db_name=field_par->table->table_cache_key; unsigned_flag=test(field_par->flags & UNSIGNED_FLAG); set_charset(field_par->charset(), COER_IMPLICIT); } @@ -344,9 +347,34 @@ longlong Item_field::val_int_result() return result_field->val_int(); } + bool Item_field::eq(const Item *item, bool binary_cmp) const { - return item->type() == FIELD_ITEM && ((Item_field*) item)->field == field; + if (item->type() != FIELD_ITEM) + return 0; + + Item_field *item_field= (Item_field*) item; + if (item_field->field) + return item_field->field == field; + /* + We may come here when we are trying to find a function in a GROUP BY + clause from the select list. + In this case the '100 % correct' way to do this would be to first + run fix_fields() on the GROUP BY item and then retry this function, but + I think it's better to relax the checking a bit as we will in + most cases do the correct thing by just checking the field name. + (In cases where we would choose wrong we would have to generate a + ER_NON_UNIQ_ERROR). + */ + return (!my_strcasecmp(system_charset_info, item_field->name, + field_name) && + (!item_field->table_name || + (!my_strcasecmp(table_alias_charset, item_field->table_name, + table_name) && + (!item_field->db_name || + (item_field->db_name && !my_strcasecmp(table_alias_charset, + item_field->db_name, + db_name)))))); } table_map Item_field::used_tables() const @@ -837,7 +865,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) return rf->fix_fields(thd, tables, ref) || rf->check_cols(1); } } - } + } else if (!tmp) return -1; diff --git a/sql/item.h b/sql/item.h index 470937f8ee7..934ea83d218 100644 --- a/sql/item.h +++ b/sql/item.h @@ -29,6 +29,8 @@ class Item { void operator=(Item &); public: static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); } + static void *operator new(size_t size, MEM_ROOT *mem_root) + { return (void*) alloc_root(mem_root, (uint) size); } static void operator delete(void *ptr,size_t size) {} /*lint -e715 */ enum Type {FIELD_ITEM, FUNC_ITEM, SUM_FUNC_ITEM, STRING_ITEM, diff --git a/sql/item_sum.cc b/sql/item_sum.cc index fa8bf7e6e0f..a57291702bc 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -217,11 +217,19 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) ** reset and add of sum_func ***********************************************************************/ -void Item_sum_sum::reset() +Item *Item_sum_sum::copy_or_same(THD* thd) { - null_value=1; sum=0.0; Item_sum_sum::add(); + return new (&thd->mem_root) Item_sum_sum(thd, *this); } + +bool Item_sum_sum::reset() +{ + null_value=1; sum=0.0; + return Item_sum_sum::add(); +} + + bool Item_sum_sum::add() { sum+=args[0]->val(); @@ -230,17 +238,26 @@ bool Item_sum_sum::add() return 0; } + double Item_sum_sum::val() { return sum; } -void Item_sum_count::reset() +Item *Item_sum_count::copy_or_same(THD* thd) { - count=0; add(); + return new (&thd->mem_root) Item_sum_count(thd, *this); } + +bool Item_sum_count::reset() +{ + count=0; + return add(); +} + + bool Item_sum_count::add() { if (!args[0]->maybe_null) @@ -260,14 +277,22 @@ longlong Item_sum_count::val_int() } /* -** Avgerage + Avgerage */ -void Item_sum_avg::reset() +Item *Item_sum_avg::copy_or_same(THD* thd) { - sum=0.0; count=0; Item_sum_avg::add(); + return new (&thd->mem_root) Item_sum_avg(thd, *this); } + +bool Item_sum_avg::reset() +{ + sum=0.0; count=0; + return Item_sum_avg::add(); +} + + bool Item_sum_avg::add() { double nr=args[0]->val(); @@ -292,7 +317,7 @@ double Item_sum_avg::val() /* -** Standard deviation + Standard deviation */ double Item_sum_std::val() @@ -301,15 +326,27 @@ double Item_sum_std::val() return tmp <= 0.0 ? 0.0 : sqrt(tmp); } +Item *Item_sum_std::copy_or_same(THD* thd) +{ + return new (&thd->mem_root) Item_sum_std(thd, *this); +} + + /* -** variance + Variance */ -void Item_sum_variance::reset() +Item *Item_sum_variance::copy_or_same(THD* thd) +{ + return new (&thd->mem_root) Item_sum_variance(thd, *this); +} + + +bool Item_sum_variance::reset() { sum=sum_sqr=0.0; count=0; - (void) Item_sum_variance::add(); + return Item_sum_variance::add(); } bool Item_sum_variance::add() @@ -440,6 +477,13 @@ Item_sum_hybrid::val_str(String *str) return str; // Keep compiler happy } + +Item *Item_sum_min::copy_or_same(THD* thd) +{ + return new (&thd->mem_root) Item_sum_min(thd, *this); +} + + bool Item_sum_min::add() { switch (hybrid_type) { @@ -487,6 +531,12 @@ bool Item_sum_min::add() } +Item *Item_sum_max::copy_or_same(THD* thd) +{ + return new (&thd->mem_root) Item_sum_max(thd, *this); +} + + bool Item_sum_max::add() { switch (hybrid_type) { @@ -541,11 +591,19 @@ longlong Item_sum_bit::val_int() return (longlong) bits; } -void Item_sum_bit::reset() + +bool Item_sum_bit::reset() +{ + bits=reset_bits; + return add(); +} + +Item *Item_sum_or::copy_or_same(THD* thd) { - bits=reset_bits; add(); + return new (&thd->mem_root) Item_sum_or(thd, *this); } + bool Item_sum_or::add() { ulonglong value= (ulonglong) args[0]->val_int(); @@ -554,6 +612,12 @@ bool Item_sum_or::add() return 0; } +Item *Item_sum_and::copy_or_same(THD* thd) +{ + return new (&thd->mem_root) Item_sum_and(thd, *this); +} + + bool Item_sum_and::add() { ulonglong value= (ulonglong) args[0]->val_int(); @@ -1032,12 +1096,21 @@ Item_sum_count_distinct::~Item_sum_count_distinct() bool Item_sum_count_distinct::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { - if (Item_sum_num::fix_fields(thd, tables, ref) || - !(tmp_table_param= new TMP_TABLE_PARAM)) + if (Item_sum_num::fix_fields(thd, tables, ref)) return 1; return 0; } +/* This is used by rollup to create a separate usable copy of the function */ + +void Item_sum_count_distinct::make_unique() +{ + table=0; + original= 0; + tree= &tree_base; +} + + bool Item_sum_count_distinct::setup(THD *thd) { List list; @@ -1045,6 +1118,9 @@ bool Item_sum_count_distinct::setup(THD *thd) if (select_lex->linkage == GLOBAL_OPTIONS_TYPE) return 1; + if (!(tmp_table_param= new TMP_TABLE_PARAM)) + return 1; + /* Create a table with an unique key over all parameters */ for (uint i=0; i < arg_count ; i++) { @@ -1192,7 +1268,14 @@ int Item_sum_count_distinct::tree_to_myisam() return 0; } -void Item_sum_count_distinct::reset() + +Item *Item_sum_count_distinct::copy_or_same(THD* thd) +{ + return new (&thd->mem_root) Item_sum_count_distinct(thd, *this); +} + + +bool Item_sum_count_distinct::reset() { if (use_tree) reset_tree(tree); @@ -1202,7 +1285,7 @@ void Item_sum_count_distinct::reset() table->file->delete_all_rows(); table->file->extra(HA_EXTRA_WRITE_CACHE); } - (void) add(); + return add(); } bool Item_sum_count_distinct::add() @@ -1265,11 +1348,11 @@ longlong Item_sum_count_distinct::val_int() #ifdef HAVE_DLOPEN -void Item_udf_sum::reset() +bool Item_udf_sum::reset() { DBUG_ENTER("Item_udf_sum::reset"); udf.reset(&null_value); - DBUG_VOID_RETURN; + DBUG_RETURN(0); } bool Item_udf_sum::add() @@ -1279,6 +1362,11 @@ bool Item_udf_sum::add() DBUG_RETURN(0); } +Item *Item_sum_udf_float::copy_or_same(THD* thd) +{ + return new (&thd->mem_root) Item_sum_udf_float(thd, *this); +} + double Item_sum_udf_float::val() { DBUG_ENTER("Item_sum_udf_float::val"); @@ -1298,6 +1386,12 @@ String *Item_sum_udf_float::val_str(String *str) } +Item *Item_sum_udf_int::copy_or_same(THD* thd) +{ + return new (&thd->mem_root) Item_sum_udf_int(thd, *this); +} + + longlong Item_sum_udf_int::val_int() { DBUG_ENTER("Item_sum_udf_int::val_int"); @@ -1306,6 +1400,7 @@ longlong Item_sum_udf_int::val_int() DBUG_RETURN(udf.val_int(&null_value)); } + String *Item_sum_udf_int::val_str(String *str) { longlong nr=val_int(); @@ -1327,6 +1422,13 @@ void Item_sum_udf_str::fix_length_and_dec() DBUG_VOID_RETURN; } + +Item *Item_sum_udf_str::copy_or_same(THD* thd) +{ + return new (&thd->mem_root) Item_sum_udf_str(thd, *this); +} + + String *Item_sum_udf_str::val_str(String *str) { DBUG_ENTER("Item_sum_udf_str::str"); @@ -1568,7 +1670,13 @@ Item_func_group_concat::~Item_func_group_concat() } -void Item_func_group_concat::reset() +Item *Item_func_group_concat::copy_or_same(THD* thd) +{ + return new (&thd->mem_root) Item_func_group_concat(thd, *this); +} + + +bool Item_func_group_concat::reset() { result.length(0); result.copy(); @@ -1582,7 +1690,7 @@ void Item_func_group_concat::reset() } if (tree_mode) reset_tree(tree); - add(); + return add(); } @@ -1768,6 +1876,16 @@ bool Item_func_group_concat::setup(THD *thd) return 0; } +/* This is used by rollup to create a separate usable copy of the function */ + +void Item_func_group_concat::make_unique() +{ + table=0; + original= 0; + tree= &tree_base; +} + + String* Item_func_group_concat::val_str(String* str) { if (null_value) diff --git a/sql/item_sum.h b/sql/item_sum.h index f996f980fff..c8614dda679 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -26,9 +26,11 @@ class Item_sum :public Item_result_field { public: - enum Sumfunctype {COUNT_FUNC,COUNT_DISTINCT_FUNC,SUM_FUNC,AVG_FUNC,MIN_FUNC, - MAX_FUNC, UNIQUE_USERS_FUNC,STD_FUNC,VARIANCE_FUNC,SUM_BIT_FUNC, - UDF_SUM_FUNC, GROUP_CONCAT_FUNC }; + enum Sumfunctype + { COUNT_FUNC,COUNT_DISTINCT_FUNC,SUM_FUNC,AVG_FUNC,MIN_FUNC, + MAX_FUNC, UNIQUE_USERS_FUNC,STD_FUNC,VARIANCE_FUNC,SUM_BIT_FUNC, + UDF_SUM_FUNC, GROUP_CONCAT_FUNC + }; Item **args,*tmp_args[2]; uint arg_count; @@ -60,7 +62,7 @@ public: enum Type type() const { return SUM_FUNC_ITEM; } virtual enum Sumfunctype sum_func () const=0; - virtual void reset()=0; + virtual bool reset()=0; virtual bool add()=0; virtual void reset_field()=0; virtual void update_field(int offset)=0; @@ -78,6 +80,7 @@ public: void fix_num_length_and_dec(); void no_rows_in_result() { reset(); } virtual bool setup(THD *thd) {return 0;} + virtual void make_unique() {} Item *get_tmp_table_item(THD *thd); }; @@ -121,14 +124,14 @@ class Item_sum_sum :public Item_sum_num Item_sum_sum(THD *thd, Item_sum_sum &item) :Item_sum_num(thd, item), sum(item.sum) {} enum Sumfunctype sum_func () const {return SUM_FUNC;} - void reset(); + bool reset(); bool add(); double val(); void reset_field(); void update_field(int offset); void no_rows_in_result() {} const char *func_name() const { return "sum"; } - Item *copy_or_same(THD* thd) { return new Item_sum_sum(thd, *this); } + Item *copy_or_same(THD* thd); }; @@ -148,7 +151,7 @@ class Item_sum_count :public Item_sum_int table_map used_tables() const { return used_table_cache; } bool const_item() const { return !used_table_cache; } enum Sumfunctype sum_func () const { return COUNT_FUNC; } - void reset(); + bool reset(); void no_rows_in_result() { count=0; } bool add(); void make_const(longlong count_arg) { count=count_arg; used_table_cache=0; } @@ -156,7 +159,7 @@ class Item_sum_count :public Item_sum_int void reset_field(); void update_field(int offset); const char *func_name() const { return "count"; } - Item *copy_or_same(THD* thd) { return new Item_sum_count(thd, *this); } + Item *copy_or_same(THD* thd); }; @@ -222,17 +225,15 @@ class Item_sum_count_distinct :public Item_sum_int table_map used_tables() const { return used_table_cache; } enum Sumfunctype sum_func () const { return COUNT_DISTINCT_FUNC; } - void reset(); + bool reset(); bool add(); longlong val_int(); void reset_field() { return ;} // Never called void update_field(int offset) { return ; } // Never called const char *func_name() const { return "count_distinct"; } bool setup(THD *thd); - Item *copy_or_same(THD* thd) - { - return new Item_sum_count_distinct(thd, *this); - } + void make_unique(); + Item *copy_or_same(THD* thd); void no_rows_in_result() {} }; @@ -268,7 +269,7 @@ class Item_sum_avg :public Item_sum_num Item_sum_avg(THD *thd, Item_sum_avg &item) :Item_sum_num(thd, item), sum(item.sum), count(item.count) {} enum Sumfunctype sum_func () const {return AVG_FUNC;} - void reset(); + bool reset(); bool add(); double val(); void reset_field(); @@ -276,7 +277,7 @@ class Item_sum_avg :public Item_sum_num Item *result_item(Field *field) { return new Item_avg_field(this); } const char *func_name() const { return "avg"; } - Item *copy_or_same(THD* thd) { return new Item_sum_avg(thd, *this); } + Item *copy_or_same(THD* thd); }; class Item_sum_variance; @@ -321,7 +322,7 @@ class Item_sum_variance : public Item_sum_num Item_sum_num(thd, item), sum(item.sum), sum_sqr(item.sum_sqr), count(item.count) {} enum Sumfunctype sum_func () const { return VARIANCE_FUNC; } - void reset(); + bool reset(); bool add(); double val(); void reset_field(); @@ -329,7 +330,7 @@ class Item_sum_variance : public Item_sum_num Item *result_item(Field *field) { return new Item_variance_field(this); } const char *func_name() const { return "variance"; } - Item *copy_or_same(THD* thd) { return new Item_sum_variance(thd, *this); } + Item *copy_or_same(THD* thd); }; class Item_sum_std; @@ -349,12 +350,16 @@ public: class Item_sum_std :public Item_sum_variance { public: - Item_sum_std(Item *item_par) :Item_sum_variance(item_par){} + Item_sum_std(Item *item_par) :Item_sum_variance(item_par) {} + Item_sum_std(THD *thd, Item_sum_std &item) + :Item_sum_variance(thd, item) + {} enum Sumfunctype sum_func () const { return STD_FUNC; } double val(); Item *result_item(Field *field) { return new Item_std_field(this); } const char *func_name() const { return "std"; } + Item *copy_or_same(THD* thd); }; // This class is a string or number function depending on num_func @@ -386,13 +391,13 @@ class Item_sum_hybrid :public Item_sum table_map used_tables() const { return used_table_cache; } bool const_item() const { return !used_table_cache; } - void reset() + bool reset() { sum=0.0; sum_int=0; value.length(0); null_value=1; - add(); + return add(); } double val(); longlong val_int(); @@ -418,7 +423,7 @@ public: bool add(); const char *func_name() const { return "min"; } - Item *copy_or_same(THD* thd) { return new Item_sum_min(thd, *this); } + Item *copy_or_same(THD* thd); }; @@ -431,7 +436,7 @@ public: bool add(); const char *func_name() const { return "max"; } - Item *copy_or_same(THD* thd) { return new Item_sum_max(thd, *this); } + Item *copy_or_same(THD* thd); }; @@ -446,7 +451,7 @@ class Item_sum_bit :public Item_sum_int Item_sum_bit(THD *thd, Item_sum_bit &item): Item_sum_int(thd, item), reset_bits(item.reset_bits), bits(item.bits) {} enum Sumfunctype sum_func () const {return SUM_BIT_FUNC;} - void reset(); + bool reset(); longlong val_int(); void reset_field(); void fix_length_and_dec() @@ -462,7 +467,7 @@ class Item_sum_or :public Item_sum_bit bool add(); void update_field(int offset); const char *func_name() const { return "bit_or"; } - Item *copy_or_same(THD* thd) { return new Item_sum_or(thd, *this); } + Item *copy_or_same(THD* thd); }; @@ -474,7 +479,7 @@ class Item_sum_and :public Item_sum_bit bool add(); void update_field(int offset); const char *func_name() const { return "bit_and"; } - Item *copy_or_same(THD* thd) { return new Item_sum_and(thd, *this); } + Item *copy_or_same(THD* thd); }; /* @@ -504,7 +509,7 @@ public: enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } virtual bool have_field_update(void) const { return 0; } - void reset(); + bool reset(); bool add(); void reset_field() {}; void update_field(int offset_arg) {}; @@ -524,7 +529,7 @@ class Item_sum_udf_float :public Item_udf_sum double val(); String *val_str(String*str); void fix_length_and_dec() { fix_num_length_and_dec(); } - Item *copy_or_same(THD* thd) { return new Item_sum_udf_float(thd, *this); } + Item *copy_or_same(THD* thd); }; @@ -542,7 +547,7 @@ public: String *val_str(String*str); enum Item_result result_type () const { return INT_RESULT; } void fix_length_and_dec() { decimals=0; max_length=21; } - Item *copy_or_same(THD* thd) { return new Item_sum_udf_int(thd, *this); } + Item *copy_or_same(THD* thd); }; @@ -571,7 +576,7 @@ public: } enum Item_result result_type () const { return STRING_RESULT; } void fix_length_and_dec(); - Item *copy_or_same(THD* thd) { return new Item_sum_udf_str(thd, *this); } + Item *copy_or_same(THD* thd); }; #else /* Dummy functions to get sql_yacc.cc compiled */ @@ -586,10 +591,9 @@ class Item_sum_udf_float :public Item_sum_num ~Item_sum_udf_float() {} enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } double val() { return 0.0; } - void reset() {} + bool reset() { return 0; } bool add() { return 0; } void update_field(int offset) {} - Item *copy_or_same(THD* thd) { return new Item_sum_udf_float(thd, *this); } }; @@ -604,10 +608,9 @@ public: enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } longlong val_int() { return 0; } double val() { return 0; } - void reset() {} + bool reset() { return 0; } bool add() { return 0; } void update_field(int offset) {} - Item *copy_or_same(THD* thd) { return new Item_sum_udf_int(thd, *this); } }; @@ -625,10 +628,9 @@ public: enum Item_result result_type () const { return STRING_RESULT; } void fix_length_and_dec() { maybe_null=1; max_length=0; } enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } - void reset() {} + bool reset() { return 0; } bool add() { return 0; } void update_field(int offset) {} - Item *copy_or_same(THD* thd) { return new Item_sum_udf_str(thd, *this); } }; #endif /* HAVE_DLOPEN */ @@ -676,7 +678,7 @@ class Item_func_group_concat : public Item_sum warning(item.warning), warning_available(item.warning_available), separator(item.separator), - tree(item.tree), + tree(item.tree), table(item.table), expr(item.expr), order(item.order), @@ -700,11 +702,12 @@ class Item_func_group_concat : public Item_sum enum Type type() const { return SUM_FUNC_ITEM; } void fix_length_and_dec() { max_length=group_concat_max_len; } virtual Item_result result_type () const { return STRING_RESULT; } - void reset(); + bool reset(); bool add(); void reset_field(); bool fix_fields(THD *, TABLE_LIST *, Item **); bool setup(THD *thd); + void make_unique(); virtual void update_field(int offset) {}; double val() { @@ -717,5 +720,5 @@ class Item_func_group_concat : public Item_sum return res ? strtoll(res->c_ptr(),(char**) 0,10) : (longlong) 0; } String* val_str(String* str); - Item *copy_or_same(THD* thd) { return new Item_func_group_concat(thd, *this); } + Item *copy_or_same(THD* thd); }; diff --git a/sql/item_uniq.h b/sql/item_uniq.h index 5ffd10be7a5..f2c64c4bde9 100644 --- a/sql/item_uniq.h +++ b/sql/item_uniq.h @@ -41,7 +41,7 @@ public: :Item_sum_num(thd, item) {} double val() { return 0.0; } enum Sumfunctype sum_func () const {return UNIQUE_USERS_FUNC;} - void reset() {} + bool reset() { return 0;} bool add() { return 0; } void reset_field() {} void update_field(int offset) {} diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 712c8853a20..97158191111 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -66,9 +66,8 @@ char* query_table_status(THD *thd,const char *db,const char *table_name); #endif #endif -extern CHARSET_INFO *system_charset_info; -extern CHARSET_INFO *files_charset_info; -extern CHARSET_INFO *national_charset_info; +extern CHARSET_INFO *system_charset_info, *files_charset_info ; +extern CHARSET_INFO *national_charset_info, *table_alias_charset; /*************************************************************************** Configuration parameters @@ -208,7 +207,7 @@ extern CHARSET_INFO *national_charset_info; #define MODE_PIPES_AS_CONCAT 2 #define MODE_ANSI_QUOTES 4 #define MODE_IGNORE_SPACE 8 -#define MODE_SERIALIZABLE 16 +#define MODE_NOT_USED 16 #define MODE_ONLY_FULL_GROUP_BY 32 #define MODE_NO_UNSIGNED_SUBTRACTION 64 #define MODE_POSTGRESQL 128 @@ -221,6 +220,7 @@ extern CHARSET_INFO *national_charset_info; #define MODE_NO_FIELD_OPTIONS 16384 #define MODE_MYSQL323 32768 #define MODE_MYSQL40 65536 +#define MODE_ANSI (MODE_MYSQL40*2) #define RAID_BLOCK_SIZE 1024 @@ -723,7 +723,7 @@ extern ulong ha_read_rnd_count, ha_read_rnd_next_count; extern ulong ha_commit_count, ha_rollback_count,table_cache_size; extern ulong max_connections,max_connect_errors, connect_timeout; extern ulong max_insert_delayed_threads, max_user_connections; -extern ulong long_query_count, what_to_log,flush_time,opt_sql_mode; +extern ulong long_query_count, what_to_log,flush_time; extern ulong query_buff_size, thread_stack,thread_stack_min; extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit; extern ulong max_binlog_size, rpl_recovery_rank, thread_cache_size; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 86ec00e1e92..019a3388341 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -208,9 +208,9 @@ const char *show_comp_option_name[]= {"YES", "NO", "DISABLED"}; const char *sql_mode_names[] = { "REAL_AS_FLOAT", "PIPES_AS_CONCAT", "ANSI_QUOTES", "IGNORE_SPACE", - "SERIALIZE", "ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION", + "?", "ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION", "POSTGRESQL", "ORACLE", "MSSQL", "DB2", "SAPDB", "NO_KEY_OPTIONS", - "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS", "MYSQL323", "MYSQL40", + "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS", "MYSQL323", "MYSQL40", "ANSI", NullS }; TYPELIB sql_mode_typelib= { array_elements(sql_mode_names)-1,"", @@ -324,6 +324,9 @@ MY_TMPDIR mysql_tmpdir_list; DATE_FORMAT dayord; MY_BITMAP temp_pool; +CHARSET_INFO *system_charset_info, *files_charset_info ; +CHARSET_INFO *national_charset_info, *table_alias_charset; + SHOW_COMP_OPTION have_berkeley_db, have_innodb, have_isam; SHOW_COMP_OPTION have_raid, have_openssl, have_symlink, have_query_cache; SHOW_COMP_OPTION have_crypt, have_compress; @@ -2281,9 +2284,7 @@ static void handle_connections_methods() #endif /* __NT__ */ if (have_tcpip && !opt_disable_networking) { -#ifdef __NT__ handler_count++; -#endif if (pthread_create(&hThread,&connection_attrib, handle_connections_sockets, 0)) { @@ -2294,9 +2295,7 @@ static void handle_connections_methods() #ifdef HAVE_SMEM if (opt_enable_shared_memory) { -#ifdef __NT__ handler_count++; -#endif if (pthread_create(&hThread,&connection_attrib, handle_connections_shared_memory, 0)) { @@ -2311,6 +2310,16 @@ static void handle_connections_methods() pthread_mutex_unlock(&LOCK_thread_count); DBUG_VOID_RETURN; } + +void decrement_handler_count() +{ + pthread_mutex_lock(&LOCK_thread_count); + handler_count--; + pthread_mutex_unlock(&LOCK_thread_count); + pthread_cond_signal(&COND_handler_count); +} +#else +#define decrement_handler_count() #endif /* defined(__NT__) || defined(HAVE_SMEM) */ @@ -2428,7 +2437,7 @@ The server will not act as a slave."); #endif /* init_slave() must be called after the thread keys are created */ init_slave(); - + if (opt_bootstrap) { int error=bootstrap(stdin); @@ -3019,13 +3028,7 @@ extern "C" pthread_handler_decl(handle_connections_sockets, // kill server must be invoked from thread 1! kill_server(MYSQL_KILL_SIGNAL); #endif - -#ifdef __NT__ - pthread_mutex_lock(&LOCK_thread_count); - handler_count--; - pthread_mutex_unlock(&LOCK_thread_count); - pthread_cond_signal(&COND_handler_count); -#endif + decrement_handler_count(); DBUG_RETURN(0); } @@ -3105,10 +3108,7 @@ extern "C" pthread_handler_decl(handle_connections_namedpipes,arg) create_new_thread(thd); } - pthread_mutex_lock(&LOCK_thread_count); - handler_count--; - pthread_mutex_unlock(&LOCK_thread_count); - pthread_cond_signal(&COND_handler_count); + decrement_handler_count(); DBUG_RETURN(0); } #endif /* __NT__ */ @@ -3322,12 +3322,8 @@ error: if (!handle_connect_file_map) CloseHandle(handle_connect_file_map); if (!event_connect_answer) CloseHandle(event_connect_answer); if (!event_connect_request) CloseHandle(event_connect_request); -#ifdef __NT__ - pthread_mutex_lock(&LOCK_thread_count); - handler_count--; - pthread_mutex_unlock(&LOCK_thread_count); - pthread_cond_signal(&COND_handler_count); -#endif + + decrement_handler_count(); DBUG_RETURN(0); } #endif /* HAVE_SMEM */ @@ -3921,7 +3917,7 @@ replicating a LOAD DATA INFILE command", (gptr*) &opt_sql_bin_update, (gptr*) &opt_sql_bin_update, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"sql-mode", OPT_SQL_MODE, - "Syntax: sql-mode=option[,option[,option...]] where option can be one of: REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, SERIALIZE, ONLY_FULL_GROUP_BY, NO_UNSIGNED_SUBTRACTION.", + "Syntax: sql-mode=option[,option[,option...]] where option can be one of: REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, ONLY_FULL_GROUP_BY, NO_UNSIGNED_SUBTRACTION.", (gptr*) &sql_mode_str, (gptr*) &sql_mode_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #ifdef HAVE_OPENSSL @@ -4634,6 +4630,12 @@ static void mysql_init_variables(void) bzero((gptr) &mysql_tmpdir_list, sizeof(mysql_tmpdir_list)); bzero((gptr) &com_stat, sizeof(com_stat)); + /* Character sets */ + system_charset_info= &my_charset_utf8_general_ci; + files_charset_info= &my_charset_utf8_general_ci; + national_charset_info= &my_charset_utf8_general_ci; + table_alias_charset= &my_charset_bin; + /* Things with default values that are not zero */ delay_key_write_options= (uint) DELAY_KEY_WRITE_ON; opt_specialflag= SPECIAL_ENGLISH; @@ -4684,6 +4686,7 @@ static void mysql_init_variables(void) sys_charset.value= (char*) MYSQL_CHARSET; sys_charset_system.value= (char*) system_charset_info->csname; + /* Set default values for some option variables */ global_system_variables.character_set_results= NULL; global_system_variables.character_set_client= default_charset_info; @@ -4789,10 +4792,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), opt_endinfo=1; /* unireg: memory allocation */ break; case 'a': - global_system_variables.sql_mode= - (MODE_REAL_AS_FLOAT | MODE_PIPES_AS_CONCAT | - MODE_ANSI_QUOTES | MODE_IGNORE_SPACE | MODE_SERIALIZABLE | - MODE_ONLY_FULL_GROUP_BY); + global_system_variables.sql_mode= fix_sql_mode(MODE_ANSI); global_system_variables.tx_isolation= ISO_SERIALIZABLE; break; case 'b': @@ -5270,11 +5270,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), fprintf(stderr, "Unknown option to sql-mode: %s\n", argument); exit(1); } - global_system_variables.tx_isolation= - ((global_system_variables.sql_mode & MODE_SERIALIZABLE) ? - ISO_SERIALIZABLE : - ISO_REPEATABLE_READ); - break; + global_system_variables.sql_mode= fix_sql_mode(global_system_variables. + sql_mode); } case OPT_MASTER_PASSWORD: master_password=argument; @@ -5332,6 +5329,9 @@ static void get_options(int argc,char **argv) /* Set global variables based on startup options */ myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size); + table_alias_charset= (lower_case_table_names ? + files_charset_info : + &my_charset_bin); } diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 8271d971782..621fa5f6334 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -14,6 +14,13 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* + This file is the net layer API for the MySQL client/server protocol, + which is a tightly coupled, proprietary protocol owned by MySQL AB. + Any re-implementations of this protocol must also be under GPL + unless one has got an license from MySQL AB stating otherwise. +*/ + /* Write and read of logical packets to/from socket diff --git a/sql/protocol.cc b/sql/protocol.cc index 848321c1576..dc61046aa20 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -102,7 +102,8 @@ void send_error(THD *thd, uint sql_errno, const char *err) if (thd->client_capabilities & CLIENT_PROTOCOL_41) { /* The first # is to make the protocol backward compatible */ - strmov(buff+2, "#000000"); + buff[2]= '#'; + strmov(buff+3, mysql_errno_to_sqlstate(sql_errno)); pos= buff + 2 + SQLSTATE_LENGTH +1; } length= (uint) (strmake(pos, err, MYSQL_ERRMSG_SIZE-1) - buff); @@ -222,8 +223,8 @@ net_printf(THD *thd, uint errcode, ...) int2store(pos, errcode); if (thd->client_capabilities & CLIENT_PROTOCOL_41) { - /* The first # is to make the protocol backward compatible */ - memcpy(pos+2, "#000000", SQLSTATE_LENGTH +1); + pos[2]= '#'; /* To make the protocol backward compatible */ + memcpy(pos+3, mysql_errno_to_sqlstate(errcode), SQLSTATE_LENGTH); } } VOID(net_real_write(net,(char*) net->buff,length+head_length+1+offset)); diff --git a/sql/set_var.cc b/sql/set_var.cc index 3145504951d..42ea92825d1 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -89,6 +89,7 @@ static void fix_query_cache_min_res_unit(THD *thd, enum_var_type type); static void fix_key_buffer_size(THD *thd, enum_var_type type); static void fix_myisam_max_extra_sort_file_size(THD *thd, enum_var_type type); static void fix_myisam_max_sort_file_size(THD *thd, enum_var_type type); +void fix_sql_mode_var(THD *thd, enum_var_type type); static byte *get_error_count(THD *thd); static byte *get_warning_count(THD *thd); @@ -1164,40 +1165,6 @@ byte *sys_var_thd_enum::value_ptr(THD *thd, enum_var_type type) } -byte *sys_var_thd_sql_mode::value_ptr(THD *thd, enum_var_type type) -{ - ulong val; - char buff[256]; - String tmp(buff, sizeof(buff), &my_charset_latin1); - my_bool found= 0; - - tmp.length(0); - val= ((type == OPT_GLOBAL) ? global_system_variables.*offset : - thd->variables.*offset); - for (uint i= 0; val; val>>= 1, i++) - { - if (val & 1) - { - tmp.append(enum_names->type_names[i]); - tmp.append(','); - } - } - if (tmp.length()) - tmp.length(tmp.length() - 1); - return (byte*) thd->strmake(tmp.ptr(), tmp.length()); -} - - -void sys_var_thd_sql_mode::set_default(THD *thd, enum_var_type type) -{ - if (type == OPT_GLOBAL) - global_system_variables.*offset= 0; - else - thd->variables.*offset= global_system_variables.*offset; -} - - - bool sys_var_thd_bit::update(THD *thd, set_var *var) { int res= (*update_func)(thd, var); @@ -1803,7 +1770,105 @@ int set_var_password::update(THD *thd) 1 : 0); } +/**************************************************************************** + Functions to handle sql_mode +****************************************************************************/ +byte *sys_var_thd_sql_mode::value_ptr(THD *thd, enum_var_type type) +{ + ulong val; + char buff[256]; + String tmp(buff, sizeof(buff), &my_charset_latin1); + my_bool found= 0; + + tmp.length(0); + val= ((type == OPT_GLOBAL) ? global_system_variables.*offset : + thd->variables.*offset); + for (uint i= 0; val; val>>= 1, i++) + { + if (val & 1) + { + tmp.append(enum_names->type_names[i]); + tmp.append(','); + } + } + if (tmp.length()) + tmp.length(tmp.length() - 1); + return (byte*) thd->strmake(tmp.ptr(), tmp.length()); +} + + +void sys_var_thd_sql_mode::set_default(THD *thd, enum_var_type type) +{ + if (type == OPT_GLOBAL) + global_system_variables.*offset= 0; + else + thd->variables.*offset= global_system_variables.*offset; +} + +void fix_sql_mode_var(THD *thd, enum_var_type type) +{ + if (type == OPT_GLOBAL) + global_system_variables.sql_mode= + fix_sql_mode(global_system_variables.sql_mode); + else + thd->variables.sql_mode= fix_sql_mode(thd->variables.sql_mode); +} + +/* Map database specific bits to function bits */ + +ulong fix_sql_mode(ulong sql_mode) +{ + /* + Note that we dont set + MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS | MODE_NO_FIELD_OPTIONS + to allow one to get full use of MySQL in this mode. + */ + + if (sql_mode & MODE_ANSI) + sql_mode|= (MODE_REAL_AS_FLOAT | MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES | + MODE_IGNORE_SPACE | MODE_ONLY_FULL_GROUP_BY); + if (sql_mode & MODE_ORACLE) + sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES | + MODE_IGNORE_SPACE | + MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS | + MODE_NO_FIELD_OPTIONS); + if (sql_mode & MODE_MSSQL) + sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES | + MODE_IGNORE_SPACE | + MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS | + MODE_NO_FIELD_OPTIONS); + if (sql_mode & MODE_MSSQL) + sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES | + MODE_IGNORE_SPACE | + MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS | + MODE_NO_FIELD_OPTIONS); + if (sql_mode & MODE_POSTGRESQL) + sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES | + MODE_IGNORE_SPACE | + MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS | + MODE_NO_FIELD_OPTIONS); + if (sql_mode & MODE_DB2) + sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES | + MODE_IGNORE_SPACE | + MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS | + MODE_NO_FIELD_OPTIONS); + if (sql_mode & MODE_DB2) + sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES | + MODE_IGNORE_SPACE | + MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS | + MODE_NO_FIELD_OPTIONS); + if (sql_mode & MODE_SAPDB) + sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES | + MODE_IGNORE_SPACE | + MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS | + MODE_NO_FIELD_OPTIONS); + if (sql_mode & MODE_MYSQL40) + sql_mode|= MODE_NO_FIELD_OPTIONS; + if (sql_mode & MODE_MYSQL323) + sql_mode|= MODE_NO_FIELD_OPTIONS; + return sql_mode; +} diff --git a/sql/set_var.h b/sql/set_var.h index f501426e553..8646668a236 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -309,11 +309,14 @@ public: }; +extern void fix_sql_mode_var(THD *thd, enum_var_type type); + class sys_var_thd_sql_mode :public sys_var_thd_enum { public: sys_var_thd_sql_mode(const char *name_arg, ulong SV::*offset_arg) - :sys_var_thd_enum(name_arg, offset_arg, &sql_mode_typelib) + :sys_var_thd_enum(name_arg, offset_arg, &sql_mode_typelib, + fix_sql_mode_var) {} bool check(THD *thd, set_var *var) { @@ -605,6 +608,7 @@ void set_var_free(); sys_var *find_sys_var(const char *str, uint length=0); int sql_set_variables(THD *thd, List *var_list); void fix_delay_key_write(THD *thd, enum_var_type type); +ulong fix_sql_mode(ulong sql_mode); extern sys_var_str sys_charset; extern sys_var_str sys_charset_system; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index eeaf560693e..0741dd1e32f 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -544,7 +544,8 @@ TABLE_LIST * find_table_in_list(TABLE_LIST *table, { for (; table; table= table->next) if ((!db_name || !strcmp(table->db, db_name)) && - (!table_name || !strcmp(table->alias, table_name))) + (!table_name || !my_strcasecmp(table_alias_charset, + table->alias, table_name))) break; return table; } @@ -1739,7 +1740,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, bool found_table=0; for (; tables ; tables=tables->next) { - if (!strcmp(tables->alias,table_name) && + if (!my_strcasecmp(table_alias_charset, tables->alias, table_name) && (!db || !tables->db || !tables->db[0] || !strcmp(db,tables->db))) { found_table=1; @@ -1868,20 +1869,22 @@ find_item_in_list(Item *find, List &items, uint *counter, { List_iterator li(items); Item **found=0,*item; + const char *db_name=0; const char *field_name=0; const char *table_name=0; if (find->type() == Item::FIELD_ITEM || find->type() == Item::REF_ITEM) { field_name= ((Item_ident*) find)->field_name; table_name= ((Item_ident*) find)->table_name; + db_name= ((Item_ident*) find)->db_name; } for (uint i= 0; (item=li++); i++) { if (field_name && item->type() == Item::FIELD_ITEM) { - if (!my_strcasecmp(system_charset_info, - ((Item_field*) item)->name,field_name)) + Item_field *item_field= (Item_field*) item; + if (!my_strcasecmp(system_charset_info, item_field->name, field_name)) { if (!table_name) { @@ -1897,11 +1900,16 @@ find_item_in_list(Item *find, List &items, uint *counter, found= li.ref(); *counter= i; } - else if (!strcmp(((Item_field*) item)->table_name,table_name)) + else { - found= li.ref(); - *counter= i; - break; + if (!strcmp(item_field->table_name,table_name) && + (!db_name || (db_name && item_field->db_name && + !strcmp(item_field->table_name,table_name)))) + { + found= li.ref(); + *counter= i; + break; + } } } } @@ -2094,7 +2102,8 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, for (; tables ; tables=tables->next) { TABLE *table=tables->table; - if (!table_name || (!strcmp(table_name,tables->alias) && + if (!table_name || (!my_strcasecmp(table_alias_charset, table_name, + tables->alias) && (!db_name || !strcmp(tables->db,db_name)))) { /* Ensure that we have access right to all columns */ diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index adc3d177fdf..7a154d206ef 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1432,7 +1432,8 @@ ulong Query_cache::init_cache() #else // windows, OS/2 or other case insensitive file names work around VOID(hash_init(&tables, - lower_case_table_names ? &my_charset_bin : system_charset_info, + lower_case_table_names ? &my_charset_bin : + system_charset_info, def_table_hash_size, 0, 0,query_cache_table_get_key, 0, 0)); #endif diff --git a/sql/sql_list.h b/sql/sql_list.h index ff21663576a..2450b2051f2 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -33,6 +33,8 @@ public: { return (void*) sql_alloc((uint) size); } + static void *operator new(size_t size, MEM_ROOT *mem_root) + { return (void*) alloc_root(mem_root, (uint) size); } static void operator delete(void *ptr, size_t size) {} /*lint -e715 */ static void operator delete[](void *ptr, size_t size) {} #ifdef HAVE_purify @@ -190,6 +192,7 @@ public: inline void *replace(void *element) { // Return old element void *tmp=current->info; + DBUG_ASSERT(current->info != 0); current->info=element; return tmp; } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 95ac57013da..fcddc2d2252 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -663,7 +663,7 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables, thd->protocol_simple.send_fields(&fields, 0) || send_item_params(stmt)) DBUG_RETURN(1); - join->cleanup(thd); + join->cleanup(); } DBUG_RETURN(0); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4167da5802a..61a64573eaa 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -138,7 +138,6 @@ static bool test_if_subpart(ORDER *a,ORDER *b); static TABLE *get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables); static void calc_group_buffer(JOIN *join,ORDER *group); static bool alloc_group_fields(JOIN *join,ORDER *group); -static bool make_sum_func_list(JOIN *join,List &fields); // Create list for using with tempory table static bool change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array, List &new_list1, @@ -153,7 +152,7 @@ static void init_tmptable_sum_functions(Item_sum **func); static void update_tmptable_sum_func(Item_sum **func,TABLE *tmp_table); static void copy_sum_funcs(Item_sum **func_ptr); static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab); -static void init_sum_functions(Item_sum **func); +static bool init_sum_functions(Item_sum **func, Item_sum **end); static bool update_sum_func(Item_sum **func); static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, bool distinct, const char *message=NullS); @@ -313,9 +312,11 @@ JOIN::prepare(Item ***rref_pointer_array, if (having->with_sum_func) having->split_sum_func(ref_pointer_array, all_fields); } - + if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */ DBUG_RETURN(-1); + + /* Check if one one uses a not constant column with group functions and no GROUP BY. @@ -345,45 +346,47 @@ JOIN::prepare(Item ***rref_pointer_array, for (table=tables_list ; table ; table=table->next) tables++; } + { + /* Caclulate the number of groups */ + send_group_parts= 0; + for (ORDER *group= group_list ; group ; group= group->next) + send_group_parts++; + } + procedure= setup_procedure(thd, proc_param, result, fields_list, &error); if (error) - DBUG_RETURN(-1); /* purecov: inspected */ + goto err; /* purecov: inspected */ if (procedure) { if (setup_new_fields(thd, tables_list, fields_list, all_fields, procedure->param_fields)) - { /* purecov: inspected */ - delete procedure; /* purecov: inspected */ - DBUG_RETURN(-1); /* purecov: inspected */ - } + goto err; /* purecov: inspected */ if (procedure->group) { if (!test_if_subpart(procedure->group,group_list)) { /* purecov: inspected */ my_message(0,"Can't handle procedures with differents groups yet", MYF(0)); /* purecov: inspected */ - delete procedure; /* purecov: inspected */ - DBUG_RETURN(-1); /* purecov: inspected */ + goto err; /* purecov: inspected */ } } #ifdef NOT_NEEDED else if (!group_list && procedure->flags & PROC_GROUP) { my_message(0,"Select must have a group with this procedure",MYF(0)); - delete procedure; - DBUG_RETURN(-1); + goto err; } #endif if (order && (procedure->flags & PROC_NO_SORT)) - { /* purecov: inspected */ + { /* purecov: inspected */ my_message(0,"Can't use order with this procedure",MYF(0)); /* purecov: inspected */ - delete procedure; /* purecov: inspected */ - DBUG_RETURN(-1); /* purecov: inspected */ + goto err; /* purecov: inspected */ } } /* Init join struct */ count_field_types(&tmp_table_param, all_fields, 0); + ref_pointer_array_size= all_fields.elements*sizeof(Item*); this->group= group_list != 0; row_limit= ((select_distinct || order || group_list) ? HA_POS_ERROR : unit->select_limit_cnt); @@ -398,15 +401,23 @@ JOIN::prepare(Item ***rref_pointer_array, if (sum_func_count && !group_list && (func_count || field_count)) { my_message(ER_WRONG_SUM_SELECT,ER(ER_WRONG_SUM_SELECT),MYF(0)); - delete procedure; - DBUG_RETURN(-1); + goto err; } #endif if (!procedure && result->prepare(fields_list, unit)) - { /* purecov: inspected */ - DBUG_RETURN(-1); /* purecov: inspected */ - } + goto err; /* purecov: inspected */ + + if (select_lex->olap == ROLLUP_TYPE && rollup_init()) + goto err; + if (alloc_func_list()) + goto err; + DBUG_RETURN(0); // All OK + +err: + delete procedure; /* purecov: inspected */ + procedure= 0; + DBUG_RETURN(-1); /* purecov: inspected */ } /* @@ -638,7 +649,9 @@ JOIN::optimize() else if (thd->is_fatal_error) // End of memory DBUG_RETURN(1); } - group_list= remove_const(this, group_list, conds, &simple_group); + simple_group= 0; + if (rollup.state == ROLLUP::STATE_NONE) + group_list= remove_const(this, group_list, conds, &simple_group); if (!group_list && group) { order=0; // The output has only one row @@ -788,14 +801,14 @@ JOIN::optimize() thd->proc_info="Sorting for group"; if (create_sort_index(thd, &join_tab[const_tables], group_list, HA_POS_ERROR, HA_POS_ERROR) || - make_sum_func_list(this, all_fields) || - alloc_group_fields(this, group_list)) + alloc_group_fields(this, group_list) || + make_sum_func_list(all_fields, fields_list, 1)) DBUG_RETURN(1); group_list=0; } else { - if (make_sum_func_list(this, all_fields)) + if (make_sum_func_list(all_fields, fields_list, 0)) DBUG_RETURN(1); if (!group_list && ! exec_tmp_table1->distinct && order && simple_order) { @@ -862,7 +875,7 @@ int JOIN::reinit() { DBUG_ENTER("JOIN::reinit"); - //TODO move to unit reinit + /* TODO move to unit reinit */ unit->offset_limit_cnt =select_lex->offset_limit; unit->select_limit_cnt =select_lex->select_limit+select_lex->offset_limit; if (unit->select_limit_cnt < select_lex->select_limit) @@ -873,7 +886,7 @@ JOIN::reinit() if (setup_tables(tables_list)) DBUG_RETURN(1); - // Reset of sum functions + /* Reset of sum functions */ first_record= 0; if (sum_funcs) { @@ -897,7 +910,7 @@ JOIN::reinit() filesort_free_buffers(exec_tmp_table2); } if (items0) - memcpy(ref_pointer_array, items0, ref_pointer_array_size); + set_items_ref_array(items0); if (tmp_join) restore_tmp(); @@ -977,9 +990,6 @@ JOIN::exec() DBUG_VOID_RETURN; } - /* Perform FULLTEXT search before all regular searches */ - //init_ftfuncs(thd, select_lex, test(order)); - JOIN *curr_join= this; List *curr_all_fields= &all_fields; List *curr_fields_list= &fields_list; @@ -1030,7 +1040,7 @@ JOIN::exec() } curr_all_fields= &tmp_all_fields1; curr_fields_list= &tmp_fields_list1; - memcpy(ref_pointer_array, items1, ref_pointer_array_size); + set_items_ref_array(items1); if (sort_and_group || curr_tmp_table->group) { @@ -1079,7 +1089,8 @@ JOIN::exec() if (make_simple_join(curr_join, curr_tmp_table)) DBUG_VOID_RETURN; calc_group_buffer(curr_join, group_list); - count_field_types(&curr_join->tmp_table_param, curr_join->tmp_all_fields1, + count_field_types(&curr_join->tmp_table_param, + curr_join->tmp_all_fields1, curr_join->select_distinct && !curr_join->group_list); curr_join->tmp_table_param.hidden_field_count= (curr_join->tmp_all_fields1.elements- @@ -1117,7 +1128,8 @@ JOIN::exec() thd->proc_info="Copying to group table"; tmp_error= -1; - if (make_sum_func_list(curr_join, *curr_all_fields) || + if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list, + 1) || (tmp_error= do_select(curr_join, (List *) 0, curr_tmp_table, 0))) { @@ -1141,7 +1153,7 @@ JOIN::exec() } curr_fields_list= &curr_join->tmp_fields_list2; curr_all_fields= &curr_join->tmp_all_fields2; - memcpy(ref_pointer_array, items2, ref_pointer_array_size); + set_items_ref_array(items2); curr_join->tmp_table_param.field_count+= curr_join->tmp_table_param.sum_func_count; curr_join->tmp_table_param.sum_func_count= 0; @@ -1169,9 +1181,7 @@ JOIN::exec() } if (procedure) - { count_field_types(&curr_join->tmp_table_param, *curr_all_fields, 0); - } if (curr_join->group || curr_join->tmp_table_param.sum_func_count || (procedure && (procedure->flags & PROC_GROUP))) @@ -1201,10 +1211,10 @@ JOIN::exec() } curr_fields_list= &tmp_fields_list3; curr_all_fields= &tmp_all_fields3; - memcpy(ref_pointer_array, items3, ref_pointer_array_size); + set_items_ref_array(items3); - if (make_sum_func_list(curr_join, *curr_all_fields) || - thd->is_fatal_error) + if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list, + 1) || thd->is_fatal_error) DBUG_VOID_RETURN; } if (curr_join->group_list || curr_join->order) @@ -1291,7 +1301,7 @@ JOIN::exec() */ int -JOIN::cleanup(THD *thd) +JOIN::cleanup() { DBUG_ENTER("JOIN::cleanup"); select_lex->join= 0; @@ -1312,7 +1322,7 @@ JOIN::cleanup(THD *thd) } } tmp_join->tmp_join= 0; - DBUG_RETURN(tmp_join->cleanup(thd)); + DBUG_RETURN(tmp_join->cleanup()); } lock=0; // It's faster to unlock later @@ -1396,7 +1406,7 @@ err: thd->limit_found_rows= curr_join->send_records; thd->examined_row_count= curr_join->examined_rows; thd->proc_info="end"; - err= join->cleanup(thd); + err= join->cleanup(); if (thd->net.report_error) err= -1; delete join; @@ -2916,7 +2926,6 @@ make_simple_join(JOIN *join,TABLE *tmp_table) join->tmp_table_param.func_count=0; join->tmp_table_param.copy_field=join->tmp_table_param.copy_field_end=0; join->first_record=join->sort_and_group=0; - join->sum_funcs=0; join->send_records=(ha_rows) 0; join->group=0; join->row_limit=join->unit->select_limit_cnt; @@ -5715,8 +5724,12 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), { if (join->having && join->having->val_int() == 0) error= -1; // Didn't satisfy having - else if (join->do_send_rows) - error=join->procedure->send_row(*join->fields) ? 1 : 0; + else + { + if (join->do_send_rows) + error=join->procedure->send_row(*join->fields) ? 1 : 0; + join->send_records++; + } if (end_of_records && join->procedure->end_of_records()) error= 1; // Fatal error } @@ -5730,17 +5743,23 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), } if (join->having && join->having->val_int() == 0) error= -1; // Didn't satisfy having - else if (join->do_send_rows) - error=join->result->send_data(*join->fields) ? 1 : 0; + else + { + if (join->do_send_rows) + error=join->result->send_data(*join->fields) ? 1 : 0; + join->send_records++; + } + if (join->rollup.state != ROLLUP::STATE_NONE && error <= 0) + { + if (join->rollup_send_data((uint) (idx+1))) + error= 1; + } } if (error > 0) DBUG_RETURN(-1); /* purecov: inspected */ if (end_of_records) - { - join->send_records++; DBUG_RETURN(0); - } - if (!error && ++join->send_records >= join->unit->select_limit_cnt && + if (join->send_records >= join->unit->select_limit_cnt && join->do_send_rows) { if (!(join->select_options & OPTION_FOUND_ROWS)) @@ -5760,7 +5779,8 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), if (idx < (int) join->send_group_parts) { copy_fields(&join->tmp_table_param); - init_sum_functions(join->sum_funcs); + if (init_sum_functions(join->sum_funcs, join->sum_funcs_end[idx+1])) + DBUG_RETURN(-1); if (join->procedure) join->procedure->add(); DBUG_RETURN(0); @@ -6016,7 +6036,8 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), { copy_fields(&join->tmp_table_param); copy_funcs(join->tmp_table_param.items_to_copy); - init_sum_functions(join->sum_funcs); + if (init_sum_functions(join->sum_funcs, join->sum_funcs_end[idx+1])) + DBUG_RETURN(-1); if (join->procedure) join->procedure->add(); DBUG_RETURN(0); @@ -7674,7 +7695,10 @@ err2: /* - Copy fields and null values between two tables + Make a copy of all simple SELECT'ed items + + This is done at the start of a new group so that we can retrieve + these later when the group changes. */ void @@ -7694,33 +7718,76 @@ copy_fields(TMP_TABLE_PARAM *param) } -/***************************************************************************** - Make an array of pointer to sum_functions to speed up sum_func calculation -*****************************************************************************/ +/* + Make an array of pointers to sum_functions to speed up sum_func calculation -static bool -make_sum_func_list(JOIN *join,List &fields) + SYNOPSIS + alloc_func_list() + + RETURN + 0 ok + 1 Error +*/ + +bool JOIN::alloc_func_list() { + uint func_count, group_parts; + DBUG_ENTER("alloc_func_list"); + + func_count= tmp_table_param.sum_func_count; + /* + If we are using rollup, we need a copy of the summary functions for + each level + */ + if (rollup.state != ROLLUP::STATE_NONE) + func_count*= (send_group_parts+1); + + group_parts= send_group_parts; + /* + If distinct, reserve memory for possible + disctinct->group_by optimization + */ + if (select_distinct) + group_parts+= fields_list.elements; + + /* This must use calloc() as rollup_make_fields depends on this */ + sum_funcs= (Item_sum**) thd->calloc(sizeof(Item_sum**) * (func_count+1) + + sizeof(Item_sum***) * (group_parts+1)); + sum_funcs_end= (Item_sum***) (sum_funcs+func_count+1); + DBUG_RETURN(sum_funcs == 0); +} + + +bool JOIN::make_sum_func_list(List &all_fields, List &send_fields, + bool before_group_by) +{ + List_iterator_fast it(all_fields); + Item_sum **func; + Item *item; DBUG_ENTER("make_sum_func_list"); - Item_sum **func = - (Item_sum**) sql_alloc(sizeof(Item_sum*)* - (join->tmp_table_param.sum_func_count+1)); - if (!func) - DBUG_RETURN(TRUE); - List_iterator it(fields); - join->sum_funcs=func; - Item *field; - while ((field=it++)) + func= sum_funcs; + while ((item=it++)) { - if (field->type() == Item::SUM_FUNC_ITEM && !field->const_item()) + if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item()) { - *func++=(Item_sum*) field; + *func++= (Item_sum*) item; /* let COUNT(DISTINCT) create the temporary table */ - if (((Item_sum*) field)->setup(join->thd)) + if (((Item_sum*) item)->setup(thd)) DBUG_RETURN(TRUE); } } + if (before_group_by && rollup.state == ROLLUP::STATE_INITED) + { + rollup.state= ROLLUP::STATE_READY; + if (rollup_make_fields(all_fields, send_fields, &func)) + DBUG_RETURN(TRUE); // Should never happen + } + else if (rollup.state == ROLLUP::STATE_NONE) + { + for (uint i=0 ; i <= send_group_parts ;i++) + sum_funcs_end[i]= func; + } *func=0; // End marker DBUG_RETURN(FALSE); } @@ -7816,8 +7883,8 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array, all_fields - all fields list RETURN - 0 - ok - !=0 - error + 0 ok + 1 error */ static bool @@ -7886,12 +7953,21 @@ copy_sum_funcs(Item_sum **func_ptr) } -static void -init_sum_functions(Item_sum **func_ptr) +static bool +init_sum_functions(Item_sum **func_ptr, Item_sum **end_ptr) { - Item_sum *func; - for (; (func= (Item_sum*) *func_ptr) ; func_ptr++) - func->reset(); + for (; func_ptr != end_ptr ;func_ptr++) + { + if ((*func_ptr)->reset()) + return 1; + } + /* If rollup, calculate the upper sum levels */ + for ( ; *func_ptr ; func_ptr++) + { + if ((*func_ptr)->add()) + return 1; + } + return 0; } @@ -7916,10 +7992,10 @@ copy_funcs(Item **func_ptr) } -/***************************************************************************** +/* Create a condition for a const reference and add this to the currenct select for the table -*****************************************************************************/ +*/ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab) { @@ -7935,7 +8011,8 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab) for (uint i=0 ; i < join_tab->ref.key_parts ; i++) { - Field *field=table->field[table->key_info[join_tab->ref.key].key_part[i].fieldnr-1]; + Field *field=table->field[table->key_info[join_tab->ref.key].key_part[i]. + fieldnr-1]; Item *value=join_tab->ref.items[i]; cond->add(new Item_func_equal(new Item_field(field),value)); } @@ -7958,7 +8035,241 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab) DBUG_RETURN(error ? TRUE : FALSE); } + +/* + Free joins of subselect of this select. + + free_underlaid_joins() + thd - THD pointer + select - pointer to st_select_lex which subselects joins we will free +*/ + +void free_underlaid_joins(THD *thd, SELECT_LEX *select) +{ + for (SELECT_LEX_UNIT *unit= select->first_inner_unit(); + unit; + unit= unit->next_unit()) + unit->cleanup(); +} + +/**************************************************************************** + ROLLUP handling +****************************************************************************/ + +/* Allocate memory needed for other rollup functions */ + +bool JOIN::rollup_init() +{ + uint i,j; + ORDER *group; + Item **ref_array; + + tmp_table_param.quick_group= 0; // Can't create groups in tmp table + rollup.state= ROLLUP::STATE_INITED; + + /* + Create pointers to the different sum function groups + These are updated by rollup_make_fields() + */ + tmp_table_param.group_parts= send_group_parts; + + if (!(rollup.fields= (List*) thd->alloc((sizeof(Item*) + + sizeof(List) + + ref_pointer_array_size) + * send_group_parts))) + return 1; + rollup.ref_pointer_arrays= (Item***) (rollup.fields + send_group_parts); + ref_array= (Item**) (rollup.ref_pointer_arrays+send_group_parts); + rollup.item_null= new (&thd->mem_root) Item_null(); + + /* + Prepare space for field list for the different levels + These will be filled up in rollup_make_fields() + */ + for (i= 0 ; i < send_group_parts ; i++) + { + List *fields= &rollup.fields[i]; + fields->empty(); + rollup.ref_pointer_arrays[i]= ref_array; + ref_array+= all_fields.elements; + for (j=0 ; j < fields_list.elements ; j++) + fields->push_back(rollup.item_null); + } + return 0; +} + + +/* + Fill up rollup structures with pointers to fields to use + + SYNOPSIS + rollup_make_fields() + all_fields List of all fields (hidden and real ones) + fields Pointer to selected fields + func Store here a pointer to all fields + + IMPLEMENTATION: + Creates copies of item_sum items for each sum level + + RETURN + 0 if ok + In this case func is pointing to next not used element. + 1 on error +*/ + +bool JOIN::rollup_make_fields(List &all_fields, List &fields, + Item_sum ***func) +{ + List_iterator_fast it(all_fields); + Item *first_field= fields.head(); + uint level; + + /* + Create field lists for the different levels + + The idea here is to have a separate field list for each rollup level to + avoid all runtime checks of which columns should be NULL. + + The list is stored in reverse order to get sum function in such an order + in func that it makes it easy to reset them with init_sum_functions() + + Assuming: SELECT a, b, c SUM(b) FROM t1 GROUP BY a,b WITH ROLLUP + + rollup.fields[0] will contain list where a,b,c is NULL + rollup.fields[1] will contain list where b,c is NULL + ... + rollup.ref_pointer_array[#] points to fields for rollup.fields[#] + ... + sum_funcs_end[0] points to all sum functions + sum_funcs_end[1] points to all sum functions, except grand totals + ... + */ + + for (level=0 ; level < send_group_parts > 0 ; level++) + { + uint i; + uint pos= send_group_parts - level -1; + bool real_fields= 0; + Item *item; + List_iterator new_it(rollup.fields[pos]); + Item **ref_array_start= rollup.ref_pointer_arrays[pos]; + ORDER *start_group; + + /* Point to first hidden field */ + Item **ref_array= ref_array_start + all_fields.elements-1; + + /* Remember where the sum functions ends for the previous level */ + sum_funcs_end[pos+1]= *func; + + /* Find the start of the group for this level */ + for (i= 0, start_group= group_list ; + i++ < pos ; + start_group= start_group->next) + ; + + it.rewind(); + while ((item= it++)) + { + if (item == first_field) + { + real_fields= 1; // End of hidden fields + ref_array= ref_array_start; + } + + if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item()) + { + /* + This is a top level summary function that must be replaced with + a sum function that is reset for this level. + + NOTE: This code creates an object which is not that nice in a + sub select. Fortunately it's not common to have rollup in + sub selects. + */ + item= item->copy_or_same(thd); + ((Item_sum*) item)->make_unique(); + if (((Item_sum*) item)->setup(thd)) + return 1; + *(*func)= (Item_sum*) item; + (*func)++; + } + else if (real_fields) + { + /* Check if this is something that is part of this group by */ + ORDER *group; + for (group= start_group ; group ; group= group->next) + { + if (*group->item == item) + { + /* + This is an element that is used by the GROUP BY and should be + set to NULL in this level + */ + item->maybe_null= 1; // Value will be null sometimes + item= rollup.item_null; + break; + } + } + } + *ref_array= item; + if (real_fields) + { + (void) new_it++; // Point to next item + new_it.replace(item); // Replace previous + ref_array++; + } + else + ref_array--; + } + } + sum_funcs_end[0]= *func; // Point to last function + return 0; +} + +/* + Send all rollup levels higher than the current one to the client + + SYNOPSIS: + rollup_send_data() + idx Level we are on: + 0 = Total sum level + 1 = First group changed (a) + 2 = Second group changed (a,b) + + SAMPLE + SELECT a, b, c SUM(b) FROM t1 GROUP BY a,b WITH ROLLUP + + RETURN + 0 ok + 1 If send_data_failed() +*/ + +int JOIN::rollup_send_data(uint idx) +{ + uint i; + for (i= send_group_parts ; i-- > idx ; ) + { + /* Get reference pointers to sum functions in place */ + memcpy((char*) ref_pointer_array, + (char*) rollup.ref_pointer_arrays[i], + ref_pointer_array_size); + if ((!having || having->val_int())) + { + if (send_records < unit->select_limit_cnt && + result->send_data(rollup.fields[i])) + return 1; + send_records++; + } + } + /* Restore ref_pointer_array */ + set_items_ref_array(current_ref_pointer_array); + return 0; +} + + /**************************************************************************** + EXPLAIN handling + Send a description about what how the select will be done to stdout ****************************************************************************/ @@ -8198,19 +8509,3 @@ int mysql_explain_select(THD *thd, SELECT_LEX *select_lex, char const *type, result, unit, select_lex, 0); DBUG_RETURN(res); } - -/* - Free joins of subselect of this select. - - free_underlaid_joins() - thd - THD pointer - select - pointer to st_select_lex which subselects joins we will free -*/ - -void free_underlaid_joins(THD *thd, SELECT_LEX *select) -{ - for (SELECT_LEX_UNIT *unit= select->first_inner_unit(); - unit; - unit= unit->next_unit()) - unit->cleanup(); -} diff --git a/sql/sql_select.h b/sql/sql_select.h index 7f3669f7478..df21d337b54 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -106,12 +106,22 @@ typedef struct st_join_table { } JOIN_TAB; -typedef struct st_position { /* Used in find_best */ +typedef struct st_position /* Used in find_best */ +{ double records_read; JOIN_TAB *table; KEYUSE *key; } POSITION; +typedef struct st_rollup +{ + enum State { STATE_NONE, STATE_INITED, STATE_READY }; + State state; + Item *item_null; + Item ***ref_pointer_arrays; + List *fields; +} ROLLUP; + class JOIN :public Sql_alloc { @@ -132,7 +142,7 @@ class JOIN :public Sql_alloc // used to store 2 possible tmp table of SELECT TABLE *exec_tmp_table1, *exec_tmp_table2; THD *thd; - Item_sum **sum_funcs; + Item_sum **sum_funcs, ***sum_funcs_end; Procedure *procedure; Item *having; Item *tmp_having; // To store Having when processed temporary table @@ -146,6 +156,7 @@ class JOIN :public Sql_alloc SELECT_LEX *select_lex; JOIN *tmp_join; // copy of this JOIN to be used with temporary tables + ROLLUP rollup; // Used with rollup bool select_distinct, //Is select distinct? no_order, simple_order, simple_group, @@ -159,7 +170,7 @@ class JOIN :public Sql_alloc List tmp_all_fields1, tmp_all_fields2, tmp_all_fields3; //Part, shared with list above, emulate following list List tmp_fields_list1, tmp_fields_list2, tmp_fields_list3; - List & fields_list; // hold field list passed to mysql_select + List &fields_list; // hold field list passed to mysql_select int error; ORDER *order, *group_list, *proc_param; //hold parameters of mysql_select @@ -168,15 +179,15 @@ class JOIN :public Sql_alloc SQL_SELECT *select; //created in optimisation phase Item **ref_pointer_array; //used pointer reference for this select // Copy of above to be used with different lists - Item **items0, **items1, **items2, **items3; + Item **items0, **items1, **items2, **items3, **current_ref_pointer_array; uint ref_pointer_array_size; // size of above in bytes const char *zero_result_cause; // not 0 if exec must return zero result bool union_part; // this subselect is part of union bool optimized; // flag to avoid double optimization in EXPLAIN - JOIN(THD *thd, List &fields, - ulong select_options, select_result *result): + JOIN(THD *thd_arg, List &fields, ulong select_options_arg, + select_result *result_arg): join_tab(0), table(0), tables(0), const_tables(0), @@ -184,13 +195,13 @@ class JOIN :public Sql_alloc do_send_rows(1), send_records(0), found_records(0), examined_rows(0), exec_tmp_table1(0), exec_tmp_table2(0), - thd(thd), + thd(thd_arg), sum_funcs(0), procedure(0), having(0), tmp_having(0), - select_options(select_options), - result(result), - lock(thd->lock), + select_options(select_options_arg), + result(result_arg), + lock(thd_arg->lock), select_lex(0), //for safety tmp_join(0), select_distinct(test(select_options & SELECT_DISTINCT)), @@ -212,6 +223,7 @@ class JOIN :public Sql_alloc bzero((char*) &keyuse,sizeof(keyuse)); tmp_table_param.copy_field=0; tmp_table_param.end_write_records= HA_POS_ERROR; + rollup.state= ROLLUP::STATE_NONE; } int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num, @@ -221,15 +233,28 @@ class JOIN :public Sql_alloc int optimize(); int reinit(); void exec(); - int cleanup(THD *thd); + int cleanup(); void restore_tmp(); + bool alloc_func_list(); + bool make_sum_func_list(List &all_fields, List &send_fields, + bool before_group_by); + inline void set_items_ref_array(Item **ptr) + { + memcpy((char*) ref_pointer_array, (char*) ptr, ref_pointer_array_size); + current_ref_pointer_array= ptr; + } inline void init_items_ref_array() { items0= ref_pointer_array + all_fields.elements; - ref_pointer_array_size= all_fields.elements*sizeof(Item*); memcpy(items0, ref_pointer_array, ref_pointer_array_size); + current_ref_pointer_array= items0; } + + bool rollup_init(); + bool rollup_make_fields(List &all_fields, List &fields, + Item_sum ***func); + int JOIN::rollup_send_data(uint idx); }; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 16934e33798..cfe392dae7d 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1004,12 +1004,7 @@ static void append_identifier(THD *thd, String *packet, const char *name) { char qtype; - if ((thd->variables.sql_mode & MODE_ANSI_QUOTES) || - (thd->variables.sql_mode & MODE_POSTGRESQL) || - (thd->variables.sql_mode & MODE_ORACLE) || - (thd->variables.sql_mode & MODE_MSSQL) || - (thd->variables.sql_mode & MODE_DB2) || - (thd->variables.sql_mode & MODE_SAPDB)) + if (thd->variables.sql_mode & MODE_ANSI_QUOTES) qtype= '\"'; else qtype= '`'; @@ -1031,16 +1026,16 @@ append_identifier(THD *thd, String *packet, const char *name) static int store_create_info(THD *thd, TABLE *table, String *packet) { - my_bool foreign_db_mode= ((thd->variables.sql_mode & MODE_POSTGRESQL) || - (thd->variables.sql_mode & MODE_ORACLE) || - (thd->variables.sql_mode & MODE_MSSQL) || - (thd->variables.sql_mode & MODE_DB2) || - (thd->variables.sql_mode & MODE_SAPDB)); - my_bool limited_mysql_mode= ((thd->variables.sql_mode & - MODE_NO_FIELD_OPTIONS) || - (thd->variables.sql_mode & MODE_MYSQL323) || - (thd->variables.sql_mode & MODE_MYSQL40)); - + my_bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL | + MODE_ORACLE | + MODE_MSSQL | + MODE_DB2 | + MODE_SAPDB | + MODE_ANSI)) != 0; + my_bool limited_mysql_mode= (thd->variables.sql_mode & + (MODE_NO_FIELD_OPTIONS | MODE_MYSQL323 | + MODE_MYSQL40)) != 0; + DBUG_ENTER("store_create_info"); DBUG_PRINT("enter",("table: %s",table->real_name)); diff --git a/sql/sql_state.c b/sql/sql_state.c new file mode 100644 index 00000000000..355b847f239 --- /dev/null +++ b/sql/sql_state.c @@ -0,0 +1,53 @@ +/* Copyright (C) 2000-2003 MySQL AB + + 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; either version 2 of the License, or + (at your option) any later version. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* Functions to map mysqld errno to sql_state */ + +#include +#include + +struct st_map_errno_to_sqlstate +{ + uint mysql_errno; + const char *odbc_state; + const char *jdbc_state; +}; + +struct st_map_errno_to_sqlstate sqlstate_map[]= +{ +#include +}; + +const char *mysql_errno_to_sqlstate(uint mysql_errno) +{ + uint first=0, end= array_elements(sqlstate_map)-1; + struct st_map_errno_to_sqlstate *map; + + /* Do binary search in the sorted array */ + while (first != end) + { + uint mid= (first+end)/2; + map= sqlstate_map+mid; + if (map->mysql_errno < mysql_errno) + first= mid+1; + else + end= mid; + } + map= sqlstate_map+first; + if (map->mysql_errno == mysql_errno) + return map->odbc_state; + return "HY000"; /* General error */ +} diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 6077c42bd1d..b4fad0dbebf 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -28,10 +28,6 @@ #include #endif -CHARSET_INFO *system_charset_info= &my_charset_utf8_general_ci; -CHARSET_INFO *files_charset_info= &my_charset_utf8_general_ci; -CHARSET_INFO *national_charset_info= &my_charset_utf8_general_ci; - extern gptr sql_alloc(unsigned size); extern void sql_element_free(void *ptr); diff --git a/sql/sql_string.h b/sql/sql_string.h index 8212bd0a2bd..d9b780ada5d 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -69,7 +69,10 @@ public: Alloced_length=str.Alloced_length; alloced=0; str_charset=str.str_charset; } - static void *operator new(size_t size) { return (void*) sql_alloc((uint) size); } + static void *operator new(size_t size) + { return (void*) sql_alloc((uint) size); } + static void *operator new(size_t size, MEM_ROOT *mem_root) + { return (void*) alloc_root(mem_root, (uint) size); } static void operator delete(void *ptr_arg,size_t size) /*lint -e715 */ { sql_element_free(ptr_arg); } ~String() { free(); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index ea3b30d24e8..7cadf187181 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1731,10 +1731,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, fn_same(new_name_buff,table_name,3); if (lower_case_table_names) my_casedn_str(system_charset_info,new_name); - if ((lower_case_table_names && - !my_strcasecmp(system_charset_info, new_name_buff,table_name)) || - (!lower_case_table_names && - !strcmp(new_name_buff,table_name))) + if (!my_strcasecmp(table_alias_charset, new_name_buff, table_name)) new_name=table_name; // No. Make later check easier else { diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 1d0f37f0042..f47900d8276 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -389,7 +389,7 @@ int st_select_lex_unit::cleanup() JOIN *join; if ((join= sl->join)) { - error|= sl->join->cleanup(thd); + error|= sl->join->cleanup(); delete join; } } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 1d735730801..efb5e42626d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2971,7 +2971,7 @@ olap_opt: } lex->current_select->select_lex()->olap= CUBE_TYPE; net_printf(lex->thd, ER_NOT_SUPPORTED_YET, "CUBE"); - YYABORT; /* To be deleted in 4.1 */ + YYABORT; /* To be deleted in 5.1 */ } | WITH ROLLUP_SYM { @@ -2983,8 +2983,6 @@ olap_opt: YYABORT; } lex->current_select->select_lex()->olap= ROLLUP_TYPE; - net_printf(lex->thd, ER_NOT_SUPPORTED_YET, "ROLLUP"); - YYABORT; /* To be deleted in 4.1 */ } ; @@ -3039,20 +3037,7 @@ opt_limit_clause: ; limit_clause: - LIMIT - { - LEX *lex= Lex; - if (lex->current_select->linkage != GLOBAL_OPTIONS_TYPE && - lex->current_select->select_lex()->olap != - UNSPECIFIED_OLAP_TYPE) - { - net_printf(lex->thd, ER_WRONG_USAGE, "CUBE/ROLLUP", - "LIMIT"); - YYABORT; - } - } - limit_options - {} + LIMIT limit_options {} ; limit_options: diff --git a/sql/unireg.h b/sql/unireg.h index 6ddd9856724..cd459dfc783 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -106,8 +106,8 @@ #define SPECIAL_SAFE_MODE 2048 /* Extern defines */ -#define store_record(A,B) bmove_allign((A)->B,(A)->record[0],(size_t) (A)->reclength) -#define restore_record(A,B) bmove_allign((A)->record[0],(A)->B,(size_t) (A)->reclength) +#define store_record(A,B) bmove_align((A)->B,(A)->record[0],(size_t) (A)->reclength) +#define restore_record(A,B) bmove_align((A)->record[0],(A)->B,(size_t) (A)->reclength) #define cmp_record(A,B) memcmp((A)->record[0],(A)->B,(size_t) (A)->reclength) #define empty_record(A) { \ restore_record((A),default_values); \ diff --git a/strings/Makefile.am b/strings/Makefile.am index 4a57ed73d20..7b2fdcccc55 100644 --- a/strings/Makefile.am +++ b/strings/Makefile.am @@ -73,7 +73,7 @@ if ASSEMBLER endif str_test: str_test.c $(LIBRARIES) - $(LINK) $(FLAGS) -DMAIN $(srcdir)/str_test.c $(LDADD) $(LIBS) + $(LINK) $(FLAGS) -DMAIN $INCLUDES $(srcdir)/str_test.c $(LDADD) $(LIBS) $(pkglib_LIBRARIES) # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/strings/ctype.c b/strings/ctype.c index ce7bb9ca4a4..cbd13111b70 100644 --- a/strings/ctype.c +++ b/strings/ctype.c @@ -31,7 +31,6 @@ static char *mstr(char *str,const char *src,uint l1,uint l2) return str; } - struct my_cs_file_section_st { int state; @@ -265,4 +264,3 @@ my_bool my_parse_charset_xml(const char *buf, uint len, my_xml_parser_free(&p); return rc; } - diff --git a/strings/str_test.c b/strings/str_test.c index 0c3ff471ad7..369fa7251d8 100644 --- a/strings/str_test.c +++ b/strings/str_test.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000-2003 MySQL AB 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 @@ -94,6 +94,8 @@ int main(void) test_strarg("bmove_upp(to+6,from+6,3)",(bmove_upp(to+6,from+6,3),0L),INT_MAX32, 3,T_CHAR,3,F_CHAR,0,0); test_strarg("bmove_upp(to,from,0)",(bmove_upp(to,from,0),0L),INT_MAX32,0,0); + test_strarg("bmove_align(to,from,8)",(bmove_align(to,from,8),0L),INT_MAX32, + 8,F_CHAR,0,0); test_strarg("strappend(to,3,' ')",(strappend(to,3,' '),0L),INT_MAX32, 3,T_CHAR,1,0,T_LEN-4,T_CHAR,1,0,0,0); test_strarg("strappend(to,T_LEN+5,' ')",(strappend(to,T_LEN+5,' '),0L),INT_MAX32, diff --git a/strings/strings-x86.s b/strings/strings-x86.s index 8b29a2db7f1..9409657e06c 100644 --- a/strings/strings-x86.s +++ b/strings/strings-x86.s @@ -23,44 +23,53 @@ # Move a alligned, not overlapped, by (long) divided memory area # Args: to,from,length -.globl bmove_allign - .type bmove_allign,@function -bmove_allign: +.globl bmove_align + .type bmove_align,@function +bmove_align: movl %edi,%edx - movl %esi,%eax + push %esi movl 4(%esp),%edi # to movl 8(%esp),%esi # from movl 12(%esp),%ecx # length addw $3,%cx # fix if not divisible with long shrw $2,%cx - rep - movsl - movl %eax,%esi + jz .ba_20 + .p2align 4,,7 +.ba_10: + movl -4(%esi,%ecx),%eax + movl %eax,-4(%edi,%ecx) + decl %ecx + jnz .ba_10 +.ba_20: pop %esi movl %edx,%edi ret -.end: - .size bmove_allign,.end-bmove_allign + .size bmove_align,.end-bmove_align # Move a string from higher to lower - # Arg from+1,to+1,length + # Arg from_end+1,to_end+1,length .globl bmove_upp .type bmove_upp,@function bmove_upp: - std # Work downward - movl %edi,%edx - movl %esi,%eax - movl 4(%esp),%edi # p1 - movl 8(%esp),%esi # p2 - movl 12(%esp),%ecx # length - decl %edi # Don't move last arg - decl %esi - rep - movsb # One byte a time because overlap - cld # C library wants cld - movl %eax,%esi + movl %edi,%edx # Remember %edi + push %esi + movl 8(%esp),%edi # dst + movl 16(%esp),%ecx # length + movl 12(%esp),%esi # source + test %ecx,%ecx + jz .bu_20 + subl %ecx,%esi # To start of strings + subl %ecx,%edi + + .p2align 4,,7 +.bu_10: movb -1(%esi,%ecx),%al + movb %al,-1(%edi,%ecx) + decl %ecx + jnz .bu_10 +.bu_20: pop %esi movl %edx,%edi ret + .bmove_upp_end: .size bmove_upp,.bmove_upp_end-bmove_upp @@ -304,22 +313,23 @@ si_99: popl %ebp strmake: pushl %edi pushl %esi - movl 12(%esp),%edi # dst - movl 16(%esp),%esi # src - movl 20(%esp),%ecx # Length of memory-area - clrb %al # For test of end-null - jecxz sm_90 # Nothing to move, put zero at end. - -sm_10: cmpb (%esi),%al # Next char to move - movsb # move arg - jz sm_99 # last char, we are ready - loop sm_10 # Continue moving -sm_90: movb %al,(%edi) # Set end pos - incl %edi # Fix that di points at end null -sm_99: decl %edi # di points now at end null - movl %edi,%eax # Ret value.p $ - popl %esi - popl %edi + mov 12(%esp),%edi # dst + movl $0,%edx + movl 20(%esp),%ecx # length + movl 16(%esp),%esi # src + cmpl %edx,%ecx + jz sm_90 +sm_00: movb (%esi,%edx),%al + cmpb $0,%al + jz sm_90 + movb %al,(%edi,%edx) + incl %edx + cmpl %edx,%ecx + jnz sm_00 +sm_90: movb $0,(%edi,%edx) +sm_99: lea (%edi,%edx),%eax # Return pointer to end null + pop %esi + pop %edi ret .strmake_end: .size strmake,.strmake_end-strmake diff --git a/strings/strings.asm b/strings/strings.asm index 43bc23fa965..fe39c8bb3e6 100644 --- a/strings/strings.asm +++ b/strings/strings.asm @@ -219,8 +219,8 @@ _bmove ENDP ; Args: to,from,length ; - PUBLIC _bmove_allign -_bmove_allign PROC + PUBLIC _bmove_align +_bmove_align PROC mov bx,bp mov dx,di mov ax,si @@ -238,7 +238,7 @@ _bmove_allign PROC mov di,dx mov bp,bx ret -_bmove_allign ENDP +_bmove_align ENDP ; ; Move a string from higher to lower @@ -656,9 +656,9 @@ _bmove ENDP ; Args: to,from,length ; - begcode bmove_allign - public _bmove_allign -_bmove_allign proc near + begcode bmove_align + public _bmove_align +_bmove_align proc near fix_es 1 mov edx,edi mov eax,esi @@ -671,8 +671,8 @@ _bmove_allign proc near mov esi,eax mov edi,edx ret -_bmove_allign ENDP - endcode bmove_allign +_bmove_align ENDP + endcode bmove_align ; ; Move a string from higher to lower -- cgit v1.2.1 From 7947830b2de3f83f674e8341abcaddcad3b9e500 Mon Sep 17 00:00:00 2001 From: "lenz@mysql.com" <> Date: Wed, 4 Jun 2003 17:31:21 +0200 Subject: - Updated Default-Stop run levels in the LSB header section to satisfy Red Hat's chkconfig (Bug #272) (The LSB spec is a bit ambigous about what actually needs to be put into this field) --- support-files/mysql.server.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index de01142beac..694e6fa8ebb 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -19,7 +19,7 @@ # Required-Start: $local_fs $network $remote_fs # Required-Stop: $local_fs $network $remote_fs # Default-Start: 2 3 4 5 -# Default-Stop: 2 3 4 5 +# Default-Stop: 0 1 6 # Short-Description: start and stop MySQL # Description: MySQL is a very fast and reliable SQL database engine. ### END INIT INFO -- cgit v1.2.1 From f5bb1e0907a6fdfe30990d5e58a387abcdb98e7c Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Wed, 4 Jun 2003 23:17:01 +0300 Subject: After merge fix --- mysql-test/r/insert_select.result | 5 ++--- mysql-test/r/loaddata.result | 5 +++++ mysql-test/r/lowercase_table.result | 6 ++++-- mysql-test/r/query_cache.result | 2 +- mysql-test/r/rpl_log.result | 22 ++++++++++++++-------- mysql-test/t/lowercase_table.test | 2 -- mysql-test/t/rpl_log.test | 2 +- sql/set_var.cc | 1 - 8 files changed, 27 insertions(+), 18 deletions(-) diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result index 4f6349f8f8b..04c3bc9027d 100644 --- a/mysql-test/r/insert_select.result +++ b/mysql-test/r/insert_select.result @@ -71,9 +71,8 @@ create table t2(a int); insert into t2 values(1),(2); reset master; insert into t1 select * from t2; -Duplicate entry '2' for key 1 +ERROR 23000: Duplicate entry '2' for key 1 show binlog events; Log_name Pos Event_type Server_id Orig_log_pos Info -master-bin.001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3 -master-bin.001 79 Query 1 79 use test; insert into t1 select * from t2 +master-bin.000001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3 drop table t1, t2; diff --git a/mysql-test/r/loaddata.result b/mysql-test/r/loaddata.result index 560c5b2567e..3cd62d8b678 100644 --- a/mysql-test/r/loaddata.result +++ b/mysql-test/r/loaddata.result @@ -17,6 +17,11 @@ a b c d 2003-03-03 2003-03-03 2003-03-03 NULL truncate table t1; load data infile '../../std_data/loaddata1.dat' into table t1 fields terminated by ',' LINES STARTING BY ',' (b,c,d); +Warnings: +Warning 1263 Data truncated for column 'c' at row 1 +Warning 1263 Data truncated for column 'd' at row 1 +Warning 1263 Data truncated for column 'b' at row 2 +Warning 1263 Data truncated for column 'd' at row 2 SELECT * from t1; a b c d NULL NULL 0000-00-00 0000-00-00 diff --git a/mysql-test/r/lowercase_table.result b/mysql-test/r/lowercase_table.result index d32228216b8..af4e2300088 100644 --- a/mysql-test/r/lowercase_table.result +++ b/mysql-test/r/lowercase_table.result @@ -21,7 +21,9 @@ select count(*) from t1; count(*) 0 select count(T1.a) from t1; -Unknown table 'T1' in field list +count(T1.a) +0 select count(bags.a) from t1 as Bags; -Unknown table 'bags' in field list +count(bags.a) +0 drop table t1; diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index 9d0c105b6c0..3b3e52d8240 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -502,7 +502,6 @@ drop table t1; show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 0 -create table t1 (a int); show global variables like "query_cache_min_res_unit"; Variable_name Value query_cache_min_res_unit 4096 @@ -562,6 +561,7 @@ set GLOBAL query_cache_min_res_unit=default; show global variables like "query_cache_min_res_unit"; Variable_name Value query_cache_min_res_unit 4096 +create table t1 (a int); set GLOBAL query_cache_size=1000; show global variables like "query_cache_size"; Variable_name Value diff --git a/mysql-test/r/rpl_log.result b/mysql-test/r/rpl_log.result index 948a755c3db..df2ef4e3d8a 100644 --- a/mysql-test/r/rpl_log.result +++ b/mysql-test/r/rpl_log.result @@ -36,6 +36,8 @@ show binlog events from 79 limit 2,1; Log_name Pos Event_type Server_id Orig_log_pos Info master-bin.000001 200 Query 1 200 use `test`; insert into t1 values (NULL) flush logs; +create table t5 (a int); +drop table t5; start slave; flush logs; stop slave; @@ -56,9 +58,11 @@ master-bin.000001 1079 Query 1 1079 use `test`; drop table t1 master-bin.000001 1127 Rotate 1 1127 master-bin.000002;pos=4 show binlog events in 'master-bin.000002'; Log_name Pos Event_type Server_id Orig_log_pos Info -master-bin.000002 4 Query 1 4 use `test`; create table t1 (n int) -master-bin.000002 62 Query 1 62 use `test`; insert into t1 values (1) -master-bin.000002 122 Query 1 122 use `test`; drop table t1 +master-bin.000002 4 Query 1 4 use `test`; create table t5 (a int) +master-bin.000002 62 Query 1 62 use `test`; drop table t5 +master-bin.000002 110 Query 1 110 use `test`; create table t1 (n int) +master-bin.000002 168 Query 1 168 use `test`; insert into t1 values (1) +master-bin.000002 228 Query 1 228 use `test`; drop table t1 show binary logs; Log_name master-bin.000001 @@ -79,14 +83,16 @@ slave-bin.000001 311 Query 1 311 use `test`; create table t1 (word char(20) not slave-bin.000001 386 Create_file 1 386 db=test;table=t1;file_id=1;block_len=581 slave-bin.000001 1065 Exec_load 1 1056 ;file_id=1 slave-bin.000001 1088 Query 1 1079 use `test`; drop table t1 -slave-bin.000001 1136 Rotate 2 1136 slave-bin.000002;pos=4 +slave-bin.000001 1136 Query 1 4 use `test`; create table t5 (a int) +slave-bin.000001 1194 Query 1 62 use `test`; drop table t5 +slave-bin.000001 1242 Rotate 2 1242 slave-bin.000002;pos=4 show binlog events in 'slave-bin.000002' from 4; Log_name Pos Event_type Server_id Orig_log_pos Info -slave-bin.000002 4 Query 1 4 use `test`; create table t1 (n int) -slave-bin.000002 62 Query 1 62 use `test`; insert into t1 values (1) -slave-bin.000002 122 Query 1 122 use `test`; drop table t1 +slave-bin.000002 4 Query 1 110 use `test`; create table t1 (n int) +slave-bin.000002 62 Query 1 168 use `test`; insert into t1 values (1) +slave-bin.000002 122 Query 1 228 use `test`; drop table t1 show slave status; Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.000002 170 slave-relay-bin.000002 1469 master-bin.000002 Yes Yes 0 0 170 1473 +127.0.0.1 root MASTER_PORT 1 master-bin.000002 276 slave-relay-bin.000002 1531 master-bin.000002 Yes Yes 0 0 276 1535 show binlog events in 'slave-bin.000005' from 4; ERROR HY000: Error when executing command SHOW BINLOG EVENTS: Could not find target log diff --git a/mysql-test/t/lowercase_table.test b/mysql-test/t/lowercase_table.test index cb30c14b70c..2a3cc5b7e8f 100644 --- a/mysql-test/t/lowercase_table.test +++ b/mysql-test/t/lowercase_table.test @@ -20,8 +20,6 @@ drop table t3; create table t1 (a int); select count(*) from T1; select count(*) from t1; ---error 1109 select count(T1.a) from t1; ---error 1109 select count(bags.a) from t1 as Bags; drop table t1; diff --git a/mysql-test/t/rpl_log.test b/mysql-test/t/rpl_log.test index 369c62848f9..f64aa292d30 100644 --- a/mysql-test/t/rpl_log.test +++ b/mysql-test/t/rpl_log.test @@ -58,7 +58,7 @@ connection slave; # Note that the above 'slave start' will cause a 3rd rotate event (a fake one) # to go into the relay log (the master always sends a fake one when replication # starts). -slave start; +start slave; sync_with_master; flush logs; stop slave; diff --git a/sql/set_var.cc b/sql/set_var.cc index b772f6410f7..b197fb7f312 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -238,7 +238,6 @@ sys_var_bool_ptr sys_slave_compressed_protocol("slave_compressed_protocol", sys_var_long_ptr sys_slave_net_timeout("slave_net_timeout", &slave_net_timeout); #endif -sys_var_bool_ptr sys_readonly("read_only", &opt_readonly); sys_var_long_ptr sys_slow_launch_time("slow_launch_time", &slow_launch_time); sys_var_thd_ulong sys_sort_buffer("sort_buffer_size", -- cgit v1.2.1 From 810e3bff14ac879e9c85e573034e50098718218e Mon Sep 17 00:00:00 2001 From: "lenz@mysql.com" <> Date: Wed, 4 Jun 2003 22:31:06 +0200 Subject: - When compiling the Max package incl. RAID support using gcc, make sure to set CXX=gcc (cannot link the code with g++) - this should help to recompile the RPM on Distributions using gcc 3 - Added a symlink /usr/sbin/rcmysql -> /etc/init.d/mysql --- support-files/mysql.spec.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index aab3e298e14..06ba2d63f45 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -254,6 +254,13 @@ export PATH # Build the 4.0 Max binary (includes BDB and UDFs and therefore # cannot be linked statically against the patched glibc) +# If we want to compile with RAID using gcc 3, we need to use +# gcc instead of g++ to avoid linking problems (RAID code is written in C++) +if gcc -v 2>&1 | grep 'version 3' > /dev/null 2>&1 +then + export CXX="gcc" +fi + BuildMySQL "--enable-shared \ --with-berkeley-db \ --with-innodb \ @@ -318,6 +325,10 @@ install -m644 $MBD/sql/mysqld.sym $RBR/usr/lib/mysql/mysqld.sym install -m644 $MBD/support-files/mysql-log-rotate $RBR/etc/logrotate.d/mysql install -m755 $MBD/support-files/mysql.server $RBR/etc/init.d/mysql +# Create a symlink "rcmysql", pointing to the init.script. SuSE users +# will appreciate that, as all services usually offer this. +ln -s ../../sbin/init.d/mysql $RPM_BUILD_ROOT/usr/sbin/rcmysql + # Create symbolic compatibility link safe_mysqld -> mysqld_safe # (safe_mysqld will be gone in MySQL 4.1) ln -sf ./mysqld_safe $RBR/usr/bin/safe_mysqld @@ -462,6 +473,7 @@ fi %attr(755, root, root) /usr/bin/safe_mysqld %attr(755, root, root) /usr/sbin/mysqld +%attr(755, root, root) /usr/sbin/rcmysql %attr(644, root, root) /usr/lib/mysql/mysqld.sym %attr(644, root, root) /etc/logrotate.d/mysql -- cgit v1.2.1 From cd3b680db00f52d7a502bf62513789f54b2dbcd0 Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Thu, 5 Jun 2003 11:55:03 +0300 Subject: Fixed problem with alarms when reading too big packet --- sql/net_serv.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sql/net_serv.cc b/sql/net_serv.cc index c8c774d365f..0b332f84bac 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -431,13 +431,13 @@ net_real_write(NET *net,const char *packet,ulong len) big packet */ -static void my_net_skip_rest(NET *net, ulong remain, thr_alarm_t *alarmed) +static void my_net_skip_rest(NET *net, ulong remain, thr_alarm_t *alarmed, + ALARM *alarm_buff) { - ALARM alarm_buff; uint retry_count=0; - if (!thr_alarm_in_use(&alarmed)) + if (!thr_alarm_in_use(alarmed)) { - if (!thr_alarm(alarmed,net->timeout,&alarm_buff) || + if (!thr_alarm(alarmed,net->timeout,alarm_buff) || (!vio_is_blocking(net->vio) && vio_blocking(net->vio,TRUE) < 0)) return; /* Can't setup, abort */ } @@ -606,7 +606,7 @@ my_real_read(NET *net, ulong *complen) { #ifdef MYSQL_SERVER if (i == 1) - my_net_skip_rest(net, len, &alarmed); + my_net_skip_rest(net, len, &alarmed, &alarm_buff); #endif len= packet_error; /* Return error */ goto end; -- cgit v1.2.1 From 772adcbd992108af5d7d74c5448cc16697183e8a Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Thu, 5 Jun 2003 12:29:13 +0300 Subject: Print error if we can't delete an alarm More debugging variables Increment aborted_threads in case of killed or too big packet --- include/thr_alarm.h | 2 +- mysys/thr_alarm.c | 11 +++++------ sql/mysqld.cc | 2 +- sql/net_serv.cc | 7 ++++++- sql/sql_parse.cc | 7 +++++++ 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/include/thr_alarm.h b/include/thr_alarm.h index 439f046252f..8ff4472f700 100644 --- a/include/thr_alarm.h +++ b/include/thr_alarm.h @@ -100,7 +100,7 @@ typedef struct st_alarm { #define thr_alarm_init(A) (*(A))=0 #define thr_alarm_in_use(A) (*(A)!= 0) void init_thr_alarm(uint max_alarm); -bool thr_alarm(thr_alarm_t *alarmed, uint sec, ALARM *buff); +my_bool thr_alarm(thr_alarm_t *alarmed, uint sec, ALARM *buff); void thr_alarm_kill(pthread_t thread_id); void thr_end_alarm(thr_alarm_t *alarmed); void end_thr_alarm(my_bool free_structures); diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c index a2647ec7399..1f9c4c3b068 100644 --- a/mysys/thr_alarm.c +++ b/mysys/thr_alarm.c @@ -127,7 +127,7 @@ void init_thr_alarm(uint max_alarms) Returns 0 if no more alarms are allowed (aborted by process) */ -bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data) +my_bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data) { ulong now; sigset_t old_mask; @@ -209,7 +209,7 @@ void thr_end_alarm(thr_alarm_t *alarmed) ALARM *alarm_data; sigset_t old_mask; uint i; - bool found=0; + my_bool found=0; DBUG_ENTER("thr_end_alarm"); pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask); @@ -230,10 +230,9 @@ void thr_end_alarm(thr_alarm_t *alarmed) DBUG_ASSERT(!*alarmed || found); if (!found) { -#ifdef MAIN - printf("Warning: Didn't find alarm %lx in queue of %d alarms\n", - (long) *alarmed, alarm_queue.elements); -#endif + if (*alarmed) + fprintf(stderr,"Warning: Didn't find alarm %lx in queue of %d alarms\n", + (long) *alarmed, alarm_queue.elements); DBUG_PRINT("warning",("Didn't find alarm %lx in queue\n", (long) *alarmed)); } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 7289d0e72cf..8ed183e2f1f 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -380,7 +380,7 @@ uint report_port = MYSQL_PORT; my_bool master_ssl = 0; ulong master_retry_count=0; -ulong bytes_sent = 0L, bytes_received = 0L; +ulong bytes_sent= 0L, bytes_received= 0L, net_big_packet_count= 0L; bool opt_endinfo,using_udf_functions, locked_in_memory; bool opt_using_transactions, using_update_log; diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 3d5055b4f24..a3bb2525f9d 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -65,11 +65,13 @@ void sql_print_error(const char *format,...); #define USE_QUERY_CACHE extern uint test_flags; extern void query_cache_insert(NET *net, const char *packet, ulong length); -extern ulong bytes_sent, bytes_received; +extern ulong bytes_sent, bytes_received, net_big_packet_count; extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received; #else #undef statistic_add +#undef statistic_increment #define statistic_add(A,B,C) +#define statistic_increment(A,B) #endif #define TEST_BLOCKING 8 @@ -557,6 +559,9 @@ static my_bool my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed, DBUG_ENTER("my_net_skip_rest"); DBUG_PRINT("enter",("bytes_to_skip: %u", (uint) remain)); + /* The following is good for debugging */ + statistic_increment(net_big_packet_count,&LOCK_bytes_received); + if (!thr_alarm_in_use(alarmed)) { my_bool old_mode; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index d9060b4b26e..b06a48f9045 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -729,6 +729,10 @@ pthread_handler_decl(handle_one_connection,arg) send_error(net,net->last_errno,NullS); statistic_increment(aborted_threads,&LOCK_status); } + else if (thd->killed) + { + statistic_increment(aborted_threads,&LOCK_status); + } end_thread: close_connection(net); @@ -905,7 +909,10 @@ bool do_command(THD *thd) vio_description(net->vio))); /* Check if we can continue without closing the connection */ if (net->error != 3) + { + statistic_increment(aborted_threads,&LOCK_status); DBUG_RETURN(TRUE); // We have to close it. + } send_error(net,net->last_errno,NullS); net->error= 0; DBUG_RETURN(FALSE); -- cgit v1.2.1 From 4b55fbe092e7ba5905dc1dfdd497d683c9e7418c Mon Sep 17 00:00:00 2001 From: "jani@ua126d19.elisa.omakaista.fi" <> Date: Thu, 5 Jun 2003 15:06:19 +0300 Subject: Fixed a bug in concat_ws(), which did not add concat separator in case of an empty string. Bug ID 586. --- mysql-test/r/func_str.result | 2 +- sql/item_strfunc.cc | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index a72d32d39f8..1a4cb9217e4 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -64,7 +64,7 @@ concat_ws(NULL,'a') concat_ws(',',NULL,'') NULL select concat_ws(',','',NULL,'a'); concat_ws(',','',NULL,'a') -a +,a SELECT CONCAT('"',CONCAT_WS('";"',repeat('a',60),repeat('b',60),repeat('c',60),repeat('d',100)), '"'); CONCAT('"',CONCAT_WS('";"',repeat('a',60),repeat('b',60),repeat('c',60),repeat('d',100)), '"') "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc";"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index ae8bf1dfecb..208be1ecd7f 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -495,18 +495,18 @@ String *Item_func_concat_ws::val_str(String *str) str->length(0); // QQ; Should be removed res=str; - // Skip until non-null and non-empty argument is found. + // Skip until non-null argument is found. // If not, return the empty string for (i=0; i < arg_count; i++) - if ((res= args[i]->val_str(str)) && res->length()) + if ((res= args[i]->val_str(str))) break; if (i == arg_count) return &empty_string; for (i++; i < arg_count ; i++) { - if (!(res2= args[i]->val_str(use_as_buff)) || !res2->length()) - continue; // Skip NULL and empty string + if (!(res2= args[i]->val_str(use_as_buff))) + continue; // Skip NULL if (res->length() + sep_str->length() + res2->length() > current_thd->variables.max_allowed_packet) -- cgit v1.2.1 From de0a3d303663be27ff888103af841fc9d9fb3589 Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Thu, 5 Jun 2003 15:15:27 +0300 Subject: Fixed test if thr_alarm() failed --- sql/net_serv.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 0b332f84bac..23a23dbde7b 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -437,7 +437,7 @@ static void my_net_skip_rest(NET *net, ulong remain, thr_alarm_t *alarmed, uint retry_count=0; if (!thr_alarm_in_use(alarmed)) { - if (!thr_alarm(alarmed,net->timeout,alarm_buff) || + if (thr_alarm(alarmed,net->timeout,alarm_buff) || (!vio_is_blocking(net->vio) && vio_blocking(net->vio,TRUE) < 0)) return; /* Can't setup, abort */ } -- cgit v1.2.1 From c2e5f4841227bb7e4e673ff13132bd5b60f4911c Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Thu, 5 Jun 2003 15:58:23 +0300 Subject: ha_innodb.cc, handler.cc: Fix the BDB crash in the previous push; to save CPU remove duplicate calls of commit in InnoDB --- sql/ha_innodb.cc | 227 ++++++++++++++++++++++++++++++++++++------------------- sql/handler.cc | 34 ++------- 2 files changed, 157 insertions(+), 104 deletions(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 50bb4275eaa..9cc86edddf8 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -131,9 +131,11 @@ static void innobase_print_error(const char* db_errpfx, char* buffer); /********************************************************************** Releases possible search latch and InnoDB thread FIFO ticket. These should -be released at each SQL statement end. It does no harm to release these -also in the middle of an SQL statement. */ +be released at each SQL statement end, and also when mysqld passes the +control to the client. It does no harm to release these also in the middle +of an SQL statement. */ static +inline void innobase_release_stat_resources( /*============================*/ @@ -896,6 +898,11 @@ innobase_commit_low( /*================*/ trx_t* trx) /* in: transaction handle */ { + if (trx->conc_state == TRX_NOT_STARTED) { + + return; + } + /* TODO: Guilhem should check if master_log_name, pending etc. are right if the master log gets rotated! Possible bug here. Comment by Heikki March 4, 2003. */ @@ -910,11 +917,13 @@ innobase_commit_low( active_mi->rli.event_len + active_mi->rli.pending)); } - trx_commit_for_mysql(trx); + + trx_commit_for_mysql(trx); } /********************************************************************* -Commits a transaction in an InnoDB database. */ +Commits a transaction in an InnoDB database or marks an SQL statement +ended. */ int innobase_commit( @@ -932,29 +941,45 @@ innobase_commit( DBUG_ENTER("innobase_commit"); DBUG_PRINT("trans", ("ending transaction")); - trx = check_trx_exists(thd); + /* The flag thd->transaction.all.innodb_active_trans is set to 1 + in ::external_lock and ::start_stmt, and it is only set to 0 in + a commit or a rollback. If it is 0 we know there cannot be resources + to be freed and we can return immediately. */ - if (trx->auto_inc_lock) { - - /* If we had reserved the auto-inc lock for - some table in this SQL statement, we release it now */ - - srv_conc_enter_innodb(trx); - row_unlock_table_autoinc_for_mysql(trx); - srv_conc_exit_innodb(trx); + if (thd->transaction.all.innodb_active_trans == 0) { + + DBUG_RETURN(0); } - if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle) { + trx = check_trx_exists(thd); + + if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle + || (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) { + innobase_commit_low(trx); - thd->transaction.all.innodb_active_trans=0; + + thd->transaction.all.innodb_active_trans = 0; + } else { + if (trx->auto_inc_lock) { + /* If we had reserved the auto-inc lock for some + table in this SQL statement we release it now */ + + srv_conc_enter_innodb(trx); + row_unlock_table_autoinc_for_mysql(trx); + srv_conc_exit_innodb(trx); + } + /* Store the current undo_no of the transaction so that we + know where to roll back if we have to roll back the next + SQL statement */ + + trx_mark_sql_stat_end(trx); } - /* Release possible statement level resources */ + /* Release a possible FIFO ticket and search latch */ innobase_release_stat_resources(trx); - trx_mark_sql_stat_end(trx); - /* Tell InnoDB server that there might be work for - utility threads: */ + /* Tell the InnoDB server that there might be work for utility + threads: */ srv_active_wake_master_thread(); @@ -1025,7 +1050,7 @@ innobase_commit_complete( } /********************************************************************* -Rolls back a transaction in an InnoDB database. */ +Rolls back a transaction or the latest SQL statement in an InnoDB database. */ int innobase_rollback( @@ -1066,11 +1091,9 @@ innobase_rollback( srv_conc_exit_innodb(trx); - /* Release possible statement level resources */ + /* Release a possible FIFO ticket and search latch */ innobase_release_stat_resources(trx); - trx_mark_sql_stat_end(trx); - DBUG_RETURN(convert_error_code_to_mysql(error, NULL)); } @@ -2994,6 +3017,8 @@ create_index( KEY* key; KEY_PART_INFO* key_part; ulint ind_type; + ulint col_type; + ulint prefix_len; ulint i; DBUG_ENTER("create_index"); @@ -3021,10 +3046,32 @@ create_index( for (i = 0; i < n_fields; i++) { key_part = key->key_part + i; + if (key_part->length != key_part->field->pack_length()) { + prefix_len = key_part->length; + + col_type = get_innobase_type_from_mysql_type( + key_part->field); + if (col_type == DATA_INT + || col_type == DATA_FLOAT + || col_type == DATA_DOUBLE + || col_type == DATA_DECIMAL) { + fprintf(stderr, +"InnoDB: error: MySQL is trying to create a column prefix index field\n" +"InnoDB: on an inappropriate data type %lu. Table name %s, column name %s.\n", + col_type, table_name, + key_part->field->field_name); + + prefix_len = 0; + } + } else { + prefix_len = 0; + } + /* We assume all fields should be sorted in ascending order, hence the '0': */ dict_mem_index_add_field(index, - (char*) key_part->field->field_name, 0); + (char*) key_part->field->field_name, + 0, prefix_len); } error = row_create_index_for_mysql(index, trx); @@ -3562,8 +3609,7 @@ ha_innobase::records_in_range( /************************************************************************* Gives an UPPER BOUND to the number of rows in a table. This is used in -filesort.cc and its better if the upper bound hold. -*/ +filesort.cc. */ ha_rows ha_innobase::estimate_number_of_rows(void) @@ -3598,11 +3644,11 @@ ha_innobase::estimate_number_of_rows(void) /* Calculate a minimum length for a clustered index record and from that an upper bound for the number of rows. Since we only calculate - new statistics in row0mysql.c when a tablehas grown - by a threshold factor, we must add a safety factor 2 in front - of the formula below. */ + new statistics in row0mysql.c when a table has grown by a threshold + factor, we must add a safety factor 2 in front of the formula below. */ - estimate = 2 * local_data_file_length / dict_index_calc_min_rec_len(index); + estimate = 2 * local_data_file_length / + dict_index_calc_min_rec_len(index); prebuilt->trx->op_info = (char*)""; @@ -3629,27 +3675,36 @@ ha_innobase::scan_time() return((double) (prebuilt->table->stat_clustered_index_size)); } -/* - Calculate the time it takes to read a set of ranges through and index - This enables us to optimise reads for clustered indexes. -*/ +/********************************************************************** +Calculate the time it takes to read a set of ranges through an index +This enables us to optimise reads for clustered indexes. */ -double ha_innobase::read_time(uint index, uint ranges, ha_rows rows) +double +ha_innobase::read_time( +/*===================*/ + /* out: estimated time measured in disk seeks */ + uint index, /* in: key number */ + uint ranges, /* in: how many ranges */ + ha_rows rows) /* in: estimated number of rows in the ranges */ { - ha_rows total_rows; - double time_for_scan; - if (index != table->primary_key) - return handler::read_time(index, ranges, rows); // Not clustered - if (rows <= 2) - return (double) rows; - /* - Assume that the read is proportional to scan time for all rows + one - seek per range. - */ - time_for_scan= scan_time(); - if ((total_rows= estimate_number_of_rows()) < rows) - return time_for_scan; - return (ranges + (double) rows / (double) total_rows * time_for_scan); + ha_rows total_rows; + double time_for_scan; + + if (index != table->primary_key) + return handler::read_time(index, ranges, rows); // Not clustered + + if (rows <= 2) + return (double) rows; + + /* Assume that the read time is proportional to the scan time for all + rows + at most one seek per range. */ + + time_for_scan= scan_time(); + + if ((total_rows= estimate_number_of_rows()) < rows) + return time_for_scan; + + return (ranges + (double) rows / (double) total_rows * time_for_scan); } /************************************************************************* @@ -3992,10 +4047,10 @@ ha_innobase::reset(void) } /********************************************************************** -Inside LOCK TABLES MySQL will not call external_lock() between SQL -statements. It will call this function at the start of each SQL statement. -Note also a spacial case: if a temporary table is created inside LOCK -TABLES, MySQL has not called external_lock() at all on that table. */ +MySQL calls this function at the start of each SQL statement. Inside LOCK +TABLES the ::external_lock method does not work to mark SQL statement +borders. Note also a special case: if a temporary table is created inside +LOCK TABLES, MySQL has not called external_lock() at all on that table. */ int ha_innobase::start_stmt( @@ -4010,8 +4065,14 @@ ha_innobase::start_stmt( trx = prebuilt->trx; + /* Here we release the search latch and the InnoDB thread FIFO ticket + if they were reserved. They should have been released already at the + end of the previous statement, but because inside LOCK TABLES the + lock count method does not work to mark the end of a SELECT statement, + that may not be the case. We MUST release the search latch before an + INSERT, for example. */ + innobase_release_stat_resources(trx); - trx_mark_sql_stat_end(trx); if (trx->isolation_level <= TRX_ISO_READ_COMMITTED && trx->read_view) { @@ -4034,7 +4095,8 @@ ha_innobase::start_stmt( prebuilt->select_lock_type = LOCK_X; } - + + /* Set the MySQL flag to mark that there is an active transaction */ thd->transaction.all.innodb_active_trans = 1; return(0); @@ -4098,17 +4160,20 @@ ha_innobase::external_lock( } if (lock_type != F_UNLCK) { - if (trx->n_mysql_tables_in_use == 0) { - trx_mark_sql_stat_end(trx); - } + /* MySQL is setting a new table lock */ + /* Set the MySQL flag to mark that there is an active + transaction */ thd->transaction.all.innodb_active_trans = 1; + trx->n_mysql_tables_in_use++; prebuilt->mysql_has_locked = TRUE; - trx->isolation_level = innobase_map_isolation_level( + if (trx->n_mysql_tables_in_use == 1) { + trx->isolation_level = innobase_map_isolation_level( (enum_tx_isolation) thd->variables.tx_isolation); + } if (trx->isolation_level == TRX_ISO_SERIALIZABLE && prebuilt->select_lock_type == LOCK_NONE) { @@ -4124,37 +4189,44 @@ ha_innobase::external_lock( trx->mysql_n_tables_locked++; } - } else { - trx->n_mysql_tables_in_use--; - prebuilt->mysql_has_locked = FALSE; - auto_inc_counter_for_this_stat = 0; - if (trx->n_mysql_tables_in_use == 0) { + DBUG_RETURN(error); + } - trx->mysql_n_tables_locked = 0; + /* MySQL is releasing a table lock */ - prebuilt->used_in_HANDLER = FALSE; + trx->n_mysql_tables_in_use--; + prebuilt->mysql_has_locked = FALSE; + auto_inc_counter_for_this_stat = 0; - /* Here we release the search latch and InnoDB - thread FIFO ticket if they were reserved. */ + /* If the MySQL lock count drops to zero we know that the current SQL + statement has ended */ - innobase_release_stat_resources(trx); + if (trx->n_mysql_tables_in_use == 0) { + trx->mysql_n_tables_locked = 0; + prebuilt->used_in_HANDLER = FALSE; + + if (!(thd->options + & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { + if (thd->transaction.all.innodb_active_trans != 0) { + innobase_commit(thd, trx); + } + } else { if (trx->isolation_level <= TRX_ISO_READ_COMMITTED && trx->read_view) { - /* At low transaction isolation levels we let + /* At low transaction isolation levels we let each consistent read set its own snapshot */ - read_view_close_for_mysql(trx); + read_view_close_for_mysql(trx); } - - if (!(thd->options - & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { - - innobase_commit(thd, trx); - } } + + /* Here we release the search latch and the InnoDB thread FIFO + ticket if they were reserved. */ + + innobase_release_stat_resources(trx); } DBUG_RETURN(error); @@ -4473,4 +4545,3 @@ ha_innobase::get_auto_increment() } #endif /* HAVE_INNOBASE_DB */ - diff --git a/sql/handler.cc b/sql/handler.cc index 6ee0b1f9c55..cae1777e958 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -209,44 +209,26 @@ void ha_close_connection(THD* thd) /* This is used to commit or rollback a single statement depending on the value - of error. If the autocommit is on, then we will commit or rollback the whole - transaction (= the statement). The autocommit mechanism built into handlers - is based on counting locks, but if the user has used LOCK TABLES then that - mechanism does not know to do the commit. + of error. Note that if the autocommit is on, then the following call inside + InnoDB will commit or rollback the whole transaction (= the statement). The + autocommit mechanism built into InnoDB is based on counting locks, but if + the user has used LOCK TABLES then that mechanism does not know to do the + commit. */ int ha_autocommit_or_rollback(THD *thd, int error) { - bool do_autocommit=FALSE; - DBUG_ENTER("ha_autocommit_or_rollback"); #ifdef USING_TRANSACTIONS - - if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) - do_autocommit=TRUE; /* We can commit or rollback the whole transaction */ - if (opt_using_transactions) { if (!error) { - if (do_autocommit) - { - if (ha_commit(thd)) - error=1; - } - else - { - if (ha_commit_stmt(thd)) - error=1; - } + if (ha_commit_stmt(thd)) + error=1; } else - { - if (do_autocommit) - (void) ha_rollback(thd); - else - (void) ha_rollback_stmt(thd); - } + (void) ha_rollback_stmt(thd); thd->variables.tx_isolation=thd->session_tx_isolation; } -- cgit v1.2.1 From e09517e2ac9596d0d011ca87f2d0cb181398da6c Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Thu, 5 Jun 2003 16:06:38 +0300 Subject: ha_innodb.cc: Revert a change to dict_mem_index_add_field which slipped prematurely into the bk tree --- sql/ha_innodb.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 9cc86edddf8..fd030fff091 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -3070,8 +3070,7 @@ create_index( /* We assume all fields should be sorted in ascending order, hence the '0': */ dict_mem_index_add_field(index, - (char*) key_part->field->field_name, - 0, prefix_len); + (char*) key_part->field->field_name, 0); } error = row_create_index_for_mysql(index, trx); -- cgit v1.2.1 From 058d8ed14b22fe3eb63cdc68cd41bffd84561367 Mon Sep 17 00:00:00 2001 From: "jani@ua126d19.elisa.omakaista.fi" <> Date: Thu, 5 Jun 2003 16:56:38 +0300 Subject: mysqld won't give a warning any more, if --user=user_name is used, if 'user_name' is the current user and it is not root. --- sql/mysqld.cc | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 8ed183e2f1f..315931094c2 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1013,14 +1013,21 @@ static void set_ports() static void set_user(const char *user) { #if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__) - struct passwd *ent; + struct passwd *ent; + uid_t user_id= geteuid(); // don't bother if we aren't superuser - if (geteuid()) + if (user_id) { if (user) - fprintf(stderr, - "Warning: One can only use the --user switch if running as root\n"); + { + /* Don't give a warning, if real user is same as given with --user */ + struct passwd *user_info= getpwnam(user); + + if (!user_info || user_id != user_info->pw_uid) + fprintf(stderr, + "Warning: One can only use the --user switch if running as root\n"); + } return; } else if (!user) -- cgit v1.2.1 From e6cdc816137b679e4c8d7c333eacf48d6afa1622 Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Thu, 5 Jun 2003 17:25:09 +0300 Subject: Added function comment --- mysys/thr_alarm.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c index 1f9c4c3b068..7a845e3eb00 100644 --- a/mysys/thr_alarm.c +++ b/mysys/thr_alarm.c @@ -122,9 +122,21 @@ 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) + + SYNOPSIS + thr_alarm() + alrm Pointer to alarm detection + alarm_data Structure to store in alarm queue + + NOTES + This function can't be called from the alarm-handling thread. + + RETURN VALUES + 0 ok + 1 If no more alarms are allowed (aborted by process) + + Stores in first argument a pointer to a non-zero int which is set to 0 + when the alarm has been given */ my_bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data) -- cgit v1.2.1 From 27cbc507faa302e09ad106eb0967e11318f876a4 Mon Sep 17 00:00:00 2001 From: "vva@eagle.mysql.r18.ru" <> Date: Thu, 5 Jun 2003 16:19:54 -0400 Subject: fixed bug (writting outside mallocced buffer in sql_help.cc) --- sql/sql_help.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 9003d4b36cd..ba7c08ff15f 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -553,14 +553,14 @@ int send_variant_2_list(MEM_ROOT *mem_root, Protocol *protocol, String **pointers= (String**)alloc_root(mem_root, sizeof(String*)*names->elements); - String **pos= pointers; + String **pos; + String **end= pointers + names->elements; List_iterator it(*names); - while ((*pos++= it++)); + for ( pos= pointers; pos!=end; (*pos++= it++)); qsort(pointers,names->elements,sizeof(String*),string_ptr_cmp); - String **end= pointers + names->elements; for (pos= pointers; pos!=end; pos++) { protocol->prepare_for_resend(); -- cgit v1.2.1 From 059b1e561287d87c18b39d317e7dbb8170b9fb74 Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Thu, 5 Jun 2003 23:19:56 +0300 Subject: After merge fixes --- include/sql_common.h | 1 + mysql-test/r/repair.result | 15 ----------- mysql-test/r/repair_part1.result | 15 +++++++++++ mysql-test/t/repair.test | 22 ---------------- mysql-test/t/repair_part1.test | 22 ++++++++++++++++ scripts/Makefile.am | 5 ++-- sql-common/client.c | 54 ++++++++++++++++++++-------------------- 7 files changed, 68 insertions(+), 66 deletions(-) delete mode 100644 mysql-test/r/repair.result create mode 100644 mysql-test/r/repair_part1.result delete mode 100644 mysql-test/t/repair.test create mode 100644 mysql-test/t/repair_part1.test diff --git a/include/sql_common.h b/include/sql_common.h index 3a668a8dd41..65283486fb4 100644 --- a/include/sql_common.h +++ b/include/sql_common.h @@ -16,6 +16,7 @@ extern const char *unknown_sqlstate; +extern const char *not_error_sqlstate; #ifdef __cplusplus extern "C" { diff --git a/mysql-test/r/repair.result b/mysql-test/r/repair.result deleted file mode 100644 index eb46622dcc1..00000000000 --- a/mysql-test/r/repair.result +++ /dev/null @@ -1,15 +0,0 @@ -drop table if exists t1; -create table t1 SELECT 1,"table 1"; -repair table t1 use_frm; -Table Op Msg_type Msg_text -test.t1 repair warning Number of rows changed from 0 to 1 -test.t1 repair status OK -alter table t1 TYPE=HEAP; -repair table t1 use_frm; -Table Op Msg_type Msg_text -test.t1 repair error The storage enginge for the table doesn't support repair -drop table t1; -repair table t1 use_frm; -Table Op Msg_type Msg_text -test.t1 repair error Table 'test.t1' doesn't exist -create table t1 type=myisam SELECT 1,"table 1"; diff --git a/mysql-test/r/repair_part1.result b/mysql-test/r/repair_part1.result new file mode 100644 index 00000000000..eb46622dcc1 --- /dev/null +++ b/mysql-test/r/repair_part1.result @@ -0,0 +1,15 @@ +drop table if exists t1; +create table t1 SELECT 1,"table 1"; +repair table t1 use_frm; +Table Op Msg_type Msg_text +test.t1 repair warning Number of rows changed from 0 to 1 +test.t1 repair status OK +alter table t1 TYPE=HEAP; +repair table t1 use_frm; +Table Op Msg_type Msg_text +test.t1 repair error The storage enginge for the table doesn't support repair +drop table t1; +repair table t1 use_frm; +Table Op Msg_type Msg_text +test.t1 repair error Table 'test.t1' doesn't exist +create table t1 type=myisam SELECT 1,"table 1"; diff --git a/mysql-test/t/repair.test b/mysql-test/t/repair.test deleted file mode 100644 index 2657f91cd02..00000000000 --- a/mysql-test/t/repair.test +++ /dev/null @@ -1,22 +0,0 @@ -# -# Test of repair table -# - ---disable_warnings -drop table if exists t1; ---enable_warnings - -create table t1 SELECT 1,"table 1"; -repair table t1 use_frm; -alter table t1 TYPE=HEAP; -repair table t1 use_frm; -drop table t1; - -# non-existent table -repair table t1 use_frm; - -# -# Create test table for repair2 -# The following must be last in this file - -create table t1 type=myisam SELECT 1,"table 1"; diff --git a/mysql-test/t/repair_part1.test b/mysql-test/t/repair_part1.test new file mode 100644 index 00000000000..2657f91cd02 --- /dev/null +++ b/mysql-test/t/repair_part1.test @@ -0,0 +1,22 @@ +# +# Test of repair table +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 SELECT 1,"table 1"; +repair table t1 use_frm; +alter table t1 TYPE=HEAP; +repair table t1 use_frm; +drop table t1; + +# non-existent table +repair table t1 use_frm; + +# +# Create test table for repair2 +# The following must be last in this file + +create table t1 type=myisam SELECT 1,"table 1"; diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 29cfad11220..6006222992e 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -33,7 +33,6 @@ bin_SCRIPTS = @server_scripts@ \ mysql_explain_log \ mysql_tableinfo \ mysqld_multi \ - fill_help_tables \ mysql_create_system_tables EXTRA_SCRIPTS = make_binary_distribution.sh \ @@ -140,5 +139,7 @@ SUFFIXES = .sh # Don't update the files from bitkeeper %::SCCS/s.% -all: make_win_src_distribution make_binary_distribution +all: fill_help_tables.sql make_win_src_distribution make_binary_distribution +fill_help_tables.sql: fill_help_tables ../Docs/manual.texi + ./fill_help_tables < ../Docs/manual.texi > fill_help_tables.sql diff --git a/sql-common/client.c b/sql-common/client.c index 55013d4bd82..cba552544f5 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -99,7 +99,8 @@ #include "client_settings.h" #include -const char *unknown_sqlstate= "000000"; +const char *unknown_sqlstate= "HY0000"; +const char *not_error_sqlstate= "00000"; #ifdef MYSQL_CLIENT extern my_bool stmt_close(MYSQL_STMT *stmt,my_bool skip_list); @@ -339,10 +340,10 @@ HANDLE create_shared_memory(MYSQL *mysql,NET *net, uint connect_timeout) /* The name of event and file-mapping events create agree next rule: - shared_memory_base_name+unique_part + shared_memory_base_name+unique_part Where: - shared_memory_base_name is unique value for each server - unique_part is uniquel value for each object (events and file-mapping) + shared_memory_base_name is unique value for each server + unique_part is uniquel value for each object (events and file-mapping) */ suffix_pos = strxmov(tmp,shared_memory_base_name,"_",NullS); strmov(suffix_pos, "CONNECT_REQUEST"); @@ -369,36 +370,34 @@ HANDLE create_shared_memory(MYSQL *mysql,NET *net, uint connect_timeout) error_allow = CR_SHARED_MEMORY_CONNECT_MAP_ERROR; goto err; } - /* - Send to server request of connection - */ + + /* Send to server request of connection */ if (!SetEvent(event_connect_request)) { error_allow = CR_SHARED_MEMORY_CONNECT_SET_ERROR; goto err; } - /* - Wait of answer from server - */ + + /* Wait of answer from server */ if (WaitForSingleObject(event_connect_answer,connect_timeout*1000) != WAIT_OBJECT_0) { error_allow = CR_SHARED_MEMORY_CONNECT_ABANDODED_ERROR; goto err; } - /* - Get number of connection - */ + + /* Get number of connection */ connect_number = uint4korr(handle_connect_map);/*WAX2*/ p= int2str(connect_number, connect_number_char, 10); /* The name of event and file-mapping events create agree next rule: shared_memory_base_name+unique_part+number_of_connection + Where: - shared_memory_base_name is uniquel value for each server - unique_part is uniquel value for each object (events and file-mapping) - number_of_connection is number of connection between server and client + shared_memory_base_name is uniquel value for each server + unique_part is uniquel value for each object (events and file-mapping) + number_of_connection is number of connection between server and client */ suffix_pos = strxmov(tmp,shared_memory_base_name,"_",connect_number_char, "_",NullS); @@ -506,7 +505,7 @@ net_safe_read(MYSQL *mysql) { NET *net= &mysql->net; ulong len=0; - init_sigpipe_variables + init_sigpipe_variables; /* Don't give sigpipe errors if the client doesn't want them */ set_sigpipe(mysql); @@ -571,7 +570,7 @@ advanced_command(MYSQL *mysql, enum enum_server_command command, { NET *net= &mysql->net; my_bool result= 1; - init_sigpipe_variables + init_sigpipe_variables; /* Don't give sigpipe errors if the client doesn't want them */ set_sigpipe(mysql); @@ -589,8 +588,8 @@ advanced_command(MYSQL *mysql, enum enum_server_command command, } net->last_error[0]=0; - net->last_errno=0; - strmov(net->sqlstate, unknown_sqlstate); + net->last_errno= 0; + strmov(net->sqlstate, not_error_sqlstate); mysql->net.report_error=0; mysql->info=0; mysql->affected_rows= ~(my_ulonglong) 0; @@ -624,7 +623,7 @@ advanced_command(MYSQL *mysql, enum enum_server_command command, if (!skip_check) result= ((mysql->packet_length=net_safe_read(mysql)) == packet_error ? 1 : 0); - end: +end: reset_sigpipe(mysql); return result; } @@ -665,7 +664,7 @@ void end_server(MYSQL *mysql) DBUG_ENTER("end_server"); if (mysql->net.vio != 0) { - init_sigpipe_variables + init_sigpipe_variables; DBUG_PRINT("info",("Net: %s", vio_description(mysql->net.vio))); set_sigpipe(mysql); vio_delete(mysql->net.vio); @@ -1457,7 +1456,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, #ifdef HAVE_SYS_UN_H struct sockaddr_un UNIXaddr; #endif - init_sigpipe_variables + init_sigpipe_variables; DBUG_ENTER("mysql_real_connect"); LINT_INIT(host_info); @@ -1561,7 +1560,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, net->vio = vio_new(sock, VIO_TYPE_SOCKET, TRUE); bzero((char*) &UNIXaddr,sizeof(UNIXaddr)); UNIXaddr.sun_family = AF_UNIX; - strmov(UNIXaddr.sun_path, unix_socket); + strmake(UNIXaddr.sun_path, unix_socket, sizeof(UNIXaddr.sun_path)-1); if (my_connect(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr), mysql->options.connect_timeout)) { @@ -2090,15 +2089,16 @@ static void mysql_fix_pointers(MYSQL* mysql, MYSQL* old_mysql) #endif /*MYSQL_CLIENT*/ } + my_bool mysql_reconnect(MYSQL *mysql) { MYSQL tmp_mysql; DBUG_ENTER("mysql_reconnect"); - if (!mysql->reconnect - || (mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info) + if (!mysql->reconnect || + (mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info) { - /* Allow reconnect next time */ + /* Allow reconnect next time */ mysql->server_status&= ~SERVER_STATUS_IN_TRANS; strmov(mysql->net.sqlstate, unknown_sqlstate); mysql->net.last_errno=CR_SERVER_GONE_ERROR; -- cgit v1.2.1 From eb0727c1428dda6884caf7376e50bec74a0dd96a Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Fri, 6 Jun 2003 10:50:13 +0500 Subject: my_global.h: ulong was used before the line it have been declared --- include/my_global.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/my_global.h b/include/my_global.h index 6d6f24c2438..9de8e310d79 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -660,8 +660,6 @@ typedef long my_ptrdiff_t; typedef long long my_ptrdiff_t; #endif -/* typedef used for length of string; Should be unsigned! */ -typedef ulong size_str; #define MY_ALIGN(A,L) (((A) + (L) - 1) & ~((L) - 1)) #define ALIGN_SIZE(A) MY_ALIGN((A),sizeof(double)) @@ -739,6 +737,8 @@ typedef unsigned __int64 my_ulonglong; typedef unsigned long long my_ulonglong; #endif +/* typedef used for length of string; Should be unsigned! */ +typedef ulong size_str; #ifdef USE_RAID /* -- cgit v1.2.1 From a6757c15df2859ab461ad4697cc80c773abdf8a5 Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Fri, 6 Jun 2003 11:06:45 +0500 Subject: client.c: Compilation falure fix --- sql-common/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql-common/client.c b/sql-common/client.c index cba552544f5..3c025d18bd6 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1456,7 +1456,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, #ifdef HAVE_SYS_UN_H struct sockaddr_un UNIXaddr; #endif - init_sigpipe_variables; + init_sigpipe_variables DBUG_ENTER("mysql_real_connect"); LINT_INIT(host_info); -- cgit v1.2.1 From 7d020eae177fb034c854cca8b4a571afcc6684bf Mon Sep 17 00:00:00 2001 From: "gluh@gluh.mysql.r18.ru" <> Date: Fri, 6 Jun 2003 17:43:23 +0500 Subject: REVOKE all privileges and delete user(244) --- include/mysqld_error.h | 2 + mysql-test/r/grant.result | 35 +++++ mysql-test/t/grant.test | 38 +++++ sql/lex.h | 2 +- sql/share/czech/errmsg.txt | 2 + sql/share/danish/errmsg.txt | 2 + sql/share/dutch/errmsg.txt | 2 + sql/share/english/errmsg.txt | 2 + sql/share/estonian/errmsg.txt | 2 + sql/share/french/errmsg.txt | 2 + sql/share/german/errmsg.txt | 2 + sql/share/greek/errmsg.txt | 2 + sql/share/hungarian/errmsg.txt | 2 + sql/share/italian/errmsg.txt | 2 + sql/share/japanese/errmsg.txt | 2 + sql/share/korean/errmsg.txt | 2 + sql/share/norwegian-ny/errmsg.txt | 2 + sql/share/norwegian/errmsg.txt | 2 + sql/share/polish/errmsg.txt | 2 + sql/share/portuguese/errmsg.txt | 2 + sql/share/romanian/errmsg.txt | 2 + sql/share/russian/errmsg.txt | 2 + sql/share/serbian/errmsg.txt | 2 + sql/share/slovak/errmsg.txt | 2 + sql/share/spanish/errmsg.txt | 2 + sql/share/swedish/errmsg.txt | 2 + sql/share/ukrainian/errmsg.txt | 2 + sql/sql_acl.cc | 288 ++++++++++++++++++++++++++++++++++++-- sql/sql_acl.h | 2 + sql/sql_lex.h | 2 +- sql/sql_parse.cc | 32 +++++ sql/sql_yacc.yy | 30 +++- 32 files changed, 456 insertions(+), 21 deletions(-) diff --git a/include/mysqld_error.h b/include/mysqld_error.h index d2fc5bbc77f..ccccb188037 100644 --- a/include/mysqld_error.h +++ b/include/mysqld_error.h @@ -282,4 +282,6 @@ #define ER_WARN_DATA_TRUNCATED 1263 #define ER_WARN_USING_OTHER_HANDLER 1264 #define ER_CANT_AGGREGATE_COLLATIONS 1265 +#define ER_DROP_USER 1266 +#define ER_REVOKE_GRANTS 1267 #define ER_ERROR_MESSAGES 266 diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index c1dcd5c29e9..715deac7965 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -1,3 +1,5 @@ +drop table if exists t1; +create table t1 (a int); delete from mysql.user where user='mysqltest_1'; delete from mysql.db where user='mysqltest_1'; flush privileges; @@ -69,3 +71,36 @@ show grants for user@localhost; Grants for user@localhost GRANT USAGE ON *.* TO 'user'@'localhost' GRANT USAGE ON `test`.* TO 'user'@'localhost' WITH GRANT OPTION +grant ALL PRIVILEGES on *.* to drop_user2@localhost with GRANT OPTION; +show grants for drop_user2@localhost; +Grants for drop_user2@localhost +GRANT ALL PRIVILEGES ON *.* TO 'drop_user2'@'localhost' WITH GRANT OPTION +revoke all privileges, grant from drop_user2@localhost; +drop user drop_user2@localhost; +grant ALL PRIVILEGES on *.* to drop_user@localhost with GRANT OPTION; +grant ALL PRIVILEGES on test.* to drop_user@localhost with GRANT OPTION; +grant select(a) on test.t1 to drop_user@localhost; +show grants for drop_user@localhost; +Grants for drop_user@localhost +GRANT ALL PRIVILEGES ON *.* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT ALL PRIVILEGES ON `test`.* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT SELECT (a) ON `test`.`t1` TO 'drop_user'@'localhost' +revoke all privileges, grant from drop_user@localhost; +show grants for drop_user@localhost; +Grants for drop_user@localhost +GRANT USAGE ON *.* TO 'drop_user'@'localhost' +drop user drop_user@localhost; +revoke all privileges, grant from drop_user@localhost; +Can't revoke all privileges, grant for one or more of the requested users +grant select(a) on test.t1 to drop_user1@localhost; +grant select on test.t1 to drop_user2@localhost; +grant select on test.* to drop_user3@localhost; +grant select on *.* to drop_user4@localhost; +drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost, +drop_user4@localhost; +Can't drop one or more of the requested users +revoke all privileges, grant from drop_user1@localhost, drop_user2@localhost, +drop_user3@localhost, drop_user4@localhost; +drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost, +drop_user4@localhost; +drop table t1; diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test index bd04b2e4c41..dcddbc99efa 100644 --- a/mysql-test/t/grant.test +++ b/mysql-test/t/grant.test @@ -1,3 +1,9 @@ +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (a int); + # # Test that SSL options works properly # @@ -42,3 +48,35 @@ flush privileges; grant usage on test.* to user@localhost with grant option; show grants for user@localhost; +# +# Test for 'drop user', 'revoke privileges, grant' +# + +grant ALL PRIVILEGES on *.* to drop_user2@localhost with GRANT OPTION; +show grants for drop_user2@localhost; +revoke all privileges, grant from drop_user2@localhost; +drop user drop_user2@localhost; + +grant ALL PRIVILEGES on *.* to drop_user@localhost with GRANT OPTION; +grant ALL PRIVILEGES on test.* to drop_user@localhost with GRANT OPTION; +grant select(a) on test.t1 to drop_user@localhost; +show grants for drop_user@localhost; +revoke all privileges, grant from drop_user@localhost; +show grants for drop_user@localhost; +drop user drop_user@localhost; +--error 1267 +revoke all privileges, grant from drop_user@localhost; + +grant select(a) on test.t1 to drop_user1@localhost; +grant select on test.t1 to drop_user2@localhost; +grant select on test.* to drop_user3@localhost; +grant select on *.* to drop_user4@localhost; +--error 1266 +drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost, +drop_user4@localhost; +revoke all privileges, grant from drop_user1@localhost, drop_user2@localhost, +drop_user3@localhost, drop_user4@localhost; +drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost, +drop_user4@localhost; + +drop table t1; diff --git a/sql/lex.h b/sql/lex.h index e89c9f51520..064bab8acbb 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -396,6 +396,7 @@ static SYMBOL symbols[] = { { "UNSIGNED", SYM(UNSIGNED),0,0}, { "USE", SYM(USE_SYM),0,0}, { "USE_FRM", SYM(USE_FRM),0,0}, + { "USER", SYM(USER),0,0}, { "USING", SYM(USING),0,0}, { "UPDATE", SYM(UPDATE_SYM),0,0}, { "USAGE", SYM(USAGE),0,0}, @@ -632,7 +633,6 @@ static SYMBOL sql_functions[] = { { "UNIQUE_USERS", SYM(UNIQUE_USERS),0,0}, { "UNIX_TIMESTAMP", SYM(UNIX_TIMESTAMP),0,0}, { "UPPER", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ucase)}, - { "USER", SYM(USER),0,0}, { "VARIANCE", SYM(VARIANCE_SYM),0,0}, { "VERSION", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_version)}, { "WEEK", SYM(WEEK_SYM),0,0}, diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index e277c19e26f..273dfa0fcf5 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -271,3 +271,5 @@ v/* "%d line(s) was(were) cut by group_concat()", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", +"Can't drop one or more of the requested users" +"Can't revoke all privileges, grant for one or more of the requested users" diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index 01856ffed01..1d39a328154 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -265,3 +265,5 @@ "%d line(s) was(were) cut by group_concat()", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", +"Can't drop one or more of the requested users" +"Can't revoke all privileges, grant for one or more of the requested users" diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index 4b9b0b9f710..5b79f06b621 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -273,3 +273,5 @@ "%d line(s) was(were) cut by group_concat()", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", +"Can't drop one or more of the requested users" +"Can't revoke all privileges, grant for one or more of the requested users" diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index 89045b13985..ad15d55405f 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -267,3 +267,5 @@ "Data truncated for column '%s' at row %ld" "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", +"Can't drop one or more of the requested users" +"Can't revoke all privileges, grant for one or more of the requested users" diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index d5064b53790..506b5fc0188 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -267,3 +267,5 @@ "%d line(s) was(were) cut by group_concat()", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", +"Can't drop one or more of the requested users" +"Can't revoke all privileges, grant for one or more of the requested users" diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index eb936243332..8882e4dceda 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -262,3 +262,5 @@ "%d line(s) was(were) cut by group_concat()", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", +"Can't drop one or more of the requested users" +"Can't revoke all privileges, grant for one or more of the requested users" diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index 2ac25216b8e..1e8f5bb2c05 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -271,3 +271,5 @@ "%d line(s) was(were) cut by group_concat()", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", +"Can't drop one or more of the requested users" +"Can't revoke all privileges, grant for one or more of the requested users" diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index 8e82559db5c..d322f3fbd6a 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -262,3 +262,5 @@ "%d line(s) was(were) cut by group_concat()", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", +"Can't drop one or more of the requested users" +"Can't revoke all privileges, grant for one or more of the requested users" diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index de0e7da614e..162bfc5509c 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -264,3 +264,5 @@ "%d line(s) was(were) cut by group_concat()", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", +"Can't drop one or more of the requested users" +"Can't revoke all privileges, grant for one or more of the requested users" diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index d9308faf8a6..26d916a968d 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -262,3 +262,5 @@ "%d line(s) was(were) cut by group_concat()", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", +"Can't drop one or more of the requested users" +"Can't revoke all privileges, grant for one or more of the requested users" diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index 45e78941906..a01a2b7ff6f 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -264,3 +264,5 @@ "%d line(s) was(were) cut by group_concat()", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", +"Can't drop one or more of the requested users" +"Can't revoke all privileges, grant for one or more of the requested users" diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index 43d291ae3a5..5f5526be04b 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -262,3 +262,5 @@ "%d line(s) was(were) cut by group_concat()", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", +"Can't drop one or more of the requested users" +"Can't revoke all privileges, grant for one or more of the requested users" diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index c0c045438ec..bf1019d3d87 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -264,3 +264,5 @@ "%d line(s) was(were) cut by group_concat()", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", +"Can't drop one or more of the requested users" +"Can't revoke all privileges, grant for one or more of the requested users" diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index 03430ae546b..68c95bbf22b 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -264,3 +264,5 @@ "%d line(s) was(were) cut by group_concat()", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", +"Can't drop one or more of the requested users" +"Can't revoke all privileges, grant for one or more of the requested users" diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index 997ee08e66a..5b93403c757 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -266,3 +266,5 @@ "%d line(s) was(were) cut by group_concat()", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", +"Can't drop one or more of the requested users" +"Can't revoke all privileges, grant for one or more of the requested users" diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index ef051d957cb..edd3e3b813f 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -262,3 +262,5 @@ "%d linha(s) foi(foram) cortada(s) por group_concat()", "Usando engine de armazenamento %s para tabela '%s'", "Combinação ilegal de collations (%s,%s) e (%s,%s) para operação '%s'", +"Can't drop one or more of the requested users" +"Can't revoke all privileges, grant for one or more of the requested users" diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 89c00b4bf15..873a708fa7b 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -266,3 +266,5 @@ "%d line(s) was(were) cut by group_concat()", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", +"Can't drop one or more of the requested users" +"Can't revoke all privileges, grant for one or more of the requested users" diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index fac4dedb3ee..a05ecde6808 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -264,3 +264,5 @@ "%d line(s) was(were) cut by group_concat()", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", +"Can't drop one or more of the requested users" +"Can't revoke all privileges, grant for one or more of the requested users" diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index d954e7998a2..c1c0de779c7 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -258,3 +258,5 @@ "%d line(s) was(were) cut by group_concat()", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", +"Can't drop one or more of the requested users" +"Can't revoke all privileges, grant for one or more of the requested users" diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index 8f7747c6bf6..26d673b847c 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -270,3 +270,5 @@ "%d line(s) was(were) cut by group_concat()", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", +"Can't drop one or more of the requested users" +"Can't revoke all privileges, grant for one or more of the requested users" diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index 4a7989ce7be..99a92f63c4e 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -263,3 +263,5 @@ "%d line(s) was(were) cut by group_concat()", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", +"Can't drop one or more of the requested users" +"Can't revoke all privileges, grant for one or more of the requested users" diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index 6734369d3ac..c613d205947 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -262,3 +262,5 @@ "%d rad(er) kapades av group_concat()", "Använder handler %s för tabell '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", +"Can't drop one or more of the requested users" +"Can't revoke all privileges, grant for one or more of the requested users" diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index 67c52dc8fee..6505c3c9cac 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -267,3 +267,5 @@ "%d line(s) was(were) cut by group_concat()", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", +"Can't drop one or more of the requested users" +"Can't revoke all privileges, grant for one or more of the requested users" diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index ec6db64ea73..49aad321702 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2179,11 +2179,6 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, { int error; GRANT_TABLE *grant_table; - if (!Str->host.str) - { - Str->host.str=(char*) "%"; - Str->host.length=1; - } if (Str->host.length > HOSTNAME_LENGTH || Str->user.length > USERNAME_LENGTH) { @@ -2350,11 +2345,6 @@ int mysql_grant (THD *thd, const char *db, List &list, int result=0; while ((Str = str_list++)) { - if (!Str->host.str) - { - Str->host.str=(char*) "%"; - Str->host.length=1; - } if (Str->host.length > HOSTNAME_LENGTH || Str->user.length > USERNAME_LENGTH) { @@ -2855,11 +2845,6 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) send_error(thd, ER_UNKNOWN_COM_ERROR); DBUG_RETURN(-1); } - if (!lex_user->host.str) - { - lex_user->host.str=(char*) "%"; - lex_user->host.length=1; - } if (lex_user->host.length > HOSTNAME_LENGTH || lex_user->user.length > USERNAME_LENGTH) { @@ -3202,6 +3187,279 @@ void get_mqh(const char *user, const char *host, USER_CONN *uc) bzero((char*) &uc->user_resources, sizeof(uc->user_resources)); } +int open_grant_tables(THD *thd, TABLE_LIST *tables) +{ + DBUG_ENTER("open_grant_tables"); + + if (!initialized) + { + send_error(thd, ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES)); + DBUG_RETURN(-1); + } + + bzero((char*) tables, 4*sizeof(*tables)); + tables->alias= tables->real_name= (char*) "user"; + (tables+1)->alias= (tables+1)->real_name= (char*) "db"; + (tables+2)->alias= (tables+2)->real_name= (char*) "tables_priv"; + (tables+3)->alias= (tables+3)->real_name= (char*) "columns_priv"; + tables->next= tables+1; + (tables+1)->next= tables+2; + (tables+2)->next= tables+3; + (tables+3)->next= 0; + tables->lock_type= (tables+1)->lock_type= + (tables+2)->lock_type= (tables+3)->lock_type= TL_WRITE; + tables->db= (tables+1)->db= (tables+2)->db= (tables+3)->db=(char*) "mysql"; + +#ifdef HAVE_REPLICATION + /* + GRANT and REVOKE are applied the slave in/exclusion rules as they are + some kind of updates to the mysql.% tables. + */ + if (thd->slave_thread && table_rules_on && !tables_ok(0, tables)) + DBUG_RETURN(1); +#endif + + if (open_and_lock_tables(thd, tables)) + { // This should never happen + close_thread_tables(thd); + DBUG_RETURN(-1); + } + + DBUG_RETURN(0); +} + +ACL_USER *check_acl_user(LEX_USER *user_name, + uint *acl_user_idx) +{ + ACL_USER *acl_user= 0; + uint counter; + + for (counter= 0 ; counter < acl_users.elements ; counter++) + { + const char *user,*host; + acl_user= dynamic_element(&acl_users, counter, ACL_USER*); + if (!(user=acl_user->user)) + user=""; + if (!(host=acl_user->host.hostname)) + host="%"; + if (!strcmp(user_name->user.str,user) && + !my_strcasecmp(system_charset_info, user_name->host.str, host)) + break; + } + if (counter == acl_users.elements) + return 0; + + *acl_user_idx= counter; + return acl_user; +} + +int mysql_drop_user(THD *thd, List &list) +{ + uint counter, user_id; + int result; + ACL_USER *acl_user; + ACL_DB *acl_db; + TABLE_LIST tables[4]; + + DBUG_ENTER("mysql_drop_user"); + + if ((result= open_grant_tables(thd, tables))) + DBUG_RETURN(result == 1 ? 0 : -1); + + rw_wrlock(&LOCK_grant); + VOID(pthread_mutex_lock(&acl_cache->lock)); + + LEX_USER *user_name; + List_iterator user_list(list); + while ((user_name=user_list++)) + { + if (!(acl_user= check_acl_user(user_name, &counter))) + { + sql_print_error("DROP USER: Can't drop user: '%s'@'%s'", + user_name->user.str, + user_name->host.str); + result= -1; + continue; + } + if ((acl_user->access & ~0)) + { + sql_print_error("DROP USER: Can't drop user: '%s'@'%s'", + user_name->user.str, + user_name->host.str); + result= -1; + continue; + } + user_id= counter; + + for (counter= 0 ; counter < acl_dbs.elements ; counter++) + { + const char *user,*host; + acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*); + if (!(user= acl_db->user)) + user=""; + if (!(host= acl_db->host.hostname)) + host=""; + + if (!strcmp(user_name->user.str,user) && + !my_strcasecmp(system_charset_info, user_name->host.str, host)) + break; + } + if (counter != acl_dbs.elements) + { + sql_print_error("DROP USER: Can't drop user: '%s'@'%s'", + user_name->user.str, + user_name->host.str); + result= -1; + continue; + } + + for (counter= 0 ; counter < column_priv_hash.records ; counter++) + { + const char *user,*host; + GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash, + counter); + if (!(user=grant_table->user)) + user=""; + if (!(host=grant_table->host)) + host=""; + + if (!strcmp(user_name->user.str,user) && + !my_strcasecmp(system_charset_info, user_name->host.str, host)) + break; + } + if (counter != column_priv_hash.records) + { + sql_print_error("DROP USER: Can't drop user: '%s'@'%s'", + user_name->user.str, + user_name->host.str); + result= -1; + continue; + } + + tables[0].table->field[0]->store(user_name->host.str,(uint) + user_name->host.length, system_charset_info); + tables[0].table->field[1]->store(user_name->user.str,(uint) + user_name->user.length, system_charset_info); + if (!tables[0].table->file->index_read_idx(tables[0].table->record[0],0, + (byte*) tables[0].table->field[0]->ptr,0, + HA_READ_KEY_EXACT)) + { + int error; + if ((error = tables[0].table->file->delete_row(tables[0].table->record[0]))) + { + tables[0].table->file->print_error(error, MYF(0)); + tables[0].table->file->index_end(); + DBUG_RETURN(-1); + } + delete_dynamic_element(&acl_users, user_id); + } + tables[0].table->file->index_end(); + } +err: + VOID(pthread_mutex_unlock(&acl_cache->lock)); + rw_unlock(&LOCK_grant); + close_thread_tables(thd); + if (result) + my_error(ER_DROP_USER, MYF(0)); + DBUG_RETURN(result); +} + +int mysql_revoke_all(THD *thd, List &list) +{ + uint counter; + int result; + ACL_USER *acl_user; ACL_DB *acl_db; + TABLE_LIST tables[4]; + DBUG_ENTER("mysql_revoke_all"); + + if ((result= open_grant_tables(thd, tables))) + DBUG_RETURN(result == 1 ? 0 : -1); + + rw_wrlock(&LOCK_grant); + VOID(pthread_mutex_lock(&acl_cache->lock)); + + LEX_USER *lex_user; + List_iterator user_list(list); + while ((lex_user=user_list++)) + { + if (!(acl_user= check_acl_user(lex_user, &counter))) + { + sql_print_error("REVOKE ALL PRIVILEGES, GRANT: User '%s'@'%s' not exists", + lex_user->user.str, + lex_user->host.str); + result= -1; + continue; + } + + if (replace_user_table(thd, tables[0].table, + *lex_user, ~0, 1, 0)) + { + result= -1; + continue; + } + + /* Remove db access privileges */ + for (counter= 0 ; counter < acl_dbs.elements ; counter++) + { + const char *user,*host; + + acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*); + if (!(user=acl_db->user)) + user=""; + if (!(host=acl_db->host.hostname)) + host=""; + + if (!strcmp(lex_user->user.str,user) && + !my_strcasecmp(system_charset_info, lex_user->host.str, host)) + { + if (replace_db_table(tables[1].table, acl_db->db, *lex_user, ~0, 1)) + result= -1; + } + } + + /* Remove column access */ + for (counter= 0 ; counter < column_priv_hash.records ; counter++) + { + const char *user,*host; + GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash, + counter); + if (!(user=grant_table->user)) + user=""; + if (!(host=grant_table->host)) + host=""; + + if (!strcmp(lex_user->user.str,user) && + !my_strcasecmp(system_charset_info, lex_user->host.str, host)) + { + if (replace_table_table(thd,grant_table,tables[2].table,*lex_user, + grant_table->db, + grant_table->tname, + ~0, 0, 1)) + { + result= -1; + continue; + } + if (grant_table->cols) + { + List columns; + if (replace_column_table(grant_table,tables[3].table, *lex_user, + columns, + grant_table->db, + grant_table->tname, + ~0, 1)) + result= -1; + } + } + } + } + + VOID(pthread_mutex_unlock(&acl_cache->lock)); + rw_unlock(&LOCK_grant); + close_thread_tables(thd); + if (result) + my_error(ER_REVOKE_GRANTS, MYF(0)); + DBUG_RETURN(result); +} /***************************************************************************** diff --git a/sql/sql_acl.h b/sql/sql_acl.h index d85a281cbb5..e6c6771253c 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -163,3 +163,5 @@ ulong get_column_grant(THD *thd, TABLE_LIST *table, Field *field); int mysql_show_grants(THD *thd, LEX_USER *user); void get_privilege_desc(char *to, uint max_length, ulong access); void get_mqh(const char *user, const char *host, USER_CONN *uc); +int mysql_drop_user(THD *thd, List &list); +int mysql_revoke_all(THD *thd, List &list); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index f31b3305e07..a01c98bb283 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -71,7 +71,7 @@ enum enum_sql_command { SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_DO, SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS, SQLCOM_SHOW_COLUMN_TYPES, SQLCOM_SHOW_TABLE_TYPES, SQLCOM_SHOW_PRIVILEGES, - SQLCOM_HELP, + SQLCOM_HELP, SQLCOM_DROP_USER, SQLCOM_REVOKE_ALL, /* This should be the last !!! */ SQLCOM_END diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 9ebb6305f70..fd3d359f0c8 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2897,6 +2897,38 @@ mysql_execute_command(THD *thd) res= -1; #endif break; + case SQLCOM_DROP_USER: + { + if (check_access(thd, GRANT_ACL,"mysql",0,1)) + break; + if (!(res= mysql_drop_user(thd, lex->users_list))) + { + mysql_update_log.write(thd, thd->query, thd->query_length); + if (mysql_bin_log.is_open()) + { + Query_log_event qinfo(thd, thd->query, thd->query_length, 0); + mysql_bin_log.write(&qinfo); + } + send_ok(thd); + } + break; + } + case SQLCOM_REVOKE_ALL: + { + if (check_access(thd, GRANT_ACL ,"mysql",0,1)) + break; + if (!(res = mysql_revoke_all(thd, lex->users_list))) + { + mysql_update_log.write(thd, thd->query, thd->query_length); + if (mysql_bin_log.is_open()) + { + Query_log_event qinfo(thd, thd->query, thd->query_length, 0); + mysql_bin_log.write(&qinfo); + } + send_ok(thd); + } + break; + } case SQLCOM_REVOKE: case SQLCOM_GRANT: { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 1002d06be88..fbc7e9deb36 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3215,7 +3215,7 @@ do: DO_SYM ; /* - Drop : delete tables or index + Drop : delete tables or index or user */ drop: @@ -3249,7 +3249,16 @@ drop: LEX *lex=Lex; lex->sql_command = SQLCOM_DROP_FUNCTION; lex->udf.name = $3; - }; + } + | DROP USER + { + LEX *lex=Lex; + lex->sql_command = SQLCOM_DROP_USER; + lex->users_list.empty(); + } + user_list + {} + ; table_list: @@ -4177,8 +4186,10 @@ user: THD *thd= YYTHD; if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) YYABORT; - $$->user = $1; $$->host.str=NullS; - } + $$->user = $1; + $$->host.str= (char *) "%"; + $$->host.length= 1; + } | ident_or_text '@' ident_or_text { THD *thd= YYTHD; @@ -4361,6 +4372,7 @@ keyword: | UDF_SYM {} | UNCOMMITTED_SYM {} | UNICODE_SYM {} + | USER {} | USE_FRM {} | VARIABLES {} | VALUE_SYM {} @@ -4632,8 +4644,18 @@ revoke: lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0; bzero((char*) &lex->mqh, sizeof(lex->mqh)); } + revoke_command + {} + ; + +revoke_command: grant_privileges ON opt_table FROM user_list {} + | + ALL PRIVILEGES ',' GRANT FROM user_list + { + Lex->sql_command = SQLCOM_REVOKE_ALL; + } ; grant: -- cgit v1.2.1 From d764294f12cd21847440403231bca71cc6b8d2ec Mon Sep 17 00:00:00 2001 From: "venu@myvenu.com" <> Date: Sun, 8 Jun 2003 09:11:14 -0700 Subject: Fix for mysql_list_fields & reset stmt buffers from stmt_free_result Windows build fix --- VC++Files/sql/mysqld.dsp | 4 + include/mysql_com.h | 2 +- include/thr_alarm.h | 2 +- libmysql/libmysql.c | 10 +- tests/client_test.c | 238 +++++++++++++++++++++++++++++++++++++---------- 5 files changed, 204 insertions(+), 52 deletions(-) diff --git a/VC++Files/sql/mysqld.dsp b/VC++Files/sql/mysqld.dsp index a475c44e948..6aab591120a 100644 --- a/VC++Files/sql/mysqld.dsp +++ b/VC++Files/sql/mysqld.dsp @@ -1137,6 +1137,10 @@ SOURCE=.\sql_show.cpp # End Source File # Begin Source File +SOURCE=.\sql_state.c +# End Source File +# Begin Source File + SOURCE=.\sql_string.cpp !IF "$(CFG)" == "mysqld - Win32 Release" diff --git a/include/mysql_com.h b/include/mysql_com.h index 2ed5038b275..faa025c934e 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -324,7 +324,7 @@ my_bool check_scramble(const char *, const char *message, unsigned long *salt,my_bool old_ver); char *get_tty_password(char *opt_message); void hash_password(unsigned long *result, const char *password); -const char *mysql_errno_to_sqlstate(uint mysql_errno); +const char *mysql_errno_to_sqlstate(unsigned int mysql_errno); /* Some other useful functions */ diff --git a/include/thr_alarm.h b/include/thr_alarm.h index 8ff4472f700..439f046252f 100644 --- a/include/thr_alarm.h +++ b/include/thr_alarm.h @@ -100,7 +100,7 @@ typedef struct st_alarm { #define thr_alarm_init(A) (*(A))=0 #define thr_alarm_in_use(A) (*(A)!= 0) void init_thr_alarm(uint max_alarm); -my_bool thr_alarm(thr_alarm_t *alarmed, uint sec, ALARM *buff); +bool thr_alarm(thr_alarm_t *alarmed, uint sec, ALARM *buff); void thr_alarm_kill(pthread_t thread_id); void thr_end_alarm(thr_alarm_t *alarmed); void end_thr_alarm(my_bool free_structures); diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 064a6c292eb..7e379ab63ba 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -990,7 +990,7 @@ mysql_list_fields(MYSQL *mysql, const char *table, const char *wild) end=strmake(strmake(buff, table,128)+1,wild ? wild : "",128); if (simple_command(mysql,COM_FIELD_LIST,buff,(ulong) (end-buff),1) || !(query = read_rows(mysql,(MYSQL_FIELD*) 0, - protocol_41(mysql) ? 7 : 6))) + protocol_41(mysql) ? 8 : 6))) DBUG_RETURN(NULL); free_old_query(mysql); @@ -1027,7 +1027,7 @@ mysql_list_processes(MYSQL *mysql) pos=(uchar*) mysql->net.read_pos; field_count=(uint) net_field_length(&pos); if (!(fields = read_rows(mysql,(MYSQL_FIELD*) 0, - protocol_41(mysql) ? 6 : 5))) + protocol_41(mysql) ? 7 : 5))) DBUG_RETURN(NULL); if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,field_count,0, mysql->server_capabilities))) @@ -3055,7 +3055,8 @@ int STDCALL mysql_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind, #ifdef CHECK_EXTRA_ARGUMENTS if (!bind || icol >= stmt->field_count) { - DBUG_PRINT("error",("Invalid column position")); + set_stmt_errmsg(stmt, "Invalid column descriptor or offset",1, + unknown_sqlstate); DBUG_RETURN(1); } #endif @@ -3377,6 +3378,9 @@ my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt) mysql->status= MYSQL_STATUS_READY; } mysql_free_result(stmt->result); + stmt->result= 0; + stmt->result_buffered= 0; + stmt->current_row= 0; DBUG_RETURN(0); } diff --git a/tests/client_test.c b/tests/client_test.c index eebf65ce45f..d22aa900a4e 100644 --- a/tests/client_test.c +++ b/tests/client_test.c @@ -180,7 +180,7 @@ static void client_connect() if (!(mysql = mysql_init(NULL))) { - myerror("mysql_init() failed"); + myerror("mysql_init() failed"); exit(0); } @@ -535,7 +535,7 @@ static void verify_prepare_field(MYSQL_RES *result, unsigned int no,const char *name, const char *org_name, enum enum_field_types type, const char *table, const char *org_table, const char *db, - unsigned long length) + unsigned long length, const char *def) { MYSQL_FIELD *field; @@ -554,6 +554,7 @@ static void verify_prepare_field(MYSQL_RES *result, fprintf(stdout,"\n length :`%ld`\t(expected: `%ld`)", field->length, length); fprintf(stdout,"\n maxlength:`%ld`", field->max_length); fprintf(stdout,"\n charsetnr:`%d`", field->charsetnr); + fprintf(stdout,"\n default :`%s`\t(expected: `%s`)", field->def ? field->def : "(null)", def ? def: "(null)"); fprintf(stdout,"\n"); myassert(strcmp(field->name,name) == 0); myassert(strcmp(field->org_name,org_name) == 0); @@ -562,6 +563,8 @@ static void verify_prepare_field(MYSQL_RES *result, myassert(strcmp(field->org_table,org_table) == 0); myassert(strcmp(field->db,db) == 0); myassert(field->length == length); + if (def) + myassert(strcmp(field->def,def) == 0); } /* @@ -1021,15 +1024,15 @@ static void test_prepare_field_result() fprintf(stdout,"\n\n field attributes:\n"); verify_prepare_field(result,0,"int_c","int_c",MYSQL_TYPE_LONG, - "t1","test_prepare_field_result",current_db,11); + "t1","test_prepare_field_result",current_db,11,0); verify_prepare_field(result,1,"var_c","var_c",MYSQL_TYPE_VAR_STRING, - "t1","test_prepare_field_result",current_db,50); + "t1","test_prepare_field_result",current_db,50,0); verify_prepare_field(result,2,"date","date_c",MYSQL_TYPE_DATE, - "t1","test_prepare_field_result",current_db,10); + "t1","test_prepare_field_result",current_db,10,0); verify_prepare_field(result,3,"ts_c","ts_c",MYSQL_TYPE_TIMESTAMP, - "t1","test_prepare_field_result",current_db,19); + "t1","test_prepare_field_result",current_db,19,0); verify_prepare_field(result,4,"char_c","char_c",MYSQL_TYPE_STRING, - "t1","test_prepare_field_result",current_db,3); + "t1","test_prepare_field_result",current_db,3,0); verify_field_count(result, 5); mysql_free_result(result); @@ -5830,7 +5833,7 @@ static void test_field_misc() "@@autocommit","", /* field and its org name */ MYSQL_TYPE_LONGLONG, /* field type */ "", "", /* table and its org name */ - "",1); /* db name, length(its bool flag)*/ + "",1,0); /* db name, length(its bool flag)*/ mysql_free_result(result); @@ -5849,7 +5852,7 @@ static void test_field_misc() "@@autocommit","", /* field and its org name */ MYSQL_TYPE_LONGLONG, /* field type */ "", "", /* table and its org name */ - "",1); /* db name, length(its bool flag)*/ + "",1,0); /* db name, length(its bool flag)*/ mysql_free_result(result); mysql_stmt_close(stmt); @@ -5893,7 +5896,7 @@ static void test_field_misc() "@@table_type","", /* field and its org name */ MYSQL_TYPE_STRING, /* field type */ "", "", /* table and its org name */ - "",type_length); /* db name, length */ + "",type_length,0); /* db name, length */ mysql_free_result(result); mysql_stmt_close(stmt); @@ -5913,7 +5916,7 @@ static void test_field_misc() "@@max_error_count","", /* field and its org name */ MYSQL_TYPE_LONGLONG, /* field type */ "", "", /* table and its org name */ - "",10); /* db name, length */ + "",10,0); /* db name, length */ mysql_free_result(result); mysql_stmt_close(stmt); @@ -5933,7 +5936,7 @@ static void test_field_misc() "@@max_allowed_packet","", /* field and its org name */ MYSQL_TYPE_LONGLONG, /* field type */ "", "", /* table and its org name */ - "",10); /* db name, length */ + "",10,0); /* db name, length */ mysql_free_result(result); mysql_stmt_close(stmt); @@ -5953,7 +5956,7 @@ static void test_field_misc() "@@sql_warnings","", /* field and its org name */ MYSQL_TYPE_LONGLONG, /* field type */ "", "", /* table and its org name */ - "",1); /* db name, length */ + "",1,0); /* db name, length */ mysql_free_result(result); mysql_stmt_close(stmt); @@ -6340,39 +6343,22 @@ static void test_explain_bug() myassert(6 == mysql_num_fields(result)); verify_prepare_field(result,0,"Field","",MYSQL_TYPE_STRING, - "","","",NAME_LEN); + "","","",NAME_LEN,0); verify_prepare_field(result,1,"Type","",MYSQL_TYPE_STRING, - "","","",40); -#if 0 - - verify_prepare_field(result,2,"Collation","",MYSQL_TYPE_STRING, - "","","",40); - - verify_prepare_field(result,3,"Null","",MYSQL_TYPE_STRING, - "","","",1); + "","","",40,0); - verify_prepare_field(result,4,"Key","",MYSQL_TYPE_STRING, - "","","",3); - - verify_prepare_field(result,5,"Default","",MYSQL_TYPE_STRING, - "","","",NAME_LEN); - - verify_prepare_field(result,6,"Extra","",MYSQL_TYPE_STRING, - "","","",20); -#else verify_prepare_field(result,2,"Null","",MYSQL_TYPE_STRING, - "","","",1); + "","","",1,0); verify_prepare_field(result,3,"Key","",MYSQL_TYPE_STRING, - "","","",3); + "","","",3,0); verify_prepare_field(result,4,"Default","",MYSQL_TYPE_STRING, - "","","",NAME_LEN); + "","","",NAME_LEN,0); verify_prepare_field(result,5,"Extra","",MYSQL_TYPE_STRING, - "","","",20); -#endif + "","","",20,0); mysql_free_result(result); mysql_stmt_close(stmt); @@ -6393,34 +6379,34 @@ static void test_explain_bug() myassert(10 == mysql_num_fields(result)); verify_prepare_field(result,0,"id","",MYSQL_TYPE_LONGLONG, - "","","",3); + "","","",3,0); verify_prepare_field(result,1,"select_type","",MYSQL_TYPE_STRING, - "","","",19); + "","","",19,0); verify_prepare_field(result,2,"table","",MYSQL_TYPE_STRING, - "","","",NAME_LEN); + "","","",NAME_LEN,0); verify_prepare_field(result,3,"type","",MYSQL_TYPE_STRING, - "","","",10); + "","","",10,0); verify_prepare_field(result,4,"possible_keys","",MYSQL_TYPE_STRING, - "","","",NAME_LEN*32); + "","","",NAME_LEN*32,0); verify_prepare_field(result,5,"key","",MYSQL_TYPE_STRING, - "","","",NAME_LEN); + "","","",NAME_LEN,0); verify_prepare_field(result,6,"key_len","",MYSQL_TYPE_LONGLONG, - "","","",3); + "","","",3,0); verify_prepare_field(result,7,"ref","",MYSQL_TYPE_STRING, - "","","",NAME_LEN*16); + "","","",NAME_LEN*16,0); verify_prepare_field(result,8,"rows","",MYSQL_TYPE_LONGLONG, - "","","",10); + "","","",10,0); verify_prepare_field(result,9,"Extra","",MYSQL_TYPE_STRING, - "","","",255); + "","","",255,0); mysql_free_result(result); mysql_stmt_close(stmt); @@ -7053,6 +7039,9 @@ static void test_fetch_column() fprintf(stdout, "\n col 0: %d(%ld)", c1, l1); myassert(c1 == 1 && l1 == 4); + rc = mysql_fetch_column(stmt,bind,10,0); + mystmt_r(stmt,rc); + rc = mysql_fetch(stmt); mystmt(stmt,rc); @@ -7110,13 +7099,20 @@ static void test_list_fields() rc= mysql_query(mysql,"drop table if exists test_list_fields"); myquery(rc); - rc = mysql_query(mysql, "create table test_list_fields(c1 int primary key auto_increment, c2 char(10))"); + rc = mysql_query(mysql, "create table test_list_fields(c1 int primary key auto_increment, c2 char(10) default 'mysql')"); myquery(rc); result = mysql_list_fields(mysql, "test_list_fields",NULL); mytest(result); myassert( 0 == my_process_result_set(result)); + + verify_prepare_field(result,0,"c1","c1",MYSQL_TYPE_LONG, + "test_list_fields","test_list_fields",current_db,11,"0"); + + verify_prepare_field(result,1,"c2","c2",MYSQL_TYPE_STRING, + "test_list_fields","test_list_fields",current_db,10,"mysql"); + mysql_free_result(result); } @@ -7188,6 +7184,149 @@ static void test_mem_overun() mysql_stmt_close(stmt); } + +/* + To test mysql_stmt_free_result() +*/ +static void test_free_result() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind[1]; + char c2[5]; + ulong length; + int rc, c1; + + myheader("test_free_result"); + + rc= mysql_query(mysql,"drop table if exists test_free_result"); + myquery(rc); + + rc = mysql_query(mysql, "create table test_free_result(c1 int primary key auto_increment)"); + myquery(rc); + + rc = mysql_query(mysql, "insert into test_free_result values(),(),()"); + myquery(rc); + + stmt = mysql_prepare(mysql,"select * from test_free_result",50); + mystmt_init(stmt); + + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (char *)c2; + bind[0].buffer_length= 7; + bind[0].is_null= 0; + bind[0].length= &length; + + rc = mysql_execute(stmt); + mystmt(stmt,rc); + + rc = mysql_fetch(stmt); + mystmt(stmt,rc); + + c2[0]= '\0'; length= 0; + rc = mysql_fetch_column(stmt,bind,0,0); + mystmt(stmt,rc); + fprintf(stdout, "\n col 1: %s(%ld)", c2, length); + myassert(strncmp(c2,"1",1)==0 && length == 1); + + rc = mysql_fetch(stmt); + mystmt(stmt,rc); + + c1= 0, length= 0; + + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (char *)&c1; + bind[0].buffer_length= 0; + bind[0].is_null= 0; + bind[0].length= &length; + + rc = mysql_fetch_column(stmt,bind,0,0); + mystmt(stmt,rc); + fprintf(stdout, "\n col 0: %d(%ld)", c1, length); + myassert(c1 == 2 && length == 4); + + rc = mysql_query(mysql,"drop table test_free_result"); + myquery_r(rc); /* error should be, COMMANDS OUT OF SYNC */ + + rc = mysql_stmt_free_result(stmt); + mystmt(stmt,rc); + + rc = mysql_query(mysql,"drop table test_free_result"); + myquery(rc); /* should be successful */ + + mysql_stmt_close(stmt); +} + +/* + To test mysql_stmt_free_result() +*/ +static void test_free_store_result() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind[1]; + char c2[5]; + ulong length; + int rc, c1; + + myheader("test_free_store_result"); + + rc= mysql_query(mysql,"drop table if exists test_free_result"); + myquery(rc); + + rc = mysql_query(mysql, "create table test_free_result(c1 int primary key auto_increment)"); + myquery(rc); + + rc = mysql_query(mysql, "insert into test_free_result values(),(),()"); + myquery(rc); + + stmt = mysql_prepare(mysql,"select * from test_free_result",50); + mystmt_init(stmt); + + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (char *)c2; + bind[0].buffer_length= 7; + bind[0].is_null= 0; + bind[0].length= &length; + + rc = mysql_execute(stmt); + mystmt(stmt,rc); + + rc = mysql_stmt_store_result(stmt); + mystmt(stmt,rc); + + rc = mysql_fetch(stmt); + mystmt(stmt,rc); + + c2[0]= '\0'; length= 0; + rc = mysql_fetch_column(stmt,bind,0,0); + mystmt(stmt,rc); + fprintf(stdout, "\n col 1: %s(%ld)", c2, length); + myassert(strncmp(c2,"1",1)==0 && length == 1); + + rc = mysql_fetch(stmt); + mystmt(stmt,rc); + + c1= 0, length= 0; + + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (char *)&c1; + bind[0].buffer_length= 0; + bind[0].is_null= 0; + bind[0].length= &length; + + rc = mysql_fetch_column(stmt,bind,0,0); + mystmt(stmt,rc); + fprintf(stdout, "\n col 0: %d(%ld)", c1, length); + myassert(c1 == 2 && length == 4); + + rc = mysql_stmt_free_result(stmt); + mystmt(stmt,rc); + + rc = mysql_query(mysql,"drop table test_free_result"); + myquery(rc); + + mysql_stmt_close(stmt); +} + /* Read and parse arguments and MySQL options from my.cnf */ @@ -7428,6 +7567,11 @@ int main(int argc, char **argv) test_open_direct(); /* direct execution in the middle of open stmts */ test_fetch_offset(); /* to test mysql_fetch_column with offset */ test_fetch_column(); /* to test mysql_fetch_column */ + test_mem_overun(); /* test DBD ovverun bug */ + test_list_fields(); /* test COM_LIST_FIELDS for DEFAULT */ + test_free_result(); /* test mysql_stmt_free_result() */ + test_free_store_result(); /* test to make sure stmt results are cleared + during stmt_free_result() */ end_time= time((time_t *)0); total_time+= difftime(end_time, start_time); -- cgit v1.2.1