Skip to content

Commit 2866972

Browse files
author
Alex.Mo
committed
introduce OperatorClass
1 parent 5d6ff6a commit 2866972

File tree

8 files changed

+226
-126
lines changed

8 files changed

+226
-126
lines changed

src/ast/dml.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ pub use super::ddl::{ColumnDef, TableConstraint};
3434
use super::{
3535
display_comma_separated, display_separated, query::InputFormatClause, Assignment, ClusteredBy,
3636
CommentDef, Expr, FileFormat, FromTable, HiveDistributionStyle, HiveFormat, HiveIOFormat,
37-
HiveRowFormat, Ident, InsertAliases, MysqlInsertPriority, ObjectName, OnCommit, OnInsert,
38-
OneOrManyWithParens, OrderByExpr, Query, RowAccessPolicy, SelectItem, Setting, SqlOption,
39-
SqliteOnConflict, StorageSerializationPolicy, TableEngine, TableObject, TableWithJoins, Tag,
40-
WrappedCollection,
37+
HiveRowFormat, Ident, IndexExpr, InsertAliases, MysqlInsertPriority, ObjectName, OnCommit,
38+
OnInsert, OneOrManyWithParens, OrderByExpr, Query, RowAccessPolicy, SelectItem, Setting,
39+
SqlOption, SqliteOnConflict, StorageSerializationPolicy, TableEngine, TableObject,
40+
TableWithJoins, Tag, WrappedCollection,
4141
};
4242

4343
/// CREATE INDEX statement.
@@ -50,7 +50,7 @@ pub struct CreateIndex {
5050
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
5151
pub table_name: ObjectName,
5252
pub using: Option<Ident>,
53-
pub columns: Vec<OrderByExpr>,
53+
pub columns: Vec<IndexExpr>,
5454
pub unique: bool,
5555
pub concurrently: bool,
5656
pub if_not_exists: bool,

src/ast/mod.rs

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8697,27 +8697,66 @@ pub enum CopyIntoSnowflakeKind {
86978697
/// [1]: https://dev.mysql.com/doc/refman/8.3/en/create-index.html
86988698
/// [2]: https://www.postgresql.org/docs/17/sql-createindex.html
86998699
/// [3]: https://dev.mysql.com/doc/refman/8.3/en/create-table.html
8700-
87018700
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
87028701
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
87038702
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
87048703
pub struct IndexExpr {
87058704
pub expr: Expr,
87068705
pub collation: Option<ObjectName>,
8707-
pub operator_class: Option<Expr>,
8708-
pub order_options: OrderByOptions,
8706+
/// The operator class identifies the operators to be used by the index for that column.
8707+
/// See: <https://www.postgresql.org/docs/17/indexes-opclass.html>
8708+
pub opclass: Option<OperatorClass>,
8709+
pub sort_options: OrderByOptions,
87098710
}
87108711

87118712
impl fmt::Display for IndexExpr {
87128713
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
87138714
write!(f, "{}", self.expr)?;
87148715
if let Some(collation) = &self.collation {
8715-
write!(f, "{collation}")?;
8716+
write!(f, " {collation}")?;
8717+
}
8718+
if let Some(opclass) = &self.opclass {
8719+
write!(f, " {opclass}")?;
87168720
}
8717-
if let Some(operator) = &self.operator_class {
8718-
write!(f, "{operator}")?;
8721+
write!(f, "{}", self.sort_options)
8722+
}
8723+
}
8724+
8725+
/// Operator class
8726+
///
8727+
/// This structure used here [`PostgreSQL` CREATE INDEX][1].
8728+
///
8729+
/// [1]: https://www.postgresql.org/docs/17/indexes-opclass.html
8730+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
8731+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
8732+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
8733+
pub struct OperatorClass {
8734+
pub name: Ident,
8735+
pub parameters: Vec<OperatorClassParameter>,
8736+
}
8737+
8738+
impl fmt::Display for OperatorClass {
8739+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
8740+
write!(f, "{}", self.name)?;
8741+
if !self.parameters.is_empty() {
8742+
write!(f, "({})", display_comma_separated(&self.parameters))?;
87198743
}
8720-
write!(f, "{}", self.order_options)
8744+
8745+
Ok(())
8746+
}
8747+
}
8748+
8749+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
8750+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
8751+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
8752+
pub struct OperatorClassParameter {
8753+
pub name: Ident,
8754+
pub value: Expr,
8755+
}
8756+
8757+
impl fmt::Display for OperatorClassParameter {
8758+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
8759+
write!(f, "{} = {}", self.name, self.value)
87218760
}
87228761
}
87238762

src/ast/spans.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2183,8 +2183,8 @@ impl Spanned for IndexExpr {
21832183
let IndexExpr {
21842184
expr,
21852185
collation: _,
2186-
operator_class: _,
2187-
order_options: _,
2186+
opclass: _,
2187+
sort_options: _,
21882188
} = self;
21892189

21902190
union_spans(core::iter::once(expr.span()))

src/parser/mod.rs

Lines changed: 61 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -6407,10 +6407,7 @@ impl<'a> Parser<'a> {
64076407
} else {
64086408
None
64096409
};
6410-
self.expect_token(&Token::LParen)?;
6411-
let columns = self.parse_comma_separated(Parser::parse_order_by_expr)?;
6412-
self.expect_token(&Token::RParen)?;
6413-
6410+
let columns = self.parse_index_exprs()?;
64146411
let include = if self.parse_keyword(Keyword::INCLUDE) {
64156412
self.expect_token(&Token::LParen)?;
64166413
let columns = self.parse_comma_separated(|p| p.parse_identifier())?;
@@ -7439,7 +7436,6 @@ impl<'a> Parser<'a> {
74397436
// optional index name
74407437
let index_name = self.parse_optional_indent()?;
74417438
let index_type = self.parse_optional_using_then_index_type()?;
7442-
74437439
let index_exprs = self.parse_index_exprs()?;
74447440
let index_options = self.parse_index_options()?;
74457441
let characteristics = self.parse_constraint_characteristics()?;
@@ -7646,10 +7642,14 @@ impl<'a> Parser<'a> {
76467642
}
76477643
}
76487644

7645+
/// Parse index expressions, like:
7646+
/// `(column_name [COLLATE collation] [opclass [ ( opclass_parameter = value [, ... ] )] [ASC | DESC] [NULLS {FIRST | LAST}]] [, ... ])`
76497647
pub fn parse_index_exprs(&mut self) -> Result<Vec<IndexExpr>, ParserError> {
76507648
self.parse_parenthesized(|p| p.parse_comma_separated(Parser::parse_index_expr))
76517649
}
76527650

7651+
/// Parse index expression, like:
7652+
/// `column_name [COLLATE collation] [opclass [ ( opclass_parameter = value [, ... ] )] [ASC | DESC] [NULLS {FIRST | LAST}]`
76537653
pub fn parse_index_expr(&mut self) -> Result<IndexExpr, ParserError> {
76547654
let expr = self.parse_expr()?;
76557655
let collation = if self.parse_keyword(Keyword::COLLATE) {
@@ -7658,27 +7658,47 @@ impl<'a> Parser<'a> {
76587658
None
76597659
};
76607660

7661-
let (operator_class, order_options) = if self.peek_keyword(Keyword::ASC)
7661+
let (opclass, sort_options) = if self.peek_keyword(Keyword::ASC)
76627662
|| self.peek_keyword(Keyword::DESC)
76637663
|| self.peek_keyword(Keyword::NULLS)
76647664
{
7665-
let order_options = self.parse_order_by_options()?;
7666-
(None, order_options)
7665+
let sort_options = self.parse_order_by_options()?;
7666+
(None, sort_options)
76677667
} else {
7668-
let operator_class = self.maybe_parse(|p| p.parse_expr())?;
7668+
let opclass = self.maybe_parse(|p| p.parse_operator_class())?;
76697669

7670-
let order_options = self.parse_order_by_options()?;
7671-
(operator_class, order_options)
7670+
let sort_options = self.parse_order_by_options()?;
7671+
(opclass, sort_options)
76727672
};
76737673

76747674
Ok(IndexExpr {
76757675
expr,
76767676
collation,
7677-
operator_class,
7678-
order_options,
7677+
opclass,
7678+
sort_options,
76797679
})
76807680
}
76817681

7682+
fn parse_operator_class(&mut self) -> Result<OperatorClass, ParserError> {
7683+
let name = self.parse_identifier()?;
7684+
let parameters = if self.peek_token() == Token::LParen {
7685+
self.parse_parenthesized(|p| {
7686+
p.parse_comma_separated(Parser::parse_operator_class_param)
7687+
})?
7688+
} else {
7689+
vec![]
7690+
};
7691+
7692+
Ok(OperatorClass { name, parameters })
7693+
}
7694+
7695+
fn parse_operator_class_param(&mut self) -> Result<OperatorClassParameter, ParserError> {
7696+
let name = self.parse_identifier()?;
7697+
self.expect_token(&Token::Eq)?;
7698+
let value = self.parse_expr()?;
7699+
Ok(OperatorClassParameter { name, value })
7700+
}
7701+
76827702
/// Parse `[ident]`, mostly `ident` is name, like:
76837703
/// `window_name`, `index_name`, ...
76847704
pub fn parse_optional_indent(&mut self) -> Result<Option<Ident>, ParserError> {
@@ -14721,8 +14741,6 @@ impl Word {
1472114741

1472214742
#[cfg(test)]
1472314743
mod tests {
14724-
use std::vec;
14725-
1472614744
use crate::test_utils::{all_dialects, TestedDialects};
1472714745

1472814746
use super::*;
@@ -15176,8 +15194,8 @@ mod tests {
1517615194
index_exprs: vec![IndexExpr {
1517715195
expr: Expr::Identifier(Ident::new("c1")),
1517815196
collation: None,
15179-
operator_class: None,
15180-
order_options: OrderByOptions {
15197+
opclass: None,
15198+
sort_options: OrderByOptions {
1518115199
asc: None,
1518215200
nulls_first: None,
1518315201
},
@@ -15195,8 +15213,8 @@ mod tests {
1519515213
index_exprs: vec![IndexExpr {
1519615214
expr: Expr::Identifier(Ident::new("c1")),
1519715215
collation: None,
15198-
operator_class: None,
15199-
order_options: OrderByOptions {
15216+
opclass: None,
15217+
sort_options: OrderByOptions {
1520015218
asc: None,
1520115219
nulls_first: None,
1520215220
},
@@ -15215,17 +15233,17 @@ mod tests {
1521515233
IndexExpr {
1521615234
expr: Expr::Identifier(Ident::new("c1")),
1521715235
collation: None,
15218-
operator_class: None,
15219-
order_options: OrderByOptions {
15236+
opclass: None,
15237+
sort_options: OrderByOptions {
1522015238
asc: None,
1522115239
nulls_first: None,
1522215240
},
1522315241
},
1522415242
IndexExpr {
1522515243
expr: Expr::Identifier(Ident::new("c2")),
1522615244
collation: None,
15227-
operator_class: None,
15228-
order_options: OrderByOptions {
15245+
opclass: None,
15246+
sort_options: OrderByOptions {
1522915247
asc: None,
1523015248
nulls_first: None,
1523115249
},
@@ -15244,8 +15262,8 @@ mod tests {
1524415262
index_exprs: vec![IndexExpr {
1524515263
expr: Expr::Identifier(Ident::new("c1")),
1524615264
collation: None,
15247-
operator_class: None,
15248-
order_options: OrderByOptions {
15265+
opclass: None,
15266+
sort_options: OrderByOptions {
1524915267
asc: None,
1525015268
nulls_first: None,
1525115269
},
@@ -15263,8 +15281,8 @@ mod tests {
1526315281
index_exprs: vec![IndexExpr {
1526415282
expr: Expr::Identifier(Ident::new("c1")),
1526515283
collation: None,
15266-
operator_class: None,
15267-
order_options: OrderByOptions {
15284+
opclass: None,
15285+
sort_options: OrderByOptions {
1526815286
asc: None,
1526915287
nulls_first: None,
1527015288
},
@@ -15282,8 +15300,8 @@ mod tests {
1528215300
index_exprs: vec![IndexExpr {
1528315301
expr: Expr::Identifier(Ident::new("c1")),
1528415302
collation: None,
15285-
operator_class: None,
15286-
order_options: OrderByOptions {
15303+
opclass: None,
15304+
sort_options: OrderByOptions {
1528715305
asc: None,
1528815306
nulls_first: None,
1528915307
},
@@ -15301,8 +15319,8 @@ mod tests {
1530115319
index_exprs: vec![IndexExpr {
1530215320
expr: Expr::Identifier(Ident::new("c1")),
1530315321
collation: None,
15304-
operator_class: None,
15305-
order_options: OrderByOptions {
15322+
opclass: None,
15323+
sort_options: OrderByOptions {
1530615324
asc: None,
1530715325
nulls_first: None,
1530815326
},
@@ -15319,49 +15337,25 @@ mod tests {
1531915337
index_type: None,
1532015338
index_exprs: vec![
1532115339
IndexExpr {
15322-
expr: Expr::Function(Function {
15323-
name: ObjectName::from(vec![Ident::new("c1")]),
15324-
uses_odbc_syntax: false,
15325-
parameters: FunctionArguments::None,
15326-
args: FunctionArguments::List(FunctionArgumentList {
15327-
duplicate_treatment: None,
15328-
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
15329-
Expr::Value(crate::test_utils::number("10"))
15330-
)),],
15331-
clauses: vec![],
15332-
}),
15333-
filter: None,
15334-
null_treatment: None,
15335-
over: None,
15336-
within_group: vec![],
15337-
}),
15340+
expr: crate::test_utils::call(
15341+
"c1",
15342+
[Expr::Value(crate::test_utils::number("10"))]
15343+
),
1533815344
collation: None,
15339-
operator_class: None,
15340-
order_options: OrderByOptions {
15345+
opclass: None,
15346+
sort_options: OrderByOptions {
1534115347
asc: None,
1534215348
nulls_first: None,
1534315349
},
1534415350
},
1534515351
IndexExpr {
15346-
expr: Expr::Nested(Box::new(Expr::Function(Function {
15347-
name: ObjectName::from(vec![Ident::new("LOWER")]),
15348-
uses_odbc_syntax: false,
15349-
parameters: FunctionArguments::None,
15350-
args: FunctionArguments::List(FunctionArgumentList {
15351-
duplicate_treatment: None,
15352-
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
15353-
Expr::Identifier(Ident::new("c2"))
15354-
)),],
15355-
clauses: vec![],
15356-
}),
15357-
filter: None,
15358-
null_treatment: None,
15359-
over: None,
15360-
within_group: vec![],
15361-
}))),
15352+
expr: Expr::Nested(Box::new(crate::test_utils::call(
15353+
"LOWER",
15354+
[Expr::Identifier(Ident::new("c2"))]
15355+
))),
1536215356
collation: None,
15363-
operator_class: None,
15364-
order_options: OrderByOptions {
15357+
opclass: None,
15358+
sort_options: OrderByOptions {
1536515359
asc: Some(false),
1536615360
nulls_first: None,
1536715361
}

src/test_utils.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,3 +426,30 @@ pub fn call(function: &str, args: impl IntoIterator<Item = Expr>) -> Expr {
426426
within_group: vec![],
427427
})
428428
}
429+
430+
pub fn call_with_named_arg(
431+
function: &str,
432+
args: impl IntoIterator<Item = (Ident, Expr, FunctionArgOperator)>,
433+
) -> Expr {
434+
Expr::Function(Function {
435+
name: ObjectName::from(vec![Ident::new(function)]),
436+
uses_odbc_syntax: false,
437+
parameters: FunctionArguments::None,
438+
args: FunctionArguments::List(FunctionArgumentList {
439+
duplicate_treatment: None,
440+
args: args
441+
.into_iter()
442+
.map(|(name, arg, operator)| FunctionArg::Named {
443+
name,
444+
arg: FunctionArgExpr::Expr(arg),
445+
operator,
446+
})
447+
.collect(),
448+
clauses: vec![],
449+
}),
450+
filter: None,
451+
null_treatment: None,
452+
over: None,
453+
within_group: vec![],
454+
})
455+
}

0 commit comments

Comments
 (0)