mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-09-23 06:02:30 +00:00
Support create index with clause (#1389)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com> Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
This commit is contained in:
parent
d64beea4d4
commit
4d52ee7280
7 changed files with 92 additions and 0 deletions
|
@ -45,6 +45,8 @@ pub struct CreateIndex {
|
||||||
pub if_not_exists: bool,
|
pub if_not_exists: bool,
|
||||||
pub include: Vec<Ident>,
|
pub include: Vec<Ident>,
|
||||||
pub nulls_distinct: Option<bool>,
|
pub nulls_distinct: Option<bool>,
|
||||||
|
/// WITH clause: <https://www.postgresql.org/docs/current/sql-createindex.html>
|
||||||
|
pub with: Vec<Expr>,
|
||||||
pub predicate: Option<Expr>,
|
pub predicate: Option<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +85,9 @@ impl Display for CreateIndex {
|
||||||
write!(f, " NULLS NOT DISTINCT")?;
|
write!(f, " NULLS NOT DISTINCT")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !self.with.is_empty() {
|
||||||
|
write!(f, " WITH ({})", display_comma_separated(&self.with))?;
|
||||||
|
}
|
||||||
if let Some(predicate) = &self.predicate {
|
if let Some(predicate) = &self.predicate {
|
||||||
write!(f, " WHERE {predicate}")?;
|
write!(f, " WHERE {predicate}")?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,4 +86,8 @@ impl Dialect for GenericDialect {
|
||||||
fn allow_extract_single_quotes(&self) -> bool {
|
fn allow_extract_single_quotes(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn supports_create_index_with_clause(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -509,6 +509,12 @@ pub trait Dialect: Debug + Any {
|
||||||
fn allow_extract_single_quotes(&self) -> bool {
|
fn allow_extract_single_quotes(&self) -> bool {
|
||||||
false
|
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
|
/// This represents the operators for which precedence must be defined
|
||||||
|
|
|
@ -162,6 +162,10 @@ impl Dialect for PostgreSqlDialect {
|
||||||
fn allow_extract_single_quotes(&self) -> bool {
|
fn allow_extract_single_quotes(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn supports_create_index_with_clause(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_comment(parser: &mut Parser) -> Result<Statement, ParserError> {
|
pub fn parse_comment(parser: &mut Parser) -> Result<Statement, ParserError> {
|
||||||
|
|
|
@ -5324,6 +5324,17 @@ impl<'a> Parser<'a> {
|
||||||
None
|
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) {
|
let predicate = if self.parse_keyword(Keyword::WHERE) {
|
||||||
Some(self.parse_expr()?)
|
Some(self.parse_expr()?)
|
||||||
} else {
|
} else {
|
||||||
|
@ -5340,6 +5351,7 @@ impl<'a> Parser<'a> {
|
||||||
if_not_exists,
|
if_not_exists,
|
||||||
include,
|
include,
|
||||||
nulls_distinct,
|
nulls_distinct,
|
||||||
|
with,
|
||||||
predicate,
|
predicate,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
@ -7554,6 +7554,7 @@ fn test_create_index_with_using_function() {
|
||||||
if_not_exists,
|
if_not_exists,
|
||||||
include,
|
include,
|
||||||
nulls_distinct: None,
|
nulls_distinct: None,
|
||||||
|
with,
|
||||||
predicate: None,
|
predicate: None,
|
||||||
}) => {
|
}) => {
|
||||||
assert_eq!("idx_name", name.to_string());
|
assert_eq!("idx_name", name.to_string());
|
||||||
|
@ -7564,6 +7565,52 @@ fn test_create_index_with_using_function() {
|
||||||
assert!(!concurrently);
|
assert!(!concurrently);
|
||||||
assert!(if_not_exists);
|
assert!(if_not_exists);
|
||||||
assert!(include.is_empty());
|
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!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -2251,6 +2251,7 @@ fn parse_create_index() {
|
||||||
if_not_exists,
|
if_not_exists,
|
||||||
nulls_distinct: None,
|
nulls_distinct: None,
|
||||||
include,
|
include,
|
||||||
|
with,
|
||||||
predicate: None,
|
predicate: None,
|
||||||
}) => {
|
}) => {
|
||||||
assert_eq_vec(&["my_index"], &name);
|
assert_eq_vec(&["my_index"], &name);
|
||||||
|
@ -2261,6 +2262,7 @@ fn parse_create_index() {
|
||||||
assert!(if_not_exists);
|
assert!(if_not_exists);
|
||||||
assert_eq_vec(&["col1", "col2"], &columns);
|
assert_eq_vec(&["col1", "col2"], &columns);
|
||||||
assert!(include.is_empty());
|
assert!(include.is_empty());
|
||||||
|
assert!(with.is_empty());
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
@ -2280,6 +2282,7 @@ fn parse_create_anonymous_index() {
|
||||||
if_not_exists,
|
if_not_exists,
|
||||||
include,
|
include,
|
||||||
nulls_distinct: None,
|
nulls_distinct: None,
|
||||||
|
with,
|
||||||
predicate: None,
|
predicate: None,
|
||||||
}) => {
|
}) => {
|
||||||
assert_eq!(None, name);
|
assert_eq!(None, name);
|
||||||
|
@ -2290,6 +2293,7 @@ fn parse_create_anonymous_index() {
|
||||||
assert!(!if_not_exists);
|
assert!(!if_not_exists);
|
||||||
assert_eq_vec(&["col1", "col2"], &columns);
|
assert_eq_vec(&["col1", "col2"], &columns);
|
||||||
assert!(include.is_empty());
|
assert!(include.is_empty());
|
||||||
|
assert!(with.is_empty());
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
@ -2309,6 +2313,7 @@ fn parse_create_index_concurrently() {
|
||||||
if_not_exists,
|
if_not_exists,
|
||||||
include,
|
include,
|
||||||
nulls_distinct: None,
|
nulls_distinct: None,
|
||||||
|
with,
|
||||||
predicate: None,
|
predicate: None,
|
||||||
}) => {
|
}) => {
|
||||||
assert_eq_vec(&["my_index"], &name);
|
assert_eq_vec(&["my_index"], &name);
|
||||||
|
@ -2319,6 +2324,7 @@ fn parse_create_index_concurrently() {
|
||||||
assert!(if_not_exists);
|
assert!(if_not_exists);
|
||||||
assert_eq_vec(&["col1", "col2"], &columns);
|
assert_eq_vec(&["col1", "col2"], &columns);
|
||||||
assert!(include.is_empty());
|
assert!(include.is_empty());
|
||||||
|
assert!(with.is_empty());
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
@ -2338,6 +2344,7 @@ fn parse_create_index_with_predicate() {
|
||||||
if_not_exists,
|
if_not_exists,
|
||||||
include,
|
include,
|
||||||
nulls_distinct: None,
|
nulls_distinct: None,
|
||||||
|
with,
|
||||||
predicate: Some(_),
|
predicate: Some(_),
|
||||||
}) => {
|
}) => {
|
||||||
assert_eq_vec(&["my_index"], &name);
|
assert_eq_vec(&["my_index"], &name);
|
||||||
|
@ -2348,6 +2355,7 @@ fn parse_create_index_with_predicate() {
|
||||||
assert!(if_not_exists);
|
assert!(if_not_exists);
|
||||||
assert_eq_vec(&["col1", "col2"], &columns);
|
assert_eq_vec(&["col1", "col2"], &columns);
|
||||||
assert!(include.is_empty());
|
assert!(include.is_empty());
|
||||||
|
assert!(with.is_empty());
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
@ -2367,6 +2375,7 @@ fn parse_create_index_with_include() {
|
||||||
if_not_exists,
|
if_not_exists,
|
||||||
include,
|
include,
|
||||||
nulls_distinct: None,
|
nulls_distinct: None,
|
||||||
|
with,
|
||||||
predicate: None,
|
predicate: None,
|
||||||
}) => {
|
}) => {
|
||||||
assert_eq_vec(&["my_index"], &name);
|
assert_eq_vec(&["my_index"], &name);
|
||||||
|
@ -2377,6 +2386,7 @@ fn parse_create_index_with_include() {
|
||||||
assert!(if_not_exists);
|
assert!(if_not_exists);
|
||||||
assert_eq_vec(&["col1", "col2"], &columns);
|
assert_eq_vec(&["col1", "col2"], &columns);
|
||||||
assert_eq_vec(&["col3"], &include);
|
assert_eq_vec(&["col3"], &include);
|
||||||
|
assert!(with.is_empty());
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
@ -2396,6 +2406,7 @@ fn parse_create_index_with_nulls_distinct() {
|
||||||
if_not_exists,
|
if_not_exists,
|
||||||
include,
|
include,
|
||||||
nulls_distinct: Some(nulls_distinct),
|
nulls_distinct: Some(nulls_distinct),
|
||||||
|
with,
|
||||||
predicate: None,
|
predicate: None,
|
||||||
}) => {
|
}) => {
|
||||||
assert_eq_vec(&["my_index"], &name);
|
assert_eq_vec(&["my_index"], &name);
|
||||||
|
@ -2407,6 +2418,7 @@ fn parse_create_index_with_nulls_distinct() {
|
||||||
assert_eq_vec(&["col1", "col2"], &columns);
|
assert_eq_vec(&["col1", "col2"], &columns);
|
||||||
assert!(include.is_empty());
|
assert!(include.is_empty());
|
||||||
assert!(!nulls_distinct);
|
assert!(!nulls_distinct);
|
||||||
|
assert!(with.is_empty());
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
@ -2423,6 +2435,7 @@ fn parse_create_index_with_nulls_distinct() {
|
||||||
if_not_exists,
|
if_not_exists,
|
||||||
include,
|
include,
|
||||||
nulls_distinct: Some(nulls_distinct),
|
nulls_distinct: Some(nulls_distinct),
|
||||||
|
with,
|
||||||
predicate: None,
|
predicate: None,
|
||||||
}) => {
|
}) => {
|
||||||
assert_eq_vec(&["my_index"], &name);
|
assert_eq_vec(&["my_index"], &name);
|
||||||
|
@ -2434,6 +2447,7 @@ fn parse_create_index_with_nulls_distinct() {
|
||||||
assert_eq_vec(&["col1", "col2"], &columns);
|
assert_eq_vec(&["col1", "col2"], &columns);
|
||||||
assert!(include.is_empty());
|
assert!(include.is_empty());
|
||||||
assert!(nulls_distinct);
|
assert!(nulls_distinct);
|
||||||
|
assert!(with.is_empty());
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue