sqlparser_mysql/base/
table_option.rs

1use nom::branch::alt;
2use nom::bytes::complete::{tag, tag_no_case, take_until};
3use nom::character::complete::{digit1, multispace0, multispace1};
4use nom::combinator::{map, opt, value};
5use nom::sequence::{delimited, tuple};
6use nom::{IResult, Parser};
7use std::fmt::{write, Display, Formatter};
8
9use base::column::Column;
10use base::error::ParseSQLError;
11use base::{
12    CommonParser, CompressionType, DefaultOrZeroOrOne, InsertMethodType, RowFormatType,
13    TablespaceType,
14};
15
16/// table_option: `{
17///     AUTOEXTEND_SIZE [=] value
18///   | AUTO_INCREMENT [=] value
19///   | AVG_ROW_LENGTH [=] value
20///   | [DEFAULT] CHARACTER SET [=] charset_name
21///   | CHECKSUM [=] {0 | 1}
22///   | [DEFAULT] COLLATE [=] collation_name
23///   | COMMENT [=] 'string'
24///   | COMPRESSION [=] {'ZLIB' | 'LZ4' | 'NONE'}
25///   | CONNECTION [=] 'connect_string'
26///   | {DATA | INDEX} DIRECTORY [=] 'absolute path to directory'
27///   | DELAY_KEY_WRITE [=] {0 | 1}
28///   | ENCRYPTION [=] {'Y' | 'N'}
29///   | ENGINE [=] engine_name
30///   | ENGINE_ATTRIBUTE [=] 'string'
31///   | INSERT_METHOD [=] { NO | FIRST | LAST }
32///   | KEY_BLOCK_SIZE [=] value
33///   | MAX_ROWS [=] value
34///   | MIN_ROWS [=] value
35///   | PACK_KEYS [=] {0 | 1 | DEFAULT}
36///   | PASSWORD [=] 'string'
37///   | ROW_FORMAT [=] {DEFAULT | DYNAMIC | FIXED | COMPRESSED | REDUNDANT | COMPACT}
38///   | SECONDARY_ENGINE_ATTRIBUTE [=] 'string'
39///   | STATS_AUTO_RECALC [=] {DEFAULT | 0 | 1}
40///   | STATS_PERSISTENT [=] {DEFAULT | 0 | 1}
41///   | STATS_SAMPLE_PAGES [=] value
42///   | TABLESPACE tablespace_name [STORAGE {DISK | MEMORY}]
43///   | UNION [=] (tbl_name[,tbl_name]...)
44///  }`
45#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
46pub enum TableOption {
47    AutoextendSize(u64),
48    AutoIncrement(u64),
49    AvgRowLength(u64),
50    DefaultCharacterSet(String),
51    DefaultCharset(String),
52    Checksum(u8),
53    DefaultCollate(String),
54    Comment(String),
55    Compression(CompressionType),
56    Connection(String),
57    DataDirectory(String),
58    IndexDirectory(String),
59    DelayKeyWrite(u8),
60    Encryption(bool),
61    Engine(String),
62    EngineAttribute(String),
63    InsertMethod(InsertMethodType),
64    KeyBlockSize(u64),
65    MaxRows(u64),
66    MinRows(u64),
67    PackKeys(DefaultOrZeroOrOne),
68    Password(String),
69    RowFormat(RowFormatType),
70    StartTransaction, // create table only
71    SecondaryEngineAttribute(String),
72    StatsAutoRecalc(DefaultOrZeroOrOne),
73    StatsPersistent(DefaultOrZeroOrOne),
74    StatsSamplePages(u64),
75    Tablespace(String, Option<TablespaceType>),
76    Union(Vec<String>),
77}
78
79impl Display for TableOption {
80    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
81        match *self {
82            TableOption::AutoextendSize(ref val) => write!(f, "AUTOEXTEND_SIZE {}", val),
83            TableOption::AutoIncrement(ref val) => write!(f, "AUTO_INCREMENT {}", val),
84            TableOption::AvgRowLength(ref val) => write!(f, "AVG_ROW_LENGTH {}", val),
85            TableOption::DefaultCharacterSet(ref val) => write!(f, "CHARACTER SET {}", val),
86            TableOption::DefaultCharset(ref val) => write!(f, "CHARSET {}", val),
87            TableOption::Checksum(ref val) => write!(f, "CHECKSUM {}", val),
88            TableOption::DefaultCollate(ref val) => write!(f, "COLLATE {}", val),
89            TableOption::Comment(ref val) => write!(f, "COMMENT '{}'", val),
90            TableOption::Compression(ref val) => write!(f, "COMPRESSION {}", val),
91            TableOption::Connection(ref val) => write!(f, "CONNECTION {}", val),
92            TableOption::DataDirectory(ref val) => write!(f, "DATA DIRECTORY '{}'", val),
93            TableOption::IndexDirectory(ref val) => write!(f, "INDEX DIRECTORY '{}'", val),
94            TableOption::DelayKeyWrite(ref val) => write!(f, "DELAY_KEY_WRITE {}", val),
95            TableOption::Encryption(ref val) => write!(f, "ENCRYPTION '{}'", val),
96            TableOption::Engine(ref val) => write!(f, "ENGINE {}", val),
97            TableOption::EngineAttribute(ref val) => write!(f, "ENGINE_ATTRIBUTE {}", val),
98            TableOption::InsertMethod(ref val) => write!(f, "INSERT_METHOD {}", val),
99            TableOption::KeyBlockSize(ref val) => write!(f, "KEY_BLOCK_SIZE {}", val),
100            TableOption::MaxRows(ref val) => write!(f, "MAX_ROWS {}", val),
101            TableOption::MinRows(ref val) => write!(f, "MIN_ROWS {}", val),
102            TableOption::PackKeys(ref val) => write!(f, "PACK_KEYS {}", val),
103            TableOption::Password(ref val) => write!(f, "PASSWORD '{}'", val),
104            TableOption::RowFormat(ref val) => write!(f, "ROW_FORMAT {}", val),
105            TableOption::StartTransaction => write!(f, "START TRANSACTION"),
106            TableOption::SecondaryEngineAttribute(ref val) => {
107                write!(f, "SECONDARY_ENGINE_ATTRIBUTE '{}'", val)
108            }
109            TableOption::StatsAutoRecalc(ref val) => write!(f, "STATS_AUTO_RECALC {}", val),
110            TableOption::StatsPersistent(ref val) => write!(f, "STATS_PERSISTENT {}", val),
111            TableOption::StatsSamplePages(ref val) => write!(f, "STATS_SAMPLE_PAGES {}", val),
112            TableOption::Tablespace(ref tablespace_name, ref tbl_space_type) => {
113                write!(f, "TABLESPACE {}", tablespace_name);
114                if let Some(tbl_space_type) = tbl_space_type {
115                    write!(f, " {}", tbl_space_type);
116                }
117                Ok(())
118            }
119            TableOption::Union(ref tbl_names) => {
120                let tbl_names = tbl_names.join(",");
121                write!(f, "UNION ({})", tbl_names)
122            }
123        }
124    }
125}
126
127impl TableOption {
128    pub fn parse(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
129        alt((Self::table_option_part_1, Self::table_option_part_2))(i)
130    }
131
132    pub fn format_list(list: &[TableOption]) -> String {
133        list.iter()
134            .map(|x| x.to_string())
135            .collect::<Vec<String>>()
136            .join(" ")
137    }
138
139    fn table_option_part_1(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
140        alt((
141            Self::autoextend_size,
142            Self::auto_increment,
143            Self::avg_row_length,
144            Self::default_character_set,
145            Self::default_charset,
146            Self::checksum,
147            Self::default_collate,
148            Self::comment,
149            Self::compression,
150            Self::connection,
151            Self::data_directory,
152            Self::index_directory,
153            Self::delay_key_write,
154            Self::encryption,
155            Self::engine,
156            Self::engine_attribute,
157        ))(i)
158    }
159
160    fn table_option_part_2(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
161        alt((
162            Self::insert_method,
163            Self::key_block_size,
164            Self::max_rows,
165            Self::min_rows,
166            Self::pack_keys,
167            Self::password,
168            Self::row_format,
169            Self::secondary_engine_attribute,
170            Self::stats_auto_recalc,
171            Self::stats_persistent,
172            Self::stats_sample_pages,
173            Self::tablespace,
174            Self::union,
175        ))(i)
176    }
177
178    /// parse `AUTOEXTEND_SIZE [=] value`
179    fn autoextend_size(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
180        map(
181            |x| CommonParser::parse_string_value_with_key(x, "AUTOEXTEND_SIZE".to_string()),
182            |value| TableOption::AutoextendSize(value.parse::<u64>().unwrap()),
183        )(i)
184    }
185
186    /// parse `AUTO_INCREMENT [=] value`
187    fn auto_increment(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
188        map(
189            |x| CommonParser::parse_digit_value_with_key(x, "AUTO_INCREMENT".to_string()),
190            |value| TableOption::AutoIncrement(value.parse::<u64>().unwrap()),
191        )(i)
192    }
193
194    /// parse `AVG_ROW_LENGTH [=] value`
195    fn avg_row_length(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
196        map(
197            |x| CommonParser::parse_string_value_with_key(x, "AVG_ROW_LENGTH".to_string()),
198            |value| TableOption::AvgRowLength(value.parse::<u64>().unwrap()),
199        )(i)
200    }
201
202    /// parse `[DEFAULT] CHARACTER SET [=] charset_name`
203    fn default_character_set(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
204        alt((
205            map(
206                tuple((
207                    opt(tag_no_case("DEFAULT ")),
208                    multispace0,
209                    tuple((
210                        tag_no_case("CHARACTER"),
211                        multispace1,
212                        tag_no_case("SET"),
213                        multispace1,
214                    )),
215                    map(CommonParser::sql_identifier, String::from),
216                )),
217                |(_, _, _, charset_name)| TableOption::DefaultCharacterSet(charset_name),
218            ),
219            map(
220                tuple((
221                    opt(tag_no_case("DEFAULT ")),
222                    multispace0,
223                    tuple((
224                        tag_no_case("CHARACTER"),
225                        multispace1,
226                        tag_no_case("SET"),
227                        multispace0,
228                        tag("="),
229                        multispace0,
230                    )),
231                    map(CommonParser::sql_identifier, String::from),
232                )),
233                |(_, _, _, charset_name)| TableOption::DefaultCharacterSet(charset_name),
234            ),
235        ))(i)
236    }
237
238    /// parse `[DEFAULT] CHARSET [=] charset_name`
239    fn default_charset(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
240        map(
241            tuple((opt(tag_no_case("DEFAULT ")), multispace0, |x| {
242                CommonParser::parse_string_value_with_key(x, "CHARSET".to_string())
243            })),
244            |(_, _, charset_name)| TableOption::DefaultCharset(charset_name),
245        )(i)
246    }
247
248    /// parse `CHECKSUM [=] {0 | 1}`
249    fn checksum(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
250        alt((
251            map(
252                tuple((
253                    tag_no_case("CHECKSUM "),
254                    multispace1,
255                    alt((map(tag("0"), |_| 0), map(tag("1"), |_| 1))),
256                )),
257                |(_, _, checksum)| TableOption::Checksum(checksum),
258            ),
259            map(
260                tuple((
261                    tag_no_case("CHECKSUM "),
262                    multispace0,
263                    tag("="),
264                    multispace0,
265                    alt((map(tag("0"), |_| 0), map(tag("1"), |_| 1))),
266                )),
267                |(_, _, _, _, checksum)| TableOption::Checksum(checksum),
268            ),
269        ))(i)
270    }
271
272    /// parse `[DEFAULT] COLLATE [=] collation_name`
273    fn default_collate(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
274        map(
275            tuple((opt(tag_no_case("DEFAULT ")), multispace0, |x| {
276                CommonParser::parse_string_value_with_key(x, "COLLATE".to_string())
277            })),
278            |(_, _, collation_name)| TableOption::DefaultCollate(collation_name),
279        )(i)
280    }
281
282    /// parse COMMENT [=] 'string'`
283    fn comment(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
284        map(
285            |x| CommonParser::parse_quoted_string_value_with_key(x, "COMMENT".to_string()),
286            TableOption::Comment,
287        )(i)
288    }
289
290    /// parse `COMPRESSION [=] {'ZLIB' | 'LZ4' | 'NONE'}`
291    fn compression(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
292        map(CompressionType::parse, TableOption::Compression)(i)
293    }
294
295    /// parse `CONNECTION [=] 'connect_string'`
296    fn connection(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
297        map(
298            |x| CommonParser::parse_string_value_with_key(x, "CONNECTION".to_string()),
299            TableOption::Connection,
300        )(i)
301    }
302
303    /// parse `{DATA | INDEX} DIRECTORY [=] 'absolute path to directory'`
304    fn data_directory(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
305        map(
306            tuple((tag_no_case("DATA"), multispace1, |x| {
307                CommonParser::parse_quoted_string_value_with_key(x, "DIRECTORY".to_string())
308            })),
309            |(_, _, path)| TableOption::DataDirectory(path),
310        )(i)
311    }
312
313    /// parse `{DATA | INDEX} DIRECTORY [=] 'absolute path to directory'`
314    fn index_directory(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
315        map(
316            tuple((tag_no_case("INDEX"), multispace1, |x| {
317                CommonParser::parse_quoted_string_value_with_key(x, "DIRECTORY".to_string())
318            })),
319            |(_, _, path)| TableOption::DataDirectory(path),
320        )(i)
321    }
322
323    /// parse `DELAY_KEY_WRITE [=] {0 | 1}`
324    fn delay_key_write(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
325        alt((
326            map(
327                tuple((
328                    tag_no_case("DELAY_KEY_RITE"),
329                    multispace1,
330                    alt((map(tag("0"), |_| 0), map(tag("1"), |_| 1))),
331                )),
332                |(_, _, delay_key_rite)| TableOption::DelayKeyWrite(delay_key_rite),
333            ),
334            map(
335                tuple((
336                    tag_no_case("DELAY_KEY_RITE"),
337                    multispace0,
338                    tag("="),
339                    multispace0,
340                    alt((map(tag("0"), |_| 0), map(tag("1"), |_| 1))),
341                )),
342                |(_, _, _, _, delay_key_rite)| TableOption::DelayKeyWrite(delay_key_rite),
343            ),
344        ))(i)
345    }
346
347    /// parse `ENCRYPTION [=] {'Y' | 'N'}`
348    fn encryption(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
349        alt((
350            map(
351                tuple((
352                    tag_no_case("ENCRYPTION"),
353                    multispace1,
354                    alt((map(tag("'Y'"), |_| true), map(tag("'N'"), |_| false))),
355                )),
356                |(_, _, encryption)| TableOption::Encryption(encryption),
357            ),
358            map(
359                tuple((
360                    tag_no_case("ENCRYPTION"),
361                    multispace0,
362                    tag("="),
363                    multispace0,
364                    alt((map(tag("'Y'"), |_| true), map(tag("'N'"), |_| false))),
365                )),
366                |(_, _, _, _, encryption)| TableOption::Encryption(encryption),
367            ),
368        ))(i)
369    }
370
371    /// parse `ENGINE [=] engine_name`
372    fn engine(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
373        map(
374            |x| CommonParser::parse_string_value_with_key(x, "ENGINE".to_string()),
375            TableOption::Engine,
376        )(i)
377    }
378
379    /// parse `ENGINE_ATTRIBUTE [=] 'string'`
380    fn engine_attribute(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
381        map(
382            |x| CommonParser::parse_quoted_string_value_with_key(x, "ENGINE_ATTRIBUTE".to_string()),
383            TableOption::EngineAttribute,
384        )(i)
385    }
386
387    /// parse `INSERT_METHOD [=] { NO | FIRST | LAST }`
388    fn insert_method(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
389        map(InsertMethodType::parse, TableOption::InsertMethod)(i)
390    }
391
392    /// parse `KEY_BLOCK_SIZE [=] value`
393    fn key_block_size(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
394        map(
395            |x| CommonParser::parse_string_value_with_key(x, "KEY_BLOCK_SIZE".to_string()),
396            |value| TableOption::KeyBlockSize(value.parse::<u64>().unwrap()),
397        )(i)
398    }
399
400    /// parse `MAX_ROWS [=] value`
401    fn max_rows(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
402        map(
403            |x| CommonParser::parse_string_value_with_key(x, "MAX_ROWS".to_string()),
404            |value| TableOption::MaxRows(value.parse::<u64>().unwrap()),
405        )(i)
406    }
407
408    /// parse `MIN_ROWS [=] value`
409    fn min_rows(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
410        map(
411            |x| CommonParser::parse_string_value_with_key(x, "MIN_ROWS".to_string()),
412            |value| TableOption::MinRows(value.parse::<u64>().unwrap()),
413        )(i)
414    }
415
416    /// parse `PACK_KEYS [=] {0 | 1 | DEFAULT}`
417    fn pack_keys(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
418        map(
419            |x| CommonParser::parse_default_value_with_key(x, "PACK_KEYS".to_string()),
420            TableOption::PackKeys,
421        )(i)
422    }
423
424    /// parse `PASSWORD [=] 'string'`
425    fn password(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
426        map(
427            |x| CommonParser::parse_quoted_string_value_with_key(x, "PASSWORD".to_string()),
428            TableOption::Password,
429        )(i)
430    }
431
432    /// parse `ROW_FORMAT [=] {DEFAULT | DYNAMIC | FIXED | COMPRESSED | REDUNDANT | COMPACT}`
433    fn row_format(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
434        map(RowFormatType::parse, TableOption::RowFormat)(i)
435    }
436
437    /// parse `START TRANSACTION`
438    /// create table only
439    fn start_transaction(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
440        map(
441            tuple((
442                tag_no_case("START"),
443                multispace1,
444                tag_no_case("TRANSACTION"),
445            )),
446            |_| TableOption::StartTransaction,
447        )(i)
448    }
449
450    /// parse `SECONDARY_ENGINE_ATTRIBUTE [=] 'string'`
451    fn secondary_engine_attribute(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
452        map(
453            |x| {
454                CommonParser::parse_quoted_string_value_with_key(
455                    x,
456                    "SECONDARY_ENGINE_ATTRIBUTE".to_string(),
457                )
458            },
459            TableOption::SecondaryEngineAttribute,
460        )(i)
461    }
462
463    /// parse `STATS_AUTO_RECALC [=] {DEFAULT | 0 | 1}`
464    fn stats_auto_recalc(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
465        map(
466            |x| CommonParser::parse_default_value_with_key(x, "STATS_AUTO_RECALC".to_string()),
467            TableOption::StatsAutoRecalc,
468        )(i)
469    }
470
471    /// parse `STATS_PERSISTENT [=] {DEFAULT | 0 | 1}`
472    fn stats_persistent(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
473        map(
474            |x| CommonParser::parse_default_value_with_key(x, "STATS_AUTO_RECALC".to_string()),
475            TableOption::StatsAutoRecalc,
476        )(i)
477    }
478
479    /// parse `STATS_SAMPLE_PAGES [=] value`
480    fn stats_sample_pages(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
481        map(
482            |x| CommonParser::parse_string_value_with_key(x, "STATS_SAMPLE_PAGES".to_string()),
483            |value| TableOption::StatsSamplePages(value.parse::<u64>().unwrap()),
484        )(i)
485    }
486
487    /// parse `TABLESPACE tablespace_name [STORAGE {DISK | MEMORY}]`
488    fn tablespace(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
489        map(
490            tuple((
491                tag_no_case("TABLESPACE"),
492                multispace1,
493                map(CommonParser::sql_identifier, String::from), // tablespace_name
494                multispace0,
495                opt(TablespaceType::parse),
496            )),
497            |(_, _, tablespace_name, _, storage)| TableOption::Tablespace(tablespace_name, storage),
498        )(i)
499    }
500
501    /// parse `UNION [=] (tbl_name[,tbl_name]...)`
502    fn union(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
503        alt((
504            map(
505                tuple((
506                    tag_no_case("UNION"),
507                    multispace1,
508                    map(
509                        tuple((
510                            multispace0,
511                            delimited(
512                                tag("("),
513                                delimited(multispace0, Column::index_col_list, multispace0),
514                                tag(")"),
515                            ),
516                        )),
517                        |(_, value)| value.iter().map(|x| x.name.clone()).collect(),
518                    ),
519                )),
520                |(_, _, union)| TableOption::Union(union),
521            ),
522            map(
523                tuple((
524                    tag_no_case("UNION "),
525                    multispace0,
526                    tag("="),
527                    multispace0,
528                    map(
529                        tuple((
530                            multispace0,
531                            delimited(
532                                tag("("),
533                                delimited(multispace0, Column::index_col_list, multispace0),
534                                tag(")"),
535                            ),
536                        )),
537                        |(_, value)| value.iter().map(|x| x.name.clone()).collect(),
538                    ),
539                )),
540                |(_, _, _, _, union)| TableOption::Union(union),
541            ),
542        ))(i)
543    }
544}
545
546/// `[CONSTRAINT [symbol]] CHECK (expr) [[NOT] ENFORCED]`
547#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
548pub struct CheckConstraintDefinition {
549    pub symbol: Option<String>,
550    pub expr: String,
551    pub enforced: bool,
552}
553
554impl Display for CheckConstraintDefinition {
555    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
556        write!(f, "CONSTRAINT");
557        if let Some(symbol) = &self.symbol {
558            write!(f, " {}", symbol);
559        }
560        write!(f, " CHECK {}", &self.expr);
561        if !&self.enforced {
562            write!(f, " NOT ENFORCED");
563        }
564        Ok(())
565    }
566}
567
568#[cfg(test)]
569mod tests {
570    use base::table_option::TableOption;
571    use base::DefaultOrZeroOrOne;
572
573    #[test]
574    fn parse_table_option() {
575        let str1 = "PACK_KEYS=1;";
576        let res1 = TableOption::parse(str1);
577        let exp = TableOption::PackKeys(DefaultOrZeroOrOne::One);
578        assert!(res1.is_ok());
579        assert_eq!(res1.unwrap().1, exp);
580
581        let str2 = "DEFAULT CHARSET=utf8;";
582        let res2 = TableOption::parse(str2);
583        let exp = TableOption::DefaultCharset("utf8".to_string());
584        assert!(res2.is_ok());
585        assert_eq!(res2.unwrap().1, exp);
586
587        let str3 = "DATA DIRECTORY='/some/path';";
588        let res3 = TableOption::parse(str3);
589        let exp = TableOption::DataDirectory("/some/path".to_string());
590        assert!(res3.is_ok());
591        assert_eq!(res3.unwrap().1, exp);
592    }
593}