Skip to content

Commit

Permalink
Support create index with clause (#1389)
Browse files Browse the repository at this point in the history
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
  • Loading branch information
3 people authored Sep 1, 2024
1 parent d64beea commit 4d52ee7
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/ast/dml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ pub struct CreateIndex {
pub if_not_exists: bool,
pub include: Vec<Ident>,
pub nulls_distinct: Option<bool>,
/// WITH clause: <https://www.postgresql.org/docs/current/sql-createindex.html>
pub with: Vec<Expr>,
pub predicate: Option<Expr>,
}

Expand Down Expand Up @@ -83,6 +85,9 @@ impl Display for CreateIndex {
write!(f, " NULLS NOT DISTINCT")?;
}
}
if !self.with.is_empty() {
write!(f, " WITH ({})", display_comma_separated(&self.with))?;
}
if let Some(predicate) = &self.predicate {
write!(f, " WHERE {predicate}")?;
}
Expand Down
4 changes: 4 additions & 0 deletions src/dialect/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,8 @@ impl Dialect for GenericDialect {
fn allow_extract_single_quotes(&self) -> bool {
true
}

fn supports_create_index_with_clause(&self) -> bool {
true
}
}
6 changes: 6 additions & 0 deletions src/dialect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,12 @@ pub trait Dialect: Debug + Any {
fn allow_extract_single_quotes(&self) -> bool {
false
}

/// Does the dialect support with clause in create index statement?
/// e.g. `CREATE INDEX idx ON t WITH (key = value, key2)`
fn supports_create_index_with_clause(&self) -> bool {
false
}
}

/// This represents the operators for which precedence must be defined
Expand Down
4 changes: 4 additions & 0 deletions src/dialect/postgresql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ impl Dialect for PostgreSqlDialect {
fn allow_extract_single_quotes(&self) -> bool {
true
}

fn supports_create_index_with_clause(&self) -> bool {
true
}
}

pub fn parse_comment(parser: &mut Parser) -> Result<Statement, ParserError> {
Expand Down
12 changes: 12 additions & 0 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5324,6 +5324,17 @@ impl<'a> Parser<'a> {
None
};

let with = if self.dialect.supports_create_index_with_clause()
&& self.parse_keyword(Keyword::WITH)
{
self.expect_token(&Token::LParen)?;
let with_params = self.parse_comma_separated(Parser::parse_expr)?;
self.expect_token(&Token::RParen)?;
with_params
} else {
Vec::new()
};

let predicate = if self.parse_keyword(Keyword::WHERE) {
Some(self.parse_expr()?)
} else {
Expand All @@ -5340,6 +5351,7 @@ impl<'a> Parser<'a> {
if_not_exists,
include,
nulls_distinct,
with,
predicate,
}))
}
Expand Down
47 changes: 47 additions & 0 deletions tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7554,6 +7554,7 @@ fn test_create_index_with_using_function() {
if_not_exists,
include,
nulls_distinct: None,
with,
predicate: None,
}) => {
assert_eq!("idx_name", name.to_string());
Expand All @@ -7564,6 +7565,52 @@ fn test_create_index_with_using_function() {
assert!(!concurrently);
assert!(if_not_exists);
assert!(include.is_empty());
assert!(with.is_empty());
}
_ => unreachable!(),
}
}

#[test]
fn test_create_index_with_with_clause() {
let sql = "CREATE UNIQUE INDEX title_idx ON films(title) WITH (fillfactor = 70, single_param)";
let indexed_columns = vec![OrderByExpr {
expr: Expr::Identifier(Ident::new("title")),
asc: None,
nulls_first: None,
with_fill: None,
}];
let with_parameters = vec![
Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::new("fillfactor"))),
op: BinaryOperator::Eq,
right: Box::new(Expr::Value(number("70"))),
},
Expr::Identifier(Ident::new("single_param")),
];
let dialects = all_dialects_where(|d| d.supports_create_index_with_clause());
match dialects.verified_stmt(sql) {
Statement::CreateIndex(CreateIndex {
name: Some(name),
table_name,
using: None,
columns,
unique,
concurrently,
if_not_exists,
include,
nulls_distinct: None,
with,
predicate: None,
}) => {
pretty_assertions::assert_eq!("title_idx", name.to_string());
pretty_assertions::assert_eq!("films", table_name.to_string());
pretty_assertions::assert_eq!(indexed_columns, columns);
assert!(unique);
assert!(!concurrently);
assert!(!if_not_exists);
assert!(include.is_empty());
pretty_assertions::assert_eq!(with_parameters, with);
}
_ => unreachable!(),
}
Expand Down
14 changes: 14 additions & 0 deletions tests/sqlparser_postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2251,6 +2251,7 @@ fn parse_create_index() {
if_not_exists,
nulls_distinct: None,
include,
with,
predicate: None,
}) => {
assert_eq_vec(&["my_index"], &name);
Expand All @@ -2261,6 +2262,7 @@ fn parse_create_index() {
assert!(if_not_exists);
assert_eq_vec(&["col1", "col2"], &columns);
assert!(include.is_empty());
assert!(with.is_empty());
}
_ => unreachable!(),
}
Expand All @@ -2280,6 +2282,7 @@ fn parse_create_anonymous_index() {
if_not_exists,
include,
nulls_distinct: None,
with,
predicate: None,
}) => {
assert_eq!(None, name);
Expand All @@ -2290,6 +2293,7 @@ fn parse_create_anonymous_index() {
assert!(!if_not_exists);
assert_eq_vec(&["col1", "col2"], &columns);
assert!(include.is_empty());
assert!(with.is_empty());
}
_ => unreachable!(),
}
Expand All @@ -2309,6 +2313,7 @@ fn parse_create_index_concurrently() {
if_not_exists,
include,
nulls_distinct: None,
with,
predicate: None,
}) => {
assert_eq_vec(&["my_index"], &name);
Expand All @@ -2319,6 +2324,7 @@ fn parse_create_index_concurrently() {
assert!(if_not_exists);
assert_eq_vec(&["col1", "col2"], &columns);
assert!(include.is_empty());
assert!(with.is_empty());
}
_ => unreachable!(),
}
Expand All @@ -2338,6 +2344,7 @@ fn parse_create_index_with_predicate() {
if_not_exists,
include,
nulls_distinct: None,
with,
predicate: Some(_),
}) => {
assert_eq_vec(&["my_index"], &name);
Expand All @@ -2348,6 +2355,7 @@ fn parse_create_index_with_predicate() {
assert!(if_not_exists);
assert_eq_vec(&["col1", "col2"], &columns);
assert!(include.is_empty());
assert!(with.is_empty());
}
_ => unreachable!(),
}
Expand All @@ -2367,6 +2375,7 @@ fn parse_create_index_with_include() {
if_not_exists,
include,
nulls_distinct: None,
with,
predicate: None,
}) => {
assert_eq_vec(&["my_index"], &name);
Expand All @@ -2377,6 +2386,7 @@ fn parse_create_index_with_include() {
assert!(if_not_exists);
assert_eq_vec(&["col1", "col2"], &columns);
assert_eq_vec(&["col3"], &include);
assert!(with.is_empty());
}
_ => unreachable!(),
}
Expand All @@ -2396,6 +2406,7 @@ fn parse_create_index_with_nulls_distinct() {
if_not_exists,
include,
nulls_distinct: Some(nulls_distinct),
with,
predicate: None,
}) => {
assert_eq_vec(&["my_index"], &name);
Expand All @@ -2407,6 +2418,7 @@ fn parse_create_index_with_nulls_distinct() {
assert_eq_vec(&["col1", "col2"], &columns);
assert!(include.is_empty());
assert!(!nulls_distinct);
assert!(with.is_empty());
}
_ => unreachable!(),
}
Expand All @@ -2423,6 +2435,7 @@ fn parse_create_index_with_nulls_distinct() {
if_not_exists,
include,
nulls_distinct: Some(nulls_distinct),
with,
predicate: None,
}) => {
assert_eq_vec(&["my_index"], &name);
Expand All @@ -2434,6 +2447,7 @@ fn parse_create_index_with_nulls_distinct() {
assert_eq_vec(&["col1", "col2"], &columns);
assert!(include.is_empty());
assert!(nulls_distinct);
assert!(with.is_empty());
}
_ => unreachable!(),
}
Expand Down

0 comments on commit 4d52ee7

Please sign in to comment.