summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.com>2022-01-13 14:20:05 +0400
committerAlexander Barkov <bar@mariadb.com>2022-01-14 06:18:13 +0400
commit2832b949fcd06f7be7fb280df327acbae9797fe8 (patch)
tree99586ed96c1ebade4ec0d78393cec92219ae87bd
parent6d8794e5670134196bc871f8c6b8406b1ac8cb85 (diff)
downloadmariadb-git-bb-10.4-bar-MDEV-25659.tar.gz
MDEV-25659 trigger name is empty after upgrade to 10.4bb-10.4-bar-MDEV-25659
Problem: At some point, we made stored rountines fail at CREATE time instead of execution time in case of this syntax: IF unknown_variable ... END IF As a result, a trigger created before this change and contained an unknown variable worked in a bad way after upgrade: - It was displayed with an empty trigger name by SHOW CREATE TRIGGER - It was displayed with an empty trigger name by INFORMATION_SCHEMA.TRIGGERS - An attempt to DROP this trigger returned errors - nothing happened. - DROP TABLE did not remove the .TRN file corresponding to this broken trigger. Underlying code observations: The old code assumed that the trigger name resides in the current lex: if(thd->lex->spname) m_trigger_name= &thd->lex->spname->m_name; This is not always the case. Some SP statements (e.g. IF) do the following in their beginning: - create a separate local LEX - set thd->lex to this new local LEX - push the new local LEX to the stack in sp_head::m_lex and the following at the end of the statement: - pop the previous LEX from the stack sp_head::m_lex - set thd->lex back to the popped value So when the parse error happens inside e.g. IF statement, thd->lex->spname is a NULL pointer, because thd->lex points to the local LEX (without SP name) rather than the top level LEX (with SP name). Fix: - Adding a new method sp_head::find_spname_recursive() which walks inside the LEX stack sp_head::m_lex from the top (the newest, most local) to the bottom (the oldest), and finds the one which contains a non-zero spname pointer. - Using the new method inside Deprecated_trigger_syntax_handler::handle_condition(): First it still tests thd->lex->spname (like before this change), and uses it in case it is not empty. Otherwise (if thd->lex->spname is empty), it calls sp_head::find_spname_recursive() to find the LEX with a non-empty spname inside the LEX stack of the current sphead.
-rw-r--r--mysql-test/main/trigger-compat.result295
-rw-r--r--mysql-test/main/trigger-compat.test216
-rw-r--r--sql/sp_head.h17
-rw-r--r--sql/sql_trigger.cc21
4 files changed, 546 insertions, 3 deletions
diff --git a/mysql-test/main/trigger-compat.result b/mysql-test/main/trigger-compat.result
index 387d4fb1489..656edc63a7d 100644
--- a/mysql-test/main/trigger-compat.result
+++ b/mysql-test/main/trigger-compat.result
@@ -142,3 +142,298 @@ DROP TRIGGER tr12;
DROP TRIGGER tr11;
DROP TABLE t1;
DROP TABLE t2;
+#
+# MDEV-25659 trigger name is empty after upgrade to 10.4
+#
+# START: Total triggers 1, broken triggers 1, DROP TABLE
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+FLUSH TABLES;
+DELETE FROM t1 WHERE a=1;
+ERROR 42000: Trigger 'tr1' has an error in its body: 'Undeclared variable: unknown_variable'
+INSERT INTO t1 VALUES (2);
+ERROR 42000: Trigger 'tr1' has an error in its body: 'Undeclared variable: unknown_variable'
+SET time_zone='+00:00';
+SHOW TRIGGERS LIKE 't1';
+Trigger tr1
+Event DELETE
+Table t1
+Statement CREATE DEFINER=`root`@`localhost` TRIGGER tr1 AFTER DELETE ON t1 FOR EACH ROW
+BEGIN
+ IF unknown_variable
+ THEN
+ INSERT INTO t2 VALUES (OLD.a);
+ END IF;
+END
+Timing AFTER
+Created 2022-01-13 08:23:06.47
+sql_mode STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
+Definer
+character_set_client utf8
+collation_connection utf8_general_ci
+Database Collation latin1_swedish_ci
+SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='tr1';
+TRIGGER_CATALOG def
+TRIGGER_SCHEMA test
+TRIGGER_NAME tr1
+EVENT_MANIPULATION DELETE
+EVENT_OBJECT_CATALOG def
+EVENT_OBJECT_SCHEMA test
+EVENT_OBJECT_TABLE t1
+ACTION_ORDER 1
+ACTION_CONDITION NULL
+ACTION_STATEMENT CREATE DEFINER=`root`@`localhost` TRIGGER tr1 AFTER DELETE ON t1 FOR EACH ROW
+BEGIN
+ IF unknown_variable
+ THEN
+ INSERT INTO t2 VALUES (OLD.a);
+ END IF;
+END
+ACTION_ORIENTATION ROW
+ACTION_TIMING AFTER
+ACTION_REFERENCE_OLD_TABLE NULL
+ACTION_REFERENCE_NEW_TABLE NULL
+ACTION_REFERENCE_OLD_ROW OLD
+ACTION_REFERENCE_NEW_ROW NEW
+CREATED 2022-01-13 08:23:06.47
+SQL_MODE STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
+DEFINER
+CHARACTER_SET_CLIENT utf8
+COLLATION_CONNECTION utf8_general_ci
+DATABASE_COLLATION latin1_swedish_ci
+SET time_zone=DEFAULT;
+# Listing trigger files
+t1.TRG
+tr1.TRN
+# Listing trigger files done
+DROP TABLE t1;
+# Listing trigger files
+# Listing trigger files done
+# END: Total triggers 1, broken triggers 1, DROP TABLE
+# START: Total triggers 1, broken triggers 1, DROP TRIGGER
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+FLUSH TABLES;
+DELETE FROM t1 WHERE a=1;
+ERROR 42000: Trigger 'tr1' has an error in its body: 'Undeclared variable: unknown_variable'
+INSERT INTO t1 VALUES (2);
+ERROR 42000: Trigger 'tr1' has an error in its body: 'Undeclared variable: unknown_variable'
+SET time_zone='+00:00';
+SHOW TRIGGERS LIKE 't1';
+Trigger tr1
+Event DELETE
+Table t1
+Statement CREATE DEFINER=`root`@`localhost` TRIGGER tr1 AFTER DELETE ON t1 FOR EACH ROW
+BEGIN
+ IF unknown_variable
+ THEN
+ INSERT INTO t2 VALUES (OLD.a);
+ END IF;
+END
+Timing AFTER
+Created 2022-01-13 08:23:06.47
+sql_mode STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
+Definer
+character_set_client utf8
+collation_connection utf8_general_ci
+Database Collation latin1_swedish_ci
+SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='tr1';
+TRIGGER_CATALOG def
+TRIGGER_SCHEMA test
+TRIGGER_NAME tr1
+EVENT_MANIPULATION DELETE
+EVENT_OBJECT_CATALOG def
+EVENT_OBJECT_SCHEMA test
+EVENT_OBJECT_TABLE t1
+ACTION_ORDER 1
+ACTION_CONDITION NULL
+ACTION_STATEMENT CREATE DEFINER=`root`@`localhost` TRIGGER tr1 AFTER DELETE ON t1 FOR EACH ROW
+BEGIN
+ IF unknown_variable
+ THEN
+ INSERT INTO t2 VALUES (OLD.a);
+ END IF;
+END
+ACTION_ORIENTATION ROW
+ACTION_TIMING AFTER
+ACTION_REFERENCE_OLD_TABLE NULL
+ACTION_REFERENCE_NEW_TABLE NULL
+ACTION_REFERENCE_OLD_ROW OLD
+ACTION_REFERENCE_NEW_ROW NEW
+CREATED 2022-01-13 08:23:06.47
+SQL_MODE STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
+DEFINER
+CHARACTER_SET_CLIENT utf8
+COLLATION_CONNECTION utf8_general_ci
+DATABASE_COLLATION latin1_swedish_ci
+SET time_zone=DEFAULT;
+# Listing trigger files
+t1.TRG
+tr1.TRN
+# Listing trigger files done
+DROP TRIGGER tr1;
+# Listing trigger files
+# Listing trigger files done
+DROP TABLE t1;
+# END: Total triggers 1, broken triggers 1, DROP TRIGGER
+# START: Total triggers 2, broken triggers 1, DROP TABLE
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+FLUSH TABLES;
+DELETE FROM t1 WHERE a=1;
+ERROR 42000: Trigger 'tr1' has an error in its body: 'Undeclared variable: unknown_variable'
+INSERT INTO t1 VALUES (2);
+ERROR 42000: Trigger 'tr1' has an error in its body: 'Undeclared variable: unknown_variable'
+SET time_zone='+00:00';
+SHOW TRIGGERS LIKE 't1';
+Trigger tr2
+Event INSERT
+Table t1
+Statement INSERT INTO t2 VALUES (NEW.a+100)
+Timing AFTER
+Created 2022-01-13 10:01:48.74
+sql_mode STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
+Definer root@localhost
+character_set_client utf8
+collation_connection utf8_general_ci
+Database Collation latin1_swedish_ci
+Trigger tr1
+Event DELETE
+Table t1
+Statement CREATE DEFINER=`root`@`localhost` TRIGGER tr1 AFTER DELETE ON t1 FOR EACH ROW
+BEGIN
+ IF unknown_variable
+ THEN
+ INSERT INTO t2 VALUES (OLD.a);
+ END IF;
+END
+Timing AFTER
+Created 2022-01-13 10:01:48.73
+sql_mode STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
+Definer
+character_set_client utf8
+collation_connection utf8_general_ci
+Database Collation latin1_swedish_ci
+SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='tr1';
+TRIGGER_CATALOG def
+TRIGGER_SCHEMA test
+TRIGGER_NAME tr1
+EVENT_MANIPULATION DELETE
+EVENT_OBJECT_CATALOG def
+EVENT_OBJECT_SCHEMA test
+EVENT_OBJECT_TABLE t1
+ACTION_ORDER 1
+ACTION_CONDITION NULL
+ACTION_STATEMENT CREATE DEFINER=`root`@`localhost` TRIGGER tr1 AFTER DELETE ON t1 FOR EACH ROW
+BEGIN
+ IF unknown_variable
+ THEN
+ INSERT INTO t2 VALUES (OLD.a);
+ END IF;
+END
+ACTION_ORIENTATION ROW
+ACTION_TIMING AFTER
+ACTION_REFERENCE_OLD_TABLE NULL
+ACTION_REFERENCE_NEW_TABLE NULL
+ACTION_REFERENCE_OLD_ROW OLD
+ACTION_REFERENCE_NEW_ROW NEW
+CREATED 2022-01-13 10:01:48.73
+SQL_MODE STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
+DEFINER
+CHARACTER_SET_CLIENT utf8
+COLLATION_CONNECTION utf8_general_ci
+DATABASE_COLLATION latin1_swedish_ci
+SET time_zone=DEFAULT;
+# Listing trigger files
+t1.TRG
+tr1.TRN
+tr2.TRN
+# Listing trigger files done
+DROP TABLE t1;
+# Listing trigger files
+# Listing trigger files done
+# END: Total triggers 2, broken triggers 1, using DROP TABLE
+# START: Total triggers 2, broken triggers 1, DROP TRIGGER
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+FLUSH TABLES;
+DELETE FROM t1 WHERE a=1;
+ERROR 42000: Trigger 'tr1' has an error in its body: 'Undeclared variable: unknown_variable'
+INSERT INTO t1 VALUES (2);
+ERROR 42000: Trigger 'tr1' has an error in its body: 'Undeclared variable: unknown_variable'
+SET time_zone='+00:00';
+SHOW TRIGGERS LIKE 't1';
+Trigger tr2
+Event INSERT
+Table t1
+Statement INSERT INTO t2 VALUES (NEW.a+100)
+Timing AFTER
+Created 2022-01-13 10:01:48.74
+sql_mode STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
+Definer root@localhost
+character_set_client utf8
+collation_connection utf8_general_ci
+Database Collation latin1_swedish_ci
+Trigger tr1
+Event DELETE
+Table t1
+Statement CREATE DEFINER=`root`@`localhost` TRIGGER tr1 AFTER DELETE ON t1 FOR EACH ROW
+BEGIN
+ IF unknown_variable
+ THEN
+ INSERT INTO t2 VALUES (OLD.a);
+ END IF;
+END
+Timing AFTER
+Created 2022-01-13 10:01:48.73
+sql_mode STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
+Definer
+character_set_client utf8
+collation_connection utf8_general_ci
+Database Collation latin1_swedish_ci
+SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='tr1';
+TRIGGER_CATALOG def
+TRIGGER_SCHEMA test
+TRIGGER_NAME tr1
+EVENT_MANIPULATION DELETE
+EVENT_OBJECT_CATALOG def
+EVENT_OBJECT_SCHEMA test
+EVENT_OBJECT_TABLE t1
+ACTION_ORDER 1
+ACTION_CONDITION NULL
+ACTION_STATEMENT CREATE DEFINER=`root`@`localhost` TRIGGER tr1 AFTER DELETE ON t1 FOR EACH ROW
+BEGIN
+ IF unknown_variable
+ THEN
+ INSERT INTO t2 VALUES (OLD.a);
+ END IF;
+END
+ACTION_ORIENTATION ROW
+ACTION_TIMING AFTER
+ACTION_REFERENCE_OLD_TABLE NULL
+ACTION_REFERENCE_NEW_TABLE NULL
+ACTION_REFERENCE_OLD_ROW OLD
+ACTION_REFERENCE_NEW_ROW NEW
+CREATED 2022-01-13 10:01:48.73
+SQL_MODE STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
+DEFINER
+CHARACTER_SET_CLIENT utf8
+COLLATION_CONNECTION utf8_general_ci
+DATABASE_COLLATION latin1_swedish_ci
+SET time_zone=DEFAULT;
+# Listing trigger files
+t1.TRG
+tr1.TRN
+tr2.TRN
+# Listing trigger files done
+DROP TRIGGER tr1;
+# Listing trigger files
+t1.TRG
+tr2.TRN
+# Listing trigger files done
+INSERT INTO t1 VALUES (100);
+ERROR 42S02: Table 'test.t2' doesn't exist
+DROP TABLE t1;
+# Listing trigger files
+# Listing trigger files done
+# END: Total triggers 2, broken triggers 1, using DROP TRIGGER
diff --git a/mysql-test/main/trigger-compat.test b/mysql-test/main/trigger-compat.test
index baf3cad11d6..4d9160c7728 100644
--- a/mysql-test/main/trigger-compat.test
+++ b/mysql-test/main/trigger-compat.test
@@ -289,3 +289,219 @@ DROP TRIGGER tr11;
DROP TABLE t1;
DROP TABLE t2;
+
+
+--echo #
+--echo # MDEV-25659 trigger name is empty after upgrade to 10.4
+--echo #
+
+--echo # START: Total triggers 1, broken triggers 1, DROP TABLE
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+
+--write_file $MYSQLD_DATADIR/test/tr1.TRN
+TYPE=TRIGGERNAME
+trigger_table=t1
+EOF
+
+--write_file $MYSQLD_DATADIR/test/t1.TRG
+TYPE=TRIGGERS
+triggers='CREATE DEFINER=`root`@`localhost` TRIGGER tr1 AFTER DELETE ON t1 FOR EACH ROW\nBEGIN\n IF unknown_variable\n THEN\n INSERT INTO t2 VALUES (OLD.a);\n END IF;\nEND'
+sql_modes=1411383296
+definers='root@localhost'
+client_cs_names='utf8'
+connection_cl_names='utf8_general_ci'
+db_cl_names='latin1_swedish_ci'
+created=164206218647
+EOF
+
+FLUSH TABLES;
+--error ER_PARSE_ERROR
+DELETE FROM t1 WHERE a=1;
+--error ER_PARSE_ERROR
+INSERT INTO t1 VALUES (2);
+
+SET time_zone='+00:00';
+--vertical_results
+SHOW TRIGGERS LIKE 't1';
+SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='tr1';
+--horizontal_results
+SET time_zone=DEFAULT;
+
+--echo # Listing trigger files
+--list_files $MYSQLD_DATADIR/test *.TR?
+--echo # Listing trigger files done
+
+DROP TABLE t1;
+
+--echo # Listing trigger files
+--list_files $MYSQLD_DATADIR/test *.TR?
+--echo # Listing trigger files done
+
+--echo # END: Total triggers 1, broken triggers 1, DROP TABLE
+
+
+--echo # START: Total triggers 1, broken triggers 1, DROP TRIGGER
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+
+--write_file $MYSQLD_DATADIR/test/tr1.TRN
+TYPE=TRIGGERNAME
+trigger_table=t1
+EOF
+
+--write_file $MYSQLD_DATADIR/test/t1.TRG
+TYPE=TRIGGERS
+triggers='CREATE DEFINER=`root`@`localhost` TRIGGER tr1 AFTER DELETE ON t1 FOR EACH ROW\nBEGIN\n IF unknown_variable\n THEN\n INSERT INTO t2 VALUES (OLD.a);\n END IF;\nEND'
+sql_modes=1411383296
+definers='root@localhost'
+client_cs_names='utf8'
+connection_cl_names='utf8_general_ci'
+db_cl_names='latin1_swedish_ci'
+created=164206218647
+EOF
+
+FLUSH TABLES;
+--error ER_PARSE_ERROR
+DELETE FROM t1 WHERE a=1;
+--error ER_PARSE_ERROR
+INSERT INTO t1 VALUES (2);
+
+SET time_zone='+00:00';
+--vertical_results
+SHOW TRIGGERS LIKE 't1';
+SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='tr1';
+--horizontal_results
+SET time_zone=DEFAULT;
+
+--echo # Listing trigger files
+--list_files $MYSQLD_DATADIR/test *.TR?
+--echo # Listing trigger files done
+
+DROP TRIGGER tr1;
+
+--echo # Listing trigger files
+--list_files $MYSQLD_DATADIR/test *.TR?
+--echo # Listing trigger files done
+
+DROP TABLE t1;
+
+--echo # END: Total triggers 1, broken triggers 1, DROP TRIGGER
+
+
+--echo # START: Total triggers 2, broken triggers 1, DROP TABLE
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+
+--write_file $MYSQLD_DATADIR/test/tr1.TRN
+TYPE=TRIGGERNAME
+trigger_table=t1
+EOF
+
+--write_file $MYSQLD_DATADIR/test/tr2.TRN
+TYPE=TRIGGERNAME
+trigger_table=t1
+EOF
+
+--write_file $MYSQLD_DATADIR/test/t1.TRG
+TYPE=TRIGGERS
+triggers='CREATE DEFINER=`root`@`localhost` TRIGGER tr2 AFTER INSERT ON t1 FOR EACH ROW INSERT INTO t2 VALUES (NEW.a+100)' 'CREATE DEFINER=`root`@`localhost` TRIGGER tr1 AFTER DELETE ON t1 FOR EACH ROW\nBEGIN\n IF unknown_variable\n THEN\n INSERT INTO t2 VALUES (OLD.a);\n END IF;\nEND'
+sql_modes=1411383296 1411383296
+definers='root@localhost' 'root@localhost'
+client_cs_names='utf8' 'utf8'
+connection_cl_names='utf8_general_ci' 'utf8_general_ci'
+db_cl_names='latin1_swedish_ci' 'latin1_swedish_ci'
+created=164206810874 164206810873
+EOF
+
+FLUSH TABLES;
+--error ER_PARSE_ERROR
+DELETE FROM t1 WHERE a=1;
+--error ER_PARSE_ERROR
+INSERT INTO t1 VALUES (2);
+
+SET time_zone='+00:00';
+--vertical_results
+SHOW TRIGGERS LIKE 't1';
+SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='tr1';
+--horizontal_results
+SET time_zone=DEFAULT;
+
+--echo # Listing trigger files
+--list_files $MYSQLD_DATADIR/test *.TR?
+--echo # Listing trigger files done
+
+DROP TABLE t1;
+
+--echo # Listing trigger files
+--list_files $MYSQLD_DATADIR/test *.TR?
+--echo # Listing trigger files done
+
+--echo # END: Total triggers 2, broken triggers 1, using DROP TABLE
+
+
+--echo # START: Total triggers 2, broken triggers 1, DROP TRIGGER
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+
+--write_file $MYSQLD_DATADIR/test/tr1.TRN
+TYPE=TRIGGERNAME
+trigger_table=t1
+EOF
+
+--write_file $MYSQLD_DATADIR/test/tr2.TRN
+TYPE=TRIGGERNAME
+trigger_table=t1
+EOF
+
+--write_file $MYSQLD_DATADIR/test/t1.TRG
+TYPE=TRIGGERS
+triggers='CREATE DEFINER=`root`@`localhost` TRIGGER tr2 AFTER INSERT ON t1 FOR EACH ROW INSERT INTO t2 VALUES (NEW.a+100)' 'CREATE DEFINER=`root`@`localhost` TRIGGER tr1 AFTER DELETE ON t1 FOR EACH ROW\nBEGIN\n IF unknown_variable\n THEN\n INSERT INTO t2 VALUES (OLD.a);\n END IF;\nEND'
+sql_modes=1411383296 1411383296
+definers='root@localhost' 'root@localhost'
+client_cs_names='utf8' 'utf8'
+connection_cl_names='utf8_general_ci' 'utf8_general_ci'
+db_cl_names='latin1_swedish_ci' 'latin1_swedish_ci'
+created=164206810874 164206810873
+EOF
+
+FLUSH TABLES;
+--error ER_PARSE_ERROR
+DELETE FROM t1 WHERE a=1;
+--error ER_PARSE_ERROR
+INSERT INTO t1 VALUES (2);
+
+SET time_zone='+00:00';
+--vertical_results
+SHOW TRIGGERS LIKE 't1';
+SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='tr1';
+--horizontal_results
+SET time_zone=DEFAULT;
+
+--echo # Listing trigger files
+--list_files $MYSQLD_DATADIR/test *.TR?
+--echo # Listing trigger files done
+
+DROP TRIGGER tr1;
+
+--echo # Listing trigger files
+--list_files $MYSQLD_DATADIR/test *.TR?
+--echo # Listing trigger files done
+
+# Now we dropped the broken trigger. Make sure the good one is fired.
+# If everything goes as expected, it will try to insert into t2,
+# which does not exists, hence the (expected) error.
+--error ER_NO_SUCH_TABLE
+INSERT INTO t1 VALUES (100);
+
+DROP TABLE t1;
+
+--echo # Listing trigger files
+--list_files $MYSQLD_DATADIR/test *.TR?
+--echo # Listing trigger files done
+
+--echo # END: Total triggers 2, broken triggers 1, using DROP TRIGGER
diff --git a/sql/sp_head.h b/sql/sp_head.h
index 500446c5e16..69232da10c7 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -612,6 +612,23 @@ public:
DBUG_RETURN(false);
}
+ /**
+ Iterate through the LEX stack from the top (the newest) to the bottom
+ (the oldest) and find the one that contains a non-zero spname.
+ @returns - the address of spname, or NULL of no spname found.
+ */
+ const sp_name *find_spname_recursive()
+ {
+ uint count= m_lex.elements;
+ for (uint i= 0; i < count; i++)
+ {
+ const LEX *tmp= m_lex.elem(count - i - 1);
+ if (tmp->spname)
+ return tmp->spname;
+ }
+ return NULL;
+ }
+
/// Put the instruction on the backpatch list, associated with the label.
int
push_backpatch(THD *thd, sp_instr *, sp_label *);
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 5802d2c811e..08cc2113706 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -292,7 +292,7 @@ class Deprecated_trigger_syntax_handler : public Internal_error_handler
private:
char m_message[MYSQL_ERRMSG_SIZE];
- LEX_CSTRING *m_trigger_name;
+ const LEX_CSTRING *m_trigger_name;
public:
@@ -308,8 +308,23 @@ public:
if (sql_errno != EE_OUTOFMEMORY &&
sql_errno != ER_OUT_OF_RESOURCES)
{
+ // Check if the current LEX contains a non-empty spname
if(thd->lex->spname)
m_trigger_name= &thd->lex->spname->m_name;
+ else if (thd->lex->sphead)
+ {
+ /*
+ Some SP statements, for example IF, create their own local LEX.
+ All LEX instances are available in the LEX stack in sphead::m_lex.
+ Let's find the one that contains a non-zero spname.
+ Note, although a parse error has happened, the LEX instances
+ in sphead::m_lex are not freed yet at this point. The first
+ found non-zero spname contains the valid trigger name.
+ */
+ const sp_name *spname= thd->lex->sphead->find_spname_recursive();
+ if (spname)
+ m_trigger_name= &spname->m_name;
+ }
if (m_trigger_name)
my_snprintf(m_message, sizeof(m_message),
ER_THD(thd, ER_ERROR_IN_TRIGGER_BODY),
@@ -322,7 +337,7 @@ public:
return false;
}
- LEX_CSTRING *get_trigger_name() { return m_trigger_name; }
+ const LEX_CSTRING *get_trigger_name() { return m_trigger_name; }
char *get_error_message() { return m_message; }
};
@@ -1490,7 +1505,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const LEX_CSTRING *db,
if (unlikely(parse_error))
{
- LEX_CSTRING *name;
+ const LEX_CSTRING *name;
/*
In case of errors, disable all triggers for the table, but keep