use alloc::vec::Vec;
use crate::{
keywords::Keyword,
lexer::Token,
parser::{ParseError, Parser},
qualified_name::parse_qualified_name,
Identifier, QualifiedName, Span, Spanned, Statement,
};
#[derive(Debug, Clone)]
pub struct DropTable<'a> {
pub drop_span: Span,
pub temporary: Option<Span>,
pub table_span: Span,
pub if_exists: Option<Span>,
pub tables: Vec<QualifiedName<'a>>,
pub cascade: Option<Span>,
}
impl<'a> Spanned for DropTable<'a> {
fn span(&self) -> Span {
self.drop_span
.join_span(&self.temporary)
.join_span(&self.table_span)
.join_span(&self.if_exists)
.join_span(&self.tables)
}
}
#[derive(Debug, Clone)]
pub struct DropView<'a> {
pub drop_span: Span,
pub temporary: Option<Span>,
pub view_span: Span,
pub if_exists: Option<Span>,
pub views: Vec<QualifiedName<'a>>,
}
impl<'a> Spanned for DropView<'a> {
fn span(&self) -> Span {
self.drop_span
.join_span(&self.temporary)
.join_span(&self.view_span)
.join_span(&self.if_exists)
.join_span(&self.views)
}
}
#[derive(Debug, Clone)]
pub struct DropDatabase<'a> {
pub drop_span: Span,
pub database_span: Span,
pub if_exists: Option<Span>,
pub database: Identifier<'a>,
}
impl<'a> Spanned for DropDatabase<'a> {
fn span(&self) -> Span {
self.drop_span
.join_span(&self.database_span)
.join_span(&self.if_exists)
.join_span(&self.database)
}
}
#[derive(Debug, Clone)]
pub struct DropEvent<'a> {
pub drop_span: Span,
pub event_span: Span,
pub if_exists: Option<Span>,
pub event: QualifiedName<'a>,
}
impl<'a> Spanned for DropEvent<'a> {
fn span(&self) -> Span {
self.drop_span
.join_span(&self.event_span)
.join_span(&self.if_exists)
.join_span(&self.event)
}
}
#[derive(Debug, Clone)]
pub struct DropFunction<'a> {
pub drop_span: Span,
pub function_span: Span,
pub if_exists: Option<Span>,
pub function: QualifiedName<'a>,
}
impl<'a> Spanned for DropFunction<'a> {
fn span(&self) -> Span {
self.drop_span
.join_span(&self.function_span)
.join_span(&self.if_exists)
.join_span(&self.function)
}
}
#[derive(Debug, Clone)]
pub struct DropProcedure<'a> {
pub drop_span: Span,
pub procedure_span: Span,
pub if_exists: Option<Span>,
pub procedure: QualifiedName<'a>,
}
impl<'a> Spanned for DropProcedure<'a> {
fn span(&self) -> Span {
self.drop_span
.join_span(&self.procedure_span)
.join_span(&self.if_exists)
.join_span(&self.procedure)
}
}
#[derive(Debug, Clone)]
pub struct DropServer<'a> {
pub drop_span: Span,
pub server_span: Span,
pub if_exists: Option<Span>,
pub server: Identifier<'a>,
}
impl<'a> Spanned for DropServer<'a> {
fn span(&self) -> Span {
self.drop_span
.join_span(&self.server_span)
.join_span(&self.if_exists)
.join_span(&self.server)
}
}
#[derive(Debug, Clone)]
pub struct DropTrigger<'a> {
pub drop_span: Span,
pub trigger_span: Span,
pub if_exists: Option<Span>,
pub identifier: QualifiedName<'a>,
}
impl<'a> Spanned for DropTrigger<'a> {
fn span(&self) -> Span {
self.drop_span
.join_span(&self.trigger_span)
.join_span(&self.if_exists)
.join_span(&self.identifier)
}
}
pub(crate) fn parse_drop<'a>(parser: &mut Parser<'a, '_>) -> Result<Statement<'a>, ParseError> {
let drop_span = parser.consume_keyword(Keyword::DROP)?;
let temporary = parser.skip_keyword(Keyword::TEMPORARY);
match &parser.token {
Token::Ident(_, Keyword::TABLE) => {
let table_span = parser.consume_keyword(Keyword::TABLE)?;
let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
} else {
None
};
let mut tables = Vec::new();
loop {
tables.push(parse_qualified_name(parser)?);
if parser.skip_token(Token::Comma).is_none() {
break;
}
}
let cascade = if parser.options.dialect.is_postgresql() {
parser.skip_keyword(Keyword::CASCADE)
} else {
None
};
Ok(Statement::DropTable(DropTable {
drop_span,
temporary,
table_span,
if_exists,
tables,
cascade,
}))
}
Token::Ident(_, kw @ Keyword::DATABASE | kw @ Keyword::SCHEMA) => {
let kw = *kw;
let database_span = parser.consume_keyword(kw)?;
let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
} else {
None
};
let database = parser.consume_plain_identifier()?;
Ok(Statement::DropDatabase(DropDatabase {
drop_span,
database_span,
if_exists,
database,
}))
}
Token::Ident(_, Keyword::EVENT) => {
let event_span = parser.consume_keyword(Keyword::EVENT)?;
let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
} else {
None
};
let event = parse_qualified_name(parser)?;
Ok(Statement::DropEvent(DropEvent {
drop_span,
event_span,
if_exists,
event,
}))
}
Token::Ident(_, Keyword::FUNCTION) => {
let function_span = parser.consume_keyword(Keyword::FUNCTION)?;
let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
} else {
None
};
let function = parse_qualified_name(parser)?;
Ok(Statement::DropFunction(DropFunction {
drop_span,
function_span,
if_exists,
function,
}))
}
Token::Ident(_, Keyword::INDEX) => {
let index_span = parser.consume_keyword(Keyword::INDEX)?;
let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
} else {
None
};
let index_name = parser.consume_plain_identifier()?;
let on = if let Some(span) = parser.skip_keyword(Keyword::ON) {
let table_name = parse_qualified_name(parser)?;
Some((span, table_name))
} else {
None
};
let v = DropIndex {
drop_span,
index_span,
if_exists,
index_name,
on,
};
if v.on.is_none() && parser.options.dialect.is_maria() {
parser.err("On required for index drops in MariaDb", &v);
}
if v.on.is_some() && parser.options.dialect.is_postgresql() {
parser.err("On not supported for index drops in PostgreSQL", &v);
}
Ok(Statement::DropIndex(v))
}
Token::Ident(_, Keyword::PROCEDURE) => {
let procedure_span = parser.consume_keyword(Keyword::PROCEDURE)?;
let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
} else {
None
};
let procedure = parse_qualified_name(parser)?;
Ok(Statement::DropProcedure(DropProcedure {
drop_span,
procedure_span,
if_exists,
procedure,
}))
}
Token::Ident(_, Keyword::SEQUENCE) => {
parser.todo(file!(), line!())
}
Token::Ident(_, Keyword::SERVER) => {
let server_span = parser.consume_keyword(Keyword::SERVER)?;
let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
} else {
None
};
let server = parser.consume_plain_identifier()?;
Ok(Statement::DropServer(DropServer {
drop_span,
server_span,
if_exists,
server,
}))
}
Token::Ident(_, Keyword::TRIGGER) => {
let trigger_span = parser.consume_keyword(Keyword::TRIGGER)?;
let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
} else {
None
};
let identifier = parse_qualified_name(parser)?;
Ok(Statement::DropTrigger(DropTrigger {
drop_span,
trigger_span,
if_exists,
identifier,
}))
}
Token::Ident(_, Keyword::VIEW) => {
let view_span = parser.consume_keyword(Keyword::VIEW)?;
let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
} else {
None
};
let mut views = Vec::new();
loop {
views.push(parse_qualified_name(parser)?);
if parser.skip_token(Token::Comma).is_none() {
break;
}
}
Ok(Statement::DropView(DropView {
drop_span,
temporary,
view_span,
if_exists,
views,
}))
}
Token::Ident(_, Keyword::USER) => {
parser.todo(file!(), line!())
}
_ => parser.expected_failure("droppable"),
}
}
#[derive(Debug, Clone)]
pub struct DropIndex<'a> {
pub drop_span: Span,
pub index_span: Span,
pub if_exists: Option<Span>,
pub index_name: Identifier<'a>,
pub on: Option<(Span, QualifiedName<'a>)>,
}
impl<'a> Spanned for DropIndex<'a> {
fn span(&self) -> Span {
self.drop_span
.join_span(&self.index_span)
.join_span(&self.if_exists)
.join_span(&self.index_name)
.join_span(&self.on)
}
}