sqlparser_mysql/base/
index_option.rs

1use nom::branch::alt;
2use nom::bytes::complete::{tag, tag_no_case, take_until};
3use nom::character::complete;
4use nom::character::complete::{multispace0, multispace1};
5use nom::combinator::{map, opt};
6use nom::multi::many1;
7use nom::sequence::{delimited, preceded, tuple};
8use nom::IResult;
9use std::fmt::{Display, Formatter};
10
11use base::error::ParseSQLError;
12use base::index_type::IndexType;
13use base::visible_type::VisibleType;
14use base::CommonParser;
15
16/// index_option: {
17///     KEY_BLOCK_SIZE [=] value
18///   | index_type
19///   | WITH PARSER parser_name
20///   | COMMENT 'string'
21///   | {VISIBLE | INVISIBLE}
22///   | ENGINE_ATTRIBUTE [=] 'string' >>> create table only
23///   | SECONDARY_ENGINE_ATTRIBUTE [=] 'string' >>> create table only
24/// }
25#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
26pub enum IndexOption {
27    KeyBlockSize(u64),
28    IndexType(IndexType),
29    WithParser(String),
30    Comment(String),
31    VisibleType(VisibleType),
32    EngineAttribute(String),          // create table only
33    SecondaryEngineAttribute(String), // create table only
34}
35
36impl Display for IndexOption {
37    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
38        match *self {
39            IndexOption::KeyBlockSize(ref val) => write!(f, "KEY_BLOCK_SIZE {}", val),
40            IndexOption::IndexType(ref val) => write!(f, "{}", val),
41            IndexOption::WithParser(ref val) => write!(f, "WITH PARSER {}", val),
42            IndexOption::Comment(ref val) => write!(f, "COMMENT '{}'", val),
43            IndexOption::VisibleType(ref val) => match *val {
44                VisibleType::Visible => write!(f, "VISIBLE"),
45                VisibleType::Invisible => write!(f, "INVISIBLE"),
46            },
47            IndexOption::EngineAttribute(ref val) => write!(f, "ENGINE_ATTRIBUTE {}", val),
48            IndexOption::SecondaryEngineAttribute(ref val) => {
49                write!(f, "SECONDARY_ENGINE_ATTRIBUTE {}", val)
50            }
51        }
52    }
53}
54
55impl IndexOption {
56    pub fn parse(i: &str) -> IResult<&str, IndexOption, ParseSQLError<&str>> {
57        alt((
58            map(Self::key_block_size, IndexOption::KeyBlockSize),
59            map(IndexType::parse, IndexOption::IndexType),
60            map(Self::with_parser, IndexOption::WithParser),
61            map(CommonParser::parse_comment, IndexOption::Comment),
62            map(VisibleType::parse, IndexOption::VisibleType),
63            map(Self::engine_attribute, IndexOption::EngineAttribute),
64            map(
65                Self::secondary_engine_attribute,
66                IndexOption::SecondaryEngineAttribute,
67            ),
68        ))(i)
69    }
70
71    pub fn format_list(list: &[IndexOption]) -> String {
72        list.iter()
73            .map(|x| x.to_string())
74            .collect::<Vec<String>>()
75            .join(" ")
76    }
77
78    /// `[index_option]`
79    /// index_option: {
80    ///     KEY_BLOCK_SIZE [=] value
81    ///   | index_type
82    ///   | WITH PARSER parser_name
83    ///   | COMMENT 'string'
84    ///   | {VISIBLE | INVISIBLE}
85    ///   |ENGINE_ATTRIBUTE [=] 'string'
86    ///   |SECONDARY_ENGINE_ATTRIBUTE [=] 'string'
87    /// }
88    pub fn opt_index_option(
89        i: &str,
90    ) -> IResult<&str, Option<Vec<IndexOption>>, ParseSQLError<&str>> {
91        opt(many1(map(preceded(multispace0, IndexOption::parse), |x| x)))(i)
92    }
93
94    /// KEY_BLOCK_SIZE [=] value
95    fn key_block_size(i: &str) -> IResult<&str, u64, ParseSQLError<&str>> {
96        map(
97            tuple((
98                multispace0,
99                tag_no_case("KEY_BLOCK_SIZE"),
100                multispace0,
101                opt(tag("=")),
102                multispace0,
103                complete::u64,
104            )),
105            |(_, _, _, _, _, size)| size,
106        )(i)
107    }
108
109    /// WITH PARSER parser_name
110    fn with_parser(i: &str) -> IResult<&str, String, ParseSQLError<&str>> {
111        map(
112            tuple((
113                multispace0,
114                tag_no_case("WITH"),
115                multispace1,
116                tag_no_case("PARSER"),
117                multispace1,
118                CommonParser::sql_identifier,
119                multispace0,
120            )),
121            |(_, _, _, _, _, parser_name, _)| String::from(parser_name),
122        )(i)
123    }
124
125    /// ENGINE_ATTRIBUTE [=] value
126    fn engine_attribute(i: &str) -> IResult<&str, String, ParseSQLError<&str>> {
127        map(
128            tuple((
129                tag_no_case("ENGINE_ATTRIBUTE"),
130                multispace0,
131                opt(tag("=")),
132                map(delimited(tag("'"), take_until("'"), tag("'")), |x| {
133                    String::from(x)
134                }),
135                multispace0,
136            )),
137            |(_, _, _, engine, _)| engine,
138        )(i)
139    }
140
141    /// SECONDARY_ENGINE_ATTRIBUTE [=] value
142    fn secondary_engine_attribute(i: &str) -> IResult<&str, String, ParseSQLError<&str>> {
143        CommonParser::parse_string_value_with_key(i, "SECONDARY_ENGINE_ATTRIBUTE".to_string())
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use base::index_option::IndexOption;
150    use base::visible_type::VisibleType;
151    use base::visible_type::VisibleType::Invisible;
152
153    #[test]
154    fn parse_index_option_item() {
155        let parts = [
156            "KEY_BLOCK_SIZE=1024",
157            "COMMENT 'This is an index comment'",
158            "INVISIBLE",
159            "WITH PARSER ngram",
160        ];
161        let exps = [
162            IndexOption::KeyBlockSize(1024),
163            IndexOption::Comment("This is an index comment".to_string()),
164            IndexOption::VisibleType(VisibleType::Invisible),
165            IndexOption::WithParser("ngram".to_string()),
166        ];
167        for i in 0..parts.len() {
168            let res = IndexOption::parse(parts[i]);
169            assert!(res.is_ok());
170            assert_eq!(res.unwrap().1, exps[i]);
171        }
172    }
173
174    #[test]
175    fn parse_index_option() {
176        let parts = ["INVISIBLE KEY_BLOCK_SIZE 333"];
177        let exps = [vec![
178            IndexOption::VisibleType(Invisible),
179            IndexOption::KeyBlockSize(333),
180        ]];
181        for i in 0..parts.len() {
182            let res = IndexOption::opt_index_option(parts[i]);
183            assert!(res.is_ok());
184            assert_eq!(res.unwrap().1.unwrap(), exps[i]);
185        }
186    }
187}