From 80c0891588dd8aef2a0e08864b00067ffd9de5ce Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 9 Apr 2013 09:58:51 +0300 Subject: [PATCH 1/8] MDEV-4326 fix. Removed "optimization" which caused preoblems on second execution of PS with string parameter in LIMIT clause. Fixed test_bug43560 to be able to skipp it if connection is UNIX socket. --- sql/sql_prepare.cc | 2 +- tests/mysql_client_test.c | 110 +++++++++++++++++++++++++++++++++++++- 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 0c1c33dcee0..733fc00bf20 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -787,7 +787,7 @@ static bool insert_params_with_log(Prepared_statement *stmt, uchar *null_array, if (param->state == Item_param::NO_VALUE) DBUG_RETURN(1); - if (param->limit_clause_param && param->item_type != Item::INT_ITEM) + if (param->limit_clause_param) { param->set_int(param->val_int(), MY_INT64_NUM_DECIMAL_DIGITS); param->item_type= Item::INT_ITEM; diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 462575ac456..0e18ca12c42 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -16750,7 +16750,11 @@ static void test_bug43560(void) fprintf(stdout, "Skipping test_bug43560: server not DEBUG version\n"); DBUG_VOID_RETURN; } - + if (opt_unix_socket) + { + fprintf(stdout, "Skipping test_bug43560: connected via UNIX socket\n"); + DBUG_VOID_RETURN; + } /* Set up a separate connection for this test to avoid messing up the general MYSQL object used in other subtests. Use TCP protocol to avoid @@ -17541,6 +17545,109 @@ static void test_bug13001491() myquery(rc); } +static void test_mdev4326() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind; + char query[]= "SELECT * FROM mysql.user LIMIT ?"; + char str_data[]= "1"; + unsigned long length= 0; + int int_data= 1; + int rc, count; + my_bool is_null= 0; + my_bool error= 0; + myheader("test_mdev4326"); + + rc= mysql_change_user(mysql, opt_user, opt_password, "mysql"); + myquery(rc); + + rc= mysql_query(mysql, "SET GLOBAL general_log = 1"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + check_stmt(stmt); + + /* Numeric parameter test */ + + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + check_stmt(stmt); + verify_param_count(stmt, 1); + + memset((char *)&bind, 0, sizeof(bind)); + bind.buffer_type= MYSQL_TYPE_LONG; + bind.buffer= (char *)&int_data; + bind.is_null= &is_null; + bind.length= &length; + bind.error= &error; + + rc= mysql_stmt_bind_param(stmt, &bind); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + count= 0; + while (!(rc= mysql_stmt_fetch(stmt))) + count++; + DIE_UNLESS(count == 1); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + count= 0; + while (!(rc= mysql_stmt_fetch(stmt))) + count++; + DIE_UNLESS(count == 1); + int_data= 0; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + count= 0; + while (!(rc= mysql_stmt_fetch(stmt))) + count++; + DIE_UNLESS(count == 0); + rc= mysql_stmt_close(stmt); + check_execute(stmt, rc); + + /* String parameter test */ + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + check_stmt(stmt); + verify_param_count(stmt, 1); + + memset((char *)&bind, 0, sizeof(bind)); + bind.buffer_type= MYSQL_TYPE_STRING; + bind.buffer= (char *)str_data; + length= bind.buffer_length= sizeof(str_data); + bind.is_null= &is_null; + bind.length= &length; + bind.error= &error; + + rc= mysql_stmt_bind_param(stmt, &bind); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + count= 0; + while (!(rc= mysql_stmt_fetch(stmt))) + count++; + DIE_UNLESS(count == 1); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + count= 0; + while (!(rc= mysql_stmt_fetch(stmt))) + count++; + DIE_UNLESS(count == 1); + str_data[0]= '0'; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + count= 0; + while (!(rc= mysql_stmt_fetch(stmt))) + count++; + DIE_UNLESS(count == 0); + rc= mysql_stmt_close(stmt); + check_execute(stmt, rc); + + rc= mysql_change_user(mysql, opt_user, opt_password, current_db); + myquery(rc); +} static struct my_tests_st my_tests[]= { { "disable_query_logs", disable_query_logs }, @@ -17790,6 +17897,7 @@ static struct my_tests_st my_tests[]= { { "test_bug58036", test_bug58036 }, { "test_bug56976", test_bug56976 }, { "test_bug13001491", test_bug13001491 }, + { "test_mdev4326", test_mdev4326 }, { 0, 0 } }; From 682c8a36ca503f53db50628463424f205b609ab0 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 3 May 2013 16:07:13 +0300 Subject: [PATCH 2/8] MDEV-4290: Fix agregate function resolution in derived tables (no name resolution over a derived table border) --- mysql-test/r/func_group.result | 28 ++++++++++++++++++++++++++++ mysql-test/t/func_group.test | 24 ++++++++++++++++++++++++ sql/item.h | 6 ++++++ sql/item_sum.cc | 21 ++++++++++++++++----- sql/sql_lex.cc | 1 + sql/sql_lex.h | 3 +++ 6 files changed, 78 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index bd77f800f67..5fa37f577e9 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -2097,3 +2097,31 @@ avg(export_set( 3, 'y', sha(i))) group_concat(d) 0 2008-10-02 0 2010-12-12 drop table t1; +# +# MDEV-4290: crash in st_select_lex::mark_as_dependent +# +create table `t1`(`a` int); +select 1 from t1 v1 right join t1 on count(*); +ERROR HY000: Invalid use of group function +select 1 from t1 order by +( +select 1 from +( +select 1 from t1 v1 right join t1 on count(*) +) v +); +ERROR HY000: Invalid use of group function +insert into t1 values (1),(1),(2),(2); +select count(*) from t1; +count(*) +4 +select z from (select count(*) as z from t1) v; +z +4 +# next is how it implemented now (may be changed in case of dependent +# derived tables) +select z from (select count(*) as z from t1) v group by 1; +z +4 +drop table t1; +# end of 5.3 tests diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index fef4d3b1de2..9f0d7e102da 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -1380,3 +1380,27 @@ insert into t1 values (1, '2008-10-02'), (2, '2010-12-12'); select avg(export_set( 3, 'y', sha(i))), group_concat(d) from t1 group by d order by i; drop table t1; +--echo # +--echo # MDEV-4290: crash in st_select_lex::mark_as_dependent +--echo # +create table `t1`(`a` int); + +--error ER_INVALID_GROUP_FUNC_USE +select 1 from t1 v1 right join t1 on count(*); +--error ER_INVALID_GROUP_FUNC_USE +select 1 from t1 order by +( + select 1 from + ( + select 1 from t1 v1 right join t1 on count(*) + ) v +); +insert into t1 values (1),(1),(2),(2); +select count(*) from t1; +select z from (select count(*) as z from t1) v; +--echo # next is how it implemented now (may be changed in case of dependent +--echo # derived tables) +select z from (select count(*) as z from t1) v group by 1; +drop table t1; + +--echo # end of 5.3 tests diff --git a/sql/item.h b/sql/item.h index 1e35c7839de..1938273c261 100644 --- a/sql/item.h +++ b/sql/item.h @@ -353,6 +353,12 @@ struct Name_resolution_context: Sql_alloc { (*error_processor)(thd, error_processor_data); } + st_select_lex *outer_select() + { + return (outer_context ? + outer_context->select_lex : + NULL); + } }; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 3f2020efeb5..489c0f1c23e 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -53,7 +53,15 @@ bool Item_sum::init_sum_func_check(THD *thd) { - if (!thd->lex->allow_sum_func) + SELECT_LEX *curr_sel= thd->lex->current_select; + if (!curr_sel->name_visibility_map) + { + for (SELECT_LEX *sl= curr_sel; sl; sl= sl->context.outer_select()) + { + curr_sel->name_visibility_map|= (1 << sl-> nest_level); + } + } + if (!(thd->lex->allow_sum_func & curr_sel->name_visibility_map)) { my_message(ER_INVALID_GROUP_FUNC_USE, ER(ER_INVALID_GROUP_FUNC_USE), MYF(0)); @@ -124,8 +132,11 @@ bool Item_sum::init_sum_func_check(THD *thd) bool Item_sum::check_sum_func(THD *thd, Item **ref) { + SELECT_LEX *curr_sel= thd->lex->current_select; + nesting_map allow_sum_func= (thd->lex->allow_sum_func & + curr_sel->name_visibility_map); bool invalid= FALSE; - nesting_map allow_sum_func= thd->lex->allow_sum_func; + DBUG_ASSERT(curr_sel->name_visibility_map); // should be set already /* The value of max_arg_level is updated if an argument of the set function contains a column reference resolved against a subquery whose level is @@ -158,7 +169,7 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref) if (!invalid && aggr_level < 0) { aggr_level= nest_level; - aggr_sel= thd->lex->current_select; + aggr_sel= curr_sel; } /* By this moment we either found a subquery where the set function is @@ -295,9 +306,9 @@ bool Item_sum::register_sum_func(THD *thd, Item **ref) { SELECT_LEX *sl; nesting_map allow_sum_func= thd->lex->allow_sum_func; - for (sl= thd->lex->current_select->master_unit()->outer_select() ; + for (sl= thd->lex->current_select->context.outer_select() ; sl && sl->nest_level > max_arg_level; - sl= sl->master_unit()->outer_select() ) + sl= sl->context.outer_select()) { if (aggr_level < 0 && (allow_sum_func & (1 << sl->nest_level))) { diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 5bacb675644..ab50ad99c28 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1690,6 +1690,7 @@ void st_select_lex::init_select() merged_into= 0; m_non_agg_field_used= false; m_agg_func_used= false; + name_visibility_map= 0; } /* diff --git a/sql/sql_lex.h b/sql/sql_lex.h index a3240d3bcab..4b4496a7df8 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -783,6 +783,9 @@ public: */ List *prev_join_using; + /* namp of nesting SELECT visibility (for aggregate functions check) */ + nesting_map name_visibility_map; + void init_query(); void init_select(); st_select_lex_unit* master_unit(); From 4a0f2563d3d1747a4704e6241380071efbeb3882 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 8 May 2013 14:32:32 +0200 Subject: [PATCH 3/8] MDEV-4462 mysqld gets SIGFPE when mysql.user table is empty avoid divison by zero --- mysql-test/r/empty_user_table.result | 8 ++++++++ mysql-test/t/empty_user_table.test | 18 ++++++++++++++++++ sql/sql_acl.cc | 6 ++++++ 3 files changed, 32 insertions(+) create mode 100644 mysql-test/r/empty_user_table.result create mode 100644 mysql-test/t/empty_user_table.test diff --git a/mysql-test/r/empty_user_table.result b/mysql-test/r/empty_user_table.result new file mode 100644 index 00000000000..df9d803e5c0 --- /dev/null +++ b/mysql-test/r/empty_user_table.result @@ -0,0 +1,8 @@ +create table t1 as select * from mysql.user; +truncate table mysql.user; +flush privileges; +connect(localhost,u1,,test,MASTER_PORT,MASTER_SOCKET); +ERROR 28000: Access denied for user 'u1'@'localhost' (using password: NO) +insert mysql.user select * from t1; +drop table t1; +flush privileges; diff --git a/mysql-test/t/empty_user_table.test b/mysql-test/t/empty_user_table.test new file mode 100644 index 00000000000..7e672cc64f6 --- /dev/null +++ b/mysql-test/t/empty_user_table.test @@ -0,0 +1,18 @@ +# +# MDEV-4462 mysqld gets SIGFPE when mysql.user table is empty +# + +source include/not_embedded.inc; + +create table t1 as select * from mysql.user; +truncate table mysql.user; +flush privileges; + +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--error ER_ACCESS_DENIED_ERROR +connect (fail,localhost,u1); + +insert mysql.user select * from t1; +drop table t1; +flush privileges; + diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 29922aa5321..9983c52abb5 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -7367,6 +7367,12 @@ static bool find_mpvio_user(MPVIO_EXT *mpvio, Security_context *sctx) cs->coll->hash_sort(cs, (uchar*) sctx->user, strlen(sctx->user), &nr1, &nr2); pthread_mutex_lock(&acl_cache->lock); + if (!acl_users.elements) + { + pthread_mutex_unlock(&acl_cache->lock); + login_failed_error(mpvio->thd); + return 1; + } uint i= nr1 % acl_users.elements; ACL_USER *acl_user_tmp= dynamic_element(&acl_users, i, ACL_USER*); mpvio->acl_user= acl_user_tmp->copy(mpvio->thd->mem_root); From 4e9bf37f1f70ddc0c901760e4302dd4040a2730c Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Sat, 11 May 2013 15:55:11 +0300 Subject: [PATCH 4/8] MDEV-4280: Assertion `empty_size == empty_size_on_page' failure in ma_blockrec.c or ER_NOT_KEYFILE on query with DISTINCT and GROUP BY This could happen when using Aria for internal temporary files (default case) and using DISTINCT. _ma_scan_restore_block_record() didn't work correctly if there was rows inserted, updated or deleted on the handler between calls to _ma_scan_remember_block_record() and _ma_scan_restore_block_record(). The effect was that some DISTINCT queries that used remove_dup_with_compare() could fail. .bzrignore: Ignore sql_yacc.hh mysql-test/suite/maria/r/distinct.result: Test case for MDEV-4280 mysql-test/suite/maria/t/distinct.test: Test case for MDEV-4280 mysql-test/t/mysql.test: Fixed test suite (we could get error -1 in some cases) sql/sql_select.cc: Break loop if restart_rnd_next() gives an error storage/maria/ha_maria.cc: scan_restore_pos() can return disk fault error. storage/maria/ma_blockrec.c: _ma_scan_remember_block_record() did incorrectly update scan.dir instead of scan_save.dir . _ma_scan_restore_block_record() didn't work correctly if there was rows inserted,updated or deleted on the handler between calls to _ma_scan_remember_block_record() and _ma_scan_restore_block_record(). Fixed by adding counters for row changes and reading the current scan page if changes had been made. storage/maria/ma_blockrec.h: scan_restore_pos() can return disk fault error. storage/maria/ma_delete.c: Increment row_changes storage/maria/ma_scan.c: scan_restore_pos() can return disk fault error. storage/maria/ma_update.c: Increment row_changes storage/maria/ma_write.c: Increment row_changes storage/maria/maria_def.h: scan_restore_pos() can return disk fault error. --- .bzrignore | 1 + mysql-test/suite/maria/r/distinct.result | 25 +++++++++ mysql-test/suite/maria/t/distinct.test | 25 +++++++++ mysql-test/t/mysql.test | 2 +- sql/sql_select.cc | 3 +- storage/maria/ha_maria.cc | 4 +- storage/maria/ma_blockrec.c | 67 +++++++++++++++++++----- storage/maria/ma_blockrec.h | 4 +- storage/maria/ma_delete.c | 1 + storage/maria/ma_scan.c | 3 +- storage/maria/ma_update.c | 1 + storage/maria/ma_write.c | 1 + storage/maria/maria_def.h | 6 ++- 13 files changed, 121 insertions(+), 22 deletions(-) create mode 100644 mysql-test/suite/maria/r/distinct.result create mode 100644 mysql-test/suite/maria/t/distinct.test diff --git a/.bzrignore b/.bzrignore index 84ebe547912..5d89804d637 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1957,3 +1957,4 @@ CPackSourceConfig.cmake win/nmake_cache.txt *.manifest *.resource.txt +sql/sql_yacc.hh diff --git a/mysql-test/suite/maria/r/distinct.result b/mysql-test/suite/maria/r/distinct.result new file mode 100644 index 00000000000..04d5e3d6a2c --- /dev/null +++ b/mysql-test/suite/maria/r/distinct.result @@ -0,0 +1,25 @@ +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a INT, b INT) ENGINE=Aria; +INSERT t1 VALUES (3,2004),(2,2006),(1,2007),(3,2008),(2,2005),(2,2001); +SELECT GROUP_CONCAT(a) FROM t1 GROUP BY b; +GROUP_CONCAT(a) +2 +3 +2 +2 +1 +3 +SELECT DISTINCT GROUP_CONCAT(a) FROM t1 GROUP BY b; +GROUP_CONCAT(a) +2 +3 +1 +DROP TABLE t1; +CREATE TABLE t1 (a INT, b VARCHAR(1)) ENGINE=MyISAM; +INSERT INTO t1 VALUES (7,'q'),(2,NULL),(7,'g'),(6,'x'); +SELECT DISTINCT MAX( a ) FROM t1 GROUP BY b ORDER BY DES_DECRYPT( b ); +MAX( a ) +2 +7 +6 +DROP TABLE t1; diff --git a/mysql-test/suite/maria/t/distinct.test b/mysql-test/suite/maria/t/distinct.test new file mode 100644 index 00000000000..b30d97b8383 --- /dev/null +++ b/mysql-test/suite/maria/t/distinct.test @@ -0,0 +1,25 @@ +# +# MDEV-4280: +# Assertion `empty_size == empty_size_on_page' failure in ma_blockrec.c or +# ER_NOT_KEYFILE on query with DISTINCT and GROUP BY +# +# This issue was a bug in how we delete row during duplicate removal when +# we use Aria for internal temporary table. +# + +-- source include/have_maria.inc + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (a INT, b INT) ENGINE=Aria; +INSERT t1 VALUES (3,2004),(2,2006),(1,2007),(3,2008),(2,2005),(2,2001); +SELECT GROUP_CONCAT(a) FROM t1 GROUP BY b; +SELECT DISTINCT GROUP_CONCAT(a) FROM t1 GROUP BY b; +DROP TABLE t1; + +CREATE TABLE t1 (a INT, b VARCHAR(1)) ENGINE=MyISAM; +INSERT INTO t1 VALUES (7,'q'),(2,NULL),(7,'g'),(6,'x'); +SELECT DISTINCT MAX( a ) FROM t1 GROUP BY b ORDER BY DES_DECRYPT( b ); +DROP TABLE t1; diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index dc6c8cf9be7..4ed776f1987 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -224,7 +224,7 @@ drop table t17583; --exec $MYSQL test -e "connect test invalid_hostname" 2>&1 --echo The commands reported in the bug report ---replace_regex /\([0-9]*\)/(errno)/ +--replace_regex /\([0-9|-]*\)/(errno)/ --error 1 --exec $MYSQL test -e "\r\r\n\r\n cyril\ has\ found\ a\ bug\ :)XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 2>&1 diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 24ca1ab0174..b76e8afac36 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -14656,7 +14656,8 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field, if (!found) break; // End of file /* Restart search on saved row */ - error=file->restart_rnd_next(record); + if ((error= file->restart_rnd_next(record))) + goto err; } file->extra(HA_EXTRA_NO_CACHE); diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 8b1fe4d05b3..ce308887516 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -2255,7 +2255,9 @@ int ha_maria::remember_rnd_pos() int ha_maria::restart_rnd_next(uchar *buf) { - (*file->s->scan_restore_pos)(file, remember_pos); + int error; + if ((error= (*file->s->scan_restore_pos)(file, remember_pos))) + return error; return rnd_next(buf); } diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c index 71bbb389ca2..73b3326fd28 100644 --- a/storage/maria/ma_blockrec.c +++ b/storage/maria/ma_blockrec.c @@ -4008,6 +4008,8 @@ static int delete_dir_entry(uchar *buff, uint block_size, uint record_number, uint length, empty_space; uchar *dir; DBUG_ENTER("delete_dir_entry"); + DBUG_PRINT("enter", ("record_number: %u number_of_records: %u", + record_number, number_of_records)); #ifdef SANITY_CHECKS if (record_number >= number_of_records || @@ -4024,7 +4026,8 @@ static int delete_dir_entry(uchar *buff, uint block_size, uint record_number, check_directory(buff, block_size, 0, (uint) -1); empty_space= uint2korr(buff + EMPTY_SPACE_OFFSET); dir= dir_entry_pos(buff, block_size, record_number); - length= uint2korr(dir + 2); + length= uint2korr(dir + 2); /* Length of entry we just deleted */ + DBUG_ASSERT(uint2korr(dir) != 0 && length < block_size); if (record_number == number_of_records - 1) { @@ -5230,11 +5233,6 @@ void _ma_scan_end_block_record(MARIA_HA *info) For the moment we can only remember one position, but this is good enough for MySQL usage - @Warning - When this function is called, we assume that the thread is not deleting - or updating the current row before ma_scan_restore_block_record() - is called! - @return @retval 0 ok @retval HA_ERR_WRONG_IN_RECORD Could not allocate memory to hold position @@ -5254,15 +5252,18 @@ int _ma_scan_remember_block_record(MARIA_HA *info, info->scan_save->bitmap_buff= ((uchar*) info->scan_save + ALIGN_SIZE(sizeof(*info->scan_save))); } - /* Point to the last read row */ - *lastpos= info->cur_row.nextpos - 1; - info->scan.dir+= DIR_ENTRY_SIZE; + /* For checking if pages have changed since we last read it */ + info->scan.row_changes= info->row_changes; /* Remember used bitmap and used head page */ bitmap_buff= info->scan_save->bitmap_buff; memcpy(info->scan_save, &info->scan, sizeof(*info->scan_save)); info->scan_save->bitmap_buff= bitmap_buff; memcpy(bitmap_buff, info->scan.bitmap_buff, info->s->block_size * 2); + + /* Point to the last read row */ + *lastpos= info->cur_row.nextpos - 1; + info->scan_save->dir+= DIR_ENTRY_SIZE; DBUG_RETURN(0); } @@ -5270,15 +5271,22 @@ int _ma_scan_remember_block_record(MARIA_HA *info, /** @brief restore scan block it's original values + @return + 0 ok + # error + @note In theory we could swap bitmap buffers instead of copy them. For the moment we don't do that because there are variables pointing inside the buffers and it's a bit of hassle to either make them relative or repoint them. + + If the data file has changed, we will re-read the new block record + to ensure that when we continue scanning we can ignore any deleted rows. */ -void _ma_scan_restore_block_record(MARIA_HA *info, - MARIA_RECORD_POS lastpos) +int _ma_scan_restore_block_record(MARIA_HA *info, + MARIA_RECORD_POS lastpos) { uchar *bitmap_buff; DBUG_ENTER("_ma_scan_restore_block_record"); @@ -5289,7 +5297,26 @@ void _ma_scan_restore_block_record(MARIA_HA *info, info->scan.bitmap_buff= bitmap_buff; memcpy(bitmap_buff, info->scan_save->bitmap_buff, info->s->block_size * 2); - DBUG_VOID_RETURN; + if (info->scan.row_changes != info->row_changes) + { + /* + Table has been changed. We have to re-read the current page block as + data may have changed on it that we have to see. + */ + if (!(pagecache_read(info->s->pagecache, + &info->dfile, + ma_recordpos_to_page(info->scan.row_base_page), + 0, info->scan.page_buff, + info->s->page_type, + PAGECACHE_LOCK_LEFT_UNLOCKED, 0))) + DBUG_RETURN(my_errno); + info->scan.number_of_rows= + (uint) (uchar) info->scan.page_buff[DIR_COUNT_OFFSET]; + info->scan.dir_end= (info->scan.page_buff + info->s->block_size - + PAGE_SUFFIX_SIZE - + info->scan.number_of_rows * DIR_ENTRY_SIZE); + } + DBUG_RETURN(0); } @@ -5316,7 +5343,7 @@ void _ma_scan_restore_block_record(MARIA_HA *info, RETURN 0 ok - # Error code + # Error code (Normally HA_ERR_END_OF_FILE) */ int _ma_scan_block_record(MARIA_HA *info, uchar *record, @@ -5336,6 +5363,12 @@ restart_record_read: uchar *data, *end_of_data; int error; + /* Ensure that scan.dir and record_pos are in sync */ + DBUG_ASSERT(info->scan.dir == dir_entry_pos(info->scan.page_buff, + share->block_size, + record_pos)); + + /* Search for a valid directory entry (not 0) */ while (!(offset= uint2korr(info->scan.dir))) { info->scan.dir-= DIR_ENTRY_SIZE; @@ -5348,13 +5381,19 @@ restart_record_read: } #endif } + /* + This should always be true as the directory should always start with + a valid entry. + */ + DBUG_ASSERT(info->scan.dir >= info->scan.dir_end); + /* found row */ info->cur_row.lastpos= info->scan.row_base_page + record_pos; info->cur_row.nextpos= record_pos + 1; data= info->scan.page_buff + offset; length= uint2korr(info->scan.dir + 2); end_of_data= data + length; - info->scan.dir-= DIR_ENTRY_SIZE; /* Point to previous row */ + info->scan.dir-= DIR_ENTRY_SIZE; /* Point to next row to process */ #ifdef SANITY_CHECKS if (end_of_data > info->scan.dir_end || offset < PAGE_HEADER_SIZE || length < share->base.min_block_length) diff --git a/storage/maria/ma_blockrec.h b/storage/maria/ma_blockrec.h index 2a323d16ffa..f6aae8d4759 100644 --- a/storage/maria/ma_blockrec.h +++ b/storage/maria/ma_blockrec.h @@ -168,8 +168,8 @@ my_bool _ma_scan_init_block_record(MARIA_HA *info); void _ma_scan_end_block_record(MARIA_HA *info); int _ma_scan_remember_block_record(MARIA_HA *info, MARIA_RECORD_POS *lastpos); -void _ma_scan_restore_block_record(MARIA_HA *info, - MARIA_RECORD_POS lastpos); +int _ma_scan_restore_block_record(MARIA_HA *info, + MARIA_RECORD_POS lastpos); MARIA_RECORD_POS _ma_write_init_block_record(MARIA_HA *info, const uchar *record); diff --git a/storage/maria/ma_delete.c b/storage/maria/ma_delete.c index ab66499ecfe..977c7c82cb7 100644 --- a/storage/maria/ma_delete.c +++ b/storage/maria/ma_delete.c @@ -112,6 +112,7 @@ int maria_delete(MARIA_HA *info,const uchar *record) info->state->checksum-= info->cur_row.checksum; info->state->records--; info->update= HA_STATE_CHANGED+HA_STATE_DELETED+HA_STATE_ROW_CHANGED; + info->row_changes++; share->state.changed|= (STATE_NOT_OPTIMIZED_ROWS | STATE_NOT_MOVABLE | STATE_NOT_ZEROFILLED); info->state->changed=1; diff --git a/storage/maria/ma_scan.c b/storage/maria/ma_scan.c index cbac463a2c8..ad526211615 100644 --- a/storage/maria/ma_scan.c +++ b/storage/maria/ma_scan.c @@ -68,7 +68,8 @@ int _ma_def_scan_remember_pos(MARIA_HA *info, MARIA_RECORD_POS *lastpos) } -void _ma_def_scan_restore_pos(MARIA_HA *info, MARIA_RECORD_POS lastpos) +int _ma_def_scan_restore_pos(MARIA_HA *info, MARIA_RECORD_POS lastpos) { info->cur_row.nextpos= lastpos; + return 0; } diff --git a/storage/maria/ma_update.c b/storage/maria/ma_update.c index abd9116a711..80b1fd86782 100644 --- a/storage/maria/ma_update.c +++ b/storage/maria/ma_update.c @@ -173,6 +173,7 @@ int maria_update(register MARIA_HA *info, const uchar *oldrec, uchar *newrec) We can't yet have HA_STATE_AKTIV here, as block_record dosn't support it */ info->update= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED | key_changed); + info->row_changes++; share->state.changed|= STATE_NOT_MOVABLE | STATE_NOT_ZEROFILLED; info->state->changed= 1; diff --git a/storage/maria/ma_write.c b/storage/maria/ma_write.c index b4bf5086e0b..3c5efdc2ef0 100644 --- a/storage/maria/ma_write.c +++ b/storage/maria/ma_write.c @@ -288,6 +288,7 @@ int maria_write(MARIA_HA *info, uchar *record) info->state->records++; info->update= (HA_STATE_CHANGED | HA_STATE_AKTIV | HA_STATE_WRITTEN | HA_STATE_ROW_CHANGED); + info->row_changes++; share->state.changed|= STATE_NOT_MOVABLE | STATE_NOT_ZEROFILLED; info->state->changed= 1; diff --git a/storage/maria/maria_def.h b/storage/maria/maria_def.h index 41501b8eb74..fe9bf10fe24 100644 --- a/storage/maria/maria_def.h +++ b/storage/maria/maria_def.h @@ -317,7 +317,7 @@ typedef struct st_maria_share /* End scan */ void (*scan_end)(MARIA_HA *); int (*scan_remember_pos)(MARIA_HA *, MARIA_RECORD_POS*); - void (*scan_restore_pos)(MARIA_HA *, MARIA_RECORD_POS); + int (*scan_restore_pos)(MARIA_HA *, MARIA_RECORD_POS); /* Pre-write of row (some handlers may do the actual write here) */ MARIA_RECORD_POS (*write_record_init)(MARIA_HA *, const uchar *); /* Write record (or accept write_record_init) */ @@ -492,6 +492,7 @@ typedef struct st_maria_block_scan ulonglong bits; uint number_of_rows, bit_pos; MARIA_RECORD_POS row_base_page; + ulonglong row_changes; } MARIA_BLOCK_SCAN; @@ -533,6 +534,7 @@ struct st_maria_handler int (*read_record)(MARIA_HA *, uchar*, MARIA_RECORD_POS); invalidator_by_filename invalidator; /* query cache invalidator */ ulonglong last_auto_increment; /* auto value at start of statement */ + ulonglong row_changes; /* Incremented for each change */ ulong this_unique; /* uniq filenumber or thread */ ulong last_unique; /* last unique number */ ulong this_loop; /* counter for this open */ @@ -1175,7 +1177,7 @@ my_bool _ma_check_status(void *param); void _ma_restore_status(void *param); void _ma_reset_status(MARIA_HA *maria); int _ma_def_scan_remember_pos(MARIA_HA *info, MARIA_RECORD_POS *lastpos); -void _ma_def_scan_restore_pos(MARIA_HA *info, MARIA_RECORD_POS lastpos); +int _ma_def_scan_restore_pos(MARIA_HA *info, MARIA_RECORD_POS lastpos); #include "ma_commit.h" From 4b9a6c03fafe7f4c1901ba909796a3385184c516 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Sat, 11 May 2013 18:57:06 +0300 Subject: [PATCH 5/8] Fixed compiler warning --- client/mysqldump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index b271cb8429b..ece88a51306 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -1886,7 +1886,7 @@ static void print_xml_row(FILE *xml_file, const char *row_name, const char *str_create) { uint i; - my_bool body_found= 0; + my_bool body_found __attribute__((unused)) = 0; char *create_stmt_ptr= NULL; ulong create_stmt_len= 0; MYSQL_FIELD *field; From 3b3f870994299c905627c7925c4af473e948d78d Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Sat, 11 May 2013 20:23:57 +0300 Subject: [PATCH 6/8] Fixed compiler failure on solaris --- mysys/my_gethwaddr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysys/my_gethwaddr.c b/mysys/my_gethwaddr.c index c96af3f1018..95306e71650 100644 --- a/mysys/my_gethwaddr.c +++ b/mysys/my_gethwaddr.c @@ -101,7 +101,7 @@ my_bool my_gethwaddr(uchar *to) uint i; for (i= 0; res && i < ifc.ifc_len / sizeof(ifr[0]); i++) { -#ifdef SIOCGIFHWADDR +#ifdef __linux__ if (ioctl(fd, SIOCGIFHWADDR, &ifr[i]) >= 0) res= memcpy_and_test(to, (uchar *)&ifr[i].ifr_hwaddr.sa_data, ETHER_ADDR_LEN); From cbd300e7b028ab7716a4e02fa2e5067c4d8ee006 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Sun, 19 May 2013 16:22:33 +0200 Subject: [PATCH 7/8] Fix cpack error - safe_process.pl does not exist anymore. --- mysql-test/lib/My/SafeProcess/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/lib/My/SafeProcess/CMakeLists.txt b/mysql-test/lib/My/SafeProcess/CMakeLists.txt index 6edf9d45683..67755a065ea 100644 --- a/mysql-test/lib/My/SafeProcess/CMakeLists.txt +++ b/mysql-test/lib/My/SafeProcess/CMakeLists.txt @@ -26,4 +26,4 @@ ELSE() MYSQL_ADD_EXECUTABLE(my_safe_process safe_process.cc ${INSTALL_ARGS}) ENDIF() -INSTALL(FILES safe_process.pl Base.pm DESTINATION "${INSTALL_MYSQLTESTDIR}/lib/My/SafeProcess" COMPONENT Test) +INSTALL(FILES Base.pm DESTINATION "${INSTALL_MYSQLTESTDIR}/lib/My/SafeProcess" COMPONENT Test) From dc56d56ce578d32e4bfba23f01a644da97c7ccb6 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Sun, 19 May 2013 16:38:56 +0200 Subject: [PATCH 8/8] MDEV-4544 - update MSI to include HeidiSQL 8.0 --- win/packaging/heidisql.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win/packaging/heidisql.cmake b/win/packaging/heidisql.cmake index f826c9a6633..124f85bb87e 100644 --- a/win/packaging/heidisql.cmake +++ b/win/packaging/heidisql.cmake @@ -1,4 +1,4 @@ -SET(HEIDISQL_BASE_NAME "HeidiSQL_7.0_Portable") +SET(HEIDISQL_BASE_NAME "HeidiSQL_8.0_Portable") SET(HEIDISQL_ZIP "${HEIDISQL_BASE_NAME}.zip") SET(HEIDISQL_URL "http://heidisql.googlecode.com/files/${HEIDISQL_ZIP}") SET(HEIDISQL_DOWNLOAD_DIR ${THIRD_PARTY_DOWNLOAD_LOCATION}/${HEIDISQL_BASE_NAME})