mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-09-27 07:59:11 +00:00
solve stack overflow
on RecursionLimitExceeded
during debug building (#1171)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
This commit is contained in:
parent
05af4e049c
commit
83c5d8191b
1 changed files with 64 additions and 33 deletions
|
@ -470,7 +470,7 @@ impl<'a> Parser<'a> {
|
||||||
Keyword::ANALYZE => Ok(self.parse_analyze()?),
|
Keyword::ANALYZE => Ok(self.parse_analyze()?),
|
||||||
Keyword::SELECT | Keyword::WITH | Keyword::VALUES => {
|
Keyword::SELECT | Keyword::WITH | Keyword::VALUES => {
|
||||||
self.prev_token();
|
self.prev_token();
|
||||||
Ok(Statement::Query(Box::new(self.parse_query()?)))
|
Ok(Statement::Query(self.parse_boxed_query()?))
|
||||||
}
|
}
|
||||||
Keyword::TRUNCATE => Ok(self.parse_truncate()?),
|
Keyword::TRUNCATE => Ok(self.parse_truncate()?),
|
||||||
Keyword::ATTACH => Ok(self.parse_attach_database()?),
|
Keyword::ATTACH => Ok(self.parse_attach_database()?),
|
||||||
|
@ -530,7 +530,7 @@ impl<'a> Parser<'a> {
|
||||||
},
|
},
|
||||||
Token::LParen => {
|
Token::LParen => {
|
||||||
self.prev_token();
|
self.prev_token();
|
||||||
Ok(Statement::Query(Box::new(self.parse_query()?)))
|
Ok(Statement::Query(self.parse_boxed_query()?))
|
||||||
}
|
}
|
||||||
_ => self.expected("an SQL statement", next_token),
|
_ => self.expected("an SQL statement", next_token),
|
||||||
}
|
}
|
||||||
|
@ -1084,7 +1084,7 @@ impl<'a> Parser<'a> {
|
||||||
let expr =
|
let expr =
|
||||||
if self.parse_keyword(Keyword::SELECT) || self.parse_keyword(Keyword::WITH) {
|
if self.parse_keyword(Keyword::SELECT) || self.parse_keyword(Keyword::WITH) {
|
||||||
self.prev_token();
|
self.prev_token();
|
||||||
Expr::Subquery(Box::new(self.parse_query()?))
|
Expr::Subquery(self.parse_boxed_query()?)
|
||||||
} else {
|
} else {
|
||||||
let exprs = self.parse_comma_separated(Parser::parse_expr)?;
|
let exprs = self.parse_comma_separated(Parser::parse_expr)?;
|
||||||
match exprs.len() {
|
match exprs.len() {
|
||||||
|
@ -1465,7 +1465,7 @@ impl<'a> Parser<'a> {
|
||||||
self.expect_token(&Token::LParen)?;
|
self.expect_token(&Token::LParen)?;
|
||||||
let exists_node = Expr::Exists {
|
let exists_node = Expr::Exists {
|
||||||
negated,
|
negated,
|
||||||
subquery: Box::new(self.parse_query()?),
|
subquery: self.parse_boxed_query()?,
|
||||||
};
|
};
|
||||||
self.expect_token(&Token::RParen)?;
|
self.expect_token(&Token::RParen)?;
|
||||||
Ok(exists_node)
|
Ok(exists_node)
|
||||||
|
@ -1654,9 +1654,9 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
// Parses an array constructed from a subquery
|
// Parses an array constructed from a subquery
|
||||||
pub fn parse_array_subquery(&mut self) -> Result<Expr, ParserError> {
|
pub fn parse_array_subquery(&mut self) -> Result<Expr, ParserError> {
|
||||||
let query = self.parse_query()?;
|
let query = self.parse_boxed_query()?;
|
||||||
self.expect_token(&Token::RParen)?;
|
self.expect_token(&Token::RParen)?;
|
||||||
Ok(Expr::ArraySubquery(Box::new(query)))
|
Ok(Expr::ArraySubquery(query))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a SQL LISTAGG expression, e.g. `LISTAGG(...) WITHIN GROUP (ORDER BY ...)`.
|
/// Parse a SQL LISTAGG expression, e.g. `LISTAGG(...) WITHIN GROUP (ORDER BY ...)`.
|
||||||
|
@ -2554,7 +2554,7 @@ impl<'a> Parser<'a> {
|
||||||
self.prev_token();
|
self.prev_token();
|
||||||
Expr::InSubquery {
|
Expr::InSubquery {
|
||||||
expr: Box::new(expr),
|
expr: Box::new(expr),
|
||||||
subquery: Box::new(self.parse_query()?),
|
subquery: self.parse_boxed_query()?,
|
||||||
negated,
|
negated,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -3637,7 +3637,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.expect_keyword(Keyword::AS)?;
|
self.expect_keyword(Keyword::AS)?;
|
||||||
let query = Box::new(self.parse_query()?);
|
let query = self.parse_boxed_query()?;
|
||||||
// Optional `WITH [ CASCADED | LOCAL ] CHECK OPTION` is widely supported here.
|
// Optional `WITH [ CASCADED | LOCAL ] CHECK OPTION` is widely supported here.
|
||||||
|
|
||||||
let with_no_schema_binding = dialect_of!(self is RedshiftSqlDialect | GenericDialect)
|
let with_no_schema_binding = dialect_of!(self is RedshiftSqlDialect | GenericDialect)
|
||||||
|
@ -4032,7 +4032,7 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
self.expect_keyword(Keyword::FOR)?;
|
self.expect_keyword(Keyword::FOR)?;
|
||||||
|
|
||||||
let query = Some(Box::new(self.parse_query()?));
|
let query = Some(self.parse_boxed_query()?);
|
||||||
|
|
||||||
Ok(Statement::Declare {
|
Ok(Statement::Declare {
|
||||||
stmts: vec![Declare {
|
stmts: vec![Declare {
|
||||||
|
@ -4126,7 +4126,7 @@ impl<'a> Parser<'a> {
|
||||||
match self.peek_token().token {
|
match self.peek_token().token {
|
||||||
Token::Word(w) if w.keyword == Keyword::SELECT => (
|
Token::Word(w) if w.keyword == Keyword::SELECT => (
|
||||||
Some(DeclareType::Cursor),
|
Some(DeclareType::Cursor),
|
||||||
Some(Box::new(self.parse_query()?)),
|
Some(self.parse_boxed_query()?),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
|
@ -4650,7 +4650,7 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
// Parse optional `AS ( query )`
|
// Parse optional `AS ( query )`
|
||||||
let query = if self.parse_keyword(Keyword::AS) {
|
let query = if self.parse_keyword(Keyword::AS) {
|
||||||
Some(Box::new(self.parse_query()?))
|
Some(self.parse_boxed_query()?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -5646,7 +5646,7 @@ impl<'a> Parser<'a> {
|
||||||
let with_options = self.parse_options(Keyword::WITH)?;
|
let with_options = self.parse_options(Keyword::WITH)?;
|
||||||
|
|
||||||
self.expect_keyword(Keyword::AS)?;
|
self.expect_keyword(Keyword::AS)?;
|
||||||
let query = Box::new(self.parse_query()?);
|
let query = self.parse_boxed_query()?;
|
||||||
|
|
||||||
Ok(Statement::AlterView {
|
Ok(Statement::AlterView {
|
||||||
name,
|
name,
|
||||||
|
@ -5686,7 +5686,7 @@ impl<'a> Parser<'a> {
|
||||||
pub fn parse_copy(&mut self) -> Result<Statement, ParserError> {
|
pub fn parse_copy(&mut self) -> Result<Statement, ParserError> {
|
||||||
let source;
|
let source;
|
||||||
if self.consume_token(&Token::LParen) {
|
if self.consume_token(&Token::LParen) {
|
||||||
source = CopySource::Query(Box::new(self.parse_query()?));
|
source = CopySource::Query(self.parse_boxed_query()?);
|
||||||
self.expect_token(&Token::RParen)?;
|
self.expect_token(&Token::RParen)?;
|
||||||
} else {
|
} else {
|
||||||
let table_name = self.parse_object_name(false)?;
|
let table_name = self.parse_object_name(false)?;
|
||||||
|
@ -6910,6 +6910,15 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Call's [`Self::parse_query`] returning a `Box`'ed result.
|
||||||
|
///
|
||||||
|
/// This function can be used to reduce the stack size required in debug
|
||||||
|
/// builds. Instead of `sizeof(Query)` only a pointer (`Box<Query>`)
|
||||||
|
/// is used.
|
||||||
|
fn parse_boxed_query(&mut self) -> Result<Box<Query>, ParserError> {
|
||||||
|
self.parse_query().map(Box::new)
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse a query expression, i.e. a `SELECT` statement optionally
|
/// Parse a query expression, i.e. a `SELECT` statement optionally
|
||||||
/// preceded with some `WITH` CTE declarations and optionally followed
|
/// preceded with some `WITH` CTE declarations and optionally followed
|
||||||
/// by `ORDER BY`. Unlike some other parse_... methods, this one doesn't
|
/// by `ORDER BY`. Unlike some other parse_... methods, this one doesn't
|
||||||
|
@ -6924,13 +6933,10 @@ impl<'a> Parser<'a> {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.parse_keyword(Keyword::INSERT) {
|
if self.parse_keyword(Keyword::INSERT) {
|
||||||
let insert = self.parse_insert()?;
|
|
||||||
|
|
||||||
Ok(Query {
|
Ok(Query {
|
||||||
with,
|
with,
|
||||||
body: Box::new(SetExpr::Insert(insert)),
|
body: self.parse_insert_setexpr_boxed()?,
|
||||||
limit: None,
|
limit: None,
|
||||||
limit_by: vec![],
|
limit_by: vec![],
|
||||||
order_by: vec![],
|
order_by: vec![],
|
||||||
|
@ -6940,10 +6946,9 @@ impl<'a> Parser<'a> {
|
||||||
for_clause: None,
|
for_clause: None,
|
||||||
})
|
})
|
||||||
} else if self.parse_keyword(Keyword::UPDATE) {
|
} else if self.parse_keyword(Keyword::UPDATE) {
|
||||||
let update = self.parse_update()?;
|
|
||||||
Ok(Query {
|
Ok(Query {
|
||||||
with,
|
with,
|
||||||
body: Box::new(SetExpr::Update(update)),
|
body: self.parse_update_setexpr_boxed()?,
|
||||||
limit: None,
|
limit: None,
|
||||||
limit_by: vec![],
|
limit_by: vec![],
|
||||||
order_by: vec![],
|
order_by: vec![],
|
||||||
|
@ -6953,7 +6958,7 @@ impl<'a> Parser<'a> {
|
||||||
for_clause: None,
|
for_clause: None,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
let body = Box::new(self.parse_query_body(0)?);
|
let body = self.parse_boxed_query_body(0)?;
|
||||||
|
|
||||||
let order_by = if self.parse_keywords(&[Keyword::ORDER, Keyword::BY]) {
|
let order_by = if self.parse_keywords(&[Keyword::ORDER, Keyword::BY]) {
|
||||||
self.parse_comma_separated(Parser::parse_order_by_expr)?
|
self.parse_comma_separated(Parser::parse_order_by_expr)?
|
||||||
|
@ -7143,7 +7148,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.expect_token(&Token::LParen)?;
|
self.expect_token(&Token::LParen)?;
|
||||||
let query = Box::new(self.parse_query()?);
|
let query = self.parse_boxed_query()?;
|
||||||
self.expect_token(&Token::RParen)?;
|
self.expect_token(&Token::RParen)?;
|
||||||
let alias = TableAlias {
|
let alias = TableAlias {
|
||||||
name,
|
name,
|
||||||
|
@ -7167,7 +7172,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.expect_token(&Token::LParen)?;
|
self.expect_token(&Token::LParen)?;
|
||||||
let query = Box::new(self.parse_query()?);
|
let query = self.parse_boxed_query()?;
|
||||||
self.expect_token(&Token::RParen)?;
|
self.expect_token(&Token::RParen)?;
|
||||||
let alias = TableAlias { name, columns };
|
let alias = TableAlias { name, columns };
|
||||||
Cte {
|
Cte {
|
||||||
|
@ -7183,6 +7188,15 @@ impl<'a> Parser<'a> {
|
||||||
Ok(cte)
|
Ok(cte)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Call's [`Self::parse_query_body`] returning a `Box`'ed result.
|
||||||
|
///
|
||||||
|
/// This function can be used to reduce the stack size required in debug
|
||||||
|
/// builds. Instead of `sizeof(QueryBody)` only a pointer (`Box<QueryBody>`)
|
||||||
|
/// is used.
|
||||||
|
fn parse_boxed_query_body(&mut self, precedence: u8) -> Result<Box<SetExpr>, ParserError> {
|
||||||
|
self.parse_query_body(precedence).map(Box::new)
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse a "query body", which is an expression with roughly the
|
/// Parse a "query body", which is an expression with roughly the
|
||||||
/// following grammar:
|
/// following grammar:
|
||||||
/// ```sql
|
/// ```sql
|
||||||
|
@ -7191,16 +7205,19 @@ impl<'a> Parser<'a> {
|
||||||
/// subquery ::= query_body [ order_by_limit ]
|
/// subquery ::= query_body [ order_by_limit ]
|
||||||
/// set_operation ::= query_body { 'UNION' | 'EXCEPT' | 'INTERSECT' } [ 'ALL' ] query_body
|
/// set_operation ::= query_body { 'UNION' | 'EXCEPT' | 'INTERSECT' } [ 'ALL' ] query_body
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// If you need `Box<SetExpr>` then maybe there is sense to use `parse_boxed_query_body`
|
||||||
|
/// due to prevent stack overflow in debug building(to reserve less memory on stack).
|
||||||
pub fn parse_query_body(&mut self, precedence: u8) -> Result<SetExpr, ParserError> {
|
pub fn parse_query_body(&mut self, precedence: u8) -> Result<SetExpr, ParserError> {
|
||||||
// We parse the expression using a Pratt parser, as in `parse_expr()`.
|
// We parse the expression using a Pratt parser, as in `parse_expr()`.
|
||||||
// Start by parsing a restricted SELECT or a `(subquery)`:
|
// Start by parsing a restricted SELECT or a `(subquery)`:
|
||||||
let mut expr = if self.parse_keyword(Keyword::SELECT) {
|
let mut expr = if self.parse_keyword(Keyword::SELECT) {
|
||||||
SetExpr::Select(Box::new(self.parse_select()?))
|
SetExpr::Select(self.parse_select().map(Box::new)?)
|
||||||
} else if self.consume_token(&Token::LParen) {
|
} else if self.consume_token(&Token::LParen) {
|
||||||
// CTEs are not allowed here, but the parser currently accepts them
|
// CTEs are not allowed here, but the parser currently accepts them
|
||||||
let subquery = self.parse_query()?;
|
let subquery = self.parse_boxed_query()?;
|
||||||
self.expect_token(&Token::RParen)?;
|
self.expect_token(&Token::RParen)?;
|
||||||
SetExpr::Query(Box::new(subquery))
|
SetExpr::Query(subquery)
|
||||||
} else if self.parse_keyword(Keyword::VALUES) {
|
} else if self.parse_keyword(Keyword::VALUES) {
|
||||||
let is_mysql = dialect_of!(self is MySqlDialect);
|
let is_mysql = dialect_of!(self is MySqlDialect);
|
||||||
SetExpr::Values(self.parse_values(is_mysql)?)
|
SetExpr::Values(self.parse_values(is_mysql)?)
|
||||||
|
@ -7233,7 +7250,7 @@ impl<'a> Parser<'a> {
|
||||||
left: Box::new(expr),
|
left: Box::new(expr),
|
||||||
op: op.unwrap(),
|
op: op.unwrap(),
|
||||||
set_quantifier,
|
set_quantifier,
|
||||||
right: Box::new(self.parse_query_body(next_precedence)?),
|
right: self.parse_boxed_query_body(next_precedence)?,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8147,7 +8164,7 @@ impl<'a> Parser<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
lateral: IsLateral,
|
lateral: IsLateral,
|
||||||
) -> Result<TableFactor, ParserError> {
|
) -> Result<TableFactor, ParserError> {
|
||||||
let subquery = Box::new(self.parse_query()?);
|
let subquery = self.parse_boxed_query()?;
|
||||||
self.expect_token(&Token::RParen)?;
|
self.expect_token(&Token::RParen)?;
|
||||||
let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
|
let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
|
||||||
Ok(TableFactor::Derived {
|
Ok(TableFactor::Derived {
|
||||||
|
@ -8395,6 +8412,13 @@ impl<'a> Parser<'a> {
|
||||||
Ok(insert.clone())
|
Ok(insert.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse an INSERT statement, returning a `Box`ed SetExpr
|
||||||
|
///
|
||||||
|
/// This is used to reduce the size of the stack frames in debug builds
|
||||||
|
fn parse_insert_setexpr_boxed(&mut self) -> Result<Box<SetExpr>, ParserError> {
|
||||||
|
Ok(Box::new(SetExpr::Insert(self.parse_insert()?)))
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse an INSERT statement
|
/// Parse an INSERT statement
|
||||||
pub fn parse_insert(&mut self) -> Result<Statement, ParserError> {
|
pub fn parse_insert(&mut self) -> Result<Statement, ParserError> {
|
||||||
let or = if !dialect_of!(self is SQLiteDialect) {
|
let or = if !dialect_of!(self is SQLiteDialect) {
|
||||||
|
@ -8445,7 +8469,7 @@ impl<'a> Parser<'a> {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let source = Box::new(self.parse_query()?);
|
let source = self.parse_boxed_query()?;
|
||||||
Ok(Statement::Directory {
|
Ok(Statement::Directory {
|
||||||
local,
|
local,
|
||||||
path,
|
path,
|
||||||
|
@ -8478,7 +8502,7 @@ impl<'a> Parser<'a> {
|
||||||
// Hive allows you to specify columns after partitions as well if you want.
|
// Hive allows you to specify columns after partitions as well if you want.
|
||||||
let after_columns = self.parse_parenthesized_column_list(Optional, false)?;
|
let after_columns = self.parse_parenthesized_column_list(Optional, false)?;
|
||||||
|
|
||||||
let source = Some(Box::new(self.parse_query()?));
|
let source = Some(self.parse_boxed_query()?);
|
||||||
|
|
||||||
(columns, partitioned, after_columns, source)
|
(columns, partitioned, after_columns, source)
|
||||||
};
|
};
|
||||||
|
@ -8581,6 +8605,13 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse an UPDATE statement, returning a `Box`ed SetExpr
|
||||||
|
///
|
||||||
|
/// This is used to reduce the size of the stack frames in debug builds
|
||||||
|
fn parse_update_setexpr_boxed(&mut self) -> Result<Box<SetExpr>, ParserError> {
|
||||||
|
Ok(Box::new(SetExpr::Update(self.parse_update()?)))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_update(&mut self) -> Result<Statement, ParserError> {
|
pub fn parse_update(&mut self) -> Result<Statement, ParserError> {
|
||||||
let table = self.parse_table_and_joins()?;
|
let table = self.parse_table_and_joins()?;
|
||||||
self.expect_keyword(Keyword::SET)?;
|
self.expect_keyword(Keyword::SET)?;
|
||||||
|
@ -8686,11 +8717,11 @@ impl<'a> Parser<'a> {
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
self.prev_token();
|
self.prev_token();
|
||||||
let subquery = self.parse_query()?;
|
let subquery = self.parse_boxed_query()?;
|
||||||
self.expect_token(&Token::RParen)?;
|
self.expect_token(&Token::RParen)?;
|
||||||
return Ok((
|
return Ok((
|
||||||
vec![FunctionArg::Unnamed(FunctionArgExpr::from(Expr::Subquery(
|
vec![FunctionArg::Unnamed(FunctionArgExpr::from(Expr::Subquery(
|
||||||
Box::new(subquery),
|
subquery,
|
||||||
)))],
|
)))],
|
||||||
vec![],
|
vec![],
|
||||||
));
|
));
|
||||||
|
@ -9204,7 +9235,7 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
pub fn parse_unload(&mut self) -> Result<Statement, ParserError> {
|
pub fn parse_unload(&mut self) -> Result<Statement, ParserError> {
|
||||||
self.expect_token(&Token::LParen)?;
|
self.expect_token(&Token::LParen)?;
|
||||||
let query = self.parse_query()?;
|
let query = self.parse_boxed_query()?;
|
||||||
self.expect_token(&Token::RParen)?;
|
self.expect_token(&Token::RParen)?;
|
||||||
|
|
||||||
self.expect_keyword(Keyword::TO)?;
|
self.expect_keyword(Keyword::TO)?;
|
||||||
|
@ -9213,7 +9244,7 @@ impl<'a> Parser<'a> {
|
||||||
let with_options = self.parse_options(Keyword::WITH)?;
|
let with_options = self.parse_options(Keyword::WITH)?;
|
||||||
|
|
||||||
Ok(Statement::Unload {
|
Ok(Statement::Unload {
|
||||||
query: Box::new(query),
|
query,
|
||||||
to,
|
to,
|
||||||
with: with_options,
|
with: with_options,
|
||||||
})
|
})
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue