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`
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]

View file

@ -41,12 +41,24 @@ macro_rules! define_keywords {
($(
$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] = &[
$($ident),*
];
}
};
}
// 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`
/// 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:
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:
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)
OUTER,
Keyword::OUTER,
];
/// Can't be used as a column alias, so that `SELECT <expr> alias`
/// 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:
WITH, SELECT, WHERE, GROUP, HAVING, ORDER, LIMIT, OFFSET, FETCH, UNION, EXCEPT, INTERSECT,
// Reserved only as a column alias in the `SELECT` clause:
FROM,
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 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::str::Chars;
use super::dialect::keywords::ALL_KEYWORDS;
use super::dialect::keywords::{Keyword, ALL_KEYWORDS, ALL_KEYWORDS_INDEX};
use super::dialect::Dialect;
use std::fmt;
@ -146,15 +146,14 @@ impl Token {
}
pub fn make_word(word: &str, quote_style: Option<char>) -> Self {
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 {
value: word.to_string(),
quote_style,
keyword: if is_keyword {
word_uppercase
keyword: if quote_style == None {
let keyword = ALL_KEYWORDS.binary_search(&word_uppercase.as_str());
keyword.map_or(Keyword::NoKeyword, |x| ALL_KEYWORDS_INDEX[x])
} else {
"".to_string()
Keyword::NoKeyword
},
})
}
@ -172,7 +171,7 @@ pub struct Word {
pub quote_style: Option<char>,
/// 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
pub keyword: String,
pub keyword: Keyword,
}
impl fmt::Display for Word {

View file

@ -22,7 +22,7 @@ use matches::assert_matches;
use sqlparser::ast::*;
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};
#[test]
@ -1354,10 +1354,12 @@ fn parse_window_functions() {
avg(bar) OVER (ORDER BY a \
RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING), \
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";
let select = verified_only_select(sql);
assert_eq!(4, select.projection.len());
assert_eq!(5, select.projection.len());
assert_eq!(
&Expr::Function(Function {
name: ObjectName(vec![Ident::new("row_number")]),
@ -2872,7 +2874,7 @@ fn parse_drop_index() {
}
#[test]
fn keywords_sorted() {
fn all_keywords_sorted() {
// assert!(ALL_KEYWORDS.is_sorted())
let mut copy = Vec::from(ALL_KEYWORDS);
copy.sort();