Skip to content

Commit ccb06c2

Browse files
committed
chore: optimize array parsing: keep column_id/literal, add fast path in try_dispatch, create array_number function for numeric arrays, handle negative numbers directly
1 parent 595aec1 commit ccb06c2

File tree

6 files changed

+211
-115
lines changed

6 files changed

+211
-115
lines changed

โ€Žsrc/query/ast/benches/bench.rsโ€Ž

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ fn main() {
1818

1919
// bench fastest โ”‚ slowest โ”‚ median โ”‚ mean โ”‚ samples โ”‚ iters
2020
// โ•ฐโ”€ dummy โ”‚ โ”‚ โ”‚ โ”‚ โ”‚
21-
// โ”œโ”€ deep_function_call 117.2 ยตs โ”‚ 407.3 ยตs โ”‚ 127.5 ยตs โ”‚ 132.2 ยตs โ”‚ 100 โ”‚ 100
22-
// โ”œโ”€ deep_query 229.7 ยตs โ”‚ 395.8 ยตs โ”‚ 242.6 ยตs โ”‚ 244.6 ยตs โ”‚ 100 โ”‚ 100
23-
// โ”œโ”€ large_query 203.8 ยตs โ”‚ 275.7 ยตs โ”‚ 210.9 ยตs โ”‚ 212.8 ยตs โ”‚ 100 โ”‚ 100
24-
// โ”œโ”€ large_statement 206.7 ยตs โ”‚ 238.3 ยตs โ”‚ 212.9 ยตs โ”‚ 213.7 ยตs โ”‚ 100 โ”‚ 100
25-
// โ”œโ”€ wide_embedding 3.628 ms โ”‚ 4.088 ms โ”‚ 3.761 ms โ”‚ 3.762 ms โ”‚ 100 โ”‚ 100
26-
// โ•ฐโ”€ wide_expr 39.76 ยตs โ”‚ 46.04 ยตs โ”‚ 40.18 ยตs โ”‚ 40.43 ยตs โ”‚ 100 โ”‚ 100
21+
// โ”œโ”€ deep_function_call 81.55 ยตs โ”‚ 290.1 ยตs โ”‚ 91.42 ยตs โ”‚ 94.28 ยตs โ”‚ 100 โ”‚ 100
22+
// โ”œโ”€ deep_query 237.3 ยตs โ”‚ 460.7 ยตs โ”‚ 250.4 ยตs โ”‚ 255.7 ยตs โ”‚ 100 โ”‚ 100
23+
// โ”œโ”€ large_query 150.1 ยตs โ”‚ 282.1 ยตs โ”‚ 163.9 ยตs โ”‚ 167 ยตs โ”‚ 100 โ”‚ 100
24+
// โ”œโ”€ large_statement 149.7 ยตs โ”‚ 185.4 ยตs โ”‚ 161.4 ยตs โ”‚ 161.8 ยตs โ”‚ 100 โ”‚ 100
25+
// โ”œโ”€ wide_embedding 2.435 ms โ”‚ 2.8 ms โ”‚ 2.503 ms โ”‚ 2.514 ms โ”‚ 100 โ”‚ 100
26+
// โ•ฐโ”€ wide_expr 30.73 ยตs โ”‚ 45.14 ยตs โ”‚ 31.18 ยตs โ”‚ 31.78 ยตs โ”‚ 100 โ”‚ 100
2727

2828
#[divan::bench_group(max_time = 0.5)]
2929
mod dummy {

โ€Žsrc/query/ast/src/parser/common.rsโ€Ž

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -326,35 +326,44 @@ pub fn column_reference_only(i: Input) -> IResult<(TableReference, Identifier)>
326326
}
327327

328328
pub fn column_id(i: Input) -> IResult<ColumnID> {
329-
alt((
330-
map_res(rule! { ColumnPosition }, |token| {
331-
let name = token.text().to_string();
332-
let pos = name[1..]
333-
.parse::<usize>()
334-
.map_err(|e| nom::Err::Failure(e.into()))?;
335-
if pos == 0 {
336-
return Err(nom::Err::Failure(ErrorKind::Other(
337-
"column position must be greater than 0",
338-
)));
339-
}
340-
Ok(ColumnID::Position(crate::ast::ColumnPosition {
341-
pos,
342-
name,
343-
span: Some(token.span),
344-
}))
345-
}),
346-
// ROW could be a column name for compatibility
347-
map_res(rule! {ROW}, |token| {
348-
Ok(ColumnID::Name(Identifier::from_name(
349-
transform_span(&[token.clone()]),
350-
"row",
351-
)))
352-
}),
353-
map_res(rule! { #ident }, |ident| Ok(ColumnID::Name(ident))),
354-
))
329+
alt((column_position, column_row, column_ident)).parse(i)
330+
}
331+
332+
pub fn column_position(i: Input) -> IResult<ColumnID> {
333+
map_res(rule! { ColumnPosition }, |token| {
334+
let name = token.text().to_string();
335+
let pos = name[1..]
336+
.parse::<usize>()
337+
.map_err(|e| nom::Err::Failure(e.into()))?;
338+
if pos == 0 {
339+
return Err(nom::Err::Failure(ErrorKind::Other(
340+
"column position must be greater than 0",
341+
)));
342+
}
343+
Ok(ColumnID::Position(crate::ast::ColumnPosition {
344+
pos,
345+
name,
346+
span: Some(token.span),
347+
}))
348+
})
355349
.parse(i)
356350
}
357351

352+
pub fn column_row(i: Input) -> IResult<ColumnID> {
353+
// ROW could be a column name for compatibility
354+
map_res(rule! {ROW}, |token| {
355+
Ok(ColumnID::Name(Identifier::from_name(
356+
transform_span(&[token.clone()]),
357+
"row",
358+
)))
359+
})
360+
.parse(i)
361+
}
362+
363+
pub fn column_ident(i: Input) -> IResult<ColumnID> {
364+
map_res(rule! { #ident }, |ident| Ok(ColumnID::Name(ident))).parse(i)
365+
}
366+
358367
pub fn variable_ident(i: Input) -> IResult<String> {
359368
map(rule! { IdentVariable }, |t| t.text()[1..].to_string()).parse(i)
360369
}

โ€Žsrc/query/ast/src/parser/expr.rsโ€Ž

Lines changed: 136 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use ethnum::i256;
1616
use itertools::Itertools;
1717
use nom::combinator::consumed;
18+
use nom::combinator::verify;
1819
use nom::error::context;
1920
use nom::Parser;
2021
use nom_rule::rule;
@@ -32,6 +33,7 @@ use crate::parser::query::*;
3233
use crate::parser::token::*;
3334
use crate::parser::Error;
3435
use crate::parser::ErrorKind;
36+
use crate::span::merge_span;
3537
use crate::Span;
3638

3739
macro_rules! with_span {
@@ -819,15 +821,42 @@ impl<'a, I: Iterator<Item = WithSpan<'a, ExprElement>>> PrattParser<I> for ExprP
819821
}
820822

821823
fn prefix(&mut self, elem: WithSpan<'a, ExprElement>, rhs: Expr) -> Result<Expr, &'static str> {
822-
let expr = match elem.elem {
823-
ExprElement::UnaryOp { op } => Expr::UnaryOp {
824-
span: transform_span(elem.span.tokens),
825-
op,
826-
expr: Box::new(rhs),
827-
},
824+
match elem.elem {
825+
ExprElement::UnaryOp { op } => {
826+
let op_span = transform_span(elem.span.tokens);
827+
match (op, rhs) {
828+
(
829+
UnaryOperator::Minus,
830+
Expr::Literal {
831+
span: rhs_span,
832+
value,
833+
},
834+
) => {
835+
if let Some(value) = try_negate_literal(&value) {
836+
Ok(Expr::Literal {
837+
span: merge_span(op_span, rhs_span),
838+
value,
839+
})
840+
} else {
841+
Ok(Expr::UnaryOp {
842+
span: op_span,
843+
op: UnaryOperator::Minus,
844+
expr: Box::new(Expr::Literal {
845+
span: rhs_span,
846+
value,
847+
}),
848+
})
849+
}
850+
}
851+
(op, rhs_expr) => Ok(Expr::UnaryOp {
852+
span: op_span,
853+
op,
854+
expr: Box::new(rhs_expr),
855+
}),
856+
}
857+
}
828858
_ => unreachable!(),
829-
};
830-
Ok(expr)
859+
}
831860
}
832861

833862
fn postfix(
@@ -1230,7 +1259,7 @@ pub fn expr_element(i: Input) -> IResult<WithSpan<ExprElement>> {
12301259
rule! {
12311260
"." ~ #column_id
12321261
},
1233-
|(_, key)| ExprElement::DotAccess { key },
1262+
|(_, column)| ExprElement::DotAccess { key: column },
12341263
);
12351264

12361265
let chain_function_call = check_experimental_chain_function(
@@ -1550,6 +1579,74 @@ pub fn expr_element(i: Input) -> IResult<WithSpan<ExprElement>> {
15501579
let stage_location = map(rule! { #at_string }, |location| {
15511580
ExprElement::StageLocation { location }
15521581
});
1582+
let string = map(literal_string, |literal| ExprElement::Literal {
1583+
value: Literal::String(literal),
1584+
});
1585+
let code_string = map(code_string, |literal| ExprElement::Literal {
1586+
value: Literal::String(literal),
1587+
});
1588+
let boolean = map(literal_bool, |literal| ExprElement::Literal {
1589+
value: Literal::Boolean(literal),
1590+
});
1591+
let null = value(
1592+
ExprElement::Literal {
1593+
value: Literal::Null,
1594+
},
1595+
rule! { NULL },
1596+
);
1597+
let decimal_uint = map_res(
1598+
rule! {
1599+
LiteralInteger
1600+
},
1601+
|token| {
1602+
Ok(ExprElement::Literal {
1603+
value: parse_uint(token.text(), 10).map_err(nom::Err::Failure)?,
1604+
})
1605+
},
1606+
);
1607+
let hex_uint = map_res(literal_hex_str, |str| {
1608+
Ok(ExprElement::Literal {
1609+
value: parse_uint(str, 16).map_err(nom::Err::Failure)?,
1610+
})
1611+
});
1612+
let decimal_float = map_res(
1613+
verify(
1614+
rule! {
1615+
LiteralFloat
1616+
},
1617+
|token: &Token| !token.text().starts_with('.'),
1618+
),
1619+
|token| {
1620+
Ok(ExprElement::Literal {
1621+
value: parse_float(token.text()).map_err(nom::Err::Failure)?,
1622+
})
1623+
},
1624+
);
1625+
let column_position = map(column_position, |column| ExprElement::ColumnRef {
1626+
column: ColumnRef {
1627+
database: None,
1628+
table: None,
1629+
column,
1630+
},
1631+
});
1632+
let column_row = map(column_row, |column| ExprElement::ColumnRef {
1633+
column: ColumnRef {
1634+
database: None,
1635+
table: None,
1636+
column,
1637+
},
1638+
});
1639+
let column_ident = map(column_ident, |column| ExprElement::ColumnRef {
1640+
column: ColumnRef {
1641+
database: None,
1642+
table: None,
1643+
column,
1644+
},
1645+
});
1646+
1647+
if i.tokens.first().map(|token| token.kind) == Some(ColumnPosition) {
1648+
return with_span!(column_position).parse(i);
1649+
}
15531650

15541651
try_dispatch!(i, true,
15551652
IS => with_span!(rule!(#is_null | #is_distinct_from)).parse(i),
@@ -1656,6 +1753,14 @@ pub fn expr_element(i: Input) -> IResult<WithSpan<ExprElement>> {
16561753
| AtAt
16571754
| HashMinus => with_span!(json_op).parse(i),
16581755
Factorial | SquareRoot | BitWiseNot | CubeRoot | Abs => with_span!(unary_op).parse(i),
1756+
LiteralString => with_span!(string).parse(i),
1757+
LiteralCodeString => with_span!(code_string).parse(i),
1758+
LiteralInteger => with_span!(decimal_uint).parse(i),
1759+
LiteralFloat => with_span!(decimal_float).parse(i),
1760+
MySQLLiteralHex | PGLiteralHex => with_span!(hex_uint).parse(i),
1761+
TRUE | FALSE => with_span!(boolean).parse(i),
1762+
NULL => with_span!(null).parse(i),
1763+
ROW => with_span!(column_row).parse(i),
16591764
);
16601765

16611766
// The try-parse operation in the function call is very expensive, easy to stack overflow
@@ -1669,7 +1774,7 @@ pub fn expr_element(i: Input) -> IResult<WithSpan<ExprElement>> {
16691774
}
16701775

16711776
with_span!(alt((rule!(
1672-
#column_ref : "<column>"
1777+
#column_ident : "<column>"
16731778
| #dot_number_map_access : ".<key>"
16741779
| #literal : "<literal>"
16751780
),)))
@@ -2722,6 +2827,27 @@ pub fn parse_uint(text: &str, radix: u32) -> Result<Literal, ErrorKind> {
27222827
}
27232828
}
27242829

2830+
fn try_negate_literal(literal: &Literal) -> Option<Literal> {
2831+
match literal {
2832+
Literal::UInt64(value) => Some(Literal::Decimal256 {
2833+
value: -i256::from(*value),
2834+
precision: 76,
2835+
scale: 0,
2836+
}),
2837+
Literal::Decimal256 {
2838+
value,
2839+
precision,
2840+
scale,
2841+
} => Some(Literal::Decimal256 {
2842+
value: -*value,
2843+
precision: *precision,
2844+
scale: *scale,
2845+
}),
2846+
Literal::Float64(value) => Some(Literal::Float64(-value)),
2847+
_ => None,
2848+
}
2849+
}
2850+
27252851
pub(crate) fn make_func_get_variable(span: Span, name: String) -> Expr {
27262852
Expr::FunctionCall {
27272853
span,

0 commit comments

Comments
ย (0)