From: Dmitry Shulga Date: May 3 2011 12:03pm Subject: bzr commit into mysql-5.1 branch (Dmitry.Shulga:3667) Bug#45235 Bug#11753738 List-Archive: http://lists.mysql.com/commits/136564 X-Bug: 45235,11753738 Message-Id: <201105031203.p43C3OVS024945@acsmt357.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1791755854461593893==" --===============1791755854461593893== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///Users/shulga/projects/mysql/mysql-5.1-bug11753738/ based on revid:sergey.glukhov@stripped 3667 Dmitry Shulga 2011-05-03 Fixed bug#11753738 (formely known as bug#45235) - 5.1 DOES NOT SUPPORT 5.0-ONLY SYNTAX TRIGGERS IN ANY WAY Table with triggers which were using deprecated (5.0-only) syntax became unavailable for any DML and DDL after upgrade to 5.1 version of server. Attempt to execute any statement on such a table resulted in parsing error reported. Since this included DROP TRIGGER and DROP TABLES statements (actually, the latter was allowed but was not functioning properly for such tables) it was impossible to fix the problem without manual operations on .TRG and .TRN files in data directory. The problem was that failure to parse trigger body (due to 5.0-only syntax) when opening trigger file for a table prevented the table from being open. This made all operations on the table impossible (except DROP TABLE which due to peculiarity in its implementation dropped the table but left trigger files around). This patch solves this problem by silencing error which occurs when we parse trigger body during table open. Error message is preserved for the future use and table is marked as having a broken trigger. We also try to analyze parse tree to recover trigger name, which will be needed in order to drop the broken trigger. DML statements which invoke triggers on the table marked as having broken trigger are prohibited and emit saved error message. The same happens for DDL which change triggers except DROP TRIGGER and DROP TABLE which try their best to do what was requested. Table becomes no longer marked as having broken trigger when last such trigger is dropped. @ mysql-test/r/trigger-compat.result Add results for test case for bug#45235 @ mysql-test/t/trigger-compat.test Add test case for bug#45235. @ sql/sp_head.cc Added protection against mem root double restoring. Since restore_thd_mem_root() can be both in case of normal execution way and in case of error handling we need to protect mem root against second consequenced call to restore_thd_mem_root. This can be occured for example when CREATE TRIGGER SQL-statement being parsed and there is a parsing error in trigger body. @ sql/sql_trigger.cc Bug#45235: - New class to implement error suppression and recovery of trigger name. - Comment correction - Errors for trigger manipulation statements - More comment correction - Fix exploiting new class. - indentation correction. - Split up a conjunction in an assert. - Added code for handling completely broken triggers - More errors for trigger manipulation statements. - Method for setting broken triggers flag & error message. @ sql/sql_trigger.h Bug#45235: New members to handle broken triggers and error messages. modified: mysql-test/r/trigger-compat.result mysql-test/r/trigger.result mysql-test/t/trigger-compat.test sql/sp_head.cc sql/sql_parse.cc sql/sql_trigger.cc sql/sql_trigger.h === modified file 'mysql-test/r/trigger-compat.result' --- a/mysql-test/r/trigger-compat.result 2009-02-19 23:24:25 +0000 +++ b/mysql-test/r/trigger-compat.result 2011-05-03 12:03:10 +0000 @@ -43,3 +43,96 @@ DROP TABLE t2; DROP USER mysqltest_dfn@localhost; DROP USER mysqltest_inv@localhost; DROP DATABASE mysqltest_db1; +USE test; +# +# Bug#45235: 5.1 does not support 5.0-only syntax triggers in any way +# +DROP TABLE IF EXISTS t1, t2, t3; +CREATE TABLE t1 ( a INT ); +CREATE TABLE t2 ( a INT ); +CREATE TABLE t3 ( a INT ); +INSERT INTO t1 VALUES (1), (2), (3); +INSERT INTO t2 VALUES (1), (2), (3); +INSERT INTO t3 VALUES (1), (2), (3); +# We simulate importing a trigger from 5.0 by writing a .TRN file for +# each trigger plus a .TRG file the way MySQL 5.0 would have done it, +# with syntax allowed in 5.0 only. +# +# Note that in 5.0 the following lines are missing from t1.TRG: +# +# client_cs_names='latin1' +# connection_cl_names='latin1_swedish_ci' +# db_cl_names='latin1_swedish_ci' +# We will get parse errors for most DDL and DML statements when the table +# has broken triggers. The parse error refers to the first broken +# trigger. +CREATE TRIGGER tr16 AFTER UPDATE ON t1 FOR EACH ROW INSERT INTO t1 VALUES (1); +ERROR 42000: Trigger 'tr13' has a syntax error in its body: 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'a USING t1 a' at line 1' +CREATE TRIGGER tr22 BEFORE INSERT ON t2 FOR EACH ROW DELETE FROM non_existing_table; +ERROR 42000: Unknown trigger has a syntax error in its body: 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'Not allowed syntax here, and trigger name cant be extracted either.' at line 1' +SHOW TRIGGERS; +Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation +tr11 INSERT t1 DELETE FROM t3 BEFORE NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +tr12 INSERT t1 DELETE FROM t3 AFTER NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +tr14 DELETE t1 DELETE FROM non_existing_table AFTER NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +Warnings: +Warning 1603 Triggers for table `test`.`t1` have no creation context +Warning 1603 Triggers for table `test`.`t2` have no creation context +INSERT INTO t1 VALUES (1); +ERROR 42000: Trigger 'tr13' has a syntax error in its body: 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'a USING t1 a' at line 1' +INSERT INTO t2 VALUES (1); +ERROR 42000: Unknown trigger has a syntax error in its body: 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'Not allowed syntax here, and trigger name cant be extracted either.' at line 1' +DELETE FROM t1; +ERROR 42000: Trigger 'tr13' has a syntax error in its body: 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'a USING t1 a' at line 1' +UPDATE t1 SET a = 1 WHERE a = 1; +ERROR 42000: Trigger 'tr13' has a syntax error in its body: 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'a USING t1 a' at line 1' +SELECT * FROM t1; +a +1 +2 +3 +RENAME TABLE t1 TO t1_2; +ERROR 42000: Trigger 'tr13' has a syntax error in its body: 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'a USING t1 a' at line 1' +SHOW TRIGGERS; +Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation +tr11 INSERT t1 DELETE FROM t3 BEFORE NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +tr12 INSERT t1 DELETE FROM t3 AFTER NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +tr14 DELETE t1 DELETE FROM non_existing_table AFTER NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +Warnings: +Warning 1603 Triggers for table `test`.`t1` have no creation context +DROP TRIGGER tr11; +Warnings: +Warning 1603 Triggers for table `test`.`t1` have no creation context +DROP TRIGGER tr12; +DROP TRIGGER tr13; +DROP TRIGGER tr14; +DROP TRIGGER tr15; +SHOW TRIGGERS; +Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation +# Make sure there is no trigger file left. +# We write the same trigger files one more time to test DROP TABLE. +DROP TABLE t1; +Warnings: +Warning 1603 Triggers for table `test`.`t1` have no creation context +DROP TABLE t2; +Warnings: +Warning 1603 Triggers for table `test`.`t2` have no creation context +DROP TABLE t3; +# Make sure there is no trigger file left. +CREATE TABLE t1 ( a INT ); +CREATE TABLE t2 ( a INT ); +INSERT INTO t1 VALUES (1), (2), (3); +INSERT INTO t2 VALUES (1), (2), (3); +# We write two trigger files. First trigger is correct, second trigger is broken. +# Next we try to execute SHOW CREATE TRGGIR command for broken trigger and then try to drop one. +FLUSH TABLE t1; +SHOW CREATE TRIGGER tr12; +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +tr12 CREATE DEFINER=`root`@`localhost` TRIGGER tr12 BEFORE INSERT ON t1 FOR EACH ROW DELETE FROM t2 latin1 latin1_swedish_ci latin1_swedish_ci +Warnings: +Warning 1603 Triggers for table `test`.`t1` have no creation context +DROP TRIGGER tr12; +Warnings: +Warning 1603 Triggers for table `test`.`t1` have no creation context +DROP TABLE t1; +DROP TABLE t2; === modified file 'mysql-test/r/trigger.result' --- a/mysql-test/r/trigger.result 2010-08-18 04:56:06 +0000 +++ b/mysql-test/r/trigger.result 2011-05-03 12:03:10 +0000 @@ -2134,10 +2134,8 @@ CREATE TRIGGER trg1 BEFORE INSERT ON t2 # Used to crash SHOW TRIGGERS IN db1; Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation -Warnings: -Warning 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'VALUES (1)' at line 1 INSERT INTO t2 VALUES (1); -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'VALUES (1)' at line 1 +ERROR 42000: Trigger 'trg1' has a syntax error in its body: 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'VALUES (1)' at line 1' SELECT * FROM t1; b # Work around Bug#45235 === modified file 'mysql-test/t/trigger-compat.test' --- a/mysql-test/t/trigger-compat.test 2009-02-19 23:24:25 +0000 +++ b/mysql-test/t/trigger-compat.test 2011-05-03 12:03:10 +0000 @@ -106,4 +106,175 @@ DROP TABLE t2; DROP USER mysqltest_dfn@localhost; DROP USER mysqltest_inv@localhost; DROP DATABASE mysqltest_db1; +USE test; + +--echo # +--echo # Bug#45235: 5.1 does not support 5.0-only syntax triggers in any way +--echo # +let $MYSQLD_DATADIR=`SELECT @@datadir`; + +--disable_warnings +DROP TABLE IF EXISTS t1, t2, t3; +--enable_warnings + +CREATE TABLE t1 ( a INT ); +CREATE TABLE t2 ( a INT ); +CREATE TABLE t3 ( a INT ); +INSERT INTO t1 VALUES (1), (2), (3); +INSERT INTO t2 VALUES (1), (2), (3); +INSERT INTO t3 VALUES (1), (2), (3); + +--echo # We simulate importing a trigger from 5.0 by writing a .TRN file for +--echo # each trigger plus a .TRG file the way MySQL 5.0 would have done it, +--echo # with syntax allowed in 5.0 only. +--echo # +--echo # Note that in 5.0 the following lines are missing from t1.TRG: +--echo # +--echo # client_cs_names='latin1' +--echo # connection_cl_names='latin1_swedish_ci' +--echo # db_cl_names='latin1_swedish_ci' + +--write_file $MYSQLD_DATADIR/test/tr11.TRN +TYPE=TRIGGERNAME +trigger_table=t1 +EOF + +--write_file $MYSQLD_DATADIR/test/tr12.TRN +TYPE=TRIGGERNAME +trigger_table=t1 +EOF + +--write_file $MYSQLD_DATADIR/test/tr13.TRN +TYPE=TRIGGERNAME +trigger_table=t1 +EOF + +--write_file $MYSQLD_DATADIR/test/tr14.TRN +TYPE=TRIGGERNAME +trigger_table=t1 +EOF + +--write_file $MYSQLD_DATADIR/test/tr15.TRN +TYPE=TRIGGERNAME +trigger_table=t1 +EOF + +--write_file $MYSQLD_DATADIR/test/t1.TRG +TYPE=TRIGGERS +triggers='CREATE DEFINER=`root`@`localhost` TRIGGER tr11 BEFORE INSERT ON t1 FOR EACH ROW DELETE FROM t3' 'CREATE DEFINER=`root`@`localhost` TRIGGER tr12 AFTER INSERT ON t1 FOR EACH ROW DELETE FROM t3' 'CREATE DEFINER=`root`@`localhost` TRIGGER tr13 BEFORE DELETE ON t1 FOR EACH ROW DELETE FROM t1 a USING t1 a' 'CREATE DEFINER=`root`@`localhost` TRIGGER tr14 AFTER DELETE ON t1 FOR EACH ROW DELETE FROM non_existing_table' 'CREATE DEFINER=`root`@`localhost` TRIGGER tr15 BEFORE UPDATE ON t1 FOR EACH ROW DELETE FROM non_existing_table a USING non_existing_table a' +sql_modes=0 0 0 0 0 +definers='root@localhost' 'root@localhost' 'root@localhost' 'root@localhost' 'root@localhost' +EOF + +--write_file $MYSQLD_DATADIR/test/t2.TRG +TYPE=TRIGGERS +triggers='Not allowed syntax here, and trigger name cant be extracted either.' +sql_modes=0 +definers='root@localhost' +EOF + +--echo # We will get parse errors for most DDL and DML statements when the table +--echo # has broken triggers. The parse error refers to the first broken +--echo # trigger. +--error ER_PARSE_ERROR +CREATE TRIGGER tr16 AFTER UPDATE ON t1 FOR EACH ROW INSERT INTO t1 VALUES (1); +--error ER_PARSE_ERROR +CREATE TRIGGER tr22 BEFORE INSERT ON t2 FOR EACH ROW DELETE FROM non_existing_table; +SHOW TRIGGERS; +--error ER_PARSE_ERROR +INSERT INTO t1 VALUES (1); +--error ER_PARSE_ERROR +INSERT INTO t2 VALUES (1); +--error ER_PARSE_ERROR +DELETE FROM t1; +--error ER_PARSE_ERROR +UPDATE t1 SET a = 1 WHERE a = 1; +SELECT * FROM t1; +--error ER_PARSE_ERROR +RENAME TABLE t1 TO t1_2; +SHOW TRIGGERS; + +DROP TRIGGER tr11; +DROP TRIGGER tr12; +DROP TRIGGER tr13; +DROP TRIGGER tr14; +DROP TRIGGER tr15; + +SHOW TRIGGERS; + +--echo # Make sure there is no trigger file left. +--list_files $MYSQLD_DATADIR/test/ tr* + +--echo # We write the same trigger files one more time to test DROP TABLE. +--write_file $MYSQLD_DATADIR/test/tr11.TRN +TYPE=TRIGGERNAME +trigger_table=t1 +EOF + +--write_file $MYSQLD_DATADIR/test/tr12.TRN +TYPE=TRIGGERNAME +trigger_table=t1 +EOF + +--write_file $MYSQLD_DATADIR/test/tr13.TRN +TYPE=TRIGGERNAME +trigger_table=t1 +EOF + +--write_file $MYSQLD_DATADIR/test/tr14.TRN +TYPE=TRIGGERNAME +trigger_table=t1 +EOF + +--write_file $MYSQLD_DATADIR/test/tr15.TRN +TYPE=TRIGGERNAME +trigger_table=t1 +EOF + +--write_file $MYSQLD_DATADIR/test/t1.TRG +TYPE=TRIGGERS +triggers='CREATE DEFINER=`root`@`localhost` TRIGGER tr11 BEFORE INSERT ON t1 FOR EACH ROW DELETE FROM t3' 'CREATE DEFINER=`root`@`localhost` TRIGGER tr12 AFTER INSERT ON t1 FOR EACH ROW DELETE FROM t3' 'CREATE DEFINER=`root`@`localhost` TRIGGER tr13 BEFORE DELETE ON t1 FOR EACH ROW DELETE FROM t1 a USING t1 a' 'CREATE DEFINER=`root`@`localhost` TRIGGER tr14 AFTER DELETE ON t1 FOR EACH ROW DELETE FROM non_existing_table' 'CREATE DEFINER=`root`@`localhost` TRIGGER tr15 BEFORE UPDATE ON t1 FOR EACH ROW DELETE FROM non_existing_table a USING non_existing_table a' +sql_modes=0 0 0 0 0 +definers='root@localhost' 'root@localhost' 'root@localhost' 'root@localhost' 'root@localhost' +EOF + +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; + +--echo # Make sure there is no trigger file left. + +--list_files $MYSQLD_DATADIR/test/ tr* + +CREATE TABLE t1 ( a INT ); +CREATE TABLE t2 ( a INT ); +INSERT INTO t1 VALUES (1), (2), (3); +INSERT INTO t2 VALUES (1), (2), (3); + +--echo # We write two trigger files. First trigger is correct, second trigger is broken. +--echo # Next we try to execute SHOW CREATE TRGGIR command for broken trigger and then try to drop one. +--write_file $MYSQLD_DATADIR/test/tr11.TRN +TYPE=TRIGGERNAME +trigger_table=t1 +EOF + +--write_file $MYSQLD_DATADIR/test/tr12.TRN +TYPE=TRIGGERNAME +trigger_table=t1 +EOF + +--write_file $MYSQLD_DATADIR/test/t1.TRG +TYPE=TRIGGERS +triggers='CREATE DEFINER=`root`@`localhost` TRIGGER tr11 BEFORE DELETE ON t1 FOR EACH ROW DELETE FROM t1 a USING t1 a' 'CREATE DEFINER=`root`@`localhost` TRIGGER tr12 BEFORE INSERT ON t1 FOR EACH ROW DELETE FROM t2' +sql_modes=0 0 +definers='root@localhost' 'root@localhost' +EOF + +FLUSH TABLE t1; + +SHOW CREATE TRIGGER tr12; +DROP TRIGGER tr12; + +DROP TABLE t1; +DROP TABLE t2; === modified file 'sql/sp_head.cc' --- a/sql/sp_head.cc 2010-11-11 04:52:51 +0000 +++ b/sql/sp_head.cc 2011-05-03 12:03:10 +0000 @@ -2354,6 +2354,10 @@ void sp_head::restore_thd_mem_root(THD *thd) { DBUG_ENTER("sp_head::restore_thd_mem_root"); + + if (!m_thd) + DBUG_VOID_RETURN; + Item *flist= free_list; // The old list set_query_arena(thd); // Get new free_list and mem_root state= INITIALIZED_FOR_SP; === modified file 'sql/sql_parse.cc' --- a/sql/sql_parse.cc 2011-03-03 08:25:37 +0000 +++ b/sql/sql_parse.cc 2011-05-03 12:03:10 +0000 @@ -7973,10 +7973,14 @@ bool parse_sql(THD *thd, bool mysql_parse_status= MYSQLparse(thd) != 0; - /* Check that if MYSQLparse() failed, thd->is_error() is set. */ + /* + Check that if MYSQLparse() failed, thd->is_error() is set (unless + we have an error handler installed, which might have silenced error). + */ DBUG_ASSERT(!mysql_parse_status || - (mysql_parse_status && thd->is_error())); + (mysql_parse_status && + (thd->is_error() || thd->get_internal_handler()))); /* Reset parser state. */ === modified file 'sql/sql_trigger.cc' --- a/sql/sql_trigger.cc 2010-09-07 08:53:46 +0000 +++ b/sql/sql_trigger.cc 2011-05-03 12:03:10 +0000 @@ -291,6 +291,43 @@ private: LEX_STRING *trigger_table_value; }; +class Deprecated_trigger_syntax_handler : public Internal_error_handler +{ +private: + + char m_message[MYSQL_ERRMSG_SIZE]; + +public: + + LEX_STRING *m_trigger_name; + + Deprecated_trigger_syntax_handler() : m_trigger_name(NULL) {} + + bool handle_error(uint sql_errno, const char *message, + MYSQL_ERROR::enum_warning_level level, THD *thd) + { + + if (sql_errno == ER_PARSE_ERROR) + { + if(thd->lex->spname) + m_trigger_name= &thd->lex->spname->m_name; + if (m_trigger_name) + my_snprintf(m_message, sizeof(m_message), + "Trigger '%s' has a syntax error in its body: '%s'", + m_trigger_name->str, message); + else + my_snprintf(m_message, sizeof(m_message), + "Unknown trigger has a syntax error in its body: '%s'", + message); + return TRUE; + } + return FALSE; + } + + LEX_STRING *get_trigger_name() { return m_trigger_name; } + char *get_error_text() { return m_message; } + +}; /** Create or drop trigger for table. @@ -552,13 +589,16 @@ end: (SUID/new trigger). @retval - False success + false success @retval - True error + true error */ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, String *stmt_query) { + if (check_for_broken_triggers()) + return TRUE; + LEX *lex= thd->lex; TABLE *table= tables->table; char file_buff[FN_REFLEN], trigname_buff[FN_REFLEN]; @@ -848,7 +888,7 @@ static bool rm_trigger_file(char *path, @param path char buffer of size FN_REFLEN to be used for constructing path to .TRN file. @param db trigger's database name - @param table_name trigger's name + @param trigger_name trigger's name @retval False success @@ -1312,12 +1352,11 @@ bool Table_triggers_list::check_n_load(T lex_start(thd); thd->spcont= NULL; - if (parse_sql(thd, & parser_state, creation_ctx)) - { - /* Currently sphead is always deleted in case of a parse error */ - DBUG_ASSERT(lex.sphead == 0); - goto err_with_lex_cleanup; - } + Deprecated_trigger_syntax_handler error_handler; + thd->push_internal_handler(&error_handler); + bool parse_error= parse_sql(thd, & parser_state, creation_ctx); + thd->pop_internal_handler(); + /* Not strictly necessary to invoke this method here, since we know that we've parsed CREATE TRIGGER and not an @@ -1328,6 +1367,40 @@ bool Table_triggers_list::check_n_load(T */ lex.set_trg_event_type_for_tables(); + if (parse_error) + { + if (!triggers->m_has_unparseable_trigger) + triggers->set_parse_error(error_handler.get_error_text()); + /* Currently sphead is always set to NULL in case of a parse error */ + DBUG_ASSERT(lex.sphead == 0); + if (error_handler.get_trigger_name()) + { + if (triggers->names_list.push_back(error_handler.get_trigger_name(), + &table->mem_root)) + goto err_with_lex_cleanup; + } + else + { + /* + The Table_triggers_list is not constructed as a list of + trigger objects as one would expect, but rather of lists of + properties of equal length. Thus, even if we don't get the + trigger name, we still fill all in all the lists with + placeholders as we might otherwise create a skew in the + lists. Obviously, this has to be refactored. + */ + LEX_STRING *empty= alloc_lex_string(&table->mem_root); + empty->str= const_cast(""); + empty->length= 0; + if (triggers->names_list.push_back(empty, &table->mem_root) || + triggers->on_table_names_list.push_back(empty, + &table->mem_root)) + goto err_with_lex_cleanup; + } + lex_end(&lex); + continue; + } + lex.sphead->set_info(0, 0, &lex.sp_chistics, (ulong) *trg_sql_mode); int event= lex.trg_chistics.event; @@ -1368,8 +1441,8 @@ bool Table_triggers_list::check_n_load(T if (triggers->names_list.push_back(&lex.sphead->m_name, &table->mem_root)) - goto err_with_lex_cleanup; - + goto err_with_lex_cleanup; + if (!(on_table_name= alloc_lex_string(&table->mem_root))) goto err_with_lex_cleanup; @@ -1394,9 +1467,8 @@ bool Table_triggers_list::check_n_load(T char fname[NAME_LEN + 1]; DBUG_ASSERT((!my_strcasecmp(table_alias_charset, lex.query_tables->db, db) || (check_n_cut_mysql50_prefix(db, fname, sizeof(fname)) && - !my_strcasecmp(table_alias_charset, lex.query_tables->db, fname))) && - (!my_strcasecmp(table_alias_charset, lex.query_tables->table_name, - table_name) || + !my_strcasecmp(table_alias_charset, lex.query_tables->db, fname)))); + DBUG_ASSERT((!my_strcasecmp(table_alias_charset, lex.query_tables->table_name, table_name) || (check_n_cut_mysql50_prefix(table_name, fname, sizeof(fname)) && !my_strcasecmp(table_alias_charset, lex.query_tables->table_name, fname)))); #endif @@ -1680,6 +1752,13 @@ bool Table_triggers_list::drop_all_trigg while ((trigger= it_name++)) { + /* + Since trigger name can be missed when trigger parsing failed + in Table_triggers_list::check_n_load() we must check here + the length of trigger name for equal to zero. + */ + if (trigger->length == 0) + continue; if (rm_trigname_file(path, db, trigger->str)) { /* @@ -1903,6 +1982,12 @@ bool Table_triggers_list::change_table_n } if (table.triggers) { + if (table.triggers->check_for_broken_triggers()) + { + result= 1; + my_error(ER_PARSE_ERROR, MYF(0)); + goto end; + } LEX_STRING old_table_name= { (char *) old_table, strlen(old_table) }; LEX_STRING new_table_name= { (char *) new_table, strlen(new_table) }; /* @@ -1986,6 +2071,9 @@ bool Table_triggers_list::process_trigge trg_action_time_type time_type, bool old_row_is_record1) { + if (check_for_broken_triggers()) + return TRUE; + bool err_status; Sub_statement_state statement_state; sp_head *sp_trigger= bodies[event][time_type]; @@ -2070,6 +2158,22 @@ void Table_triggers_list::mark_fields_us /** + Signals to the Table_triggers_list that a parse error has occured when + reading a trigger from file. This makes the Table_triggers_list enter an + error state flagged by m_has_unparseable_trigger == true. The error message + will be used whenever a statement invoking or manipulating triggers is + issued against the Table_triggers_list's table. + + @param error_message The error message thrown by the parser. + */ +void Table_triggers_list::set_parse_error(char *error_message) +{ + m_has_unparseable_trigger= TRUE; + strcpy(m_parse_error_text, error_message); +} + + +/** Trigger BUG#14090 compatibility hook. @param[in,out] unknown_key reference on the line with unknown === modified file 'sql/sql_trigger.h' --- a/sql/sql_trigger.h 2009-01-14 14:50:51 +0000 +++ b/sql/sql_trigger.h 2011-05-03 12:03:10 +0000 @@ -62,6 +62,27 @@ class Table_triggers_list: public Sql_al */ GRANT_INFO subject_table_grants[TRG_EVENT_MAX][TRG_ACTION_MAX]; + /** + This flag indicates that one of the triggers was not parsed successfully, + and as a precaution the object has entered a state where all trigger + access results in errors until all such triggers are dropped. It is not + safe to add triggers since we don't know if the broken trigger has the + same name or event type. Nor is it safe to invoke any trigger for the + aforementioned reasons. The only safe operations are drop_trigger and + drop_all_triggers. + + @see Table_triggers_list::set_parse_error + */ + bool m_has_unparseable_trigger; + + /** + This error will be displayed when the user tries to manipulate or invoke + triggers on a table that has broken triggers. It will get set only once + per statement and thus will contain the first parse error encountered in + the trigger file. + */ + char m_parse_error_text[MYSQL_ERRMSG_SIZE]; + public: /** Field responsible for storing triggers definitions in file. @@ -84,7 +105,7 @@ public: /* End of character ser context. */ Table_triggers_list(TABLE *table_arg): - record1_field(0), trigger_table(table_arg) + record1_field(0), trigger_table(table_arg), m_has_unparseable_trigger(FALSE) { bzero((char *)bodies, sizeof(bodies)); bzero((char *)trigger_fields, sizeof(trigger_fields)); @@ -140,6 +161,8 @@ public: void mark_fields_used(trg_event_type event); + void set_parse_error(char *error_message); + friend class Item_trigger_field; friend int sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, TABLE_LIST *table); @@ -155,6 +178,16 @@ private: const char *new_db_name, LEX_STRING *old_table_name, LEX_STRING *new_table_name); + + bool check_for_broken_triggers() + { + if (m_has_unparseable_trigger) + { + my_message(ER_PARSE_ERROR, m_parse_error_text, MYF(0)); + return TRUE; + } + return FALSE; + } }; extern const LEX_STRING trg_action_time_type_names[]; --===============1791755854461593893== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/dmitry.shulga@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: dmitry.shulga@stripped\ # 21wl6g6fe2y09qjb # target_branch: file:///Users/shulga/projects/mysql/mysql-5.1-\ # bug11753738/ # testament_sha1: ee2aa742013fb14b6c856cfb5608ffc706a3d52a # timestamp: 2011-05-03 19:03:17 +0700 # base_revision_id: sergey.glukhov@stripped\ # t0iwi2pxtos5w7x1 # # Begin bundle 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 hQkMWBalgA== --===============1791755854461593893==--