Skip to main content

qusql_parse/
drop.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5// http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12
13use alloc::{boxed::Box, vec::Vec};
14
15use crate::{
16    Identifier, QualifiedName, Span, Spanned, Statement,
17    data_type::{DataType, DataTypeContext},
18    keywords::Keyword,
19    lexer::Token,
20    operator::parse_operator_name,
21    parser::{ParseError, Parser},
22    qualified_name::parse_qualified_name_unreserved,
23};
24
25/// Drop cascade or restrict option (PostgreSQL)
26#[derive(Debug, Clone)]
27pub enum CascadeOrRestrict {
28    /// CASCADE option
29    Cascade(Span),
30    /// RESTRICT option
31    Restrict(Span),
32}
33
34impl Spanned for CascadeOrRestrict {
35    fn span(&self) -> Span {
36        match self {
37            CascadeOrRestrict::Cascade(s) => s.clone(),
38            CascadeOrRestrict::Restrict(s) => s.clone(),
39        }
40    }
41}
42
43pub(crate) fn parse_cascade_or_restrict<'a>(
44    parser: &mut Parser<'a, '_>,
45) -> Option<CascadeOrRestrict> {
46    let cascade_span = parser.skip_keyword(Keyword::CASCADE);
47    parser.postgres_only(&cascade_span);
48    let restrict_span = parser.skip_keyword(Keyword::RESTRICT);
49    parser.postgres_only(&restrict_span);
50    match (cascade_span, restrict_span) {
51        (Some(cascade), None) => Some(CascadeOrRestrict::Cascade(cascade)),
52        (None, Some(restrict)) => Some(CascadeOrRestrict::Restrict(restrict)),
53        (Some(cascade), Some(restrict)) => {
54            parser
55                .err("Cannot specify both CASCADE and RESTRICT", &cascade)
56                .frag("RESTRICT specified here", &restrict);
57            None
58        }
59        (None, None) => None,
60    }
61}
62
63/// Represent a drop table statement
64/// ```
65/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropTable, Statement, Issues};
66/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
67/// #
68/// let sql = "DROP TABLE `Employees`, `Customers`;";
69/// let mut issues = Issues::new(sql);
70///
71/// let mut stmts = parse_statements(sql, &mut issues, &options);
72///
73/// # assert!(issues.is_ok());
74/// let delete: DropTable = match stmts.pop() {
75///     Some(Statement::DropTable(d)) => *d,
76///     _ => panic!("We should get a drop table statement")
77/// };
78///
79/// assert!(delete.tables.get(0).unwrap().identifier.as_str() == "Employees");
80/// ```
81#[derive(Debug, Clone)]
82pub struct DropTable<'a> {
83    /// Span of "DROP"
84    pub drop_span: Span,
85    /// Span of "TEMPORARY" if specified
86    pub temporary: Option<Span>,
87    /// Span of "TABLE"
88    pub table_span: Span,
89    /// Span of "IF EXISTS" if specified
90    pub if_exists: Option<Span>,
91    /// List of tables to drop
92    pub tables: Vec<QualifiedName<'a>>,
93    /// Span of "CASCADE" or "RESTRICT" if specified (PostgreSQL)
94    pub restrict_or_cascade: Option<CascadeOrRestrict>,
95}
96
97impl<'a> Spanned for DropTable<'a> {
98    fn span(&self) -> Span {
99        self.drop_span
100            .join_span(&self.temporary)
101            .join_span(&self.table_span)
102            .join_span(&self.if_exists)
103            .join_span(&self.tables)
104    }
105}
106
107fn parse_drop_table<'a>(
108    parser: &mut Parser<'a, '_>,
109    drop_span: Span,
110    temporary: Option<Span>,
111) -> Result<DropTable<'a>, ParseError> {
112    let table_span = parser.consume_keyword(Keyword::TABLE)?;
113    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
114        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
115    } else {
116        None
117    };
118    let mut tables = Vec::new();
119    loop {
120        tables.push(parse_qualified_name_unreserved(parser)?);
121        if parser.skip_token(Token::Comma).is_none() {
122            break;
123        }
124    }
125    let restrict_or_cascade = parse_cascade_or_restrict(parser);
126    Ok(DropTable {
127        drop_span,
128        temporary,
129        table_span,
130        if_exists,
131        tables,
132        restrict_or_cascade,
133    })
134}
135
136/// Represent a drop view statement
137/// ```
138/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropView, Statement, Issues};
139/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
140/// #
141/// let sql = "DROP VIEW `Employees`, `Customers`;";
142/// let mut issues = Issues::new(sql);
143/// let mut stmts = parse_statements(sql, &mut issues, &options);
144///
145/// # assert!(issues.is_ok());
146/// let delete: DropView = match stmts.pop() {
147///     Some(Statement::DropView(d)) => *d,
148///     _ => panic!("We should get a drop table statement")
149/// };
150///
151/// assert!(delete.views.get(0).unwrap().identifier.as_str() == "Employees");
152/// ```
153#[derive(Debug, Clone)]
154pub struct DropView<'a> {
155    /// Span of "DROP"
156    pub drop_span: Span,
157    /// Span of "TEMPORARY" if specified
158    pub temporary: Option<Span>,
159    /// Span of "VIEW"
160    pub view_span: Span,
161    /// Span of "IF EXISTS"
162    pub if_exists: Option<Span>,
163    /// List of views to drop
164    pub views: Vec<QualifiedName<'a>>,
165    /// Span of "CASCADE" or "RESTRICT" if specified (PostgreSQL)
166    pub restrict_or_cascade: Option<CascadeOrRestrict>,
167}
168
169impl<'a> Spanned for DropView<'a> {
170    fn span(&self) -> Span {
171        self.drop_span
172            .join_span(&self.temporary)
173            .join_span(&self.view_span)
174            .join_span(&self.if_exists)
175            .join_span(&self.views)
176            .join_span(&self.restrict_or_cascade)
177    }
178}
179
180fn parse_drop_view<'a>(
181    parser: &mut Parser<'a, '_>,
182    drop_span: Span,
183    temporary: Option<Span>,
184) -> Result<DropView<'a>, ParseError> {
185    let view_span = parser.consume_keyword(Keyword::VIEW)?;
186    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
187        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
188    } else {
189        None
190    };
191    let mut views = Vec::new();
192    loop {
193        views.push(parse_qualified_name_unreserved(parser)?);
194        if parser.skip_token(Token::Comma).is_none() {
195            break;
196        }
197    }
198    let restrict_or_cascade = parse_cascade_or_restrict(parser);
199    Ok(DropView {
200        drop_span,
201        temporary,
202        view_span,
203        if_exists,
204        views,
205        restrict_or_cascade,
206    })
207}
208
209/// Represent a drop database statement
210/// ```
211/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropDatabase, Statement, Issues};
212/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
213/// #
214/// let sql = "DROP DATABASE mydb;";
215/// let mut issues = Issues::new(sql);
216/// let mut stmts = parse_statements(sql, &mut issues, &options);
217///
218/// # assert!(issues.is_ok());
219/// #
220/// let s: DropDatabase = match stmts.pop() {
221///     Some(Statement::DropDatabase(s)) => *s,
222///     _ => panic!("We should get a drop database statement")
223/// };
224///
225/// assert!(s.database.as_str() == "mydb");
226/// ```
227#[derive(Debug, Clone)]
228pub struct DropDatabase<'a> {
229    /// Span of "DROP"
230    pub drop_span: Span,
231    /// Span of "DATABASE"
232    pub database_span: Span,
233    /// Span of "IF EXISTS" if specified
234    pub if_exists: Option<Span>,
235    /// Name of database to drop
236    pub database: Identifier<'a>,
237}
238
239impl<'a> Spanned for DropDatabase<'a> {
240    fn span(&self) -> Span {
241        self.drop_span
242            .join_span(&self.database_span)
243            .join_span(&self.if_exists)
244            .join_span(&self.database)
245    }
246}
247
248fn parse_drop_database<'a>(
249    parser: &mut Parser<'a, '_>,
250    drop_span: Span,
251    kw: Keyword,
252) -> Result<DropDatabase<'a>, ParseError> {
253    // TODO complain about temporary
254    let database_span = parser.consume_keyword(kw)?;
255    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
256        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
257    } else {
258        None
259    };
260    let database = parser.consume_plain_identifier_unreserved()?;
261    Ok(DropDatabase {
262        drop_span,
263        database_span,
264        if_exists,
265        database,
266    })
267}
268
269/// Represent a drop event statement
270/// ```
271/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropEvent, Statement, Issues};
272/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
273/// #
274/// let sql = "DROP EVENT myevent;";
275/// let mut issues = Issues::new(sql);
276/// let mut stmts = parse_statements(sql, &mut issues, &options);
277///
278/// # assert!(issues.is_ok());
279/// let s: DropEvent = match stmts.pop() {
280///     Some(Statement::DropEvent(s)) => *s,
281///     _ => panic!("We should get a drop event statement")
282/// };
283///
284/// assert!(s.event.identifier.as_str() == "myevent");
285/// ```
286#[derive(Debug, Clone)]
287pub struct DropEvent<'a> {
288    /// Span of "DROP"
289    pub drop_span: Span,
290    /// Span of "EVENT"
291    pub event_span: Span,
292    /// Span of "IF EXISTS" if specified
293    pub if_exists: Option<Span>,
294    /// Event to drop
295    pub event: QualifiedName<'a>,
296}
297
298impl<'a> Spanned for DropEvent<'a> {
299    fn span(&self) -> Span {
300        self.drop_span
301            .join_span(&self.event_span)
302            .join_span(&self.if_exists)
303            .join_span(&self.event)
304    }
305}
306
307fn parse_drop_event<'a>(
308    parser: &mut Parser<'a, '_>,
309    drop_span: Span,
310) -> Result<DropEvent<'a>, ParseError> {
311    // TODO complain about temporary
312    let event_span = parser.consume_keyword(Keyword::EVENT)?;
313    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
314        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
315    } else {
316        None
317    };
318    let event = parse_qualified_name_unreserved(parser)?;
319    Ok(DropEvent {
320        drop_span,
321        event_span,
322        if_exists,
323        event,
324    })
325}
326
327#[derive(Debug, Clone)]
328pub enum DropFunctionArgMode {
329    In(Span),
330    Out(Span),
331    InOut(Span),
332}
333
334impl Spanned for DropFunctionArgMode {
335    fn span(&self) -> Span {
336        match self {
337            DropFunctionArgMode::In(s) => s.clone(),
338            DropFunctionArgMode::Out(s) => s.clone(),
339            DropFunctionArgMode::InOut(s) => s.clone(),
340        }
341    }
342}
343
344#[derive(Debug, Clone)]
345pub struct DropFunctionArg<'a> {
346    pub mode: Option<DropFunctionArgMode>,
347    pub name: Option<Identifier<'a>>,
348    pub data_type: DataType<'a>,
349    pub default: Option<Span>, // = value (span only, for now)
350}
351
352impl<'a> Spanned for DropFunctionArg<'a> {
353    fn span(&self) -> Span {
354        self.data_type
355            .span()
356            .join_span(&self.mode)
357            .join_span(&self.name)
358            .join_span(&self.default)
359    }
360}
361
362/// Represent a drop function statement
363/// ```
364/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropFunction, Statement, Issues};
365/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
366/// #
367/// let sql = "DROP FUNCTION myfunc;";
368/// let mut issues = Issues::new(sql);
369/// let mut stmts = parse_statements(sql, &mut issues, &options);
370///
371/// # assert!(issues.is_ok());
372/// let s: DropFunction = match stmts.pop() {
373///     Some(Statement::DropFunction(s)) => *s,
374///     _ => panic!("We should get a drop function statement")
375/// };
376///
377/// assert!(s.functions.get(0).unwrap().0.identifier.as_str() == "myfunc");
378/// ```
379#[derive(Debug, Clone)]
380pub struct DropFunction<'a> {
381    /// Span of "DROP"
382    pub drop_span: Span,
383    /// Span of "FUNCTION"
384    pub function_span: Span,
385    /// Span of "IF EXISTS" if specified
386    pub if_exists: Option<Span>,
387    /// List of functions to drop (PostgreSQL: can be multiple)
388    pub functions: Vec<(QualifiedName<'a>, Option<Vec<DropFunctionArg<'a>>>)>,
389    /// Restrict or cascade option (PostgreSQL)
390    pub restrict_or_cascade: Option<CascadeOrRestrict>,
391}
392
393impl<'a> Spanned for DropFunction<'a> {
394    fn span(&self) -> Span {
395        let mut span = self
396            .drop_span
397            .join_span(&self.function_span)
398            .join_span(&self.if_exists)
399            .join_span(&self.restrict_or_cascade);
400        for (name, args) in &self.functions {
401            span = span.join_span(name);
402            if let Some(args) = args {
403                for arg in args {
404                    span = span.join_span(arg);
405                }
406            }
407        }
408        span
409    }
410}
411
412fn parse_drop_function<'a>(
413    parser: &mut Parser<'a, '_>,
414    drop_span: Span,
415) -> Result<DropFunction<'a>, ParseError> {
416    let function_span = parser.consume_keyword(Keyword::FUNCTION)?;
417    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
418        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
419    } else {
420        None
421    };
422    let mut functions = Vec::new();
423    loop {
424        let name = parse_qualified_name_unreserved(parser)?;
425        let args = if parser.token == Token::LParen {
426            let lparen = parser.consume_token(Token::LParen)?;
427            let mut arg_list = Vec::new();
428            parser.recovered(")", &|t| t == &Token::RParen, |parser| {
429                loop {
430                    // Parse mode (IN, OUT, INOUT)
431                    let mode = match &parser.token {
432                        Token::Ident(_, Keyword::IN) => Some(DropFunctionArgMode::In(
433                            parser.consume_keyword(Keyword::IN)?,
434                        )),
435                        Token::Ident(_, Keyword::OUT) => Some(DropFunctionArgMode::Out(
436                            parser.consume_keyword(Keyword::OUT)?,
437                        )),
438                        Token::Ident(_, Keyword::INOUT) => Some(DropFunctionArgMode::InOut(
439                            parser.consume_keyword(Keyword::INOUT)?,
440                        )),
441                        _ => None,
442                    };
443                    // Parse parameter name (optional)
444                    let name = match &parser.token {
445                        Token::Ident(_, kw) if !kw.restricted(parser.reserved()) => {
446                            Some(parser.consume_plain_identifier_unreserved()?)
447                        }
448                        _ => None,
449                    };
450                    // Parse data type
451                    let data_type =
452                        crate::data_type::parse_data_type(parser, DataTypeContext::FunctionParam)?;
453                    // Parse default value (optional)
454                    let default = if parser.skip_token(Token::Eq).is_some() {
455                        // Just record the span for now
456                        Some(parser.consume().clone())
457                    } else {
458                        None
459                    };
460                    arg_list.push(DropFunctionArg {
461                        mode,
462                        name,
463                        data_type,
464                        default,
465                    });
466                    if parser.skip_token(Token::Comma).is_none() {
467                        break;
468                    }
469                }
470                Ok(())
471            })?;
472            parser.consume_token(Token::RParen)?;
473            parser.postgres_only(&lparen.join_span(&arg_list));
474            Some(arg_list)
475        } else {
476            None
477        };
478        functions.push((name, args));
479        if parser.skip_token(Token::Comma).is_none() {
480            break;
481        }
482    }
483    if let [(first, _), (second, _), ..] = functions.as_slice()
484        && !parser.options.dialect.is_postgresql()
485    {
486        parser
487            .err("Multiple function only supported by ", second)
488            .frag("First function supplied here", first);
489    }
490    let restrict_or_cascade = parse_cascade_or_restrict(parser);
491    Ok(DropFunction {
492        drop_span,
493        function_span,
494        if_exists,
495        functions,
496        restrict_or_cascade,
497    })
498}
499
500/// Represent a drop procedure statement
501/// ```
502/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropProcedure, Statement, Issues};
503/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
504/// #
505/// let sql = "DROP PROCEDURE myproc;";
506/// let mut issues = Issues::new(sql);
507/// let mut stmts = parse_statements(sql, &mut issues, &options);
508///
509/// # assert!(issues.is_ok());
510/// let s: DropProcedure = match stmts.pop() {
511///     Some(Statement::DropProcedure(s)) => *s,
512///     _ => panic!("We should get a drop procedure statement")
513/// };
514///
515/// assert!(s.procedure.identifier.as_str() == "myproc");
516/// ```
517#[derive(Debug, Clone)]
518pub struct DropProcedure<'a> {
519    /// Span of "DROP"
520    pub drop_span: Span,
521    /// Span of "PROCEDURE"
522    pub procedure_span: Span,
523    /// Span of "IF EXISTS" if specified
524    pub if_exists: Option<Span>,
525    /// Procedure to drop
526    pub procedure: QualifiedName<'a>,
527}
528
529impl<'a> Spanned for DropProcedure<'a> {
530    fn span(&self) -> Span {
531        self.drop_span
532            .join_span(&self.procedure_span)
533            .join_span(&self.if_exists)
534            .join_span(&self.procedure)
535    }
536}
537
538fn parse_drop_procedure<'a>(
539    parser: &mut Parser<'a, '_>,
540    drop_span: Span,
541) -> Result<DropProcedure<'a>, ParseError> {
542    // TODO complain about temporary
543    let procedure_span = parser.consume_keyword(Keyword::PROCEDURE)?;
544    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
545        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
546    } else {
547        None
548    };
549    let procedure = parse_qualified_name_unreserved(parser)?;
550    Ok(DropProcedure {
551        drop_span,
552        procedure_span,
553        if_exists,
554        procedure,
555    })
556}
557
558/// Represent a drop sequence statement (PostgreSQL)
559/// ```
560/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropSequence, Statement, Issues};
561/// # let options = ParseOptions::new().dialect(SQLDialect::PostgreSQL);
562/// #
563/// let sql = "DROP SEQUENCE myseq CASCADE;";
564/// let mut issues = Issues::new(sql);
565/// let mut stmts = parse_statements(sql, &mut issues, &options);
566///
567/// # assert!(issues.is_ok());
568/// let s: DropSequence = match stmts.pop() {
569///     Some(Statement::DropSequence(s)) => *s,
570///     _ => panic!("We should get a drop sequence statement")
571/// };
572///
573/// assert!(s.sequences.get(0).unwrap().identifier.as_str() == "myseq");
574/// ```
575#[derive(Debug, Clone)]
576pub struct DropSequence<'a> {
577    /// Span of "DROP"
578    pub drop_span: Span,
579    /// Span of "SEQUENCE"
580    pub sequence_span: Span,
581    /// Span of "IF EXISTS" if specified
582    pub if_exists: Option<Span>,
583    /// List of sequences to drop
584    pub sequences: Vec<QualifiedName<'a>>,
585    /// Restrict or cascade option (PostgreSQL)
586    pub restrict_or_cascade: Option<CascadeOrRestrict>,
587}
588
589impl<'a> Spanned for DropSequence<'a> {
590    fn span(&self) -> Span {
591        self.drop_span
592            .join_span(&self.sequence_span)
593            .join_span(&self.if_exists)
594            .join_span(&self.sequences)
595            .join_span(&self.restrict_or_cascade)
596    }
597}
598
599fn parse_drop_sequence<'a>(
600    parser: &mut Parser<'a, '_>,
601    drop_span: Span,
602) -> Result<DropSequence<'a>, ParseError> {
603    // DROP SEQUENCE [IF EXISTS] sequence_name [, sequence_name] ... [CASCADE | RESTRICT]
604    let sequence_span = parser.consume_keyword(Keyword::SEQUENCE)?;
605    parser.postgres_only(&sequence_span);
606    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
607        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
608    } else {
609        None
610    };
611    let mut sequences = Vec::new();
612    loop {
613        sequences.push(parse_qualified_name_unreserved(parser)?);
614        if parser.skip_token(Token::Comma).is_none() {
615            break;
616        }
617    }
618    let restrict_or_cascade = parse_cascade_or_restrict(parser);
619    Ok(DropSequence {
620        drop_span,
621        sequence_span,
622        if_exists,
623        sequences,
624        restrict_or_cascade,
625    })
626}
627
628/// Represent a drop server statement
629/// ```
630/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropServer, Statement, Issues};
631/// # let options = ParseOptions::new().dialect(SQLDialect::PostgreSQL);
632/// #
633/// let sql = "DROP SERVER myserver;";
634/// let mut issues = Issues::new(sql);
635/// let mut stmts = parse_statements(sql, &mut issues, &options);
636///
637/// # assert!(issues.is_ok());
638/// #
639/// let s: DropServer = match stmts.pop() {
640///     Some(Statement::DropServer(s)) => *s,
641///     _ => panic!("We should get a drop server statement")
642/// };
643///
644/// assert!(s.server.as_str() == "myserver");
645/// ```
646#[derive(Debug, Clone)]
647pub struct DropServer<'a> {
648    /// Span of "DROP"
649    pub drop_span: Span,
650    /// Span of "SERVER"
651    pub server_span: Span,
652    /// Span of "IF EXISTS" if specified
653    pub if_exists: Option<Span>,
654    /// Server to drop
655    pub server: Identifier<'a>,
656}
657
658impl<'a> Spanned for DropServer<'a> {
659    fn span(&self) -> Span {
660        self.drop_span
661            .join_span(&self.server_span)
662            .join_span(&self.if_exists)
663            .join_span(&self.server)
664    }
665}
666
667fn parse_drop_server<'a>(
668    parser: &mut Parser<'a, '_>,
669    drop_span: Span,
670) -> Result<DropServer<'a>, ParseError> {
671    // TODO complain about temporary
672    let server_span = parser.consume_keyword(Keyword::SERVER)?;
673    parser.postgres_only(&server_span);
674    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
675        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
676    } else {
677        None
678    };
679    let server = parser.consume_plain_identifier_unreserved()?;
680    Ok(DropServer {
681        drop_span,
682        server_span,
683        if_exists,
684        server,
685    })
686}
687
688/// Represent a drop trigger statement
689/// ```
690/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropTrigger, Statement, Issues};
691/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
692/// #
693/// let sql = "DROP TRIGGER IF EXISTS `foo`.`mytrigger`;";
694/// let mut issues = Issues::new(sql);
695/// let mut stmts = parse_statements(sql, &mut issues, &options);
696///
697/// # assert!(issues.is_ok());
698/// let s: DropTrigger = match stmts.pop() {
699///     Some(Statement::DropTrigger(s)) => *s,
700///     _ => panic!("We should get a drop trigger statement")
701/// };
702///
703/// assert!(s.identifier.identifier.as_str() == "mytrigger");
704/// ```
705#[derive(Debug, Clone)]
706pub struct DropTrigger<'a> {
707    /// Span of "DROP"
708    pub drop_span: Span,
709    /// Span of "TRIGGER"
710    pub trigger_span: Span,
711    /// Span of "IF EXISTS" if specified
712    pub if_exists: Option<Span>,
713    /// Trigger to drop
714    pub identifier: QualifiedName<'a>,
715    /// ON table_name (PostgreSQL/PostGIS)
716    pub on: Option<(Span, QualifiedName<'a>)>,
717    /// Restrict or cascade option (PostgreSQL)
718    pub restrict_or_cascade: Option<CascadeOrRestrict>,
719}
720
721impl<'a> Spanned for DropTrigger<'a> {
722    fn span(&self) -> Span {
723        self.drop_span
724            .join_span(&self.trigger_span)
725            .join_span(&self.if_exists)
726            .join_span(&self.identifier)
727            .join_span(&self.on)
728            .join_span(&self.restrict_or_cascade)
729    }
730}
731
732fn parse_drop_trigger<'a>(
733    parser: &mut Parser<'a, '_>,
734    drop_span: Span,
735) -> Result<DropTrigger<'a>, ParseError> {
736    let trigger_span = parser.consume_keyword(Keyword::TRIGGER)?;
737    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
738        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
739    } else {
740        None
741    };
742    let identifier = parse_qualified_name_unreserved(parser)?;
743    let on = if let Some(span) = parser.skip_keyword(Keyword::ON) {
744        let table_name = parse_qualified_name_unreserved(parser)?;
745        parser.postgres_only(&span);
746        Some((span, table_name))
747    } else {
748        if parser.options.dialect.is_postgresql() {
749            parser.err("ON required for trigger drops in PostgreSQL", &trigger_span);
750        }
751        None
752    };
753    let restrict_or_cascade = parse_cascade_or_restrict(parser);
754    Ok(DropTrigger {
755        drop_span,
756        trigger_span,
757        if_exists,
758        identifier,
759        on,
760        restrict_or_cascade,
761    })
762}
763
764/// Represent a drop index statement.
765///
766/// MariaDB example
767/// ```
768/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropIndex, Statement, Issues};
769/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
770/// #
771/// let sql = "DROP INDEX IF EXISTS `myindex` ON `bar`;";
772/// let mut issues = Issues::new(sql);
773/// let mut stmts = parse_statements(sql, &mut issues, &options);
774///
775/// # assert!(issues.is_ok());
776/// let s: DropIndex = match stmts.pop() {
777///     Some(Statement::DropIndex(s)) => *s,
778///     _ => panic!("We should get a drop trigger statement")
779/// };
780///
781/// assert!(s.index_name.as_str() == "myindex");
782/// ```
783///
784/// PostgreSQL example
785/// ```
786/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropIndex, Statement, Issues};
787/// # let options = ParseOptions::new().dialect(SQLDialect::PostgreSQL);
788/// #
789/// let sql = "DROP INDEX IF EXISTS \"myindex\";";
790/// let mut issues = Issues::new(sql);
791/// let mut stmts = parse_statements(sql, &mut issues, &options);
792///
793/// # assert!(issues.is_ok(), "{}", issues);
794/// #
795/// let s: DropIndex = match stmts.pop() {
796///     Some(Statement::DropIndex(s)) => *s,
797///     _ => panic!("We should get a drop trigger statement")
798/// };
799///
800/// assert!(s.index_name.as_str() == "myindex");
801/// ```
802#[derive(Debug, Clone)]
803pub struct DropIndex<'a> {
804    /// Span of "DROP"
805    pub drop_span: Span,
806    /// Span of "INDEX"
807    pub index_span: Span,
808    /// Span of "IF EXISTS" if specified
809    pub if_exists: Option<Span>,
810    /// Name of index to drop
811    pub index_name: Identifier<'a>,
812    // on tbl_name is required in MariaDB but not in PostgreSQL
813    pub on: Option<(Span, QualifiedName<'a>)>,
814    /// Restrict or cascade option (PostgreSQL)
815    pub restrict_or_cascade: Option<CascadeOrRestrict>,
816}
817
818impl<'a> Spanned for DropIndex<'a> {
819    fn span(&self) -> Span {
820        self.drop_span
821            .join_span(&self.index_span)
822            .join_span(&self.if_exists)
823            .join_span(&self.index_name)
824            .join_span(&self.on)
825            .join_span(&self.restrict_or_cascade)
826    }
827}
828
829fn parse_drop_index<'a>(
830    parser: &mut Parser<'a, '_>,
831    drop_span: Span,
832) -> Result<DropIndex<'a>, ParseError> {
833    // DROP INDEX [IF EXISTS] index_name ON tbl_name
834    let index_span = parser.consume_keyword(Keyword::INDEX)?;
835    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
836        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
837    } else {
838        None
839    };
840    let index_name = parser.consume_plain_identifier_unreserved()?;
841    let on = if let Some(span) = parser.skip_keyword(Keyword::ON) {
842        let table_name = parse_qualified_name_unreserved(parser)?;
843        Some((span, table_name))
844    } else {
845        None
846    };
847
848    if on.is_none() && parser.options.dialect.is_maria() {
849        parser.err("On required for index drops in MariaDb", &drop_span);
850    }
851    parser.maria_only(&on);
852
853    let restrict_or_cascade = parse_cascade_or_restrict(parser);
854
855    Ok(DropIndex {
856        drop_span,
857        index_span,
858        if_exists,
859        index_name,
860        on,
861        restrict_or_cascade,
862    })
863}
864
865/// Represent a drop domain statement
866/// ```
867/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropDomain, Statement, Issues};
868/// # let options = ParseOptions::new().dialect(SQLDialect::PostgreSQL);
869/// #
870/// let sql = "DROP DOMAIN IF EXISTS mydomain, otherdomain;";
871/// let mut issues = Issues::new(sql);
872/// let mut stmts = parse_statements(sql, &mut issues, &options);
873///
874/// # assert!(issues.is_ok());
875/// let drop: DropDomain = match stmts.pop() {
876///     Some(Statement::DropDomain(d)) => *d,
877///     _ => panic!("We should get a drop domain statement")
878/// };
879/// assert!(drop.domains.get(0).unwrap().identifier.as_str() == "mydomain");
880/// ```
881#[derive(Debug, Clone)]
882pub struct DropDomain<'a> {
883    /// Span of "DROP"
884    pub drop_span: Span,
885    /// Span of "DOMAIN"
886    pub domain_span: Span,
887    /// Span of "IF EXISTS" if specified
888    pub if_exists: Option<Span>,
889    /// List of domains to drop
890    pub domains: Vec<QualifiedName<'a>>,
891    /// Restrict or cascade option (PostgreSQL)
892    pub restrict_or_cascade: Option<CascadeOrRestrict>,
893}
894
895impl<'a> Spanned for DropDomain<'a> {
896    fn span(&self) -> Span {
897        self.drop_span
898            .join_span(&self.domain_span)
899            .join_span(&self.if_exists)
900            .join_span(&self.domains)
901            .join_span(&self.restrict_or_cascade)
902    }
903}
904
905fn parse_drop_domain<'a>(
906    parser: &mut Parser<'a, '_>,
907    drop_span: Span,
908) -> Result<DropDomain<'a>, ParseError> {
909    let domain_span = parser.consume_keyword(Keyword::DOMAIN)?;
910    parser.postgres_only(&domain_span);
911    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
912        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
913    } else {
914        None
915    };
916    let mut domains = Vec::new();
917    loop {
918        domains.push(parse_qualified_name_unreserved(parser)?);
919        if parser.skip_token(Token::Comma).is_none() {
920            break;
921        }
922    }
923    let restrict_or_cascade = parse_cascade_or_restrict(parser);
924    Ok(DropDomain {
925        drop_span,
926        domain_span,
927        if_exists,
928        domains,
929        restrict_or_cascade,
930    })
931}
932
933/// Represent a drop extension statement (PostgreSQL)
934/// ```
935/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropExtension, Statement, Issues};
936/// # let options = ParseOptions::new().dialect(SQLDialect::PostgreSQL);
937/// #
938/// let sql = "DROP EXTENSION IF EXISTS myext, otherext CASCADE;";
939/// let mut issues = Issues::new(sql);
940/// let mut stmts = parse_statements(sql, &mut issues, &options);
941/// # assert!(issues.is_ok());
942/// let drop: DropExtension = match stmts.pop() {
943///     Some(Statement::DropExtension(d)) => *d,
944///     _ => panic!("We should get a drop extension statement")
945/// };
946/// assert!(drop.extensions.get(0).unwrap().as_str() == "myext");
947/// ```
948#[derive(Debug, Clone)]
949pub struct DropExtension<'a> {
950    /// Span of "DROP"
951    pub drop_span: Span,
952    /// Span of "EXTENSION"
953    pub extension_span: Span,
954    /// Span of "IF EXISTS" if specified
955    pub if_exists: Option<Span>,
956    /// List of extensions to drop
957    pub extensions: Vec<Identifier<'a>>,
958    /// Restrict or cascade option (PostgreSQL)
959    pub restrict_or_cascade: Option<CascadeOrRestrict>,
960}
961
962impl<'a> Spanned for DropExtension<'a> {
963    fn span(&self) -> Span {
964        self.drop_span
965            .join_span(&self.extension_span)
966            .join_span(&self.if_exists)
967            .join_span(&self.extensions)
968            .join_span(&self.restrict_or_cascade)
969    }
970}
971
972fn parse_drop_extension<'a>(
973    parser: &mut Parser<'a, '_>,
974    drop_span: Span,
975) -> Result<DropExtension<'a>, ParseError> {
976    let extension_span = parser.consume_keyword(Keyword::EXTENSION)?;
977    parser.postgres_only(&extension_span);
978    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
979        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
980    } else {
981        None
982    };
983    let mut extensions = Vec::new();
984    loop {
985        extensions.push(parser.consume_plain_identifier_unreserved()?);
986        if parser.skip_token(Token::Comma).is_none() {
987            break;
988        }
989    }
990    let restrict_or_cascade = parse_cascade_or_restrict(parser);
991
992    Ok(DropExtension {
993        drop_span,
994        extension_span,
995        if_exists,
996        extensions,
997        restrict_or_cascade,
998    })
999}
1000
1001/// Represent a drop operator statement (PostgreSQL)
1002/// ```
1003/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropOperator, Statement, Issues};
1004/// # let options = ParseOptions::new().dialect(SQLDialect::PostgreSQL);
1005/// #
1006/// let sql = "DROP OPERATOR IF EXISTS +(integer, integer) CASCADE;";
1007/// let mut issues = Issues::new(sql);
1008/// let mut stmts = parse_statements(sql, &mut issues, &options);
1009/// # assert!(issues.is_ok());
1010/// let drop: DropOperator = match stmts.pop() {
1011///     Some(Statement::DropOperator(d)) => *d,
1012///     _ => panic!("We should get a drop operator statement")
1013/// };
1014/// assert!(drop.operators.get(0).unwrap().name.identifier.as_str() == "+");
1015/// ```
1016
1017#[derive(Debug, Clone)]
1018pub struct DropOperatorItem<'a> {
1019    pub name: QualifiedName<'a>,
1020    pub left_type: Option<DataType<'a>>,
1021    pub right_type: Option<DataType<'a>>,
1022}
1023
1024impl<'a> Spanned for DropOperatorItem<'a> {
1025    fn span(&self) -> Span {
1026        self.name
1027            .span()
1028            .join_span(&self.left_type)
1029            .join_span(&self.right_type)
1030    }
1031}
1032
1033#[derive(Debug, Clone)]
1034pub struct DropOperator<'a> {
1035    /// Span of "DROP OPERATOR"
1036    pub drop_operator_span: Span,
1037    /// Span of "IF EXISTS" if specified
1038    pub if_exists: Option<Span>,
1039    /// List of operators to drop
1040    pub operators: Vec<DropOperatorItem<'a>>,
1041    /// Restrict or cascade option (PostgreSQL)
1042    pub restrict_or_cascade: Option<CascadeOrRestrict>,
1043}
1044
1045impl<'a> Spanned for DropOperator<'a> {
1046    fn span(&self) -> Span {
1047        self.drop_operator_span
1048            .join_span(&self.if_exists)
1049            .join_span(&self.restrict_or_cascade)
1050            .join_span(&self.operators)
1051    }
1052}
1053
1054fn parse_drop_operator<'a>(
1055    parser: &mut Parser<'a, '_>,
1056    drop_operator_span: Span,
1057) -> Result<DropOperator<'a>, ParseError> {
1058    parser.postgres_only(&drop_operator_span);
1059    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
1060        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
1061    } else {
1062        None
1063    };
1064    // Parse comma-separated list of operators
1065    let mut operators = Vec::new();
1066    loop {
1067        if parser.token == Token::LParen {
1068            return Err(parser.expected_failure("operator name")?);
1069        }
1070        let name = parse_operator_name(parser)?;
1071        let (left_type, right_type) = if parser.token == Token::LParen {
1072            parser.consume_token(Token::LParen)?;
1073            let mut left = None;
1074            let mut right = None;
1075            parser.recovered(")", &|t| t == &Token::RParen, |parser| {
1076                if parser.token != Token::Comma && parser.token != Token::RParen {
1077                    left = Some(crate::data_type::parse_data_type(
1078                        parser,
1079                        DataTypeContext::TypeRef,
1080                    )?);
1081                }
1082                if parser.skip_token(Token::Comma).is_some() && parser.token != Token::RParen {
1083                    right = Some(crate::data_type::parse_data_type(
1084                        parser,
1085                        DataTypeContext::TypeRef,
1086                    )?);
1087                }
1088                Ok(())
1089            })?;
1090            parser.consume_token(Token::RParen)?;
1091            (left, right)
1092        } else {
1093            (None, None)
1094        };
1095        operators.push(DropOperatorItem {
1096            name,
1097            left_type,
1098            right_type,
1099        });
1100        if parser.skip_token(Token::Comma).is_none() {
1101            break;
1102        }
1103    }
1104    let restrict_or_cascade = parse_cascade_or_restrict(parser);
1105    Ok(DropOperator {
1106        drop_operator_span,
1107        if_exists,
1108        operators,
1109        restrict_or_cascade,
1110    })
1111}
1112
1113/// Represent a drop operator family statement (PostgreSQL)
1114/// ```
1115/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropOperatorFamily, Statement, Issues};
1116/// # let options = ParseOptions::new().dialect(SQLDialect::PostgreSQL);
1117/// #
1118/// let sql = "DROP OPERATOR FAMILY IF EXISTS myfamily USING gist CASCADE;";
1119/// let mut issues = Issues::new(sql);
1120/// let mut stmts = parse_statements(sql, &mut issues, &options);
1121/// # assert!(issues.is_ok());
1122/// let drop: DropOperatorFamily = match stmts.pop() {
1123///     Some(Statement::DropOperatorFamily(d)) => *d,
1124///     _ => panic!("We should get a drop operator family statement")
1125/// };
1126/// assert!(drop.family.identifier.as_str() == "myfamily");
1127/// ```
1128#[derive(Debug, Clone)]
1129pub struct DropOperatorFamily<'a> {
1130    /// Span of "DROP OPERATOR FAMILY"
1131    pub drop_operator_family_span: Span,
1132    /// Span of "IF EXISTS" if specified
1133    pub if_exists: Option<Span>,
1134    /// Name of the operator family
1135    pub family: QualifiedName<'a>,
1136    /// Span and name of the index method (USING ...)
1137    pub using: Option<(Span, Identifier<'a>)>,
1138    /// Restrict or cascade option (PostgreSQL)
1139    pub restrict_or_cascade: Option<CascadeOrRestrict>,
1140}
1141
1142impl<'a> Spanned for DropOperatorFamily<'a> {
1143    fn span(&self) -> Span {
1144        self.drop_operator_family_span
1145            .join_span(&self.if_exists)
1146            .join_span(&self.family)
1147            .join_span(&self.using)
1148            .join_span(&self.restrict_or_cascade)
1149    }
1150}
1151
1152fn parse_drop_operator_family<'a>(
1153    parser: &mut Parser<'a, '_>,
1154    drop_operator_family_span: Span,
1155) -> Result<DropOperatorFamily<'a>, ParseError> {
1156    parser.postgres_only(&drop_operator_family_span);
1157    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
1158        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
1159    } else {
1160        None
1161    };
1162    let family = parse_qualified_name_unreserved(parser)?;
1163    let using = if let Some(span) = parser.skip_keyword(Keyword::USING) {
1164        let method = parser.consume_plain_identifier_unreserved()?;
1165        Some((span, method))
1166    } else {
1167        None
1168    };
1169    let restrict_or_cascade = parse_cascade_or_restrict(parser);
1170    Ok(DropOperatorFamily {
1171        drop_operator_family_span,
1172        if_exists,
1173        family,
1174        using,
1175        restrict_or_cascade,
1176    })
1177}
1178
1179/// Represent a drop operator class statement (PostgreSQL)
1180/// ```
1181/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropOperatorClass, Statement, Issues};
1182/// # let options = ParseOptions::new().dialect(SQLDialect::PostgreSQL);
1183/// #
1184/// let sql = "DROP OPERATOR CLASS IF EXISTS myclass USING gist CASCADE;";
1185/// let mut issues = Issues::new(sql);
1186/// let mut stmts = parse_statements(sql, &mut issues, &options);
1187/// # assert!(issues.is_ok());
1188/// let drop: DropOperatorClass = match stmts.pop() {
1189///     Some(Statement::DropOperatorClass(d)) => *d,
1190///     _ => panic!("We should get a drop operator class statement")
1191/// };
1192/// assert!(drop.class.identifier.as_str() == "myclass");
1193/// ```
1194#[derive(Debug, Clone)]
1195pub struct DropOperatorClass<'a> {
1196    /// Span of "DROP OPERATOR CLASS"
1197    pub drop_operator_class_span: Span,
1198    /// Span of "IF EXISTS" if specified
1199    pub if_exists: Option<Span>,
1200    /// Name of the operator class
1201    pub class: QualifiedName<'a>,
1202    /// Span and name of the index method (USING ...)
1203    pub using: Option<(Span, Identifier<'a>)>,
1204    /// Restrict or cascade option (PostgreSQL)
1205    pub restrict_or_cascade: Option<CascadeOrRestrict>,
1206}
1207
1208impl<'a> Spanned for DropOperatorClass<'a> {
1209    fn span(&self) -> Span {
1210        self.drop_operator_class_span
1211            .join_span(&self.if_exists)
1212            .join_span(&self.class)
1213            .join_span(&self.using)
1214            .join_span(&self.restrict_or_cascade)
1215    }
1216}
1217
1218fn parse_drop_operator_class<'a>(
1219    parser: &mut Parser<'a, '_>,
1220    drop_operator_class_span: Span,
1221) -> Result<DropOperatorClass<'a>, ParseError> {
1222    parser.postgres_only(&drop_operator_class_span);
1223    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
1224        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
1225    } else {
1226        None
1227    };
1228    let class = parse_qualified_name_unreserved(parser)?;
1229    let using = if let Some(span) = parser.skip_keyword(Keyword::USING) {
1230        let method = parser.consume_plain_identifier_unreserved()?;
1231        Some((span, method))
1232    } else {
1233        None
1234    };
1235    let restrict_or_cascade = parse_cascade_or_restrict(parser);
1236    Ok(DropOperatorClass {
1237        drop_operator_class_span,
1238        if_exists,
1239        class,
1240        using,
1241        restrict_or_cascade,
1242    })
1243}
1244
1245pub(crate) fn parse_drop<'a>(parser: &mut Parser<'a, '_>) -> Result<Statement<'a>, ParseError> {
1246    let drop_span = parser.consume_keyword(Keyword::DROP)?;
1247    let temporary = parser.skip_keyword(Keyword::TEMPORARY);
1248    match &parser.token {
1249        Token::Ident(_, Keyword::TABLE) => Ok(Statement::DropTable(Box::new(parse_drop_table(
1250            parser, drop_span, temporary,
1251        )?))),
1252        Token::Ident(_, Keyword::VIEW) => Ok(Statement::DropView(Box::new(parse_drop_view(
1253            parser, drop_span, temporary,
1254        )?))),
1255        Token::Ident(_, kw @ Keyword::DATABASE | kw @ Keyword::SCHEMA) => Ok(
1256            Statement::DropDatabase(Box::new(parse_drop_database(parser, drop_span, *kw)?)),
1257        ),
1258        Token::Ident(_, Keyword::DOMAIN) => Ok(Statement::DropDomain(Box::new(parse_drop_domain(
1259            parser, drop_span,
1260        )?))),
1261        Token::Ident(_, Keyword::EXTENSION) => Ok(Statement::DropExtension(Box::new(
1262            parse_drop_extension(parser, drop_span)?,
1263        ))),
1264        Token::Ident(_, Keyword::EVENT) => Ok(Statement::DropEvent(Box::new(parse_drop_event(
1265            parser, drop_span,
1266        )?))),
1267        Token::Ident(_, Keyword::FUNCTION) => Ok(Statement::DropFunction(Box::new(
1268            parse_drop_function(parser, drop_span)?,
1269        ))),
1270        Token::Ident(_, Keyword::OPERATOR) => {
1271            let operator_span = parser.consume_keyword(Keyword::OPERATOR)?;
1272            match &parser.token {
1273                Token::Ident(_, Keyword::FAMILY) => {
1274                    let family_span = parser.consume_keyword(Keyword::FAMILY)?;
1275                    Ok(Statement::DropOperatorFamily(Box::new(
1276                        parse_drop_operator_family(
1277                            parser,
1278                            drop_span.join_span(&operator_span).join_span(&family_span),
1279                        )?,
1280                    )))
1281                }
1282                Token::Ident(_, Keyword::CLASS) => {
1283                    let class_span = parser.consume_keyword(Keyword::CLASS)?;
1284                    Ok(Statement::DropOperatorClass(Box::new(
1285                        parse_drop_operator_class(
1286                            parser,
1287                            drop_span.join_span(&operator_span).join_span(&class_span),
1288                        )?,
1289                    )))
1290                }
1291                _ => Ok(Statement::DropOperator(Box::new(parse_drop_operator(
1292                    parser,
1293                    drop_span.join_span(&operator_span),
1294                )?))),
1295            }
1296        }
1297        Token::Ident(_, Keyword::INDEX) => Ok(Statement::DropIndex(Box::new(parse_drop_index(
1298            parser, drop_span,
1299        )?))),
1300        Token::Ident(_, Keyword::PROCEDURE) => Ok(Statement::DropProcedure(Box::new(
1301            parse_drop_procedure(parser, drop_span)?,
1302        ))),
1303        Token::Ident(_, Keyword::SEQUENCE) => Ok(Statement::DropSequence(Box::new(
1304            parse_drop_sequence(parser, drop_span)?,
1305        ))),
1306        Token::Ident(_, Keyword::SERVER) => Ok(Statement::DropServer(Box::new(parse_drop_server(
1307            parser, drop_span,
1308        )?))),
1309        Token::Ident(_, Keyword::TRIGGER) => Ok(Statement::DropTrigger(Box::new(
1310            parse_drop_trigger(parser, drop_span)?,
1311        ))),
1312        Token::Ident(_, Keyword::USER) => {
1313            // DROP USER [IF EXISTS] user_name [, user_name] ..
1314            parser.todo(file!(), line!())
1315        }
1316        _ => parser.expected_failure("droppable"),
1317    }
1318}