@@ -28,6 +28,7 @@ use helpers::{
2828 stmt_data_loading:: { FileStagingCommand , StageLoadSelectItemKind } ,
2929} ;
3030
31+ use core:: cmp:: Ordering ;
3132use core:: ops:: Deref ;
3233use core:: {
3334 fmt:: { self , Display } ,
@@ -60,13 +61,14 @@ pub use self::ddl::{
6061 AlterColumnOperation , AlterConnectorOwner , AlterIndexOperation , AlterPolicyOperation ,
6162 AlterTableAlgorithm , AlterTableLock , AlterTableOperation , AlterType , AlterTypeAddValue ,
6263 AlterTypeAddValuePosition , AlterTypeOperation , AlterTypeRename , AlterTypeRenameValue ,
63- ClusteredBy , ColumnDef , ColumnOption , ColumnOptionDef , ColumnPolicy , ColumnPolicyProperty ,
64- ConstraintCharacteristics , CreateConnector , CreateDomain , CreateFunction , Deduplicate ,
65- DeferrableInitial , DropBehavior , GeneratedAs , GeneratedExpressionMode , IdentityParameters ,
66- IdentityProperty , IdentityPropertyFormatKind , IdentityPropertyKind , IdentityPropertyOrder ,
67- IndexOption , IndexType , KeyOrIndexDisplay , NullsDistinctOption , Owner , Partition ,
68- ProcedureParam , ReferentialAction , ReplicaIdentity , TableConstraint , TagsColumnOption ,
69- UserDefinedTypeCompositeAttributeDef , UserDefinedTypeRepresentation , ViewColumnDef ,
64+ ClusteredBy , ColumnDef , ColumnOption , ColumnOptionDef , ColumnOptions , ColumnPolicy ,
65+ ColumnPolicyProperty , ConstraintCharacteristics , CreateConnector , CreateDomain , CreateFunction ,
66+ Deduplicate , DeferrableInitial , DropBehavior , GeneratedAs , GeneratedExpressionMode ,
67+ IdentityParameters , IdentityProperty , IdentityPropertyFormatKind , IdentityPropertyKind ,
68+ IdentityPropertyOrder , IndexOption , IndexType , KeyOrIndexDisplay , NullsDistinctOption , Owner ,
69+ Partition , ProcedureParam , ReferentialAction , ReplicaIdentity , TableConstraint ,
70+ TagsColumnOption , UserDefinedTypeCompositeAttributeDef , UserDefinedTypeRepresentation ,
71+ ViewColumnDef ,
7072} ;
7173pub use self :: dml:: { CreateIndex , CreateTable , Delete , IndexColumn , Insert } ;
7274pub use self :: operator:: { BinaryOperator , UnaryOperator } ;
@@ -172,7 +174,7 @@ fn format_statement_list(f: &mut fmt::Formatter, statements: &[Statement]) -> fm
172174}
173175
174176/// An identifier, decomposed into its value or character data and the quote style.
175- #[ derive( Debug , Clone , PartialOrd , Ord ) ]
177+ #[ derive( Debug , Clone ) ]
176178#[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
177179#[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
178180pub struct Ident {
@@ -214,6 +216,35 @@ impl core::hash::Hash for Ident {
214216
215217impl Eq for Ident { }
216218
219+ impl PartialOrd for Ident {
220+ fn partial_cmp ( & self , other : & Self ) -> Option < Ordering > {
221+ Some ( self . cmp ( other) )
222+ }
223+ }
224+
225+ impl Ord for Ident {
226+ fn cmp ( & self , other : & Self ) -> Ordering {
227+ let Ident {
228+ value,
229+ quote_style,
230+ // exhaustiveness check; we ignore spans in ordering
231+ span : _,
232+ } = self ;
233+
234+ let Ident {
235+ value : other_value,
236+ quote_style : other_quote_style,
237+ // exhaustiveness check; we ignore spans in ordering
238+ span : _,
239+ } = other;
240+
241+ // First compare by value, then by quote_style
242+ value
243+ . cmp ( other_value)
244+ . then_with ( || quote_style. cmp ( other_quote_style) )
245+ }
246+ }
247+
217248impl Ident {
218249 /// Create a new identifier with the given value and no quotes and an empty span.
219250 pub fn new < S > ( value : S ) -> Self
@@ -748,7 +779,7 @@ pub enum Expr {
748779 /// `[ NOT ] IN (SELECT ...)`
749780 InSubquery {
750781 expr : Box < Expr > ,
751- subquery : Box < SetExpr > ,
782+ subquery : Box < Query > ,
752783 negated : bool ,
753784 } ,
754785 /// `[ NOT ] IN UNNEST(array_expression)`
@@ -2990,6 +3021,36 @@ impl From<Set> for Statement {
29903021 }
29913022}
29923023
3024+ /// A representation of a `WHEN` arm with all the identifiers catched and the statements to execute
3025+ /// for the arm.
3026+ ///
3027+ /// Snowflake: <https://docs.snowflake.com/en/sql-reference/snowflake-scripting/exception>
3028+ /// BigQuery: <https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language#beginexceptionend>
3029+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
3030+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
3031+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
3032+ pub struct ExceptionWhen {
3033+ pub idents : Vec < Ident > ,
3034+ pub statements : Vec < Statement > ,
3035+ }
3036+
3037+ impl Display for ExceptionWhen {
3038+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
3039+ write ! (
3040+ f,
3041+ "WHEN {idents} THEN" ,
3042+ idents = display_separated( & self . idents, " OR " )
3043+ ) ?;
3044+
3045+ if !self . statements . is_empty ( ) {
3046+ write ! ( f, " " ) ?;
3047+ format_statement_list ( f, & self . statements ) ?;
3048+ }
3049+
3050+ Ok ( ( ) )
3051+ }
3052+ }
3053+
29933054/// A top-level statement (SELECT, INSERT, CREATE, etc.)
29943055#[ allow( clippy:: large_enum_variant) ]
29953056#[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
@@ -3678,17 +3739,20 @@ pub enum Statement {
36783739 /// END;
36793740 /// ```
36803741 statements : Vec < Statement > ,
3681- /// Statements of an exception clause .
3742+ /// Exception handling with exception clauses .
36823743 /// Example:
36833744 /// ```sql
3684- /// BEGIN
3685- /// SELECT 1;
3686- /// EXCEPTION WHEN ERROR THEN
3687- /// SELECT 2;
3688- /// SELECT 3;
3689- /// END;
3745+ /// EXCEPTION
3746+ /// WHEN EXCEPTION_1 THEN
3747+ /// SELECT 2;
3748+ /// WHEN EXCEPTION_2 OR EXCEPTION_3 THEN
3749+ /// SELECT 3;
3750+ /// WHEN OTHER THEN
3751+ /// SELECT 4;
3752+ /// ```
36903753 /// <https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language#beginexceptionend>
3691- exception_statements : Option < Vec < Statement > > ,
3754+ /// <https://docs.snowflake.com/en/sql-reference/snowflake-scripting/exception>
3755+ exception : Option < Vec < ExceptionWhen > > ,
36923756 /// TRUE if the statement has an `END` keyword.
36933757 has_end_keyword : bool ,
36943758 } ,
@@ -3881,6 +3945,7 @@ pub enum Statement {
38813945 or_alter : bool ,
38823946 name : ObjectName ,
38833947 params : Option < Vec < ProcedureParam > > ,
3948+ language : Option < Ident > ,
38843949 body : ConditionalStatements ,
38853950 } ,
38863951 /// ```sql
@@ -4181,7 +4246,7 @@ pub enum Statement {
41814246 /// ```sql
41824247 /// NOTIFY channel [ , payload ]
41834248 /// ```
4184- /// send a notification event together with an optional “ payload” string to channel
4249+ /// send a notification event together with an optional " payload" string to channel
41854250 ///
41864251 /// See Postgres <https://www.postgresql.org/docs/current/sql-notify.html>
41874252 NOTIFY {
@@ -4784,6 +4849,7 @@ impl fmt::Display for Statement {
47844849 name,
47854850 or_alter,
47864851 params,
4852+ language,
47874853 body,
47884854 } => {
47894855 write ! (
@@ -4799,6 +4865,10 @@ impl fmt::Display for Statement {
47994865 }
48004866 }
48014867
4868+ if let Some ( language) = language {
4869+ write ! ( f, " LANGUAGE {language}" ) ?;
4870+ }
4871+
48024872 write ! ( f, " AS {body}" )
48034873 }
48044874 Statement :: CreateMacro {
@@ -5533,7 +5603,7 @@ impl fmt::Display for Statement {
55335603 transaction,
55345604 modifier,
55355605 statements,
5536- exception_statements ,
5606+ exception ,
55375607 has_end_keyword,
55385608 } => {
55395609 if * syntax_begin {
@@ -5555,11 +5625,10 @@ impl fmt::Display for Statement {
55555625 write ! ( f, " " ) ?;
55565626 format_statement_list ( f, statements) ?;
55575627 }
5558- if let Some ( exception_statements) = exception_statements {
5559- write ! ( f, " EXCEPTION WHEN ERROR THEN" ) ?;
5560- if !exception_statements. is_empty ( ) {
5561- write ! ( f, " " ) ?;
5562- format_statement_list ( f, exception_statements) ?;
5628+ if let Some ( exception_when) = exception {
5629+ write ! ( f, " EXCEPTION" ) ?;
5630+ for when in exception_when {
5631+ write ! ( f, " {when}" ) ?;
55635632 }
55645633 }
55655634 if * has_end_keyword {
@@ -9739,6 +9808,8 @@ impl fmt::Display for NullInclusion {
97399808
97409809#[ cfg( test) ]
97419810mod tests {
9811+ use crate :: tokenizer:: Location ;
9812+
97429813 use super :: * ;
97439814
97449815 #[ test]
@@ -10034,4 +10105,16 @@ mod tests {
1003410105 test_steps ( OneOrManyWithParens :: Many ( vec ! [ 2 ] ) , vec ! [ 2 ] , 3 ) ;
1003510106 test_steps ( OneOrManyWithParens :: Many ( vec ! [ 3 , 4 ] ) , vec ! [ 3 , 4 ] , 4 ) ;
1003610107 }
10108+
10109+ // Tests that the position in the code of an `Ident` does not affect its
10110+ // ordering.
10111+ #[ test]
10112+ fn test_ident_ord ( ) {
10113+ let mut a = Ident :: with_span ( Span :: new ( Location :: new ( 1 , 1 ) , Location :: new ( 1 , 1 ) ) , "a" ) ;
10114+ let mut b = Ident :: with_span ( Span :: new ( Location :: new ( 2 , 2 ) , Location :: new ( 2 , 2 ) ) , "b" ) ;
10115+
10116+ assert ! ( a < b) ;
10117+ std:: mem:: swap ( & mut a. span , & mut b. span ) ;
10118+ assert ! ( a < b) ;
10119+ }
1003710120}
0 commit comments