diff --git a/CMakeLists.txt b/CMakeLists.txt index a06495021b3..341f8d08df2 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,8 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +CMAKE_MINIMUM_REQUIRED(VERSION 2.4.7 FATAL_ERROR) + PROJECT(MySql) # This reads user configuration, generated by configure.js. diff --git a/include/my_sys.h b/include/my_sys.h index 2ce36760032..7ae05bb96f7 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -691,6 +691,8 @@ extern WF_PACK *wf_comp(char * str); extern int wf_test(struct wild_file_pack *wf_pack,const char *name); extern void wf_end(struct wild_file_pack *buffer); extern size_t strip_sp(char * str); +extern my_bool array_append_string_unique(const char *str, + const char **array, size_t size); extern void get_date(char * to,int timeflag,time_t use_time); extern void soundex(CHARSET_INFO *, char * out_pntr, char * in_pntr, pbool remove_garbage); diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared index 3a2559921f9..02855532e41 100644 --- a/libmysql/Makefile.shared +++ b/libmysql/Makefile.shared @@ -59,7 +59,7 @@ mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \ mf_pack.lo my_messnc.lo mf_dirname.lo mf_fn_ext.lo\ mf_wcomp.lo typelib.lo safemalloc.lo my_alloc.lo \ mf_format.lo mf_path.lo mf_unixpath.lo my_fopen.lo \ - my_symlink.lo my_fstream.lo \ + my_symlink.lo my_fstream.lo mf_arr_appstr.lo \ mf_loadpath.lo my_pthread.lo my_thr_init.lo \ thr_mutex.lo mulalloc.lo string.lo \ default.lo default_modify.lo \ diff --git a/mysql-test/r/innodb-semi-consistent.result b/mysql-test/r/innodb-semi-consistent.result new file mode 100644 index 00000000000..ad7b70d0497 --- /dev/null +++ b/mysql-test/r/innodb-semi-consistent.result @@ -0,0 +1,36 @@ +set session transaction isolation level read committed; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +insert into t1 values (1),(2),(3),(4),(5),(6),(7); +set autocommit=0; +select * from t1 where a=3 lock in share mode; +a +3 +set session transaction isolation level read committed; +set autocommit=0; +update t1 set a=10 where a=5; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +commit; +update t1 set a=10 where a=5; +select * from t1 where a=2 for update; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +select * from t1 where a=2 limit 1 for update; +a +2 +update t1 set a=11 where a=6; +update t1 set a=12 where a=2; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +update t1 set a=13 where a=1; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +commit; +update t1 set a=14 where a=1; +commit; +select * from t1; +a +14 +2 +3 +4 +10 +11 +7 +drop table t1; diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index d0b67e90afb..051a9e1dc0b 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -472,43 +472,6 @@ a b 3 3 drop table t1,t2; CREATE TABLE t1 ( -id int(11) NOT NULL auto_increment, -ggid varchar(32) binary DEFAULT '' NOT NULL, -email varchar(64) DEFAULT '' NOT NULL, -passwd varchar(32) binary DEFAULT '' NOT NULL, -PRIMARY KEY (id), -UNIQUE ggid (ggid) -) ENGINE=innodb; -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'); -ERROR 23000: Duplicate entry 'test2' for key 'ggid' -insert into t1 (ggid,id) values ('this will fail',1); -ERROR 23000: Duplicate entry '1' for key 'PRIMARY' -select * from t1 where ggid='test1'; -id ggid email passwd -1 test1 xxx -select * from t1 where passwd='xxx'; -id ggid email passwd -1 test1 xxx -select * from t1 where id=2; -id ggid email passwd -2 test2 yyy -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; -ERROR 23000: Duplicate entry 'test2' for key 'ggid' -select * from t1; -id ggid email passwd -1 this will work -4 test2 this will work -select * from t1 where id=1; -id ggid email passwd -1 this will work -select * from t1 where id=999; -id ggid email passwd -drop table t1; -CREATE TABLE t1 ( user_name varchar(12), password text, subscribed char(1), @@ -1751,13 +1714,13 @@ Variable_name Value Innodb_page_size 16384 show status like "Innodb_rows_deleted"; Variable_name Value -Innodb_rows_deleted 70 +Innodb_rows_deleted 69 show status like "Innodb_rows_inserted"; Variable_name Value -Innodb_rows_inserted 1083 +Innodb_rows_inserted 1080 show status like "Innodb_rows_updated"; Variable_name Value -Innodb_rows_updated 886 +Innodb_rows_updated 885 show status like "Innodb_row_lock_waits"; Variable_name Value Innodb_row_lock_waits 0 @@ -3189,3 +3152,52 @@ c25 CHAR(255), c26 CHAR(255), c27 CHAR(255), c28 CHAR(255), c29 CHAR(255), c30 CHAR(255), c31 CHAR(255), c32 CHAR(255) ) ENGINE = InnoDB; ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs +DROP TABLE IF EXISTS t1; +Warnings: +Note 1051 Unknown table 't1' +CREATE TABLE t1( +id BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY +) ENGINE=InnoDB; +INSERT INTO t1 VALUES(-10); +SELECT * FROM t1; +id +-10 +INSERT INTO t1 VALUES(NULL); +SELECT * FROM t1; +id +-10 +1 +DROP TABLE t1; +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +DROP TABLE IF EXISTS t1, t2; +Warnings: +Note 1051 Unknown table 't1' +Note 1051 Unknown table 't2' +CREATE TABLE t1 ( a int ) ENGINE=InnoDB; +CREATE TABLE t2 LIKE t1; +SELECT * FROM t2; +a +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +INSERT INTO t1 VALUES (1); +COMMIT; +SELECT * FROM t1 WHERE a=1; +a +1 +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +SELECT * FROM t2; +a +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +INSERT INTO t1 VALUES (2); +COMMIT; +SELECT * FROM t1 WHERE a=2; +a +2 +SELECT * FROM t1 WHERE a=2; +a +2 +DROP TABLE t1; +DROP TABLE t2; diff --git a/mysql-test/r/innodb_autoinc_lock_mode_zero.result b/mysql-test/r/innodb_autoinc_lock_mode_zero.result new file mode 100644 index 00000000000..3d016684338 --- /dev/null +++ b/mysql-test/r/innodb_autoinc_lock_mode_zero.result @@ -0,0 +1,39 @@ +drop table if exists t1; +CREATE TABLE t1 ( +id int(11) NOT NULL auto_increment, +ggid varchar(32) binary DEFAULT '' NOT NULL, +email varchar(64) DEFAULT '' NOT NULL, +passwd varchar(32) binary DEFAULT '' NOT NULL, +PRIMARY KEY (id), +UNIQUE ggid (ggid) +) ENGINE=innodb; +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'); +ERROR 23000: Duplicate entry 'test2' for key 'ggid' +insert into t1 (ggid,id) values ('this will fail',1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +select * from t1 where ggid='test1'; +id ggid email passwd +1 test1 xxx +select * from t1 where passwd='xxx'; +id ggid email passwd +1 test1 xxx +select * from t1 where id=2; +id ggid email passwd +2 test2 yyy +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; +ERROR 23000: Duplicate entry 'test2' for key 'ggid' +select * from t1; +id ggid email passwd +1 this will work +3 test2 this will work +select * from t1 where id=1; +id ggid email passwd +1 this will work +select * from t1 where id=999; +id ggid email passwd +drop table t1; +End of tests diff --git a/mysql-test/t/innodb-semi-consistent-master.opt b/mysql-test/t/innodb-semi-consistent-master.opt new file mode 100644 index 00000000000..2746e4e184e --- /dev/null +++ b/mysql-test/t/innodb-semi-consistent-master.opt @@ -0,0 +1 @@ +--innodb_locks_unsafe_for_binlog=true --innodb_lock_wait_timeout=2 diff --git a/mysql-test/t/innodb-semi-consistent.test b/mysql-test/t/innodb-semi-consistent.test new file mode 100644 index 00000000000..7a9231b508f --- /dev/null +++ b/mysql-test/t/innodb-semi-consistent.test @@ -0,0 +1,46 @@ +-- source include/not_embedded.inc +-- source include/have_innodb.inc + +# basic tests of semi-consistent reads + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +set session transaction isolation level read committed; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +insert into t1 values (1),(2),(3),(4),(5),(6),(7); +set autocommit=0; +# this should lock the entire table +select * from t1 where a=3 lock in share mode; +connection b; +set session transaction isolation level read committed; +set autocommit=0; +-- error ER_LOCK_WAIT_TIMEOUT +update t1 set a=10 where a=5; +connection a; +commit; +connection b; +update t1 set a=10 where a=5; +connection a; +-- error ER_LOCK_WAIT_TIMEOUT +select * from t1 where a=2 for update; +# this should lock the records (1),(2) +select * from t1 where a=2 limit 1 for update; +connection b; +update t1 set a=11 where a=6; +-- error ER_LOCK_WAIT_TIMEOUT +update t1 set a=12 where a=2; +-- error ER_LOCK_WAIT_TIMEOUT +update t1 set a=13 where a=1; +connection a; +commit; +connection b; +update t1 set a=14 where a=1; +commit; +connection a; +select * from t1; +drop table t1; + +connection default; +disconnect a; +disconnect b; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index cc1ef6f9730..f68bb87655e 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -326,39 +326,6 @@ select * from t1; select * from t2; drop table t1,t2; -# -# Search on unique key -# - -CREATE TABLE t1 ( - id int(11) NOT NULL auto_increment, - ggid varchar(32) binary DEFAULT '' NOT NULL, - email varchar(64) DEFAULT '' NOT NULL, - passwd varchar(32) binary DEFAULT '' NOT NULL, - PRIMARY KEY (id), - UNIQUE ggid (ggid) -) ENGINE=innodb; - -insert into t1 (ggid,passwd) values ('test1','xxx'); -insert into t1 (ggid,passwd) values ('test2','yyy'); --- error ER_DUP_ENTRY -insert into t1 (ggid,passwd) values ('test2','this will fail'); --- error ER_DUP_ENTRY -insert into t1 (ggid,id) values ('this will fail',1); - -select * from t1 where ggid='test1'; -select * from t1 where passwd='xxx'; -select * from t1 where id=2; - -replace into t1 (ggid,id) values ('this will work',1); -replace into t1 (ggid,passwd) values ('test2','this will work'); --- error ER_DUP_ENTRY -update t1 set id=100,ggid='test2' where id=1; -select * from t1; -select * from t1 where id=1; -select * from t1 where id=999; -drop table t1; - # # ORDER BY on not primary key # @@ -2323,6 +2290,67 @@ CREATE TABLE t1 ( c29 CHAR(255), c30 CHAR(255), c31 CHAR(255), c32 CHAR(255) ) ENGINE = InnoDB; +# +# Bug #31860 InnoDB assumes AUTOINC values can only be positive. +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1( + id BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY + ) ENGINE=InnoDB; +INSERT INTO t1 VALUES(-10); +SELECT * FROM t1; +# +# NOTE: The server really needs to be restarted at this point +# for the test to be useful. +# +# Without the fix InnoDB would trip over an assertion here. +INSERT INTO t1 VALUES(NULL); +# The next value should be 1 and not -9 or a -ve number +SELECT * FROM t1; +DROP TABLE t1; + +# +# Bug #21409 Incorrect result returned when in READ-COMMITTED with +# query_cache ON +# +CONNECT (c1,localhost,root,,); +CONNECT (c2,localhost,root,,); +CONNECTION c1; +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +DROP TABLE IF EXISTS t1, t2; +CREATE TABLE t1 ( a int ) ENGINE=InnoDB; +CREATE TABLE t2 LIKE t1; +SELECT * FROM t2; +CONNECTION c2; +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +INSERT INTO t1 VALUES (1); +COMMIT; +CONNECTION c1; +SELECT * FROM t1 WHERE a=1; +DISCONNECT c1; +DISCONNECT c2; +CONNECT (c1,localhost,root,,); +CONNECT (c2,localhost,root,,); +CONNECTION c1; +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +SELECT * FROM t2; +CONNECTION c2; +SET TX_ISOLATION='read-committed'; +SET AUTOCOMMIT=0; +INSERT INTO t1 VALUES (2); +COMMIT; +CONNECTION c1; +# The result set below should be the same for both selects +SELECT * FROM t1 WHERE a=2; +SELECT * FROM t1 WHERE a=2; +DROP TABLE t1; +DROP TABLE t2; +DISCONNECT c1; +DISCONNECT c2; + ####################################################################### # # # Please, DO NOT TOUCH this file as well as the innodb.result file. # diff --git a/mysql-test/t/innodb_autoinc_lock_mode_zero-master.opt b/mysql-test/t/innodb_autoinc_lock_mode_zero-master.opt new file mode 100644 index 00000000000..fad0da2ac2e --- /dev/null +++ b/mysql-test/t/innodb_autoinc_lock_mode_zero-master.opt @@ -0,0 +1 @@ +--innodb-autoinc-lock-mode=0 diff --git a/mysql-test/t/innodb_autoinc_lock_mode_zero.test b/mysql-test/t/innodb_autoinc_lock_mode_zero.test new file mode 100644 index 00000000000..96f748673c0 --- /dev/null +++ b/mysql-test/t/innodb_autoinc_lock_mode_zero.test @@ -0,0 +1,44 @@ +# This test runs with old-style locking, as: +# --innodb-autoinc-lock-mode=0 + +-- source include/have_innodb.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + + +# +# Search on unique key +# + +CREATE TABLE t1 ( + id int(11) NOT NULL auto_increment, + ggid varchar(32) binary DEFAULT '' NOT NULL, + email varchar(64) DEFAULT '' NOT NULL, + passwd varchar(32) binary DEFAULT '' NOT NULL, + PRIMARY KEY (id), + UNIQUE ggid (ggid) +) ENGINE=innodb; + +insert into t1 (ggid,passwd) values ('test1','xxx'); +insert into t1 (ggid,passwd) values ('test2','yyy'); +-- error ER_DUP_ENTRY +insert into t1 (ggid,passwd) values ('test2','this will fail'); +-- error ER_DUP_ENTRY +insert into t1 (ggid,id) values ('this will fail',1); + +select * from t1 where ggid='test1'; +select * from t1 where passwd='xxx'; +select * from t1 where id=2; + +replace into t1 (ggid,id) values ('this will work',1); +replace into t1 (ggid,passwd) values ('test2','this will work'); +-- error ER_DUP_ENTRY +update t1 set id=100,ggid='test2' where id=1; +select * from t1; +select * from t1 where id=1; +select * from t1 where id=999; +drop table t1; + +--echo End of tests diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test index fada7983c2c..747aab21ca6 100644 --- a/mysql-test/t/type_datetime.test +++ b/mysql-test/t/type_datetime.test @@ -155,13 +155,13 @@ set @@sql_mode='ansi,traditional'; insert into t1 values ('2007-03-23 13:49:38','2007-03-23 13:49:38'); insert into t1 set dt='2007-03-23 13:49:38',da=dt; # Test error handling ---error 1292 +--error ER_TRUNCATED_WRONG_VALUE insert into t1 values ('2007-03-32','2007-03-23 13:49:38'); select * from t1; drop table t1; ---error 1067 +--error ER_INVALID_DEFAULT create table t1 (da date default '1962-03-32 23:33:34', dt datetime default '1962-03-03'); ---error 1067 +--error ER_INVALID_DEFAULT create table t1 (t time default '916:00:00 a'); set @@sql_mode= @org_mode; @@ -169,6 +169,19 @@ set @@sql_mode= @org_mode; # # Bug#27590: Wrong DATE/DATETIME comparison. # +## The following sub test will fail (difference to expected result) if the +## select curdate() < now(), f1 < now(), cast(f1 as date) < now() from t1; +## runs exact at midnight ('00:00:00'). +## ( Bug#29290 type_datetime.test failure in 5.1 ) +## Therefore we sleep a bit if we are too close to midnight. +## The complete test itself needs around 1 second. +## Therefore a time_distance to midnight of 5 seconds should be sufficient. +if (`SELECT CURTIME() > SEC_TO_TIME(24 * 3600 - 5)`) +{ + # We are here when CURTIME() is between '23:59:56' and '23:59:59'. + # So a sleep time of 5 seconds brings us between '00:00:01' and '00:00:04'. + --real_sleep 5 +} create table t1 (f1 date, f2 datetime, f3 timestamp); insert into t1(f1) values(curdate()); select curdate() < now(), f1 < now(), cast(f1 as date) < now() from t1; diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index 6b24165686a..60e75c96b75 100755 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -29,7 +29,7 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c default_ errors.c hash.c list.c md5.c mf_brkhant.c mf_cache.c mf_dirname.c mf_fn_ext.c mf_format.c mf_getdate.c mf_iocache.c mf_iocache2.c mf_keycache.c mf_keycaches.c mf_loadpath.c mf_pack.c mf_path.c mf_qsort.c mf_qsort2.c - mf_radix.c mf_same.c mf_sort.c mf_soundex.c mf_strip.c mf_tempdir.c + mf_radix.c mf_same.c mf_sort.c mf_soundex.c mf_strip.c mf_arr_appstr.c mf_tempdir.c mf_tempfile.c mf_unixpath.c mf_wcomp.c mf_wfile.c mulalloc.c my_access.c my_aes.c my_alarm.c my_alloc.c my_append.c my_bit.c my_bitmap.c my_chsize.c my_clock.c my_compress.c my_conio.c my_copy.c my_crc32.c my_create.c my_delete.c diff --git a/mysys/Makefile.am b/mysys/Makefile.am index fca13ab52b8..f06d81da849 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -35,7 +35,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \ my_error.c errors.c my_div.c my_messnc.c \ mf_format.c mf_same.c mf_dirname.c mf_fn_ext.c \ my_symlink.c my_symlink2.c \ - mf_pack.c mf_unixpath.c mf_strip.c \ + mf_pack.c mf_unixpath.c mf_strip.c mf_arr_appstr.c \ mf_wcomp.c mf_wfile.c my_gethwaddr.c \ mf_qsort.c mf_qsort2.c mf_sort.c \ ptr_cmp.c mf_radix.c queues.c my_getncpus.c \ diff --git a/mysys/default.c b/mysys/default.c index 3cc5b08e77c..550bd0c8865 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -47,7 +47,7 @@ char *my_defaults_extra_file=0; /* Which directories are searched for options (and in which order) */ -#define MAX_DEFAULT_DIRS 7 +#define MAX_DEFAULT_DIRS 6 const char *default_directories[MAX_DEFAULT_DIRS + 1]; #ifdef __WIN__ @@ -83,7 +83,22 @@ static int search_default_file_with_ext(Process_option_func func, void *func_ctx, const char *dir, const char *ext, const char *config_file, int recursion_level); -static void init_default_directories(); + + + +/** + Create the list of default directories. + + @details + On all systems, if a directory is already in the list, it will be moved + to the end of the list. This avoids reading defaults files multiple times, + while ensuring the correct precedence. + + @return void +*/ + +static void (*init_default_directories)(); + static char *remove_end_comment(char *ptr); @@ -922,6 +937,25 @@ void print_defaults(const char *conf_file, const char **groups) #include +#define ADD_DIRECTORY(DIR) \ + do { \ + my_bool rc= \ + array_append_string_unique((DIR), default_directories, \ + array_elements(default_directories)); \ + DBUG_ASSERT(rc == FALSE); /* Success */ \ + } while (0) + + +#define ADD_COMMON_DIRECTORIES() \ + do { \ + char *env; \ + if ((env= getenv(STRINGIFY_ARG(DEFAULT_HOME_ENV)))) \ + ADD_DIRECTORY(env); \ + /* Placeholder for --defaults-extra-file= */ \ + ADD_DIRECTORY(""); \ + } while (0) + + #ifdef __WIN__ /* This wrapper for GetSystemWindowsDirectory() will dynamically bind to the @@ -956,71 +990,33 @@ static size_t my_get_system_windows_directory(char *buffer, size_t size) } return count; } -#endif -/* - Create the list of default directories. +/** + Initialize default directories for Microsoft Windows - On Microsoft Windows, this is: - 1. C:/ + @details + 1. GetSystemWindowsDirectory() 2. GetWindowsDirectory() - 3. GetSystemWindowsDirectory() - 4. getenv(DEFAULT_HOME_ENV) - 5. Directory above where the executable is located - 6. "" - 7. --sysconfdir= + 3. C:/ + 4. Directory above where the executable is located + 5. getenv(DEFAULT_HOME_ENV) + 6. --defaults-extra-file= (run-time option) +*/ - On Novell NetWare, this is: - 1. sys:/etc/ - 2. getenv(DEFAULT_HOME_ENV) - 3. "" - 4. --sysconfdir= - - On OS/2, this is: - 1. getenv(ETC) - 2. /etc/ - 3. getenv(DEFAULT_HOME_ENV) - 4. "" - 5. "~/" - 6. --sysconfdir= - - Everywhere else, this is: - 1. /etc/ - 2. /etc/mysql/ - 3. getenv(DEFAULT_HOME_ENV) - 4. "" - 5. "~/" - 6. --sysconfdir= - - */ - -static void init_default_directories() +static void init_default_directories_win() { - const char *env, **ptr= default_directories; + bzero(default_directories, sizeof(default_directories)); -#ifdef __WIN__ - *ptr++= "C:/"; + if (my_get_system_windows_directory(shared_system_dir, + sizeof(shared_system_dir))) + ADD_DIRECTORY(&shared_system_dir); if (GetWindowsDirectory(system_dir,sizeof(system_dir))) - *ptr++= (char*)&system_dir; - if (my_get_system_windows_directory(shared_system_dir, - sizeof(shared_system_dir)) && - strcmp(system_dir, shared_system_dir)) - *ptr++= (char *)&shared_system_dir; + ADD_DIRECTORY(&system_dir); + + ADD_DIRECTORY("C:/"); -#elif defined(__NETWARE__) - *ptr++= "sys:/etc/"; -#else - *ptr++= "/etc/"; - *ptr++= "/etc/mysql/"; -#endif - if ((env= getenv(STRINGIFY_ARG(DEFAULT_HOME_ENV)))) - *ptr++= env; - *ptr++= ""; /* Place for defaults_extra_file */ -#if !defined(__WIN__) && !defined(__NETWARE__) - *ptr++= "~/";; -#elif defined(__WIN__) if (GetModuleFileName(NULL, config_dir, sizeof(config_dir))) { char *last= NULL, *end= strend(config_dir); @@ -1050,12 +1046,61 @@ static void init_default_directories() last= end; } } - *ptr++= (char *)&config_dir; + ADD_DIRECTORY(&config_dir); } -#endif + + ADD_COMMON_DIRECTORIES(); +} + +static void (*init_default_directories)()= init_default_directories_win; + +#elif defined(__NETWARE__) + +/** + Initialize default directories for Novell Netware + + @details + 1. sys:/etc/ + 2. getenv(DEFAULT_HOME_ENV) + 3. --defaults-extra-file= (run-time option) +*/ + +static void init_default_directories_netware() +{ + bzero(default_directories, sizeof(default_directories)); + ADD_DIRECTORY("sys:/etc/"); + ADD_COMMON_DIRECTORIES(); +} + +static void (*init_default_directories)()= init_default_directories_netware; + +#else + +/** + Initialize default directories for Unix + + @details + 1. /etc/ + 2. /etc/mysql/ + 3. --sysconfdir= (compile-time option) + 4. getenv(DEFAULT_HOME_ENV) + 5. --defaults-extra-file= (run-time option) + 6. "~/" +*/ + +static void init_default_directories_unix() +{ + bzero(default_directories, sizeof(default_directories)); + ADD_DIRECTORY("/etc/"); + ADD_DIRECTORY("/etc/mysql/"); #ifdef DEFAULT_SYSCONFDIR if (DEFAULT_SYSCONFDIR != "") - *ptr++= DEFAULT_SYSCONFDIR; + ADD_DIRECTORY(DEFAULT_SYSCONFDIR); #endif - *ptr= 0; /* end marker */ + ADD_COMMON_DIRECTORIES(); + ADD_DIRECTORY("~/"); } + +static void (*init_default_directories)()= init_default_directories_unix; + +#endif diff --git a/mysys/mf_arr_appstr.c b/mysys/mf_arr_appstr.c new file mode 100644 index 00000000000..1edbea9df4a --- /dev/null +++ b/mysys/mf_arr_appstr.c @@ -0,0 +1,61 @@ +/* Copyright (C) 2007 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; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "mysys_priv.h" +#include /* strcmp() */ + + +/** + Append str to array, or move to the end if it already exists + + @param str String to be appended + @param array The array, terminated by a NULL element, all unused elements + pre-initialized to NULL + @param size Size of the array; array must be terminated by a NULL + pointer, so can hold size - 1 elements + + @retval FALSE Success + @retval TRUE Failure, array is full +*/ + +my_bool array_append_string_unique(const char *str, + const char **array, size_t size) +{ + const char **p; + /* end points at the terminating NULL element */ + const char **end= array + size - 1; + DBUG_ASSERT(*end == NULL); + + for (p= array; *p; ++p) + { + if (strcmp(*p, str) == 0) + break; + } + if (p >= end) + return TRUE; /* Array is full */ + + DBUG_ASSERT(*p == NULL || strcmp(*p, str) == 0); + + while (*(p + 1)) + { + *p= *(p + 1); + ++p; + } + + DBUG_ASSERT(p < end); + *p= str; + + return FALSE; /* Success */ +} diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 299f4ae4285..77f8bb9e5b2 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -90,13 +90,6 @@ TARGET_LINK_LIBRARIES(mysqld SET_TARGET_PROPERTIES(mysqld PROPERTIES OUTPUT_NAME mysqld${MYSQLD_EXE_SUFFIX}) -# Work around for 2.4.6 bug, OUTPUT_NAME will not set the right .PDB -# file name. Note that COMPILE_FLAGS set some temporary pdb during build, -# LINK_FLAGS sets the real one. -SET_TARGET_PROPERTIES(mysqld PROPERTIES - COMPILE_FLAGS "/Fd${CMAKE_CFG_INTDIR}/mysqld${MYSQLD_EXE_SUFFIX}.pdb" - LINK_FLAGS "/PDB:${CMAKE_CFG_INTDIR}/mysqld${MYSQLD_EXE_SUFFIX}.pdb") - IF(EMBED_MANIFESTS) MYSQL_EMBED_MANIFEST("mysqld" "asInvoker") ENDIF(EMBED_MANIFESTS) diff --git a/storage/innobase/buf/buf0lru.c b/storage/innobase/buf/buf0lru.c index 7b49a7641af..f3913ed49b7 100644 --- a/storage/innobase/buf/buf0lru.c +++ b/storage/innobase/buf/buf0lru.c @@ -881,7 +881,7 @@ buf_LRU_block_free_non_file_page( UT_LIST_ADD_FIRST(free, buf_pool->free, block); block->in_free_list = TRUE; - UNIV_MEM_FREE(block->frame, UNIV_PAGE_SIZE); + UNIV_MEM_ASSERT_AND_FREE(block->frame, UNIV_PAGE_SIZE); if (srv_use_awe && block->frame) { /* Add to the list of mapped pages */ diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index 595dfb06ee5..368ff3c2bc2 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -441,6 +441,8 @@ dict_table_autoinc_initialize( dict_table_t* table, /* in: table */ ib_longlong value) /* in: next value to assign to a row */ { + ut_ad(mutex_own(&table->autoinc_mutex)); + table->autoinc_inited = TRUE; table->autoinc = value; } @@ -457,6 +459,8 @@ dict_table_autoinc_read( { ib_longlong value; + ut_ad(mutex_own(&table->autoinc_mutex)); + if (!table->autoinc_inited) { value = 0; diff --git a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c index 1ff1fd54cec..f594e64f517 100644 --- a/storage/innobase/dict/dict0load.c +++ b/storage/innobase/dict/dict0load.c @@ -551,11 +551,13 @@ dict_load_fields( Loads definitions for table indexes. Adds them to the data dictionary cache. */ static -ibool +ulint dict_load_indexes( /*==============*/ - /* out: TRUE if ok, FALSE if corruption - of dictionary table */ + /* out: DB_SUCCESS if ok, DB_CORRUPTION + if corruption of dictionary table or + DB_UNSUPPORTED if table has unknown index + type */ dict_table_t* table, /* in: table */ mem_heap_t* heap) /* in: memory heap for temporary storage */ { @@ -578,6 +580,7 @@ dict_load_indexes( ibool is_sys_table; dulint id; mtr_t mtr; + ulint error = DB_SUCCESS; ut_ad(mutex_own(&(dict_sys->mutex))); @@ -624,10 +627,8 @@ dict_load_indexes( dict_load_report_deleted_index(table->name, ULINT_UNDEFINED); - btr_pcur_close(&pcur); - mtr_commit(&mtr); - - return(FALSE); + error = DB_CORRUPTION; + goto func_exit; } field = rec_get_nth_field_old(rec, 1, &len); @@ -653,7 +654,18 @@ dict_load_indexes( field = rec_get_nth_field_old(rec, 8, &len); page_no = mach_read_from_4(field); - if (page_no == FIL_NULL) { + /* We check for unsupported types first, so that the + subsequent checks are relevant for the supported types. */ + if (type & ~(DICT_CLUSTERED | DICT_UNIQUE)) { + + fprintf(stderr, + "InnoDB: Error: unknown type %lu" + " of index %s of table %s\n", + (ulong) type, name_buf, table->name); + + error = DB_UNSUPPORTED; + goto func_exit; + } else if (page_no == FIL_NULL) { fprintf(stderr, "InnoDB: Error: trying to load index %s" @@ -661,14 +673,10 @@ dict_load_indexes( "InnoDB: but the index tree has been freed!\n", name_buf, table->name); - btr_pcur_close(&pcur); - mtr_commit(&mtr); - - return(FALSE); - } - - if ((type & DICT_CLUSTERED) == 0 - && NULL == dict_table_get_first_index(table)) { + error = DB_CORRUPTION; + goto func_exit; + } else if ((type & DICT_CLUSTERED) == 0 + && NULL == dict_table_get_first_index(table)) { fprintf(stderr, "InnoDB: Error: trying to load index %s" @@ -677,18 +685,14 @@ dict_load_indexes( " is not clustered!\n", name_buf, table->name); - btr_pcur_close(&pcur); - mtr_commit(&mtr); - - return(FALSE); - } - - if (is_sys_table - && ((type & DICT_CLUSTERED) - || ((table == dict_sys->sys_tables) - && (name_len == (sizeof "ID_IND") - 1) - && (0 == ut_memcmp(name_buf, "ID_IND", - name_len))))) { + error = DB_CORRUPTION; + goto func_exit; + } else if (is_sys_table + && ((type & DICT_CLUSTERED) + || ((table == dict_sys->sys_tables) + && (name_len == (sizeof "ID_IND") - 1) + && (0 == ut_memcmp(name_buf, + "ID_IND", name_len))))) { /* The index was created in memory already at booting of the database server */ @@ -704,10 +708,11 @@ dict_load_indexes( btr_pcur_move_to_next_user_rec(&pcur, &mtr); } +func_exit: btr_pcur_close(&pcur); mtr_commit(&mtr); - return(TRUE); + return(error); } /************************************************************************ @@ -857,11 +862,20 @@ err_exit: mem_heap_empty(heap); - dict_load_indexes(table, heap); + err = dict_load_indexes(table, heap); - err = dict_load_foreigns(table->name, TRUE); + /* If the force recovery flag is set, we open the table irrespective + of the error condition, since the user may want to dump data from the + clustered index. However we load the foreign key information only if + all indexes were loaded. */ + if (err != DB_SUCCESS && !srv_force_recovery) { + dict_mem_table_free(table); + table = NULL; + } else if (err == DB_SUCCESS) { + err = dict_load_foreigns(table->name, TRUE); + } #if 0 - if (err != DB_SUCCESS) { + if (err != DB_SUCCESS && table != NULL) { mutex_enter(&dict_foreign_err_mutex); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 783553f5d87..f075fe6c3b4 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -129,6 +129,7 @@ static my_bool innobase_locks_unsafe_for_binlog = FALSE; static my_bool innobase_rollback_on_timeout = FALSE; static my_bool innobase_create_status_file = FALSE; static my_bool innobase_stats_on_metadata = TRUE; +static my_bool innobase_use_adaptive_hash_indexes = TRUE; static char* internal_innobase_data_file_path = NULL; @@ -1143,7 +1144,6 @@ innobase_query_caching_of_table_permitted( } if (trx->has_search_latch) { - ut_print_timestamp(stderr); sql_print_error("The calling thread is holding the adaptive " "search, latch though calling " "innobase_query_caching_of_table_permitted."); @@ -1246,8 +1246,7 @@ innobase_invalidate_query_cache( } /********************************************************************* -Display an SQL identifier. -This definition must match the one in innobase/ut/ut0ut.c! */ +Display an SQL identifier. */ extern "C" void innobase_print_identifier( @@ -1635,6 +1634,9 @@ innobase_init( srv_stats_on_metadata = (ibool) innobase_stats_on_metadata; + srv_use_adaptive_hash_indexes = + (ibool) innobase_use_adaptive_hash_indexes; + srv_print_verbose_log = mysqld_embedded ? 0 : 1; /* Store the default charset-collation number of this MySQL @@ -2319,14 +2321,18 @@ ha_innobase::open( ib_table = dict_table_get(norm_name, TRUE); if (NULL == ib_table) { - ut_print_timestamp(stderr); - sql_print_error("Cannot find table %s from the internal data " - "dictionary\nof InnoDB though the .frm file " - "for the table exists. Maybe you\nhave " - "deleted and recreated InnoDB data files but " - "have forgotten\nto delete the corresponding " - ".frm files of InnoDB tables, or you\n" - "have moved .frm files to another database?\n" + sql_print_error("Cannot find or open table %s from\n" + "the internal data dictionary of InnoDB " + "though the .frm file for the\n" + "table exists. Maybe you have deleted and " + "recreated InnoDB data\n" + "files but have forgotten to delete the " + "corresponding .frm files\n" + "of InnoDB tables, or you have moved .frm " + "files to another database?\n" + "or, the table contains indexes that this " + "version of the engine\n" + "doesn't support.\n" "See http://dev.mysql.com/doc/refman/5.1/en/innodb-troubleshooting.html\n" "how you can resolve the problem.\n", norm_name); @@ -2338,7 +2344,6 @@ ha_innobase::open( } if (ib_table->ibd_file_missing && !thd_tablespace_op(thd)) { - ut_print_timestamp(stderr); sql_print_error("MySQL is trying to open a table handle but " "the .ibd file for\ntable %s does not exist.\n" "Have you deleted the .ibd file from the " @@ -3412,7 +3417,7 @@ no_commit: /* ut_print_timestamp(stderr); fprintf(stderr, - " InnoDB error: ALTER TABLE is holding lock" + " InnoDB: ALTER TABLE is holding lock" " on %lu tables!\n", prebuilt->trx->mysql_n_tables_locked); */ @@ -3476,6 +3481,7 @@ no_commit: /* Handle duplicate key errors */ if (auto_inc_used) { + ulint err; ulonglong auto_inc; /* Note the number of rows processed for this statement, used @@ -3529,7 +3535,11 @@ set_max_autoinc: ut_a(prebuilt->table->autoinc_increment > 0); auto_inc += prebuilt->table->autoinc_increment; - innobase_set_max_autoinc(auto_inc); + err = innobase_set_max_autoinc(auto_inc); + + if (err != DB_SUCCESS) { + error = (int) err; + } } break; } @@ -3765,7 +3775,7 @@ ha_innobase::update_row( if (auto_inc != 0) { auto_inc += prebuilt->table->autoinc_increment; - innobase_set_max_autoinc(auto_inc); + error = innobase_set_max_autoinc(auto_inc); } } @@ -5710,7 +5720,6 @@ ha_innobase::info( for (i = 0; i < table->s->keys; i++) { if (index == NULL) { - ut_print_timestamp(stderr); sql_print_error("Table %s contains fewer " "indexes inside InnoDB than " "are defined in the MySQL " @@ -5726,7 +5735,6 @@ ha_innobase::info( for (j = 0; j < table->key_info[i].key_parts; j++) { if (j + 1 > index->n_uniq) { - ut_print_timestamp(stderr); sql_print_error( "Index %s of %s has %lu columns unique inside InnoDB, but MySQL is asking " "statistics for %lu columns. Have you mixed up .frm files from different " @@ -5791,7 +5799,6 @@ ha_innobase::info( ret = innobase_read_and_init_auto_inc(&auto_inc); if (ret != 0) { - ut_print_timestamp(stderr); sql_print_error("Cannot get table %s auto-inc" "counter value in ::info\n", ib_table->name); @@ -6304,6 +6311,9 @@ ha_innobase::start_stmt( innobase_release_stat_resources(trx); + /* Reset the AUTOINC statement level counter for multi-row INSERTs. */ + trx->n_autoinc_rows = 0; + prebuilt->sql_stat_start = TRUE; prebuilt->hint_need_to_fetch_extra_cols = 0; reset_template(prebuilt); @@ -6446,9 +6456,6 @@ ha_innobase::external_lock( innobase_register_stmt(ht, thd); } - trx->n_mysql_tables_in_use++; - prebuilt->mysql_has_locked = TRUE; - if (trx->isolation_level == TRX_ISO_SERIALIZABLE && prebuilt->select_lock_type == LOCK_NONE && thd_test_options(thd, @@ -6497,6 +6504,9 @@ ha_innobase::external_lock( trx->mysql_n_tables_locked++; } + trx->n_mysql_tables_in_use++; + prebuilt->mysql_has_locked = TRUE; + DBUG_RETURN(0); } @@ -6562,14 +6572,17 @@ ha_innobase::transactional_table_lock( if (prebuilt->table->ibd_file_missing && !thd_tablespace_op(thd)) { ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB error:\n" -"MySQL is trying to use a table handle but the .ibd file for\n" -"table %s does not exist.\n" -"Have you deleted the .ibd file from the database directory under\n" -"the MySQL datadir?" -"See http://dev.mysql.com/doc/refman/5.1/en/innodb-troubleshooting.html\n" -"how you can resolve the problem.\n", - prebuilt->table->name); + fprintf(stderr, + " InnoDB: MySQL is trying to use a table handle" + " but the .ibd file for\n" + "InnoDB: table %s does not exist.\n" + "InnoDB: Have you deleted the .ibd file" + " from the database directory under\n" + "InnoDB: the MySQL datadir?" + "InnoDB: See" + " http://dev.mysql.com/doc/refman/5.1/en/innodb-troubleshooting.html\n" + "InnoDB: how you can resolve the problem.\n", + prebuilt->table->name); DBUG_RETURN(HA_ERR_CRASHED); } @@ -7120,8 +7133,8 @@ the value of the auto-inc counter. */ int ha_innobase::innobase_read_and_init_auto_inc( /*=========================================*/ - /* out: 0 or error code: - deadlock or lock wait timeout */ + /* out: 0 or generic MySQL + error code */ longlong* value) /* out: the autoinc value */ { longlong auto_inc; @@ -7178,9 +7191,10 @@ ha_innobase::innobase_read_and_init_auto_inc( ++auto_inc; dict_table_autoinc_initialize(innodb_table, auto_inc); } else { - fprintf(stderr, " InnoDB error: Couldn't read the " - "max AUTOINC value from index (%s).\n", - index->name); + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: Error: (%lu) Couldn't read " + "the max AUTOINC value from the index (%s).\n", + error, index->name); mysql_error = 1; } @@ -7217,6 +7231,11 @@ ha_innobase::innobase_get_auto_increment( { ulong error; + *value = 0; + + /* Note: If the table is not initialized when we attempt the + read below. We initialize the table's auto-inc counter and + always do a reread of the AUTOINC value. */ do { error = innobase_autoinc_lock(); @@ -7256,7 +7275,15 @@ ha_innobase::innobase_get_auto_increment( } else { *value = (ulonglong) autoinc; } + /* A deadlock error during normal processing is OK + and can be ignored. */ + } else if (error != DB_DEADLOCK) { + + sql_print_error("InnoDB: Error: %lu in " + "::innobase_get_auto_increment()", + error); } + } while (*value == 0 && error == DB_SUCCESS); return(error); @@ -7272,7 +7299,7 @@ we have a table-level lock). offset, increment, nb_desired_values are ignored. void ha_innobase::get_auto_increment( -/*=================================*/ +/*============================*/ ulonglong offset, /* in: */ ulonglong increment, /* in: table autoinc increment */ ulonglong nb_desired_values, /* in: number of values reqd */ @@ -7289,13 +7316,6 @@ ha_innobase::get_auto_increment( error = innobase_get_auto_increment(&autoinc); if (error != DB_SUCCESS) { - /* This should never happen in the code > ver 5.0.6, - since we call this function only after the counter - has been initialized. */ - - ut_print_timestamp(stderr); - sql_print_error("Error %lu in ::get_auto_increment()", error); - *first_value = (~(ulonglong) 0); return; } @@ -7310,6 +7330,11 @@ ha_innobase::get_auto_increment( trx = prebuilt->trx; + /* Note: We can't rely on *first_value since some MySQL engines, + in particular the partition engine, don't initialize it to 0 when + invoking this method. So we are not sure if it's guaranteed to + be 0 or not. */ + /* Called for the first time ? */ if (trx->n_autoinc_rows == 0) { @@ -7318,16 +7343,16 @@ ha_innobase::get_auto_increment( /* It's possible for nb_desired_values to be 0: e.g., INSERT INTO T1(C) SELECT C FROM T2; */ if (nb_desired_values == 0) { - + trx->n_autoinc_rows = 1; } - + set_if_bigger(*first_value, autoinc); /* Not in the middle of a mult-row INSERT. */ } else if (prebuilt->last_value == 0) { set_if_bigger(*first_value, autoinc); } - + *nb_reserved_values = trx->n_autoinc_rows; /* With old style AUTOINC locking we only update the table's @@ -7359,7 +7384,9 @@ ha_innobase::get_auto_increment( /* See comment in handler.h */ int -ha_innobase::reset_auto_increment(ulonglong value) +ha_innobase::reset_auto_increment( +/*==============================*/ + ulonglong value) /* in: new value for table autoinc */ { DBUG_ENTER("ha_innobase::reset_auto_increment"); @@ -7923,6 +7950,11 @@ static MYSQL_SYSVAR_BOOL(stats_on_metadata, innobase_stats_on_metadata, "Enable statistics gathering for metadata commands such as SHOW TABLE STATUS (on by default)", NULL, NULL, TRUE); +static MYSQL_SYSVAR_BOOL(use_adaptive_hash_indexes, innobase_use_adaptive_hash_indexes, + PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY, + "Enable the InnoDB adaptive hash indexes (enabled by default)", + NULL, NULL, TRUE); + static MYSQL_SYSVAR_LONG(additional_mem_pool_size, innobase_additional_mem_pool_size, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures.", @@ -8051,6 +8083,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(open_files), MYSQL_SYSVAR(rollback_on_timeout), MYSQL_SYSVAR(stats_on_metadata), + MYSQL_SYSVAR(use_adaptive_hash_indexes), MYSQL_SYSVAR(status_file), MYSQL_SYSVAR(support_xa), MYSQL_SYSVAR(sync_spin_loops), diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index fe5ebd57990..773884b6584 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -250,17 +250,3 @@ int thd_binlog_format(const MYSQL_THD thd); */ void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all); } - -/* - don't delete it - it may be re-enabled later - as an optimization for the most common case InnoDB+binlog -*/ -#if 0 -int innobase_report_binlog_offset_and_commit( - THD* thd, - void* trx_handle, - char* log_file_name, - my_off_t end_offset); -int innobase_commit_complete(void* trx_handle); -void innobase_store_binlog_offset_and_flush_log(char *binlog_name,longlong offset); -#endif diff --git a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c index 44972356304..126fd9fdd33 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.c +++ b/storage/innobase/ibuf/ibuf0ibuf.c @@ -2900,7 +2900,7 @@ dump: ut_print_timestamp(stderr); fprintf(stderr, - "InnoDB: Error: Insert buffer insert" + " InnoDB: Error: Insert buffer insert" " fails; page free %lu," " dtuple size %lu\n", (ulong) page_get_max_insert_size( @@ -2925,7 +2925,7 @@ dump: buf_frame_get_page_no(page), IBUF_BITMAP_FREE, mtr); - fprintf(stderr, "Bitmap bits %lu\n", + fprintf(stderr, "InnoDB: Bitmap bits %lu\n", (ulong) old_bits); fputs("InnoDB: Submit a detailed bug report" diff --git a/storage/innobase/include/db0err.h b/storage/innobase/include/db0err.h index 0aa1b87e470..ed7ce151718 100644 --- a/storage/innobase/include/db0err.h +++ b/storage/innobase/include/db0err.h @@ -61,12 +61,14 @@ Created 5/24/1996 Heikki Tuuri activated by the operation would lead to a duplicate key in some table */ - #define DB_TOO_MANY_CONCURRENT_TRXS 47 /* when InnoDB runs out of the preconfigured undo slots, this can only happen when there are too many concurrent transactions */ - +#define DB_UNSUPPORTED 48 /* when InnoDB sees any artefact or + a feature that it can't recoginize or + work with e.g., FT indexes created by + a later version of the engine. */ /* The following are partial failure codes */ #define DB_FAIL 1000 #define DB_OVERFLOW 1001 diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h index 7fb50988941..ef0722321af 100644 --- a/storage/innobase/include/ha_prototypes.h +++ b/storage/innobase/include/ha_prototypes.h @@ -1,6 +1,8 @@ #ifndef HA_INNODB_PROTOTYPES_H #define HA_INNODB_PROTOTYPES_H +#ifndef UNIV_HOTBACKUP + #include "univ.i" /* ulint, uint */ #include "m_ctype.h" /* CHARSET_INFO */ @@ -22,6 +24,19 @@ innobase_convert_string( CHARSET_INFO* from_cs, uint* errors); +/********************************************************************* +Display an SQL identifier. */ + +void +innobase_print_identifier( +/*======================*/ + FILE* f, /* in: output stream */ + trx_t* trx, /* in: transaction */ + ibool table_id,/* in: TRUE=print a table name, + FALSE=print other identifier */ + const char* name, /* in: name to print */ + ulint namelen);/* in: length of name */ + /********************************************************************** Returns true if the thread is the replication thread on the slave server. Used in srv_conc_enter_innodb() to determine if the thread @@ -49,3 +64,4 @@ thd_has_edited_nontrans_tables( void* thd); /* in: thread handle (THD*) */ #endif +#endif diff --git a/storage/innobase/include/mach0data.h b/storage/innobase/include/mach0data.h index 8377114a723..37d862cc678 100644 --- a/storage/innobase/include/mach0data.h +++ b/storage/innobase/include/mach0data.h @@ -327,6 +327,17 @@ mach_write_to_2_little_endian( byte* dest, /* in: where to write */ ulint n); /* in: unsigned long int to write */ +/************************************************************* +Convert integral type from storage byte order (big endian) to +host byte order. */ +UNIV_INLINE +void +mach_read_int_type( +/*===============*/ + byte* dest, /* out: where to write */ + const byte* src, /* in: where to read from */ + ulint len, /* in: length of src */ + ibool unsigned_type); /* in: signed or unsigned flag */ #ifndef UNIV_NONINL #include "mach0data.ic" #endif diff --git a/storage/innobase/include/mach0data.ic b/storage/innobase/include/mach0data.ic index 03ece7529a8..64fb87f56ed 100644 --- a/storage/innobase/include/mach0data.ic +++ b/storage/innobase/include/mach0data.ic @@ -7,6 +7,8 @@ to the machine format. Created 11/28/1995 Heikki Tuuri ***********************************************************************/ +#include "ut0mem.h" + /*********************************************************** The following function is used to store data in one byte. */ UNIV_INLINE @@ -689,3 +691,38 @@ mach_write_to_2_little_endian( *dest = (byte)(n & 0xFFUL); } + +/************************************************************* +Convert integral type from storage byte order (big endian) to +host byte order. */ +UNIV_INLINE +void +mach_read_int_type( +/*===============*/ + byte* dest, /* out: where to write */ + const byte* src, /* in: where to read from */ + ulint len, /* in: length of src */ + ibool unsigned_type) /* in: signed or unsigned flag */ +{ +#ifdef WORDS_BIGENDIAN + memcpy(dest, src, len); + + if (!unsigned_type) { + dest[0] ^= 128; + } +#else + byte* ptr; + + /* Convert integer data from Innobase to a little-endian format, + sign bit restored to normal. */ + + for (ptr = dest + len; ptr != dest; ++src) { + --ptr; + *ptr = *src; + } + + if (!unsigned_type) { + dest[len - 1] ^= 128; + } +#endif +} diff --git a/storage/innobase/include/mem0dbg.h b/storage/innobase/include/mem0dbg.h index 36cd7a89565..2393e4edb54 100644 --- a/storage/innobase/include/mem0dbg.h +++ b/storage/innobase/include/mem0dbg.h @@ -60,6 +60,14 @@ mem_heap_validate_or_print( ulint* n_blocks); /* out: number of blocks in the heap, if a NULL pointer is passed as this argument, it is ignored */ +/****************************************************************** +Validates the contents of a memory heap. */ + +ibool +mem_heap_validate( +/*==============*/ + /* out: TRUE if ok */ + mem_heap_t* heap); /* in: memory heap */ #endif /* UNIV_MEM_DEBUG || UNIV_DEBUG */ #ifdef UNIV_DEBUG /****************************************************************** @@ -71,14 +79,6 @@ mem_heap_check( /* out: TRUE if ok */ mem_heap_t* heap); /* in: memory heap */ #endif /* UNIV_DEBUG */ -/****************************************************************** -Validates the contents of a memory heap. */ - -ibool -mem_heap_validate( -/*==============*/ - /* out: TRUE if ok */ - mem_heap_t* heap); /* in: memory heap */ #ifdef UNIV_MEM_DEBUG /********************************************************************* TRUE if no memory is currently allocated. */ diff --git a/storage/innobase/include/mem0mem.ic b/storage/innobase/include/mem0mem.ic index adae9ad8a33..6227a27f277 100644 --- a/storage/innobase/include/mem0mem.ic +++ b/storage/innobase/include/mem0mem.ic @@ -271,19 +271,16 @@ mem_heap_free_heap_top( ut_ad(mem_block_get_start(block) <= mem_block_get_free(block)); /* In the debug version erase block from top up */ - { - ulint len = (byte*)block + block->len - old_top; - mem_erase_buf(old_top, len); - UNIV_MEM_FREE(old_top, len); - } + mem_erase_buf(old_top, (byte*)block + block->len - old_top); /* Update allocated memory count */ mutex_enter(&mem_hash_mutex); mem_current_allocated_memory -= (total_size - size); mutex_exit(&mem_hash_mutex); #else /* UNIV_MEM_DEBUG */ - UNIV_MEM_FREE(old_top, (byte*)block + block->len - old_top); + UNIV_MEM_ASSERT_W(old_top, (byte*)block + block->len - old_top); #endif /* UNIV_MEM_DEBUG */ + UNIV_MEM_ALLOC(old_top, (byte*)block + block->len - old_top); /* If free == start, we may free the block if it is not the first one */ @@ -363,6 +360,7 @@ mem_heap_free_top( /* Subtract the free field of block */ mem_block_set_free(block, mem_block_get_free(block) - MEM_SPACE_NEEDED(n)); + UNIV_MEM_ASSERT_W((byte*) block + mem_block_get_free(block), n); #ifdef UNIV_MEM_DEBUG ut_ad(mem_block_get_start(block) <= mem_block_get_free(block)); @@ -378,7 +376,11 @@ mem_heap_free_top( == mem_block_get_start(block))) { mem_heap_block_free(heap, block); } else { - UNIV_MEM_FREE((byte*) block + mem_block_get_free(block), n); + /* Avoid a bogus UNIV_MEM_ASSERT_W() warning in a + subsequent invocation of mem_heap_free_top(). + Originally, this was UNIV_MEM_FREE(), to catch writes + to freed memory. */ + UNIV_MEM_ALLOC((byte*) block + mem_block_get_free(block), n); } } diff --git a/storage/innobase/include/rem0rec.ic b/storage/innobase/include/rem0rec.ic index 95aa65fabba..5a4a0a0b5df 100644 --- a/storage/innobase/include/rem0rec.ic +++ b/storage/innobase/include/rem0rec.ic @@ -801,6 +801,7 @@ rec_offs_set_n_alloc( { ut_ad(offsets); ut_ad(n_alloc > 0); + UNIV_MEM_ASSERT_AND_ALLOC(offsets, n_alloc * sizeof *offsets); offsets[0] = n_alloc; } diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index aabb7f5f047..fd7ec8918ee 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -319,9 +319,11 @@ row_mysql_unfreeze_data_dictionary( /*===============================*/ trx_t* trx); /* in: transaction */ /************************************************************************* -Does a table creation operation for MySQL. If the name of the created -table ends to characters INNODB_MONITOR, then this also starts -printing of monitor output by the master thread. */ +Drops a table for MySQL. If the name of the table ends in +one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor", +"innodb_table_monitor", then this will also start the printing of monitor +output by the master thread. If the table name ends in "innodb_mem_validate", +InnoDB will try to invoke mem_validate(). */ int row_create_table_for_mysql( @@ -399,8 +401,9 @@ row_truncate_table_for_mysql( dict_table_t* table, /* in: table handle */ trx_t* trx); /* in: transaction handle */ /************************************************************************* -Drops a table for MySQL. If the name of the dropped table ends to -characters INNODB_MONITOR, then this also stops printing of monitor +Drops a table for MySQL. If the name of the dropped table ends in +one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor", +"innodb_table_monitor", then this will also stop the printing of monitor output by the master thread. */ int diff --git a/storage/innobase/include/sync0rw.h b/storage/innobase/include/sync0rw.h index abf04253141..7d2f63803d0 100644 --- a/storage/innobase/include/sync0rw.h +++ b/storage/innobase/include/sync0rw.h @@ -101,6 +101,7 @@ void rw_lock_free( /*=========*/ rw_lock_t* lock); /* in: rw-lock */ +#ifdef UNIV_DEBUG /********************************************************************** Checks that the rw-lock has been initialized and that there are no simultaneous shared and exclusive locks. */ @@ -109,6 +110,7 @@ ibool rw_lock_validate( /*=============*/ rw_lock_t* lock); +#endif /* UNIV_DEBUG */ /****************************************************************** NOTE! The following macros should be used in rw s-locking, not the corresponding function. */ diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index ba8e6e56219..8163ae16e4e 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -308,11 +308,39 @@ typedef void* os_thread_ret_t; # define UNIV_MEM_INVALID(addr, size) VALGRIND_MAKE_MEM_UNDEFINED(addr, size) # define UNIV_MEM_FREE(addr, size) VALGRIND_MAKE_MEM_NOACCESS(addr, size) # define UNIV_MEM_ALLOC(addr, size) VALGRIND_MAKE_MEM_UNDEFINED(addr, size) +# define UNIV_MEM_ASSERT_RW(addr, size) do { \ + const void* _p = (const void*) (ulint) \ + VALGRIND_CHECK_MEM_IS_DEFINED(addr, size); \ + if (UNIV_LIKELY_NULL(_p)) \ + fprintf(stderr, "%s:%d: %p[%u] undefined at %ld\n", \ + __FILE__, __LINE__, \ + (const void*) (addr), (unsigned) (size), (long) \ + (((const char*) _p) - ((const char*) (addr)))); \ + } while (0) +# define UNIV_MEM_ASSERT_W(addr, size) do { \ + const void* _p = (const void*) (ulint) \ + VALGRIND_CHECK_MEM_IS_ADDRESSABLE(addr, size); \ + if (UNIV_LIKELY_NULL(_p)) \ + fprintf(stderr, "%s:%d: %p[%u] unwritable at %ld\n", \ + __FILE__, __LINE__, \ + (const void*) (addr), (unsigned) (size), (long) \ + (((const char*) _p) - ((const char*) (addr)))); \ + } while (0) #else # define UNIV_MEM_VALID(addr, size) do {} while(0) # define UNIV_MEM_INVALID(addr, size) do {} while(0) # define UNIV_MEM_FREE(addr, size) do {} while(0) # define UNIV_MEM_ALLOC(addr, size) do {} while(0) +# define UNIV_MEM_ASSERT_RW(addr, size) do {} while(0) +# define UNIV_MEM_ASSERT_W(addr, size) do {} while(0) #endif +#define UNIV_MEM_ASSERT_AND_FREE(addr, size) do { \ + UNIV_MEM_ASSERT_W(addr, size); \ + UNIV_MEM_FREE(addr, size); \ +} while (0) +#define UNIV_MEM_ASSERT_AND_ALLOC(addr, size) do { \ + UNIV_MEM_ASSERT_W(addr, size); \ + UNIV_MEM_ALLOC(addr, size); \ +} while (0) #endif diff --git a/storage/innobase/include/ut0ut.h b/storage/innobase/include/ut0ut.h index 825c10d5f11..a60ce73c35a 100644 --- a/storage/innobase/include/ut0ut.h +++ b/storage/innobase/include/ut0ut.h @@ -263,6 +263,24 @@ ut_copy_file( FILE* dest, /* in: output file */ FILE* src); /* in: input file to be appended to output */ +/************************************************************************** +snprintf(). */ + +#ifdef __WIN__ +int +ut_snprintf( + /* out: number of characters that would + have been printed if the size were + unlimited, not including the terminating + '\0'. */ + char* str, /* out: string */ + size_t size, /* in: str size */ + const char* fmt, /* in: format */ + ...); /* in: format values */ +#else +#define ut_snprintf snprintf +#endif /* __WIN__ */ + #ifndef UNIV_NONINL #include "ut0ut.ic" #endif diff --git a/storage/innobase/mem/mem0dbg.c b/storage/innobase/mem/mem0dbg.c index eb77dd01f6d..72452907c3f 100644 --- a/storage/innobase/mem/mem0dbg.c +++ b/storage/innobase/mem/mem0dbg.c @@ -223,6 +223,8 @@ mem_init_buf( { byte* ptr; + UNIV_MEM_ASSERT_W(buf, n); + for (ptr = buf; ptr < buf + n; ptr++) { if (ut_rnd_gen_ibool()) { @@ -231,6 +233,8 @@ mem_init_buf( *ptr = 0xBE; } } + + UNIV_MEM_INVALID(buf, n); } /******************************************************************* @@ -245,6 +249,8 @@ mem_erase_buf( { byte* ptr; + UNIV_MEM_ASSERT_W(buf, n); + for (ptr = buf; ptr < buf + n; ptr++) { if (ut_rnd_gen_ibool()) { *ptr = 0xDE; @@ -252,6 +258,8 @@ mem_erase_buf( *ptr = 0xAD; } } + + UNIV_MEM_FREE(buf, n); } /******************************************************************* @@ -546,9 +554,7 @@ completed: } *error = FALSE; } -#endif /* UNIV_MEM_DEBUG || UNIV_DEBUG */ -#ifdef UNIV_DEBUG /****************************************************************** Prints the contents of a memory heap. */ static @@ -574,20 +580,6 @@ mem_heap_print( ut_a(!error); } -/****************************************************************** -Checks that an object is a memory heap (or a block of it). */ - -ibool -mem_heap_check( -/*===========*/ - /* out: TRUE if ok */ - mem_heap_t* heap) /* in: memory heap */ -{ - ut_a(heap->magic_n == MEM_BLOCK_MAGIC_N); - - return(TRUE); -} - /****************************************************************** Validates the contents of a memory heap. */ @@ -614,6 +606,22 @@ mem_heap_validate( return(TRUE); } +#endif /* UNIV_MEM_DEBUG || UNIV_DEBUG */ + +#ifdef UNIV_DEBUG +/****************************************************************** +Checks that an object is a memory heap (or a block of it). */ + +ibool +mem_heap_check( +/*===========*/ + /* out: TRUE if ok */ + mem_heap_t* heap) /* in: memory heap */ +{ + ut_a(heap->magic_n == MEM_BLOCK_MAGIC_N); + + return(TRUE); +} #endif /* UNIV_DEBUG */ #ifdef UNIV_MEM_DEBUG diff --git a/storage/innobase/mem/mem0mem.c b/storage/innobase/mem/mem0mem.c index d89a3a55d88..f4fd178a39c 100644 --- a/storage/innobase/mem/mem0mem.c +++ b/storage/innobase/mem/mem0mem.c @@ -512,9 +512,9 @@ mem_heap_block_free( of hex 0xDE and 0xAD. */ mem_erase_buf((byte*)block, len); - -#endif - UNIV_MEM_FREE(block, len); +#else /* UNIV_MEM_DEBUG */ + UNIV_MEM_ASSERT_AND_FREE(block, len); +#endif /* UNIV_MEM_DEBUG */ if (init_block) { /* Do not have to free: do nothing */ diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index b8d201e3da2..b3cf20b78b8 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -1728,10 +1728,11 @@ row_mysql_unlock_data_dictionary( } /************************************************************************* -Does a table creation operation for MySQL. If the name of the table -to be created is equal with one of the predefined magic table names, -then this also starts printing the corresponding monitor output by -the master thread. */ +Drops a table for MySQL. If the name of the table ends in +one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor", +"innodb_table_monitor", then this will also start the printing of monitor +output by the master thread. If the table name ends in "innodb_mem_validate", +InnoDB will try to invoke mem_validate(). */ int row_create_table_for_mysql( @@ -1756,13 +1757,11 @@ row_create_table_for_mysql( ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH); if (srv_created_new_raw) { - fputs("InnoDB: A new raw disk partition was initialized or\n" - "InnoDB: innodb_force_recovery is on: we do not allow\n" - "InnoDB: database modifications by the user. Shut down\n" - "InnoDB: mysqld and edit my.cnf so that newraw" - " is replaced\n" - "InnoDB: with raw, and innodb_force_... is removed.\n", - stderr); + fputs("InnoDB: A new raw disk partition was initialized:\n" + "InnoDB: we do not allow database modifications" + " by the user.\n" + "InnoDB: Shut down mysqld and edit my.cnf so that newraw" + " is replaced with raw.\n", stderr); dict_mem_table_free(table); trx_commit_for_mysql(trx); @@ -2703,13 +2702,11 @@ row_truncate_table_for_mysql( ut_ad(table); if (srv_created_new_raw) { - fputs("InnoDB: A new raw disk partition was initialized or\n" - "InnoDB: innodb_force_recovery is on: we do not allow\n" - "InnoDB: database modifications by the user. Shut down\n" - "InnoDB: mysqld and edit my.cnf so that newraw" - " is replaced\n" - "InnoDB: with raw, and innodb_force_... is removed.\n", - stderr); + fputs("InnoDB: A new raw disk partition was initialized:\n" + "InnoDB: we do not allow database modifications" + " by the user.\n" + "InnoDB: Shut down mysqld and edit my.cnf so that newraw" + " is replaced with raw.\n", stderr); return(DB_ERROR); } @@ -2898,7 +2895,9 @@ next_rec: /* MySQL calls ha_innobase::reset_auto_increment() which does the same thing. */ + dict_table_autoinc_lock(table); dict_table_autoinc_initialize(table, 0); + dict_table_autoinc_unlock(table); dict_update_statistics(table); trx_commit_for_mysql(trx); @@ -2916,9 +2915,10 @@ funct_exit: #endif /* !UNIV_HOTBACKUP */ /************************************************************************* -Drops a table for MySQL. If the name of the table to be dropped is equal -with one of the predefined magic table names, then this also stops printing -the corresponding monitor output by the master thread. */ +Drops a table for MySQL. If the name of the dropped table ends in +one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor", +"innodb_table_monitor", then this will also stop the printing of monitor +output by the master thread. */ int row_drop_table_for_mysql( @@ -2934,21 +2934,17 @@ row_drop_table_for_mysql( ulint err; const char* table_name; ulint namelen; - char* dir_path_of_temp_table = NULL; - ibool success; ibool locked_dictionary = FALSE; pars_info_t* info = NULL; ut_a(name != NULL); if (srv_created_new_raw) { - fputs("InnoDB: A new raw disk partition was initialized or\n" - "InnoDB: innodb_force_recovery is on: we do not allow\n" - "InnoDB: database modifications by the user. Shut down\n" - "InnoDB: mysqld and edit my.cnf so that newraw" - " is replaced\n" - "InnoDB: with raw, and innodb_force_... is removed.\n", - stderr); + fputs("InnoDB: A new raw disk partition was initialized:\n" + "InnoDB: we do not allow database modifications" + " by the user.\n" + "InnoDB: Shut down mysqld and edit my.cnf so that newraw" + " is replaced with raw.\n", stderr); return(DB_ERROR); } @@ -3232,14 +3228,20 @@ check_next_foreign: } else { ibool is_path; const char* name_or_path; + mem_heap_t* heap; + heap = mem_heap_create(200); + + /* Clone the name, in case it has been allocated + from table->heap, which will be freed by + dict_table_remove_from_cache(table) below. */ + name = mem_heap_strdup(heap, name); space_id = table->space; if (table->dir_path_of_temp_table != NULL) { - dir_path_of_temp_table = mem_strdup( - table->dir_path_of_temp_table); is_path = TRUE; - name_or_path = dir_path_of_temp_table; + name_or_path = mem_heap_strdup( + heap, table->dir_path_of_temp_table); } else { is_path = FALSE; name_or_path = name; @@ -3272,13 +3274,7 @@ check_next_foreign: "InnoDB: of table "); ut_print_name(stderr, trx, TRUE, name); fprintf(stderr, ".\n"); - - goto funct_exit; - } - - success = fil_delete_tablespace(space_id); - - if (!success) { + } else if (!fil_delete_tablespace(space_id)) { fprintf(stderr, "InnoDB: We removed now the InnoDB" " internal data dictionary entry\n" @@ -3296,6 +3292,8 @@ check_next_foreign: err = DB_ERROR; } } + + mem_heap_free(heap); } funct_exit: @@ -3305,10 +3303,6 @@ funct_exit: row_mysql_unlock_data_dictionary(trx); } - if (dir_path_of_temp_table) { - mem_free(dir_path_of_temp_table); - } - trx->op_info = ""; #ifndef UNIV_HOTBACKUP diff --git a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c index fdf6aa46351..29bded114e0 100644 --- a/storage/innobase/row/row0sel.c +++ b/storage/innobase/row/row0sel.c @@ -531,12 +531,13 @@ row_sel_build_prev_vers( /*====================*/ /* out: DB_SUCCESS or error code */ read_view_t* read_view, /* in: read view */ - plan_t* plan, /* in: plan node for table */ + dict_index_t* index, /* in: plan node for table */ rec_t* rec, /* in: record in a clustered index */ ulint** offsets, /* in/out: offsets returned by rec_get_offsets(rec, plan->index) */ mem_heap_t** offset_heap, /* in/out: memory heap from which the offsets are allocated */ + mem_heap_t** old_vers_heap, /* out: old version heap to use */ rec_t** old_vers, /* out: old version, or NULL if the record does not exist in the view: i.e., it was freshly inserted @@ -545,15 +546,15 @@ row_sel_build_prev_vers( { ulint err; - if (plan->old_vers_heap) { - mem_heap_empty(plan->old_vers_heap); + if (*old_vers_heap) { + mem_heap_empty(*old_vers_heap); } else { - plan->old_vers_heap = mem_heap_create(512); + *old_vers_heap = mem_heap_create(512); } err = row_vers_build_for_consistent_read( - rec, mtr, plan->index, offsets, read_view, offset_heap, - plan->old_vers_heap, old_vers); + rec, mtr, index, offsets, read_view, offset_heap, + *old_vers_heap, old_vers); return(err); } @@ -765,9 +766,11 @@ row_sel_get_clust_rec( if (!lock_clust_rec_cons_read_sees(clust_rec, index, offsets, node->read_view)) { - err = row_sel_build_prev_vers(node->read_view, plan, - clust_rec, &offsets, - &heap, &old_vers, mtr); + err = row_sel_build_prev_vers( + node->read_view, index, clust_rec, + &offsets, &heap, &plan->old_vers_heap, + &old_vers, mtr); + if (err != DB_SUCCESS) { goto err_exit; @@ -1490,10 +1493,11 @@ skip_lock: if (!lock_clust_rec_cons_read_sees(rec, index, offsets, node->read_view)) { - err = row_sel_build_prev_vers(node->read_view, - plan, rec, - &offsets, &heap, - &old_vers, &mtr); + err = row_sel_build_prev_vers( + node->read_view, index, rec, + &offsets, &heap, &plan->old_vers_heap, + &old_vers, &mtr); + if (err != DB_SUCCESS) { goto lock_wait_or_error; @@ -3999,6 +4003,7 @@ no_gap_lock: mutex_enter(&kernel_mutex); if (trx->was_chosen_as_deadlock_victim) { mutex_exit(&kernel_mutex); + err = DB_DEADLOCK; goto lock_wait_or_error; } @@ -4521,7 +4526,8 @@ row_search_check_if_query_cache_permitted( } /*********************************************************************** -Read the AUTOINC column from the current row. */ +Read the AUTOINC column from the current row. If the value is less than +0 and the type is not unsigned then we reset the value to 0. */ static ib_longlong row_search_autoinc_read_column( @@ -4536,6 +4542,7 @@ row_search_autoinc_read_column( const byte* data; ib_longlong value; mem_heap_t* heap = NULL; + /* Our requirement is that dest should be word aligned. */ byte dest[sizeof(value)]; ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint* offsets = offsets_; @@ -4554,26 +4561,43 @@ row_search_autoinc_read_column( ut_a(len != UNIV_SQL_NULL); ut_a(len <= sizeof value); - /* Copy integer data and restore sign bit */ - if (unsigned_type || (data[0] & 128)) - memset(dest, 0x00, sizeof(dest)); - else - memset(dest, 0xff, sizeof(dest)); + mach_read_int_type(dest, data, len, unsigned_type); - memcpy(dest + (sizeof(value) - len), data, len); + /* The assumption here is that the AUTOINC value can't be negative + and that dest is word aligned. */ + switch (len) { + case 8: + value = *(ib_longlong*) dest; + break; - if (!unsigned_type) - dest[sizeof(value) - len] ^= 128; + case 4: + value = *(ib_uint32_t*) dest; + break; - /* The assumption here is that the AUTOINC value can't be negative.*/ - value = (((ib_longlong) mach_read_from_4(dest)) << 32) | - ((ib_longlong) mach_read_from_4(dest + 4)); + case 3: + value = *(ib_uint32_t*) dest; + value &= 0xFFFFFF; + break; + + case 2: + value = *(uint16 *) dest; + break; + + case 1: + value = *dest; + break; + + default: + ut_error; + } if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } - ut_a(value >= 0); + if (!unsigned_type && value < 0) { + value = 0; + } return(value); } diff --git a/storage/innobase/sync/sync0rw.c b/storage/innobase/sync/sync0rw.c index 4db780c8b3f..8dbc69816e9 100644 --- a/storage/innobase/sync/sync0rw.c +++ b/storage/innobase/sync/sync0rw.c @@ -174,9 +174,7 @@ rw_lock_free( /*=========*/ rw_lock_t* lock) /* in: rw-lock */ { -#ifdef UNIV_DEBUG - ut_a(rw_lock_validate(lock)); -#endif /* UNIV_DEBUG */ + ut_ad(rw_lock_validate(lock)); ut_a(rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED); ut_a(rw_lock_get_waiters(lock) == 0); ut_a(rw_lock_get_reader_count(lock) == 0); @@ -199,6 +197,7 @@ rw_lock_free( mutex_exit(&rw_lock_list_mutex); } +#ifdef UNIV_DEBUG /********************************************************************** Checks that the rw-lock has been initialized and that there are no simultaneous shared and exclusive locks. */ @@ -226,6 +225,7 @@ rw_lock_validate( return(TRUE); } +#endif /* UNIV_DEBUG */ /********************************************************************** Lock an rw-lock in shared mode for the current thread. If the rw-lock is diff --git a/storage/innobase/sync/sync0sync.c b/storage/innobase/sync/sync0sync.c index bf3f4d1ff20..39872f72204 100644 --- a/storage/innobase/sync/sync0sync.c +++ b/storage/innobase/sync/sync0sync.c @@ -830,7 +830,7 @@ sync_thread_levels_g( mutex = slot->latch; fprintf(stderr, - "InnoDB error: sync levels should be" + "InnoDB: sync levels should be" " > %lu but a level is %lu\n", (ulong) limit, (ulong) slot->level); diff --git a/storage/innobase/ut/ut0ut.c b/storage/innobase/ut/ut0ut.c index 389063ad821..1ca278cd633 100644 --- a/storage/innobase/ut/ut0ut.c +++ b/storage/innobase/ut/ut0ut.c @@ -18,6 +18,7 @@ Created 5/11/1994 Heikki Tuuri #include "ut0sort.h" #include "trx0trx.h" +#include "ha_prototypes.h" ibool ut_always_false = FALSE; @@ -70,22 +71,6 @@ ut_gettimeofday( #define ut_gettimeofday gettimeofday #endif -#ifndef UNIV_HOTBACKUP -/********************************************************************* -Display an SQL identifier. -This definition must match the one in sql/ha_innodb.cc! */ -extern -void -innobase_print_identifier( -/*======================*/ - FILE* f, /* in: output stream */ - trx_t* trx, /* in: transaction */ - ibool table_id,/* in: TRUE=print a table name, - FALSE=print other identifier */ - const char* name, /* in: name to print */ - ulint namelen);/* in: length of name */ -#endif /* !UNIV_HOTBACKUP */ - /************************************************************ Gets the high 32 bits in a ulint. That is makes a shift >> 32, but since there seem to be compiler bugs in both gcc and Visual C++, @@ -360,6 +345,8 @@ ut_print_buf( const byte* data; ulint i; + UNIV_MEM_ASSERT_RW(buf, len); + fprintf(file, " len %lu; hex ", len); for (data = (const byte*)buf, i = 0; i < len; i++) { @@ -474,17 +461,20 @@ ut_print_namel( #ifdef UNIV_HOTBACKUP fwrite(name, 1, namelen, f); #else - char* slash = memchr(name, '/', namelen); + if (table_id) { + char* slash = memchr(name, '/', namelen); + if (!slash) { + + goto no_db_name; + } - if (UNIV_LIKELY_NULL(slash)) { /* Print the database name and table name separately. */ - ut_ad(table_id); - innobase_print_identifier(f, trx, TRUE, name, slash - name); putc('.', f); innobase_print_identifier(f, trx, TRUE, slash + 1, namelen - (slash - name) - 1); } else { +no_db_name: innobase_print_identifier(f, trx, table_id, name, namelen); } #endif @@ -515,3 +505,44 @@ ut_copy_file( } } while (len > 0); } + +/************************************************************************** +snprintf(). */ + +#ifdef __WIN__ +#include +int +ut_snprintf( + /* out: number of characters that would + have been printed if the size were + unlimited, not including the terminating + '\0'. */ + char* str, /* out: string */ + size_t size, /* in: str size */ + const char* fmt, /* in: format */ + ...) /* in: format values */ +{ + int res; + va_list ap1; + va_list ap2; + + va_start(ap1, fmt); + va_start(ap2, fmt); + + res = _vscprintf(fmt, ap1); + ut_a(res != -1); + + if (size > 0) { + _vsnprintf(str, size, fmt, ap2); + + if ((size_t) res >= size) { + str[size - 1] = '\0'; + } + } + + va_end(ap1); + va_end(ap2); + + return(res); +} +#endif /* __WIN__ */ diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index e0933aff8a4..65e13aaaca0 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -314,7 +314,7 @@ case "$mode" in fi exit $return_value else - log_failure_msg "Couldn't find MySQL manager or server" + log_failure_msg "Couldn't find MySQL manager ($manager) or server ($bindir/mysqld_safe)" fi ;;