mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-25659 trigger name is empty after upgrade to 10.4
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.
This commit is contained in:
@ -142,3 +142,298 @@ DROP TRIGGER tr12;
|
|||||||
DROP TRIGGER tr11;
|
DROP TRIGGER tr11;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
DROP TABLE t2;
|
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
|
||||||
|
@ -289,3 +289,219 @@ DROP TRIGGER tr11;
|
|||||||
|
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
DROP TABLE t2;
|
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
|
||||||
|
@ -612,6 +612,23 @@ public:
|
|||||||
DBUG_RETURN(false);
|
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.
|
/// Put the instruction on the backpatch list, associated with the label.
|
||||||
int
|
int
|
||||||
push_backpatch(THD *thd, sp_instr *, sp_label *);
|
push_backpatch(THD *thd, sp_instr *, sp_label *);
|
||||||
|
@ -292,7 +292,7 @@ class Deprecated_trigger_syntax_handler : public Internal_error_handler
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
char m_message[MYSQL_ERRMSG_SIZE];
|
char m_message[MYSQL_ERRMSG_SIZE];
|
||||||
LEX_CSTRING *m_trigger_name;
|
const LEX_CSTRING *m_trigger_name;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -308,8 +308,23 @@ public:
|
|||||||
if (sql_errno != EE_OUTOFMEMORY &&
|
if (sql_errno != EE_OUTOFMEMORY &&
|
||||||
sql_errno != ER_OUT_OF_RESOURCES)
|
sql_errno != ER_OUT_OF_RESOURCES)
|
||||||
{
|
{
|
||||||
|
// Check if the current LEX contains a non-empty spname
|
||||||
if(thd->lex->spname)
|
if(thd->lex->spname)
|
||||||
m_trigger_name= &thd->lex->spname->m_name;
|
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)
|
if (m_trigger_name)
|
||||||
my_snprintf(m_message, sizeof(m_message),
|
my_snprintf(m_message, sizeof(m_message),
|
||||||
ER_THD(thd, ER_ERROR_IN_TRIGGER_BODY),
|
ER_THD(thd, ER_ERROR_IN_TRIGGER_BODY),
|
||||||
@ -322,7 +337,7 @@ public:
|
|||||||
return false;
|
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; }
|
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))
|
if (unlikely(parse_error))
|
||||||
{
|
{
|
||||||
LEX_CSTRING *name;
|
const LEX_CSTRING *name;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
In case of errors, disable all triggers for the table, but keep
|
In case of errors, disable all triggers for the table, but keep
|
||||||
|
Reference in New Issue
Block a user