Skip to content

Commit 6432a93

Browse files
committed
Merge branch 'main' into add_value_spans
2 parents 273da6c + aab12ad commit 6432a93

20 files changed

+878
-243
lines changed

src/ast/mod.rs

Lines changed: 67 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,11 @@ pub use self::query::{
6868
JsonTableColumn, JsonTableColumnErrorHandling, JsonTableNamedColumn, JsonTableNestedColumn,
6969
LateralView, LockClause, LockType, MatchRecognizePattern, MatchRecognizeSymbol, Measure,
7070
NamedWindowDefinition, NamedWindowExpr, NonBlock, Offset, OffsetRows, OpenJsonTableColumn,
71-
OrderBy, OrderByExpr, PivotValueSource, ProjectionSelect, Query, RenameSelectItem,
72-
RepetitionQuantifier, ReplaceSelectElement, ReplaceSelectItem, RowsPerMatch, Select,
73-
SelectFlavor, SelectInto, SelectItem, SelectItemQualifiedWildcardKind, SetExpr, SetOperator,
74-
SetQuantifier, Setting, SymbolDefinition, Table, TableAlias, TableAliasColumnDef, TableFactor,
75-
TableFunctionArgs, TableIndexHintForClause, TableIndexHintType, TableIndexHints,
71+
OrderBy, OrderByExpr, OrderByKind, OrderByOptions, PivotValueSource, ProjectionSelect, Query,
72+
RenameSelectItem, RepetitionQuantifier, ReplaceSelectElement, ReplaceSelectItem, RowsPerMatch,
73+
Select, SelectFlavor, SelectInto, SelectItem, SelectItemQualifiedWildcardKind, SetExpr,
74+
SetOperator, SetQuantifier, Setting, SymbolDefinition, Table, TableAlias, TableAliasColumnDef,
75+
TableFactor, TableFunctionArgs, TableIndexHintForClause, TableIndexHintType, TableIndexHints,
7676
TableIndexType, TableSample, TableSampleBucket, TableSampleKind, TableSampleMethod,
7777
TableSampleModifier, TableSampleQuantity, TableSampleSeed, TableSampleSeedModifier,
7878
TableSampleUnit, TableVersion, TableWithJoins, Top, TopQuantity, UpdateTableFromKind,
@@ -600,6 +600,22 @@ pub enum CeilFloorKind {
600600
Scale(Value),
601601
}
602602

603+
/// A WHEN clause in a CASE expression containing both
604+
/// the condition and its corresponding result
605+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
606+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
607+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
608+
pub struct CaseWhen {
609+
pub condition: Expr,
610+
pub result: Expr,
611+
}
612+
613+
impl fmt::Display for CaseWhen {
614+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
615+
write!(f, "WHEN {} THEN {}", self.condition, self.result)
616+
}
617+
}
618+
603619
/// An SQL expression of any type.
604620
///
605621
/// # Semantics / Type Checking
@@ -918,8 +934,7 @@ pub enum Expr {
918934
/// <https://jakewheat.github.io/sql-overview/sql-2011-foundation-grammar.html#simple-when-clause>
919935
Case {
920936
operand: Option<Box<Expr>>,
921-
conditions: Vec<Expr>,
922-
results: Vec<Expr>,
937+
conditions: Vec<CaseWhen>,
923938
else_result: Option<Box<Expr>>,
924939
},
925940
/// An exists expression `[ NOT ] EXISTS(SELECT ...)`, used in expressions like
@@ -1628,17 +1643,15 @@ impl fmt::Display for Expr {
16281643
Expr::Case {
16291644
operand,
16301645
conditions,
1631-
results,
16321646
else_result,
16331647
} => {
16341648
write!(f, "CASE")?;
16351649
if let Some(operand) = operand {
16361650
write!(f, " {operand}")?;
16371651
}
1638-
for (c, r) in conditions.iter().zip(results) {
1639-
write!(f, " WHEN {c} THEN {r}")?;
1652+
for when in conditions {
1653+
write!(f, " {when}")?;
16401654
}
1641-
16421655
if let Some(else_result) = else_result {
16431656
write!(f, " ELSE {else_result}")?;
16441657
}
@@ -3066,6 +3079,28 @@ pub enum Statement {
30663079
begin: bool,
30673080
transaction: Option<BeginTransactionKind>,
30683081
modifier: Option<TransactionModifier>,
3082+
/// List of statements belonging to the `BEGIN` block.
3083+
/// Example:
3084+
/// ```sql
3085+
/// BEGIN
3086+
/// SELECT 1;
3087+
/// SELECT 2;
3088+
/// END;
3089+
/// ```
3090+
statements: Vec<Statement>,
3091+
/// Statements of an exception clause.
3092+
/// Example:
3093+
/// ```sql
3094+
/// BEGIN
3095+
/// SELECT 1;
3096+
/// EXCEPTION WHEN ERROR THEN
3097+
/// SELECT 2;
3098+
/// SELECT 3;
3099+
/// END;
3100+
/// <https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language#beginexceptionend>
3101+
exception_statements: Option<Vec<Statement>>,
3102+
/// TRUE if the statement has an `END` keyword.
3103+
has_end_keyword: bool,
30693104
},
30703105
/// ```sql
30713106
/// SET TRANSACTION ...
@@ -4809,6 +4844,9 @@ impl fmt::Display for Statement {
48094844
begin: syntax_begin,
48104845
transaction,
48114846
modifier,
4847+
statements,
4848+
exception_statements,
4849+
has_end_keyword,
48124850
} => {
48134851
if *syntax_begin {
48144852
if let Some(modifier) = *modifier {
@@ -4825,6 +4863,24 @@ impl fmt::Display for Statement {
48254863
if !modes.is_empty() {
48264864
write!(f, " {}", display_comma_separated(modes))?;
48274865
}
4866+
if !statements.is_empty() {
4867+
write!(f, " {}", display_separated(statements, "; "))?;
4868+
// We manually insert semicolon for the last statement,
4869+
// since display_separated doesn't handle that case.
4870+
write!(f, ";")?;
4871+
}
4872+
if let Some(exception_statements) = exception_statements {
4873+
write!(f, " EXCEPTION WHEN ERROR THEN")?;
4874+
if !exception_statements.is_empty() {
4875+
write!(f, " {}", display_separated(exception_statements, "; "))?;
4876+
// We manually insert semicolon for the last statement,
4877+
// since display_separated doesn't handle that case.
4878+
write!(f, ";")?;
4879+
}
4880+
}
4881+
if *has_end_keyword {
4882+
write!(f, " END")?;
4883+
}
48284884
Ok(())
48294885
}
48304886
Statement::SetTransaction {

src/ast/query.rs

Lines changed: 53 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2218,30 +2218,50 @@ pub enum JoinConstraint {
22182218
None,
22192219
}
22202220

2221+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2222+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2223+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2224+
pub enum OrderByKind {
2225+
/// ALL syntax of [DuckDB] and [ClickHouse].
2226+
///
2227+
/// [DuckDB]: <https://duckdb.org/docs/sql/query_syntax/orderby>
2228+
/// [ClickHouse]: <https://clickhouse.com/docs/en/sql-reference/statements/select/order-by>
2229+
All(OrderByOptions),
2230+
2231+
/// Expressions
2232+
Expressions(Vec<OrderByExpr>),
2233+
}
2234+
22212235
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
22222236
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
22232237
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
22242238
pub struct OrderBy {
2225-
pub exprs: Vec<OrderByExpr>,
2239+
pub kind: OrderByKind,
2240+
22262241
/// Optional: `INTERPOLATE`
22272242
/// Supported by [ClickHouse syntax]
2228-
///
2229-
/// [ClickHouse syntax]: <https://clickhouse.com/docs/en/sql-reference/statements/select/order-by#order-by-expr-with-fill-modifier>
22302243
pub interpolate: Option<Interpolate>,
22312244
}
22322245

22332246
impl fmt::Display for OrderBy {
22342247
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
22352248
write!(f, "ORDER BY")?;
2236-
if !self.exprs.is_empty() {
2237-
write!(f, " {}", display_comma_separated(&self.exprs))?;
2249+
match &self.kind {
2250+
OrderByKind::Expressions(exprs) => {
2251+
write!(f, " {}", display_comma_separated(exprs))?;
2252+
}
2253+
OrderByKind::All(all) => {
2254+
write!(f, " ALL{}", all)?;
2255+
}
22382256
}
2257+
22392258
if let Some(ref interpolate) = self.interpolate {
22402259
match &interpolate.exprs {
22412260
Some(exprs) => write!(f, " INTERPOLATE ({})", display_comma_separated(exprs))?,
22422261
None => write!(f, " INTERPOLATE")?,
22432262
}
22442263
}
2264+
22452265
Ok(())
22462266
}
22472267
}
@@ -2252,28 +2272,15 @@ impl fmt::Display for OrderBy {
22522272
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
22532273
pub struct OrderByExpr {
22542274
pub expr: Expr,
2255-
/// Optional `ASC` or `DESC`
2256-
pub asc: Option<bool>,
2257-
/// Optional `NULLS FIRST` or `NULLS LAST`
2258-
pub nulls_first: Option<bool>,
2275+
pub options: OrderByOptions,
22592276
/// Optional: `WITH FILL`
22602277
/// Supported by [ClickHouse syntax]: <https://clickhouse.com/docs/en/sql-reference/statements/select/order-by#order-by-expr-with-fill-modifier>
22612278
pub with_fill: Option<WithFill>,
22622279
}
22632280

22642281
impl fmt::Display for OrderByExpr {
22652282
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2266-
write!(f, "{}", self.expr)?;
2267-
match self.asc {
2268-
Some(true) => write!(f, " ASC")?,
2269-
Some(false) => write!(f, " DESC")?,
2270-
None => (),
2271-
}
2272-
match self.nulls_first {
2273-
Some(true) => write!(f, " NULLS FIRST")?,
2274-
Some(false) => write!(f, " NULLS LAST")?,
2275-
None => (),
2276-
}
2283+
write!(f, "{}{}", self.expr, self.options)?;
22772284
if let Some(ref with_fill) = self.with_fill {
22782285
write!(f, " {}", with_fill)?
22792286
}
@@ -2339,6 +2346,32 @@ impl fmt::Display for InterpolateExpr {
23392346
}
23402347
}
23412348

2349+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2350+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2351+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2352+
pub struct OrderByOptions {
2353+
/// Optional `ASC` or `DESC`
2354+
pub asc: Option<bool>,
2355+
/// Optional `NULLS FIRST` or `NULLS LAST`
2356+
pub nulls_first: Option<bool>,
2357+
}
2358+
2359+
impl fmt::Display for OrderByOptions {
2360+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2361+
match self.asc {
2362+
Some(true) => write!(f, " ASC")?,
2363+
Some(false) => write!(f, " DESC")?,
2364+
None => (),
2365+
}
2366+
match self.nulls_first {
2367+
Some(true) => write!(f, " NULLS FIRST")?,
2368+
Some(false) => write!(f, " NULLS LAST")?,
2369+
None => (),
2370+
}
2371+
Ok(())
2372+
}
2373+
}
2374+
23422375
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
23432376
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
23442377
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]

src/ast/spans.rs

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ use super::{
3030
FunctionArguments, GroupByExpr, HavingBound, IlikeSelectItem, Insert, Interpolate,
3131
InterpolateExpr, Join, JoinConstraint, JoinOperator, JsonPath, JsonPathElem, LateralView,
3232
MatchRecognizePattern, Measure, NamedWindowDefinition, ObjectName, ObjectNamePart, Offset,
33-
OnConflict, OnConflictAction, OnInsert, OrderBy, OrderByExpr, Partition, PivotValueSource,
34-
ProjectionSelect, Query, ReferentialAction, RenameSelectItem, ReplaceSelectElement,
35-
ReplaceSelectItem, Select, SelectInto, SelectItem, SetExpr, SqlOption, Statement, Subscript,
36-
SymbolDefinition, TableAlias, TableAliasColumnDef, TableConstraint, TableFactor, TableObject,
37-
TableOptionsClustered, TableWithJoins, UpdateTableFromKind, Use, Value, Values, ViewColumnDef,
38-
WildcardAdditionalOptions, With, WithFill,
33+
OnConflict, OnConflictAction, OnInsert, OrderBy, OrderByExpr, OrderByKind, Partition,
34+
PivotValueSource, ProjectionSelect, Query, ReferentialAction, RenameSelectItem,
35+
ReplaceSelectElement, ReplaceSelectItem, Select, SelectInto, SelectItem, SetExpr, SqlOption,
36+
Statement, Subscript, SymbolDefinition, TableAlias, TableAliasColumnDef, TableConstraint,
37+
TableFactor, TableObject, TableOptionsClustered, TableWithJoins, UpdateTableFromKind, Use,
38+
Value, Values, ViewColumnDef, WildcardAdditionalOptions, With, WithFill,
3939
};
4040

4141
/// Given an iterator of spans, return the [Span::union] of all spans.
@@ -1095,16 +1095,21 @@ impl Spanned for ProjectionSelect {
10951095
}
10961096
}
10971097

1098+
/// # partial span
1099+
///
1100+
/// Missing spans:
1101+
/// - [OrderByKind::All]
10981102
impl Spanned for OrderBy {
10991103
fn span(&self) -> Span {
1100-
let OrderBy { exprs, interpolate } = self;
1101-
1102-
union_spans(
1103-
exprs
1104-
.iter()
1105-
.map(|i| i.span())
1106-
.chain(interpolate.iter().map(|i| i.span())),
1107-
)
1104+
match &self.kind {
1105+
OrderByKind::All(_) => Span::empty(),
1106+
OrderByKind::Expressions(exprs) => union_spans(
1107+
exprs
1108+
.iter()
1109+
.map(|i| i.span())
1110+
.chain(self.interpolate.iter().map(|i| i.span())),
1111+
),
1112+
}
11081113
}
11091114
}
11101115

@@ -1445,15 +1450,15 @@ impl Spanned for Expr {
14451450
Expr::Case {
14461451
operand,
14471452
conditions,
1448-
results,
14491453
else_result,
14501454
} => union_spans(
14511455
operand
14521456
.as_ref()
14531457
.map(|i| i.span())
14541458
.into_iter()
1455-
.chain(conditions.iter().map(|i| i.span()))
1456-
.chain(results.iter().map(|i| i.span()))
1459+
.chain(conditions.iter().flat_map(|case_when| {
1460+
[case_when.condition.span(), case_when.result.span()]
1461+
}))
14571462
.chain(else_result.as_ref().map(|i| i.span())),
14581463
),
14591464
Expr::Exists { subquery, .. } => subquery.span(),
@@ -1902,8 +1907,7 @@ impl Spanned for OrderByExpr {
19021907
fn span(&self) -> Span {
19031908
let OrderByExpr {
19041909
expr,
1905-
asc: _, // bool
1906-
nulls_first: _, // bool
1910+
options: _,
19071911
with_fill,
19081912
} = self;
19091913

src/ast/value.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,12 @@ impl From<ValueWithSpan> for Value {
111111
/// Primitive SQL values such as number and string
112112
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
113113
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
114-
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
114+
#[cfg_attr(
115+
feature = "visitor",
116+
derive(Visit, VisitMut),
117+
visit(with = "visit_value")
118+
)]
119+
115120
pub enum Value {
116121
/// Numeric literal
117122
#[cfg(not(feature = "bigdecimal"))]

0 commit comments

Comments
 (0)