Skip to content

Commit 94f3b1b

Browse files
Moved CreateView struct out of Statement enum
1 parent 9a4d235 commit 94f3b1b

File tree

10 files changed

+214
-212
lines changed

10 files changed

+214
-212
lines changed

src/ast/ddl.rs

Lines changed: 143 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ use sqlparser_derive::{Visit, VisitMut};
3131
use crate::ast::value::escape_single_quote_string;
3232
use 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
};
4343
use 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+
}

src/ast/mod.rs

Lines changed: 15 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,13 @@ pub use self::ddl::{
6464
AlterType, AlterTypeAddValue, AlterTypeAddValuePosition, AlterTypeOperation, AlterTypeRename,
6565
AlterTypeRenameValue, ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ColumnOptions,
6666
ColumnPolicy, ColumnPolicyProperty, ConstraintCharacteristics, CreateConnector, CreateDomain,
67-
CreateFunction, CreateIndex, CreateTable, CreateTrigger, Deduplicate, DeferrableInitial,
68-
DropBehavior, DropTrigger, GeneratedAs, GeneratedExpressionMode, IdentityParameters,
69-
IdentityProperty, IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder,
70-
IndexColumn, IndexOption, IndexType, KeyOrIndexDisplay, Msck, NullsDistinctOption, Owner,
71-
Partition, ProcedureParam, ReferentialAction, RenameTableNameKind, ReplicaIdentity,
72-
TableConstraint, TagsColumnOption, Truncate, UserDefinedTypeCompositeAttributeDef,
73-
UserDefinedTypeRepresentation, ViewColumnDef,
67+
CreateFunction, CreateIndex, CreateTable, CreateTrigger, CreateView, Deduplicate,
68+
DeferrableInitial, DropBehavior, DropTrigger, GeneratedAs, GeneratedExpressionMode,
69+
IdentityParameters, IdentityProperty, IdentityPropertyFormatKind, IdentityPropertyKind,
70+
IdentityPropertyOrder, IndexColumn, IndexOption, IndexType, KeyOrIndexDisplay, Msck,
71+
NullsDistinctOption, Owner, Partition, ProcedureParam, ReferentialAction, RenameTableNameKind,
72+
ReplicaIdentity, TableConstraint, TagsColumnOption, Truncate,
73+
UserDefinedTypeCompositeAttributeDef, UserDefinedTypeRepresentation, ViewColumnDef,
7474
};
7575
pub use self::dml::{Delete, Insert, Update};
7676
pub use self::operator::{BinaryOperator, UnaryOperator};
@@ -3249,48 +3249,7 @@ pub enum Statement {
32493249
/// ```sql
32503250
/// CREATE VIEW
32513251
/// ```
3252-
CreateView {
3253-
/// True if this is a `CREATE OR ALTER VIEW` statement
3254-
///
3255-
/// [MsSql](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-view-transact-sql)
3256-
or_alter: bool,
3257-
or_replace: bool,
3258-
materialized: bool,
3259-
/// Snowflake: SECURE view modifier
3260-
/// <https://docs.snowflake.com/en/sql-reference/sql/create-view#syntax>
3261-
secure: bool,
3262-
/// View name
3263-
name: ObjectName,
3264-
/// If `if_not_exists` is true, this flag is set to true if the view name comes before the `IF NOT EXISTS` clause.
3265-
/// Example:
3266-
/// ```sql
3267-
/// CREATE VIEW myview IF NOT EXISTS AS SELECT 1`
3268-
/// ```
3269-
/// Otherwise, the flag is set to false if the view name comes after the clause
3270-
/// Example:
3271-
/// ```sql
3272-
/// CREATE VIEW IF NOT EXISTS myview AS SELECT 1`
3273-
/// ```
3274-
name_before_not_exists: bool,
3275-
columns: Vec<ViewColumnDef>,
3276-
query: Box<Query>,
3277-
options: CreateTableOptions,
3278-
cluster_by: Vec<Ident>,
3279-
/// Snowflake: Views can have comments in Snowflake.
3280-
/// <https://docs.snowflake.com/en/sql-reference/sql/create-view#syntax>
3281-
comment: Option<String>,
3282-
/// if true, has RedShift [`WITH NO SCHEMA BINDING`] clause <https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_VIEW.html>
3283-
with_no_schema_binding: bool,
3284-
/// if true, has SQLite `IF NOT EXISTS` clause <https://www.sqlite.org/lang_createview.html>
3285-
if_not_exists: bool,
3286-
/// if true, has SQLite `TEMP` or `TEMPORARY` clause <https://www.sqlite.org/lang_createview.html>
3287-
temporary: bool,
3288-
/// if not None, has Clickhouse `TO` clause, specify the table into which to insert results
3289-
/// <https://clickhouse.com/docs/en/sql-reference/statements/create/view#materialized-view>
3290-
to: Option<ObjectName>,
3291-
/// MySQL: Optional parameters for the view algorithm, definer, and security context
3292-
params: Option<CreateViewParams>,
3293-
},
3252+
CreateView(CreateView),
32943253
/// ```sql
32953254
/// CREATE TABLE
32963255
/// ```
@@ -4817,80 +4776,7 @@ impl fmt::Display for Statement {
48174776
}
48184777
Ok(())
48194778
}
4820-
Statement::CreateView {
4821-
or_alter,
4822-
name,
4823-
or_replace,
4824-
columns,
4825-
query,
4826-
materialized,
4827-
secure,
4828-
options,
4829-
cluster_by,
4830-
comment,
4831-
with_no_schema_binding,
4832-
if_not_exists,
4833-
temporary,
4834-
to,
4835-
params,
4836-
name_before_not_exists,
4837-
} => {
4838-
write!(
4839-
f,
4840-
"CREATE {or_alter}{or_replace}",
4841-
or_alter = if *or_alter { "OR ALTER " } else { "" },
4842-
or_replace = if *or_replace { "OR REPLACE " } else { "" },
4843-
)?;
4844-
if let Some(params) = params {
4845-
params.fmt(f)?;
4846-
}
4847-
write!(
4848-
f,
4849-
"{secure}{materialized}{temporary}VIEW {if_not_and_name}{to}",
4850-
if_not_and_name = if *if_not_exists {
4851-
if *name_before_not_exists {
4852-
format!("{name} IF NOT EXISTS")
4853-
} else {
4854-
format!("IF NOT EXISTS {name}")
4855-
}
4856-
} else {
4857-
format!("{name}")
4858-
},
4859-
secure = if *secure { "SECURE " } else { "" },
4860-
materialized = if *materialized { "MATERIALIZED " } else { "" },
4861-
temporary = if *temporary { "TEMPORARY " } else { "" },
4862-
to = to
4863-
.as_ref()
4864-
.map(|to| format!(" TO {to}"))
4865-
.unwrap_or_default()
4866-
)?;
4867-
if !columns.is_empty() {
4868-
write!(f, " ({})", display_comma_separated(columns))?;
4869-
}
4870-
if matches!(options, CreateTableOptions::With(_)) {
4871-
write!(f, " {options}")?;
4872-
}
4873-
if let Some(comment) = comment {
4874-
write!(
4875-
f,
4876-
" COMMENT = '{}'",
4877-
value::escape_single_quote_string(comment)
4878-
)?;
4879-
}
4880-
if !cluster_by.is_empty() {
4881-
write!(f, " CLUSTER BY ({})", display_comma_separated(cluster_by))?;
4882-
}
4883-
if matches!(options, CreateTableOptions::Options(_)) {
4884-
write!(f, " {options}")?;
4885-
}
4886-
f.write_str(" AS")?;
4887-
SpaceOrNewline.fmt(f)?;
4888-
query.fmt(f)?;
4889-
if *with_no_schema_binding {
4890-
write!(f, " WITH NO SCHEMA BINDING")?;
4891-
}
4892-
Ok(())
4893-
}
4779+
Statement::CreateView(create_view) => create_view.fmt(f),
48944780
Statement::CreateTable(create_table) => create_table.fmt(f),
48954781
Statement::LoadData {
48964782
local,
@@ -10836,6 +10722,12 @@ impl From<Update> for Statement {
1083610722
}
1083710723
}
1083810724

10725+
impl From<CreateView> for Statement {
10726+
fn from(cv: CreateView) -> Self {
10727+
Self::CreateView(cv)
10728+
}
10729+
}
10730+
1083910731
impl From<CaseStatement> for Statement {
1084010732
fn from(c: CaseStatement) -> Self {
1084110733
Self::Case(c)

src/ast/spans.rs

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -348,31 +348,7 @@ impl Spanned for Statement {
348348
},
349349
Statement::Update(update) => update.span(),
350350
Statement::Delete(delete) => delete.span(),
351-
Statement::CreateView {
352-
or_alter: _,
353-
or_replace: _,
354-
materialized: _,
355-
secure: _,
356-
name,
357-
columns,
358-
query,
359-
options,
360-
cluster_by,
361-
comment: _,
362-
with_no_schema_binding: _,
363-
if_not_exists: _,
364-
temporary: _,
365-
to,
366-
name_before_not_exists: _,
367-
params: _,
368-
} => union_spans(
369-
core::iter::once(name.span())
370-
.chain(columns.iter().map(|i| i.span()))
371-
.chain(core::iter::once(query.span()))
372-
.chain(core::iter::once(options.span()))
373-
.chain(cluster_by.iter().map(|i| i.span))
374-
.chain(to.iter().map(|i| i.span())),
375-
),
351+
Statement::CreateView(create_view) => create_view.span(),
376352
Statement::CreateTable(create_table) => create_table.span(),
377353
Statement::CreateVirtualTable {
378354
name,

src/parser/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5929,7 +5929,7 @@ impl<'a> Parser<'a> {
59295929
Keyword::BINDING,
59305930
]);
59315931

5932-
Ok(Statement::CreateView {
5932+
Ok(CreateView {
59335933
or_alter,
59345934
name,
59355935
columns,
@@ -5946,7 +5946,8 @@ impl<'a> Parser<'a> {
59465946
to,
59475947
params: create_view_params,
59485948
name_before_not_exists,
5949-
})
5949+
}
5950+
.into())
59505951
}
59515952

59525953
/// Parse optional parameters for the `CREATE VIEW` statement supported by [MySQL].

0 commit comments

Comments
 (0)