solve stack overflow on RecursionLimitExceeded during debug building (#1171)

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
This commit is contained in:
Nikita-str 2024-04-07 15:12:48 +03:00 committed by GitHub
parent 05af4e049c
commit 83c5d8191b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -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,
}) })