Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3204,7 +3204,7 @@ pub enum Statement {
DropTrigger {
if_exists: bool,
trigger_name: ObjectName,
table_name: ObjectName,
table_name: Option<ObjectName>,
/// `CASCADE` or `RESTRICT`
option: Option<ReferentialAction>,
},
Expand Down Expand Up @@ -4010,7 +4010,10 @@ impl fmt::Display for Statement {
if *if_exists {
write!(f, " IF EXISTS")?;
}
write!(f, " {trigger_name} ON {table_name}")?;
match &table_name {
Some(table_name) => write!(f, " {trigger_name} ON {table_name}")?,
None => write!(f, " {trigger_name}")?,
};
if let Some(option) = option {
write!(f, " {option}")?;
}
Expand Down
40 changes: 22 additions & 18 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4970,14 +4970,19 @@ impl<'a> Parser<'a> {
/// DROP TRIGGER [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ]
/// ```
pub fn parse_drop_trigger(&mut self) -> Result<Statement, ParserError> {
if !dialect_of!(self is PostgreSqlDialect | GenericDialect) {
if !dialect_of!(self is PostgreSqlDialect | GenericDialect | MySqlDialect) {
self.prev_token();
return self.expected("an object type after DROP", self.peek_token());
}
let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
let trigger_name = self.parse_object_name(false)?;
self.expect_keyword_is(Keyword::ON)?;
let table_name = self.parse_object_name(false)?;
let table_name = match dialect_of!(self is PostgreSqlDialect | GenericDialect) {
true => {
self.expect_keyword_is(Keyword::ON)?;
Some(self.parse_object_name(false)?)
}
false => None,
};
let option = self
.parse_one_of_keywords(&[Keyword::CASCADE, Keyword::RESTRICT])
.map(|keyword| match keyword {
Expand All @@ -4998,7 +5003,7 @@ impl<'a> Parser<'a> {
or_replace: bool,
is_constraint: bool,
) -> Result<Statement, ParserError> {
if !dialect_of!(self is PostgreSqlDialect | GenericDialect) {
if !dialect_of!(self is PostgreSqlDialect | GenericDialect | MySqlDialect) {
self.prev_token();
return self.expected("an object type after CREATE", self.peek_token());
}
Expand Down Expand Up @@ -5061,20 +5066,19 @@ impl<'a> Parser<'a> {
}

pub fn parse_trigger_period(&mut self) -> Result<TriggerPeriod, ParserError> {
Ok(
match self.expect_one_of_keywords(&[
Keyword::BEFORE,
Keyword::AFTER,
Keyword::INSTEAD,
])? {
Keyword::BEFORE => TriggerPeriod::Before,
Keyword::AFTER => TriggerPeriod::After,
Keyword::INSTEAD => self
.expect_keyword_is(Keyword::OF)
.map(|_| TriggerPeriod::InsteadOf)?,
_ => unreachable!(),
},
)
let allowed_keywords = if dialect_of!(self is MySqlDialect) {
vec![Keyword::BEFORE, Keyword::AFTER]
} else {
vec![Keyword::BEFORE, Keyword::AFTER, Keyword::INSTEAD]
};
Ok(match self.expect_one_of_keywords(&allowed_keywords)? {
Keyword::BEFORE => TriggerPeriod::Before,
Keyword::AFTER => TriggerPeriod::After,
Keyword::INSTEAD => self
.expect_keyword_is(Keyword::OF)
.map(|_| TriggerPeriod::InsteadOf)?,
_ => unreachable!(),
})
}

pub fn parse_trigger_event(&mut self) -> Result<TriggerEvent, ParserError> {
Expand Down
52 changes: 52 additions & 0 deletions tests/sqlparser_mysql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3255,3 +3255,55 @@ fn parse_looks_like_single_line_comment() {
"UPDATE account SET balance = balance WHERE account_id = 5752",
);
}

#[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, "");
assert_eq!(
create_stmt,
Statement::CreateTrigger {
or_replace: false,
is_constraint: false,
name: ObjectName::from(vec![Ident::new("emp_stamp")]),
period: TriggerPeriod::Before,
events: vec![TriggerEvent::Insert],
table_name: ObjectName::from(vec![Ident::new("emp")]),
referenced_table_name: None,
referencing: vec![],
trigger_object: TriggerObject::Row,
include_each: true,
condition: None,
exec_body: TriggerExecBody {
exec_type: TriggerExecBodyType::Function,
func_desc: FunctionDesc {
name: ObjectName::from(vec![Ident::new("emp_stamp")]),
args: None,
}
},
characteristics: None,
}
);
}

#[test]
fn parse_drop_trigger() {
let sql_drop_trigger = "DROP TRIGGER emp_stamp;";
let drop_stmt = mysql().one_statement_parses_to(sql_drop_trigger, "");
assert_eq!(
drop_stmt,
Statement::DropTrigger {
if_exists: false,
trigger_name: ObjectName::from(vec![Ident::new("emp_stamp")]),
table_name: None,
option: None,
}
);
let sql_drop_trigger_invalid = "DROP TRIGGER emp_stamp on emp;";
assert!(mysql()
.parse_sql_statements(sql_drop_trigger_invalid)
.is_err());
}
4 changes: 2 additions & 2 deletions tests/sqlparser_postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4958,7 +4958,7 @@ fn parse_drop_trigger() {
Statement::DropTrigger {
if_exists,
trigger_name: ObjectName::from(vec![Ident::new("check_update")]),
table_name: ObjectName::from(vec![Ident::new("table_name")]),
table_name: Some(ObjectName::from(vec![Ident::new("table_name")])),
option
}
);
Expand Down Expand Up @@ -5211,7 +5211,7 @@ fn parse_trigger_related_functions() {
Statement::DropTrigger {
if_exists: false,
trigger_name: ObjectName::from(vec![Ident::new("emp_stamp")]),
table_name: ObjectName::from(vec![Ident::new("emp")]),
table_name: Some(ObjectName::from(vec![Ident::new("emp")])),
option: None
}
);
Expand Down