From: Dmitry Shulga Date: June 10 2011 6:21am Subject: bzr commit into mysql-5.5 branch (Dmitry.Shulga:3438) Bug#11753738 List-Archive: http://lists.mysql.com/commits/139020 X-Bug: 11753738 Message-Id: <201106100621.p5A6LnCk003767@acsmt356.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============5862141872641288624==" --===============5862141872641288624== 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 06:19:16 +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 06:19:16 +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 06:19:16 +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 06:19:16 +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 '%s' has an error in its body: '%s'" + +ER_ERROR_IN_UNKNOWN_TRIGGER_BODY + eng "Unknown trigger has an error in its body: '%s'" + === 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 06:19:16 +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 06:19:16 +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 06:19:16 +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[]; --===============5862141872641288624== 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\ # a81tq8wqwob1wgkc # target_branch: file:///Users/shulga/projects/mysql/mysql-5.5/ # testament_sha1: 0b2fb78e6b9aadc95f75d68d5dd7ae2e23da50a0 # timestamp: 2011-06-10 13:21:40 +0700 # source_branch: file:///Users/shulga/projects/mysql/mysql-5.1-\ # bug11749345/ # base_revision_id: marko.makela@stripped\ # ztc4qe2mczn6088o # # Begin bundle IyBCYXphYXIgcmV2aXNpb24gYnVuZGxlIHY0CiMKQlpoOTFBWSZTWWoNOb8AF9H/gHV8UER///// f+//+v////5gLV573eFxmz77d98Xw9e8AANHR2BbXaZMLHdz7we97sRoKAooSFBRXXPAeUFUBQs2 esDl05s66z3upYO23Nd7eWhr13T20415u73bpdlbrdnR0m21Q6cUjs99vL2N7JO7u625z53uBTCU QmRMRoyNU8nkjEGammp6pmJNpomQaNBiADQAZBKBAQ0ECMonpoVP0I01PUZMIekAAAAAAMg1T9Ca p6UNGmmgNDQAAADQAAAAAAABJqJCAIJgEnpqYJpT9U9lPaqMmjJ6n6UGmjRiAAaAyCJSAmRTxFPy p+lPaTJNgk9J6UfhKeU002mhGQekY0anqHqA9T1AqSQCAJoACBpMmU2jUMiek002poQ8pmSP1TJ6 gA0cufZB+2Aod74fKP8wLDkDOVPKXD6ktf7OQrPOeQhYnsHEC6kIP8pfEvA/EDMP4NxifWHb7p6m knwQflX38eVVfiz7fjWqw+DAyLxT+rOsn8G67OaIp3VONGdBFrYBUfTF5OGB/IwoViBVM9aChYMp AGkui8xexh+/t9ujDpd7ItOQ9g5qQjufXlnwVKvuJMOKsec7dLUkTyv8p23+h/XWyd9kYNpf85xj kpf9iB1Lry+7m70m5lKiucCikvdZg+y3+/hln0PQUqqB2xlx5co8yecnZfNpHixmPZzj4t06s3zi xv2222+zGe2NL9vKZuq/d9/5dJSdvndvWIN8ZGrMVwLnnaCGYLtcvaxlVRFqgqqqIb5sCoKaxgDo lOM1P43XW5CD4Zq3x31lYJ7zKWUqzN0Z6GlTpVbaH20TTniwEqFJlN5xNWANuugrVRndW40pZZ9H 6An5gy7Ezhnq5/N3ybczkUeDz7Ah0pOZDl663OSXuu5bhhOdH7K0w55Og86zokU83Z+PX4SBCwe7 1uZLDJ7MtXXOL+7QNZFarsZWgu2y6kSnK2lqrO8VWUp1pEloKzPDT39mR1f20e2nUsJZt1od/kyh aDQT7w237X0O5LeHWxEQE2Ohc4qvp5cB1pJCToIEjEARYgoIioyMYsFRUFCzpGEN5xAOzX9WCvy7 D2HWi0sKiyKT1nkeh+Q7INCObXe769mSiaI6O0Hwa88dfxVMJOH0FLN/Hf6Q3LB8avgE62RkiKSK AqiiiioiqAiRbCC8iIG3WVPIIZFVUAgTgR19D4MLWu2RINUYoRSJSbF4MyBCzq7BEdJrCMyCgwdX ZWZjKRVySiBWLFLJeqPRhpUegqNDJZmvZ2f7yjyZYasKzLC1u82UnK5ZRoqNDFXesE7Xpa/cC970 e63Ksr5SkS/7Nw/Ie35cz+P5D35aZZxy2k3Jp7qMtWntAQiXLmUGUuXMgmERKsyxMkCzCIefK8aN K1ddHx8L+jwZtbi+d7g4sFlOZ9j/RN8fk3dr2+aTEPQsfR6fy5t1NJVe/p5tSHsXSf0NNDkom0nC lUi9T48FjUp3I7Q25fRS04fKvydPWdTkN/ne1U3DalKXe5/FDndzUMdbhm/Sr8ZrTZUYNBRQiUJO TaWWfqBKVoGUNCpSlLH8+tM9xrrxutQu+KZO12yLnq8KrcKKqovSwrAlAZoLSsmPSIPHhE/PnVmt 9Nm+JkT1SZYBvT5vSd/TKzQ3xI/OYTvKNWYEUDN/v5p4JRoU6kN6yMmRoMEkKDsw6ozr+EDMlsWB XdtaU+i4dFHBN6C3OcirfMxRDEmUfWGXLTv9ZefZb1zXWEctJ3jDKKfjA2tzOh9LG/n1tXLAGCWs wNXAtE7m1efS1u4wdHOFcpiro8rmYSKczWniEMeWSrbYZQQWijilpxHLLy5bf43TJonbRNcqh9j2 PrKofMLpRERoUPLeEVcs2jRgdTQ1Yc6KgW0An/5IhPv8ze2aNno5RLzb0FRRHp5CwYn+YCZ9QE5B 5pHJI0/K3K9VRaBBhz4KaAnKZasASkcO68dMotISokC+bja1pKDCCUyaxOUlDCajgaHp7Z55Urpn iF+l9CsWAdd3SqlT1YpTcWXFhNaHsnJ0u83N/yIiOIc7jATQrv6B6ChbpMSmXJ7L1kNJ5UkMKMUm SU7dmH2b/42i3yFvk2wo+Ue+l8ckRO3WS3GN2hc7ZztL9vORvVr6KuRYfOLqpvFH38YzdcpZJe7k 3/ZN0AgCIZud3RVTkBicLPKdFI18hcRTry2iVsjxJrMsYSmK9c8i1+ilQ0PGhVJA2to4PpPMKP+g 8PAofmeTC9UqkrBVgmOI/YgBgUcYGHNk4AUwvt2TQnx5lK2O4iJyfoBbP51G9M1m/lX7fZGIf0cn 6lb6aAS8fCYGpxCyFFMxYOnKcyEJZNTTa85JTb0Vx85uQuUtSYsySsslyoppKnHgBQHzPeEDL37K 03ypqaag+ihjzSiEB5qbJk5FPxfcHGp6dCKUXmYfJYknxUF1YgkX6YiYD9XCAObo0yS44KJyVpfH ehrnoTrlVyCPKxHxiIpKKPiIMm6D6r4FDUXAGIBkhKIpuPq3tFPUp3TxeXrVfL00WMXyeh3hdaF4 xn5D0H3HeTx9cWVdclUh9zTdbx4owRQ4Xfblz827/3Vy0vT8eo9khN3Dt/QuJAD+aXFUVUVURVVE VEfdJVSBoT5UjNh/hVR6O9VU6wYfPm+w5+opE6zQh6r0YvuNekKDbJzDARAGRAUT69ftMSBxfy5c Og0+ezLkTBRcbHOlr8lmskDyMGm7FjP3ars1lG18A9lZDOsgdT3En3DC8uWBDFQ47YM5oDWrfYj+ WKvnVK1IP8DU/FSx7VgF8hlb6pQ+G/d3kVEPeIPEpmbbqVX3F3Rxwp0+vhob50kYhRNes+0/fRDI qyws/O/pZ4LJUEwdVNC6ePx8nrsj1qCEqdGSdWPP7GeCnxXJXYOd2LbdrFcyv3uATofJJrO6KR+m UqAN8OcDh5QqfLAPdXQcJx5DmbMURKHvLMN6e5oRs+rXrT1P6Uj7ihfOjk1Kbdkebuzbd3LknSvj TQ2tvJ74zFFUjgSanGLknjuDkGqdMcsz2OaKwpSOk3d2ePtd1Z2IqPVmViiu6LKTc3TCIHLOtc5G +RyTn7UYkOyKdDuST94D2Jx4blrUWiyV18ovA+C+2Ei+t3almp1PBVyqKTCCdt9wz75h7YXs/OvP +PrXQbs9UlrUB6fkbPosRVRHzS4esgITme70d58uE75eRcwgiEDDhnn+jwuQWUwMnrEp1M1oaVqu AsyTNkzfIDL97BWPfHTPEEL5r3IGoNVQTzCElSE31CH1XKR3gNTgVuLhgLLRJOfVvX3yiU2WsqsU wWaNl74fus1NBlYLI0gRFFANEjKHJSk7CDIdjGcWkIgjAhWdGKoiLKopN0IasTILlCyUDAiTYejM JihQLqQSAqgl1HFEqhs5YsbZKuDMYsXpiOaJSYIx8pAeTjjbj/7B4pXCKWAdFJiVM6oTMI8+9Dmz xNeYVA5XigZOmqi3lxWeulFOOo69ZJeqJYvz24blSeztgzaQz02TWwjCZr7X9qrNoS017rHbwYo0 XlokmdzHh4nL0mQ4W6BRCNNJgJiitBLKcFmNtfAUzXHmNf+mDUwJ7hU0NWCyCpgdUI7iJJTUgLDK vo+7bcu3a1PdS/p1yNhOWllc3VBlI8jkcsC/TJiwpmMyilSinMUJxKSIDheOYruKwpyaRgo5+E6n 2ZHYETKey4kDmCNOxqriUxrrYuTFJghmn9YDcyRhc1Sxm1ZrMZ0RkU7KdhQ32k+M7ekZuZeh6MQw PLc09OExnAQnWVFKgQaViD5m6QfiI2c5kmHxwlMSqgtK9kkTqPEIUTidhmec6b3N5Txkna52Ta1O L042ygZYz3bCMyNs3cYfFSvowsl3aOnSd6SsE5x5zHWsparKsgkVAvjrfqIJzGekLZwXGu92thlu A64cRJLZJvOy7gAacxoZGWtNjbnRWIOoYLMoJmcdLk3PaJmPg63vOXKzd4ZknmMZ83ac+dm7lmkR EJL/nvOXFoHTY0mITINUmZA+sjW5HgULSIysM2pqprI5EjMkLK44u9CxzBE41nIsVGHHI20JFiBE x5VJ1ONx9swQ7Iip+ZVUZH2FkafMpRwbl7mXbWTg2rPcYHG50P3xRfNnOOEfmUMwNs+OiHzLxLHJ aSy4J70zMozhrNF8mVqsyOVJtzNYB0PmEKGbpWuQ6WMwmOSJ0LoIk0xvXgoYtF6sdLSPheUjIuUS w12eQL3OWpSkk5C7W02KOaC7Aibjibkyp6IUTNU94XaqzRrQdEF2mKvuGUdsygImvRqNwczLMFtm FCRfkUA9PZqcWppoxxzMVeyO6OwfQdI6XL088bz1x2Zbcg58he3ey8eWEWCdIkrSFM7IMlhSRzuA OiHvFA8EmBfEkvnJ870UigwDHcWRI4F+JOS3YoVPHi8jjY+XcnMn2M+bjDKzH0oPshuKhwo25CRs czeIL7+PdpmUJmsT0yJE1y2oaWMlmU5mp1gK15g2iAQkzsMCJg6lzMoxBBumRTNKBAx1GD84GVe6 dPCHsQ+4fINDHqdS5ZuWFSa06dHZhm4r4J3qsqVpag+RWC6GQJ8VTZVktRpzzS9r7Otv5N6vFmvz UilrKXNTirjTWxqNpEapn7fIkT0sfzC202JJYPnA9QshgUXTQnpz1xVBvaLmpREcnRJTmX1J+flH 4NI5afgfqc804cz6VTSnB5FqwN2QqJ6OdCSIwx0U6E7IbAxYuxzHGcjpZNFPRdm1ZNLLZRqPEw7p 3R1Rxd+8fBNDqhx7MewbbqvdObcsSiT9nvxRYes5rIdSpO6J0XIgEJqlIRPFoAjCNQSh4NShQkAJ fuaaQCErl9pkm7nMqpKJ8VckZZK4nw+GhYgqtssEFzedeLb6EjA7/QXeevV8PtXU2mcrpXQ4KKTH Lqt08SdDZvqDTi9Da4ybnQ4rNjJZtcHvUvXOuGLzi21UYNmPxjY7DvO7hHvsOJ0R73X227vPq20H n146vatp3spDzidAWLSlNSsCJcdSWh38WkeNL30+JnQzGOpgYU2PcBpTJM9IOQRo/G/PTSew4b0q 5NbNI1ORgnrxnwbkq7YcmQ0FnFtBah6anLYntVDRCycl7v9cejogYxfgOhGZ59DovKc7Ryb2vXHu JLyTSuuLp5d9OmNemV11zZGkde7U1rTe0llFIeJD9qbrUZGLqjg9hLcgQhr3kRf5Xz8KcGqUOZro Vo6NnbmaNJBsKalRj3y6kuz5pM5QKW02GNnoczS8E7jORi5qYLHM1KF0mbuTy0rBM+Rrub7Hcwcy DIkULmRhipMxQkSObjFKh5OnvweYIW0t2vGbqzxEoiUOwOSVfhy55YoNGtfle6vLfC7pWi3M1VRF s1ExgXSmEFoOoh7V01KvXXLoZQTNDT5ZY79qJmLFBGwXI92uJG5tCFS6ngkSymSz2wRPVb63lc5E qcdx/VjNzY2LGCx8pjHMyMyDxbn/KfUifAEqbR0K186yPJ/h83Jc6+GfNWcvpOtXjLm3qJlhgUl4 QkWGRsFFaL2EmiQgF60nYmiA6Fhx/PKRjmD0Ae+Rj3SxSAgy8KTfb2EWT0s93RFuZ3u2jzPKm7r1 zJSVW7KPJmL9mMoZIGY7YdN9JCqaLceiUG4RLOgwYw1pQUQbW+GkxhVcveBmdxs+/AKv8J5rMk+4 y8Oes6NHbqMikYoqoEexdcAlKqUIi0F7whi/MAd5WsHxHmDNFPNznWRFycIvs0AnTn0lT1dvUAuQ 9XvFVc+oBNQhFDzBcPtQPALT0gec/JQvFgQEhL/x63vwvKcARCMWIyTKVA/5ATAMHCs4bBC37UkW 8SwYFLX81aWM9RgoZx9f2XWhhBbwglCFAgmKhmSi1gwYL6g9Ch/u4CzCG4f6Nw1F/rBlBaggDQoN klygsXFlEnzWscQzQwkHTfLt6T9yTOWBpMnANSP2JD8Xck61xOtC0CLRTAVgVeiTMBPage//zNea QApLiR/qvHhf2TMO1/xwSbUX4oXJKRO9F1ndsOUVKkU4wGqAss4NquCFkdD0LE162cBX4pLRfI4n AwqqhSDoNjskP7mTCODpT/Ux7qXVa4VKFrrSHeI6pBl+NSugdcHMjXmnIkvSX5Ncacl3/yIe49p7 a7SBtglwO2OUQiNhUK5yuz3FZIeNB3Jf6ON/hVUvnvlPJDrOfcF3j9O9xQbxDxtFB2CEYLzd2oNt xw4HINghBsNUxgYDrTqDVbSJG8xClIUnJSQtZClWSX3JLPZIPY0c0EblSTLEnBEwcoGMkbkMCHUK NdIlUKKheVBVaKsmjU+3iSb2piOTJFzJFpG1p/U7lDEc8JvYxyX6U/FUzlT47TejoWqhOW5SzHwp IbZDLFZJQlKSoTpRfhgLKHHZC4R+wKk4HPF8kow0AF2huqiaKUP/RKQ8XZQqlrKJ8xQbqwOhHpnA b2Jm3dHfczRhIva1nqoM70ktKYhYdPMK8WnXtueG7cFoTaO59bW/Y+TWapDYwkqqXDVdaHhhrZPl G5Lfg2P91T9r8D9X3riP5P1s4wjK6LKux/YYWqqLYLJgjnUAKj0hhe3SFE+hfPmEvTAmRWC25qrK wT5lGIf2nCQ1Gs1z4IbRBi7oHAsm5WTDDUZEN9jMSygxZkybc4ZSTNkmozwlHA3kXmDeLKUTBpk2 1vo1BTOYM5RXcC4LbUMy2lDBJeLj9kZCgFcF+P6hYL0gd9DjgZyAnwpLoo5z0n3fcfgZ9ihGKn2F jSv1DWfOes7vm7g4eSinAMIyI0HkBCcmaKWHcO6OwQfVN0tNGj8s6ZTWazeS+HxsVkzRaSBvktDs 6L56OY2NTW3fds2PX2NQh4Z7X35Lv9FhamHnl7Yvca1PBp/wbJv1vucLL0hsIq7b1R/jwm94PkYj sf5rUqoWPF6UG9/ztwiqutNVwtMrZayy3B7LY0cVSlSEvzfzjLFURX1RbBQ56N6pF73kd1XspUOb ukyjCwpPGh4r4+FXUuIc86NIf3jgVJjjEjIQKMWAUsqVRRRWZUnhDfJu7wrZlJNAE1gFnT+5BvNd XRrFZ33MQsJisodOsMSSdtY0ZDC0WtMV174tniau26I7qn2HFnJI0FJCoFXb49CF21cmFg3jU1nK CGIqBEaewxjT6Wazwdi9gyfQ9cbHvfBjrGjFo+jYczNg3ta9rx/mxe1yWjc+HPG94SLtzHa1MJop 662OZR1O/zdwxGkFOSFIkiqVJGo1B8CYIHQkD5+bdKldYZKJlj5uOi8nKeFBTS90ecKwNStERQF0 lhYZRr8AaA0xlzhhpIjiO/X38aYDBOnui7jHm9sbsnJwb3R6lnmsg7Uve2yPJXl32vjCuZreZHZt cFU4L13num4wZ87uj47lTX7ule3Wbur1nDB4cD0G81jB76FaNgl7R6fvCT+77ody6F7/t6mvviNJ kRq2XwpeWS88LwLJdhx1JQvLjKm0UClZcc5wJGJK2u8YY/fb/FUT4fjkubVIq2r4F6NrWwdNFcZa ooaqpURx6ZfdOioeiH0/CXMj0GyX6GtrCu1CvKqSOTi5SLiijFlSZYKwnqcxhi0oQwwMjsJQqUis 3GOCkMMKiYREYsoswG8vvHIXouMrOU1mcgGgjMJzVjS4yDB+OkiNj9gpWIKfS6TPs6pDf0M2Tc2r MHO6WOyBXY2nOzOI7dd8aZkHjzN5ydxAvhtIgmQzoaozKjMZEpkMI37+S7r1GD5xh+WDG1X+jWRa /19fMXEfD/N8xUlpFLQoWfmjMbuaP1Lj7656ah5Id5yJoQ1uqUAprJ0FS6EKi4VPf6tsYOjYAUSK BeyH3igZ3qIQpP5v1fYgZ3prEVyFGfDBRtSC5EtWSoolEpVESAuowSGpKsya6M4MalIBUBZyLSK2 AlGQFZSsxSLfGMoPLJpqZ5uOAqiZ6kpT1CYlLApMNRzDnrvrRYjjY44zYVyBb6Rgtq7Clda62lsa 6MD7/XIvSwqqqo445aMDXVbZdZJiSoMcLVbFnjy541EQAOVQDoNpVPHdESXCvKeYG3DbiU1J3N0D GF/Ac3Lnkxea8ZnJu8GSwqS0QwLqfQUPeEzY+tDUoXNMWT2qKvcdpfBn0yRklhO6d4k1MWFZmCaR QwCxFxFPVfOxch6OZfJ7F0TBhJ6RZJ4uh1NL0+mIzkmpfUvj7vXZv1xVLLX39hOE9q96dlc4Sn6H OEpXjk+d4qRRTEtCSSo5XopOX1StevxuVWpUd0Z6EVnkd/2NjDo8HPqs8+raSdIMxEOJ0zh2JkDG hqsDJiJDDnTCYcwMhUZNTBnDvKnWPhPZ2cnvOhohQm+BTeoG4T1+LyHr7mD3CaolJFKexRrdu1t+ 6rZWWkyZzfHNFS2jwi9aSYxoVdkoKkD9s+sPEvV4h3mvHunjGdacUBXfdge2sWEFhOVOWzdnpogO ZkCCgYV9GUoXyhipK25Lr6iLSZWQzmdkZpzwLSzTzBf1V2Bjq0J4u2VJU7FggdkahkP/Hkul0eK1 pUnM6KD3/WtIdZUOqHGckdPQ61sluqq6njcy6/LXgwjZmm8pe7kYd6+SFaHHO0iL2+2SRlsYlCpR U1MhgN2JzLrqiN1rLwuinRhHOitYyf2LAun2bCznOaSKgKCijR9llF/WQDz+np8jyTX8mVp9i/87 3klKFnewaM/sO2POZL2pk/OzXMjeCbItfgTLKZlyRgjU6p3FJlLbn6Rz56F0y3M4Njcu6IPYPKMD wQ/pknGG2nukloUVrItixetI602A92riIg5IheG5lqcTrozQ3QzD1QzHB4Q2QAyZA9cibI5tWuUO M4t3YtwuoONEcTUmpKJjLYo0CIPIBVBVSlNAc/b2UoWYogPERTLCrh6QShCq4eaAOmw6VKzDJiQL VRLUsMoFKDwy7BVSCxEi9JTCiidgy9JIVDFEA2z0CpBJVILVCgJUtYBqtrAe0OvOFqN0X5oIkBis BQhuLIcfz7iTbn3zfAoUFDeDl6cSHHBuiIiz2wA9ISaQhcnHTMz1IMZj3lTlI/exCUq7Zod8ZilD tSRZgLjVabHwey+fPXLYq+h9exjIyzlPFzHk7Yhqs3rSbMlPudfppX8PX/VZbBhFuMGcCD2ME3rO MPAmW2m3OKhQ2FAOdmxLo2UY8J564zUSYVDBJMY2unW3M/++c9JFadQUwiMe7z8AckxkPpY9VOsO TnHqxwLGbHrssHuhlW+TD+6CBBUDz47Jzc7JYf66n2HznkSDxJBDAEkYoQCETXzpumgt3ffNxP3F 5jqjIZpRERRIqMX4GnXiFBDbpCFd007CT2kGVZdU6SO3VDfKuZ4pExiUOe9zuPG+DZZzhgDYCJeS SigsDBly0dO4HYzQhh8ekRMS70MTxq9QalDWkw6/EcoSaXYBQalCXak+Q4gXmIxwdEc/k9Jzm1Or 9D7eUanqjVxVsos22WqUNeYu7aqkBnZ58ipDCSgOAa4QzPPDQYJ9daszQqHaVCZ4JhnsY8p1SvwH 9ygou0Rf7WfHCdOxs6cPVC4Kic1WQqUVFzQhFV4AAVUkZAwUEKCFybrRZkHISuOrXoV6pIARCQRT g2WkDtjGG5yJ1qZjGiJx1y5Byvs2vHGTUjfotUOCz/DPq6LbUVJzK6UUfTQsrepVa2T+wj+STZ43 io3ZXLwCofJxSoI9dSjRIDCow5yjcMlnDYHCRZJShw6pc87Olp2tjStL7FWWIKmnuJPgfVg6vdXq 9dFAlNOuB/HV/7fbf4+0rjye4l0dRR6Ug+0mIb35G94CO5ShSNCMgiWfQcpupjkF79+TIBZdIJBO aua6B3yVK0HgimqypqqVNn8ge4gS3GTznqH9ZqP6I1eF43Q6dse1vaBxg0hWBgE63oSjkmQ7MEZh +C04Si+HRxFgnbShLTiVqqRjcKoqeWBqwG/sQhXOYAzuEbMYl4P0l0NiNVU0BAzBMAYkoPVCpZDu QS9IHRPCnlfp7AvVsICcRTFYZQ6cdYFqfeTvSxlspkZIk9xy7dk26xoHF4EkFl3gIVjBdFBBAqAy KOgHJJdCXAyLlQChkgZYoJVFQLk6TeBjGLkMi/5GmMPGpMWkSlE30OdPiyk6G2MR9hfDUBu2cEOq DbFUsk4xLGBLH8cAGadmUyAS6MFpFkh7oaELLN8Lk34IYC6N51fN0PnEWT9tS4UGq1klFrDXQuXc c0zwfqnfHWP1/a4dJHjHc2RgQtLcZM4HRVggVaS1D88ZE1FiW9AfMtFCbyW4n0p8YdB1apLJAKFQ hzhNBCCs4FdYm5hLIpfgcqoYrpL/az59V/fjKlNJLpjYjilqKbyRMZ5bxouQ0hQ0MQkgyuAM/ZVp LlS1WiKRRSHxA0iNbDrlzmplyWTx17bLSDeLguczQLl0UahykBeHJnYb0lKJL5SS5pvu5ntT/Idn GZcPaGnXswlow7N1Cr6TaMK4HYEwjzi+5FWVq7HyWklSFE/y+MPruslU2SWiawpjJndBw+GHYYSv vtLqOsdPKOHFP0R9Ptj9d+/W9FyoqH173vxWo/NQm6+kQEEHpkOdiIs9Y2APIQQVB0LxzE8aFR41 oOeOXBySPRHbH5J793eeo+7tkknf5u8bT9EdvUreR22hhVFVR4CktYtLSdYVSKLxQqDbSskYgqEF YKYKIVJV0XBSCyDJEYxWKq85iJQHiDCT1sD8WJCSk0lT3HxoxraogoRhIyjVwvAwmuLriLPT8Hqv 0MniWRa5dBvSIIbwsS6Zb6As06W/jGB1E3YOMOOvWu139o6S98gamQLNlwK2D1Qn4apPqES2ODzY Qb31xv1zb3y5O243nziyhSEqhIoVINB+99DnTHBveSRstrtDDbdbGh2DomgwMpC4+8XaJnXdIfOT ZxR+CfgL84tWkbwjlUEpm3XbxpnHdTciFBU++QkKVRkFkW6qSTQkIwPCTnhgwmIzBgDXgh6QbMhI xCESj0+z1auzFaZm0qjGQ8NJQTadWJJNpMCKkxYZCHYZZMISdmkUoIKygySULKCiRwgLpMmEoGJh IYoMOCCUwdRxRuo8wDk5OwTdX7CWGrFUgqON1F+/KN8l5elFHa0btbCMFHpa8ZOlj+l0/wrnkhVq naa3O0jhptOqovXirSqwUlKiLNU57Mp+CqT2bM4GjMHnhkX8t0OPLNhYQc4fFjIl4BXf0IDe0TAv qaC2IldqsONI9TpkeFKpNOaMnzjLnUbeb98k+xTjZZSlrLLWWUpayy1OaLvyZfaZ25ul1Q3aDxTZ Pu/bo+EbTezM1WVG+y0WxvTXwpEeE3lCznO0oqYl5VdmMFFTIkyKgiEEExlZZIERQHUonPdg0UYg aghTcEISF4CY6i2ZSyd2KHhFzPpix69CN8XIbaFxThr2RNibvU+0d3By2snppVMr85ofDBrphUws LXZ/oatGhSv21pWQD5TfO0mLUyHoRJSYDQqKuf1sYFSlbXkaeQUHVETNFVChrmKTQJITODJsL2sK I7ObvT+JOiSRfKQ+SUFqFmkWJ9EUetbdqkrW5pIu4xmpZaSWiw0CsKMFKxbB0GCkCAQPrSh36hYf al+Lgz2msD80GSkYAb/KZB5+4pYcDtCk/CvA4BxJYB/AXy+l8tCVA+QIigk/bV2dFKxel/Me+TuZ qC5oncMMhekl7UXK5pxJ0po5CMMyRomQA2b5v1M2/EWFYtcBDyUl1TTOWOyodkl1j7xgwp2zm7cU z+kxSTklyo9BCp3QdEVUCZNxxIZkWJXHl65IiQJFqgL8ptS4BulgUh4+6nnBKy8tPC0DiYSohUQP fCiixKEESYPpjKMuQoOkYQP4VQoOz4mtHBMAFnIFFjDJP6kp8aWqL20mKLSd9F57P7cml+EzLQ3z o/RFmCdzG0WImDnWJ7arG9TwtIX/u6LSXsrePoBEcmz0TkdSSa0HaQL6EwG5Dwc51RCDB8ZT4FN6 otRkHDKKVqGyqirG7mCdO1D1ix70j9fF3QqQ3FJU+VEc/S6RDcIneqtx762pVtosudIRKwDIuiOH l3l5iMB+47EGpJC6CbItynVFT6OxCPheLxw2+nKNp/D2avV+7VGn68IYKJ0eFs4/bKbkrbhDkjpn 6TOdF7KIuO+l2hwjP8sWeUf1xtamDm9keRrRqo+VN1TRORFvzkVIX0cjUsuqO+MmFxqivSvToj2k YYT6o+0ix6Qqcmkc3WO6pHDBOjoND6mIwFFQ9EU9UeuLGrX7MkvR5dWHM8jDcUThKkHdGj8ugxPO rnciNGZXLskKKs1GIEdJOUScxVFYsKuWsRPdTXe9h6WeRM/4o0jR1x9fhyOuONuUDuDX8owv1yTo t7+XtMa9tvWy75J3FTbm2vwF6b/C8AYpecr+n0HMVvuY0rp7pa2lCz/4u5IpwoSDUGnN+A== --===============5862141872641288624==--