From: Dmitry Shulga Date: June 10 2011 7:23am Subject: bzr push into mysql-5.5 branch (Dmitry.Shulga:3438 to 3439) Bug#11753738 List-Archive: http://lists.mysql.com/commits/139029 X-Bug: 11753738 Message-Id: <201106100723.p5A7NaUn026429@acsmt357.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============7899189197640557130==" --===============7899189197640557130== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline 3439 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 3438 Tor Didriksen 2011-06-10 Bug#12641810 - MYSQL MAKE DIST DOESN'T WORK WHEN USING MYSQL TREE + PLUGIN TREE(S) @ cmake/make_dist.cmake.in Run 'bzr export' for plugins. @ cmake/plugin.cmake Lookup plugins with bzr repos. modified: cmake/make_dist.cmake.in cmake/plugin.cmake === 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:29:23 +0000 +++ b/mysql-test/r/trigger.result 2011-06-10 07:20:15 +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: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:12:32 +0000 +++ b/sql/share/errmsg-utf8.txt 2011-06-10 07:20:15 +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:20:15 +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:20:15 +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:20:15 +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[]; --===============7899189197640557130== 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\ # ie1fg12b4adfcjc3 # target_branch: file:///Users/shulga/projects/mysql/mysql-5.5/ # testament_sha1: e9a7c47724b11ecad56c642768b777e7ddc58b4f # timestamp: 2011-06-10 14:23:31 +0700 # source_branch: file:///Users/shulga/projects/mysql/mysql-5.1-\ # bug11749345/ # base_revision_id: tor.didriksen@stripped\ # hha01c7beu1ogyd7 # # Begin bundle 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 --===============7899189197640557130==--