From: Dmitry Shulga Date: June 10 2011 7:39am Subject: bzr commit into mysql-trunk branch (Dmitry.Shulga:3180) Bug#11753738 List-Archive: http://lists.mysql.com/commits/139031 X-Bug: 11753738 Message-Id: <201106100739.p5A7ddac024765@acsmt358.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============8152596517112062897==" --===============8152596517112062897== 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-trunk/ based on revid:tor.didriksen@stripped 3180 Dmitry Shulga 2011-06-10 [merge] Manual-merge of patch for bug#11753738 from mysql-5.5. modified: mysql-test/r/trigger-compat.result mysql-test/r/trigger.result mysql-test/t/trigger-compat.test sql/share/errmsg-utf8.txt sql/sp_head.cc sql/sql_trigger.cc sql/sql_trigger.h === modified file 'mysql-test/r/trigger-compat.result' --- a/mysql-test/r/trigger-compat.result 2010-02-03 21:48:40 +0000 +++ b/mysql-test/r/trigger-compat.result 2011-06-10 07:20:15 +0000 @@ -41,3 +41,98 @@ 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' +FLUSH TABLE t1; +FLUSH TABLE t2; +# 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 an 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 an 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 +INSERT INTO t1 VALUES (1); +ERROR 42000: Trigger 'tr13' has an 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 an 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 an 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 an 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 an 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 +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. +FLUSH TABLE t1; +FLUSH TABLE t2; +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 three trigger files. First trigger is syntaxically incorrect, next trigger is correct +# and last 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 +SHOW CREATE TRIGGER tr11; +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +tr11 CREATE DEFINER=`root`@`localhost` TRIGGER tr11 BEFORE DELETE ON t1 FOR EACH ROW DELETE FROM t1 a USING t1 a latin1 latin1_swedish_ci latin1_swedish_ci +DROP TRIGGER tr12; +DROP TRIGGER tr11; +DROP TABLE t1; +DROP TABLE t2; === modified file 'mysql-test/r/trigger.result' --- a/mysql-test/r/trigger.result 2011-05-09 08:48:22 +0000 +++ b/mysql-test/r/trigger.result 2011-06-10 07:38:06 +0000 @@ -2106,7 +2106,7 @@ CREATE TRIGGER trg1 BEFORE INSERT ON t2 SHOW TRIGGERS IN db1; Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation 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 't1 VALUES (1)' at line 1 +ERROR 42000: Trigger 'trg1' has an 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-06-10 07:20:15 +0000 @@ -106,4 +106,184 @@ 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 + +FLUSH TABLE t1; +FLUSH TABLE t2; + +--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 + +FLUSH TABLE t1; +FLUSH TABLE t2; + +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 three trigger files. First trigger is syntaxically incorrect, next trigger is correct +--echo # and last 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 the wrongest trigger_in_the_world' '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 0 +definers='root@localhost' 'root@localhost' 'root@localhost' +EOF + +FLUSH TABLE t1; + +SHOW CREATE TRIGGER tr12; +SHOW CREATE TRIGGER tr11; +DROP TRIGGER tr12; +DROP TRIGGER tr11; + +DROP TABLE t1; +DROP TABLE t2; === modified file 'sql/share/errmsg-utf8.txt' --- a/sql/share/errmsg-utf8.txt 2011-05-31 09:30:59 +0000 +++ b/sql/share/errmsg-utf8.txt 2011-06-10 07:38:06 +0000 @@ -6505,3 +6505,10 @@ ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_DR ER_INDEX_COLUMN_TOO_LONG eng "Index column size too large. The maximum column size is %lu bytes." + +ER_ERROR_IN_TRIGGER_BODY + eng "Trigger '%-.64s' has an error in its body: '%-.256s'" + +ER_ERROR_IN_UNKNOWN_TRIGGER_BODY + eng "Unknown trigger has an error in its body: '%-.256s'" + === modified file 'sql/sp_head.cc' --- a/sql/sp_head.cc 2011-06-09 08:58:41 +0000 +++ b/sql/sp_head.cc 2011-06-10 07:38:06 +0000 @@ -2540,7 +2540,22 @@ void sp_head::restore_thd_mem_root(THD *thd) { DBUG_ENTER("sp_head::restore_thd_mem_root"); - Item *flist= free_list; // The old list + + /* + In some cases our parser detects a syntax error and calls + LEX::cleanup_lex_after_parse_error() method only after + finishing parsing the whole routine. In such a situation + sp_head::restore_thd_mem_root() will be called twice - the + first time as part of normal parsing process and the second + time by cleanup_lex_after_parse_error(). + To avoid ruining active arena/mem_root state in this case we + skip restoration of old arena/mem_root if this method has been + already called for this routine. + */ + 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= STMT_INITIALIZED_FOR_SP; === modified file 'sql/sql_trigger.cc' --- a/sql/sql_trigger.cc 2011-05-26 15:20:09 +0000 +++ b/sql/sql_trigger.cc 2011-06-10 07:38:06 +0000 @@ -31,6 +31,7 @@ #include "sql_acl.h" // *_ACL, is_acl_user #include "sql_handler.h" // mysql_ha_rm_tables #include "sp_cache.h" // sp_invalidate_cache +#include /*************************************************************************/ @@ -305,6 +306,55 @@ private: /** + An error handler that catches all non-OOM errors which can occur during + parsing of trigger body. Such errors are ignored and corresponding error + message is used to construct a more verbose error message which contains + name of problematic trigger. This error message is later emitted when + one tries to perform DML or some of DDL on this table. + Also, if possible, grabs name of the trigger being parsed so it can be + used to correctly drop problematic trigger. +*/ +class Deprecated_trigger_syntax_handler : public Internal_error_handler +{ +private: + + char m_message[MYSQL_ERRMSG_SIZE]; + LEX_STRING *m_trigger_name; + +public: + + Deprecated_trigger_syntax_handler() : m_trigger_name(NULL) {} + + virtual bool handle_condition(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* message, + MYSQL_ERROR ** cond_hdl) + { + if (sql_errno != EE_OUTOFMEMORY && + sql_errno != ER_OUT_OF_RESOURCES) + { + if(thd->lex->spname) + m_trigger_name= &thd->lex->spname->m_name; + if (m_trigger_name) + my_snprintf(m_message, sizeof(m_message), + ER(ER_ERROR_IN_TRIGGER_BODY), + m_trigger_name->str, message); + else + my_snprintf(m_message, sizeof(m_message), + ER(ER_ERROR_IN_UNKNOWN_TRIGGER_BODY), message); + return true; + } + return false; + } + + LEX_STRING *get_trigger_name() { return m_trigger_name; } + char *get_error_message() { return m_message; } +}; + + +/** Create or drop trigger for table. @param thd current thread context (including trigger definition in LEX) @@ -591,6 +641,8 @@ bool Table_triggers_list::create_trigger LEX_STRING *trg_connection_cl_name; LEX_STRING *trg_db_cl_name; + if (check_for_broken_triggers()) + return true; /* Trigger must be in the same schema as target table. */ if (my_strcasecmp(table_alias_charset, table->s->db.str, @@ -864,7 +916,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 @@ -1329,12 +1381,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 @@ -1345,6 +1396,54 @@ 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_message(error_handler.get_error_message()); + /* Currently sphead is always set to NULL in case of a parse error */ + DBUG_ASSERT(lex.sphead == 0); + if (error_handler.get_trigger_name()) + { + LEX_STRING *trigger_name; + const LEX_STRING *orig_trigger_name= error_handler.get_trigger_name(); + + if (!(trigger_name= alloc_lex_string(&table->mem_root)) || + !(trigger_name->str= strmake_root(&table->mem_root, + orig_trigger_name->str, + orig_trigger_name->length))) + goto err_with_lex_cleanup; + + trigger_name->length= orig_trigger_name->length; + + if (triggers->names_list.push_back(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); + if (!empty) + goto err_with_lex_cleanup; + + empty->str= const_cast(""); + empty->length= 0; + if (triggers->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; int action_time= lex.trg_chistics.action_time; @@ -1411,9 +1510,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 @@ -1695,6 +1793,13 @@ bool Table_triggers_list::drop_all_trigg while ((trigger= it_name++)) { + /* + Trigger, which body we failed to parse during call + Table_triggers_list::check_n_load(), might be missing name. + Such triggers have zero-length name and are skipped here. + */ + if (trigger->length == 0) + continue; if (rm_trigname_file(path, db, trigger->str)) { /* @@ -1913,6 +2018,11 @@ bool Table_triggers_list::change_table_n } if (table.triggers) { + if (table.triggers->check_for_broken_triggers()) + { + result= 1; + goto end; + } LEX_STRING old_table_name= { (char *) old_alias, strlen(old_alias) }; LEX_STRING new_table_name= { (char *) new_table, strlen(new_table) }; /* @@ -2001,6 +2111,9 @@ bool Table_triggers_list::process_trigge sp_head *sp_trigger= bodies[event][time_type]; SELECT_LEX *save_current_select; + if (check_for_broken_triggers()) + return true; + if (sp_trigger == NULL) return FALSE; @@ -2135,6 +2248,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_message(char *error_message) +{ + m_has_unparseable_trigger= true; + strcpy(m_parse_error_message, 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 2011-05-26 15:20:09 +0000 +++ b/sql/sql_trigger.h 2011-06-10 07:38:06 +0000 @@ -97,6 +97,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_message[MYSQL_ERRMSG_SIZE]; + public: /** Field responsible for storing triggers definitions in file. @@ -118,8 +139,9 @@ public: /* End of character ser context. */ - Table_triggers_list(TABLE *table_arg): - record1_field(0), trigger_table(table_arg) + Table_triggers_list(TABLE *table_arg) + :record1_field(0), trigger_table(table_arg), + m_has_unparseable_trigger(false) { memset(bodies, 0, sizeof(bodies)); memset(trigger_fields, 0, sizeof(trigger_fields)); @@ -176,6 +198,8 @@ public: void mark_fields_used(trg_event_type event); + void set_parse_error_message(char *error_message); + friend class Item_trigger_field; bool add_tables_and_routines_for_triggers(THD *thd, @@ -193,6 +217,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_message, MYF(0)); + return true; + } + return false; + } }; extern const LEX_STRING trg_action_time_type_names[]; --===============8152596517112062897== 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\ # fnfdefu19gab5xwp # target_branch: file:///Users/shulga/projects/mysql/mysql-trunk/ # testament_sha1: 642ca855849a32376260fe0d5f7a276e65df8286 # timestamp: 2011-06-10 14:39:34 +0700 # source_branch: file:///Users/shulga/projects/mysql/mysql-5.5-\ # bug11763757/ # base_revision_id: tor.didriksen@stripped\ # nykxw30y6ly819hg # # Begin bundle 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 3nrKP4sMqS/GKtSRd/+LuSKcKEgFISJLAA== --===============8152596517112062897==--