@@ -31,13 +31,13 @@ use sqlparser_derive::{Visit, VisitMut};
3131use crate :: ast:: value:: escape_single_quote_string;
3232use crate :: ast:: {
3333 display_comma_separated, display_separated, ArgMode , CommentDef , ConditionalStatements ,
34- CreateFunctionBody , CreateFunctionUsing , CreateTableLikeKind , CreateTableOptions , DataType ,
35- Expr , FileFormat , FunctionBehavior , FunctionCalledOnNull , FunctionDeterminismSpecifier ,
36- FunctionParallel , HiveDistributionStyle , HiveFormat , HiveIOFormat , HiveRowFormat , Ident ,
37- InitializeKind , MySQLColumnPosition , ObjectName , OnCommit , OneOrManyWithParens ,
38- OperateFunctionArg , OrderByExpr , ProjectionSelect , Query , RefreshModeKind , RowAccessPolicy ,
39- SequenceOptions , Spanned , SqlOption , StorageSerializationPolicy , TableVersion , Tag ,
40- TriggerEvent , TriggerExecBody , TriggerObject , TriggerPeriod , TriggerReferencing , Value ,
34+ CreateFunctionBody , CreateFunctionUsing , CreateTableLikeKind , CreateTableOptions ,
35+ CreateViewParams , DataType , Expr , FileFormat , FunctionBehavior , FunctionCalledOnNull ,
36+ FunctionDeterminismSpecifier , FunctionParallel , HiveDistributionStyle , HiveFormat ,
37+ HiveIOFormat , HiveRowFormat , Ident , InitializeKind , MySQLColumnPosition , ObjectName , OnCommit ,
38+ OneOrManyWithParens , OperateFunctionArg , OrderByExpr , ProjectionSelect , Query , RefreshModeKind ,
39+ RowAccessPolicy , SequenceOptions , Spanned , SqlOption , StorageSerializationPolicy , TableVersion ,
40+ Tag , TriggerEvent , TriggerExecBody , TriggerObject , TriggerPeriod , TriggerReferencing , Value ,
4141 ValueWithSpan , WrappedCollection ,
4242} ;
4343use crate :: display_utils:: { DisplayCommaSeparated , Indent , NewLine , SpaceOrNewline } ;
@@ -3527,3 +3527,139 @@ impl Spanned for Msck {
35273527 self . table_name . span ( )
35283528 }
35293529}
3530+
3531+ /// CREATE VIEW statement.
3532+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
3533+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
3534+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
3535+ pub struct CreateView {
3536+ /// True if this is a `CREATE OR ALTER VIEW` statement
3537+ ///
3538+ /// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-view-transact-sql)
3539+ pub or_alter : bool ,
3540+ pub or_replace : bool ,
3541+ pub materialized : bool ,
3542+ /// Snowflake: SECURE view modifier
3543+ /// <https://docs.snowflake.com/en/sql-reference/sql/create-view#syntax>
3544+ pub secure : bool ,
3545+ /// View name
3546+ pub name : ObjectName ,
3547+ /// If `if_not_exists` is true, this flag is set to true if the view name comes before the `IF NOT EXISTS` clause.
3548+ /// Example:
3549+ /// ```sql
3550+ /// CREATE VIEW myview IF NOT EXISTS AS SELECT 1`
3551+ /// ```
3552+ /// Otherwise, the flag is set to false if the view name comes after the clause
3553+ /// Example:
3554+ /// ```sql
3555+ /// CREATE VIEW IF NOT EXISTS myview AS SELECT 1`
3556+ /// ```
3557+ pub name_before_not_exists : bool ,
3558+ pub columns : Vec < ViewColumnDef > ,
3559+ pub query : Box < Query > ,
3560+ pub options : CreateTableOptions ,
3561+ pub cluster_by : Vec < Ident > ,
3562+ /// Snowflake: Views can have comments in Snowflake.
3563+ /// <https://docs.snowflake.com/en/sql-reference/sql/create-view#syntax>
3564+ pub comment : Option < String > ,
3565+ /// if true, has RedShift [`WITH NO SCHEMA BINDING`] clause <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_VIEW.html>
3566+ pub with_no_schema_binding : bool ,
3567+ /// if true, has SQLite `IF NOT EXISTS` clause <https://www.sqlite.org/lang_createview.html>
3568+ pub if_not_exists : bool ,
3569+ /// if true, has SQLite `TEMP` or `TEMPORARY` clause <https://www.sqlite.org/lang_createview.html>
3570+ pub temporary : bool ,
3571+ /// if not None, has Clickhouse `TO` clause, specify the table into which to insert results
3572+ /// <https://clickhouse.com/docs/en/sql-reference/statements/create/view#materialized-view>
3573+ pub to : Option < ObjectName > ,
3574+ /// MySQL: Optional parameters for the view algorithm, definer, and security context
3575+ pub params : Option < CreateViewParams > ,
3576+ }
3577+
3578+ impl fmt:: Display for CreateView {
3579+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
3580+ write ! (
3581+ f,
3582+ "CREATE {or_alter}{or_replace}" ,
3583+ or_alter = if self . or_alter { "OR ALTER " } else { "" } ,
3584+ or_replace = if self . or_replace { "OR REPLACE " } else { "" } ,
3585+ ) ?;
3586+ if let Some ( ref params) = self . params {
3587+ params. fmt ( f) ?;
3588+ }
3589+ write ! (
3590+ f,
3591+ "{secure}{materialized}{temporary}VIEW {if_not_and_name}{to}" ,
3592+ if_not_and_name = if self . if_not_exists {
3593+ if self . name_before_not_exists {
3594+ format!( "{} IF NOT EXISTS" , self . name)
3595+ } else {
3596+ format!( "IF NOT EXISTS {}" , self . name)
3597+ }
3598+ } else {
3599+ format!( "{}" , self . name)
3600+ } ,
3601+ secure = if self . secure { "SECURE " } else { "" } ,
3602+ materialized = if self . materialized {
3603+ "MATERIALIZED "
3604+ } else {
3605+ ""
3606+ } ,
3607+ temporary = if self . temporary { "TEMPORARY " } else { "" } ,
3608+ to = self
3609+ . to
3610+ . as_ref( )
3611+ . map( |to| format!( " TO {to}" ) )
3612+ . unwrap_or_default( )
3613+ ) ?;
3614+ if !self . columns . is_empty ( ) {
3615+ write ! ( f, " ({})" , display_comma_separated( & self . columns) ) ?;
3616+ }
3617+ if matches ! ( self . options, CreateTableOptions :: With ( _) ) {
3618+ write ! ( f, " {}" , self . options) ?;
3619+ }
3620+ if let Some ( ref comment) = self . comment {
3621+ write ! ( f, " COMMENT = '{}'" , escape_single_quote_string( comment) ) ?;
3622+ }
3623+ if !self . cluster_by . is_empty ( ) {
3624+ write ! (
3625+ f,
3626+ " CLUSTER BY ({})" ,
3627+ display_comma_separated( & self . cluster_by)
3628+ ) ?;
3629+ }
3630+ if matches ! ( self . options, CreateTableOptions :: Options ( _) ) {
3631+ write ! ( f, " {}" , self . options) ?;
3632+ }
3633+ f. write_str ( " AS" ) ?;
3634+ SpaceOrNewline . fmt ( f) ?;
3635+ self . query . fmt ( f) ?;
3636+ if self . with_no_schema_binding {
3637+ write ! ( f, " WITH NO SCHEMA BINDING" ) ?;
3638+ }
3639+ Ok ( ( ) )
3640+ }
3641+ }
3642+
3643+ impl Spanned for CreateView {
3644+ fn span ( & self ) -> Span {
3645+ let name_span = self . name . span ( ) ;
3646+ let query_span = self . query . span ( ) ;
3647+ let options_span = self . options . span ( ) ;
3648+
3649+ // Union all the relevant spans
3650+ let mut spans = vec ! [ name_span, query_span, options_span] ;
3651+
3652+ // Add column spans
3653+ spans. extend ( self . columns . iter ( ) . map ( |col| col. span ( ) ) ) ;
3654+
3655+ // Add cluster_by spans
3656+ spans. extend ( self . cluster_by . iter ( ) . map ( |ident| ident. span ) ) ;
3657+
3658+ // Add to span if present
3659+ if let Some ( ref to) = self . to {
3660+ spans. push ( to. span ( ) ) ;
3661+ }
3662+
3663+ Span :: union_iter ( spans)
3664+ }
3665+ }
0 commit comments