Improve MySQL CREATE TRIGGER parsing

MySQL uses a statement body similar to MSSQL (but without the `AS`
keyword) instead of `EXECUTE` body style used in Postgres and standard
SQL. But unlike MSSQL, MySQL puts the trigger period before the target
table. We add some flags to indicate these differences and allow parsing
and round tripping MySQL triggers. The main benefit is that we can now
handle MySQL triggers which include `BEGIN; ... END;` compound
statements.
This commit is contained in:
Michael Victor Zink 2025-08-07 09:17:12 -07:00
parent 698154d0e0
commit a2940fd757
6 changed files with 58 additions and 15 deletions

View file

@ -3914,11 +3914,8 @@ fn parse_looks_like_single_line_comment() {
#[test]
fn parse_create_trigger() {
let sql_create_trigger = r#"
CREATE TRIGGER emp_stamp BEFORE INSERT ON emp
FOR EACH ROW EXECUTE FUNCTION emp_stamp();
"#;
let create_stmt = mysql().one_statement_parses_to(sql_create_trigger, "");
let sql_create_trigger = r#"CREATE TRIGGER emp_stamp BEFORE INSERT ON emp FOR EACH ROW EXECUTE FUNCTION emp_stamp()"#;
let create_stmt = mysql().verified_stmt(sql_create_trigger);
assert_eq!(
create_stmt,
Statement::CreateTrigger {
@ -3927,6 +3924,7 @@ fn parse_create_trigger() {
is_constraint: false,
name: ObjectName::from(vec![Ident::new("emp_stamp")]),
period: TriggerPeriod::Before,
period_before_table: true,
events: vec![TriggerEvent::Insert],
table_name: ObjectName::from(vec![Ident::new("emp")]),
referenced_table_name: None,
@ -3938,15 +3936,22 @@ fn parse_create_trigger() {
exec_type: TriggerExecBodyType::Function,
func_desc: FunctionDesc {
name: ObjectName::from(vec![Ident::new("emp_stamp")]),
args: None,
args: Some(vec![]),
}
}),
statements_as: false,
statements: None,
characteristics: None,
}
);
}
#[test]
fn parse_create_trigger_compound_statement() {
mysql_and_generic().verified_stmt("CREATE TRIGGER mytrigger BEFORE INSERT ON mytable FOR EACH ROW BEGIN SET NEW.a = 1; SET NEW.b = 2; END");
mysql_and_generic().verified_stmt("CREATE TRIGGER tr AFTER INSERT ON t1 FOR EACH ROW BEGIN INSERT INTO t2 VALUES (NEW.id); END");
}
#[test]
fn parse_drop_trigger() {
let sql_drop_trigger = "DROP TRIGGER emp_stamp;";