Skip to main content

qusql_parse/
create_view.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.
12use crate::{
13    QualifiedName, Span, Spanned, Statement,
14    create_option::CreateOption,
15    keywords::Keyword,
16    parser::{ParseError, Parser},
17    qualified_name::parse_qualified_name_unreserved,
18    statement::parse_compound_query,
19};
20use alloc::vec::Vec;
21
22/// Represent a create view statement
23/// ```
24/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, CreateView, Statement, Issues};
25/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
26/// #
27/// let sql = "CREATE ALGORITHM=UNDEFINED DEFINER=`phpmyadmin`@`localhost` SQL SECURITY DEFINER
28///    VIEW `v1`
29///    AS SELECT
30///         `t1`.`id` AS `id`,
31///         `t1`.`c1` AS `c1`,
32///         (SELECT `t2`.`c2` FROM `t2` WHERE `t2`.`id` = `t1`.`c3`) AS `c2`
33///         FROM `t1` WHERE `t1`.`deleted` IS NULL;";
34/// let mut issues = Issues::new(sql);
35/// let mut stmts = parse_statements(sql, &mut issues, &options);
36///
37/// # assert!(issues.is_ok());
38/// let create: CreateView = match stmts.pop() {
39///     Some(Statement::CreateView(c)) => * c,
40///     _ => panic!("We should get an create view statement")
41/// };
42///
43/// assert!(create.name.identifier.as_str() == "v1");
44/// println!("{:#?}", create.select)
45/// ```
46
47#[derive(Clone, Debug)]
48pub struct CreateView<'a> {
49    /// Span of "CREATE"
50    pub create_span: Span,
51    /// Options after "CREATE"
52    pub create_options: Vec<CreateOption<'a>>,
53    /// Span of "VIEW"
54    pub view_span: Span,
55    /// Span of "IF NOT EXISTS" if specified
56    pub if_not_exists: Option<Span>,
57    /// Name of the created view
58    pub name: QualifiedName<'a>,
59    /// Span of "AS"
60    pub as_span: Span,
61    /// The select statement following "AS"
62    pub select: Statement<'a>,
63}
64
65impl<'a> Spanned for CreateView<'a> {
66    fn span(&self) -> Span {
67        self.create_span
68            .join_span(&self.create_options)
69            .join_span(&self.view_span)
70            .join_span(&self.if_not_exists)
71            .join_span(&self.name)
72            .join_span(&self.as_span)
73            .join_span(&self.select)
74    }
75}
76
77pub(crate) fn parse_create_view<'a>(
78    parser: &mut Parser<'a, '_>,
79    create_span: Span,
80    create_options: Vec<CreateOption<'a>>,
81) -> Result<CreateView<'a>, ParseError> {
82    let view_span = parser.consume_keyword(Keyword::VIEW)?;
83
84    let if_not_exists = if let Some(if_) = parser.skip_keyword(Keyword::IF) {
85        Some(
86            parser
87                .consume_keywords(&[Keyword::NOT, Keyword::EXISTS])?
88                .join_span(&if_),
89        )
90    } else {
91        None
92    };
93
94    let name = parse_qualified_name_unreserved(parser)?;
95    // TODO (column_list)
96
97    let as_span = parser.consume_keyword(Keyword::AS)?;
98
99    let select = parse_compound_query(parser)?;
100
101    // TODO [WITH [CASCADED | LOCAL] CHECK OPTION]
102
103    Ok(CreateView {
104        create_span,
105        create_options,
106        view_span,
107        if_not_exists,
108        name,
109        as_span,
110        select,
111    })
112}