Change Word::keyword to a enum (#193)

This improves performance and paves the way to future API enhancements as discussed in the PR https://github.com/andygrove/sqlparser-rs/pull/193
This commit is contained in:
Daniël Heres 2020-06-11 21:00:35 +02:00 committed by GitHub
parent 0fe3a8ec39
commit 34548e890b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 395 additions and 342 deletions

View file

@ -388,22 +388,6 @@ impl fmt::Display for WindowFrameUnits {
} }
} }
impl FromStr for WindowFrameUnits {
type Err = ParserError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"ROWS" => Ok(WindowFrameUnits::Rows),
"RANGE" => Ok(WindowFrameUnits::Range),
"GROUPS" => Ok(WindowFrameUnits::Groups),
_ => Err(ParserError::ParserError(format!(
"Expected ROWS, RANGE, or GROUPS, found: {}",
s
))),
}
}
}
/// Specifies [WindowFrame]'s `start_bound` and `end_bound` /// Specifies [WindowFrame]'s `start_bound` and `end_bound`
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]

View file

@ -41,12 +41,24 @@ macro_rules! define_keywords {
($( ($(
$ident:ident $(= $string_keyword:expr)? $ident:ident $(= $string_keyword:expr)?
),*) => { ),*) => {
$(kw_def!($ident $(= $string_keyword)?);)* #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord)]
#[allow(non_camel_case_types)]
pub enum Keyword {
NoKeyword,
$($ident),*
}
pub const ALL_KEYWORDS_INDEX: &[Keyword] = &[
$(Keyword::$ident),*
];
$(kw_def!($ident $(= $string_keyword)?);)*
pub const ALL_KEYWORDS: &[&str] = &[ pub const ALL_KEYWORDS: &[&str] = &[
$($ident),* $($ident),*
]; ];
}
};
} }
// The following keywords should be sorted to be able to match using binary search // The following keywords should be sorted to be able to match using binary search
@ -434,20 +446,52 @@ define_keywords!(
/// These keywords can't be used as a table alias, so that `FROM table_name alias` /// These keywords can't be used as a table alias, so that `FROM table_name alias`
/// can be parsed unambiguously without looking ahead. /// can be parsed unambiguously without looking ahead.
pub const RESERVED_FOR_TABLE_ALIAS: &[&str] = &[ pub const RESERVED_FOR_TABLE_ALIAS: &[Keyword] = &[
// Reserved as both a table and a column alias: // Reserved as both a table and a column alias:
WITH, SELECT, WHERE, GROUP, HAVING, ORDER, TOP, LIMIT, OFFSET, FETCH, UNION, EXCEPT, INTERSECT, Keyword::WITH,
Keyword::SELECT,
Keyword::WHERE,
Keyword::GROUP,
Keyword::HAVING,
Keyword::ORDER,
Keyword::TOP,
Keyword::LIMIT,
Keyword::OFFSET,
Keyword::FETCH,
Keyword::UNION,
Keyword::EXCEPT,
Keyword::INTERSECT,
// Reserved only as a table alias in the `FROM`/`JOIN` clauses: // Reserved only as a table alias in the `FROM`/`JOIN` clauses:
ON, JOIN, INNER, CROSS, FULL, LEFT, RIGHT, NATURAL, USING, Keyword::ON,
Keyword::JOIN,
Keyword::INNER,
Keyword::CROSS,
Keyword::FULL,
Keyword::LEFT,
Keyword::RIGHT,
Keyword::NATURAL,
Keyword::USING,
// for MSSQL-specific OUTER APPLY (seems reserved in most dialects) // for MSSQL-specific OUTER APPLY (seems reserved in most dialects)
OUTER, Keyword::OUTER,
]; ];
/// Can't be used as a column alias, so that `SELECT <expr> alias` /// Can't be used as a column alias, so that `SELECT <expr> alias`
/// can be parsed unambiguously without looking ahead. /// can be parsed unambiguously without looking ahead.
pub const RESERVED_FOR_COLUMN_ALIAS: &[&str] = &[ pub const RESERVED_FOR_COLUMN_ALIAS: &[Keyword] = &[
// Reserved as both a table and a column alias: // Reserved as both a table and a column alias:
WITH, SELECT, WHERE, GROUP, HAVING, ORDER, LIMIT, OFFSET, FETCH, UNION, EXCEPT, INTERSECT, Keyword::WITH,
// Reserved only as a column alias in the `SELECT` clause: Keyword::SELECT,
FROM, Keyword::WHERE,
Keyword::GROUP,
Keyword::HAVING,
Keyword::ORDER,
Keyword::TOP,
Keyword::LIMIT,
Keyword::OFFSET,
Keyword::FETCH,
Keyword::UNION,
Keyword::EXCEPT,
Keyword::INTERSECT,
// Reserved only as a column alias in the `SELECT` clause
Keyword::FROM,
]; ];

File diff suppressed because it is too large Load diff

View file

@ -19,7 +19,7 @@
use std::iter::Peekable; use std::iter::Peekable;
use std::str::Chars; use std::str::Chars;
use super::dialect::keywords::ALL_KEYWORDS; use super::dialect::keywords::{Keyword, ALL_KEYWORDS, ALL_KEYWORDS_INDEX};
use super::dialect::Dialect; use super::dialect::Dialect;
use std::fmt; use std::fmt;
@ -146,15 +146,14 @@ impl Token {
} }
pub fn make_word(word: &str, quote_style: Option<char>) -> Self { pub fn make_word(word: &str, quote_style: Option<char>) -> Self {
let word_uppercase = word.to_uppercase(); let word_uppercase = word.to_uppercase();
let is_keyword =
quote_style == None && ALL_KEYWORDS.binary_search(&word_uppercase.as_str()).is_ok();
Token::Word(Word { Token::Word(Word {
value: word.to_string(), value: word.to_string(),
quote_style, quote_style,
keyword: if is_keyword { keyword: if quote_style == None {
word_uppercase let keyword = ALL_KEYWORDS.binary_search(&word_uppercase.as_str());
keyword.map_or(Keyword::NoKeyword, |x| ALL_KEYWORDS_INDEX[x])
} else { } else {
"".to_string() Keyword::NoKeyword
}, },
}) })
} }
@ -172,7 +171,7 @@ pub struct Word {
pub quote_style: Option<char>, pub quote_style: Option<char>,
/// If the word was not quoted and it matched one of the known keywords, /// If the word was not quoted and it matched one of the known keywords,
/// this will have one of the values from dialect::keywords, otherwise empty /// this will have one of the values from dialect::keywords, otherwise empty
pub keyword: String, pub keyword: Keyword,
} }
impl fmt::Display for Word { impl fmt::Display for Word {

View file

@ -22,7 +22,7 @@ use matches::assert_matches;
use sqlparser::ast::*; use sqlparser::ast::*;
use sqlparser::dialect::keywords::ALL_KEYWORDS; use sqlparser::dialect::keywords::ALL_KEYWORDS;
use sqlparser::parser::*; use sqlparser::parser::{Parser, ParserError};
use sqlparser::test_utils::{all_dialects, expr_from_projection, number, only}; use sqlparser::test_utils::{all_dialects, expr_from_projection, number, only};
#[test] #[test]
@ -1354,10 +1354,12 @@ fn parse_window_functions() {
avg(bar) OVER (ORDER BY a \ avg(bar) OVER (ORDER BY a \
RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING), \ RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING), \
max(baz) OVER (ORDER BY a \ max(baz) OVER (ORDER BY a \
ROWS UNBOUNDED PRECEDING) \ ROWS UNBOUNDED PRECEDING), \
sum(qux) OVER (ORDER BY a \
GROUPS BETWEEN 1 PRECEDING AND 1 FOLLOWING) \
FROM foo"; FROM foo";
let select = verified_only_select(sql); let select = verified_only_select(sql);
assert_eq!(4, select.projection.len()); assert_eq!(5, select.projection.len());
assert_eq!( assert_eq!(
&Expr::Function(Function { &Expr::Function(Function {
name: ObjectName(vec![Ident::new("row_number")]), name: ObjectName(vec![Ident::new("row_number")]),
@ -2872,7 +2874,7 @@ fn parse_drop_index() {
} }
#[test] #[test]
fn keywords_sorted() { fn all_keywords_sorted() {
// assert!(ALL_KEYWORDS.is_sorted()) // assert!(ALL_KEYWORDS.is_sorted())
let mut copy = Vec::from(ALL_KEYWORDS); let mut copy = Vec::from(ALL_KEYWORDS);
copy.sort(); copy.sort();