Skip to content

Commit fb42425

Browse files
author
Aleksei Piianin
authored
MS SQL Server: add support for IDENTITY column option (#1432)
1 parent 71318df commit fb42425

File tree

4 files changed

+155
-2
lines changed

4 files changed

+155
-2
lines changed

src/ast/ddl.rs

+28
Original file line numberDiff line numberDiff line change
@@ -1050,6 +1050,20 @@ impl fmt::Display for ColumnOptionDef {
10501050
}
10511051
}
10521052

1053+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1054+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1055+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1056+
pub struct IdentityProperty {
1057+
pub seed: Expr,
1058+
pub increment: Expr,
1059+
}
1060+
1061+
impl fmt::Display for IdentityProperty {
1062+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1063+
write!(f, "{}, {}", self.seed, self.increment)
1064+
}
1065+
}
1066+
10531067
/// `ColumnOption`s are modifiers that follow a column definition in a `CREATE
10541068
/// TABLE` statement.
10551069
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
@@ -1120,6 +1134,13 @@ pub enum ColumnOption {
11201134
/// [1]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#view_column_option_list
11211135
/// [2]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#column_option_list
11221136
Options(Vec<SqlOption>),
1137+
/// MS SQL Server specific: Creates an identity column in a table.
1138+
/// Syntax
1139+
/// ```sql
1140+
/// IDENTITY [ (seed , increment) ]
1141+
/// ```
1142+
/// [MS SQL Server]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
1143+
Identity(Option<IdentityProperty>),
11231144
}
11241145

11251146
impl fmt::Display for ColumnOption {
@@ -1221,6 +1242,13 @@ impl fmt::Display for ColumnOption {
12211242
Options(options) => {
12221243
write!(f, "OPTIONS({})", display_comma_separated(options))
12231244
}
1245+
Identity(parameters) => {
1246+
write!(f, "IDENTITY")?;
1247+
if let Some(parameters) = parameters {
1248+
write!(f, "({parameters})")?;
1249+
}
1250+
Ok(())
1251+
}
12241252
}
12251253
}
12261254
}

src/ast/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ pub use self::dcl::{AlterRoleOperation, ResetConfig, RoleOption, SetConfigValue,
3636
pub use self::ddl::{
3737
AlterColumnOperation, AlterIndexOperation, AlterTableOperation, ClusteredBy, ColumnDef,
3838
ColumnOption, ColumnOptionDef, ConstraintCharacteristics, Deduplicate, DeferrableInitial,
39-
GeneratedAs, GeneratedExpressionMode, IndexOption, IndexType, KeyOrIndexDisplay, Owner,
40-
Partition, ProcedureParam, ReferentialAction, TableConstraint,
39+
GeneratedAs, GeneratedExpressionMode, IdentityProperty, IndexOption, IndexType,
40+
KeyOrIndexDisplay, Owner, Partition, ProcedureParam, ReferentialAction, TableConstraint,
4141
UserDefinedTypeCompositeAttributeDef, UserDefinedTypeRepresentation, ViewColumnDef,
4242
};
4343
pub use self::dml::{CreateIndex, CreateTable, Delete, Insert};

src/parser/mod.rs

+14
Original file line numberDiff line numberDiff line change
@@ -6069,6 +6069,20 @@ impl<'a> Parser<'a> {
60696069
&& dialect_of!(self is MySqlDialect | SQLiteDialect | DuckDbDialect | GenericDialect)
60706070
{
60716071
self.parse_optional_column_option_as()
6072+
} else if self.parse_keyword(Keyword::IDENTITY)
6073+
&& dialect_of!(self is MsSqlDialect | GenericDialect)
6074+
{
6075+
let property = if self.consume_token(&Token::LParen) {
6076+
let seed = self.parse_number()?;
6077+
self.expect_token(&Token::Comma)?;
6078+
let increment = self.parse_number()?;
6079+
self.expect_token(&Token::RParen)?;
6080+
6081+
Some(IdentityProperty { seed, increment })
6082+
} else {
6083+
None
6084+
};
6085+
Ok(Some(ColumnOption::Identity(property)))
60726086
} else {
60736087
Ok(None)
60746088
}

tests/sqlparser_mssql.rs

+111
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,117 @@ fn parse_create_table_with_invalid_options() {
908908
}
909909
}
910910

911+
#[test]
912+
fn parse_create_table_with_identity_column() {
913+
let with_column_options = [
914+
(
915+
r#"CREATE TABLE mytable (columnA INT IDENTITY NOT NULL)"#,
916+
vec![
917+
ColumnOptionDef {
918+
name: None,
919+
option: ColumnOption::Identity(None),
920+
},
921+
ColumnOptionDef {
922+
name: None,
923+
option: ColumnOption::NotNull,
924+
},
925+
],
926+
),
927+
(
928+
r#"CREATE TABLE mytable (columnA INT IDENTITY(1, 1) NOT NULL)"#,
929+
vec![
930+
ColumnOptionDef {
931+
name: None,
932+
#[cfg(not(feature = "bigdecimal"))]
933+
option: ColumnOption::Identity(Some(IdentityProperty {
934+
seed: Expr::Value(Value::Number("1".to_string(), false)),
935+
increment: Expr::Value(Value::Number("1".to_string(), false)),
936+
})),
937+
#[cfg(feature = "bigdecimal")]
938+
option: ColumnOption::Identity(Some(IdentityProperty {
939+
seed: Expr::Value(Value::Number(bigdecimal::BigDecimal::from(1), false)),
940+
increment: Expr::Value(Value::Number(
941+
bigdecimal::BigDecimal::from(1),
942+
false,
943+
)),
944+
})),
945+
},
946+
ColumnOptionDef {
947+
name: None,
948+
option: ColumnOption::NotNull,
949+
},
950+
],
951+
),
952+
];
953+
954+
for (sql, column_options) in with_column_options {
955+
assert_eq!(
956+
ms_and_generic().verified_stmt(sql),
957+
Statement::CreateTable(CreateTable {
958+
or_replace: false,
959+
temporary: false,
960+
external: false,
961+
global: None,
962+
if_not_exists: false,
963+
transient: false,
964+
volatile: false,
965+
name: ObjectName(vec![Ident {
966+
value: "mytable".to_string(),
967+
quote_style: None,
968+
},],),
969+
columns: vec![ColumnDef {
970+
name: Ident {
971+
value: "columnA".to_string(),
972+
quote_style: None,
973+
},
974+
data_type: Int(None,),
975+
collation: None,
976+
options: column_options,
977+
},],
978+
constraints: vec![],
979+
hive_distribution: HiveDistributionStyle::NONE,
980+
hive_formats: Some(HiveFormat {
981+
row_format: None,
982+
serde_properties: None,
983+
storage: None,
984+
location: None,
985+
},),
986+
table_properties: vec![],
987+
with_options: vec![],
988+
file_format: None,
989+
location: None,
990+
query: None,
991+
without_rowid: false,
992+
like: None,
993+
clone: None,
994+
engine: None,
995+
comment: None,
996+
auto_increment_offset: None,
997+
default_charset: None,
998+
collation: None,
999+
on_commit: None,
1000+
on_cluster: None,
1001+
primary_key: None,
1002+
order_by: None,
1003+
partition_by: None,
1004+
cluster_by: None,
1005+
clustered_by: None,
1006+
options: None,
1007+
strict: false,
1008+
copy_grants: false,
1009+
enable_schema_evolution: None,
1010+
change_tracking: None,
1011+
data_retention_time_in_days: None,
1012+
max_data_extension_time_in_days: None,
1013+
default_ddl_collation: None,
1014+
with_aggregation_policy: None,
1015+
with_row_access_policy: None,
1016+
with_tags: None,
1017+
}),
1018+
);
1019+
}
1020+
}
1021+
9111022
fn ms() -> TestedDialects {
9121023
TestedDialects {
9131024
dialects: vec![Box::new(MsSqlDialect {})],

0 commit comments

Comments
 (0)