use crate::{
Expression, Identifier, QualifiedName, Span, Spanned, Statement,
create_option::CreateOption,
expression::{PRIORITY_MAX, parse_expression_unreserved},
keywords::Keyword,
lexer::Token,
parser::{ParseError, Parser},
qualified_name::parse_qualified_name_unreserved,
statement::parse_statement,
};
use alloc::{boxed::Box, vec::Vec};
#[derive(Clone, Debug)]
pub struct ExecuteFunction<'a> {
pub execute_span: Span,
pub func_name: QualifiedName<'a>,
pub args: Vec<Expression<'a>>,
}
impl<'a> Spanned for ExecuteFunction<'a> {
fn span(&self) -> Span {
self.execute_span
.join_span(&self.func_name)
.join_span(&self.args)
}
}
#[derive(Clone, Debug)]
pub enum TriggerForEach {
Row(Span),
Statement(Span),
}
impl Spanned for TriggerForEach {
fn span(&self) -> Span {
match self {
TriggerForEach::Row(s) => s.clone(),
TriggerForEach::Statement(s) => s.clone(),
}
}
}
#[derive(Clone, Debug)]
pub enum TriggerTime {
Before(Span),
After(Span),
InsteadOf(Span),
}
impl Spanned for TriggerTime {
fn span(&self) -> Span {
match &self {
TriggerTime::Before(v) => v.span(),
TriggerTime::After(v) => v.span(),
TriggerTime::InsteadOf(v) => v.span(),
}
}
}
#[derive(Clone, Debug)]
pub enum TriggerEvent {
Update(Span),
Insert(Span),
Delete(Span),
Truncate(Span),
}
impl Spanned for TriggerEvent {
fn span(&self) -> Span {
match &self {
TriggerEvent::Update(v) => v.span(),
TriggerEvent::Insert(v) => v.span(),
TriggerEvent::Delete(v) => v.span(),
TriggerEvent::Truncate(v) => v.span(),
}
}
}
#[derive(Clone, Debug)]
pub enum TriggerReferenceDirection {
New(Span),
Old(Span),
}
impl Spanned for TriggerReferenceDirection {
fn span(&self) -> Span {
match &self {
TriggerReferenceDirection::New(v) => v.span(),
TriggerReferenceDirection::Old(v) => v.span(),
}
}
}
#[derive(Clone, Debug)]
pub struct TriggerReference<'a> {
direction: TriggerReferenceDirection,
table_as_span: Span,
alias: Identifier<'a>,
}
impl Spanned for TriggerReference<'_> {
fn span(&self) -> Span {
self.direction
.join_span(&self.table_as_span)
.join_span(&self.alias)
}
}
#[derive(Clone, Debug)]
pub struct CreateTrigger<'a> {
pub create_span: Span,
pub create_options: Vec<CreateOption<'a>>,
pub trigger_span: Span,
pub if_not_exists: Option<Span>,
pub name: Identifier<'a>,
pub trigger_time: TriggerTime,
pub trigger_events: Vec<TriggerEvent>,
pub on_span: Span,
pub table: Identifier<'a>,
pub for_each: Option<TriggerForEach>,
pub referencing: Vec<TriggerReference<'a>>,
pub when_condition: Option<(Span, Expression<'a>)>,
pub statement: Statement<'a>,
}
impl<'a> Spanned for CreateTrigger<'a> {
fn span(&self) -> Span {
self.create_span
.join_span(&self.create_options)
.join_span(&self.trigger_span)
.join_span(&self.if_not_exists)
.join_span(&self.name)
.join_span(&self.trigger_time)
.join_span(&self.trigger_events)
.join_span(&self.on_span)
.join_span(&self.table)
.join_span(&self.for_each)
.join_span(&self.referencing)
.join_span(&self.when_condition.as_ref().map(|(s, e)| s.join_span(e)))
.join_span(&self.statement)
}
}
pub(crate) fn parse_create_trigger<'a>(
parser: &mut Parser<'a, '_>,
create_span: Span,
create_options: Vec<CreateOption<'a>>,
) -> Result<CreateTrigger<'a>, ParseError> {
let trigger_span = parser.consume_keyword(Keyword::TRIGGER)?;
let if_not_exists = if let Some(if_) = parser.skip_keyword(Keyword::IF) {
Some(
parser
.consume_keywords(&[Keyword::NOT, Keyword::EXISTS])?
.join_span(&if_),
)
} else {
None
};
let name = parser.consume_plain_identifier_unreserved()?;
let trigger_time = match &parser.token {
Token::Ident(_, Keyword::AFTER) => {
TriggerTime::After(parser.consume_keyword(Keyword::AFTER)?)
}
Token::Ident(_, Keyword::BEFORE) => {
TriggerTime::Before(parser.consume_keyword(Keyword::BEFORE)?)
}
Token::Ident(_, Keyword::INSTEAD) => {
TriggerTime::InsteadOf(parser.consume_keywords(&[Keyword::INSTEAD, Keyword::OF])?)
}
_ => parser.expected_failure("'BEFORE', 'AFTER', or 'INSTEAD OF'")?,
};
let mut trigger_events = Vec::new();
loop {
let event = match &parser.token {
Token::Ident(_, Keyword::UPDATE) => {
TriggerEvent::Update(parser.consume_keyword(Keyword::UPDATE)?)
}
Token::Ident(_, Keyword::INSERT) => {
TriggerEvent::Insert(parser.consume_keyword(Keyword::INSERT)?)
}
Token::Ident(_, Keyword::DELETE) => {
TriggerEvent::Delete(parser.consume_keyword(Keyword::DELETE)?)
}
Token::Ident(_, Keyword::TRUNCATE) => {
TriggerEvent::Truncate(parser.consume_keyword(Keyword::TRUNCATE)?)
}
_ => parser.expected_failure("'UPDATE', 'INSERT', 'DELETE', or 'TRUNCATE'")?,
};
trigger_events.push(event);
if parser.skip_keyword(Keyword::OR).is_none() {
break;
}
}
let on_span = parser.consume_keyword(Keyword::ON)?;
let table = parser.consume_plain_identifier_unreserved()?;
let for_each = if parser.options.dialect.is_postgresql() {
if let Some(for_span) = parser.skip_keyword(Keyword::FOR) {
let each_span = parser.skip_keyword(Keyword::EACH);
match &parser.token {
Token::Ident(_, Keyword::ROW) => Some(TriggerForEach::Row(
for_span
.join_span(&each_span)
.join_span(&parser.consume_keyword(Keyword::ROW)?),
)),
Token::Ident(_, Keyword::STATEMENT) => Some(TriggerForEach::Statement(
for_span
.join_span(&each_span)
.join_span(&parser.consume_keyword(Keyword::STATEMENT)?),
)),
_ => Some(TriggerForEach::Row(for_span.join_span(&each_span))),
}
} else {
None
}
} else {
Some(TriggerForEach::Row(parser.consume_keywords(&[
Keyword::FOR,
Keyword::EACH,
Keyword::ROW,
])?))
};
let mut referencing = Vec::new();
if parser.skip_keyword(Keyword::REFERENCING).is_some() {
loop {
let direction = match &parser.token {
Token::Ident(_, Keyword::NEW) => {
TriggerReferenceDirection::New(parser.consume_keyword(Keyword::NEW)?)
}
Token::Ident(_, Keyword::OLD) => {
TriggerReferenceDirection::Old(parser.consume_keyword(Keyword::OLD)?)
}
_ => break,
};
let table_as_span = parser.consume_keywords(&[Keyword::TABLE, Keyword::AS])?;
let alias = parser.consume_plain_identifier_unreserved()?;
referencing.push(TriggerReference {
direction,
table_as_span,
alias,
});
}
}
let when_condition = if let Some(when_span) = parser.skip_keyword(Keyword::WHEN) {
parser.consume_token(Token::LParen)?;
let expr = parser.recovered(")", &|t| t == &Token::RParen, |parser| {
Ok(Some(parse_expression_unreserved(parser, PRIORITY_MAX)?))
})?;
parser.consume_token(Token::RParen)?;
expr.map(|e| (when_span, e))
} else {
None
};
let statement = if matches!(parser.token, Token::Ident(_, Keyword::EXECUTE)) {
let execute_span = parser.consume_keyword(Keyword::EXECUTE)?;
let execute_span = if let Some(s) = parser.skip_keyword(Keyword::FUNCTION) {
execute_span.join_span(&s)
} else {
execute_span.join_span(&parser.consume_keyword(Keyword::PROCEDURE)?)
};
let func_name = parse_qualified_name_unreserved(parser)?;
parser.consume_token(Token::LParen)?;
let mut args = Vec::new();
parser.recovered("')'", &|t| t == &Token::RParen, |parser| {
loop {
if matches!(parser.token, Token::RParen) {
break;
}
args.push(parse_expression_unreserved(parser, PRIORITY_MAX)?);
if parser.skip_token(Token::Comma).is_none() {
break;
}
}
Ok(())
})?;
parser.consume_token(Token::RParen)?;
Statement::ExecuteFunction(Box::new(ExecuteFunction {
execute_span,
func_name,
args,
}))
} else {
let old = core::mem::replace(&mut parser.permit_compound_statements, true);
let statement = match parse_statement(parser)? {
Some(v) => v,
None => parser.expected_failure("statement")?,
};
parser.permit_compound_statements = old;
statement
};
Ok(CreateTrigger {
create_span,
create_options,
trigger_span,
if_not_exists,
name,
trigger_time,
trigger_events,
on_span,
table,
for_each,
referencing,
when_condition,
statement,
})
}