From: Dmitry Shulga Date: June 10 2011 7:08am Subject: bzr commit into mysql-5.5 branch (Dmitry.Shulga:3438) Bug#11753738 List-Archive: http://lists.mysql.com/commits/139024 X-Bug: 11753738 Message-Id: <201106100709.p5A79KGl015966@acsmt357.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1179708240411029314==" --===============1179708240411029314== 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.5/ based on revid:marko.makela@stripped 3438 Dmitry Shulga 2011-06-10 [merge] Manual-merge of patch for bug#11753738 from mysql-5.1 tree. 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:04:46 +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:29:23 +0000 +++ b/mysql-test/r/trigger.result 2011-06-10 07:04:46 +0000 @@ -2118,7 +2118,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 '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:04:46 +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:12:32 +0000 +++ b/sql/share/errmsg-utf8.txt 2011-06-10 07:04:46 +0000 @@ -6408,3 +6408,10 @@ WARN_OPTION_BELOW_LIMIT 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-05-21 08:59:32 +0000 +++ b/sql/sp_head.cc 2011-06-10 07:04:46 +0000 @@ -2543,7 +2543,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-04-15 12:02:22 +0000 +++ b/sql/sql_trigger.cc 2011-06-10 07:04:46 +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 2010-09-16 09:11:13 +0000 +++ b/sql/sql_trigger.h 2011-06-10 07:04:46 +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) { bzero((char *)bodies, sizeof(bodies)); bzero((char *)trigger_fields, 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[]; --===============1179708240411029314== 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\ # r52lp7bkzrt17bg7 # target_branch: file:///Users/shulga/projects/mysql/mysql-5.5/ # testament_sha1: 5feddd49765a2bb691127b882be368824e8bfe6a # timestamp: 2011-06-10 14:09:10 +0700 # source_branch: file:///Users/shulga/projects/mysql/mysql-5.1-\ # bug11749345/ # base_revision_id: marko.makela@stripped\ # ztc4qe2mczn6088o # # Begin bundle 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 --===============1179708240411029314==--