diff --git a/mysql-test/r/rpl_insert_id.result b/mysql-test/r/rpl_insert_id.result index d0360c8b9a3..d133a2ae8ed 100644 --- a/mysql-test/r/rpl_insert_id.result +++ b/mysql-test/r/rpl_insert_id.result @@ -272,6 +272,7 @@ DROP TABLE t1, t2; DROP PROCEDURE IF EXISTS p1; DROP FUNCTION IF EXISTS f1; DROP FUNCTION IF EXISTS f2; +DROP FUNCTION IF EXISTS f3; DROP TABLE IF EXISTS t1, t2; CREATE TABLE t1 ( i INT NOT NULL AUTO_INCREMENT PRIMARY KEY, @@ -295,6 +296,11 @@ RETURN 0; END | CREATE FUNCTION f2() RETURNS INT NOT DETERMINISTIC RETURN LAST_INSERT_ID() | +CREATE FUNCTION f3() RETURNS INT MODIFIES SQL DATA +BEGIN +INSERT INTO t2 (i) VALUES (LAST_INSERT_ID()); +RETURN 0; +END | INSERT INTO t1 VALUES (NULL, -1); CALL p1(); SELECT f1(); @@ -307,6 +313,11 @@ INSERT INTO t1 VALUES (NULL, LAST_INSERT_ID()), (NULL, LAST_INSERT_ID(5)), (NULL, @@LAST_INSERT_ID); INSERT INTO t1 VALUES (NULL, 0), (NULL, LAST_INSERT_ID()); UPDATE t1 SET j= -1 WHERE i IS NULL; +INSERT INTO t1 (i) VALUES (NULL); +INSERT INTO t1 (i) VALUES (NULL); +SELECT f3(); +f3() +0 SELECT * FROM t1; i j 1 -1 @@ -327,12 +338,15 @@ i j 16 13 17 -1 18 14 +19 0 +20 0 SELECT * FROM t2; i 2 3 5 6 +19 SELECT * FROM t1; i j 1 -1 @@ -353,15 +367,19 @@ i j 16 13 17 -1 18 14 +19 0 +20 0 SELECT * FROM t2; i 2 3 5 6 +19 DROP PROCEDURE p1; DROP FUNCTION f1; DROP FUNCTION f2; +DROP FUNCTION f3; DROP TABLE t1, t2; # End of 5.0 tests diff --git a/mysql-test/t/rpl_insert_id.test b/mysql-test/t/rpl_insert_id.test index 126aad68df4..331a913256c 100644 --- a/mysql-test/t/rpl_insert_id.test +++ b/mysql-test/t/rpl_insert_id.test @@ -299,6 +299,7 @@ DROP TABLE t1, t2; DROP PROCEDURE IF EXISTS p1; DROP FUNCTION IF EXISTS f1; DROP FUNCTION IF EXISTS f2; +DROP FUNCTION IF EXISTS f3; DROP TABLE IF EXISTS t1, t2; --enable_warnings @@ -328,6 +329,12 @@ END | CREATE FUNCTION f2() RETURNS INT NOT DETERMINISTIC RETURN LAST_INSERT_ID() | + +CREATE FUNCTION f3() RETURNS INT MODIFIES SQL DATA +BEGIN + INSERT INTO t2 (i) VALUES (LAST_INSERT_ID()); + RETURN 0; +END | delimiter ;| INSERT INTO t1 VALUES (NULL, -1); @@ -342,6 +349,15 @@ INSERT INTO t1 VALUES (NULL, LAST_INSERT_ID()), (NULL, LAST_INSERT_ID(5)), INSERT INTO t1 VALUES (NULL, 0), (NULL, LAST_INSERT_ID()); UPDATE t1 SET j= -1 WHERE i IS NULL; +# Test statement-based replication of function calls. +INSERT INTO t1 (i) VALUES (NULL); + +connection master1; +INSERT INTO t1 (i) VALUES (NULL); + +connection master; +SELECT f3(); + SELECT * FROM t1; SELECT * FROM t2; @@ -353,6 +369,7 @@ connection master; DROP PROCEDURE p1; DROP FUNCTION f1; DROP FUNCTION f2; +DROP FUNCTION f3; DROP TABLE t1, t2; diff --git a/sql/item_func.cc b/sql/item_func.cc index e395a7a3af5..a294bbd7a71 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3362,6 +3362,7 @@ bool Item_func_last_insert_id::fix_fields(THD *thd, Item **ref) id of the previous statement in THD::current_insert_id. */ thd->last_insert_id_used= TRUE; + thd->last_insert_id_used_bin_log= TRUE; thd->current_insert_id= thd->last_insert_id; } null_value= FALSE; diff --git a/sql/log.cc b/sql/log.cc index 1cd01865f9f..98829220f3d 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1702,7 +1702,7 @@ bool MYSQL_LOG::write(Log_event *event_info) if (thd) { - if (thd->last_insert_id_used) + if (thd->last_insert_id_used_bin_log) { Intvar_log_event e(thd,(uchar) LAST_INSERT_ID_EVENT, thd->current_insert_id); @@ -1994,7 +1994,7 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length, tmp_errno=errno; strmov(db,thd->db); } - if (thd->last_insert_id_used) + if (thd->last_insert_id_used_bin_log) { end=strmov(end,",last_insert_id="); end=longlong10_to_str((longlong) thd->current_insert_id,end,-10); diff --git a/sql/set_var.cc b/sql/set_var.cc index d00857a2bc1..783d20bfda1 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2579,6 +2579,7 @@ byte *sys_var_last_insert_id::value_ptr(THD *thd, enum_var_type type, of the previous statement in THD::current_insert_id. */ thd->last_insert_id_used= TRUE; + thd->last_insert_id_used_bin_log= TRUE; thd->current_insert_id= thd->last_insert_id; } return (byte*) &thd->current_insert_id; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 4d47ec338c0..645ac6e28f3 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -179,9 +179,9 @@ THD::THD() lock_id(&main_lock_id), user_time(0), in_sub_stmt(0), global_read_lock(0), is_fatal_error(0), rand_used(0), time_zone_used(0), - last_insert_id_used(0), insert_id_used(0), clear_next_insert_id(0), - in_lock_tables(0), bootstrap(0), derived_tables_processing(FALSE), - spcont(NULL) + last_insert_id_used(0), last_insert_id_used_bin_log(0), insert_id_used(0), + clear_next_insert_id(0), in_lock_tables(0), bootstrap(0), + derived_tables_processing(FALSE), spcont(NULL) { stmt_arena= this; thread_stack= 0; @@ -560,7 +560,7 @@ bool THD::store_globals() THD::cleanup_after_query() DESCRIPTION - This function is used to reset thread data to it's default state. + This function is used to reset thread data to its default state. NOTE This function is not suitable for setting thread data to some @@ -568,6 +568,7 @@ bool THD::store_globals() different master threads may overwrite data of each other on slave. */ + void THD::cleanup_after_query() { last_insert_id_used= FALSE; @@ -582,6 +583,7 @@ void THD::cleanup_after_query() where= THD::DEFAULT_WHERE; } + /* Convert a string to another character set diff --git a/sql/sql_class.h b/sql/sql_class.h index ccc7a661446..d30797a605f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1340,11 +1340,20 @@ public: /* last_insert_id_used is set when current statement calls - LAST_INSERT_ID() or reads @@LAST_INSERT_ID, so that binary log - LAST_INSERT_ID_EVENT be generated. + LAST_INSERT_ID() or reads @@LAST_INSERT_ID. */ bool last_insert_id_used; + /* + last_insert_id_used is set when current statement or any stored + function called from this statement calls LAST_INSERT_ID() or + reads @@LAST_INSERT_ID, so that binary log LAST_INSERT_ID_EVENT be + generated. Required for statement-based binary log for issuing + "SET LAST_INSERT_ID= #" before "SELECT func()", if func() reads + LAST_INSERT_ID. + */ + bool last_insert_id_used_bin_log; + /* insert_id_used is set when current statement updates THD::last_insert_id, so that binary log INSERT_ID_EVENT be diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 1b69e266442..c62c286cfdb 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5651,6 +5651,7 @@ void mysql_reset_thd_for_next_command(THD *thd) thd->free_list= 0; thd->select_number= 1; thd->query_start_used= thd->insert_id_used=0; + thd->last_insert_id_used_bin_log= FALSE; thd->is_fatal_error= thd->time_zone_used= 0; thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS | SERVER_QUERY_NO_INDEX_USED | diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 87cbdef0522..e0deeb7d65e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8154,11 +8154,11 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) 21)))) { /* - Set THD::last_insert_id_used manually, as this statement - uses LAST_INSERT_ID() in a sense, and should issue - LAST_INSERT_ID_EVENT. + Set THD::last_insert_id_used_bin_log manually, as this + statement uses LAST_INSERT_ID() in a sense, and should + issue LAST_INSERT_ID_EVENT. */ - thd->last_insert_id_used= TRUE; + thd->last_insert_id_used_bin_log= TRUE; cond=new_cond; /*