Skip to content

Commit a359663

Browse files
Refactored ColumnOption::Unique to reuse UniqueConstraint and PrimaryKeyConstraint
1 parent 0fb3b6b commit a359663

File tree

7 files changed

+172
-67
lines changed

7 files changed

+172
-67
lines changed

src/ast/ddl.rs

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@ use sqlparser_derive::{Visit, VisitMut};
3030

3131
use crate::ast::value::escape_single_quote_string;
3232
use crate::ast::{
33-
display_comma_separated, display_separated, table_constraints::TableConstraint, ArgMode,
34-
CommentDef, ConditionalStatements, CreateFunctionBody, CreateFunctionUsing,
33+
display_comma_separated, display_separated,
34+
table_constraints::{PrimaryKeyConstraint, TableConstraint, UniqueConstraint},
35+
ArgMode, CommentDef, ConditionalStatements, CreateFunctionBody, CreateFunctionUsing,
3536
CreateTableLikeKind, CreateTableOptions, DataType, Expr, FileFormat, FunctionBehavior,
3637
FunctionCalledOnNull, FunctionDeterminismSpecifier, FunctionParallel, HiveDistributionStyle,
3738
HiveFormat, HiveIOFormat, HiveRowFormat, Ident, InitializeKind, MySQLColumnPosition,
@@ -53,6 +54,22 @@ pub struct IndexColumn {
5354
pub operator_class: Option<Ident>,
5455
}
5556

57+
impl From<Ident> for IndexColumn {
58+
fn from(c: Ident) -> Self {
59+
Self {
60+
column: OrderByExpr::from(c),
61+
operator_class: None,
62+
}
63+
}
64+
}
65+
66+
impl<'a> From<&'a str> for IndexColumn {
67+
fn from(c: &'a str) -> Self {
68+
let ident = Ident::new(c);
69+
ident.into()
70+
}
71+
}
72+
5673
impl fmt::Display for IndexColumn {
5774
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5875
write!(f, "{}", self.column)?;
@@ -1553,11 +1570,10 @@ pub enum ColumnOption {
15531570
/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/create/table#default_values)
15541571
Alias(Expr),
15551572

1556-
/// `{ PRIMARY KEY | UNIQUE } [<constraint_characteristics>]`
1557-
Unique {
1558-
is_primary: bool,
1559-
characteristics: Option<ConstraintCharacteristics>,
1560-
},
1573+
/// `PRIMARY KEY [<constraint_characteristics>]`
1574+
PrimaryKey(PrimaryKeyConstraint),
1575+
/// `UNIQUE [<constraint_characteristics>]`
1576+
Unique(UniqueConstraint),
15611577
/// A referential integrity constraint (`[FOREIGN KEY REFERENCES
15621578
/// <foreign_table> (<referred_columns>)
15631579
/// { [ON DELETE <referential_action>] [ON UPDATE <referential_action>] |
@@ -1642,6 +1658,18 @@ pub enum ColumnOption {
16421658
Invisible,
16431659
}
16441660

1661+
impl From<UniqueConstraint> for ColumnOption {
1662+
fn from(c: UniqueConstraint) -> Self {
1663+
ColumnOption::Unique(c)
1664+
}
1665+
}
1666+
1667+
impl From<PrimaryKeyConstraint> for ColumnOption {
1668+
fn from(c: PrimaryKeyConstraint) -> Self {
1669+
ColumnOption::PrimaryKey(c)
1670+
}
1671+
}
1672+
16451673
impl fmt::Display for ColumnOption {
16461674
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
16471675
use ColumnOption::*;
@@ -1658,12 +1686,16 @@ impl fmt::Display for ColumnOption {
16581686
}
16591687
}
16601688
Alias(expr) => write!(f, "ALIAS {expr}"),
1661-
Unique {
1662-
is_primary,
1663-
characteristics,
1664-
} => {
1665-
write!(f, "{}", if *is_primary { "PRIMARY KEY" } else { "UNIQUE" })?;
1666-
if let Some(characteristics) = characteristics {
1689+
PrimaryKey(constraint) => {
1690+
write!(f, "PRIMARY KEY")?;
1691+
if let Some(characteristics) = &constraint.characteristics {
1692+
write!(f, " {characteristics}")?;
1693+
}
1694+
Ok(())
1695+
}
1696+
Unique(constraint) => {
1697+
write!(f, "UNIQUE")?;
1698+
if let Some(characteristics) = &constraint.characteristics {
16671699
write!(f, " {characteristics}")?;
16681700
}
16691701
Ok(())

src/ast/query.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2506,6 +2506,16 @@ pub struct OrderByExpr {
25062506
pub with_fill: Option<WithFill>,
25072507
}
25082508

2509+
impl From<Ident> for OrderByExpr {
2510+
fn from(ident: Ident) -> Self {
2511+
OrderByExpr {
2512+
expr: Expr::Identifier(ident),
2513+
options: OrderByOptions::default(),
2514+
with_fill: None,
2515+
}
2516+
}
2517+
}
2518+
25092519
impl fmt::Display for OrderByExpr {
25102520
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
25112521
write!(f, "{}{}", self.expr, self.options)?;
@@ -2574,7 +2584,7 @@ impl fmt::Display for InterpolateExpr {
25742584
}
25752585
}
25762586

2577-
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2587+
#[derive(Default, Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
25782588
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25792589
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
25802590
pub struct OrderByOptions {

src/ast/spans.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -809,7 +809,8 @@ impl Spanned for RaiseStatementValue {
809809
/// - [ColumnOption::Null]
810810
/// - [ColumnOption::NotNull]
811811
/// - [ColumnOption::Comment]
812-
/// - [ColumnOption::Unique]¨
812+
/// - [ColumnOption::PrimaryKey]
813+
/// - [ColumnOption::Unique]
813814
/// - [ColumnOption::DialectSpecific]
814815
/// - [ColumnOption::Generated]
815816
impl Spanned for ColumnOption {
@@ -821,7 +822,8 @@ impl Spanned for ColumnOption {
821822
ColumnOption::Materialized(expr) => expr.span(),
822823
ColumnOption::Ephemeral(expr) => expr.as_ref().map_or(Span::empty(), |e| e.span()),
823824
ColumnOption::Alias(expr) => expr.span(),
824-
ColumnOption::Unique { .. } => Span::empty(),
825+
ColumnOption::PrimaryKey(constraint) => constraint.span(),
826+
ColumnOption::Unique(constraint) => constraint.span(),
825827
ColumnOption::ForeignKey {
826828
foreign_table,
827829
referred_columns,

src/parser/mod.rs

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7919,7 +7919,7 @@ impl<'a> Parser<'a> {
79197919
}
79207920

79217921
pub fn parse_column_def(&mut self) -> Result<ColumnDef, ParserError> {
7922-
let name = self.parse_identifier()?;
7922+
let col_name = self.parse_identifier()?;
79237923
let data_type = if self.is_column_type_sqlite_unspecified() {
79247924
DataType::Unspecified
79257925
} else {
@@ -7929,22 +7929,22 @@ impl<'a> Parser<'a> {
79297929
loop {
79307930
if self.parse_keyword(Keyword::CONSTRAINT) {
79317931
let name = Some(self.parse_identifier()?);
7932-
if let Some(option) = self.parse_optional_column_option()? {
7932+
if let Some(option) = self.parse_optional_column_option(&col_name)? {
79337933
options.push(ColumnOptionDef { name, option });
79347934
} else {
79357935
return self.expected(
79367936
"constraint details after CONSTRAINT <name>",
79377937
self.peek_token(),
79387938
);
79397939
}
7940-
} else if let Some(option) = self.parse_optional_column_option()? {
7940+
} else if let Some(option) = self.parse_optional_column_option(&col_name)? {
79417941
options.push(ColumnOptionDef { name: None, option });
79427942
} else {
79437943
break;
79447944
};
79457945
}
79467946
Ok(ColumnDef {
7947-
name,
7947+
name: col_name,
79487948
data_type,
79497949
options,
79507950
})
@@ -7973,20 +7973,26 @@ impl<'a> Parser<'a> {
79737973
}
79747974
}
79757975

7976-
pub fn parse_optional_column_option(&mut self) -> Result<Option<ColumnOption>, ParserError> {
7976+
pub fn parse_optional_column_option(
7977+
&mut self,
7978+
column_name: &Ident,
7979+
) -> Result<Option<ColumnOption>, ParserError> {
79777980
if let Some(option) = self.dialect.parse_column_option(self)? {
79787981
return option;
79797982
}
79807983

79817984
self.with_state(
79827985
ColumnDefinition,
79837986
|parser| -> Result<Option<ColumnOption>, ParserError> {
7984-
parser.parse_optional_column_option_inner()
7987+
parser.parse_optional_column_option_inner(column_name)
79857988
},
79867989
)
79877990
}
79887991

7989-
fn parse_optional_column_option_inner(&mut self) -> Result<Option<ColumnOption>, ParserError> {
7992+
fn parse_optional_column_option_inner(
7993+
&mut self,
7994+
column_name: &Ident,
7995+
) -> Result<Option<ColumnOption>, ParserError> {
79907996
if self.parse_keywords(&[Keyword::CHARACTER, Keyword::SET]) {
79917997
Ok(Some(ColumnOption::CharacterSet(
79927998
self.parse_object_name(false)?,
@@ -8029,16 +8035,32 @@ impl<'a> Parser<'a> {
80298035
}
80308036
} else if self.parse_keywords(&[Keyword::PRIMARY, Keyword::KEY]) {
80318037
let characteristics = self.parse_constraint_characteristics()?;
8032-
Ok(Some(ColumnOption::Unique {
8033-
is_primary: true,
8034-
characteristics,
8035-
}))
8038+
Ok(Some(
8039+
PrimaryKeyConstraint {
8040+
name: None,
8041+
index_name: None,
8042+
index_type: None,
8043+
columns: vec![column_name.clone().into()],
8044+
index_options: vec![],
8045+
characteristics,
8046+
}
8047+
.into(),
8048+
))
80368049
} else if self.parse_keyword(Keyword::UNIQUE) {
80378050
let characteristics = self.parse_constraint_characteristics()?;
8038-
Ok(Some(ColumnOption::Unique {
8039-
is_primary: false,
8040-
characteristics,
8041-
}))
8051+
Ok(Some(
8052+
UniqueConstraint {
8053+
name: None,
8054+
index_name: None,
8055+
index_type_display: KeyOrIndexDisplay::None,
8056+
index_type: None,
8057+
columns: vec![column_name.clone().into()],
8058+
index_options: vec![],
8059+
characteristics,
8060+
nulls_distinct: NullsDistinctOption::None,
8061+
}
8062+
.into(),
8063+
))
80428064
} else if self.parse_keyword(Keyword::REFERENCES) {
80438065
let foreign_table = self.parse_object_name(false)?;
80448066
// PostgreSQL allows omitting the column list and
@@ -9046,7 +9068,7 @@ impl<'a> Parser<'a> {
90469068
let new_name = self.parse_identifier()?;
90479069
let data_type = self.parse_data_type()?;
90489070
let mut options = vec![];
9049-
while let Some(option) = self.parse_optional_column_option()? {
9071+
while let Some(option) = self.parse_optional_column_option(&new_name)? {
90509072
options.push(option);
90519073
}
90529074

@@ -9064,7 +9086,7 @@ impl<'a> Parser<'a> {
90649086
let col_name = self.parse_identifier()?;
90659087
let data_type = self.parse_data_type()?;
90669088
let mut options = vec![];
9067-
while let Some(option) = self.parse_optional_column_option()? {
9089+
while let Some(option) = self.parse_optional_column_option(&col_name)? {
90689090
options.push(option);
90699091
}
90709092

@@ -11325,7 +11347,7 @@ impl<'a> Parser<'a> {
1132511347
/// Parses a column definition within a view.
1132611348
fn parse_view_column(&mut self) -> Result<ViewColumnDef, ParserError> {
1132711349
let name = self.parse_identifier()?;
11328-
let options = self.parse_view_column_options()?;
11350+
let options = self.parse_view_column_options(&name)?;
1132911351
let data_type = if dialect_of!(self is ClickHouseDialect) {
1133011352
Some(self.parse_data_type()?)
1133111353
} else {
@@ -11338,10 +11360,13 @@ impl<'a> Parser<'a> {
1133811360
})
1133911361
}
1134011362

11341-
fn parse_view_column_options(&mut self) -> Result<Option<ColumnOptions>, ParserError> {
11363+
fn parse_view_column_options(
11364+
&mut self,
11365+
column_name: &Ident,
11366+
) -> Result<Option<ColumnOptions>, ParserError> {
1134211367
let mut options = Vec::new();
1134311368
loop {
11344-
let option = self.parse_optional_column_option()?;
11369+
let option = self.parse_optional_column_option(column_name)?;
1134511370
if let Some(option) = option {
1134611371
options.push(option);
1134711372
} else {

tests/sqlparser_common.rs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3763,21 +3763,31 @@ fn parse_create_table() {
37633763
},
37643764
ColumnOptionDef {
37653765
name: Some("pkey".into()),
3766-
option: ColumnOption::Unique {
3767-
is_primary: true,
3768-
characteristics: None
3769-
},
3766+
option: ColumnOption::PrimaryKey(PrimaryKeyConstraint {
3767+
name: None,
3768+
index_name: None,
3769+
index_type: None,
3770+
columns: vec!["constrained".into()],
3771+
index_options: vec![],
3772+
characteristics: None,
3773+
}),
37703774
},
37713775
ColumnOptionDef {
37723776
name: None,
37733777
option: ColumnOption::NotNull,
37743778
},
37753779
ColumnOptionDef {
37763780
name: None,
3777-
option: ColumnOption::Unique {
3778-
is_primary: false,
3779-
characteristics: None
3780-
},
3781+
option: ColumnOption::Unique(UniqueConstraint {
3782+
name: None,
3783+
index_name: None,
3784+
index_type_display: KeyOrIndexDisplay::None,
3785+
index_type: None,
3786+
columns: vec!["constrained".into()],
3787+
index_options: vec![],
3788+
characteristics: None,
3789+
nulls_distinct: NullsDistinctOption::None,
3790+
}),
37813791
},
37823792
ColumnOptionDef {
37833793
name: None,
@@ -4086,10 +4096,16 @@ fn parse_create_table_column_constraint_characteristics() {
40864096
data_type: DataType::Int(None),
40874097
options: vec![ColumnOptionDef {
40884098
name: None,
4089-
option: ColumnOption::Unique {
4090-
is_primary: false,
4091-
characteristics: expected_value
4092-
}
4099+
option: ColumnOption::Unique(UniqueConstraint {
4100+
name: None,
4101+
index_name: None,
4102+
index_type_display: KeyOrIndexDisplay::None,
4103+
index_type: None,
4104+
columns: vec!["a".into()],
4105+
index_options: vec![],
4106+
characteristics: expected_value,
4107+
nulls_distinct: NullsDistinctOption::None,
4108+
})
40934109
}]
40944110
}],
40954111
"{message}"

0 commit comments

Comments
 (0)