Skip to content

Commit a863696

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

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")]
@@ -2303,7 +2310,7 @@ pub enum Statement {
23032310
DropFunction {
23042311
if_exists: bool,
23052312
/// One or more function to drop
2306-
func_desc: Vec<DropFunctionDesc>,
2313+
func_desc: Vec<FunctionDesc>,
23072314
/// `CASCADE` or `RESTRICT`
23082315
option: Option<ReferentialAction>,
23092316
},
@@ -2313,7 +2320,7 @@ pub enum Statement {
23132320
DropProcedure {
23142321
if_exists: bool,
23152322
/// One or more function to drop
2316-
proc_desc: Vec<DropFunctionDesc>,
2323+
proc_desc: Vec<FunctionDesc>,
23172324
/// `CASCADE` or `RESTRICT`
23182325
option: Option<ReferentialAction>,
23192326
},
@@ -2639,6 +2646,96 @@ pub enum Statement {
26392646
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_a_remote_function)
26402647
remote_connection: Option<ObjectName>,
26412648
},
2649+
/// CREATE TRIGGER
2650+
///
2651+
/// Examples:
2652+
///
2653+
/// ```sql
2654+
/// CREATE TRIGGER trigger_name
2655+
/// BEFORE INSERT ON table_name
2656+
/// FOR EACH ROW
2657+
/// EXECUTE FUNCTION trigger_function();
2658+
/// ```
2659+
///
2660+
/// Postgres: <https://www.postgresql.org/docs/current/sql-createtrigger.html>
2661+
CreateTrigger {
2662+
/// The `OR REPLACE` clause is used to re-create the trigger if it already exists.
2663+
///
2664+
/// Example:
2665+
/// ```sql
2666+
/// CREATE OR REPLACE TRIGGER trigger_name
2667+
/// AFTER INSERT ON table_name
2668+
/// FOR EACH ROW
2669+
/// EXECUTE FUNCTION trigger_function();
2670+
/// ```
2671+
or_replace: bool,
2672+
/// The `CONSTRAINT` keyword is used to create a trigger as a constraint.
2673+
is_constraint: bool,
2674+
/// The name of the trigger to be created.
2675+
name: ObjectName,
2676+
/// Determines whether the function is called before, after, or instead of the event.
2677+
///
2678+
/// Example of BEFORE:
2679+
///
2680+
/// ```sql
2681+
/// CREATE TRIGGER trigger_name
2682+
/// BEFORE INSERT ON table_name
2683+
/// FOR EACH ROW
2684+
/// EXECUTE FUNCTION trigger_function();
2685+
/// ```
2686+
///
2687+
/// Example of AFTER:
2688+
///
2689+
/// ```sql
2690+
/// CREATE TRIGGER trigger_name
2691+
/// AFTER INSERT ON table_name
2692+
/// FOR EACH ROW
2693+
/// EXECUTE FUNCTION trigger_function();
2694+
/// ```
2695+
///
2696+
/// Example of INSTEAD OF:
2697+
///
2698+
/// ```sql
2699+
/// CREATE TRIGGER trigger_name
2700+
/// INSTEAD OF INSERT ON table_name
2701+
/// FOR EACH ROW
2702+
/// EXECUTE FUNCTION trigger_function();
2703+
/// ```
2704+
period: TriggerPeriod,
2705+
/// Multiple events can be specified using OR, such as `INSERT`, `UPDATE`, `DELETE`, or `TRUNCATE`.
2706+
events: Vec<TriggerEvent>,
2707+
/// The table on which the trigger is to be created.
2708+
table_name: ObjectName,
2709+
/// The optional referenced table name that can be referenced via
2710+
/// the `FROM` keyword.
2711+
referenced_table_name: Option<ObjectName>,
2712+
/// This keyword immediately precedes the declaration of one or two relation names that provide access to the transition relations of the triggering statement.
2713+
referencing: Vec<TriggerReferencing>,
2714+
/// This specifies whether the trigger function should be fired once for
2715+
/// every row affected by the trigger event, or just once per SQL statement.
2716+
trigger_object: TriggerObject,
2717+
/// Whether to include the `EACH` term of the `FOR EACH`, as it is optional syntax.
2718+
include_each: bool,
2719+
/// Triggering conditions
2720+
condition: Option<Expr>,
2721+
/// Execute logic block
2722+
exec_body: TriggerExecBody,
2723+
/// The characteristic of the trigger, which include whether the trigger is `DEFERRABLE`, `INITIALLY DEFERRED`, or `INITIALLY IMMEDIATE`,
2724+
characteristics: Option<ConstraintCharacteristics>,
2725+
},
2726+
/// DROP TRIGGER
2727+
///
2728+
/// ```sql
2729+
/// DROP TRIGGER [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ]
2730+
/// ```
2731+
///
2732+
DropTrigger {
2733+
if_exists: bool,
2734+
trigger_name: ObjectName,
2735+
table_name: ObjectName,
2736+
/// `CASCADE` or `RESTRICT`
2737+
option: Option<ReferentialAction>,
2738+
},
26422739
/// ```sql
26432740
/// CREATE PROCEDURE
26442741
/// ```
@@ -3415,6 +3512,71 @@ impl fmt::Display for Statement {
34153512
}
34163513
Ok(())
34173514
}
3515+
Statement::CreateTrigger {
3516+
or_replace,
3517+
is_constraint,
3518+
name,
3519+
period,
3520+
events,
3521+
table_name,
3522+
referenced_table_name,
3523+
referencing,
3524+
trigger_object,
3525+
condition,
3526+
include_each,
3527+
exec_body,
3528+
characteristics,
3529+
} => {
3530+
write!(
3531+
f,
3532+
"CREATE {or_replace}{is_constraint}TRIGGER {name} {period}",
3533+
or_replace = if *or_replace { "OR REPLACE " } else { "" },
3534+
is_constraint = if *is_constraint { "CONSTRAINT " } else { "" },
3535+
)?;
3536+
3537+
if !events.is_empty() {
3538+
write!(f, " {}", display_separated(events, " OR "))?;
3539+
}
3540+
write!(f, " ON {table_name}")?;
3541+
3542+
if let Some(referenced_table_name) = referenced_table_name {
3543+
write!(f, " FROM {referenced_table_name}")?;
3544+
}
3545+
3546+
if let Some(characteristics) = characteristics {
3547+
write!(f, " {characteristics}")?;
3548+
}
3549+
3550+
if !referencing.is_empty() {
3551+
write!(f, " REFERENCING {}", display_separated(referencing, " "))?;
3552+
}
3553+
3554+
if *include_each {
3555+
write!(f, " FOR EACH {trigger_object}")?;
3556+
} else {
3557+
write!(f, " FOR {trigger_object}")?;
3558+
}
3559+
if let Some(condition) = condition {
3560+
write!(f, " WHEN {condition}")?;
3561+
}
3562+
write!(f, " EXECUTE {exec_body}")
3563+
}
3564+
Statement::DropTrigger {
3565+
if_exists,
3566+
trigger_name,
3567+
table_name,
3568+
option,
3569+
} => {
3570+
write!(f, "DROP TRIGGER")?;
3571+
if *if_exists {
3572+
write!(f, " IF EXISTS")?;
3573+
}
3574+
write!(f, " {trigger_name} ON {table_name}")?;
3575+
if let Some(option) = option {
3576+
write!(f, " {option}")?;
3577+
}
3578+
Ok(())
3579+
}
34183580
Statement::CreateProcedure {
34193581
name,
34203582
or_alter,
@@ -6047,16 +6209,16 @@ impl fmt::Display for DropFunctionOption {
60476209
}
60486210
}
60496211

6050-
/// Function describe in DROP FUNCTION.
6212+
/// Generic function description for DROP FUNCTION and CREATE TRIGGER.
60516213
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
60526214
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
60536215
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
6054-
pub struct DropFunctionDesc {
6216+
pub struct FunctionDesc {
60556217
pub name: ObjectName,
60566218
pub args: Option<Vec<OperateFunctionArg>>,
60576219
}
60586220

6059-
impl fmt::Display for DropFunctionDesc {
6221+
impl fmt::Display for FunctionDesc {
60606222
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
60616223
write!(f, "{}", self.name)?;
60626224
if let Some(args) = &self.args {

0 commit comments

Comments
 (0)