Skip to content

Commit b072ce2

Browse files
LucaCappelletti94git-hulkiffyioalamb
authored
Adding support for parsing CREATE TRIGGER and DROP TRIGGER statements (#1352)
Co-authored-by: hulk <[email protected]> Co-authored-by: Ifeanyi Ubah <[email protected]> Co-authored-by: Andrew Lamb <[email protected]>
1 parent f5b818e commit b072ce2

File tree

8 files changed

+1022
-25
lines changed

8 files changed

+1022
-25
lines changed

src/ast/data_type.rs

+5
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,10 @@ pub enum DataType {
319319
/// [`SQLiteDialect`](crate::dialect::SQLiteDialect), from statements such
320320
/// as `CREATE TABLE t1 (a)`.
321321
Unspecified,
322+
/// Trigger data type, returned by functions associated with triggers
323+
///
324+
/// [postgresql]: https://www.postgresql.org/docs/current/plpgsql-trigger.html
325+
Trigger,
322326
}
323327

324328
impl fmt::Display for DataType {
@@ -543,6 +547,7 @@ impl fmt::Display for DataType {
543547
write!(f, "Nested({})", display_comma_separated(fields))
544548
}
545549
DataType::Unspecified => Ok(()),
550+
DataType::Trigger => write!(f, "TRIGGER"),
546551
}
547552
}
548553
}

src/ast/ddl.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1175,7 +1175,7 @@ fn display_option_spaced<T: fmt::Display>(option: &Option<T>) -> impl fmt::Displ
11751175
/// `<constraint_characteristics> = [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] [ ENFORCED | NOT ENFORCED ]`
11761176
///
11771177
/// Used in UNIQUE and foreign key constraints. The individual settings may occur in any order.
1178-
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1178+
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Default, Eq, Ord, Hash)]
11791179
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
11801180
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
11811181
pub struct ConstraintCharacteristics {

src/ast/mod.rs

+167-5
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ pub use self::query::{
5353
TableAlias, TableFactor, TableFunctionArgs, TableVersion, TableWithJoins, Top, TopQuantity,
5454
ValueTableMode, Values, WildcardAdditionalOptions, With, WithFill,
5555
};
56+
57+
pub use self::trigger::{
58+
TriggerEvent, TriggerExecBody, TriggerExecBodyType, TriggerObject, TriggerPeriod,
59+
TriggerReferencing, TriggerReferencingType,
60+
};
61+
5662
pub use self::value::{
5763
escape_double_quote_string, escape_quoted_string, DateTimeField, DollarQuotedString,
5864
TrimWhereField, Value,
@@ -71,6 +77,7 @@ mod dml;
7177
pub mod helpers;
7278
mod operator;
7379
mod query;
80+
mod trigger;
7481
mod value;
7582

7683
#[cfg(feature = "visitor")]
@@ -2282,7 +2289,7 @@ pub enum Statement {
22822289
DropFunction {
22832290
if_exists: bool,
22842291
/// One or more function to drop
2285-
func_desc: Vec<DropFunctionDesc>,
2292+
func_desc: Vec<FunctionDesc>,
22862293
/// `CASCADE` or `RESTRICT`
22872294
option: Option<ReferentialAction>,
22882295
},
@@ -2292,7 +2299,7 @@ pub enum Statement {
22922299
DropProcedure {
22932300
if_exists: bool,
22942301
/// One or more function to drop
2295-
proc_desc: Vec<DropFunctionDesc>,
2302+
proc_desc: Vec<FunctionDesc>,
22962303
/// `CASCADE` or `RESTRICT`
22972304
option: Option<ReferentialAction>,
22982305
},
@@ -2618,6 +2625,96 @@ pub enum Statement {
26182625
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_remote_function)
26192626
remote_connection: Option<ObjectName>,
26202627
},
2628+
/// CREATE TRIGGER
2629+
///
2630+
/// Examples:
2631+
///
2632+
/// ```sql
2633+
/// CREATE TRIGGER trigger_name
2634+
/// BEFORE INSERT ON table_name
2635+
/// FOR EACH ROW
2636+
/// EXECUTE FUNCTION trigger_function();
2637+
/// ```
2638+
///
2639+
/// Postgres: <https://www.postgresql.org/docs/current/sql-createtrigger.html>
2640+
CreateTrigger {
2641+
/// The `OR REPLACE` clause is used to re-create the trigger if it already exists.
2642+
///
2643+
/// Example:
2644+
/// ```sql
2645+
/// CREATE OR REPLACE TRIGGER trigger_name
2646+
/// AFTER INSERT ON table_name
2647+
/// FOR EACH ROW
2648+
/// EXECUTE FUNCTION trigger_function();
2649+
/// ```
2650+
or_replace: bool,
2651+
/// The `CONSTRAINT` keyword is used to create a trigger as a constraint.
2652+
is_constraint: bool,
2653+
/// The name of the trigger to be created.
2654+
name: ObjectName,
2655+
/// Determines whether the function is called before, after, or instead of the event.
2656+
///
2657+
/// Example of BEFORE:
2658+
///
2659+
/// ```sql
2660+
/// CREATE TRIGGER trigger_name
2661+
/// BEFORE INSERT ON table_name
2662+
/// FOR EACH ROW
2663+
/// EXECUTE FUNCTION trigger_function();
2664+
/// ```
2665+
///
2666+
/// Example of AFTER:
2667+
///
2668+
/// ```sql
2669+
/// CREATE TRIGGER trigger_name
2670+
/// AFTER INSERT ON table_name
2671+
/// FOR EACH ROW
2672+
/// EXECUTE FUNCTION trigger_function();
2673+
/// ```
2674+
///
2675+
/// Example of INSTEAD OF:
2676+
///
2677+
/// ```sql
2678+
/// CREATE TRIGGER trigger_name
2679+
/// INSTEAD OF INSERT ON table_name
2680+
/// FOR EACH ROW
2681+
/// EXECUTE FUNCTION trigger_function();
2682+
/// ```
2683+
period: TriggerPeriod,
2684+
/// Multiple events can be specified using OR, such as `INSERT`, `UPDATE`, `DELETE`, or `TRUNCATE`.
2685+
events: Vec<TriggerEvent>,
2686+
/// The table on which the trigger is to be created.
2687+
table_name: ObjectName,
2688+
/// The optional referenced table name that can be referenced via
2689+
/// the `FROM` keyword.
2690+
referenced_table_name: Option<ObjectName>,
2691+
/// This keyword immediately precedes the declaration of one or two relation names that provide access to the transition relations of the triggering statement.
2692+
referencing: Vec<TriggerReferencing>,
2693+
/// This specifies whether the trigger function should be fired once for
2694+
/// every row affected by the trigger event, or just once per SQL statement.
2695+
trigger_object: TriggerObject,
2696+
/// Whether to include the `EACH` term of the `FOR EACH`, as it is optional syntax.
2697+
include_each: bool,
2698+
/// Triggering conditions
2699+
condition: Option<Expr>,
2700+
/// Execute logic block
2701+
exec_body: TriggerExecBody,
2702+
/// The characteristic of the trigger, which include whether the trigger is `DEFERRABLE`, `INITIALLY DEFERRED`, or `INITIALLY IMMEDIATE`,
2703+
characteristics: Option<ConstraintCharacteristics>,
2704+
},
2705+
/// DROP TRIGGER
2706+
///
2707+
/// ```sql
2708+
/// DROP TRIGGER [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ]
2709+
/// ```
2710+
///
2711+
DropTrigger {
2712+
if_exists: bool,
2713+
trigger_name: ObjectName,
2714+
table_name: ObjectName,
2715+
/// `CASCADE` or `RESTRICT`
2716+
option: Option<ReferentialAction>,
2717+
},
26212718
/// ```sql
26222719
/// CREATE PROCEDURE
26232720
/// ```
@@ -3394,6 +3491,71 @@ impl fmt::Display for Statement {
33943491
}
33953492
Ok(())
33963493
}
3494+
Statement::CreateTrigger {
3495+
or_replace,
3496+
is_constraint,
3497+
name,
3498+
period,
3499+
events,
3500+
table_name,
3501+
referenced_table_name,
3502+
referencing,
3503+
trigger_object,
3504+
condition,
3505+
include_each,
3506+
exec_body,
3507+
characteristics,
3508+
} => {
3509+
write!(
3510+
f,
3511+
"CREATE {or_replace}{is_constraint}TRIGGER {name} {period}",
3512+
or_replace = if *or_replace { "OR REPLACE " } else { "" },
3513+
is_constraint = if *is_constraint { "CONSTRAINT " } else { "" },
3514+
)?;
3515+
3516+
if !events.is_empty() {
3517+
write!(f, " {}", display_separated(events, " OR "))?;
3518+
}
3519+
write!(f, " ON {table_name}")?;
3520+
3521+
if let Some(referenced_table_name) = referenced_table_name {
3522+
write!(f, " FROM {referenced_table_name}")?;
3523+
}
3524+
3525+
if let Some(characteristics) = characteristics {
3526+
write!(f, " {characteristics}")?;
3527+
}
3528+
3529+
if !referencing.is_empty() {
3530+
write!(f, " REFERENCING {}", display_separated(referencing, " "))?;
3531+
}
3532+
3533+
if *include_each {
3534+
write!(f, " FOR EACH {trigger_object}")?;
3535+
} else {
3536+
write!(f, " FOR {trigger_object}")?;
3537+
}
3538+
if let Some(condition) = condition {
3539+
write!(f, " WHEN {condition}")?;
3540+
}
3541+
write!(f, " EXECUTE {exec_body}")
3542+
}
3543+
Statement::DropTrigger {
3544+
if_exists,
3545+
trigger_name,
3546+
table_name,
3547+
option,
3548+
} => {
3549+
write!(f, "DROP TRIGGER")?;
3550+
if *if_exists {
3551+
write!(f, " IF EXISTS")?;
3552+
}
3553+
write!(f, " {trigger_name} ON {table_name}")?;
3554+
if let Some(option) = option {
3555+
write!(f, " {option}")?;
3556+
}
3557+
Ok(())
3558+
}
33973559
Statement::CreateProcedure {
33983560
name,
33993561
or_alter,
@@ -6026,16 +6188,16 @@ impl fmt::Display for DropFunctionOption {
60266188
}
60276189
}
60286190

6029-
/// Function describe in DROP FUNCTION.
6191+
/// Generic function description for DROP FUNCTION and CREATE TRIGGER.
60306192
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
60316193
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
60326194
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6033-
pub struct DropFunctionDesc {
6195+
pub struct FunctionDesc {
60346196
pub name: ObjectName,
60356197
pub args: Option<Vec<OperateFunctionArg>>,
60366198
}
60376199

6038-
impl fmt::Display for DropFunctionDesc {
6200+
impl fmt::Display for FunctionDesc {
60396201
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
60406202
write!(f, "{}", self.name)?;
60416203
if let Some(args) = &self.args {

0 commit comments

Comments
 (0)