sql_parse/
create.rs

1use alloc::{boxed::Box, vec::Vec};
2
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14use crate::{
15    data_type::parse_data_type,
16    expression::parse_expression,
17    keywords::Keyword,
18    lexer::Token,
19    parser::{ParseError, Parser},
20    qualified_name::parse_qualified_name,
21    statement::{parse_compound_query, parse_statement},
22    DataType, Expression, Identifier, QualifiedName, SString, Span, Spanned, Statement,
23};
24
25/// Options on created table
26#[derive(Clone, Debug)]
27pub enum TableOption<'a> {
28    AutoExtendSize {
29        identifier: Span,
30        value: Identifier<'a>,
31    },
32    AutoIncrement {
33        identifier: Span,
34        value: Identifier<'a>,
35    },
36    AvgRowLength {
37        identifier: Span,
38        value: Identifier<'a>,
39    },
40    CharSet {
41        identifier: Span,
42        value: Identifier<'a>,
43    },
44    DefaultCharSet {
45        identifier: Span,
46        value: Identifier<'a>,
47    },
48    Checksum {
49        identifier: Span,
50        value: (bool, Span),
51    },
52    Collate {
53        identifier: Span,
54        value: Identifier<'a>,
55    },
56    DefaultCollate {
57        identifier: Span,
58        value: Identifier<'a>,
59    },
60    Comment {
61        identifier: Span,
62        value: SString<'a>,
63    },
64    Compression {
65        identifier: Span,
66        value: SString<'a>,
67    },
68    Connection {
69        identifier: Span,
70        value: SString<'a>,
71    },
72    DataDirectory {
73        identifier: Span,
74        value: SString<'a>,
75    },
76    IndexDirectory {
77        identifier: Span,
78        value: SString<'a>,
79    },
80    DelayKeyWrite {
81        identifier: Span,
82        value: (bool, Span),
83    },
84    Encryption {
85        identifier: Span,
86        value: (bool, Span),
87    },
88    Engine {
89        identifier: Span,
90        value: Identifier<'a>,
91    },
92    EngineAttribute {
93        identifier: Span,
94        value: SString<'a>,
95    },
96    InsertMethod {
97        identifier: Span,
98        value: Identifier<'a>,
99    },
100    KeyBlockSize {
101        identifier: Span,
102        value: (usize, Span),
103    },
104    MaxRows {
105        identifier: Span,
106        value: (usize, Span),
107    },
108    MinRows {
109        identifier: Span,
110        value: (usize, Span),
111    },
112    // PACK_KEYS
113    Password {
114        identifier: Span,
115        value: SString<'a>,
116    },
117    RowFormat {
118        identifier: Span,
119        value: Identifier<'a>,
120    },
121    SecondaryEngineAttribute {
122        identifier: Span,
123        value: SString<'a>,
124    },
125    Strict {
126        identifier: Span,
127    },
128    //StatsAutoRecalc
129    //StatsPersistance
130    //StatsSamplePages
131    //TABLESPACE
132    //UNION
133}
134
135impl<'a> Spanned for TableOption<'a> {
136    fn span(&self) -> Span {
137        match &self {
138            TableOption::AutoExtendSize { identifier, value } => identifier.span().join_span(value),
139            TableOption::AutoIncrement { identifier, value } => identifier.span().join_span(value),
140            TableOption::AvgRowLength { identifier, value } => identifier.span().join_span(value),
141            TableOption::CharSet { identifier, value } => identifier.span().join_span(value),
142            TableOption::DefaultCharSet { identifier, value } => identifier.span().join_span(value),
143            TableOption::Checksum { identifier, value } => identifier.span().join_span(value),
144            TableOption::Collate { identifier, value } => identifier.span().join_span(value),
145            TableOption::DefaultCollate { identifier, value } => identifier.span().join_span(value),
146            TableOption::Comment { identifier, value } => identifier.span().join_span(value),
147            TableOption::Compression { identifier, value } => identifier.span().join_span(value),
148            TableOption::Connection { identifier, value } => identifier.span().join_span(value),
149            TableOption::DataDirectory { identifier, value } => identifier.span().join_span(value),
150            TableOption::IndexDirectory { identifier, value } => identifier.span().join_span(value),
151            TableOption::DelayKeyWrite { identifier, value } => identifier.span().join_span(value),
152            TableOption::Encryption { identifier, value } => identifier.span().join_span(value),
153            TableOption::Engine { identifier, value } => identifier.span().join_span(value),
154            TableOption::EngineAttribute { identifier, value } => {
155                identifier.span().join_span(value)
156            }
157            TableOption::InsertMethod { identifier, value } => identifier.span().join_span(value),
158            TableOption::KeyBlockSize { identifier, value } => identifier.span().join_span(value),
159            TableOption::MaxRows { identifier, value } => identifier.span().join_span(value),
160            TableOption::MinRows { identifier, value } => identifier.span().join_span(value),
161            TableOption::Password { identifier, value } => identifier.span().join_span(value),
162            TableOption::RowFormat { identifier, value } => identifier.span().join_span(value),
163            TableOption::SecondaryEngineAttribute { identifier, value } => {
164                identifier.span().join_span(value)
165            }
166            TableOption::Strict { identifier } => identifier.span(),
167        }
168    }
169}
170
171/// Definition in create table
172#[derive(Clone, Debug)]
173pub enum CreateDefinition<'a> {
174    ColumnDefinition {
175        /// Name of column
176        identifier: Identifier<'a>,
177        /// Datatype and options for column
178        data_type: DataType<'a>,
179    },
180    ConstraintDefinition {
181        span: Span,
182        identifier: Identifier<'a>,
183    },
184}
185
186impl<'a> Spanned for CreateDefinition<'a> {
187    fn span(&self) -> Span {
188        match &self {
189            CreateDefinition::ColumnDefinition {
190                identifier,
191                data_type,
192            } => identifier.span().join_span(data_type),
193            CreateDefinition::ConstraintDefinition { span, identifier } => {
194                span.join_span(identifier)
195            }
196        }
197    }
198}
199
200/// Special algorithm used for table creation
201#[derive(Clone, Debug)]
202pub enum CreateAlgorithm {
203    Undefined(Span),
204    Merge(Span),
205    TempTable(Span),
206}
207impl Spanned for CreateAlgorithm {
208    fn span(&self) -> Span {
209        match &self {
210            CreateAlgorithm::Undefined(s) => s.span(),
211            CreateAlgorithm::Merge(s) => s.span(),
212            CreateAlgorithm::TempTable(s) => s.span(),
213        }
214    }
215}
216
217/// Options for create statement
218#[derive(Clone, Debug)]
219pub enum CreateOption<'a> {
220    OrReplace(Span),
221    Temporary(Span),
222    Unique(Span),
223    Algorithm(Span, CreateAlgorithm),
224    Definer {
225        definer_span: Span,
226        user: Identifier<'a>,
227        host: Identifier<'a>,
228    },
229    SqlSecurityDefiner(Span, Span),
230    SqlSecurityUser(Span, Span),
231}
232impl<'a> Spanned for CreateOption<'a> {
233    fn span(&self) -> Span {
234        match &self {
235            CreateOption::OrReplace(v) => v.span(),
236            CreateOption::Temporary(v) => v.span(),
237            CreateOption::Algorithm(s, a) => s.join_span(a),
238            CreateOption::Definer {
239                definer_span,
240                user,
241                host,
242            } => definer_span.join_span(user).join_span(host),
243            CreateOption::SqlSecurityDefiner(a, b) => a.join_span(b),
244            CreateOption::SqlSecurityUser(a, b) => a.join_span(b),
245            CreateOption::Unique(v) => v.span(),
246        }
247    }
248}
249
250/// Represent a create table statement
251/// ```
252/// # use sql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, CreateTable, Statement, Issues};
253/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
254/// let sql = "CREATE TABLE `parts` (
255///         `id` int(11) NOT NULL COMMENT 'THIS IS THE ID FIELD',
256///         `hash` varchar(64) COLLATE utf8_bin NOT NULL,
257///         `destination` varchar(64) COLLATE utf8_bin NOT NULL,
258///         `part` varchar(64) COLLATE utf8_bin NOT NULL,
259///         `success` tinyint(1) NOT NULL
260///     ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;";
261///
262/// let mut issues = Issues::new(sql);
263/// let mut stmts = parse_statements(sql, &mut issues, &options);
264///
265/// # assert!(issues.is_ok());
266/// let create: CreateTable = match stmts.pop() {
267///     Some(Statement::CreateTable(c)) => c,
268///     _ => panic!("We should get an create table statement")
269/// };
270///
271/// assert!(create.identifier.identifier.as_str() == "parts");
272/// println!("{:#?}", create.create_definitions)
273/// ```
274
275#[derive(Clone, Debug)]
276pub struct CreateTable<'a> {
277    /// Span of "CREATE"
278    pub create_span: Span,
279    /// Options specified after "CREATE"
280    pub create_options: Vec<CreateOption<'a>>,
281    /// Span of "TABLE"
282    pub table_span: Span,
283    /// Name of the table
284    pub identifier: QualifiedName<'a>,
285    /// Span of "IF NOT EXISTS" if specified
286    pub if_not_exists: Option<Span>,
287    /// Definitions of table members
288    pub create_definitions: Vec<CreateDefinition<'a>>,
289    /// Options specified after the table creation
290    pub options: Vec<TableOption<'a>>,
291}
292
293impl<'a> Spanned for CreateTable<'a> {
294    fn span(&self) -> Span {
295        self.create_span
296            .join_span(&self.create_options)
297            .join_span(&self.table_span)
298            .join_span(&self.identifier)
299            .join_span(&self.if_not_exists)
300            .join_span(&self.create_definitions)
301            .join_span(&self.options)
302    }
303}
304
305/// Represent a create view statement
306/// ```
307/// # use sql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, CreateView, Statement, Issues};
308/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
309/// #
310/// let sql = "CREATE ALGORITHM=UNDEFINED DEFINER=`phpmyadmin`@`localhost` SQL SECURITY DEFINER
311///    VIEW `v1`
312///    AS SELECT
313///         `t1`.`id` AS `id`,
314///         `t1`.`c1` AS `c1`,
315///         (SELECT `t2`.`c2` FROM `t2` WHERE `t2`.`id` = `t1`.`c3`) AS `c2`
316///         FROM `t1` WHERE `t1`.`deleted` IS NULL;";
317/// let mut issues = Issues::new(sql);
318/// let mut stmts = parse_statements(sql, &mut issues, &options);
319///
320/// # assert!(issues.is_ok());
321/// let create: CreateView = match stmts.pop() {
322///     Some(Statement::CreateView(c)) => c,
323///     _ => panic!("We should get an create view statement")
324/// };
325///
326/// assert!(create.name.identifier.as_str() == "v1");
327/// println!("{:#?}", create.select)
328/// ```
329
330#[derive(Clone, Debug)]
331pub struct CreateView<'a> {
332    /// Span of "CREATE"
333    pub create_span: Span,
334    /// Options after "CREATE"
335    pub create_options: Vec<CreateOption<'a>>,
336    /// Span of "VIEW"
337    pub view_span: Span,
338    /// Span of "IF NOT EXISTS" if specified
339    pub if_not_exists: Option<Span>,
340    /// Name of the created view
341    pub name: QualifiedName<'a>,
342    /// Span of "AS"
343    pub as_span: Span,
344    /// The select statement following "AS"
345    pub select: Box<Statement<'a>>,
346}
347
348impl<'a> Spanned for CreateView<'a> {
349    fn span(&self) -> Span {
350        self.create_span
351            .join_span(&self.create_options)
352            .join_span(&self.view_span)
353            .join_span(&self.if_not_exists)
354            .join_span(&self.name)
355            .join_span(&self.as_span)
356            .join_span(&self.select)
357    }
358}
359
360pub(crate) fn parse_create_constraint_definition<'a>(
361    parser: &mut Parser<'a, '_>,
362) -> Result<CreateDefinition<'a>, ParseError> {
363    let span = parser.consume_keyword(Keyword::CONSTRAINT)?;
364    let identifier = parser.consume_plain_identifier()?;
365    parser.consume_keywords(&[Keyword::FOREIGN, Keyword::KEY])?;
366    parser.consume_token(Token::LParen)?;
367    parser.consume_plain_identifier()?;
368    while parser.skip_token(Token::Comma).is_some() {
369        parser.consume_plain_identifier()?;
370    }
371    parser.consume_token(Token::RParen)?;
372    parser.consume_keyword(Keyword::REFERENCES)?;
373    parser.consume_plain_identifier()?;
374    parser.consume_token(Token::LParen)?;
375    parser.consume_plain_identifier()?;
376    while parser.skip_token(Token::Comma).is_some() {
377        parser.consume_plain_identifier()?;
378    }
379
380    parser.consume_token(Token::RParen)?;
381    if parser.skip_keyword(Keyword::ON).is_some() {
382        parser.consume_keyword(Keyword::DELETE)?;
383        match parser.token {
384            Token::Ident(_, Keyword::CASCADE) => {
385                parser.consume_keyword(Keyword::CASCADE)?;
386            }
387            Token::Ident(_, Keyword::DELETE) => {
388                parser.consume_keyword(Keyword::DELETE)?;
389            }
390            Token::Ident(_, Keyword::RESTRICT) => {
391                parser.consume_keyword(Keyword::RESTRICT)?;
392            }
393            Token::Ident(_, Keyword::SET) => {
394                parser.consume_keywords(&[Keyword::SET, Keyword::NULL])?;
395            }
396            _ => parser.expected_failure("CASCADE, DELETE OR SET NULL")?,
397        }
398    }
399    Ok(CreateDefinition::ConstraintDefinition { span, identifier })
400}
401
402pub(crate) fn parse_create_definition<'a>(
403    parser: &mut Parser<'a, '_>,
404) -> Result<CreateDefinition<'a>, ParseError> {
405    match &parser.token {
406        Token::Ident(_, Keyword::CONSTRAINT) => parse_create_constraint_definition(parser),
407        Token::Ident(_, _) => Ok(CreateDefinition::ColumnDefinition {
408            identifier: parser.consume_plain_identifier()?,
409            data_type: parse_data_type(parser, false)?,
410        }),
411        _ => parser.expected_failure("identifier"),
412    }
413}
414
415fn parse_create_view<'a>(
416    parser: &mut Parser<'a, '_>,
417    create_span: Span,
418    create_options: Vec<CreateOption<'a>>,
419) -> Result<Statement<'a>, ParseError> {
420    let view_span = parser.consume_keyword(Keyword::VIEW)?;
421
422    let if_not_exists = if let Some(if_) = parser.skip_keyword(Keyword::IF) {
423        Some(
424            parser
425                .consume_keywords(&[Keyword::NOT, Keyword::EXISTS])?
426                .join_span(&if_),
427        )
428    } else {
429        None
430    };
431
432    let name = parse_qualified_name(parser)?;
433    // TODO (column_list)
434
435    let as_span = parser.consume_keyword(Keyword::AS)?;
436
437    let select = parse_compound_query(parser)?;
438
439    // TODO [WITH [CASCADED | LOCAL] CHECK OPTION]
440
441    Ok(Statement::CreateView(CreateView {
442        create_span,
443        create_options,
444        view_span,
445        if_not_exists,
446        name,
447        as_span,
448        select: Box::new(select),
449    }))
450}
451
452/// Characteristic of a function
453#[derive(Clone, Debug)]
454pub enum FunctionCharacteristic<'a> {
455    LanguageSql(Span),
456    LanguagePlpgsql(Span),
457    NotDeterministic(Span),
458    Deterministic(Span),
459    ContainsSql(Span),
460    NoSql(Span),
461    ReadsSqlData(Span),
462    ModifiesSqlData(Span),
463    SqlSecurityDefiner(Span),
464    SqlSecurityUser(Span),
465    Comment(SString<'a>),
466}
467
468impl<'a> Spanned for FunctionCharacteristic<'a> {
469    fn span(&self) -> Span {
470        match &self {
471            FunctionCharacteristic::LanguageSql(v) => v.span(),
472            FunctionCharacteristic::NotDeterministic(v) => v.span(),
473            FunctionCharacteristic::Deterministic(v) => v.span(),
474            FunctionCharacteristic::ContainsSql(v) => v.span(),
475            FunctionCharacteristic::NoSql(v) => v.span(),
476            FunctionCharacteristic::ReadsSqlData(v) => v.span(),
477            FunctionCharacteristic::ModifiesSqlData(v) => v.span(),
478            FunctionCharacteristic::SqlSecurityDefiner(v) => v.span(),
479            FunctionCharacteristic::SqlSecurityUser(v) => v.span(),
480            FunctionCharacteristic::Comment(v) => v.span(),
481            FunctionCharacteristic::LanguagePlpgsql(v) => v.span(),
482        }
483    }
484}
485
486/// Direction of a function argument
487#[derive(Clone, Debug)]
488pub enum FunctionParamDirection {
489    In(Span),
490    Out(Span),
491    InOut(Span),
492}
493
494impl Spanned for FunctionParamDirection {
495    fn span(&self) -> Span {
496        match &self {
497            FunctionParamDirection::In(v) => v.span(),
498            FunctionParamDirection::Out(v) => v.span(),
499            FunctionParamDirection::InOut(v) => v.span(),
500        }
501    }
502}
503
504/// Representation of Create Function Statement
505///
506/// This is not fully implemented yet
507///
508/// ```ignore
509/// # use sql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, CreateFunction, Statement, Issues};
510/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
511/// #
512/// let sql = "DELIMITER $$
513/// CREATE FUNCTION add_func3(IN a INT, IN b INT, OUT c INT) RETURNS INT
514/// BEGIN
515///     SET c = 100;
516///     RETURN a + b;
517/// END;
518/// $$
519/// DELIMITER ;";
520/// let mut issues = Issues::new(sql);
521/// let mut stmts = parse_statements(sql, &mut issues, &options);
522///
523/// assert!(issues.is_empty());
524/// #
525/// let create: CreateFunction = match stmts.pop() {
526///     Some(Statement::CreateFunction(c)) => c,
527///     _ => panic!("We should get an create function statement")
528/// };
529///
530/// assert!(create.name.as_str() == "add_func3");
531/// println!("{:#?}", create.return_)
532/// ```
533#[derive(Clone, Debug)]
534pub struct CreateFunction<'a> {
535    /// Span of "CREATE"
536    pub create_span: Span,
537    /// Options after "CREATE"
538    pub create_options: Vec<CreateOption<'a>>,
539    /// Span of "FUNCTION"
540    pub function_span: Span,
541    /// Span of "IF NOT EXISTS" if specified
542    pub if_not_exists: Option<Span>,
543    /// Name o created function
544    pub name: Identifier<'a>,
545    /// Names and types of function arguments
546    pub params: Vec<(Option<FunctionParamDirection>, Identifier<'a>, DataType<'a>)>,
547    /// Span of "RETURNS"
548    pub returns_span: Span,
549    /// Type of return value
550    pub return_type: DataType<'a>,
551    /// Characteristics of created function
552    pub characteristics: Vec<FunctionCharacteristic<'a>>,
553    /// Statement computing return value
554    pub return_: Option<Box<Statement<'a>>>,
555}
556
557impl<'a> Spanned for CreateFunction<'a> {
558    fn span(&self) -> Span {
559        self.create_span
560            .join_span(&self.create_options)
561            .join_span(&self.function_span)
562            .join_span(&self.if_not_exists)
563            .join_span(&self.name)
564            .join_span(&self.return_type)
565            .join_span(&self.characteristics)
566            .join_span(&self.return_)
567    }
568}
569
570fn parse_create_function<'a>(
571    parser: &mut Parser<'a, '_>,
572    create_span: Span,
573    create_options: Vec<CreateOption<'a>>,
574) -> Result<Statement<'a>, ParseError> {
575    let function_span = parser.consume_keyword(Keyword::FUNCTION)?;
576
577    let if_not_exists = if let Some(if_) = parser.skip_keyword(Keyword::IF) {
578        Some(
579            parser
580                .consume_keywords(&[Keyword::NOT, Keyword::EXISTS])?
581                .join_span(&if_),
582        )
583    } else {
584        None
585    };
586
587    let name = parser.consume_plain_identifier()?;
588    let mut params = Vec::new();
589    parser.consume_token(Token::LParen)?;
590    parser.recovered("')'", &|t| t == &Token::RParen, |parser| {
591        loop {
592            let direction = match &parser.token {
593                Token::Ident(_, Keyword::IN) => {
594                    let in_ = parser.consume_keyword(Keyword::IN)?;
595                    if let Some(out) = parser.skip_keyword(Keyword::OUT) {
596                        Some(FunctionParamDirection::InOut(in_.join_span(&out)))
597                    } else {
598                        Some(FunctionParamDirection::In(in_))
599                    }
600                }
601                Token::Ident(_, Keyword::OUT) => Some(FunctionParamDirection::Out(
602                    parser.consume_keyword(Keyword::OUT)?,
603                )),
604                Token::Ident(_, Keyword::INOUT) => Some(FunctionParamDirection::InOut(
605                    parser.consume_keyword(Keyword::INOUT)?,
606                )),
607                _ => None,
608            };
609
610            let name = parser.consume_plain_identifier()?;
611            let type_ = parse_data_type(parser, false)?;
612            params.push((direction, name, type_));
613            if parser.skip_token(Token::Comma).is_none() {
614                break;
615            }
616        }
617        Ok(())
618    })?;
619    parser.consume_token(Token::RParen)?;
620    let returns_span = parser.consume_keyword(Keyword::RETURNS)?;
621    let return_type = parse_data_type(parser, true)?;
622    if parser.options.dialect.is_postgresql() && parser.skip_keyword(Keyword::AS).is_some() {
623        parser.consume_token(Token::DoubleDollar)?;
624        loop {
625            match &parser.token {
626                Token::Eof | Token::DoubleDollar => {
627                    parser.consume_token(Token::DoubleDollar)?;
628                    break;
629                }
630                _ => {
631                    parser.consume();
632                }
633            }
634        }
635    }
636
637    let mut characteristics = Vec::new();
638    loop {
639        let f = match &parser.token {
640            Token::Ident(_, Keyword::LANGUAGE) => {
641                let lg = parser.consume();
642                match &parser.token {
643                    Token::Ident(_, Keyword::SQL) => {
644                        FunctionCharacteristic::LanguageSql(lg.join_span(&parser.consume()))
645                    }
646                    Token::Ident(_, Keyword::PLPGSQL) => {
647                        FunctionCharacteristic::LanguagePlpgsql(lg.join_span(&parser.consume()))
648                    }
649                    _ => parser.expected_failure("language name")?,
650                }
651            }
652            Token::Ident(_, Keyword::NOT) => FunctionCharacteristic::NotDeterministic(
653                parser.consume_keywords(&[Keyword::NOT, Keyword::DETERMINISTIC])?,
654            ),
655            Token::Ident(_, Keyword::DETERMINISTIC) => FunctionCharacteristic::Deterministic(
656                parser.consume_keyword(Keyword::DETERMINISTIC)?,
657            ),
658            Token::Ident(_, Keyword::CONTAINS) => FunctionCharacteristic::ContainsSql(
659                parser.consume_keywords(&[Keyword::CONTAINS, Keyword::SQL])?,
660            ),
661            Token::Ident(_, Keyword::NO) => FunctionCharacteristic::NoSql(
662                parser.consume_keywords(&[Keyword::NO, Keyword::SQL])?,
663            ),
664            Token::Ident(_, Keyword::READS) => {
665                FunctionCharacteristic::ReadsSqlData(parser.consume_keywords(&[
666                    Keyword::READS,
667                    Keyword::SQL,
668                    Keyword::DATA,
669                ])?)
670            }
671            Token::Ident(_, Keyword::MODIFIES) => {
672                FunctionCharacteristic::ModifiesSqlData(parser.consume_keywords(&[
673                    Keyword::MODIFIES,
674                    Keyword::SQL,
675                    Keyword::DATA,
676                ])?)
677            }
678            Token::Ident(_, Keyword::COMMENT) => {
679                parser.consume_keyword(Keyword::COMMENT)?;
680                FunctionCharacteristic::Comment(parser.consume_string()?)
681            }
682            Token::Ident(_, Keyword::SQL) => {
683                let span = parser.consume_keywords(&[Keyword::SQL, Keyword::SECURITY])?;
684                match &parser.token {
685                    Token::Ident(_, Keyword::DEFINER) => {
686                        FunctionCharacteristic::SqlSecurityDefiner(
687                            parser.consume_keyword(Keyword::DEFINER)?.join_span(&span),
688                        )
689                    }
690                    Token::Ident(_, Keyword::USER) => FunctionCharacteristic::SqlSecurityUser(
691                        parser.consume_keyword(Keyword::USER)?.join_span(&span),
692                    ),
693                    _ => parser.expected_failure("'DEFINER' or 'USER'")?,
694                }
695            }
696            _ => break,
697        };
698        characteristics.push(f);
699    }
700
701    let return_ = if parser.options.dialect.is_maria() {
702        match parse_statement(parser)? {
703            Some(v) => Some(Box::new(v)),
704            None => parser.expected_failure("statement")?,
705        }
706    } else {
707        None
708    };
709
710    Ok(Statement::CreateFunction(CreateFunction {
711        create_span,
712        create_options,
713        function_span,
714        if_not_exists,
715        name,
716        params,
717        return_type,
718        characteristics,
719        return_,
720        returns_span,
721    }))
722}
723
724/// When to fire the trigger
725#[derive(Clone, Debug)]
726
727pub enum TriggerTime {
728    Before(Span),
729    After(Span),
730}
731
732impl Spanned for TriggerTime {
733    fn span(&self) -> Span {
734        match &self {
735            TriggerTime::Before(v) => v.span(),
736            TriggerTime::After(v) => v.span(),
737        }
738    }
739}
740
741/// On what event to fire the trigger
742#[derive(Clone, Debug)]
743pub enum TriggerEvent {
744    Update(Span),
745    Insert(Span),
746    Delete(Span),
747}
748
749impl Spanned for TriggerEvent {
750    fn span(&self) -> Span {
751        match &self {
752            TriggerEvent::Update(v) => v.span(),
753            TriggerEvent::Insert(v) => v.span(),
754            TriggerEvent::Delete(v) => v.span(),
755        }
756    }
757}
758
759/// Represent a create trigger statement
760/// ```
761/// # use sql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, CreateTrigger, Statement, Issues};
762/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
763/// #
764/// let sql = "DROP TRIGGER IF EXISTS `my_trigger`;
765/// DELIMITER $$
766/// CREATE TRIGGER `my_trigger` AFTER DELETE ON `things` FOR EACH ROW BEGIN
767///     IF OLD.`value` IS NOT NULL THEN
768///         UPDATE `t2` AS `j`
769///             SET
770///             `j`.`total_items` = `total_items` - 1
771///             WHERE `j`.`id`=OLD.`value` AND NOT `j`.`frozen`;
772///         END IF;
773///     INSERT INTO `updated_things` (`thing`) VALUES (OLD.`id`);
774/// END
775/// $$
776/// DELIMITER ;";
777/// let mut issues = Issues::new(sql);
778/// let mut stmts = parse_statements(sql, &mut issues, &options);
779///
780/// # assert_eq!(issues.get(), &[]);
781/// #
782/// let create: CreateTrigger = match stmts.pop() {
783///     Some(Statement::CreateTrigger(c)) => c,
784///     _ => panic!("We should get an create trigger statement")
785/// };
786///
787/// assert!(create.name.as_str() == "my_trigger");
788/// println!("{:#?}", create.statement)
789/// ```
790#[derive(Clone, Debug)]
791pub struct CreateTrigger<'a> {
792    /// Span of "CREATE"
793    pub create_span: Span,
794    /// Options after "CREATE"
795    pub create_options: Vec<CreateOption<'a>>,
796    /// Span of "TRIGGER"
797    pub trigger_span: Span,
798    /// Span of "IF NOT EXISTS" if specified
799    pub if_not_exists: Option<Span>,
800    /// Name of the created trigger
801    pub name: Identifier<'a>,
802    /// Should the trigger be fired before or after the event
803    pub trigger_time: TriggerTime,
804    /// What event should the trigger be fired on
805    pub trigger_event: TriggerEvent,
806    /// Span of "ON"
807    pub on_span: Span,
808    /// Name of table to create the trigger on
809    pub table: Identifier<'a>,
810    /// Span of "FOR EACH ROW"
811    pub for_each_row_span: Span,
812    /// Statement to execute
813    pub statement: Box<Statement<'a>>,
814}
815
816impl<'a> Spanned for CreateTrigger<'a> {
817    fn span(&self) -> Span {
818        self.create_span
819            .join_span(&self.create_options)
820            .join_span(&self.trigger_span)
821            .join_span(&self.if_not_exists)
822            .join_span(&self.name)
823            .join_span(&self.trigger_time)
824            .join_span(&self.trigger_event)
825            .join_span(&self.on_span)
826            .join_span(&self.table)
827            .join_span(&self.for_each_row_span)
828            .join_span(&self.statement)
829    }
830}
831
832fn parse_create_trigger<'a>(
833    parser: &mut Parser<'a, '_>,
834    create_span: Span,
835    create_options: Vec<CreateOption<'a>>,
836) -> Result<Statement<'a>, ParseError> {
837    let trigger_span = parser.consume_keyword(Keyword::TRIGGER)?;
838
839    let if_not_exists = if let Some(if_) = parser.skip_keyword(Keyword::IF) {
840        Some(
841            parser
842                .consume_keywords(&[Keyword::NOT, Keyword::EXISTS])?
843                .join_span(&if_),
844        )
845    } else {
846        None
847    };
848
849    let name = parser.consume_plain_identifier()?;
850
851    let trigger_time = match &parser.token {
852        Token::Ident(_, Keyword::AFTER) => {
853            TriggerTime::After(parser.consume_keyword(Keyword::AFTER)?)
854        }
855        Token::Ident(_, Keyword::BEFORE) => {
856            TriggerTime::Before(parser.consume_keyword(Keyword::BEFORE)?)
857        }
858        _ => parser.expected_failure("'BEFORE' or 'AFTER'")?,
859    };
860
861    let trigger_event = match &parser.token {
862        Token::Ident(_, Keyword::UPDATE) => {
863            TriggerEvent::Update(parser.consume_keyword(Keyword::UPDATE)?)
864        }
865        Token::Ident(_, Keyword::INSERT) => {
866            TriggerEvent::Insert(parser.consume_keyword(Keyword::INSERT)?)
867        }
868        Token::Ident(_, Keyword::DELETE) => {
869            TriggerEvent::Delete(parser.consume_keyword(Keyword::DELETE)?)
870        }
871        _ => parser.expected_failure("'UPDATE' or 'INSERT' or 'DELETE'")?,
872    };
873
874    let on_span = parser.consume_keyword(Keyword::ON)?;
875
876    let table = parser.consume_plain_identifier()?;
877
878    let for_each_row_span =
879        parser.consume_keywords(&[Keyword::FOR, Keyword::EACH, Keyword::ROW])?;
880
881    // TODO [{ FOLLOWS | PRECEDES } other_trigger_name ]
882
883    let old = core::mem::replace(&mut parser.permit_compound_statements, true);
884    let statement = match parse_statement(parser)? {
885        Some(v) => v,
886        None => parser.expected_failure("statement")?,
887    };
888    parser.permit_compound_statements = old;
889
890    Ok(Statement::CreateTrigger(CreateTrigger {
891        create_span,
892        create_options,
893        trigger_span,
894        if_not_exists,
895        name,
896        trigger_time,
897        trigger_event,
898        on_span,
899        table,
900        for_each_row_span,
901        statement: Box::new(statement),
902    }))
903}
904
905#[derive(Clone, Debug)]
906pub struct CreateTypeEnum<'a> {
907    /// Span of "CREATE"
908    pub create_span: Span,
909    /// Options after "CREATE"
910    pub create_options: Vec<CreateOption<'a>>,
911    /// Span of "TYPE"
912    pub type_span: Span,
913    /// Name of the created type
914    pub name: Identifier<'a>,
915    /// Span of "AS ENUM"
916    pub as_enum_span: Span,
917    /// Enum values
918    pub values: Vec<SString<'a>>,
919}
920
921impl<'a> Spanned for CreateTypeEnum<'a> {
922    fn span(&self) -> Span {
923        self.create_span
924            .join_span(&self.create_options)
925            .join_span(&self.type_span)
926            .join_span(&self.name)
927            .join_span(&self.as_enum_span)
928            .join_span(&self.values)
929    }
930}
931
932fn parse_create_type<'a>(
933    parser: &mut Parser<'a, '_>,
934    create_span: Span,
935    create_options: Vec<CreateOption<'a>>,
936) -> Result<Statement<'a>, ParseError> {
937    let type_span = parser.consume_keyword(Keyword::TYPE)?;
938    if !parser.options.dialect.is_postgresql() {
939        parser.err("CREATE TYPE only supported by postgresql", &type_span);
940    }
941    let name = parser.consume_plain_identifier()?;
942    let as_enum_span = parser.consume_keywords(&[Keyword::AS, Keyword::ENUM])?;
943    parser.consume_token(Token::LParen)?;
944    let mut values = Vec::new();
945    loop {
946        parser.recovered(
947            "')' or ','",
948            &|t| matches!(t, Token::RParen | Token::Comma),
949            |parser| {
950                values.push(parser.consume_string()?);
951                Ok(())
952            },
953        )?;
954        if matches!(parser.token, Token::RParen) {
955            break;
956        }
957        parser.consume_token(Token::Comma)?;
958    }
959    parser.consume_token(Token::RParen)?;
960    Ok(Statement::CreateTypeEnum(CreateTypeEnum {
961        create_span,
962        create_options,
963        type_span,
964        name,
965        as_enum_span,
966        values,
967    }))
968}
969
970#[derive(Clone, Debug)]
971pub enum CreateIndexOption {
972    UsingGist(Span),
973}
974
975impl Spanned for CreateIndexOption {
976    fn span(&self) -> Span {
977        match self {
978            CreateIndexOption::UsingGist(s) => s.clone(),
979        }
980    }
981}
982
983#[derive(Clone, Debug)]
984pub struct CreateIndex<'a> {
985    pub create_span: Span,
986    pub create_options: Vec<CreateOption<'a>>,
987    pub index_span: Span,
988    pub index_name: Identifier<'a>,
989    pub if_not_exists: Option<Span>,
990    pub on_span: Span,
991    pub table_name: QualifiedName<'a>,
992    pub index_options: Vec<CreateIndexOption>,
993    pub l_paren_span: Span,
994    pub column_names: Vec<Identifier<'a>>,
995    pub r_paren_span: Span,
996    pub where_: Option<(Span, Expression<'a>)>,
997}
998
999impl<'a> Spanned for CreateIndex<'a> {
1000    fn span(&self) -> Span {
1001        self.create_span
1002            .join_span(&self.create_options)
1003            .join_span(&self.index_span)
1004            .join_span(&self.index_name)
1005            .join_span(&self.on_span)
1006            .join_span(&self.table_name)
1007            .join_span(&self.index_options)
1008            .join_span(&self.l_paren_span)
1009            .join_span(&self.column_names)
1010            .join_span(&self.r_paren_span)
1011            .join_span(&self.where_)
1012    }
1013}
1014
1015fn parse_create_index<'a>(
1016    parser: &mut Parser<'a, '_>,
1017    create_span: Span,
1018    create_options: Vec<CreateOption<'a>>,
1019) -> Result<Statement<'a>, ParseError> {
1020    let index_span = parser.consume_keyword(Keyword::INDEX)?;
1021    let if_not_exists = if let Some(s) = parser.skip_keyword(Keyword::IF) {
1022        Some(s.join_span(&parser.consume_keywords(&[Keyword::NOT, Keyword::EXISTS])?))
1023    } else {
1024        None
1025    };
1026    let index_name = parser.consume_plain_identifier()?;
1027    let on_span = parser.consume_keyword(Keyword::ON)?;
1028    let table_name = parse_qualified_name(parser)?;
1029    let mut index_options = Vec::new();
1030    if let Some(using_span) = parser.skip_keyword(Keyword::USING) {
1031        let gist_span = parser.consume_keyword(Keyword::GIST)?;
1032        index_options.push(CreateIndexOption::UsingGist(
1033            gist_span.join_span(&using_span),
1034        ));
1035    }
1036    let l_paren_span = parser.consume_token(Token::LParen)?;
1037    let mut column_names = Vec::new();
1038    column_names.push(parser.consume_plain_identifier()?);
1039    while parser.skip_token(Token::Comma).is_some() {
1040        column_names.push(parser.consume_plain_identifier()?);
1041    }
1042    let r_paren_span = parser.consume_token(Token::RParen)?;
1043
1044    let mut where_ = None;
1045    if let Some(where_span) = parser.skip_keyword(Keyword::WHERE) {
1046        let where_expr = parse_expression(parser, false)?;
1047        if parser.options.dialect.is_maria() {
1048            parser.err(
1049                "Partial indexes not supported",
1050                &where_span.join_span(&where_expr),
1051            );
1052        }
1053        where_ = Some((where_span, where_expr));
1054    }
1055
1056    Ok(Statement::CreateIndex(CreateIndex {
1057        create_span,
1058        create_options,
1059        index_span,
1060        index_name,
1061        if_not_exists,
1062        on_span,
1063        table_name,
1064        index_options,
1065        l_paren_span,
1066        column_names,
1067        r_paren_span,
1068        where_,
1069    }))
1070}
1071
1072fn parse_create_table<'a>(
1073    parser: &mut Parser<'a, '_>,
1074    create_span: Span,
1075    create_options: Vec<CreateOption<'a>>,
1076) -> Result<Statement<'a>, ParseError> {
1077    let table_span = parser.consume_keyword(Keyword::TABLE)?;
1078
1079    let mut identifier = QualifiedName {
1080        identifier: Identifier::new("", 0..0),
1081        prefix: Default::default(),
1082    };
1083    let mut if_not_exists = None;
1084
1085    parser.recovered("'('", &|t| t == &Token::LParen, |parser| {
1086        if let Some(if_) = parser.skip_keyword(Keyword::IF) {
1087            if_not_exists = Some(
1088                if_.start
1089                    ..parser
1090                        .consume_keywords(&[Keyword::NOT, Keyword::EXISTS])?
1091                        .end,
1092            );
1093        }
1094        identifier = parse_qualified_name(parser)?;
1095        Ok(())
1096    })?;
1097
1098    parser.consume_token(Token::LParen)?;
1099
1100    let mut create_definitions = Vec::new();
1101    if !matches!(parser.token, Token::RParen) {
1102        loop {
1103            parser.recovered(
1104                "')' or ','",
1105                &|t| matches!(t, Token::RParen | Token::Comma),
1106                |parser| {
1107                    create_definitions.push(parse_create_definition(parser)?);
1108                    Ok(())
1109                },
1110            )?;
1111            if matches!(parser.token, Token::RParen) {
1112                break;
1113            }
1114            parser.consume_token(Token::Comma)?;
1115        }
1116    }
1117    parser.consume_token(Token::RParen)?;
1118
1119    let mut options = Vec::new();
1120    let delimiter = parser.delimiter.clone();
1121    parser.recovered(
1122        delimiter.name(),
1123        &|t| t == &Token::Eof || t == &delimiter,
1124        |parser| {
1125            loop {
1126                let identifier = parser.span.clone();
1127                match &parser.token {
1128                    Token::Ident(_, Keyword::ENGINE) => {
1129                        parser.consume_keyword(Keyword::ENGINE)?;
1130                        parser.skip_token(Token::Eq);
1131                        options.push(TableOption::Engine {
1132                            identifier,
1133                            value: parser.consume_plain_identifier()?,
1134                        });
1135                    }
1136                    Token::Ident(_, Keyword::DEFAULT) => {
1137                        parser.consume_keyword(Keyword::DEFAULT)?;
1138                        match &parser.token {
1139                            Token::Ident(_, Keyword::CHARSET) => {
1140                                parser.consume_keyword(Keyword::CHARSET)?;
1141                                parser.skip_token(Token::Eq);
1142                                options.push(TableOption::DefaultCharSet {
1143                                    identifier,
1144                                    value: parser.consume_plain_identifier()?,
1145                                });
1146                            }
1147                            Token::Ident(_, Keyword::COLLATE) => {
1148                                parser.consume_keyword(Keyword::COLLATE)?;
1149                                parser.skip_token(Token::Eq);
1150                                options.push(TableOption::DefaultCollate {
1151                                    identifier,
1152                                    value: parser.consume_plain_identifier()?,
1153                                });
1154                            }
1155                            _ => parser.expected_failure("'CHARSET' or 'COLLATE'")?,
1156                        }
1157                    }
1158                    Token::Ident(_, Keyword::CHARSET) => {
1159                        parser.consume_keyword(Keyword::CHARSET)?;
1160                        parser.skip_token(Token::Eq);
1161                        options.push(TableOption::CharSet {
1162                            identifier,
1163                            value: parser.consume_plain_identifier()?,
1164                        });
1165                    }
1166                    Token::Ident(_, Keyword::COLLATE) => {
1167                        parser.consume_keyword(Keyword::COLLATE)?;
1168                        parser.skip_token(Token::Eq);
1169                        options.push(TableOption::Collate {
1170                            identifier,
1171                            value: parser.consume_plain_identifier()?,
1172                        });
1173                    }
1174                    Token::Ident(_, Keyword::ROW_FORMAT) => {
1175                        parser.consume_keyword(Keyword::ROW_FORMAT)?;
1176                        parser.skip_token(Token::Eq);
1177                        options.push(TableOption::RowFormat {
1178                            identifier,
1179                            value: parser.consume_plain_identifier()?,
1180                        });
1181                        //TODO validate raw format is in the keyword set
1182                    }
1183                    Token::Ident(_, Keyword::COMMENT) => {
1184                        parser.consume_keyword(Keyword::COMMENT)?;
1185                        parser.skip_token(Token::Eq);
1186                        options.push(TableOption::Comment {
1187                            identifier,
1188                            value: parser.consume_string()?,
1189                        });
1190                    }
1191                    Token::Ident(_, Keyword::STRICT) => {
1192                        parser.consume_keyword(Keyword::STRICT)?;
1193                        options.push(TableOption::Strict { identifier });
1194                    }
1195                    t if t == &parser.delimiter => break,
1196                    Token::Eof => break,
1197                    _ => {
1198                        parser.expected_failure("table option or delimiter")?;
1199                    }
1200                }
1201            }
1202            Ok(())
1203        },
1204    )?;
1205
1206    Ok(Statement::CreateTable(CreateTable {
1207        create_span,
1208        create_options,
1209        table_span,
1210        identifier,
1211        if_not_exists,
1212        options,
1213        create_definitions,
1214    }))
1215}
1216
1217pub(crate) fn parse_create<'a>(parser: &mut Parser<'a, '_>) -> Result<Statement<'a>, ParseError> {
1218    let create_span = parser.span.clone();
1219    parser.consume_keyword(Keyword::CREATE)?;
1220
1221    let mut create_options = Vec::new();
1222    const CREATABLE: &str = "'TABLE' | 'VIEW' | 'TRIGGER' | 'FUNCTION' | 'INDEX' | 'TYPE'";
1223
1224    parser.recovered(
1225        CREATABLE,
1226        &|t| {
1227            matches!(
1228                t,
1229                Token::Ident(
1230                    _,
1231                    Keyword::TABLE
1232                        | Keyword::VIEW
1233                        | Keyword::TRIGGER
1234                        | Keyword::FUNCTION
1235                        | Keyword::INDEX
1236                        | Keyword::TYPE
1237                )
1238            )
1239        },
1240        |parser| {
1241            loop {
1242                let v = match &parser.token {
1243                    Token::Ident(_, Keyword::OR) => CreateOption::OrReplace(
1244                        parser.consume_keywords(&[Keyword::OR, Keyword::REPLACE])?,
1245                    ),
1246                    Token::Ident(_, Keyword::TEMPORARY) => {
1247                        CreateOption::Temporary(parser.consume_keyword(Keyword::TEMPORARY)?)
1248                    }
1249                    Token::Ident(_, Keyword::UNIQUE) => {
1250                        CreateOption::Unique(parser.consume_keyword(Keyword::UNIQUE)?)
1251                    }
1252                    Token::Ident(_, Keyword::ALGORITHM) => {
1253                        let algorithm_span = parser.consume_keyword(Keyword::ALGORITHM)?;
1254                        parser.consume_token(Token::Eq)?;
1255                        let algorithm = match &parser.token {
1256                            Token::Ident(_, Keyword::UNDEFINED) => CreateAlgorithm::Undefined(
1257                                parser.consume_keyword(Keyword::UNDEFINED)?,
1258                            ),
1259                            Token::Ident(_, Keyword::MERGE) => {
1260                                CreateAlgorithm::Merge(parser.consume_keyword(Keyword::MERGE)?)
1261                            }
1262                            Token::Ident(_, Keyword::TEMPTABLE) => CreateAlgorithm::TempTable(
1263                                parser.consume_keyword(Keyword::TEMPTABLE)?,
1264                            ),
1265                            _ => parser.expected_failure("'UNDEFINED', 'MERGE' or 'TEMPTABLE'")?,
1266                        };
1267                        CreateOption::Algorithm(algorithm_span, algorithm)
1268                    }
1269                    Token::Ident(_, Keyword::DEFINER) => {
1270                        let definer_span = parser.consume_keyword(Keyword::DEFINER)?;
1271                        parser.consume_token(Token::Eq)?;
1272                        // TODO user | CURRENT_USER | role | CURRENT_ROLE
1273                        let user = parser.consume_plain_identifier()?;
1274                        parser.consume_token(Token::At)?;
1275                        let host = parser.consume_plain_identifier()?;
1276                        CreateOption::Definer {
1277                            definer_span,
1278                            user,
1279                            host,
1280                        }
1281                    }
1282                    Token::Ident(_, Keyword::SQL) => {
1283                        let sql_security =
1284                            parser.consume_keywords(&[Keyword::SQL, Keyword::SECURITY])?;
1285                        match &parser.token {
1286                            Token::Ident(_, Keyword::DEFINER) => CreateOption::SqlSecurityDefiner(
1287                                sql_security,
1288                                parser.consume_keyword(Keyword::DEFINER)?,
1289                            ),
1290                            Token::Ident(_, Keyword::USER) => CreateOption::SqlSecurityUser(
1291                                sql_security,
1292                                parser.consume_keyword(Keyword::USER)?,
1293                            ),
1294                            _ => parser.expected_failure("'DEFINER', 'USER'")?,
1295                        }
1296                    }
1297                    _ => break,
1298                };
1299                create_options.push(v);
1300            }
1301            Ok(())
1302        },
1303    )?;
1304
1305    match &parser.token {
1306        Token::Ident(_, Keyword::INDEX) => parse_create_index(parser, create_span, create_options),
1307        Token::Ident(_, Keyword::TABLE) => parse_create_table(parser, create_span, create_options),
1308        Token::Ident(_, Keyword::VIEW) => parse_create_view(parser, create_span, create_options),
1309        Token::Ident(_, Keyword::FUNCTION) => {
1310            parse_create_function(parser, create_span, create_options)
1311        }
1312        Token::Ident(_, Keyword::TRIGGER) => {
1313            parse_create_trigger(parser, create_span, create_options)
1314        }
1315        Token::Ident(_, Keyword::TYPE) => parse_create_type(parser, create_span, create_options),
1316        _ => parser.expected_failure(CREATABLE),
1317    }
1318}