diff options
author | unknown <anozdrin/alik@booka.> | 2006-07-28 02:49:18 +0400 |
---|---|---|
committer | unknown <anozdrin/alik@booka.> | 2006-07-28 02:49:18 +0400 |
commit | d36f57813094135cf4cf7f4ab3ca275714b9c44c (patch) | |
tree | c10c09a840456bf62d7906ab2295f10857cf900b | |
parent | 3c108584740ca89fb77c7f002c67982abb86651c (diff) | |
download | mariadb-git-d36f57813094135cf4cf7f4ab3ca275714b9c44c.tar.gz |
Fix for BUG#20438: CREATE statements for views, stored routines and triggers
can be not replicable.
Now CREATE statements for writing in the binlog are created as follows:
- the beginning of the statement is re-created;
- the rest of the statement is copied from the original query.
The problem appears when there is a version-specific comment (produced by
mysqldump), started in the re-created part of the statement and closed in the
copied part -- there is closing comment-parenthesis, but there is no opening
one.
The proper fix could be to re-create original statement, but we can not
implement it in 5.0. So, for 5.0 the fix is just to cut closing
comment-parenthesis. This technique is also used for SHOW CREATE PROCEDURE
statement (so we are able to reuse existing code).
mysql-test/r/rpl_sp.result:
Updated result file.
mysql-test/r/rpl_trigger.result:
Updated result file.
mysql-test/r/rpl_view.result:
Updated result file.
mysql-test/t/rpl_sp.test:
Added test case for BUG#20438.
mysql-test/t/rpl_trigger.test:
Added test case for BUG#20438.
mysql-test/t/rpl_view.test:
Added test case for BUG#20438.
sql/sp.cc:
Trim comments at the end.
sql/sp_head.cc:
Moved this code to the separate function to be re-used.
sql/sql_lex.cc:
Added a new function.
sql/sql_lex.h:
Added a new function.
sql/sql_trigger.cc:
Trim comments at the end.
sql/sql_view.cc:
Trim comments at the end.
-rw-r--r-- | mysql-test/r/rpl_sp.result | 44 | ||||
-rw-r--r-- | mysql-test/r/rpl_trigger.result | 47 | ||||
-rw-r--r-- | mysql-test/r/rpl_view.result | 37 | ||||
-rw-r--r-- | mysql-test/t/rpl_sp.test | 80 | ||||
-rw-r--r-- | mysql-test/t/rpl_trigger.test | 92 | ||||
-rw-r--r-- | mysql-test/t/rpl_view.test | 84 | ||||
-rw-r--r-- | sql/sp.cc | 5 | ||||
-rw-r--r-- | sql/sp_head.cc | 5 | ||||
-rw-r--r-- | sql/sql_lex.cc | 24 | ||||
-rw-r--r-- | sql/sql_lex.h | 2 | ||||
-rw-r--r-- | sql/sql_trigger.cc | 5 | ||||
-rw-r--r-- | sql/sql_view.cc | 6 |
12 files changed, 422 insertions, 9 deletions
diff --git a/mysql-test/r/rpl_sp.result b/mysql-test/r/rpl_sp.result index 5dfda16c763..7b096b27733 100644 --- a/mysql-test/r/rpl_sp.result +++ b/mysql-test/r/rpl_sp.result @@ -420,4 +420,48 @@ SELECT * FROM t1; col test DROP PROCEDURE p1; + +---> Test for BUG#20438 + +---> Preparing environment... +---> connection: master +DROP PROCEDURE IF EXISTS p1; +DROP FUNCTION IF EXISTS f1; + +---> Synchronizing slave with master... + +---> connection: master + +---> Creating procedure... +/*!50003 CREATE PROCEDURE p1() SET @a = 1 */; +/*!50003 CREATE FUNCTION f1() RETURNS INT RETURN 0 */; + +---> Checking on master... +SHOW CREATE PROCEDURE p1; +Procedure sql_mode Create Procedure +p1 CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`() +SET @a = 1 +SHOW CREATE FUNCTION f1; +Function sql_mode Create Function +f1 CREATE DEFINER=`root`@`localhost` FUNCTION `f1`() RETURNS int(11) +RETURN 0 + +---> Synchronizing slave with master... +---> connection: master + +---> Checking on slave... +SHOW CREATE PROCEDURE p1; +Procedure sql_mode Create Procedure +p1 CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`() +SET @a = 1 +SHOW CREATE FUNCTION f1; +Function sql_mode Create Function +f1 CREATE DEFINER=`root`@`localhost` FUNCTION `f1`() RETURNS int(11) +RETURN 0 + +---> connection: master + +---> Cleaning up... +DROP PROCEDURE p1; +DROP FUNCTION f1; drop table t1; diff --git a/mysql-test/r/rpl_trigger.result b/mysql-test/r/rpl_trigger.result index 3e4a3349e13..49f0f5c4c44 100644 --- a/mysql-test/r/rpl_trigger.result +++ b/mysql-test/r/rpl_trigger.result @@ -896,3 +896,50 @@ Tables_in_test (t_) SHOW TRIGGERS; Trigger Event Table Statement Timing Created sql_mode Definer RESET MASTER; +START SLAVE; + +---> Test for BUG#20438 + +---> Preparing environment... +---> connection: master +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; + +---> Synchronizing slave with master... + +---> connection: master + +---> Creating objects... +CREATE TABLE t1(c INT); +CREATE TABLE t2(c INT); +/*!50003 CREATE TRIGGER t1_bi BEFORE INSERT ON t1 +FOR EACH ROW +INSERT INTO t2 VALUES(NEW.c * 10) */; + +---> Inserting value... +INSERT INTO t1 VALUES(1); + +---> Checking on master... +SELECT * FROM t1; +c +1 +SELECT * FROM t2; +c +10 + +---> Synchronizing slave with master... +---> connection: master + +---> Checking on slave... +SELECT * FROM t1; +c +1 +SELECT * FROM t2; +c +10 + +---> connection: master + +---> Cleaning up... +DROP TABLE t1; +DROP TABLE t2; diff --git a/mysql-test/r/rpl_view.result b/mysql-test/r/rpl_view.result index cf4c161b296..5a101defe38 100644 --- a/mysql-test/r/rpl_view.result +++ b/mysql-test/r/rpl_view.result @@ -54,3 +54,40 @@ slave-bin.000001 # Query 1 # use `test`; delete from v1 where a=2 slave-bin.000001 # Query 1 # use `test`; ALTER ALGORITHM=UNDEFINED DEFINER=root@localhost SQL SECURITY DEFINER VIEW v1 AS select a as b from t1 slave-bin.000001 # Query 1 # use `test`; drop view v1 slave-bin.000001 # Query 1 # use `test`; drop table t1 + +---> Test for BUG#20438 + +---> Preparing environment... +---> connection: master +DROP TABLE IF EXISTS t1; +DROP VIEW IF EXISTS v1; + +---> Synchronizing slave with master... + +---> connection: master + +---> Creating objects... +CREATE TABLE t1(c INT); +/*!50003 CREATE VIEW v1 AS SELECT * FROM t1 */; + +---> Inserting value... +INSERT INTO t1 VALUES(1); + +---> Checking on master... +SELECT * FROM t1; +c +1 + +---> Synchronizing slave with master... +---> connection: master + +---> Checking on slave... +SELECT * FROM t1; +c +1 + +---> connection: master + +---> Cleaning up... +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/t/rpl_sp.test b/mysql-test/t/rpl_sp.test index 8be17be3822..7479794eded 100644 --- a/mysql-test/t/rpl_sp.test +++ b/mysql-test/t/rpl_sp.test @@ -435,6 +435,86 @@ connection master; DROP PROCEDURE p1; + +# +# BUG#20438: CREATE statements for views, stored routines and triggers can be +# not replicable. +# + +--echo +--echo ---> Test for BUG#20438 + +# Prepare environment. + +--echo +--echo ---> Preparing environment... +--echo ---> connection: master +--connection master + +--disable_warnings +DROP PROCEDURE IF EXISTS p1; +DROP FUNCTION IF EXISTS f1; +--enable_warnings + +--echo +--echo ---> Synchronizing slave with master... + +--save_master_pos +--connection slave +--sync_with_master + +--echo +--echo ---> connection: master +--connection master + +# Test. + +--echo +--echo ---> Creating procedure... + +/*!50003 CREATE PROCEDURE p1() SET @a = 1 */; + +/*!50003 CREATE FUNCTION f1() RETURNS INT RETURN 0 */; + +--echo +--echo ---> Checking on master... + +SHOW CREATE PROCEDURE p1; +SHOW CREATE FUNCTION f1; + +--echo +--echo ---> Synchronizing slave with master... + +--save_master_pos +--connection slave +--sync_with_master + +--echo ---> connection: master + +--echo +--echo ---> Checking on slave... + +SHOW CREATE PROCEDURE p1; +SHOW CREATE FUNCTION f1; + +# Cleanup. + +--echo +--echo ---> connection: master +--connection master + +--echo +--echo ---> Cleaning up... + +DROP PROCEDURE p1; +DROP FUNCTION f1; + +--save_master_pos +--connection slave +--sync_with_master +--connection master + + # cleanup connection master; drop table t1; diff --git a/mysql-test/t/rpl_trigger.test b/mysql-test/t/rpl_trigger.test index 35f0a0b0a4b..3c8cbb97b31 100644 --- a/mysql-test/t/rpl_trigger.test +++ b/mysql-test/t/rpl_trigger.test @@ -331,6 +331,98 @@ SHOW TRIGGERS; RESET MASTER; +# Restart slave. + +connection slave; +START SLAVE; + + +# +# BUG#20438: CREATE statements for views, stored routines and triggers can be +# not replicable. +# + +--echo +--echo ---> Test for BUG#20438 + +# Prepare environment. + +--echo +--echo ---> Preparing environment... +--echo ---> connection: master +--connection master + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +--enable_warnings + +--echo +--echo ---> Synchronizing slave with master... + +--save_master_pos +--connection slave +--sync_with_master + +--echo +--echo ---> connection: master +--connection master + +# Test. + +--echo +--echo ---> Creating objects... + +CREATE TABLE t1(c INT); +CREATE TABLE t2(c INT); + +/*!50003 CREATE TRIGGER t1_bi BEFORE INSERT ON t1 + FOR EACH ROW + INSERT INTO t2 VALUES(NEW.c * 10) */; + +--echo +--echo ---> Inserting value... + +INSERT INTO t1 VALUES(1); + +--echo +--echo ---> Checking on master... + +SELECT * FROM t1; +SELECT * FROM t2; + +--echo +--echo ---> Synchronizing slave with master... + +--save_master_pos +--connection slave +--sync_with_master + +--echo ---> connection: master + +--echo +--echo ---> Checking on slave... + +SELECT * FROM t1; +SELECT * FROM t2; + +# Cleanup. + +--echo +--echo ---> connection: master +--connection master + +--echo +--echo ---> Cleaning up... + +DROP TABLE t1; +DROP TABLE t2; + +--save_master_pos +--connection slave +--sync_with_master +--connection master + # # End of tests diff --git a/mysql-test/t/rpl_view.test b/mysql-test/t/rpl_view.test index 0a0c6a6dddb..d0990b4fbee 100644 --- a/mysql-test/t/rpl_view.test +++ b/mysql-test/t/rpl_view.test @@ -45,3 +45,87 @@ drop table t1; sync_slave_with_master; --replace_column 2 # 5 # show binlog events limit 1,100; + + + +# +# BUG#20438: CREATE statements for views, stored routines and triggers can be +# not replicable. +# + +--echo +--echo ---> Test for BUG#20438 + +# Prepare environment. + +--echo +--echo ---> Preparing environment... +--echo ---> connection: master +--connection master + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP VIEW IF EXISTS v1; +--enable_warnings + +--echo +--echo ---> Synchronizing slave with master... + +--save_master_pos +--connection slave +--sync_with_master + +--echo +--echo ---> connection: master +--connection master + +# Test. + +--echo +--echo ---> Creating objects... + +CREATE TABLE t1(c INT); + +/*!50003 CREATE VIEW v1 AS SELECT * FROM t1 */; + +--echo +--echo ---> Inserting value... + +INSERT INTO t1 VALUES(1); + +--echo +--echo ---> Checking on master... + +SELECT * FROM t1; + +--echo +--echo ---> Synchronizing slave with master... + +--save_master_pos +--connection slave +--sync_with_master + +--echo ---> connection: master + +--echo +--echo ---> Checking on slave... + +SELECT * FROM t1; + +# Cleanup. + +--echo +--echo ---> connection: master +--connection master + +--echo +--echo ---> Cleaning up... + +DROP VIEW v1; +DROP TABLE t1; + +--save_master_pos +--connection slave +--sync_with_master +--connection master + diff --git a/sql/sp.cc b/sql/sp.cc index b5a4f8bad8f..e8d36e15fa2 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -633,7 +633,10 @@ db_create_routine(THD *thd, int type, sp_head *sp) log_query.append(STRING_WITH_LEN("CREATE ")); append_definer(thd, &log_query, &thd->lex->definer->user, &thd->lex->definer->host); - log_query.append(thd->lex->stmt_definition_begin); + log_query.append(thd->lex->stmt_definition_begin, + (char *)sp->m_body_begin - + thd->lex->stmt_definition_begin + + sp->m_body.length); /* Such a statement can always go directly to binlog, no trans cache */ Query_log_event qinfo(thd, log_query.c_ptr(), log_query.length(), 0, diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 7bcadde2760..eec6e0fc3cd 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -527,10 +527,7 @@ sp_head::init_strings(THD *thd, LEX *lex) Trim "garbage" at the end. This is sometimes needed with the "/ * ! VERSION... * /" wrapper in dump files. */ - while (m_body_begin < endp && - (endp[-1] <= ' ' || endp[-1] == '*' || - endp[-1] == '/' || endp[-1] == ';')) - endp-= 1; + endp= skip_rear_comments(m_body_begin, endp); m_body.length= endp - m_body_begin; m_body.str= strmake_root(root, (char *)m_body_begin, m_body.length); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index efbf29cf207..bb66fde79fe 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1054,6 +1054,30 @@ int MYSQLlex(void *arg, void *yythd) } } + +/* + Skip comment in the end of statement. + + SYNOPSIS + skip_rear_comments() + begin pointer to the beginning of statement + end pointer to the end of statement + + DESCRIPTION + The function is intended to trim comments at the end of the statement. + + RETURN + Pointer to the last non-comment symbol of the statement. +*/ + +uchar *skip_rear_comments(uchar *begin, uchar *end) +{ + while (begin < end && (end[-1] <= ' ' || end[-1] == '*' || + end[-1] == '/' || end[-1] == ';')) + end-= 1; + return end; +} + /* st_select_lex structures initialisations */ diff --git a/sql/sql_lex.h b/sql/sql_lex.h index e5b087fc72a..d7438a37d7e 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1115,4 +1115,4 @@ extern void lex_free(void); extern void lex_start(THD *thd, uchar *buf,uint length); extern void lex_end(LEX *lex); extern int MYSQLlex(void *arg, void *yythd); - +extern uchar *skip_rear_comments(uchar *begin, uchar *end); diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index f46c7414fa4..e806dd4a3f3 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -295,7 +295,10 @@ end: append_definer(thd, &log_query, &definer_user, &definer_host); } - log_query.append(thd->lex->stmt_definition_begin); + log_query.append(thd->lex->stmt_definition_begin, + (char *)thd->lex->sphead->m_body_begin - + thd->lex->stmt_definition_begin + + thd->lex->sphead->m_body.length); } /* Such a statement can always go directly to binlog, no trans cache. */ diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 1561ade78af..80cb8970049 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -671,8 +671,10 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, view->query.str= (char*)str.ptr(); view->query.length= str.length()-1; // we do not need last \0 view->source.str= thd->query + thd->lex->create_view_select_start; - view->source.length= (thd->query_length - - thd->lex->create_view_select_start); + view->source.length= (char *)skip_rear_comments((uchar *)view->source.str, + (uchar *)thd->query + + thd->query_length) - + view->source.str; view->file_version= 1; view->calc_md5(md5); view->md5.str= md5; |