This is an automated email from the ASF dual-hosted git repository.

github-bot pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git


The following commit(s) were added to refs/heads/main by this push:
     new 67684c84 SQLite: make period optional for CREATE TRIGGER (#2071)
67684c84 is described below

commit 67684c84d4c2589356c411ea4917dcf1defcd77c
Author: Thomas Kluyver <[email protected]>
AuthorDate: Wed Oct 22 10:12:06 2025 +0100

    SQLite: make period optional for CREATE TRIGGER (#2071)
    
    Co-authored-by: Ifeanyi Ubah <[email protected]>
---
 src/ast/ddl.rs              | 16 ++++++++++------
 src/dialect/mssql.rs        |  2 +-
 src/parser/mod.rs           |  2 +-
 tests/sqlparser_mssql.rs    |  2 +-
 tests/sqlparser_mysql.rs    |  2 +-
 tests/sqlparser_postgres.rs | 14 +++++++-------
 tests/sqlparser_sqlite.rs   | 16 ++++++++++------
 7 files changed, 31 insertions(+), 23 deletions(-)

diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs
index f6616536..fd481213 100644
--- a/src/ast/ddl.rs
+++ b/src/ast/ddl.rs
@@ -3063,7 +3063,7 @@ pub struct CreateTrigger {
     /// FOR EACH ROW
     /// EXECUTE FUNCTION trigger_function();
     /// ```
-    pub period: TriggerPeriod,
+    pub period: Option<TriggerPeriod>,
     /// Whether the trigger period was specified before the target table name.
     /// This does not refer to whether the period is BEFORE, AFTER, or INSTEAD 
OF,
     /// but rather the position of the period clause in relation to the table 
name.
@@ -3132,14 +3132,18 @@ impl Display for CreateTrigger {
         )?;
 
         if *period_before_table {
-            write!(f, "{period}")?;
+            if let Some(p) = period {
+                write!(f, "{p} ")?;
+            }
             if !events.is_empty() {
-                write!(f, " {}", display_separated(events, " OR "))?;
+                write!(f, "{} ", display_separated(events, " OR "))?;
             }
-            write!(f, " ON {table_name}")?;
-        } else {
             write!(f, "ON {table_name}")?;
-            write!(f, " {period}")?;
+        } else {
+            write!(f, "ON {table_name} ")?;
+            if let Some(p) = period {
+                write!(f, "{p}")?;
+            }
             if !events.is_empty() {
                 write!(f, " {}", display_separated(events, ", "))?;
             }
diff --git a/src/dialect/mssql.rs b/src/dialect/mssql.rs
index f1d54cd6..e1902b38 100644
--- a/src/dialect/mssql.rs
+++ b/src/dialect/mssql.rs
@@ -258,7 +258,7 @@ impl MsSqlDialect {
             or_replace: false,
             is_constraint: false,
             name,
-            period,
+            period: Some(period),
             period_before_table: false,
             events,
             table_name,
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index b7d69f30..b44171c7 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -5592,7 +5592,7 @@ impl<'a> Parser<'a> {
         }
 
         let name = self.parse_object_name(false)?;
-        let period = self.parse_trigger_period()?;
+        let period = self.maybe_parse(|parser| parser.parse_trigger_period())?;
 
         let events = self.parse_keyword_separated(Keyword::OR, 
Parser::parse_trigger_event)?;
         self.expect_keyword_is(Keyword::ON)?;
diff --git a/tests/sqlparser_mssql.rs b/tests/sqlparser_mssql.rs
index e11c79f0..a947db49 100644
--- a/tests/sqlparser_mssql.rs
+++ b/tests/sqlparser_mssql.rs
@@ -2392,7 +2392,7 @@ fn parse_create_trigger() {
             or_replace: false,
             is_constraint: false,
             name: ObjectName::from(vec![Ident::new("reminder1")]),
-            period: TriggerPeriod::After,
+            period: Some(TriggerPeriod::After),
             period_before_table: false,
             events: vec![TriggerEvent::Insert, TriggerEvent::Update(vec![]),],
             table_name: ObjectName::from(vec![Ident::new("Sales"), 
Ident::new("Customer")]),
diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs
index 26ef58fd..e43df87a 100644
--- a/tests/sqlparser_mysql.rs
+++ b/tests/sqlparser_mysql.rs
@@ -4034,7 +4034,7 @@ fn parse_create_trigger() {
             or_replace: false,
             is_constraint: false,
             name: ObjectName::from(vec![Ident::new("emp_stamp")]),
-            period: TriggerPeriod::Before,
+            period: Some(TriggerPeriod::Before),
             period_before_table: true,
             events: vec![TriggerEvent::Insert],
             table_name: ObjectName::from(vec![Ident::new("emp")]),
diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs
index 9d08540a..bcc15428 100644
--- a/tests/sqlparser_postgres.rs
+++ b/tests/sqlparser_postgres.rs
@@ -5640,7 +5640,7 @@ fn parse_create_simple_before_insert_trigger() {
         or_replace: false,
         is_constraint: false,
         name: ObjectName::from(vec![Ident::new("check_insert")]),
-        period: TriggerPeriod::Before,
+        period: Some(TriggerPeriod::Before),
         period_before_table: true,
         events: vec![TriggerEvent::Insert],
         table_name: ObjectName::from(vec![Ident::new("accounts")]),
@@ -5672,7 +5672,7 @@ fn parse_create_after_update_trigger_with_condition() {
         or_replace: false,
         is_constraint: false,
         name: ObjectName::from(vec![Ident::new("check_update")]),
-        period: TriggerPeriod::After,
+        period: Some(TriggerPeriod::After),
         period_before_table: true,
         events: vec![TriggerEvent::Update(vec![])],
         table_name: ObjectName::from(vec![Ident::new("accounts")]),
@@ -5711,7 +5711,7 @@ fn parse_create_instead_of_delete_trigger() {
         or_replace: false,
         is_constraint: false,
         name: ObjectName::from(vec![Ident::new("check_delete")]),
-        period: TriggerPeriod::InsteadOf,
+        period: Some(TriggerPeriod::InsteadOf),
         period_before_table: true,
         events: vec![TriggerEvent::Delete],
         table_name: ObjectName::from(vec![Ident::new("accounts")]),
@@ -5743,7 +5743,7 @@ fn 
parse_create_trigger_with_multiple_events_and_deferrable() {
         or_replace: false,
         is_constraint: true,
         name: ObjectName::from(vec![Ident::new("check_multiple_events")]),
-        period: TriggerPeriod::Before,
+        period: Some(TriggerPeriod::Before),
         period_before_table: true,
         events: vec![
             TriggerEvent::Insert,
@@ -5783,7 +5783,7 @@ fn parse_create_trigger_with_referencing() {
         or_replace: false,
         is_constraint: false,
         name: ObjectName::from(vec![Ident::new("check_referencing")]),
-        period: TriggerPeriod::Before,
+        period: Some(TriggerPeriod::Before),
         period_before_table: true,
         events: vec![TriggerEvent::Insert],
         table_name: ObjectName::from(vec![Ident::new("accounts")]),
@@ -5830,7 +5830,7 @@ fn parse_create_trigger_invalid_cases() {
         ),
         (
             "CREATE TRIGGER check_update TOMORROW UPDATE ON accounts EXECUTE 
FUNCTION check_account_update",
-            "Expected: one of FOR or BEFORE or AFTER or INSTEAD, found: 
TOMORROW"
+            "Expected: one of INSERT or UPDATE or DELETE or TRUNCATE, found: 
TOMORROW"
         ),
         (
             "CREATE TRIGGER check_update BEFORE SAVE ON accounts EXECUTE 
FUNCTION check_account_update",
@@ -6099,7 +6099,7 @@ fn parse_trigger_related_functions() {
             or_replace: false,
             is_constraint: false,
             name: ObjectName::from(vec![Ident::new("emp_stamp")]),
-            period: TriggerPeriod::Before,
+            period: Some(TriggerPeriod::Before),
             period_before_table: true,
             events: vec![TriggerEvent::Insert, TriggerEvent::Update(vec![])],
             table_name: ObjectName::from(vec![Ident::new("emp")]),
diff --git a/tests/sqlparser_sqlite.rs b/tests/sqlparser_sqlite.rs
index 943e7a23..f1f6cf49 100644
--- a/tests/sqlparser_sqlite.rs
+++ b/tests/sqlparser_sqlite.rs
@@ -647,7 +647,7 @@ fn test_create_trigger() {
             assert!(!or_replace);
             assert!(!is_constraint);
             assert_eq!(name.to_string(), "trg_inherit_asset_models");
-            assert_eq!(period, TriggerPeriod::After);
+            assert_eq!(period, Some(TriggerPeriod::After));
             assert!(period_before_table);
             assert_eq!(events, vec![TriggerEvent::Insert]);
             assert_eq!(table_name.to_string(), "assets");
@@ -693,7 +693,7 @@ fn test_create_trigger() {
             assert!(!or_replace);
             assert!(!is_constraint);
             assert_eq!(name.to_string(), "log_new_user");
-            assert_eq!(period, TriggerPeriod::After);
+            assert_eq!(period, Some(TriggerPeriod::After));
             assert!(period_before_table);
             assert_eq!(events, vec![TriggerEvent::Insert]);
             assert_eq!(table_name.to_string(), "users");
@@ -733,7 +733,7 @@ fn test_create_trigger() {
             assert!(!or_replace);
             assert!(!is_constraint);
             assert_eq!(name.to_string(), "cleanup_orders");
-            assert_eq!(period, TriggerPeriod::After);
+            assert_eq!(period, Some(TriggerPeriod::After));
             assert!(period_before_table);
             assert_eq!(events, vec![TriggerEvent::Delete]);
             assert_eq!(table_name.to_string(), "customers");
@@ -773,7 +773,7 @@ fn test_create_trigger() {
             assert!(!or_replace);
             assert!(!is_constraint);
             assert_eq!(name.to_string(), "trg_before_update");
-            assert_eq!(period, TriggerPeriod::Before);
+            assert_eq!(period, Some(TriggerPeriod::Before));
             assert!(period_before_table);
             assert_eq!(events, vec![TriggerEvent::Update(Vec::new())]);
             assert_eq!(table_name.to_string(), "products");
@@ -817,7 +817,7 @@ fn test_create_trigger() {
             assert!(!or_replace);
             assert!(!is_constraint);
             assert_eq!(name.to_string(), "trg_instead_of_insert");
-            assert_eq!(period, TriggerPeriod::InsteadOf);
+            assert_eq!(period, Some(TriggerPeriod::InsteadOf));
             assert!(period_before_table);
             assert_eq!(events, vec![TriggerEvent::Insert]);
             assert_eq!(table_name.to_string(), "my_view");
@@ -858,7 +858,7 @@ fn test_create_trigger() {
             assert!(!or_replace);
             assert!(!is_constraint);
             assert_eq!(name.to_string(), "temp_trigger");
-            assert_eq!(period, TriggerPeriod::After);
+            assert_eq!(period, Some(TriggerPeriod::After));
             assert!(period_before_table);
             assert_eq!(events, vec![TriggerEvent::Insert]);
             assert_eq!(table_name.to_string(), "temp_table");
@@ -871,6 +871,10 @@ fn test_create_trigger() {
         }
         _ => unreachable!("Expected CREATE TRIGGER statement"),
     }
+
+    // We test a trigger defined without a period (BEFORE/AFTER/INSTEAD OF)
+    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";
+    sqlite().verified_stmt(statement7);
 }
 
 #[test]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to