summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.bzrignore2
-rw-r--r--client/mysqldump.c4
-rw-r--r--mysql-test/r/empty_user_table.result8
-rw-r--r--mysql-test/r/func_group.result28
-rw-r--r--mysql-test/suite/maria/distinct.result25
-rw-r--r--mysql-test/suite/maria/distinct.test25
-rw-r--r--mysql-test/t/empty_user_table.test18
-rw-r--r--mysql-test/t/func_group.test25
-rw-r--r--mysql-test/t/mysql.test2
-rw-r--r--sql/item.h6
-rw-r--r--sql/item_sum.cc21
-rw-r--r--sql/sql_acl.cc6
-rw-r--r--sql/sql_lex.cc1
-rw-r--r--sql/sql_lex.h3
-rw-r--r--sql/sql_prepare.cc2
-rw-r--r--sql/sql_select.cc3
-rw-r--r--storage/maria/ha_maria.cc4
-rw-r--r--storage/maria/ma_blockrec.c67
-rw-r--r--storage/maria/ma_blockrec.h4
-rw-r--r--storage/maria/ma_delete.c1
-rw-r--r--storage/maria/ma_scan.c3
-rw-r--r--storage/maria/ma_update.c1
-rw-r--r--storage/maria/ma_write.c1
-rw-r--r--storage/maria/maria_def.h6
-rw-r--r--tests/mysql_client_test.c110
25 files changed, 343 insertions, 33 deletions
diff --git a/.bzrignore b/.bzrignore
index 37ae77824f8..fa493bd3ede 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -1129,6 +1129,7 @@ cmd-line-utils/libedit/emacs.h
mysql-test/collections/default.release
support-files/plugins.files
client/mysql_plugin
+*.resource.txt
plugin/handler_socket/perl-Net-HandlerSocket/HandlerSocket.c
plugin/handler_socket/perl-Net-HandlerSocket/blib
plugin/handler_socket/perl-Net-HandlerSocket/pm_to_blib
@@ -1145,3 +1146,4 @@ sql/db.opt
./install_manifest_*.txt
typescript
mysql-test/collections/default.release.done
+sql/sql_yacc.hh
diff --git a/client/mysqldump.c b/client/mysqldump.c
index 652dcfb9aab..63e0dc04096 100644
--- a/client/mysqldump.c
+++ b/client/mysqldump.c
@@ -1914,9 +1914,7 @@ static void print_xml_row(FILE *xml_file, const char *row_name,
const char *str_create)
{
uint i;
-#ifndef DBUG_OFF
- my_bool body_found= 0;
-#endif
+ my_bool body_found __attribute__((unused)) = 0;
char *create_stmt_ptr= NULL;
ulong create_stmt_len= 0;
MYSQL_FIELD *field;
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/r/func_group.result b/mysql-test/r/func_group.result
index c6fa040246a..38aa3f49c4d 100644
--- a/mysql-test/r/func_group.result
+++ b/mysql-test/r/func_group.result
@@ -2098,6 +2098,34 @@ avg(export_set( 3, 'y', sha(i))) group_concat(d)
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
+#
# Bug#52123 Assertion failed: aggregator == aggr->Aggrtype(),
# file .\item_sum.cc, line 587
#
diff --git a/mysql-test/suite/maria/distinct.result b/mysql-test/suite/maria/distinct.result
new file mode 100644
index 00000000000..7963e7b72ff
--- /dev/null
+++ b/mysql-test/suite/maria/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 MD5( b );
+MAX( a )
+2
+7
+6
+DROP TABLE t1;
diff --git a/mysql-test/suite/maria/distinct.test b/mysql-test/suite/maria/distinct.test
new file mode 100644
index 00000000000..c71a172597c
--- /dev/null
+++ b/mysql-test/suite/maria/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 MD5( b );
+DROP TABLE t1;
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/mysql-test/t/func_group.test b/mysql-test/t/func_group.test
index 97766fefa91..a5c35c0dff2 100644
--- a/mysql-test/t/func_group.test
+++ b/mysql-test/t/func_group.test
@@ -1380,7 +1380,30 @@ 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;
-#### End of 5.3 tests
+--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
--echo #
--echo # Bug#52123 Assertion failed: aggregator == aggr->Aggrtype(),
diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test
index cad5b67c363..9187cf82513 100644
--- a/mysql-test/t/mysql.test
+++ b/mysql-test/t/mysql.test
@@ -231,7 +231,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/item.h b/sql/item.h
index 891a1500eb1..2b0456bd30c 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -384,6 +384,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 1fed1efc637..4f4d8588a3a 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -65,7 +65,15 @@ ulonglong Item_sum::ram_limitation(THD *thd)
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));
@@ -136,8 +144,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
@@ -172,7 +183,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
@@ -309,9 +320,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 & ((nesting_map)1 << sl->nest_level)))
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index a7b840beb03..1af275f9c7f 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -8301,6 +8301,12 @@ static bool find_mpvio_user(MPVIO_EXT *mpvio)
cs->coll->hash_sort(cs, (uchar*) sctx->user, strlen(sctx->user), &nr1, &nr2);
mysql_mutex_lock(&acl_cache->lock);
+ if (!acl_users.elements)
+ {
+ mysql_mutex_unlock(&acl_cache->lock);
+ login_failed_error(mpvio->thd);
+ DBUG_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);
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index fdf53f7b521..14105de9e59 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1917,6 +1917,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 2f3214646de..2af1ddbf39c 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -887,6 +887,9 @@ public:
*/
List<String> *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();
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 4d1ae0b79b2..dfaab2a2f92 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -879,7 +879,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/sql/sql_select.cc b/sql/sql_select.cc
index d3bfc959176..39512034cba 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -19541,7 +19541,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 722fb059d5f..7958868689b 100644
--- a/storage/maria/ha_maria.cc
+++ b/storage/maria/ha_maria.cc
@@ -2415,7 +2415,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 ab134bbac10..dcfabe7b3a2 100644
--- a/storage/maria/ma_blockrec.c
+++ b/storage/maria/ma_blockrec.c
@@ -4007,6 +4007,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 ||
@@ -4023,7 +4025,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)
{
@@ -5240,11 +5243,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
@@ -5264,15 +5262,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);
}
@@ -5280,15 +5281,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");
@@ -5299,7 +5307,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);
}
@@ -5326,7 +5353,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,
@@ -5345,6 +5372,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;
@@ -5357,13 +5390,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 45f5613bb60..40ca2591236 100644
--- a/storage/maria/ma_blockrec.h
+++ b/storage/maria/ma_blockrec.h
@@ -167,8 +167,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 5b8d0e01677..22f7341098d 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 0a726c1b7f9..e0e804ca655 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 f1649083105..944ae93b17f 100644
--- a/storage/maria/ma_write.c
+++ b/storage/maria/ma_write.c
@@ -298,6 +298,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 1eb720c9607..a588986e4f0 100644
--- a/storage/maria/maria_def.h
+++ b/storage/maria/maria_def.h
@@ -385,7 +385,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) */
@@ -560,6 +560,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;
//typedef ICP_RESULT (*index_cond_func_t)(void *param);
@@ -602,6 +603,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 */
@@ -1291,7 +1293,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"
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c
index d726563f86a..57fde42a92e 100644
--- a/tests/mysql_client_test.c
+++ b/tests/mysql_client_test.c
@@ -17740,7 +17740,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
@@ -18851,6 +18855,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 },
@@ -19116,6 +19223,7 @@ static struct my_tests_st my_tests[]= {
{ "test_progress_reporting", test_progress_reporting },
{ "test_bug11754979", test_bug11754979 },
{ "test_bug13001491", test_bug13001491 },
+ { "test_mdev4326", test_mdev4326 },
{ 0, 0 }
};