Skip to content

Commit f3ac084

Browse files
committed
SQLite: make period optional for CREATE TRIGGER
1 parent f861566 commit f3ac084

File tree

7 files changed

+85
-22
lines changed

7 files changed

+85
-22
lines changed

src/ast/ddl.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3029,7 +3029,9 @@ pub struct CreateTrigger {
30293029
/// FOR EACH ROW
30303030
/// EXECUTE FUNCTION trigger_function();
30313031
/// ```
3032-
pub period: TriggerPeriod,
3032+
///
3033+
/// This may be omitted in SQLite, the effect is equivalent to BEFORE.
3034+
pub period: Option<TriggerPeriod>,
30333035
/// Whether the trigger period was specified before the target table name.
30343036
/// This does not refer to whether the period is BEFORE, AFTER, or INSTEAD OF,
30353037
/// but rather the position of the period clause in relation to the table name.
@@ -3098,14 +3100,18 @@ impl Display for CreateTrigger {
30983100
)?;
30993101

31003102
if *period_before_table {
3101-
write!(f, "{period}")?;
3103+
if let Some(p) = period {
3104+
write!(f, "{p} ")?;
3105+
}
31023106
if !events.is_empty() {
3103-
write!(f, " {}", display_separated(events, " OR "))?;
3107+
write!(f, "{} ", display_separated(events, " OR "))?;
31043108
}
3105-
write!(f, " ON {table_name}")?;
3106-
} else {
31073109
write!(f, "ON {table_name}")?;
3108-
write!(f, " {period}")?;
3110+
} else {
3111+
write!(f, "ON {table_name} ")?;
3112+
if let Some(p) = period {
3113+
write!(f, "{p}")?;
3114+
}
31093115
if !events.is_empty() {
31103116
write!(f, " {}", display_separated(events, ", "))?;
31113117
}

src/dialect/mssql.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ impl MsSqlDialect {
258258
or_replace: false,
259259
is_constraint: false,
260260
name,
261-
period,
261+
period: Some(period),
262262
period_before_table: false,
263263
events,
264264
table_name,

src/parser/mod.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5592,7 +5592,20 @@ impl<'a> Parser<'a> {
55925592
}
55935593

55945594
let name = self.parse_object_name(false)?;
5595-
let period = self.parse_trigger_period()?;
5595+
let period = if dialect_of!(self is SQLiteDialect)
5596+
&& self
5597+
.peek_one_of_keywords(&[
5598+
Keyword::INSERT,
5599+
Keyword::UPDATE,
5600+
Keyword::DELETE,
5601+
Keyword::TRUNCATE,
5602+
])
5603+
.is_some()
5604+
{
5605+
None // SQLite: period can be skipped (equivalent to BEFORE)
5606+
} else {
5607+
Some(self.parse_trigger_period()?)
5608+
};
55965609

55975610
let events = self.parse_keyword_separated(Keyword::OR, Parser::parse_trigger_event)?;
55985611
self.expect_keyword_is(Keyword::ON)?;

tests/sqlparser_mssql.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2392,7 +2392,7 @@ fn parse_create_trigger() {
23922392
or_replace: false,
23932393
is_constraint: false,
23942394
name: ObjectName::from(vec![Ident::new("reminder1")]),
2395-
period: TriggerPeriod::After,
2395+
period: Some(TriggerPeriod::After),
23962396
period_before_table: false,
23972397
events: vec![TriggerEvent::Insert, TriggerEvent::Update(vec![]),],
23982398
table_name: ObjectName::from(vec![Ident::new("Sales"), Ident::new("Customer")]),

tests/sqlparser_mysql.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4022,7 +4022,7 @@ fn parse_create_trigger() {
40224022
or_replace: false,
40234023
is_constraint: false,
40244024
name: ObjectName::from(vec![Ident::new("emp_stamp")]),
4025-
period: TriggerPeriod::Before,
4025+
period: Some(TriggerPeriod::Before),
40264026
period_before_table: true,
40274027
events: vec![TriggerEvent::Insert],
40284028
table_name: ObjectName::from(vec![Ident::new("emp")]),

tests/sqlparser_postgres.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5640,7 +5640,7 @@ fn parse_create_simple_before_insert_trigger() {
56405640
or_replace: false,
56415641
is_constraint: false,
56425642
name: ObjectName::from(vec![Ident::new("check_insert")]),
5643-
period: TriggerPeriod::Before,
5643+
period: Some(TriggerPeriod::Before),
56445644
period_before_table: true,
56455645
events: vec![TriggerEvent::Insert],
56465646
table_name: ObjectName::from(vec![Ident::new("accounts")]),
@@ -5672,7 +5672,7 @@ fn parse_create_after_update_trigger_with_condition() {
56725672
or_replace: false,
56735673
is_constraint: false,
56745674
name: ObjectName::from(vec![Ident::new("check_update")]),
5675-
period: TriggerPeriod::After,
5675+
period: Some(TriggerPeriod::After),
56765676
period_before_table: true,
56775677
events: vec![TriggerEvent::Update(vec![])],
56785678
table_name: ObjectName::from(vec![Ident::new("accounts")]),
@@ -5711,7 +5711,7 @@ fn parse_create_instead_of_delete_trigger() {
57115711
or_replace: false,
57125712
is_constraint: false,
57135713
name: ObjectName::from(vec![Ident::new("check_delete")]),
5714-
period: TriggerPeriod::InsteadOf,
5714+
period: Some(TriggerPeriod::InsteadOf),
57155715
period_before_table: true,
57165716
events: vec![TriggerEvent::Delete],
57175717
table_name: ObjectName::from(vec![Ident::new("accounts")]),
@@ -5743,7 +5743,7 @@ fn parse_create_trigger_with_multiple_events_and_deferrable() {
57435743
or_replace: false,
57445744
is_constraint: true,
57455745
name: ObjectName::from(vec![Ident::new("check_multiple_events")]),
5746-
period: TriggerPeriod::Before,
5746+
period: Some(TriggerPeriod::Before),
57475747
period_before_table: true,
57485748
events: vec![
57495749
TriggerEvent::Insert,
@@ -5783,7 +5783,7 @@ fn parse_create_trigger_with_referencing() {
57835783
or_replace: false,
57845784
is_constraint: false,
57855785
name: ObjectName::from(vec![Ident::new("check_referencing")]),
5786-
period: TriggerPeriod::Before,
5786+
period: Some(TriggerPeriod::Before),
57875787
period_before_table: true,
57885788
events: vec![TriggerEvent::Insert],
57895789
table_name: ObjectName::from(vec![Ident::new("accounts")]),
@@ -6099,7 +6099,7 @@ fn parse_trigger_related_functions() {
60996099
or_replace: false,
61006100
is_constraint: false,
61016101
name: ObjectName::from(vec![Ident::new("emp_stamp")]),
6102-
period: TriggerPeriod::Before,
6102+
period: Some(TriggerPeriod::Before),
61036103
period_before_table: true,
61046104
events: vec![TriggerEvent::Insert, TriggerEvent::Update(vec![])],
61056105
table_name: ObjectName::from(vec![Ident::new("emp")]),

tests/sqlparser_sqlite.rs

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,7 @@ fn test_create_trigger() {
639639
assert!(!or_replace);
640640
assert!(!is_constraint);
641641
assert_eq!(name.to_string(), "trg_inherit_asset_models");
642-
assert_eq!(period, TriggerPeriod::After);
642+
assert_eq!(period, Some(TriggerPeriod::After));
643643
assert!(period_before_table);
644644
assert_eq!(events, vec![TriggerEvent::Insert]);
645645
assert_eq!(table_name.to_string(), "assets");
@@ -685,7 +685,7 @@ fn test_create_trigger() {
685685
assert!(!or_replace);
686686
assert!(!is_constraint);
687687
assert_eq!(name.to_string(), "log_new_user");
688-
assert_eq!(period, TriggerPeriod::After);
688+
assert_eq!(period, Some(TriggerPeriod::After));
689689
assert!(period_before_table);
690690
assert_eq!(events, vec![TriggerEvent::Insert]);
691691
assert_eq!(table_name.to_string(), "users");
@@ -725,7 +725,7 @@ fn test_create_trigger() {
725725
assert!(!or_replace);
726726
assert!(!is_constraint);
727727
assert_eq!(name.to_string(), "cleanup_orders");
728-
assert_eq!(period, TriggerPeriod::After);
728+
assert_eq!(period, Some(TriggerPeriod::After));
729729
assert!(period_before_table);
730730
assert_eq!(events, vec![TriggerEvent::Delete]);
731731
assert_eq!(table_name.to_string(), "customers");
@@ -765,7 +765,7 @@ fn test_create_trigger() {
765765
assert!(!or_replace);
766766
assert!(!is_constraint);
767767
assert_eq!(name.to_string(), "trg_before_update");
768-
assert_eq!(period, TriggerPeriod::Before);
768+
assert_eq!(period, Some(TriggerPeriod::Before));
769769
assert!(period_before_table);
770770
assert_eq!(events, vec![TriggerEvent::Update(Vec::new())]);
771771
assert_eq!(table_name.to_string(), "products");
@@ -809,7 +809,7 @@ fn test_create_trigger() {
809809
assert!(!or_replace);
810810
assert!(!is_constraint);
811811
assert_eq!(name.to_string(), "trg_instead_of_insert");
812-
assert_eq!(period, TriggerPeriod::InsteadOf);
812+
assert_eq!(period, Some(TriggerPeriod::InsteadOf));
813813
assert!(period_before_table);
814814
assert_eq!(events, vec![TriggerEvent::Insert]);
815815
assert_eq!(table_name.to_string(), "my_view");
@@ -850,7 +850,7 @@ fn test_create_trigger() {
850850
assert!(!or_replace);
851851
assert!(!is_constraint);
852852
assert_eq!(name.to_string(), "temp_trigger");
853-
assert_eq!(period, TriggerPeriod::After);
853+
assert_eq!(period, Some(TriggerPeriod::After));
854854
assert!(period_before_table);
855855
assert_eq!(events, vec![TriggerEvent::Insert]);
856856
assert_eq!(table_name.to_string(), "temp_table");
@@ -863,6 +863,50 @@ fn test_create_trigger() {
863863
}
864864
_ => unreachable!("Expected CREATE TRIGGER statement"),
865865
}
866+
867+
// We test a trigger defined without a period (BEFORE/AFTER/INSTEAD OF)
868+
let statement7 = "CREATE TRIGGER trg_inherit_asset_models INSERT ON assets FOR EACH ROW BEGIN INSERT INTO users (name) SELECT pam.name FROM users AS pam; END";
869+
match sqlite().verified_stmt(statement7) {
870+
Statement::CreateTrigger(CreateTrigger {
871+
or_alter,
872+
temporary,
873+
or_replace,
874+
is_constraint,
875+
name,
876+
period,
877+
period_before_table,
878+
events,
879+
table_name,
880+
referenced_table_name,
881+
referencing,
882+
trigger_object,
883+
condition,
884+
exec_body: _,
885+
statements_as,
886+
statements: _,
887+
characteristics,
888+
}) => {
889+
assert!(!or_alter);
890+
assert!(!temporary);
891+
assert!(!or_replace);
892+
assert!(!is_constraint);
893+
assert_eq!(name.to_string(), "trg_inherit_asset_models");
894+
assert_eq!(period, None);
895+
assert!(period_before_table);
896+
assert_eq!(events, vec![TriggerEvent::Insert]);
897+
assert_eq!(table_name.to_string(), "assets");
898+
assert!(referenced_table_name.is_none());
899+
assert!(referencing.is_empty());
900+
assert_eq!(
901+
trigger_object,
902+
Some(TriggerObjectKind::ForEach(TriggerObject::Row))
903+
);
904+
assert!(condition.is_none());
905+
assert!(!statements_as);
906+
assert!(characteristics.is_none());
907+
}
908+
_ => unreachable!("Expected CREATE TRIGGER statement"),
909+
}
866910
}
867911

868912
#[test]

0 commit comments

Comments
 (0)