mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-18 21:20:15 +00:00
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:
parent
0fe3a8ec39
commit
34548e890b
5 changed files with 395 additions and 342 deletions
|
@ -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))]
|
||||||
|
|
|
@ -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,
|
||||||
];
|
];
|
||||||
|
|
634
src/parser.rs
634
src/parser.rs
File diff suppressed because it is too large
Load diff
|
@ -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 {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue