@@ -37,7 +37,8 @@ use serde::{Deserialize, Serialize};
37
37
#[ cfg( feature = "visitor" ) ]
38
38
use sqlparser_derive:: { Visit , VisitMut } ;
39
39
40
- use crate :: tokenizer:: Span ;
40
+ use crate :: keywords:: Keyword ;
41
+ use crate :: tokenizer:: { Span , Token } ;
41
42
42
43
pub use self :: data_type:: {
43
44
ArrayElemTypeDef , BinaryLength , CharLengthUnits , CharacterLength , DataType , EnumMember ,
@@ -2136,20 +2137,23 @@ pub enum Password {
2136
2137
#[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
2137
2138
#[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
2138
2139
pub struct CaseStatement {
2140
+ /// The `CASE` token that starts the statement.
2141
+ pub case_token : AttachedToken ,
2139
2142
pub match_expr : Option < Expr > ,
2140
- pub when_blocks : Vec < ConditionalStatements > ,
2141
- pub else_block : Option < Vec < Statement > > ,
2142
- /// TRUE if the statement ends with `END CASE` (vs `END `).
2143
- pub has_end_case : bool ,
2143
+ pub when_blocks : Vec < ConditionalStatementBlock > ,
2144
+ pub else_block : Option < ConditionalStatementBlock > ,
2145
+ /// The last token of the statement ( `END` or `CASE `).
2146
+ pub end_case_token : AttachedToken ,
2144
2147
}
2145
2148
2146
2149
impl fmt:: Display for CaseStatement {
2147
2150
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
2148
2151
let CaseStatement {
2152
+ case_token : _,
2149
2153
match_expr,
2150
2154
when_blocks,
2151
2155
else_block,
2152
- has_end_case ,
2156
+ end_case_token : AttachedToken ( end ) ,
2153
2157
} = self ;
2154
2158
2155
2159
write ! ( f, "CASE" ) ?;
@@ -2163,13 +2167,15 @@ impl fmt::Display for CaseStatement {
2163
2167
}
2164
2168
2165
2169
if let Some ( else_block) = else_block {
2166
- write ! ( f, " ELSE " ) ?;
2167
- format_statement_list ( f, else_block) ?;
2170
+ write ! ( f, " {else_block}" ) ?;
2168
2171
}
2169
2172
2170
2173
write ! ( f, " END" ) ?;
2171
- if * has_end_case {
2172
- write ! ( f, " CASE" ) ?;
2174
+
2175
+ if let Token :: Word ( w) = & end. token {
2176
+ if w. keyword == Keyword :: CASE {
2177
+ write ! ( f, " CASE" ) ?;
2178
+ }
2173
2179
}
2174
2180
2175
2181
Ok ( ( ) )
@@ -2178,7 +2184,7 @@ impl fmt::Display for CaseStatement {
2178
2184
2179
2185
/// An `IF` statement.
2180
2186
///
2181
- /// Examples :
2187
+ /// Example (BigQuery or Snowflake) :
2182
2188
/// ```sql
2183
2189
/// IF TRUE THEN
2184
2190
/// SELECT 1;
@@ -2189,16 +2195,22 @@ impl fmt::Display for CaseStatement {
2189
2195
/// SELECT 4;
2190
2196
/// END IF
2191
2197
/// ```
2192
- ///
2193
2198
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language#if)
2194
2199
/// [Snowflake](https://docs.snowflake.com/en/sql-reference/snowflake-scripting/if)
2200
+ ///
2201
+ /// Example (MSSQL):
2202
+ /// ```sql
2203
+ /// IF 1=1 SELECT 1 ELSE SELECT 2
2204
+ /// ```
2205
+ /// [MSSQL](https://learn.microsoft.com/en-us/sql/t-sql/language-elements/if-else-transact-sql?view=sql-server-ver16)
2195
2206
#[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
2196
2207
#[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
2197
2208
#[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
2198
2209
pub struct IfStatement {
2199
- pub if_block : ConditionalStatements ,
2200
- pub elseif_blocks : Vec < ConditionalStatements > ,
2201
- pub else_block : Option < Vec < Statement > > ,
2210
+ pub if_block : ConditionalStatementBlock ,
2211
+ pub elseif_blocks : Vec < ConditionalStatementBlock > ,
2212
+ pub else_block : Option < ConditionalStatementBlock > ,
2213
+ pub end_token : Option < AttachedToken > ,
2202
2214
}
2203
2215
2204
2216
impl fmt:: Display for IfStatement {
@@ -2207,82 +2219,128 @@ impl fmt::Display for IfStatement {
2207
2219
if_block,
2208
2220
elseif_blocks,
2209
2221
else_block,
2222
+ end_token,
2210
2223
} = self ;
2211
2224
2212
2225
write ! ( f, "{if_block}" ) ?;
2213
2226
2214
- if ! elseif_blocks. is_empty ( ) {
2215
- write ! ( f, " {}" , display_separated ( elseif_blocks , " " ) ) ?;
2227
+ for elseif_block in elseif_blocks {
2228
+ write ! ( f, " {elseif_block}" ) ?;
2216
2229
}
2217
2230
2218
2231
if let Some ( else_block) = else_block {
2219
- write ! ( f, " ELSE " ) ?;
2220
- format_statement_list ( f, else_block) ?;
2232
+ write ! ( f, " {else_block}" ) ?;
2221
2233
}
2222
2234
2223
- write ! ( f, " END IF" ) ?;
2235
+ if let Some ( AttachedToken ( end_token) ) = end_token {
2236
+ write ! ( f, " END {end_token}" ) ?;
2237
+ }
2224
2238
2225
2239
Ok ( ( ) )
2226
2240
}
2227
2241
}
2228
2242
2229
- /// Represents a type of [ConditionalStatements]
2230
- #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
2231
- #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
2232
- #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
2233
- pub enum ConditionalStatementKind {
2234
- /// `WHEN <condition> THEN <statements>`
2235
- When ,
2236
- /// `IF <condition> THEN <statements>`
2237
- If ,
2238
- /// `ELSEIF <condition> THEN <statements>`
2239
- ElseIf ,
2240
- }
2241
-
2242
2243
/// A block within a [Statement::Case] or [Statement::If]-like statement
2243
2244
///
2244
- /// Examples :
2245
+ /// Example 1 :
2245
2246
/// ```sql
2246
2247
/// WHEN EXISTS(SELECT 1) THEN SELECT 1;
2248
+ /// ```
2247
2249
///
2250
+ /// Example 2:
2251
+ /// ```sql
2248
2252
/// IF TRUE THEN SELECT 1; SELECT 2;
2249
2253
/// ```
2254
+ ///
2255
+ /// Example 3:
2256
+ /// ```sql
2257
+ /// ELSE SELECT 1; SELECT 2;
2258
+ /// ```
2250
2259
#[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
2251
2260
#[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
2252
2261
#[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
2253
- pub struct ConditionalStatements {
2254
- /// The condition expression.
2255
- pub condition : Expr ,
2256
- /// Statement list of the `THEN` clause.
2257
- pub statements : Vec < Statement > ,
2258
- pub kind : ConditionalStatementKind ,
2262
+ pub struct ConditionalStatementBlock {
2263
+ pub start_token : AttachedToken ,
2264
+ pub condition : Option < Expr > ,
2265
+ pub then_token : Option < AttachedToken > ,
2266
+ pub conditional_statements : ConditionalStatements ,
2259
2267
}
2260
2268
2261
- impl fmt:: Display for ConditionalStatements {
2269
+ impl ConditionalStatementBlock {
2270
+ pub fn statements ( & self ) -> & Vec < Statement > {
2271
+ self . conditional_statements . statements ( )
2272
+ }
2273
+ }
2274
+
2275
+ impl fmt:: Display for ConditionalStatementBlock {
2262
2276
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
2263
- let ConditionalStatements {
2264
- condition : expr,
2265
- statements,
2266
- kind,
2277
+ let ConditionalStatementBlock {
2278
+ start_token : AttachedToken ( start_token) ,
2279
+ condition,
2280
+ then_token,
2281
+ conditional_statements,
2267
2282
} = self ;
2268
2283
2269
- let kind = match kind {
2270
- ConditionalStatementKind :: When => "WHEN" ,
2271
- ConditionalStatementKind :: If => "IF" ,
2272
- ConditionalStatementKind :: ElseIf => "ELSEIF" ,
2273
- } ;
2284
+ write ! ( f , "{start_token}" ) ? ;
2285
+
2286
+ if let Some ( condition ) = condition {
2287
+ write ! ( f , " {condition}" ) ? ;
2288
+ }
2274
2289
2275
- write ! ( f, "{kind} {expr} THEN" ) ?;
2290
+ if then_token. is_some ( ) {
2291
+ write ! ( f, " THEN" ) ?;
2292
+ }
2276
2293
2277
- if !statements. is_empty ( ) {
2278
- write ! ( f, " " ) ?;
2279
- format_statement_list ( f, statements) ?;
2294
+ if !conditional_statements. statements ( ) . is_empty ( ) {
2295
+ write ! ( f, " {conditional_statements}" ) ?;
2280
2296
}
2281
2297
2282
2298
Ok ( ( ) )
2283
2299
}
2284
2300
}
2285
2301
2302
+ /// A list of statements in a [ConditionalStatementBlock].
2303
+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
2304
+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
2305
+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
2306
+ pub enum ConditionalStatements {
2307
+ /// SELECT 1; SELECT 2; SELECT 3; ...
2308
+ Sequence { statements : Vec < Statement > } ,
2309
+ /// BEGIN SELECT 1; SELECT 2; SELECT 3; ... END
2310
+ BeginEnd {
2311
+ begin_token : AttachedToken ,
2312
+ statements : Vec < Statement > ,
2313
+ end_token : AttachedToken ,
2314
+ } ,
2315
+ }
2316
+
2317
+ impl ConditionalStatements {
2318
+ pub fn statements ( & self ) -> & Vec < Statement > {
2319
+ match self {
2320
+ ConditionalStatements :: Sequence { statements } => statements,
2321
+ ConditionalStatements :: BeginEnd { statements, .. } => statements,
2322
+ }
2323
+ }
2324
+ }
2325
+
2326
+ impl fmt:: Display for ConditionalStatements {
2327
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
2328
+ match self {
2329
+ ConditionalStatements :: Sequence { statements } => {
2330
+ if !statements. is_empty ( ) {
2331
+ format_statement_list ( f, statements) ?;
2332
+ }
2333
+ Ok ( ( ) )
2334
+ }
2335
+ ConditionalStatements :: BeginEnd { statements, .. } => {
2336
+ write ! ( f, "BEGIN " ) ?;
2337
+ format_statement_list ( f, statements) ?;
2338
+ write ! ( f, " END" )
2339
+ }
2340
+ }
2341
+ }
2342
+ }
2343
+
2286
2344
/// A `RAISE` statement.
2287
2345
///
2288
2346
/// Examples:
0 commit comments