Skip to content

Commit

Permalink
MS SQL Server: add support for IDENTITY column option
Browse files Browse the repository at this point in the history
  • Loading branch information
7phs committed Sep 18, 2024
1 parent 246838a commit c41a356
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 0 deletions.
14 changes: 14 additions & 0 deletions src/ast/ddl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1120,6 +1120,13 @@ pub enum ColumnOption {
/// [1]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#view_column_option_list
/// [2]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#column_option_list
Options(Vec<SqlOption>),
/// MS SQL Server specific: Creates an identity column in a table.
/// Syntax
/// ```sql
/// IDENTITY [ (seed , increment) ]
/// ```
/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
Identity(Option<SqlOption>),
}

impl fmt::Display for ColumnOption {
Expand Down Expand Up @@ -1221,6 +1228,13 @@ impl fmt::Display for ColumnOption {
Options(options) => {
write!(f, "OPTIONS({})", display_comma_separated(options))
}
Identity(parameters) => {
write!(f, "IDENTITY")?;
if let Some(parameters) = parameters {
write!(f, "({parameters})")?;
}
Ok(())
}
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5818,6 +5818,13 @@ pub enum SqlOption {
range_direction: Option<PartitionRangeDirection>,
for_values: Vec<Expr>,
},
/// MS SQL Server specific: Optional parameters of identity column
/// E.g.
///
/// IDENTITY(1, 2)
///
/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
Identity { seed: Value, increment: Value },
}

impl fmt::Display for SqlOption {
Expand Down Expand Up @@ -5849,6 +5856,9 @@ impl fmt::Display for SqlOption {
display_comma_separated(for_values)
)
}
SqlOption::Identity { seed, increment } => {
write!(f, "{}, {}", seed, increment)
}
}
}
}
Expand Down
14 changes: 14 additions & 0 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6043,6 +6043,20 @@ impl<'a> Parser<'a> {
&& dialect_of!(self is MySqlDialect | SQLiteDialect | DuckDbDialect | GenericDialect)
{
self.parse_optional_column_option_as()
} else if self.parse_keyword(Keyword::IDENTITY)
&& dialect_of!(self is MsSqlDialect | GenericDialect)
{
let parameters = if self.expect_token(&Token::LParen).is_ok() {
let seed = self.parse_number_value()?;
self.expect_token(&Token::Comma)?;
let increment = self.parse_number_value()?;
self.expect_token(&Token::RParen)?;

Some(SqlOption::Identity { seed, increment })
} else {
None
};
Ok(Some(ColumnOption::Identity(parameters)))
} else {
Ok(None)
}
Expand Down
108 changes: 108 additions & 0 deletions tests/sqlparser_mssql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,114 @@ fn parse_create_table_with_invalid_options() {
}
}

#[test]
fn parse_create_table_with_identity_column() {
let with_column_options = [
(
r#"CREATE TABLE [mytable] ([columnA] INT IDENTITY NOT NULL)"#,
vec![
ColumnOptionDef {
name: None,
option: ColumnOption::Identity(None),
},
ColumnOptionDef {
name: None,
option: ColumnOption::NotNull,
},
],
),
(
r#"CREATE TABLE [mytable] ([columnA] INT IDENTITY(1, 1) NOT NULL)"#,
vec![
ColumnOptionDef {
name: None,
#[cfg(not(feature = "bigdecimal"))]
option: ColumnOption::Identity(Some(SqlOption::Identity {
seed: Value::Number("1".to_string(), false),
increment: Value::Number("1".to_string(), false),
})),
#[cfg(feature = "bigdecimal")]
option: ColumnOption::Identity(Some(SqlOption::Identity {
seed: Value::Number(bigdecimal::BigDecimal::from(1), false),
increment: Value::Number(bigdecimal::BigDecimal::from(1), false),
})),
},
ColumnOptionDef {
name: None,
option: ColumnOption::NotNull,
},
],
),
];

for (sql, column_options) in with_column_options {
assert_eq!(
ms().verified_stmt(sql),
Statement::CreateTable(CreateTable {
or_replace: false,
temporary: false,
external: false,
global: None,
if_not_exists: false,
transient: false,
volatile: false,
name: ObjectName(vec![Ident {
value: "mytable".to_string(),
quote_style: Some('['),
},],),
columns: vec![ColumnDef {
name: Ident {
value: "columnA".to_string(),
quote_style: Some('['),
},
data_type: Int(None,),
collation: None,
options: column_options,
},],
constraints: vec![],
hive_distribution: HiveDistributionStyle::NONE,
hive_formats: Some(HiveFormat {
row_format: None,
serde_properties: None,
storage: None,
location: None,
},),
table_properties: vec![],
with_options: vec![],
file_format: None,
location: None,
query: None,
without_rowid: false,
like: None,
clone: None,
engine: None,
comment: None,
auto_increment_offset: None,
default_charset: None,
collation: None,
on_commit: None,
on_cluster: None,
primary_key: None,
order_by: None,
partition_by: None,
cluster_by: None,
clustered_by: None,
options: None,
strict: false,
copy_grants: false,
enable_schema_evolution: None,
change_tracking: None,
data_retention_time_in_days: None,
max_data_extension_time_in_days: None,
default_ddl_collation: None,
with_aggregation_policy: None,
with_row_access_policy: None,
with_tags: None,
}),
);
}
}

fn ms() -> TestedDialects {
TestedDialects {
dialects: vec![Box::new(MsSqlDialect {})],
Expand Down

0 comments on commit c41a356

Please sign in to comment.