@@ -151,6 +151,15 @@ where
151151 DisplaySeparated { slice, sep : ", " }
152152}
153153
154+ /// Writes the given statements to the formatter, each ending with
155+ /// a semicolon and space separated.
156+ fn format_statement_list ( f : & mut fmt:: Formatter , statements : & [ Statement ] ) -> fmt:: Result {
157+ write ! ( f, "{}" , display_separated( statements, "; " ) ) ?;
158+ // We manually insert semicolon for the last statement,
159+ // since display_separated doesn't handle that case.
160+ write ! ( f, ";" )
161+ }
162+
154163/// An identifier, decomposed into its value or character data and the quote style.
155164#[ derive( Debug , Clone , PartialOrd , Ord ) ]
156165#[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
@@ -2080,6 +2089,173 @@ pub enum Password {
20802089 NullPassword ,
20812090}
20822091
2092+ /// A `CASE` statement.
2093+ ///
2094+ /// Examples:
2095+ /// ```sql
2096+ /// CASE
2097+ /// WHEN EXISTS(SELECT 1)
2098+ /// THEN SELECT 1 FROM T;
2099+ /// WHEN EXISTS(SELECT 2)
2100+ /// THEN SELECT 1 FROM U;
2101+ /// ELSE
2102+ /// SELECT 1 FROM V;
2103+ /// END CASE;
2104+ /// ```
2105+ ///
2106+ /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language#case_search_expression)
2107+ /// [Snowflake](https://docs.snowflake.com/en/sql-reference/snowflake-scripting/case)
2108+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
2109+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
2110+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
2111+ pub struct CaseStatement {
2112+ pub match_expr : Option < Expr > ,
2113+ pub when_blocks : Vec < ConditionalStatements > ,
2114+ pub else_block : Option < Vec < Statement > > ,
2115+ /// TRUE if the statement ends with `END CASE` (vs `END`).
2116+ pub has_end_case : bool ,
2117+ }
2118+
2119+ impl fmt:: Display for CaseStatement {
2120+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
2121+ let CaseStatement {
2122+ match_expr,
2123+ when_blocks,
2124+ else_block,
2125+ has_end_case,
2126+ } = self ;
2127+
2128+ write ! ( f, "CASE" ) ?;
2129+
2130+ if let Some ( expr) = match_expr {
2131+ write ! ( f, " {expr}" ) ?;
2132+ }
2133+
2134+ if !when_blocks. is_empty ( ) {
2135+ write ! ( f, " {}" , display_separated( when_blocks, " " ) ) ?;
2136+ }
2137+
2138+ if let Some ( else_block) = else_block {
2139+ write ! ( f, " ELSE " ) ?;
2140+ format_statement_list ( f, else_block) ?;
2141+ }
2142+
2143+ write ! ( f, " END" ) ?;
2144+ if * has_end_case {
2145+ write ! ( f, " CASE" ) ?;
2146+ }
2147+
2148+ Ok ( ( ) )
2149+ }
2150+ }
2151+
2152+ /// An `IF` statement.
2153+ ///
2154+ /// Examples:
2155+ /// ```sql
2156+ /// IF TRUE THEN
2157+ /// SELECT 1;
2158+ /// SELECT 2;
2159+ /// ELSEIF TRUE THEN
2160+ /// SELECT 3;
2161+ /// ELSE
2162+ /// SELECT 4;
2163+ /// END IF
2164+ /// ```
2165+ ///
2166+ /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language#if)
2167+ /// [Snowflake](https://docs.snowflake.com/en/sql-reference/snowflake-scripting/if)
2168+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
2169+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
2170+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
2171+ pub struct IfStatement {
2172+ pub if_block : ConditionalStatements ,
2173+ pub elseif_blocks : Vec < ConditionalStatements > ,
2174+ pub else_block : Option < Vec < Statement > > ,
2175+ }
2176+
2177+ impl fmt:: Display for IfStatement {
2178+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
2179+ let IfStatement {
2180+ if_block,
2181+ elseif_blocks,
2182+ else_block,
2183+ } = self ;
2184+
2185+ write ! ( f, "{if_block}" ) ?;
2186+
2187+ if !elseif_blocks. is_empty ( ) {
2188+ write ! ( f, " {}" , display_separated( elseif_blocks, " " ) ) ?;
2189+ }
2190+
2191+ if let Some ( else_block) = else_block {
2192+ write ! ( f, " ELSE " ) ?;
2193+ format_statement_list ( f, else_block) ?;
2194+ }
2195+
2196+ write ! ( f, " END IF" ) ?;
2197+
2198+ Ok ( ( ) )
2199+ }
2200+ }
2201+
2202+ /// Represents a type of [ConditionalStatements]
2203+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
2204+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
2205+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
2206+ pub enum ConditionalStatementKind {
2207+ /// `WHEN <condition> THEN <statements>`
2208+ When ,
2209+ /// `IF <condition> THEN <statements>`
2210+ If ,
2211+ /// `ELSEIF <condition> THEN <statements>`
2212+ ElseIf ,
2213+ }
2214+
2215+ /// A block within a [Statement::Case] or [Statement::If]-like statement
2216+ ///
2217+ /// Examples:
2218+ /// ```sql
2219+ /// WHEN EXISTS(SELECT 1) THEN SELECT 1;
2220+ ///
2221+ /// IF TRUE THEN SELECT 1; SELECT 2;
2222+ /// ```
2223+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
2224+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
2225+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
2226+ pub struct ConditionalStatements {
2227+ /// The condition expression.
2228+ pub condition : Expr ,
2229+ /// Statement list of the `THEN` clause.
2230+ pub statements : Vec < Statement > ,
2231+ pub kind : ConditionalStatementKind ,
2232+ }
2233+
2234+ impl fmt:: Display for ConditionalStatements {
2235+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
2236+ let ConditionalStatements {
2237+ condition : expr,
2238+ statements,
2239+ kind,
2240+ } = self ;
2241+
2242+ let kind = match kind {
2243+ ConditionalStatementKind :: When => "WHEN" ,
2244+ ConditionalStatementKind :: If => "IF" ,
2245+ ConditionalStatementKind :: ElseIf => "ELSEIF" ,
2246+ } ;
2247+
2248+ write ! ( f, "{kind} {expr} THEN" ) ?;
2249+
2250+ if !statements. is_empty ( ) {
2251+ write ! ( f, " " ) ?;
2252+ format_statement_list ( f, statements) ?;
2253+ }
2254+
2255+ Ok ( ( ) )
2256+ }
2257+ }
2258+
20832259/// Represents an expression assignment within a variable `DECLARE` statement.
20842260///
20852261/// Examples:
@@ -2647,6 +2823,10 @@ pub enum Statement {
26472823 file_format : Option < FileFormat > ,
26482824 source : Box < Query > ,
26492825 } ,
2826+ /// A `CASE` statement.
2827+ Case ( CaseStatement ) ,
2828+ /// An `IF` statement.
2829+ If ( IfStatement ) ,
26502830 /// ```sql
26512831 /// CALL <function>
26522832 /// ```
@@ -3940,6 +4120,12 @@ impl fmt::Display for Statement {
39404120 }
39414121 Ok ( ( ) )
39424122 }
4123+ Statement :: Case ( stmt) => {
4124+ write ! ( f, "{stmt}" )
4125+ }
4126+ Statement :: If ( stmt) => {
4127+ write ! ( f, "{stmt}" )
4128+ }
39434129 Statement :: AttachDatabase {
39444130 schema_name,
39454131 database_file_name,
@@ -4942,18 +5128,14 @@ impl fmt::Display for Statement {
49425128 write ! ( f, " {}" , display_comma_separated( modes) ) ?;
49435129 }
49445130 if !statements. is_empty ( ) {
4945- write ! ( f, " {}" , display_separated( statements, "; " ) ) ?;
4946- // We manually insert semicolon for the last statement,
4947- // since display_separated doesn't handle that case.
4948- write ! ( f, ";" ) ?;
5131+ write ! ( f, " " ) ?;
5132+ format_statement_list ( f, statements) ?;
49495133 }
49505134 if let Some ( exception_statements) = exception_statements {
49515135 write ! ( f, " EXCEPTION WHEN ERROR THEN" ) ?;
49525136 if !exception_statements. is_empty ( ) {
4953- write ! ( f, " {}" , display_separated( exception_statements, "; " ) ) ?;
4954- // We manually insert semicolon for the last statement,
4955- // since display_separated doesn't handle that case.
4956- write ! ( f, ";" ) ?;
5137+ write ! ( f, " " ) ?;
5138+ format_statement_list ( f, exception_statements) ?;
49575139 }
49585140 }
49595141 if * has_end_keyword {
0 commit comments