From dc9c5440e357b1afde67ea43ad3e626835e55896 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Fri, 19 Dec 2008 09:23:15 +0100 Subject: [PATCH 1/5] Bug#36312: InnoDB DATA_FREE BUG? Problem is that DATA_FREE in SHOW TABLE STATUS is not correct when not using innodb_file_per_table. The solution is to use I_S.PARTITIONS instead. This is only a small fix for correcting mean record length and always return 0 if the table is empty. sql/ha_partition.cc: Bug#36312: InnoDB DATA_FREE BUG? This is only a small fix for correcting mean record length and always return 0 if the table is empty. --- sql/ha_partition.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 47d2d36ac8d..c8b068ca2be 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -4815,7 +4815,7 @@ int ha_partition::info(uint flag) /* Calculates statistical variables records: Estimate of number records in table - We report sum (always at least 2) + We report sum (always at least 2 if not empty) deleted: Estimate of number holes in the table due to deletes We report sum @@ -4854,13 +4854,13 @@ int ha_partition::info(uint flag) stats.check_time= file->stats.check_time; } } while (*(++file_array)); - if (stats.records < 2 && + if (stats.records && stats.records < 2 && !(m_file[0]->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT)) stats.records= 2; if (stats.records > 0) stats.mean_rec_length= (ulong) (stats.data_file_length / stats.records); else - stats.mean_rec_length= 1; //? What should we set here + stats.mean_rec_length= 0; } if (flag & HA_STATUS_CONST) { From f257aac8148626c81fb3447eeb2bb85d9756735e Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Sun, 28 Dec 2008 12:33:49 +0100 Subject: [PATCH 2/5] Bug#40972: some sql execution lead the whole databse crashing Problem was an errornous date that lead to end partition was before the start, leading to a crash. Solution was to check greater or equal instead of only equal between start and end partition. NOTE: partitioning pruning handles incorrect dates differently than index lookup, which can give different results in a partitioned table versus a non partitioned table for queries having 'bad' dates in the where clause. mysql-test/r/partition_pruning.result: Bug#40972: some sql execution lead the whole databse crashing Updated result file mysql-test/t/partition_pruning.test: Bug#40972: some sql execution lead the whole databse crashing Added test. sql/sql_partition.cc: Bug#40972: some sql execution lead the whole databse crashing There can be cases where the start/cur partition is greater than the end partition, so it must not continue, since that can lead to a crash. --- mysql-test/r/partition_pruning.result | 12 ++++++++++++ mysql-test/t/partition_pruning.test | 16 ++++++++++++++++ sql/sql_partition.cc | 4 ++-- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/partition_pruning.result b/mysql-test/r/partition_pruning.result index b153ad9ad47..26ddc92e97b 100644 --- a/mysql-test/r/partition_pruning.result +++ b/mysql-test/r/partition_pruning.result @@ -1,4 +1,16 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +CREATE TABLE t1 +(a INT NOT NULL AUTO_INCREMENT, +b DATETIME, +PRIMARY KEY (a,b), +KEY (b)) +PARTITION BY RANGE (to_days(b)) +(PARTITION p0 VALUES LESS THAN (733681) COMMENT = 'LESS THAN 2008-10-01', +PARTITION p1 VALUES LESS THAN (733712) COMMENT = 'LESS THAN 2008-11-01', +PARTITION pX VALUES LESS THAN MAXVALUE); +SELECT a,b FROM t1 WHERE b >= '2008-12-01' AND b < '2009-12-00'; +a b +DROP TABLE t1; create table t1 ( a int not null) partition by hash(a) partitions 2; insert into t1 values (1),(2),(3); explain select * from t1 where a=5 and a=6; diff --git a/mysql-test/t/partition_pruning.test b/mysql-test/t/partition_pruning.test index 31008d2b011..ad102062ef8 100644 --- a/mysql-test/t/partition_pruning.test +++ b/mysql-test/t/partition_pruning.test @@ -8,6 +8,22 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; --enable_warnings +# +# Bug#40972: some sql execution lead the whole database crashing +# +# Setup so the start is at partition pX and end is at p1 +# Pruning does handle 'bad' dates differently. +CREATE TABLE t1 +(a INT NOT NULL AUTO_INCREMENT, + b DATETIME, + PRIMARY KEY (a,b), + KEY (b)) +PARTITION BY RANGE (to_days(b)) +(PARTITION p0 VALUES LESS THAN (733681) COMMENT = 'LESS THAN 2008-10-01', + PARTITION p1 VALUES LESS THAN (733712) COMMENT = 'LESS THAN 2008-11-01', + PARTITION pX VALUES LESS THAN MAXVALUE); +SELECT a,b FROM t1 WHERE b >= '2008-12-01' AND b < '2009-12-00'; +DROP TABLE t1; # Check if we can infer from condition on partition fields that # no records will match. diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index c1df5552eb9..9096a2b91ef 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -6760,7 +6760,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, store_key_image_to_rec(field, max_value, field_len); bool include_endp= !test(flags & NEAR_MAX); part_iter->part_nums.end= get_endpoint(part_info, 0, include_endp); - if (part_iter->part_nums.start == part_iter->part_nums.end && + if (part_iter->part_nums.start >= part_iter->part_nums.end && !part_iter->ret_null_part) return 0; /* No partitions */ } @@ -6938,7 +6938,7 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info, uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter) { - if (part_iter->part_nums.cur == part_iter->part_nums.end) + if (part_iter->part_nums.cur >= part_iter->part_nums.end) { part_iter->part_nums.cur= part_iter->part_nums.start; return NOT_A_PARTITION_ID; From fec0b2c27a1035927651eb0927447d1d46e08155 Mon Sep 17 00:00:00 2001 From: Patrick Crews Date: Mon, 5 Jan 2009 12:10:22 -0500 Subject: [PATCH 3/5] Bug#38833: mysql-test-run needs diff. Problem w/ error handling in calling diff on Windows. Added function to check for diff and return an error message if the utility is not present. Previously, the way we did this didn't work on Windows, but did work on *Nix systems. --- client/mysqltest.c | 81 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 18 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 9c7c4d62f6f..d73cf78d9d4 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -1329,6 +1329,35 @@ static int run_tool(const char *tool_path, DYNAMIC_STRING *ds_res, ...) DBUG_RETURN(ret); } +/* + Test if diff is present. This is needed on Windows systems + as the OS returns 1 whether diff is successful or if it is + not present. + + We run diff -v and look for output in stdout. + We don't redirect stderr to stdout to make for a simplified check + Windows will output '"diff"' is not recognized... to stderr if it is + not present. +*/ + +int diff_check() +{ + char buf[512]= {0}; + FILE *res_file; + char *cmd = "diff -v"; + int have_diff = 0; + + if (!(res_file= popen(cmd, "r"))) + die("popen(\"%s\", \"r\") failed", cmd); + +/* if diff is not present, nothing will be in stdout to increment have_diff */ + if (fgets(buf, sizeof(buf), res_file)) + { + have_diff += 1; + } + pclose(res_file); + return have_diff; +} /* Show the diff of two files using the systems builtin diff @@ -1348,34 +1377,51 @@ void show_diff(DYNAMIC_STRING* ds, { DYNAMIC_STRING ds_tmp; + int have_diff = 0; if (init_dynamic_string(&ds_tmp, "", 256, 256)) die("Out of memory"); + + /* determine if we have diff on Windows + needs special processing due to return values + on that OS + */ + have_diff = diff_check(); - /* First try with unified diff */ - if (run_tool("diff", - &ds_tmp, /* Get output from diff in ds_tmp */ - "-u", - filename1, - filename2, - "2>&1", - NULL) > 1) /* Most "diff" tools return >1 if error */ + if (have_diff) { - dynstr_set(&ds_tmp, ""); - - /* Fallback to context diff with "diff -c" */ + /* First try with unified diff */ if (run_tool("diff", &ds_tmp, /* Get output from diff in ds_tmp */ - "-c", + "-u", filename1, filename2, "2>&1", NULL) > 1) /* Most "diff" tools return >1 if error */ { - /* - Fallback to dump both files to result file and inform - about installing "diff" - */ + dynstr_set(&ds_tmp, ""); + + /* Fallback to context diff with "diff -c" */ + if (run_tool("diff", + &ds_tmp, /* Get output from diff in ds_tmp */ + "-c", + filename1, + filename2, + "2>&1", + NULL) > 1) /* Most "diff" tools return >1 if error */ + { + have_diff= 1; + } + } + } + +if (!(have_diff)) + { + /* + Fallback to dump both files to result file and inform + about installing "diff" + */ + dynstr_set(&ds_tmp, ""); dynstr_append(&ds_tmp, @@ -1399,8 +1445,7 @@ void show_diff(DYNAMIC_STRING* ds, dynstr_append(&ds_tmp, " >>>\n"); cat_file(&ds_tmp, filename2); dynstr_append(&ds_tmp, "<<<<\n"); - } - } + } if (ds) { From 4bd55050adb67b35a4c15c327d06a52535811fe7 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 7 Jan 2009 13:44:32 +0100 Subject: [PATCH 4/5] fix misspelling --- sql/mysqld.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 022dbdbe7e3..1e9d942b1dd 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -230,7 +230,7 @@ extern "C" sig_handler handle_segfault(int sig); #if defined(__linux__) #define ENABLE_TEMP_POOL 1 #else -#define ENABLE_TEMP_TOOL 0 +#define ENABLE_TEMP_POOL 0 #endif /* Constants */ From 88cd7a98a5b52cd9a7c7568c864f73342f0f4d35 Mon Sep 17 00:00:00 2001 From: Timothy Smith Date: Thu, 8 Jan 2009 03:06:54 +0100 Subject: [PATCH 5/5] Fix a few problems after latest bunch of InnoDB snapshot changes: The binlog_innodb test was sensitive to what tests ran before it. Now run FLUSH STATUS before performing operations that need to be checked. sys_var_thd_ulong::update() was improperly casting an option value from ulonglong to ulong before comparing it to the max allowed value. On systems where ulong and ulonglong are of different size, this caused values greater than ULONG_MAX to wrap around (not be truncated to ULONG_MAX, which appears to have been the intention of the original coder), and caused some checks to work incorrectly. This wasn't generally visible to the user, because later checks would prevent the wrapped-around value from being used. But it caused warning messages to differ between 32- and 64-bit platforms. Fix is to just remove the cast. Also added a DBUG_ASSERT to ensure that the value really is capped properly before finally stuffing it into the ulong. --- mysql-test/suite/binlog/r/binlog_innodb.result | 7 ++++--- mysql-test/suite/binlog/t/binlog_innodb.test | 1 + sql/set_var.cc | 5 +++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/mysql-test/suite/binlog/r/binlog_innodb.result b/mysql-test/suite/binlog/r/binlog_innodb.result index 896d8f734fc..919ac33ef35 100644 --- a/mysql-test/suite/binlog/r/binlog_innodb.result +++ b/mysql-test/suite/binlog/r/binlog_innodb.result @@ -113,16 +113,17 @@ master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Xid # # COMMIT /* XID */ DROP TABLE t1; +flush status; show status like "binlog_cache_use"; Variable_name Value -Binlog_cache_use 13 +Binlog_cache_use 0 show status like "binlog_cache_disk_use"; Variable_name Value Binlog_cache_disk_use 0 create table t1 (a int) engine=innodb; show status like "binlog_cache_use"; Variable_name Value -Binlog_cache_use 14 +Binlog_cache_use 1 show status like "binlog_cache_disk_use"; Variable_name Value Binlog_cache_disk_use 1 @@ -131,7 +132,7 @@ delete from t1; commit; show status like "binlog_cache_use"; Variable_name Value -Binlog_cache_use 15 +Binlog_cache_use 2 show status like "binlog_cache_disk_use"; Variable_name Value Binlog_cache_disk_use 1 diff --git a/mysql-test/suite/binlog/t/binlog_innodb.test b/mysql-test/suite/binlog/t/binlog_innodb.test index df99e3786ee..f84fd65226a 100644 --- a/mysql-test/suite/binlog/t/binlog_innodb.test +++ b/mysql-test/suite/binlog/t/binlog_innodb.test @@ -101,6 +101,7 @@ DROP TABLE t1; # Actually this test has nothing to do with innodb per se, it just requires # transactional table. # +flush status; show status like "binlog_cache_use"; show status like "binlog_cache_disk_use"; diff --git a/sql/set_var.cc b/sql/set_var.cc index a371c1113ef..308735f52f2 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1527,14 +1527,14 @@ bool sys_var_thd_ulong::update(THD *thd, set_var *var) ulonglong tmp= var->save_result.ulonglong_value; /* Don't use bigger value than given with --maximum-variable-name=.. */ - if ((ulong) tmp > max_system_variables.*offset) + if (tmp > max_system_variables.*offset) { throw_bounds_warning(thd, TRUE, TRUE, name, (longlong) tmp); tmp= max_system_variables.*offset; } if (option_limits) - tmp= (ulong) fix_unsigned(thd, tmp, option_limits); + tmp= fix_unsigned(thd, tmp, option_limits); #if SIZEOF_LONG < SIZEOF_LONG_LONG else if (tmp > ULONG_MAX) { @@ -1543,6 +1543,7 @@ bool sys_var_thd_ulong::update(THD *thd, set_var *var) } #endif + DBUG_ASSERT(tmp <= ULONG_MAX); if (var->type == OPT_GLOBAL) global_system_variables.*offset= (ulong) tmp; else