From 6224001c4f8f74d740ff17dbf9b214605d3a0f03 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 31 Oct 2007 17:40:29 +0100 Subject: [PATCH 1/8] Fix for Bug#29290 type_datetime.test failure in 5.1 mysql-test/t/type_datetime.test: - If we are too close to midnight sleep till we reach at least midnight + 1 second. - Replace error numbers with error names. --- mysql-test/t/type_datetime.test | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test index 20733a14d46..1b893fd376e 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; From ffb12753d84ac2f114c5c5f18d11ff9f4ac4d6db Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 2 Nov 2007 15:16:45 -0400 Subject: [PATCH 2/8] Bug#31319 CMake build does not check for minimum required version - Add check --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index b7b546ab72c..27b2bf9b70e 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. From 2efb78d432d3e502616018839f500cf578d054db Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 2 Nov 2007 15:30:39 -0400 Subject: [PATCH 3/8] Bug#31217 C1033 compilation error on Windows - This workaround is no longer necessary with cmake 2.4.7. sql/CMakeLists.txt: Bug#31217 C1033 compilation error on Windows - Remove workaround no longer needed. --- sql/CMakeLists.txt | 7 ------- 1 file changed, 7 deletions(-) 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) From 7bb73945459e71bdd8fa1297dc3fd313306235cc Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 5 Nov 2007 17:48:11 +0100 Subject: [PATCH 4/8] Provide better feedback to the user when unable to find MySQL files usually caused by a bad basedir setting. support-files/mysql.server.sh: Be more verbose in error message. --- 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 c68d30daafb..0a87b04c992 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -311,7 +311,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 ;; From e2513bf07fc830ed38404428957989ebb868f7a6 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Nov 2007 15:42:58 -0700 Subject: [PATCH 5/8] Apply snapshot innodb-5.1-ss1989 Fixes the following bugs: Bug #30706: SQL thread on slave is allowed to block client queries when slave load is high Add (innodb|innobase|srv)_replication_delay MySQL config parameter. Bug #30888: Innodb table + stored procedure + row deletion = server crash While adding code for the low level read of the AUTOINC value from the index, the case for MEDIUM ints which are 3 bytes was missed triggering an assertion. Bug #30907: Regression: "--innodb_autoinc_lock_mode=0" (off) not same as older releases We don't rely on *first_value to be 0 when checking whether get_auto_increment() has been invoked for the first time in a multi-row INSERT. We instead use trx_t::n_autoinc_rows. Initialize trx::n_autoinc_rows inside ha_innobase::start_stmt() too. Bug #31444: "InnoDB: Error: MySQL is freeing a thd" in innodb_mysql.test ha_innobase::external_lock(): Update prebuilt->mysql_has_locked and trx->n_mysql_tables_in_use only after row_lock_table_for_mysql() returns DB_SUCCESS. A timeout on LOCK TABLES would lead to an inconsistent state, which would cause trx_free() to print a warning. Bug #31494: innodb + 5.1 + read committed crash, assertion Set an error code when a deadlock occurs in semi-consistent read. mysql-test/r/innodb.result: Apply snapshot innodb-5.1-ss1989 Also, a test is moved into the new innodb_autoinc_lock_mode_zero test, because it depends on a non-default setting for a read-only variable. Revision r1821: Merge a change from MySQL AB: ChangeSet@1.2536.50.1 2007-08-02 12:45:56-07:00 igor@mysql.com Fixed bug#28404. This patch adds cost estimation for the queries with ORDER BY / GROUP BY and LIMIT. If there was a ref/range access to the table whose rows were required to be ordered in the result set the optimizer always employed this access though a scan by a different index that was compatible with the required order could be cheaper to produce the first L rows of the result set. Now for such queries the optimizer makes a choice between the cheapest ref/range accesses not compatible with the given order and index scans compatible with it. innodb.result: Adjusted results for test cases affected fy the fix for bug #28404. Revision r1781: Fix a test case that was broken after Bug#16979 fix. See r1645 and r1735. The variable used in the tests below was introduced in r1735. Revision r1792: innodb.result: Revert r1655, which should have been reverted as part of r1781. Revision r1843: Add test for Bug# 21409, the actual bug was fixed in r1334. mysql-test/t/innodb.test: Apply snapshot innodb-5.1-ss1989 Also, a test is moved into the new innodb_autoinc_lock_mode_zero test, because it depends on a non-default setting for a read-only variable. Revision r1781: Fix a test case that was broken after Bug#16979 fix. See r1645 and r1735. The variable used in the tests below was introduced in r1735. Revision r1843: Add test for Bug# 21409, the actual bug was fixed in r1334. storage/innobase/buf/buf0lru.c: Apply snapshot innodb-5.1-ss1989 Revision r1819: Merge r1815:1817 from branches/zip: Improve Valgrind instrumentation. UNIV_MEM_ASSERT_RW(): New macro, to check that the contents of a memory area is defined. UNIV_MEM_ASSERT_W(): New macro, to check that a memory area is writable. UNIV_MEM_ASSERT_AND_FREE(): New macro, to check that the memory is writable before declaring it free (unwritable). This replaces UNIV_MEM_FREE() in many places. mem_init_buf(): Check that the memory is writable, and declare it undefined. mem_erase_buf(): Check that the memory is writable, and declare it freed. storage/innobase/dict/dict0dict.c: Apply snapshot innodb-5.1-ss1989 Revision r1894: Add debug lock checks to autoinc functions. Add lock guards around an invocation of dict_table_autoinc_initialize(). storage/innobase/dict/dict0load.c: Apply snapshot innodb-5.1-ss1989 Revision r1974: Prevent loading of tables that have unsupported features most notably FTS indexes. storage/innobase/handler/ha_innodb.cc: Apply snapshot innodb-5.1-ss1989 Revision r1850: Implement this feature request: http://bugs.mysql.com/30706 * Add a function that returns the number of microseconds since epoch - ut_time_us(). * Add (innodb|innobase|srv)_replication_delay MySQL config parameter. * Add UT_WAIT_FOR() macro that waits for a specified condition to occur until a timeout elapses. * Using all of the above, handle the replication thread specially in srv_conc_enter_innodb(). Approved by: Heikki Revision r1887: Merge changes from MySQL AB: ChangeSet@1.2528.115.25 2007-08-27 18:18:14-06:00 tsmith@hindu.god Fix some Windows compiler warnings. dict0mem.c: Fix compiler warning with a cast. ha_innodb.cc: Change type to fix a compiler warning. Revision r1809: ha_innobase::external_lock(): Update prebuilt->mysql_has_locked and trx->n_mysql_tables_in_use only after row_lock_table_for_mysql() returns DB_SUCCESS. A timeout on LOCK TABLES would lead to an inconsistent state, which would cause trx_free() to print a warning. This was later reported as Bug #31444. Revision r1833: Add /*== ... === */ decoration that was missing around some auto-inc functions. Add a missing comment, fix the length of a decoration. Initialize the *value out parameter in ha_innobase::innobase_get_auto_increment(). Revision r1866: Revert r1850 as MySQL did not approve the addition. log for r1850: Implement this feature request: http://bugs.mysql.com/30706 * Add a function that returns the number of microseconds since epoch - ut_time_us(). * Add (innodb|innobase|srv)_replication_delay MySQL config parameter. * Add UT_WAIT_FOR() macro that waits for a specified condition to occur until a timeout elapses. * Using all of the above, handle the replication thread specially in srv_conc_enter_innodb(). Revision r1846: Add config option innodb_use_adaptive_hash_indexes to enable/disable adaptive hash indexes. It is enabled by default (no change in default behavior). Approved by: Marko Revision r1974: Prevent loading of tables that have unsupported features most notably FTS indexes. Revision r1829: Add assertion to enforce check of an implicit invariant and add comment about retry of autoinc read semantics. We always reread the table's autoinc counter after attempting to initialize it i.e., we want to guarantee that a read of autoinc valus that is returned to the caller is always covered by the AUTOINC locking mechanism. Revision r1787: Move the prototype of innobase_print_identifier() from ut0ut.c to ha_prototypes.h. Enclose the definitions in ha_prototypes.h in #ifndef UNIV_HOTBACKUP. Revision r1888: Merge a change from MySQL AB: ChangeSet@1.2528.115.30 2007-08-28 10:17:15-06:00 tsmith@hindu.god Fix another compiler warning on Windows in InnoDB. ha_innodb.cc: Fix compiler warning: ::get_auto_increment takes a ulonglong for nb_desired_values, but InnoDB's trx struct stores it as a ulint (unsigned long). Probably harmless, as a single statement won't be asking for more than 2^32 rows. Revision r1987: Bug fix: The problem was that when write_row() attempted to update the max autoinc value, and if it was rolled back because of a deadlock, the deadlock error (transaction rollback) was not being propagated back to MySQL. Revision r1889: Merge a change from MySQL AB: ChangeSet@1.2560 2007-09-21 10:15:16+02:00 gkodinov@local ha_innodb.cc: fixed type conversion warnings revealed by bug 30639 Revision r1989: Suppress printing of deadlock errors while reading the autoinc value. DB_DEADLOCK errors are part of normal processing and excessive printing of these error messages could be disconcerting for users. Revision r1828: Fix two bugs: Bug# 30907: We don't rely on *first_value to be 0 when checking whether get_auto_increment() has been invoked for the first time in a multi-row INSERT. We instead use trx_t::n_autoinc_rows. Initialize trx::n_autoinc_rows inside ha_innobase::start_stmt() too. Bug# 30888: While adding code for the low level read of the AUTOINC value from the index, the case for MEDIUM ints which are 3 bytes was missed triggering an assertion. storage/innobase/handler/ha_innodb.h: Apply snapshot innodb-5.1-ss1989 Revision r1844: Remove the prototypes of some functions inside #if 0. The function definitions were removed in r1746. storage/innobase/ibuf/ibuf0ibuf.c: Apply snapshot innodb-5.1-ss1989 Revision r1965: ibuf_insert_to_index_page(): Fix typos in diagnostic output. storage/innobase/include/db0err.h: Apply snapshot innodb-5.1-ss1989 Revision r1974: Prevent loading of tables that have unsupported features most notably FTS indexes. storage/innobase/include/ha_prototypes.h: Apply snapshot innodb-5.1-ss1989 Revision r1787: Move the prototype of innobase_print_identifier() from ut0ut.c to ha_prototypes.h. Enclose the definitions in ha_prototypes.h in #ifndef UNIV_HOTBACKUP. storage/innobase/include/mach0data.h: Apply snapshot innodb-5.1-ss1989 Revision r1779: Fix a bug that handles the case where the host specific byte order matches the InnoDB storage byte order, which is big-endian. storage/innobase/include/mach0data.ic: Apply snapshot innodb-5.1-ss1989 Revision r1779: Fix a bug that handles the case where the host specific byte order matches the InnoDB storage byte order, which is big-endian. storage/innobase/include/mem0dbg.h: Apply snapshot innodb-5.1-ss1989 Revision r1830: Improve memory debugging. This is follow-up to r1819. mem_heap_validate(): Compile this function also if UNIV_MEM_DEBUG is defined. Previously, this function was only compiled with UNIV_DEBUG. mem_heap_free_heap_top(): Flag the memory allocated, not freed, for Valgrind. Otherwise, Valgrind would complain on the second call of mem_heap_empty(). UNIV_MEM_ASSERT_RW(), UNIV_MEM_ASSERT_W(): Display additional diagnostics for failed Valgrind checks. storage/innobase/include/mem0mem.ic: Apply snapshot innodb-5.1-ss1989 Revision r1830: Improve memory debugging. This is follow-up to r1819. mem_heap_validate(): Compile this function also if UNIV_MEM_DEBUG is defined. Previously, this function was only compiled with UNIV_DEBUG. mem_heap_free_heap_top(): Flag the memory allocated, not freed, for Valgrind. Otherwise, Valgrind would complain on the second call of mem_heap_empty(). UNIV_MEM_ASSERT_RW(), UNIV_MEM_ASSERT_W(): Display additional diagnostics for failed Valgrind checks. Revision r1937: mem_heap_free_top(): Remove a bogus Valgrind warning. Revision r1819: Merge r1815:1817 from branches/zip: Improve Valgrind instrumentation. UNIV_MEM_ASSERT_RW(): New macro, to check that the contents of a memory area is defined. UNIV_MEM_ASSERT_W(): New macro, to check that a memory area is writable. UNIV_MEM_ASSERT_AND_FREE(): New macro, to check that the memory is writable before declaring it free (unwritable). This replaces UNIV_MEM_FREE() in many places. mem_init_buf(): Check that the memory is writable, and declare it undefined. mem_erase_buf(): Check that the memory is writable, and declare it freed. storage/innobase/include/rem0rec.ic: Apply snapshot innodb-5.1-ss1989 Revision r1918: Improve Valgrind instrumentation. rec_offs_set_n_alloc(): Use UNIV_MEM_ASSERT_AND_ALLOC(). UNIV_MEM_ASSERT_AND_ALLOC(): New directive, similar to UNIV_MEM_ASSERT_AND_FREE(). storage/innobase/include/row0mysql.h: Apply snapshot innodb-5.1-ss1989 Revision r1783: Correct the function comments of row_create_table_for_mysql() and row_drop_table_for_mysql(). storage/innobase/include/sync0rw.h: Apply snapshot innodb-5.1-ss1989 Revision r1757: Enclose rw_lock_validate() in #ifdef UNIV_DEBUG. It is only called by debug assertions. storage/innobase/include/univ.i: Apply snapshot innodb-5.1-ss1989 Revision r1827: Merge r1826 from branches/zip: UNIV_MEM_ASSERT_AND_FREE(): Use UNIV_MEM_ASSERT_W() instead of UNIV_MEM_ASSERT_RW(). The memory area need not be initialized. This mistake was made in r1815. Revision r1918: Improve Valgrind instrumentation. rec_offs_set_n_alloc(): Use UNIV_MEM_ASSERT_AND_ALLOC(). UNIV_MEM_ASSERT_AND_ALLOC(): New directive, similar to UNIV_MEM_ASSERT_AND_FREE(). Revision r1830: Improve memory debugging. This is follow-up to r1819. mem_heap_validate(): Compile this function also if UNIV_MEM_DEBUG is defined. Previously, this function was only compiled with UNIV_DEBUG. mem_heap_free_heap_top(): Flag the memory allocated, not freed, for Valgrind. Otherwise, Valgrind would complain on the second call of mem_heap_empty(). UNIV_MEM_ASSERT_RW(), UNIV_MEM_ASSERT_W(): Display additional diagnostics for failed Valgrind checks. Revision r1819: Merge r1815:1817 from branches/zip: Improve Valgrind instrumentation. UNIV_MEM_ASSERT_RW(): New macro, to check that the contents of a memory area is defined. UNIV_MEM_ASSERT_W(): New macro, to check that a memory area is writable. UNIV_MEM_ASSERT_AND_FREE(): New macro, to check that the memory is writable before declaring it free (unwritable). This replaces UNIV_MEM_FREE() in many places. mem_init_buf(): Check that the memory is writable, and declare it undefined. mem_erase_buf(): Check that the memory is writable, and declare it freed. Revision r1948: UNIV_MEM_ASSERT_RW(), UNIV_MEM_ASSERT_W(): Display also __FILE__ and __LINE__ when these Valgrind checks fail. storage/innobase/include/ut0ut.h: Apply snapshot innodb-5.1-ss1989 Revision r1850: Implement this feature request: http://bugs.mysql.com/30706 * Add a function that returns the number of microseconds since epoch - ut_time_us(). * Add (innodb|innobase|srv)_replication_delay MySQL config parameter. * Add UT_WAIT_FOR() macro that waits for a specified condition to occur until a timeout elapses. * Using all of the above, handle the replication thread specially in srv_conc_enter_innodb(). Approved by: Heikki Revision r1862: Add ut_snprintf() function. On Windows this needs to be implemented using auxiliary functions because there is no snprintf-variant on Windows that behaves exactly as specified in the standard: * Always return the number of characters that would have been printed if the size were unlimited (not including the final `\0'). * Always '\0'-terminate the result * Do not touch the buffer if size=0, only return the number of characters that would have been printed. Can be used to estimate the size needed and to allocate it dynamically. See http://www.freebsd.org/cgi/query-pr.cgi?pr=87260 for the reason why 2 ap variables are used. Approved by: Heikki Revision r1866: Revert r1850 as MySQL did not approve the addition. log for r1850: Implement this feature request: http://bugs.mysql.com/30706 * Add a function that returns the number of microseconds since epoch - ut_time_us(). * Add (innodb|innobase|srv)_replication_delay MySQL config parameter. * Add UT_WAIT_FOR() macro that waits for a specified condition to occur until a timeout elapses. * Using all of the above, handle the replication thread specially in srv_conc_enter_innodb(). storage/innobase/mem/mem0dbg.c: Apply snapshot innodb-5.1-ss1989 Revision r1830: Improve memory debugging. This is follow-up to r1819. mem_heap_validate(): Compile this function also if UNIV_MEM_DEBUG is defined. Previously, this function was only compiled with UNIV_DEBUG. mem_heap_free_heap_top(): Flag the memory allocated, not freed, for Valgrind. Otherwise, Valgrind would complain on the second call of mem_heap_empty(). UNIV_MEM_ASSERT_RW(), UNIV_MEM_ASSERT_W(): Display additional diagnostics for failed Valgrind checks. Revision r1819: Merge r1815:1817 from branches/zip: Improve Valgrind instrumentation. UNIV_MEM_ASSERT_RW(): New macro, to check that the contents of a memory area is defined. UNIV_MEM_ASSERT_W(): New macro, to check that a memory area is writable. UNIV_MEM_ASSERT_AND_FREE(): New macro, to check that the memory is writable before declaring it free (unwritable). This replaces UNIV_MEM_FREE() in many places. mem_init_buf(): Check that the memory is writable, and declare it undefined. mem_erase_buf(): Check that the memory is writable, and declare it freed. storage/innobase/mem/mem0mem.c: Apply snapshot innodb-5.1-ss1989 Revision r1819: Merge r1815:1817 from branches/zip: Improve Valgrind instrumentation. UNIV_MEM_ASSERT_RW(): New macro, to check that the contents of a memory area is defined. UNIV_MEM_ASSERT_W(): New macro, to check that a memory area is writable. UNIV_MEM_ASSERT_AND_FREE(): New macro, to check that the memory is writable before declaring it free (unwritable). This replaces UNIV_MEM_FREE() in many places. mem_init_buf(): Check that the memory is writable, and declare it undefined. mem_erase_buf(): Check that the memory is writable, and declare it freed. storage/innobase/row/row0mysql.c: Apply snapshot innodb-5.1-ss1989 Revision r1786: row_create_table_for_mysql(), row_truncate_table_for_mysql(), row_drop_table_for_mysql(): Do not mention innodb_force_recovery when newraw is set. Revision r1790: row_drop_table_for_mysql(): Before calling dict_table_remove_from_cache(table) and thus freeing the memory allocated for the table, copy the table name. This avoids reading freed memory when name == table->name. Approved by Sunny. Revision r1783: Correct the function comments of row_create_table_for_mysql() and row_drop_table_for_mysql(). Revision r1894: Add debug lock checks to autoinc functions. Add lock guards around an invocation of dict_table_autoinc_initialize(). storage/innobase/row/row0sel.c: Apply snapshot innodb-5.1-ss1989 Revision r1782: Add comment that the variable dest should be word aligned. After discussion on IM with Heikki. Revision r1988: Set an error code when a deadlock occurs in semi-consistent read. (Bug #31494) innodb-semi-consistent: New tests for InnoDB semi-consistent reads. Unfortunately, these will not trigger Bug #31494, because there merely occur lock wait timeouts, not deadlocks. Revision r1820: Use the clustered index and not the one selected by the optimizer in the plan, when building a previous version of the row. This bug is triggered when running queries via InnoDB's internal SQL parser; when InnoDB's optimizer selects a secondary index for the plan. Revision r1828: Fix two bugs: Bug# 30907: We don't rely on *first_value to be 0 when checking whether get_auto_increment() has been invoked for the first time in a multi-row INSERT. We instead use trx_t::n_autoinc_rows. Initialize trx::n_autoinc_rows inside ha_innobase::start_stmt() too. Bug# 30888: While adding code for the low level read of the AUTOINC value from the index, the case for MEDIUM ints which are 3 bytes was missed triggering an assertion. Revision r1779: Fix a bug that handles the case where the host specific byte order matches the InnoDB storage byte order, which is big-endian. storage/innobase/sync/sync0rw.c: Apply snapshot innodb-5.1-ss1989 Revision r1757: Enclose rw_lock_validate() in #ifdef UNIV_DEBUG. It is only called by debug assertions. storage/innobase/ut/ut0ut.c: Apply snapshot innodb-5.1-ss1989 Revision r1850: Implement this feature request: http://bugs.mysql.com/30706 * Add a function that returns the number of microseconds since epoch - ut_time_us(). * Add (innodb|innobase|srv)_replication_delay MySQL config parameter. * Add UT_WAIT_FOR() macro that waits for a specified condition to occur until a timeout elapses. * Using all of the above, handle the replication thread specially in srv_conc_enter_innodb(). Approved by: Heikki Revision r1873: snprintf() should always return non-negative result. According to Microsoft documentation about _vscprintf(): If format is a null pointer, the invalid parameter handler is invoked, as described in Parameter Validation. If execution is allowed to continue, the functions return -1 and set errno to EINVAL. The UNIX variant of snprintf() segfaults if format is a NULL pointer (similar to strlen(NULL) for example), so it is better to conform to this behavior and crash our custom Windows version instead of returning -1. Noone would expect -1 to be returned from snprintf(). Cosmetic: Add a space after typecast. Approved by: Marko Revision r1862: Add ut_snprintf() function. On Windows this needs to be implemented using auxiliary functions because there is no snprintf-variant on Windows that behaves exactly as specified in the standard: * Always return the number of characters that would have been printed if the size were unlimited (not including the final `\0'). * Always '\0'-terminate the result * Do not touch the buffer if size=0, only return the number of characters that would have been printed. Can be used to estimate the size needed and to allocate it dynamically. See http://www.freebsd.org/cgi/query-pr.cgi?pr=87260 for the reason why 2 ap variables are used. Approved by: Heikki Revision r1866: Revert r1850 as MySQL did not approve the addition. log for r1850: Implement this feature request: http://bugs.mysql.com/30706 * Add a function that returns the number of microseconds since epoch - ut_time_us(). * Add (innodb|innobase|srv)_replication_delay MySQL config parameter. * Add UT_WAIT_FOR() macro that waits for a specified condition to occur until a timeout elapses. * Using all of the above, handle the replication thread specially in srv_conc_enter_innodb(). Revision r1787: Move the prototype of innobase_print_identifier() from ut0ut.c to ha_prototypes.h. Enclose the definitions in ha_prototypes.h in #ifndef UNIV_HOTBACKUP. Revision r1789: ut_print_namel(): Do not assume that all '/' are separators between database and table names. Approved by Heikki. Revision r1936: ut_print_buf(): Add a Valgrind check that the buffer is wholly defined. mysql-test/r/innodb-semi-consistent.result: Apply snapshot innodb-5.1-ss1989 Revision r1988: Set an error code when a deadlock occurs in semi-consistent read. (Bug #31494) innodb-semi-consistent: New tests for InnoDB semi-consistent reads. Unfortunately, these will not trigger Bug #31494, because there merely occur lock wait timeouts, not deadlocks. mysql-test/r/innodb_autoinc_lock_mode_zero.result: New test, using read-only setting --innodb-autoinc-lock-mode=0 mysql-test/t/innodb-semi-consistent-master.opt: Apply snapshot innodb-5.1-ss1989 Revision r1988: Set an error code when a deadlock occurs in semi-consistent read. (Bug #31494) innodb-semi-consistent: New tests for InnoDB semi-consistent reads. Unfortunately, these will not trigger Bug #31494, because there merely occur lock wait timeouts, not deadlocks. mysql-test/t/innodb-semi-consistent.test: Apply snapshot innodb-5.1-ss1989 Revision r1988: Set an error code when a deadlock occurs in semi-consistent read. (Bug #31494) innodb-semi-consistent: New tests for InnoDB semi-consistent reads. Unfortunately, these will not trigger Bug #31494, because there merely occur lock wait timeouts, not deadlocks. mysql-test/t/innodb_autoinc_lock_mode_zero-master.opt: New test, using read-only setting --innodb-autoinc-lock-mode=0 mysql-test/t/innodb_autoinc_lock_mode_zero.test: New test, using read-only setting --innodb-autoinc-lock-mode=0 --- mysql-test/r/innodb-semi-consistent.result | 36 +++++++ mysql-test/r/innodb.result | 76 +++++++------- .../r/innodb_autoinc_lock_mode_zero.result | 39 ++++++++ .../t/innodb-semi-consistent-master.opt | 1 + mysql-test/t/innodb-semi-consistent.test | 46 +++++++++ mysql-test/t/innodb.test | 75 +++++++------- .../innodb_autoinc_lock_mode_zero-master.opt | 1 + .../t/innodb_autoinc_lock_mode_zero.test | 44 +++++++++ storage/innobase/buf/buf0lru.c | 2 +- storage/innobase/dict/dict0dict.c | 4 + storage/innobase/dict/dict0load.c | 78 +++++++++------ storage/innobase/handler/ha_innodb.cc | 98 +++++++++++++------ storage/innobase/handler/ha_innodb.h | 14 --- storage/innobase/ibuf/ibuf0ibuf.c | 4 +- storage/innobase/include/db0err.h | 6 +- storage/innobase/include/ha_prototypes.h | 16 +++ storage/innobase/include/mach0data.h | 11 +++ storage/innobase/include/mach0data.ic | 37 +++++++ storage/innobase/include/mem0dbg.h | 16 +-- storage/innobase/include/mem0mem.ic | 16 +-- storage/innobase/include/rem0rec.ic | 1 + storage/innobase/include/row0mysql.h | 13 ++- storage/innobase/include/sync0rw.h | 2 + storage/innobase/include/univ.i | 28 ++++++ storage/innobase/include/ut0ut.h | 18 ++++ storage/innobase/mem/mem0dbg.c | 40 +++++--- storage/innobase/mem/mem0mem.c | 6 +- storage/innobase/row/row0mysql.c | 82 +++++++--------- storage/innobase/row/row0sel.c | 69 ++++++++----- storage/innobase/sync/sync0rw.c | 6 +- storage/innobase/ut/ut0ut.c | 71 ++++++++++---- 31 files changed, 671 insertions(+), 285 deletions(-) create mode 100644 mysql-test/r/innodb-semi-consistent.result create mode 100644 mysql-test/r/innodb_autoinc_lock_mode_zero.result create mode 100644 mysql-test/t/innodb-semi-consistent-master.opt create mode 100644 mysql-test/t/innodb-semi-consistent.test create mode 100644 mysql-test/t/innodb_autoinc_lock_mode_zero-master.opt create mode 100644 mysql-test/t/innodb_autoinc_lock_mode_zero.test 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..9f6cde0292f 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,36 @@ 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 +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..77c450035c7 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,48 @@ CREATE TABLE t1 ( c29 CHAR(255), c30 CHAR(255), c31 CHAR(255), c32 CHAR(255) ) ENGINE = InnoDB; +# +# 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/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..61f16522cff 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; @@ -1246,8 +1247,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 +1635,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 @@ -2320,13 +2323,18 @@ ha_innobase::open( 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); @@ -3476,6 +3484,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 +3538,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 = err; + } } break; } @@ -3765,7 +3778,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); } } @@ -6304,6 +6317,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 +6462,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 +6510,9 @@ ha_innobase::external_lock( trx->mysql_n_tables_locked++; } + trx->n_mysql_tables_in_use++; + prebuilt->mysql_has_locked = TRUE; + DBUG_RETURN(0); } @@ -7120,8 +7136,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 +7194,9 @@ 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); + 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 +7233,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 +7277,16 @@ 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) { + + ut_print_timestamp(stderr); + sql_print_error(" InnoDB Error %lu in " + "::innobase_get_auto_increment()", + error); } + } while (*value == 0 && error == DB_SUCCESS); return(error); @@ -7272,7 +7302,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 +7319,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 +7333,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 +7346,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 +7387,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 +7953,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 +8086,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..d845c1006ee 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*) \ + VALGRIND_CHECK_MEM_IS_DEFINED(addr, size); \ + if (UNIV_LIKELY_NULL(_p)) \ + fprintf(stderr, "%s:%d: %p[%u] undefined at %d\n", \ + __FILE__, __LINE__, \ + (const void*) (addr), (unsigned) (size), \ + ((const char*) _p) - ((const char*) (addr))); \ + } while (0) +# define UNIV_MEM_ASSERT_W(addr, size) do { \ + const void* _p = (const void*) \ + VALGRIND_CHECK_MEM_IS_ADDRESSABLE(addr, size); \ + if (UNIV_LIKELY_NULL(_p)) \ + fprintf(stderr, "%s:%d: %p[%u] unwritable at %d\n", \ + __FILE__, __LINE__, \ + (const void*) (addr), (unsigned) (size), \ + ((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..51f76036aae 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; } @@ -4536,6 +4541,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,20 +4560,35 @@ 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); 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/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__ */ From bdffce056b2306c4614b994e2b79d05caa38b765 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Nov 2007 16:40:50 -0700 Subject: [PATCH 6/8] Apply snapshot innodb-5.1-ss2034 The following bugs are fixed: Bug #31860: Server crashes after inserting into InnoDB table with auto_increment column In the Bug 16979 fix there was an erroneous assertion that autoincrement columns can't contain negative values. With the fix, the autoincrement table counter is set to 0 if the maximum value read from the autoinc column index is negative. mysql-test/r/innodb.result: Apply snapshot innodb-5.1-ss2034 Revision r2034: Fix for Bug# 31860, in the Bug 16979 fix there was an erroneous assertion that autoincrement columns can't contain negative values. With the fix, the autoincrement table counter is set to 0 if the maximum value read from the autoinc column index is negative. Add test for the bug fix but the test is not really useful as the server needs to be restarted half way through the test. It has been added for reference only. mysql-test/t/innodb.test: Apply snapshot innodb-5.1-ss2034 Revision r2034: Fix for Bug# 31860, in the Bug 16979 fix there was an erroneous assertion that autoincrement columns can't contain negative values. With the fix, the autoincrement table counter is set to 0 if the maximum value read from the autoinc column index is negative. Add test for the bug fix but the test is not really useful as the server needs to be restarted half way through the test. It has been added for reference only. storage/innobase/handler/ha_innodb.cc: Apply snapshot innodb-5.1-ss2034 Revision r2017: Use "InnoDB:" prefix in error messages. Revision r2018: Remove ut_print_timestamp(), this should have been removed when the following changes were made by MySQL. ChangeSet@1.1810.467.1 2005-08-11 19:19:20+03:00 jani@omakaista.fi Fix error message so that it conforms to " InnoDB: Error: ...". storage/innobase/include/univ.i: Apply snapshot innodb-5.1-ss2034 Revision r2015: UNIV_MEM_ASSERT_RW(), UNIV_MEM_ASSERT_W(): Remove warnings on 64-bit systems. storage/innobase/row/row0sel.c: Apply snapshot innodb-5.1-ss2034 Revision r2034: Fix for Bug# 31860, in the Bug 16979 fix there was an erroneous assertion that autoincrement columns can't contain negative values. With the fix, the autoincrement table counter is set to 0 if the maximum value read from the autoinc column index is negative. Add test for the bug fix but the test is not really useful as the server needs to be restarted half way through the test. It has been added for reference only. storage/innobase/sync/sync0sync.c: Apply snapshot innodb-5.1-ss2034 Revision r2017: Use "InnoDB:" prefix in error messages. --- mysql-test/r/innodb.result | 16 +++++++++++++ mysql-test/t/innodb.test | 19 +++++++++++++++ storage/innobase/handler/ha_innodb.cc | 33 ++++++++++++--------------- storage/innobase/include/univ.i | 16 ++++++------- storage/innobase/row/row0sel.c | 7 ++++-- storage/innobase/sync/sync0sync.c | 2 +- 6 files changed, 64 insertions(+), 29 deletions(-) diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 9f6cde0292f..051a9e1dc0b 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -3152,6 +3152,22 @@ 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; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 77c450035c7..f68bb87655e 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -2290,6 +2290,25 @@ 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 diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 61f16522cff..f38afbba33d 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -1144,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."); @@ -2322,7 +2321,6 @@ ha_innobase::open( ib_table = dict_table_get(norm_name, TRUE); if (NULL == ib_table) { - ut_print_timestamp(stderr); sql_print_error("Cannot find or open table %s from\n" "the internal data dictionary of InnoDB " "though the .frm file for the\n" @@ -2346,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 " @@ -3420,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); */ @@ -5723,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 " @@ -5739,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 " @@ -5804,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); @@ -6578,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); } @@ -7194,7 +7191,8 @@ ha_innobase::innobase_read_and_init_auto_inc( ++auto_inc; dict_table_autoinc_initialize(innodb_table, auto_inc); } else { - fprintf(stderr, " InnoDB error (%lu): Couldn't read " + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: Error: (%lu) Couldn't read " "the max AUTOINC value from the index (%s).\n", error, index->name); @@ -7281,8 +7279,7 @@ ha_innobase::innobase_get_auto_increment( and can be ignored. */ } else if (error != DB_DEADLOCK) { - ut_print_timestamp(stderr); - sql_print_error(" InnoDB Error %lu in " + sql_print_error("InnoDB: Error: %lu in " "::innobase_get_auto_increment()", error); } diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index d845c1006ee..8163ae16e4e 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -309,22 +309,22 @@ typedef void* os_thread_ret_t; # 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*) \ + 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 %d\n", \ + fprintf(stderr, "%s:%d: %p[%u] undefined at %ld\n", \ __FILE__, __LINE__, \ - (const void*) (addr), (unsigned) (size), \ - ((const char*) _p) - ((const char*) (addr))); \ + (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*) \ + 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 %d\n", \ + fprintf(stderr, "%s:%d: %p[%u] unwritable at %ld\n", \ __FILE__, __LINE__, \ - (const void*) (addr), (unsigned) (size), \ - ((const char*) _p) - ((const char*) (addr))); \ + (const void*) (addr), (unsigned) (size), (long) \ + (((const char*) _p) - ((const char*) (addr)))); \ } while (0) #else # define UNIV_MEM_VALID(addr, size) do {} while(0) diff --git a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c index 51f76036aae..29bded114e0 100644 --- a/storage/innobase/row/row0sel.c +++ b/storage/innobase/row/row0sel.c @@ -4526,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( @@ -4594,7 +4595,9 @@ row_search_autoinc_read_column( mem_heap_free(heap); } - ut_a(value >= 0); + if (!unsigned_type && value < 0) { + value = 0; + } return(value); } 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); From 8680f86e460d8be123ddbbc855c0e744dd749648 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Nov 2007 12:59:22 -0700 Subject: [PATCH 7/8] Cast away compiler warning on Windows. storage/innobase/handler/ha_innodb.cc: Cast away a compiler warning; some functions return ulong or ulint for errors, and some use int. Let's hope these all fit in an int. --- storage/innobase/handler/ha_innodb.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index f38afbba33d..f075fe6c3b4 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -3538,7 +3538,7 @@ set_max_autoinc: err = innobase_set_max_autoinc(auto_inc); if (err != DB_SUCCESS) { - error = err; + error = (int) err; } } break; From 707f42a6b988d94630f3e43dad410311f40ac4f8 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Nov 2007 15:23:50 -0700 Subject: [PATCH 8/8] Bug #20748: Configuration files should not be read more than once A user could not override system-wide settings in their ~/.my.cnf, because the DEFAULT_SYSCONFDIR was being searched last. Also, in some configurations (especially when the --sysconfdir compile-time option is set to /etc or /etc/mysql), the system-wide my.cnf file was read multiple times, causing confusion and potential problems. Rearrange default directories to conform to the manual and logic. Move --sysconfdir= (DEFAULT_SYSCONFDIR) from the last default directory to the middle of the list. $HOME/.my.cnf should be last, so the user is able to override the system-wide settings. Change init_default_directories() to remove duplicates from the list. include/my_sys.h: Add array_append_string_unique(), from mf_arr_appstr.c libmysql/Makefile.shared: Add new mf_arr_appstr.lo object mysys/CMakeLists.txt: Add new mf_arr_appstr.c source. mysys/Makefile.am: Add new mf_arr_appstr.c source. mysys/default.c: Change order in which defaults files are added to default_directories, in order to conform to the manual (and to common sense). This fixes a particularly bad problem on Unix, where ~/.my.cnf was read before /usr/local/etc/my.cnf. Also, don't add duplicate entries; move the existing entry to the end of the list instead. Here is a comparison of the order of defaults files, BEFORE and AFTER this patch. On Windows: BEFORE: C:\, GetWindowsDirectory(), GetSystemWindowsDirectory(), $MYSQL_HOME, defaults-extra-file, INSTALLDIR AFTER: GetSystemWindowsDirectory(), GetWindowsDirectory(), C:\, INSTALLDIR, $MYSQL_HOME, defaults-extra-file GetSystemWindowsDirectory() is moved before GetWindowsDirectory() because the former is shared by all Terminal Services users, while the latter is private for each user. On Netware (no change): BEFORE: sys:/etc/, $MYSQL_HOME, defaults-extra-file AFTER: sys:/etc, $MYSQL_HOME, defaults-extra-file On OS/2: BEFORE: $ETC, /etc, $MYSQL_HOME, defaults-extra-file AFTER: /etc, $ETC, $MYSQL_HOME, defaults-extra-file On everything else (general Unix): BEFORE: /etc, $MYSQL_HOME, defaults-extra-file, ~/, --sysconfdir AFTER: /etc/, --sysconfdir, $MYSQL_HOME, defaults-extra-file, ~/ The BEFORE code added --sysconfdir on all systems, but only the Unix build system actually defined a value for it. mysys/mf_arr_appstr.c: BitKeeper file /home/tsmith/m/bk/build/50-b20748/mysys/mf_arr_appstr.c --- include/my_sys.h | 2 + libmysql/Makefile.shared | 2 +- mysys/CMakeLists.txt | 2 +- mysys/Makefile.am | 2 +- mysys/default.c | 192 ++++++++++++++++++++++++++------------- mysys/mf_arr_appstr.c | 61 +++++++++++++ 6 files changed, 195 insertions(+), 66 deletions(-) create mode 100644 mysys/mf_arr_appstr.c diff --git a/include/my_sys.h b/include/my_sys.h index 7df2718c7b1..8c0d620984c 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -691,6 +691,8 @@ extern WF_PACK *wf_comp(my_string 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_s strip_sp(my_string str); +extern my_bool array_append_string_unique(const char *str, + const char **array, size_t size); extern void get_date(my_string to,int timeflag,time_t use_time); extern void soundex(CHARSET_INFO *, my_string out_pntr, my_string in_pntr,pbool remove_garbage); extern int init_record_cache(RECORD_CACHE *info,uint cachesize,File file, diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared index dc6d658fcdf..7839c117432 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/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index 8aaf0b5f00f..cd3e7afd6a5 100755 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -26,7 +26,7 @@ ADD_LIBRARY(mysys array.c charset-def.c charset.c checksum.c default.c default_m 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 a835492e670..8c6bf5f7006 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -38,7 +38,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 \ diff --git a/mysys/default.c b/mysys/default.c index aff38b6af0b..74d016ce53c 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); @@ -913,6 +928,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 @@ -947,73 +981,33 @@ static uint my_get_system_windows_directory(char *buffer, uint 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. getenv(DEFAULT_HOME_ENV) - 3. "" - 4. "~/" - 5. --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 -#if defined(__EMX__) || defined(OS2) - if ((env= getenv("ETC"))) - *ptr++= env; -#endif - *ptr++= "/etc/"; -#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); @@ -1043,12 +1037,84 @@ 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; + +#elif defined(__EMX__) || defined(OS2) + +/** + Initialize default directories for OS/2 + + @details + 1. /etc/ + 2. getenv(ETC) + 3. getenv(DEFAULT_HOME_ENV) + 4. --defaults-extra-file= (run-time option) +*/ + +static void init_default_directories_os2() +{ + const char *env; + + bzero(default_directories, sizeof(default_directories)); + ADD_DIRECTORY("/etc/"); + if ((env= getenv("ETC"))) + ADD_DIRECTORY(env); + ADD_COMMON_DIRECTORIES(); +} + +static void (*init_default_directories)()= init_default_directories_os2; + +#else + +/** + Initialize default directories for Unix + + @details + 1. /etc/ + 2. --sysconfdir= (compile-time option) + 3. getenv(DEFAULT_HOME_ENV) + 4. --defaults-extra-file= (run-time option) + 5. "~/" +*/ + +static void init_default_directories_unix() +{ + bzero(default_directories, sizeof(default_directories)); + ADD_DIRECTORY("/etc/"); #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 */ +}