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) -> Result<DropDatabase<'a>, ParseError> {
252    let database_span = parser.consume_keyword(Keyword::DATABASE)?;
253    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
254        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
255    } else {
256        None
257    };
258    let database = parser.consume_plain_identifier_unreserved()?;
259    Ok(DropDatabase {
260        drop_span,
261        database_span,
262        if_exists,
263        database,
264    })
265}
266
267/// Represent a drop schema statement
268/// ```
269/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropSchema, Statement, Issues};
270/// # let options = ParseOptions::new().dialect(SQLDialect::PostgreSQL);
271/// #
272/// let sql = "DROP SCHEMA myschema;";
273/// let mut issues = Issues::new(sql);
274/// let mut stmts = parse_statements(sql, &mut issues, &options);
275///
276/// # assert!(issues.is_ok());
277/// #
278/// let s: DropSchema = match stmts.pop() {
279///     Some(Statement::DropSchema(s)) => *s,
280///     _ => panic!("We should get a drop schema statement")
281/// };
282///
283/// assert!(s.schema.as_str() == "myschema");
284/// ```
285#[derive(Debug, Clone)]
286pub struct DropSchema<'a> {
287    /// Span of "DROP"
288    pub drop_span: Span,
289    /// Span of "SCHEMA"
290    pub schema_span: Span,
291    /// Span of "IF EXISTS" if specified
292    pub if_exists: Option<Span>,
293    /// Name of schema to drop
294    pub schema: Identifier<'a>,
295}
296
297impl<'a> Spanned for DropSchema<'a> {
298    fn span(&self) -> Span {
299        self.drop_span
300            .join_span(&self.schema_span)
301            .join_span(&self.if_exists)
302            .join_span(&self.schema)
303    }
304}
305
306fn parse_drop_schema<'a>(
307    parser: &mut Parser<'a, '_>,
308    drop_span: Span,
309) -> Result<DropSchema<'a>, ParseError> {
310    let schema_span = parser.consume_keyword(Keyword::SCHEMA)?;
311    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
312        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
313    } else {
314        None
315    };
316    let schema = parser.consume_plain_identifier_unreserved()?;
317    Ok(DropSchema {
318        drop_span,
319        schema_span,
320        if_exists,
321        schema,
322    })
323}
324
325/// Represent a drop event statement
326/// ```
327/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropEvent, Statement, Issues};
328/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
329/// #
330/// let sql = "DROP EVENT myevent;";
331/// let mut issues = Issues::new(sql);
332/// let mut stmts = parse_statements(sql, &mut issues, &options);
333///
334/// # assert!(issues.is_ok());
335/// let s: DropEvent = match stmts.pop() {
336///     Some(Statement::DropEvent(s)) => *s,
337///     _ => panic!("We should get a drop event statement")
338/// };
339///
340/// assert!(s.event.identifier.as_str() == "myevent");
341/// ```
342#[derive(Debug, Clone)]
343pub struct DropEvent<'a> {
344    /// Span of "DROP"
345    pub drop_span: Span,
346    /// Span of "EVENT"
347    pub event_span: Span,
348    /// Span of "IF EXISTS" if specified
349    pub if_exists: Option<Span>,
350    /// Event to drop
351    pub event: QualifiedName<'a>,
352}
353
354impl<'a> Spanned for DropEvent<'a> {
355    fn span(&self) -> Span {
356        self.drop_span
357            .join_span(&self.event_span)
358            .join_span(&self.if_exists)
359            .join_span(&self.event)
360    }
361}
362
363fn parse_drop_event<'a>(
364    parser: &mut Parser<'a, '_>,
365    drop_span: Span,
366) -> Result<DropEvent<'a>, ParseError> {
367    // TODO complain about temporary
368    let event_span = parser.consume_keyword(Keyword::EVENT)?;
369    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
370        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
371    } else {
372        None
373    };
374    let event = parse_qualified_name_unreserved(parser)?;
375    Ok(DropEvent {
376        drop_span,
377        event_span,
378        if_exists,
379        event,
380    })
381}
382
383#[derive(Debug, Clone)]
384pub enum DropFunctionArgMode {
385    In(Span),
386    Out(Span),
387    InOut(Span),
388}
389
390impl Spanned for DropFunctionArgMode {
391    fn span(&self) -> Span {
392        match self {
393            DropFunctionArgMode::In(s) => s.clone(),
394            DropFunctionArgMode::Out(s) => s.clone(),
395            DropFunctionArgMode::InOut(s) => s.clone(),
396        }
397    }
398}
399
400#[derive(Debug, Clone)]
401pub struct DropFunctionArg<'a> {
402    pub mode: Option<DropFunctionArgMode>,
403    pub name: Option<Identifier<'a>>,
404    pub data_type: DataType<'a>,
405    pub default: Option<Span>, // = value (span only, for now)
406}
407
408impl<'a> Spanned for DropFunctionArg<'a> {
409    fn span(&self) -> Span {
410        self.data_type
411            .span()
412            .join_span(&self.mode)
413            .join_span(&self.name)
414            .join_span(&self.default)
415    }
416}
417
418/// Represent a drop function statement
419/// ```
420/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropFunction, Statement, Issues};
421/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
422/// #
423/// let sql = "DROP FUNCTION myfunc;";
424/// let mut issues = Issues::new(sql);
425/// let mut stmts = parse_statements(sql, &mut issues, &options);
426///
427/// # assert!(issues.is_ok());
428/// let s: DropFunction = match stmts.pop() {
429///     Some(Statement::DropFunction(s)) => *s,
430///     _ => panic!("We should get a drop function statement")
431/// };
432///
433/// assert!(s.functions.get(0).unwrap().0.identifier.as_str() == "myfunc");
434/// ```
435#[derive(Debug, Clone)]
436pub struct DropFunction<'a> {
437    /// Span of "DROP"
438    pub drop_span: Span,
439    /// Span of "FUNCTION"
440    pub function_span: Span,
441    /// Span of "IF EXISTS" if specified
442    pub if_exists: Option<Span>,
443    /// List of functions to drop (PostgreSQL: can be multiple)
444    pub functions: Vec<(QualifiedName<'a>, Option<Vec<DropFunctionArg<'a>>>)>,
445    /// Restrict or cascade option (PostgreSQL)
446    pub restrict_or_cascade: Option<CascadeOrRestrict>,
447}
448
449impl<'a> Spanned for DropFunction<'a> {
450    fn span(&self) -> Span {
451        let mut span = self
452            .drop_span
453            .join_span(&self.function_span)
454            .join_span(&self.if_exists)
455            .join_span(&self.restrict_or_cascade);
456        for (name, args) in &self.functions {
457            span = span.join_span(name);
458            if let Some(args) = args {
459                for arg in args {
460                    span = span.join_span(arg);
461                }
462            }
463        }
464        span
465    }
466}
467
468fn parse_drop_function<'a>(
469    parser: &mut Parser<'a, '_>,
470    drop_span: Span,
471) -> Result<DropFunction<'a>, ParseError> {
472    let function_span = parser.consume_keyword(Keyword::FUNCTION)?;
473    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
474        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
475    } else {
476        None
477    };
478    let mut functions = Vec::new();
479    loop {
480        let name = parse_qualified_name_unreserved(parser)?;
481        let args = if parser.token == Token::LParen {
482            let lparen = parser.consume_token(Token::LParen)?;
483            let mut arg_list = Vec::new();
484            parser.recovered(")", &|t| t == &Token::RParen, |parser| {
485                loop {
486                    // Parse mode (IN, OUT, INOUT)
487                    let mode = match &parser.token {
488                        Token::Ident(_, Keyword::IN) => Some(DropFunctionArgMode::In(
489                            parser.consume_keyword(Keyword::IN)?,
490                        )),
491                        Token::Ident(_, Keyword::OUT) => Some(DropFunctionArgMode::Out(
492                            parser.consume_keyword(Keyword::OUT)?,
493                        )),
494                        Token::Ident(_, Keyword::INOUT) => Some(DropFunctionArgMode::InOut(
495                            parser.consume_keyword(Keyword::INOUT)?,
496                        )),
497                        _ => None,
498                    };
499                    // Parse parameter name (optional)
500                    let name = match &parser.token {
501                        Token::Ident(_, kw) if !kw.restricted(parser.reserved()) => {
502                            Some(parser.consume_plain_identifier_unreserved()?)
503                        }
504                        _ => None,
505                    };
506                    // Parse data type
507                    let data_type =
508                        crate::data_type::parse_data_type(parser, DataTypeContext::FunctionParam)?;
509                    // Parse default value (optional)
510                    let default = if parser.skip_token(Token::Eq).is_some() {
511                        // Just record the span for now
512                        Some(parser.consume().clone())
513                    } else {
514                        None
515                    };
516                    arg_list.push(DropFunctionArg {
517                        mode,
518                        name,
519                        data_type,
520                        default,
521                    });
522                    if parser.skip_token(Token::Comma).is_none() {
523                        break;
524                    }
525                }
526                Ok(())
527            })?;
528            parser.consume_token(Token::RParen)?;
529            parser.postgres_only(&lparen.join_span(&arg_list));
530            Some(arg_list)
531        } else {
532            None
533        };
534        functions.push((name, args));
535        if parser.skip_token(Token::Comma).is_none() {
536            break;
537        }
538    }
539    if let [(first, _), (second, _), ..] = functions.as_slice()
540        && !parser.options.dialect.is_postgresql()
541    {
542        parser
543            .err("Multiple function only supported by ", second)
544            .frag("First function supplied here", first);
545    }
546    let restrict_or_cascade = parse_cascade_or_restrict(parser);
547    Ok(DropFunction {
548        drop_span,
549        function_span,
550        if_exists,
551        functions,
552        restrict_or_cascade,
553    })
554}
555
556/// Represent a drop procedure statement
557/// ```
558/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropProcedure, Statement, Issues};
559/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
560/// #
561/// let sql = "DROP PROCEDURE myproc;";
562/// let mut issues = Issues::new(sql);
563/// let mut stmts = parse_statements(sql, &mut issues, &options);
564///
565/// # assert!(issues.is_ok());
566/// let s: DropProcedure = match stmts.pop() {
567///     Some(Statement::DropProcedure(s)) => *s,
568///     _ => panic!("We should get a drop procedure statement")
569/// };
570///
571/// assert!(s.procedure.identifier.as_str() == "myproc");
572/// ```
573#[derive(Debug, Clone)]
574pub struct DropProcedure<'a> {
575    /// Span of "DROP"
576    pub drop_span: Span,
577    /// Span of "PROCEDURE"
578    pub procedure_span: Span,
579    /// Span of "IF EXISTS" if specified
580    pub if_exists: Option<Span>,
581    /// Procedure to drop
582    pub procedure: QualifiedName<'a>,
583}
584
585impl<'a> Spanned for DropProcedure<'a> {
586    fn span(&self) -> Span {
587        self.drop_span
588            .join_span(&self.procedure_span)
589            .join_span(&self.if_exists)
590            .join_span(&self.procedure)
591    }
592}
593
594fn parse_drop_procedure<'a>(
595    parser: &mut Parser<'a, '_>,
596    drop_span: Span,
597) -> Result<DropProcedure<'a>, ParseError> {
598    // TODO complain about temporary
599    let procedure_span = parser.consume_keyword(Keyword::PROCEDURE)?;
600    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
601        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
602    } else {
603        None
604    };
605    let procedure = parse_qualified_name_unreserved(parser)?;
606    Ok(DropProcedure {
607        drop_span,
608        procedure_span,
609        if_exists,
610        procedure,
611    })
612}
613
614/// Represent a drop sequence statement (PostgreSQL)
615/// ```
616/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropSequence, Statement, Issues};
617/// # let options = ParseOptions::new().dialect(SQLDialect::PostgreSQL);
618/// #
619/// let sql = "DROP SEQUENCE myseq CASCADE;";
620/// let mut issues = Issues::new(sql);
621/// let mut stmts = parse_statements(sql, &mut issues, &options);
622///
623/// # assert!(issues.is_ok());
624/// let s: DropSequence = match stmts.pop() {
625///     Some(Statement::DropSequence(s)) => *s,
626///     _ => panic!("We should get a drop sequence statement")
627/// };
628///
629/// assert!(s.sequences.get(0).unwrap().identifier.as_str() == "myseq");
630/// ```
631#[derive(Debug, Clone)]
632pub struct DropSequence<'a> {
633    /// Span of "DROP"
634    pub drop_span: Span,
635    /// Span of "SEQUENCE"
636    pub sequence_span: Span,
637    /// Span of "IF EXISTS" if specified
638    pub if_exists: Option<Span>,
639    /// List of sequences to drop
640    pub sequences: Vec<QualifiedName<'a>>,
641    /// Restrict or cascade option (PostgreSQL)
642    pub restrict_or_cascade: Option<CascadeOrRestrict>,
643}
644
645impl<'a> Spanned for DropSequence<'a> {
646    fn span(&self) -> Span {
647        self.drop_span
648            .join_span(&self.sequence_span)
649            .join_span(&self.if_exists)
650            .join_span(&self.sequences)
651            .join_span(&self.restrict_or_cascade)
652    }
653}
654
655fn parse_drop_sequence<'a>(
656    parser: &mut Parser<'a, '_>,
657    drop_span: Span,
658) -> Result<DropSequence<'a>, ParseError> {
659    // DROP SEQUENCE [IF EXISTS] sequence_name [, sequence_name] ... [CASCADE | RESTRICT]
660    let sequence_span = parser.consume_keyword(Keyword::SEQUENCE)?;
661    parser.postgres_only(&sequence_span);
662    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
663        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
664    } else {
665        None
666    };
667    let mut sequences = Vec::new();
668    loop {
669        sequences.push(parse_qualified_name_unreserved(parser)?);
670        if parser.skip_token(Token::Comma).is_none() {
671            break;
672        }
673    }
674    let restrict_or_cascade = parse_cascade_or_restrict(parser);
675    Ok(DropSequence {
676        drop_span,
677        sequence_span,
678        if_exists,
679        sequences,
680        restrict_or_cascade,
681    })
682}
683
684/// Represent a drop server statement
685/// ```
686/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropServer, Statement, Issues};
687/// # let options = ParseOptions::new().dialect(SQLDialect::PostgreSQL);
688/// #
689/// let sql = "DROP SERVER myserver;";
690/// let mut issues = Issues::new(sql);
691/// let mut stmts = parse_statements(sql, &mut issues, &options);
692///
693/// # assert!(issues.is_ok());
694/// #
695/// let s: DropServer = match stmts.pop() {
696///     Some(Statement::DropServer(s)) => *s,
697///     _ => panic!("We should get a drop server statement")
698/// };
699///
700/// assert!(s.server.as_str() == "myserver");
701/// ```
702#[derive(Debug, Clone)]
703pub struct DropServer<'a> {
704    /// Span of "DROP"
705    pub drop_span: Span,
706    /// Span of "SERVER"
707    pub server_span: Span,
708    /// Span of "IF EXISTS" if specified
709    pub if_exists: Option<Span>,
710    /// Server to drop
711    pub server: Identifier<'a>,
712}
713
714impl<'a> Spanned for DropServer<'a> {
715    fn span(&self) -> Span {
716        self.drop_span
717            .join_span(&self.server_span)
718            .join_span(&self.if_exists)
719            .join_span(&self.server)
720    }
721}
722
723fn parse_drop_server<'a>(
724    parser: &mut Parser<'a, '_>,
725    drop_span: Span,
726) -> Result<DropServer<'a>, ParseError> {
727    // TODO complain about temporary
728    let server_span = parser.consume_keyword(Keyword::SERVER)?;
729    parser.postgres_only(&server_span);
730    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
731        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
732    } else {
733        None
734    };
735    let server = parser.consume_plain_identifier_unreserved()?;
736    Ok(DropServer {
737        drop_span,
738        server_span,
739        if_exists,
740        server,
741    })
742}
743
744/// Represent a drop trigger statement
745/// ```
746/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropTrigger, Statement, Issues};
747/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
748/// #
749/// let sql = "DROP TRIGGER IF EXISTS `foo`.`mytrigger`;";
750/// let mut issues = Issues::new(sql);
751/// let mut stmts = parse_statements(sql, &mut issues, &options);
752///
753/// # assert!(issues.is_ok());
754/// let s: DropTrigger = match stmts.pop() {
755///     Some(Statement::DropTrigger(s)) => *s,
756///     _ => panic!("We should get a drop trigger statement")
757/// };
758///
759/// assert!(s.identifier.identifier.as_str() == "mytrigger");
760/// ```
761#[derive(Debug, Clone)]
762pub struct DropTrigger<'a> {
763    /// Span of "DROP"
764    pub drop_span: Span,
765    /// Span of "TRIGGER"
766    pub trigger_span: Span,
767    /// Span of "IF EXISTS" if specified
768    pub if_exists: Option<Span>,
769    /// Trigger to drop
770    pub identifier: QualifiedName<'a>,
771    /// ON table_name (PostgreSQL/PostGIS)
772    pub on: Option<(Span, QualifiedName<'a>)>,
773    /// Restrict or cascade option (PostgreSQL)
774    pub restrict_or_cascade: Option<CascadeOrRestrict>,
775}
776
777impl<'a> Spanned for DropTrigger<'a> {
778    fn span(&self) -> Span {
779        self.drop_span
780            .join_span(&self.trigger_span)
781            .join_span(&self.if_exists)
782            .join_span(&self.identifier)
783            .join_span(&self.on)
784            .join_span(&self.restrict_or_cascade)
785    }
786}
787
788fn parse_drop_trigger<'a>(
789    parser: &mut Parser<'a, '_>,
790    drop_span: Span,
791) -> Result<DropTrigger<'a>, ParseError> {
792    let trigger_span = parser.consume_keyword(Keyword::TRIGGER)?;
793    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
794        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
795    } else {
796        None
797    };
798    let identifier = parse_qualified_name_unreserved(parser)?;
799    let on = if let Some(span) = parser.skip_keyword(Keyword::ON) {
800        let table_name = parse_qualified_name_unreserved(parser)?;
801        parser.postgres_only(&span);
802        Some((span, table_name))
803    } else {
804        if parser.options.dialect.is_postgresql() {
805            parser.err("ON required for trigger drops in PostgreSQL", &trigger_span);
806        }
807        None
808    };
809    let restrict_or_cascade = parse_cascade_or_restrict(parser);
810    Ok(DropTrigger {
811        drop_span,
812        trigger_span,
813        if_exists,
814        identifier,
815        on,
816        restrict_or_cascade,
817    })
818}
819
820/// Represent a drop index statement.
821///
822/// MariaDB example
823/// ```
824/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropIndex, Statement, Issues};
825/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
826/// #
827/// let sql = "DROP INDEX IF EXISTS `myindex` ON `bar`;";
828/// let mut issues = Issues::new(sql);
829/// let mut stmts = parse_statements(sql, &mut issues, &options);
830///
831/// # assert!(issues.is_ok());
832/// let s: DropIndex = match stmts.pop() {
833///     Some(Statement::DropIndex(s)) => *s,
834///     _ => panic!("We should get a drop trigger statement")
835/// };
836///
837/// assert!(s.index_name.as_str() == "myindex");
838/// ```
839///
840/// PostgreSQL example
841/// ```
842/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropIndex, Statement, Issues};
843/// # let options = ParseOptions::new().dialect(SQLDialect::PostgreSQL);
844/// #
845/// let sql = "DROP INDEX IF EXISTS \"myindex\";";
846/// let mut issues = Issues::new(sql);
847/// let mut stmts = parse_statements(sql, &mut issues, &options);
848///
849/// # assert!(issues.is_ok(), "{}", issues);
850/// #
851/// let s: DropIndex = match stmts.pop() {
852///     Some(Statement::DropIndex(s)) => *s,
853///     _ => panic!("We should get a drop trigger statement")
854/// };
855///
856/// assert!(s.index_name.as_str() == "myindex");
857/// ```
858#[derive(Debug, Clone)]
859pub struct DropIndex<'a> {
860    /// Span of "DROP"
861    pub drop_span: Span,
862    /// Span of "INDEX"
863    pub index_span: Span,
864    /// Span of "IF EXISTS" if specified
865    pub if_exists: Option<Span>,
866    /// Name of index to drop
867    pub index_name: Identifier<'a>,
868    // on tbl_name is required in MariaDB but not in PostgreSQL
869    pub on: Option<(Span, QualifiedName<'a>)>,
870    /// Restrict or cascade option (PostgreSQL)
871    pub restrict_or_cascade: Option<CascadeOrRestrict>,
872}
873
874impl<'a> Spanned for DropIndex<'a> {
875    fn span(&self) -> Span {
876        self.drop_span
877            .join_span(&self.index_span)
878            .join_span(&self.if_exists)
879            .join_span(&self.index_name)
880            .join_span(&self.on)
881            .join_span(&self.restrict_or_cascade)
882    }
883}
884
885fn parse_drop_index<'a>(
886    parser: &mut Parser<'a, '_>,
887    drop_span: Span,
888) -> Result<DropIndex<'a>, ParseError> {
889    // DROP INDEX [IF EXISTS] index_name ON tbl_name
890    let index_span = parser.consume_keyword(Keyword::INDEX)?;
891    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
892        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
893    } else {
894        None
895    };
896    let index_name = parser.consume_plain_identifier_unreserved()?;
897    let on = if let Some(span) = parser.skip_keyword(Keyword::ON) {
898        let table_name = parse_qualified_name_unreserved(parser)?;
899        Some((span, table_name))
900    } else {
901        None
902    };
903
904    if on.is_none() && parser.options.dialect.is_maria() {
905        parser.err("On required for index drops in MariaDb", &drop_span);
906    }
907    parser.maria_only(&on);
908
909    let restrict_or_cascade = parse_cascade_or_restrict(parser);
910
911    Ok(DropIndex {
912        drop_span,
913        index_span,
914        if_exists,
915        index_name,
916        on,
917        restrict_or_cascade,
918    })
919}
920
921/// Represent a drop domain statement
922/// ```
923/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropDomain, Statement, Issues};
924/// # let options = ParseOptions::new().dialect(SQLDialect::PostgreSQL);
925/// #
926/// let sql = "DROP DOMAIN IF EXISTS mydomain, otherdomain;";
927/// let mut issues = Issues::new(sql);
928/// let mut stmts = parse_statements(sql, &mut issues, &options);
929///
930/// # assert!(issues.is_ok());
931/// let drop: DropDomain = match stmts.pop() {
932///     Some(Statement::DropDomain(d)) => *d,
933///     _ => panic!("We should get a drop domain statement")
934/// };
935/// assert!(drop.domains.get(0).unwrap().identifier.as_str() == "mydomain");
936/// ```
937#[derive(Debug, Clone)]
938pub struct DropDomain<'a> {
939    /// Span of "DROP"
940    pub drop_span: Span,
941    /// Span of "DOMAIN"
942    pub domain_span: Span,
943    /// Span of "IF EXISTS" if specified
944    pub if_exists: Option<Span>,
945    /// List of domains to drop
946    pub domains: Vec<QualifiedName<'a>>,
947    /// Restrict or cascade option (PostgreSQL)
948    pub restrict_or_cascade: Option<CascadeOrRestrict>,
949}
950
951impl<'a> Spanned for DropDomain<'a> {
952    fn span(&self) -> Span {
953        self.drop_span
954            .join_span(&self.domain_span)
955            .join_span(&self.if_exists)
956            .join_span(&self.domains)
957            .join_span(&self.restrict_or_cascade)
958    }
959}
960
961fn parse_drop_domain<'a>(
962    parser: &mut Parser<'a, '_>,
963    drop_span: Span,
964) -> Result<DropDomain<'a>, ParseError> {
965    let domain_span = parser.consume_keyword(Keyword::DOMAIN)?;
966    parser.postgres_only(&domain_span);
967    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
968        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
969    } else {
970        None
971    };
972    let mut domains = Vec::new();
973    loop {
974        domains.push(parse_qualified_name_unreserved(parser)?);
975        if parser.skip_token(Token::Comma).is_none() {
976            break;
977        }
978    }
979    let restrict_or_cascade = parse_cascade_or_restrict(parser);
980    Ok(DropDomain {
981        drop_span,
982        domain_span,
983        if_exists,
984        domains,
985        restrict_or_cascade,
986    })
987}
988
989/// Represent a drop extension statement (PostgreSQL)
990/// ```
991/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropExtension, Statement, Issues};
992/// # let options = ParseOptions::new().dialect(SQLDialect::PostgreSQL);
993/// #
994/// let sql = "DROP EXTENSION IF EXISTS myext, otherext CASCADE;";
995/// let mut issues = Issues::new(sql);
996/// let mut stmts = parse_statements(sql, &mut issues, &options);
997/// # assert!(issues.is_ok());
998/// let drop: DropExtension = match stmts.pop() {
999///     Some(Statement::DropExtension(d)) => *d,
1000///     _ => panic!("We should get a drop extension statement")
1001/// };
1002/// assert!(drop.extensions.get(0).unwrap().as_str() == "myext");
1003/// ```
1004#[derive(Debug, Clone)]
1005pub struct DropExtension<'a> {
1006    /// Span of "DROP"
1007    pub drop_span: Span,
1008    /// Span of "EXTENSION"
1009    pub extension_span: Span,
1010    /// Span of "IF EXISTS" if specified
1011    pub if_exists: Option<Span>,
1012    /// List of extensions to drop
1013    pub extensions: Vec<Identifier<'a>>,
1014    /// Restrict or cascade option (PostgreSQL)
1015    pub restrict_or_cascade: Option<CascadeOrRestrict>,
1016}
1017
1018impl<'a> Spanned for DropExtension<'a> {
1019    fn span(&self) -> Span {
1020        self.drop_span
1021            .join_span(&self.extension_span)
1022            .join_span(&self.if_exists)
1023            .join_span(&self.extensions)
1024            .join_span(&self.restrict_or_cascade)
1025    }
1026}
1027
1028fn parse_drop_extension<'a>(
1029    parser: &mut Parser<'a, '_>,
1030    drop_span: Span,
1031) -> Result<DropExtension<'a>, ParseError> {
1032    let extension_span = parser.consume_keyword(Keyword::EXTENSION)?;
1033    parser.postgres_only(&extension_span);
1034    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
1035        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
1036    } else {
1037        None
1038    };
1039    let mut extensions = Vec::new();
1040    loop {
1041        extensions.push(parser.consume_plain_identifier_unreserved()?);
1042        if parser.skip_token(Token::Comma).is_none() {
1043            break;
1044        }
1045    }
1046    let restrict_or_cascade = parse_cascade_or_restrict(parser);
1047
1048    Ok(DropExtension {
1049        drop_span,
1050        extension_span,
1051        if_exists,
1052        extensions,
1053        restrict_or_cascade,
1054    })
1055}
1056
1057/// Represent a drop operator statement (PostgreSQL)
1058/// ```
1059/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropOperator, Statement, Issues};
1060/// # let options = ParseOptions::new().dialect(SQLDialect::PostgreSQL);
1061/// #
1062/// let sql = "DROP OPERATOR IF EXISTS +(integer, integer) CASCADE;";
1063/// let mut issues = Issues::new(sql);
1064/// let mut stmts = parse_statements(sql, &mut issues, &options);
1065/// # assert!(issues.is_ok());
1066/// let drop: DropOperator = match stmts.pop() {
1067///     Some(Statement::DropOperator(d)) => *d,
1068///     _ => panic!("We should get a drop operator statement")
1069/// };
1070/// assert!(drop.operators.get(0).unwrap().name.identifier.as_str() == "+");
1071/// ```
1072
1073#[derive(Debug, Clone)]
1074pub struct DropOperatorItem<'a> {
1075    pub name: QualifiedName<'a>,
1076    pub left_type: Option<DataType<'a>>,
1077    pub right_type: Option<DataType<'a>>,
1078}
1079
1080impl<'a> Spanned for DropOperatorItem<'a> {
1081    fn span(&self) -> Span {
1082        self.name
1083            .span()
1084            .join_span(&self.left_type)
1085            .join_span(&self.right_type)
1086    }
1087}
1088
1089#[derive(Debug, Clone)]
1090pub struct DropOperator<'a> {
1091    /// Span of "DROP OPERATOR"
1092    pub drop_operator_span: Span,
1093    /// Span of "IF EXISTS" if specified
1094    pub if_exists: Option<Span>,
1095    /// List of operators to drop
1096    pub operators: Vec<DropOperatorItem<'a>>,
1097    /// Restrict or cascade option (PostgreSQL)
1098    pub restrict_or_cascade: Option<CascadeOrRestrict>,
1099}
1100
1101impl<'a> Spanned for DropOperator<'a> {
1102    fn span(&self) -> Span {
1103        self.drop_operator_span
1104            .join_span(&self.if_exists)
1105            .join_span(&self.restrict_or_cascade)
1106            .join_span(&self.operators)
1107    }
1108}
1109
1110fn parse_drop_operator<'a>(
1111    parser: &mut Parser<'a, '_>,
1112    drop_operator_span: Span,
1113) -> Result<DropOperator<'a>, ParseError> {
1114    parser.postgres_only(&drop_operator_span);
1115    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
1116        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
1117    } else {
1118        None
1119    };
1120    // Parse comma-separated list of operators
1121    let mut operators = Vec::new();
1122    loop {
1123        if parser.token == Token::LParen {
1124            return Err(parser.expected_failure("operator name")?);
1125        }
1126        let name = parse_operator_name(parser)?;
1127        let (left_type, right_type) = if parser.token == Token::LParen {
1128            parser.consume_token(Token::LParen)?;
1129            let mut left = None;
1130            let mut right = None;
1131            parser.recovered(")", &|t| t == &Token::RParen, |parser| {
1132                if parser.token != Token::Comma && parser.token != Token::RParen {
1133                    left = Some(crate::data_type::parse_data_type(
1134                        parser,
1135                        DataTypeContext::TypeRef,
1136                    )?);
1137                }
1138                if parser.skip_token(Token::Comma).is_some() && parser.token != Token::RParen {
1139                    right = Some(crate::data_type::parse_data_type(
1140                        parser,
1141                        DataTypeContext::TypeRef,
1142                    )?);
1143                }
1144                Ok(())
1145            })?;
1146            parser.consume_token(Token::RParen)?;
1147            (left, right)
1148        } else {
1149            (None, None)
1150        };
1151        operators.push(DropOperatorItem {
1152            name,
1153            left_type,
1154            right_type,
1155        });
1156        if parser.skip_token(Token::Comma).is_none() {
1157            break;
1158        }
1159    }
1160    let restrict_or_cascade = parse_cascade_or_restrict(parser);
1161    Ok(DropOperator {
1162        drop_operator_span,
1163        if_exists,
1164        operators,
1165        restrict_or_cascade,
1166    })
1167}
1168
1169/// Represent a drop operator family statement (PostgreSQL)
1170/// ```
1171/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropOperatorFamily, Statement, Issues};
1172/// # let options = ParseOptions::new().dialect(SQLDialect::PostgreSQL);
1173/// #
1174/// let sql = "DROP OPERATOR FAMILY IF EXISTS myfamily USING gist CASCADE;";
1175/// let mut issues = Issues::new(sql);
1176/// let mut stmts = parse_statements(sql, &mut issues, &options);
1177/// # assert!(issues.is_ok());
1178/// let drop: DropOperatorFamily = match stmts.pop() {
1179///     Some(Statement::DropOperatorFamily(d)) => *d,
1180///     _ => panic!("We should get a drop operator family statement")
1181/// };
1182/// assert!(drop.family.identifier.as_str() == "myfamily");
1183/// ```
1184#[derive(Debug, Clone)]
1185pub struct DropOperatorFamily<'a> {
1186    /// Span of "DROP OPERATOR FAMILY"
1187    pub drop_operator_family_span: Span,
1188    /// Span of "IF EXISTS" if specified
1189    pub if_exists: Option<Span>,
1190    /// Name of the operator family
1191    pub family: QualifiedName<'a>,
1192    /// Span and name of the index method (USING ...)
1193    pub using: Option<(Span, Identifier<'a>)>,
1194    /// Restrict or cascade option (PostgreSQL)
1195    pub restrict_or_cascade: Option<CascadeOrRestrict>,
1196}
1197
1198impl<'a> Spanned for DropOperatorFamily<'a> {
1199    fn span(&self) -> Span {
1200        self.drop_operator_family_span
1201            .join_span(&self.if_exists)
1202            .join_span(&self.family)
1203            .join_span(&self.using)
1204            .join_span(&self.restrict_or_cascade)
1205    }
1206}
1207
1208fn parse_drop_operator_family<'a>(
1209    parser: &mut Parser<'a, '_>,
1210    drop_operator_family_span: Span,
1211) -> Result<DropOperatorFamily<'a>, ParseError> {
1212    parser.postgres_only(&drop_operator_family_span);
1213    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
1214        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
1215    } else {
1216        None
1217    };
1218    let family = parse_qualified_name_unreserved(parser)?;
1219    let using = if let Some(span) = parser.skip_keyword(Keyword::USING) {
1220        let method = parser.consume_plain_identifier_unreserved()?;
1221        Some((span, method))
1222    } else {
1223        None
1224    };
1225    let restrict_or_cascade = parse_cascade_or_restrict(parser);
1226    Ok(DropOperatorFamily {
1227        drop_operator_family_span,
1228        if_exists,
1229        family,
1230        using,
1231        restrict_or_cascade,
1232    })
1233}
1234
1235/// Represent a drop operator class statement (PostgreSQL)
1236/// ```
1237/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, DropOperatorClass, Statement, Issues};
1238/// # let options = ParseOptions::new().dialect(SQLDialect::PostgreSQL);
1239/// #
1240/// let sql = "DROP OPERATOR CLASS IF EXISTS myclass USING gist CASCADE;";
1241/// let mut issues = Issues::new(sql);
1242/// let mut stmts = parse_statements(sql, &mut issues, &options);
1243/// # assert!(issues.is_ok());
1244/// let drop: DropOperatorClass = match stmts.pop() {
1245///     Some(Statement::DropOperatorClass(d)) => *d,
1246///     _ => panic!("We should get a drop operator class statement")
1247/// };
1248/// assert!(drop.class.identifier.as_str() == "myclass");
1249/// ```
1250#[derive(Debug, Clone)]
1251pub struct DropOperatorClass<'a> {
1252    /// Span of "DROP OPERATOR CLASS"
1253    pub drop_operator_class_span: Span,
1254    /// Span of "IF EXISTS" if specified
1255    pub if_exists: Option<Span>,
1256    /// Name of the operator class
1257    pub class: QualifiedName<'a>,
1258    /// Span and name of the index method (USING ...)
1259    pub using: Option<(Span, Identifier<'a>)>,
1260    /// Restrict or cascade option (PostgreSQL)
1261    pub restrict_or_cascade: Option<CascadeOrRestrict>,
1262}
1263
1264impl<'a> Spanned for DropOperatorClass<'a> {
1265    fn span(&self) -> Span {
1266        self.drop_operator_class_span
1267            .join_span(&self.if_exists)
1268            .join_span(&self.class)
1269            .join_span(&self.using)
1270            .join_span(&self.restrict_or_cascade)
1271    }
1272}
1273
1274fn parse_drop_operator_class<'a>(
1275    parser: &mut Parser<'a, '_>,
1276    drop_operator_class_span: Span,
1277) -> Result<DropOperatorClass<'a>, ParseError> {
1278    parser.postgres_only(&drop_operator_class_span);
1279    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
1280        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
1281    } else {
1282        None
1283    };
1284    let class = parse_qualified_name_unreserved(parser)?;
1285    let using = if let Some(span) = parser.skip_keyword(Keyword::USING) {
1286        let method = parser.consume_plain_identifier_unreserved()?;
1287        Some((span, method))
1288    } else {
1289        None
1290    };
1291    let restrict_or_cascade = parse_cascade_or_restrict(parser);
1292    Ok(DropOperatorClass {
1293        drop_operator_class_span,
1294        if_exists,
1295        class,
1296        using,
1297        restrict_or_cascade,
1298    })
1299}
1300
1301/// DROP TYPE statement (PostgreSQL)
1302#[derive(Debug, Clone)]
1303pub struct DropType<'a> {
1304    /// Span of "DROP TYPE"
1305    pub drop_type_span: Span,
1306    /// Span of "IF EXISTS" if specified
1307    pub if_exists: Option<Span>,
1308    /// List of type names to drop
1309    pub names: Vec<QualifiedName<'a>>,
1310    /// Span of "CASCADE" or "RESTRICT" if specified
1311    pub restrict_or_cascade: Option<CascadeOrRestrict>,
1312}
1313
1314impl<'a> Spanned for DropType<'a> {
1315    fn span(&self) -> Span {
1316        self.drop_type_span
1317            .join_span(&self.if_exists)
1318            .join_span(&self.names)
1319            .join_span(&self.restrict_or_cascade)
1320    }
1321}
1322
1323fn parse_drop_type<'a>(
1324    parser: &mut Parser<'a, '_>,
1325    drop_span: Span,
1326) -> Result<DropType<'a>, ParseError> {
1327    let type_span = parser.consume_keyword(Keyword::TYPE)?;
1328    parser.postgres_only(&type_span);
1329    let drop_type_span = drop_span.join_span(&type_span);
1330    let if_exists = if let Some(span) = parser.skip_keyword(Keyword::IF) {
1331        Some(parser.consume_keyword(Keyword::EXISTS)?.join_span(&span))
1332    } else {
1333        None
1334    };
1335    let mut names = Vec::new();
1336    loop {
1337        names.push(parse_qualified_name_unreserved(parser)?);
1338        if parser.skip_token(Token::Comma).is_none() {
1339            break;
1340        }
1341    }
1342    let restrict_or_cascade = parse_cascade_or_restrict(parser);
1343    Ok(DropType {
1344        drop_type_span,
1345        if_exists,
1346        names,
1347        restrict_or_cascade,
1348    })
1349}
1350
1351pub(crate) fn parse_drop<'a>(parser: &mut Parser<'a, '_>) -> Result<Statement<'a>, ParseError> {
1352    let drop_span = parser.consume_keyword(Keyword::DROP)?;
1353    let temporary = parser.skip_keyword(Keyword::TEMPORARY);
1354    match &parser.token {
1355        Token::Ident(_, Keyword::TABLE) => Ok(Statement::DropTable(Box::new(parse_drop_table(
1356            parser, drop_span, temporary,
1357        )?))),
1358        Token::Ident(_, Keyword::VIEW) => Ok(Statement::DropView(Box::new(parse_drop_view(
1359            parser, drop_span, temporary,
1360        )?))),
1361        Token::Ident(_, Keyword::DATABASE) => Ok(Statement::DropDatabase(Box::new(
1362            parse_drop_database(parser, drop_span)?,
1363        ))),
1364        Token::Ident(_, Keyword::SCHEMA) => Ok(Statement::DropSchema(Box::new(parse_drop_schema(
1365            parser, drop_span,
1366        )?))),
1367        Token::Ident(_, Keyword::DOMAIN) => Ok(Statement::DropDomain(Box::new(parse_drop_domain(
1368            parser, drop_span,
1369        )?))),
1370        Token::Ident(_, Keyword::EXTENSION) => Ok(Statement::DropExtension(Box::new(
1371            parse_drop_extension(parser, drop_span)?,
1372        ))),
1373        Token::Ident(_, Keyword::EVENT) => Ok(Statement::DropEvent(Box::new(parse_drop_event(
1374            parser, drop_span,
1375        )?))),
1376        Token::Ident(_, Keyword::FUNCTION) => Ok(Statement::DropFunction(Box::new(
1377            parse_drop_function(parser, drop_span)?,
1378        ))),
1379        Token::Ident(_, Keyword::OPERATOR) => {
1380            let operator_span = parser.consume_keyword(Keyword::OPERATOR)?;
1381            match &parser.token {
1382                Token::Ident(_, Keyword::FAMILY) => {
1383                    let family_span = parser.consume_keyword(Keyword::FAMILY)?;
1384                    Ok(Statement::DropOperatorFamily(Box::new(
1385                        parse_drop_operator_family(
1386                            parser,
1387                            drop_span.join_span(&operator_span).join_span(&family_span),
1388                        )?,
1389                    )))
1390                }
1391                Token::Ident(_, Keyword::CLASS) => {
1392                    let class_span = parser.consume_keyword(Keyword::CLASS)?;
1393                    Ok(Statement::DropOperatorClass(Box::new(
1394                        parse_drop_operator_class(
1395                            parser,
1396                            drop_span.join_span(&operator_span).join_span(&class_span),
1397                        )?,
1398                    )))
1399                }
1400                _ => Ok(Statement::DropOperator(Box::new(parse_drop_operator(
1401                    parser,
1402                    drop_span.join_span(&operator_span),
1403                )?))),
1404            }
1405        }
1406        Token::Ident(_, Keyword::INDEX) => Ok(Statement::DropIndex(Box::new(parse_drop_index(
1407            parser, drop_span,
1408        )?))),
1409        Token::Ident(_, Keyword::PROCEDURE) => Ok(Statement::DropProcedure(Box::new(
1410            parse_drop_procedure(parser, drop_span)?,
1411        ))),
1412        Token::Ident(_, Keyword::SEQUENCE) => Ok(Statement::DropSequence(Box::new(
1413            parse_drop_sequence(parser, drop_span)?,
1414        ))),
1415        Token::Ident(_, Keyword::SERVER) => Ok(Statement::DropServer(Box::new(parse_drop_server(
1416            parser, drop_span,
1417        )?))),
1418        Token::Ident(_, Keyword::TRIGGER) => Ok(Statement::DropTrigger(Box::new(
1419            parse_drop_trigger(parser, drop_span)?,
1420        ))),
1421        Token::Ident(_, Keyword::TYPE) => Ok(Statement::DropType(Box::new(parse_drop_type(
1422            parser, drop_span,
1423        )?))),
1424        Token::Ident(_, Keyword::USER) => {
1425            // DROP USER [IF EXISTS] user_name [, user_name] ..
1426            parser.todo(file!(), line!())
1427        }
1428        _ => parser.expected_failure("droppable"),
1429    }
1430}