Skip to content

Commit dd7e4a2

Browse files
author
Alexander Beedie
committed
Custom Drop implementation
1 parent e81eb14 commit dd7e4a2

8 files changed

Lines changed: 253 additions & 154 deletions

File tree

src/ast/mod.rs

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1662,6 +1662,53 @@ impl fmt::Display for CastFormat {
16621662
}
16631663
}
16641664

1665+
impl Default for Expr {
1666+
fn default() -> Self {
1667+
Expr::Value(ValueWithSpan {
1668+
value: Value::Null,
1669+
span: Span::empty(),
1670+
})
1671+
}
1672+
}
1673+
1674+
/// Returns `true` for Expr variants that create left-recursive or
1675+
/// single-child chains which can cause deep recursion during drop.
1676+
fn is_chain_variant(expr: &Expr) -> bool {
1677+
matches!(
1678+
expr,
1679+
Expr::BinaryOp { .. } | Expr::UnaryOp { .. } | Expr::Nested(_)
1680+
)
1681+
}
1682+
1683+
/// Extracts the single deeply-nesting child from Expr variants that
1684+
/// create left-recursive or single-child chains, replacing it with a
1685+
/// cheap sentinel. Returns `None` if the child is not itself a chain
1686+
/// variant (i.e., it will drop shallowly on its own).
1687+
fn take_drop_child(expr: &mut Expr) -> Option<Expr> {
1688+
match expr {
1689+
Expr::BinaryOp { left, .. } if is_chain_variant(left.as_ref()) => {
1690+
Some(std::mem::replace(left.as_mut(), Expr::default()))
1691+
}
1692+
Expr::UnaryOp { expr, .. } | Expr::Nested(expr)
1693+
if is_chain_variant(expr.as_ref()) =>
1694+
{
1695+
Some(std::mem::replace(expr.as_mut(), Expr::default()))
1696+
}
1697+
_ => None,
1698+
}
1699+
}
1700+
1701+
impl Drop for Expr {
1702+
fn drop(&mut self) {
1703+
let mut current = take_drop_child(self);
1704+
while let Some(mut expr) = current {
1705+
current = take_drop_child(&mut expr);
1706+
// `expr` drops here, but its recursive child has been moved out
1707+
// (or it had no chain child), so the drop is shallow.
1708+
}
1709+
}
1710+
}
1711+
16651712
impl fmt::Display for Expr {
16661713
#[cfg_attr(feature = "recursive-protection", recursive::recursive)]
16671714
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -7617,12 +7664,14 @@ pub enum FunctionArgExpr {
76177664
}
76187665

76197666
impl From<Expr> for FunctionArgExpr {
7620-
fn from(wildcard_expr: Expr) -> Self {
7621-
match wildcard_expr {
7622-
Expr::QualifiedWildcard(prefix, _) => Self::QualifiedWildcard(prefix),
7623-
Expr::Wildcard(_) => Self::Wildcard,
7624-
expr => Self::Expr(expr),
7667+
fn from(mut wildcard_expr: Expr) -> Self {
7668+
if let Expr::QualifiedWildcard(ref mut prefix, _) = wildcard_expr {
7669+
return Self::QualifiedWildcard(std::mem::replace(prefix, ObjectName(vec![])));
7670+
}
7671+
if matches!(&wildcard_expr, Expr::Wildcard(_)) {
7672+
return Self::Wildcard;
76257673
}
7674+
Self::Expr(wildcard_expr)
76267675
}
76277676
}
76287677

src/parser/mod.rs

Lines changed: 132 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1997,7 +1997,7 @@ impl<'a> Parser<'a> {
19971997
// `T.interval` is parsed as a compound identifier, not as an interval
19981998
// expression.
19991999
_ => {
2000-
let expr = self.maybe_parse(|parser| {
2000+
let mut expr = self.maybe_parse(|parser| {
20012001
let expr = parser
20022002
.parse_subexpr(parser.dialect.prec_value(Precedence::Period))?;
20032003
match &expr {
@@ -2013,33 +2013,48 @@ impl<'a> Parser<'a> {
20132013
}
20142014
})?;
20152015

2016-
match expr {
2017-
// If we get back a compound field access or identifier,
2018-
// we flatten the nested expression.
2019-
// For example if the current root is `foo`
2020-
// and we get back a compound identifier expression `bar.baz`
2021-
// The full expression should be `foo.bar.baz` (i.e.
2022-
// a root with an access chain with 2 entries) and not
2023-
// `foo.(bar.baz)` (i.e. a root with an access chain with
2024-
// 1 entry`).
2025-
Some(Expr::CompoundFieldAccess { root, access_chain }) => {
2026-
chain.push(AccessExpr::Dot(*root));
2027-
chain.extend(access_chain);
2028-
}
2029-
Some(Expr::CompoundIdentifier(parts)) => chain.extend(
2030-
parts.into_iter().map(Expr::Identifier).map(AccessExpr::Dot),
2031-
),
2032-
Some(expr) => {
2033-
chain.push(AccessExpr::Dot(expr));
2016+
// If we get back a compound field access or identifier,
2017+
// we flatten the nested expression.
2018+
// For example if the current root is `foo`
2019+
// and we get back a compound identifier expression `bar.baz`
2020+
// The full expression should be `foo.bar.baz` (i.e.
2021+
// a root with an access chain with 2 entries) and not
2022+
// `foo.(bar.baz)` (i.e. a root with an access chain with
2023+
// 1 entry`).
2024+
if let Some(ref mut inner) = expr {
2025+
match inner {
2026+
Expr::CompoundFieldAccess {
2027+
ref mut root,
2028+
ref mut access_chain,
2029+
} => {
2030+
let root =
2031+
std::mem::replace(root.as_mut(), Expr::default());
2032+
let access_chain = std::mem::take(access_chain);
2033+
chain.push(AccessExpr::Dot(root));
2034+
chain.extend(access_chain);
2035+
}
2036+
Expr::CompoundIdentifier(ref mut parts) => {
2037+
let parts = std::mem::take(parts);
2038+
chain.extend(
2039+
parts
2040+
.into_iter()
2041+
.map(Expr::Identifier)
2042+
.map(AccessExpr::Dot),
2043+
);
2044+
}
2045+
_ => {
2046+
let expr =
2047+
std::mem::replace(inner, Expr::default());
2048+
chain.push(AccessExpr::Dot(expr));
2049+
}
20342050
}
2051+
} else {
20352052
// If the expression is not a valid suffix, fall back to
20362053
// parsing as an identifier. This handles cases like `T.interval`
20372054
// where `interval` is a keyword but should be treated as an identifier.
2038-
None => {
2039-
chain.push(AccessExpr::Dot(Expr::Identifier(
2040-
self.parse_identifier()?,
2041-
)));
2042-
}
2055+
chain.push(AccessExpr::Dot(Expr::Identifier(
2056+
self.parse_identifier()?,
2057+
)));
20432058
}
20442059
}
20452060
}
@@ -2111,7 +2126,10 @@ impl<'a> Parser<'a> {
21112126
.skip(1) // All except the Function
21122127
.all(|access| matches!(access, AccessExpr::Dot(Expr::Identifier(_))))
21132128
{
2114-
let Some(AccessExpr::Dot(Expr::Function(mut func))) = access_chain.pop() else {
2129+
let Some(AccessExpr::Dot(mut func_expr)) = access_chain.pop() else {
2130+
return parser_err!("expected function expression", root.span().start);
2131+
};
2132+
let Expr::Function(ref mut func) = func_expr else {
21152133
return parser_err!("expected function expression", root.span().start);
21162134
};
21172135

@@ -2121,16 +2139,18 @@ impl<'a> Parser<'a> {
21212139
AccessExpr::Dot(expr) => Some(expr),
21222140
_ => None,
21232141
}))
2124-
.flat_map(|expr| match expr {
2125-
Expr::Identifier(ident) => Some(ident),
2142+
.flat_map(|mut expr| match &mut expr {
2143+
Expr::Identifier(ident) => {
2144+
Some(std::mem::replace(ident, Ident::new("")))
2145+
}
21262146
_ => None,
21272147
})
21282148
.map(ObjectNamePart::Identifier)
2129-
.chain(func.name.0)
2149+
.chain(std::mem::take(&mut func.name.0))
21302150
.collect::<Vec<_>>();
21312151
func.name = ObjectName(compound_func_name);
21322152

2133-
return Ok(Expr::Function(func));
2153+
return Ok(func_expr);
21342154
}
21352155

21362156
// Flatten qualified outer join expressions.
@@ -2143,7 +2163,10 @@ impl<'a> Parser<'a> {
21432163
Some(AccessExpr::Dot(Expr::OuterJoin(_)))
21442164
)
21452165
{
2146-
let Some(AccessExpr::Dot(Expr::OuterJoin(inner_expr))) = access_chain.pop() else {
2166+
let Some(AccessExpr::Dot(mut outer_expr)) = access_chain.pop() else {
2167+
return parser_err!("expected (+) expression", root.span().start);
2168+
};
2169+
let Expr::OuterJoin(ref mut inner_expr) = outer_expr else {
21472170
return parser_err!("expected (+) expression", root.span().start);
21482171
};
21492172

@@ -2153,9 +2176,11 @@ impl<'a> Parser<'a> {
21532176

21542177
let token_start = root.span().start;
21552178
let mut idents = Self::exprs_to_idents(root, vec![])?;
2156-
match *inner_expr {
2157-
Expr::CompoundIdentifier(suffix) => idents.extend(suffix),
2158-
Expr::Identifier(suffix) => idents.push(suffix),
2179+
match &mut **inner_expr {
2180+
Expr::CompoundIdentifier(suffix) => idents.extend(std::mem::take(suffix)),
2181+
Expr::Identifier(suffix) => {
2182+
idents.push(std::mem::replace(suffix, Ident::new("")))
2183+
}
21592184
_ => {
21602185
return parser_err!("column identifier before (+)", token_start);
21612186
}
@@ -2190,13 +2215,16 @@ impl<'a> Parser<'a> {
21902215
}
21912216

21922217
/// Convert a root and a list of fields to a list of identifiers.
2193-
fn exprs_to_idents(root: Expr, fields: Vec<AccessExpr>) -> Result<Vec<Ident>, ParserError> {
2218+
fn exprs_to_idents(
2219+
mut root: Expr,
2220+
fields: Vec<AccessExpr>,
2221+
) -> Result<Vec<Ident>, ParserError> {
21942222
let mut idents = vec![];
2195-
if let Expr::Identifier(root) = root {
2196-
idents.push(root);
2197-
for x in fields {
2198-
if let AccessExpr::Dot(Expr::Identifier(ident)) = x {
2199-
idents.push(ident);
2223+
if let Expr::Identifier(ref mut root_ident) = root {
2224+
idents.push(std::mem::replace(root_ident, Ident::new("")));
2225+
for mut x in fields {
2226+
if let AccessExpr::Dot(Expr::Identifier(ref mut ident)) = x {
2227+
idents.push(std::mem::replace(ident, Ident::new("")));
22002228
} else {
22012229
return parser_err!(
22022230
format!("Expected identifier, found: {}", x),
@@ -10954,12 +10982,14 @@ impl<'a> Parser<'a> {
1095410982
pub fn parse_call(&mut self) -> Result<Statement, ParserError> {
1095510983
let object_name = self.parse_object_name(false)?;
1095610984
if self.peek_token_ref().token == Token::LParen {
10957-
match self.parse_function(object_name)? {
10958-
Expr::Function(f) => Ok(Statement::Call(f)),
10959-
other => parser_err!(
10960-
format!("Expected a simple procedure call but found: {other}"),
10985+
let func_expr = self.parse_function(object_name)?;
10986+
if let Expr::Function(ref f) = func_expr {
10987+
Ok(Statement::Call(f.clone()))
10988+
} else {
10989+
parser_err!(
10990+
format!("Expected a simple procedure call but found: {func_expr}"),
1096110991
self.peek_token_ref().span.start
10962-
),
10992+
)
1096310993
}
1096410994
} else {
1096510995
Ok(Statement::Call(Function {
@@ -13688,7 +13718,8 @@ impl<'a> Parser<'a> {
1368813718
Keyword::CALL => {
1368913719
let function_name = self.parse_object_name(false)?;
1369013720
let function_expr = self.parse_function(function_name)?;
13691-
if let Expr::Function(function) = function_expr {
13721+
if let Expr::Function(ref function) = function_expr {
13722+
let function = function.clone();
1369213723
let alias = self.parse_identifier_optional_alias()?;
1369313724
pipe_operators.push(PipeOperator::Call { function, alias });
1369413725
} else {
@@ -17760,57 +17791,76 @@ impl<'a> Parser<'a> {
1776017791
)
1776117792
.map(|keyword| Ident::new(format!("{keyword:?}")));
1776217793

17763-
match self.parse_wildcard_expr()? {
17764-
Expr::QualifiedWildcard(prefix, token) => Ok(SelectItem::QualifiedWildcard(
17765-
SelectItemQualifiedWildcardKind::ObjectName(prefix),
17794+
let mut expr = self.parse_wildcard_expr()?;
17795+
17796+
if let Expr::QualifiedWildcard(ref mut qw_prefix, ref mut token) = expr {
17797+
let qw_prefix = std::mem::replace(qw_prefix, ObjectName(vec![]));
17798+
let token = std::mem::replace(token, AttachedToken::empty());
17799+
return Ok(SelectItem::QualifiedWildcard(
17800+
SelectItemQualifiedWildcardKind::ObjectName(qw_prefix),
1776617801
self.parse_wildcard_additional_options(token.0)?,
17767-
)),
17768-
Expr::Wildcard(token) => Ok(SelectItem::Wildcard(
17802+
));
17803+
}
17804+
17805+
if let Expr::Wildcard(ref mut token) = expr {
17806+
let token = std::mem::replace(token, AttachedToken::empty());
17807+
return Ok(SelectItem::Wildcard(
1776917808
self.parse_wildcard_additional_options(token.0)?,
17770-
)),
17771-
Expr::Identifier(v) if v.value.to_lowercase() == "from" && v.quote_style.is_none() => {
17772-
parser_err!(
17809+
));
17810+
}
17811+
17812+
if let Expr::Identifier(ref v) = expr {
17813+
if v.value.to_lowercase() == "from" && v.quote_style.is_none() {
17814+
return parser_err!(
1777317815
format!("Expected an expression, found: {}", v),
1777417816
self.peek_token_ref().span.start
17775-
)
17817+
);
1777617818
}
17777-
Expr::BinaryOp {
17778-
left,
17779-
op: BinaryOperator::Eq,
17780-
right,
17781-
} if self.dialect.supports_eq_alias_assignment()
17782-
&& matches!(left.as_ref(), Expr::Identifier(_)) =>
17819+
}
17820+
17821+
if let Expr::BinaryOp {
17822+
ref left,
17823+
op: BinaryOperator::Eq,
17824+
ref mut right,
17825+
} = expr
17826+
{
17827+
if self.dialect.supports_eq_alias_assignment()
17828+
&& matches!(left.as_ref(), Expr::Identifier(_))
1778317829
{
17784-
let Expr::Identifier(alias) = *left else {
17830+
let alias = if let Expr::Identifier(ref ident) = **left {
17831+
ident.clone()
17832+
} else {
1778517833
return parser_err!(
1778617834
"BUG: expected identifier expression as alias",
1778717835
self.peek_token_ref().span.start
1778817836
);
1778917837
};
17790-
Ok(SelectItem::ExprWithAlias {
17791-
expr: *right,
17838+
let right_expr = std::mem::replace(right.as_mut(), Expr::default());
17839+
return Ok(SelectItem::ExprWithAlias {
17840+
expr: right_expr,
1779217841
alias,
17793-
})
17794-
}
17795-
expr if self.dialect.supports_select_expr_star()
17796-
&& self.consume_tokens(&[Token::Period, Token::Mul]) =>
17797-
{
17798-
let wildcard_token = self.get_previous_token().clone();
17799-
Ok(SelectItem::QualifiedWildcard(
17800-
SelectItemQualifiedWildcardKind::Expr(expr),
17801-
self.parse_wildcard_additional_options(wildcard_token)?,
17802-
))
17842+
});
1780317843
}
17804-
expr => self
17805-
.maybe_parse_select_item_alias()
17806-
.map(|alias| match alias {
17807-
Some(alias) => SelectItem::ExprWithAlias {
17808-
expr: maybe_prefixed_expr(expr, prefix),
17809-
alias,
17810-
},
17811-
None => SelectItem::UnnamedExpr(maybe_prefixed_expr(expr, prefix)),
17812-
}),
1781317844
}
17845+
17846+
if self.dialect.supports_select_expr_star()
17847+
&& self.consume_tokens(&[Token::Period, Token::Mul])
17848+
{
17849+
let wildcard_token = self.get_previous_token().clone();
17850+
return Ok(SelectItem::QualifiedWildcard(
17851+
SelectItemQualifiedWildcardKind::Expr(expr),
17852+
self.parse_wildcard_additional_options(wildcard_token)?,
17853+
));
17854+
}
17855+
17856+
self.maybe_parse_select_item_alias()
17857+
.map(|alias| match alias {
17858+
Some(alias) => SelectItem::ExprWithAlias {
17859+
expr: maybe_prefixed_expr(expr, prefix),
17860+
alias,
17861+
},
17862+
None => SelectItem::UnnamedExpr(maybe_prefixed_expr(expr, prefix)),
17863+
})
1781417864
}
1781517865

1781617866
/// Parse an [`WildcardAdditionalOptions`] information for wildcard select items.

tests/sqlparser_clickhouse.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -789,8 +789,8 @@ fn parse_create_table_with_primary_key() {
789789
_ => panic!("unexpected primary key type"),
790790
}
791791
match order_by {
792-
Some(OneOrManyWithParens::One(Expr::Function(order_by))) => {
793-
assert!(assert_function(&order_by, "tuple", "i"));
792+
Some(OneOrManyWithParens::One(Expr::Function(ref order_by))) => {
793+
assert!(assert_function(order_by, "tuple", "i"));
794794
}
795795
_ => panic!("unexpected order by type"),
796796
};

0 commit comments

Comments
 (0)