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#[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, 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 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 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 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 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 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 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 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 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 fn compression(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
292 map(CompressionType::parse, TableOption::Compression)(i)
293 }
294
295 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 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 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 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 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 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 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 fn insert_method(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
389 map(InsertMethodType::parse, TableOption::InsertMethod)(i)
390 }
391
392 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 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 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 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 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 fn row_format(i: &str) -> IResult<&str, TableOption, ParseSQLError<&str>> {
434 map(RowFormatType::parse, TableOption::RowFormat)(i)
435 }
436
437 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 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 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 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 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 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), multispace0,
495 opt(TablespaceType::parse),
496 )),
497 |(_, _, tablespace_name, _, storage)| TableOption::Tablespace(tablespace_name, storage),
498 )(i)
499 }
500
501 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#[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}