Improve parsing performance by reducing token cloning (#1587)

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
This commit is contained in:
Paul J. Davis 2024-12-24 16:19:35 -06:00 committed by GitHub
parent 024a878ee7
commit df3c5652b1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 344 additions and 244 deletions

View file

@ -240,11 +240,14 @@ You can run them with:
``` ```
git checkout main git checkout main
cd sqlparser_bench cd sqlparser_bench
cargo bench cargo bench -- --save-baseline main
git checkout <your branch> git checkout <your branch>
cargo bench cargo bench -- --baseline main
``` ```
By adding the `--save-baseline main` and `--baseline main` you can track the
progress of your improvements as you continue working on the feature branch.
## Licensing ## Licensing
All code in this repository is licensed under the [Apache Software License 2.0](LICENSE.txt). All code in this repository is licensed under the [Apache Software License 2.0](LICENSE.txt).

View file

@ -75,6 +75,15 @@ macro_rules! dialect_of {
}; };
} }
// Similar to above, but for applying directly against an instance of dialect
// instead of a struct member named dialect. This avoids lifetime issues when
// mixing match guards and token references.
macro_rules! dialect_is {
($dialect:ident is $($dialect_type:ty)|+) => {
($($dialect.is::<$dialect_type>())||+)
}
}
/// Encapsulates the differences between SQL implementations. /// Encapsulates the differences between SQL implementations.
/// ///
/// # SQL Dialects /// # SQL Dialects

View file

@ -245,11 +245,11 @@ impl Dialect for PostgreSqlDialect {
pub fn parse_create(parser: &mut Parser) -> Option<Result<Statement, ParserError>> { pub fn parse_create(parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
let name = parser.maybe_parse(|parser| -> Result<ObjectName, ParserError> { let name = parser.maybe_parse(|parser| -> Result<ObjectName, ParserError> {
parser.expect_keyword(Keyword::CREATE)?; parser.expect_keyword_is(Keyword::CREATE)?;
parser.expect_keyword(Keyword::TYPE)?; parser.expect_keyword_is(Keyword::TYPE)?;
let name = parser.parse_object_name(false)?; let name = parser.parse_object_name(false)?;
parser.expect_keyword(Keyword::AS)?; parser.expect_keyword_is(Keyword::AS)?;
parser.expect_keyword(Keyword::ENUM)?; parser.expect_keyword_is(Keyword::ENUM)?;
Ok(name) Ok(name)
}); });

View file

@ -273,7 +273,7 @@ pub fn parse_create_table(
match &next_token.token { match &next_token.token {
Token::Word(word) => match word.keyword { Token::Word(word) => match word.keyword {
Keyword::COPY => { Keyword::COPY => {
parser.expect_keyword(Keyword::GRANTS)?; parser.expect_keyword_is(Keyword::GRANTS)?;
builder = builder.copy_grants(true); builder = builder.copy_grants(true);
} }
Keyword::COMMENT => { Keyword::COMMENT => {
@ -297,7 +297,7 @@ pub fn parse_create_table(
break; break;
} }
Keyword::CLUSTER => { Keyword::CLUSTER => {
parser.expect_keyword(Keyword::BY)?; parser.expect_keyword_is(Keyword::BY)?;
parser.expect_token(&Token::LParen)?; parser.expect_token(&Token::LParen)?;
let cluster_by = Some(WrappedCollection::Parentheses( let cluster_by = Some(WrappedCollection::Parentheses(
parser.parse_comma_separated(|p| p.parse_identifier(false))?, parser.parse_comma_separated(|p| p.parse_identifier(false))?,
@ -360,14 +360,14 @@ pub fn parse_create_table(
parser.prev_token(); parser.prev_token();
} }
Keyword::AGGREGATION => { Keyword::AGGREGATION => {
parser.expect_keyword(Keyword::POLICY)?; parser.expect_keyword_is(Keyword::POLICY)?;
let aggregation_policy = parser.parse_object_name(false)?; let aggregation_policy = parser.parse_object_name(false)?;
builder = builder.with_aggregation_policy(Some(aggregation_policy)); builder = builder.with_aggregation_policy(Some(aggregation_policy));
} }
Keyword::ROW => { Keyword::ROW => {
parser.expect_keywords(&[Keyword::ACCESS, Keyword::POLICY])?; parser.expect_keywords(&[Keyword::ACCESS, Keyword::POLICY])?;
let policy = parser.parse_object_name(false)?; let policy = parser.parse_object_name(false)?;
parser.expect_keyword(Keyword::ON)?; parser.expect_keyword_is(Keyword::ON)?;
parser.expect_token(&Token::LParen)?; parser.expect_token(&Token::LParen)?;
let columns = parser.parse_comma_separated(|p| p.parse_identifier(false))?; let columns = parser.parse_comma_separated(|p| p.parse_identifier(false))?;
parser.expect_token(&Token::RParen)?; parser.expect_token(&Token::RParen)?;
@ -536,15 +536,15 @@ pub fn parse_copy_into(parser: &mut Parser) -> Result<Statement, ParserError> {
let from_stage: ObjectName; let from_stage: ObjectName;
let stage_params: StageParamsObject; let stage_params: StageParamsObject;
parser.expect_keyword(Keyword::FROM)?; parser.expect_keyword_is(Keyword::FROM)?;
// check if data load transformations are present // check if data load transformations are present
match parser.next_token().token { match parser.next_token().token {
Token::LParen => { Token::LParen => {
// data load with transformations // data load with transformations
parser.expect_keyword(Keyword::SELECT)?; parser.expect_keyword_is(Keyword::SELECT)?;
from_transformations = parse_select_items_for_data_load(parser)?; from_transformations = parse_select_items_for_data_load(parser)?;
parser.expect_keyword(Keyword::FROM)?; parser.expect_keyword_is(Keyword::FROM)?;
from_stage = parse_snowflake_stage_name(parser)?; from_stage = parse_snowflake_stage_name(parser)?;
stage_params = parse_stage_params(parser)?; stage_params = parse_stage_params(parser)?;
@ -860,7 +860,7 @@ fn parse_identity_property(parser: &mut Parser) -> Result<IdentityProperty, Pars
)) ))
} else if parser.parse_keyword(Keyword::START) { } else if parser.parse_keyword(Keyword::START) {
let seed = parser.parse_number()?; let seed = parser.parse_number()?;
parser.expect_keyword(Keyword::INCREMENT)?; parser.expect_keyword_is(Keyword::INCREMENT)?;
let increment = parser.parse_number()?; let increment = parser.parse_number()?;
Some(IdentityPropertyFormatKind::StartAndIncrement( Some(IdentityPropertyFormatKind::StartAndIncrement(

View file

@ -52,11 +52,11 @@ impl Parser<'_> {
/// [PostgreSQL](https://www.postgresql.org/docs/current/sql-alterpolicy.html) /// [PostgreSQL](https://www.postgresql.org/docs/current/sql-alterpolicy.html)
pub fn parse_alter_policy(&mut self) -> Result<Statement, ParserError> { pub fn parse_alter_policy(&mut self) -> Result<Statement, ParserError> {
let name = self.parse_identifier(false)?; let name = self.parse_identifier(false)?;
self.expect_keyword(Keyword::ON)?; self.expect_keyword_is(Keyword::ON)?;
let table_name = self.parse_object_name(false)?; let table_name = self.parse_object_name(false)?;
if self.parse_keyword(Keyword::RENAME) { if self.parse_keyword(Keyword::RENAME) {
self.expect_keyword(Keyword::TO)?; self.expect_keyword_is(Keyword::TO)?;
let new_name = self.parse_identifier(false)?; let new_name = self.parse_identifier(false)?;
Ok(Statement::AlterPolicy { Ok(Statement::AlterPolicy {
name, name,
@ -232,7 +232,7 @@ impl Parser<'_> {
Some(Keyword::BYPASSRLS) => RoleOption::BypassRLS(true), Some(Keyword::BYPASSRLS) => RoleOption::BypassRLS(true),
Some(Keyword::NOBYPASSRLS) => RoleOption::BypassRLS(false), Some(Keyword::NOBYPASSRLS) => RoleOption::BypassRLS(false),
Some(Keyword::CONNECTION) => { Some(Keyword::CONNECTION) => {
self.expect_keyword(Keyword::LIMIT)?; self.expect_keyword_is(Keyword::LIMIT)?;
RoleOption::ConnectionLimit(Expr::Value(self.parse_number_value()?)) RoleOption::ConnectionLimit(Expr::Value(self.parse_number_value()?))
} }
Some(Keyword::CREATEDB) => RoleOption::CreateDB(true), Some(Keyword::CREATEDB) => RoleOption::CreateDB(true),
@ -256,7 +256,7 @@ impl Parser<'_> {
Some(Keyword::SUPERUSER) => RoleOption::SuperUser(true), Some(Keyword::SUPERUSER) => RoleOption::SuperUser(true),
Some(Keyword::NOSUPERUSER) => RoleOption::SuperUser(false), Some(Keyword::NOSUPERUSER) => RoleOption::SuperUser(false),
Some(Keyword::VALID) => { Some(Keyword::VALID) => {
self.expect_keyword(Keyword::UNTIL)?; self.expect_keyword_is(Keyword::UNTIL)?;
RoleOption::ValidUntil(Expr::Value(self.parse_value()?)) RoleOption::ValidUntil(Expr::Value(self.parse_value()?))
} }
_ => self.expected("option", self.peek_token())?, _ => self.expected("option", self.peek_token())?,

File diff suppressed because it is too large Load diff