This is an automated email from the ASF dual-hosted git repository.
iffyio pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
The following commit(s) were added to refs/heads/main by this push:
new 6ec5223f Extend support for INDEX parsing (#1707)
6ec5223f is described below
commit 6ec5223f50e4056b8f07a61141e7f3e67b25d5e3
Author: Luca Cappelletti <[email protected]>
AuthorDate: Tue Mar 4 06:59:39 2025 +0100
Extend support for INDEX parsing (#1707)
Co-authored-by: Ifeanyi Ubah <[email protected]>
---
src/ast/ddl.rs | 17 +++-
src/ast/dml.rs | 31 ++++--
src/ast/mod.rs | 3 +-
src/ast/spans.rs | 5 +-
src/keywords.rs | 5 +
src/parser/mod.rs | 92 +++++++++++++++---
tests/sqlparser_common.rs | 83 +++++++++-------
tests/sqlparser_postgres.rs | 230 ++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 405 insertions(+), 61 deletions(-)
diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs
index bb85eb06..61963143 100644
--- a/src/ast/ddl.rs
+++ b/src/ast/ddl.rs
@@ -1174,13 +1174,20 @@ impl fmt::Display for KeyOrIndexDisplay {
/// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
/// [2]: https://dev.mysql.com/doc/refman/8.0/en/create-index.html
/// [3]: https://www.postgresql.org/docs/14/sql-createindex.html
-#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum IndexType {
BTree,
Hash,
- // TODO add Postgresql's possible indexes
+ GIN,
+ GiST,
+ SPGiST,
+ BRIN,
+ Bloom,
+ /// Users may define their own index types, which would
+ /// not be covered by the above variants.
+ Custom(Ident),
}
impl fmt::Display for IndexType {
@@ -1188,6 +1195,12 @@ impl fmt::Display for IndexType {
match self {
Self::BTree => write!(f, "BTREE"),
Self::Hash => write!(f, "HASH"),
+ Self::GIN => write!(f, "GIN"),
+ Self::GiST => write!(f, "GIST"),
+ Self::SPGiST => write!(f, "SPGIST"),
+ Self::BRIN => write!(f, "BRIN"),
+ Self::Bloom => write!(f, "BLOOM"),
+ Self::Custom(name) => write!(f, "{}", name),
}
}
}
diff --git a/src/ast/dml.rs b/src/ast/dml.rs
index 8cfc6741..ccea7fbc 100644
--- a/src/ast/dml.rs
+++ b/src/ast/dml.rs
@@ -34,12 +34,31 @@ pub use super::ddl::{ColumnDef, TableConstraint};
use super::{
display_comma_separated, display_separated, query::InputFormatClause,
Assignment, ClusteredBy,
CommentDef, Expr, FileFormat, FromTable, HiveDistributionStyle,
HiveFormat, HiveIOFormat,
- HiveRowFormat, Ident, InsertAliases, MysqlInsertPriority, ObjectName,
OnCommit, OnInsert,
- OneOrManyWithParens, OrderByExpr, Query, RowAccessPolicy, SelectItem,
Setting, SqlOption,
- SqliteOnConflict, StorageSerializationPolicy, TableEngine, TableObject,
TableWithJoins, Tag,
- WrappedCollection,
+ HiveRowFormat, Ident, IndexType, InsertAliases, MysqlInsertPriority,
ObjectName, OnCommit,
+ OnInsert, OneOrManyWithParens, OrderByExpr, Query, RowAccessPolicy,
SelectItem, Setting,
+ SqlOption, SqliteOnConflict, StorageSerializationPolicy, TableEngine,
TableObject,
+ TableWithJoins, Tag, WrappedCollection,
};
+/// Index column type.
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct IndexColumn {
+ pub column: OrderByExpr,
+ pub operator_class: Option<Ident>,
+}
+
+impl Display for IndexColumn {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", self.column)?;
+ if let Some(operator_class) = &self.operator_class {
+ write!(f, " {}", operator_class)?;
+ }
+ Ok(())
+ }
+}
+
/// CREATE INDEX statement.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@@ -49,8 +68,8 @@ pub struct CreateIndex {
pub name: Option<ObjectName>,
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
pub table_name: ObjectName,
- pub using: Option<Ident>,
- pub columns: Vec<OrderByExpr>,
+ pub using: Option<IndexType>,
+ pub columns: Vec<IndexColumn>,
pub unique: bool,
pub concurrently: bool,
pub if_not_exists: bool,
diff --git a/src/ast/mod.rs b/src/ast/mod.rs
index 554ec19b..e5e4aef0 100644
--- a/src/ast/mod.rs
+++ b/src/ast/mod.rs
@@ -58,7 +58,7 @@ pub use self::ddl::{
ReferentialAction, TableConstraint, TagsColumnOption,
UserDefinedTypeCompositeAttributeDef,
UserDefinedTypeRepresentation, ViewColumnDef,
};
-pub use self::dml::{CreateIndex, CreateTable, Delete, Insert};
+pub use self::dml::{CreateIndex, CreateTable, Delete, IndexColumn, Insert};
pub use self::operator::{BinaryOperator, UnaryOperator};
pub use self::query::{
AfterMatchSkip, ConnectBy, Cte, CteAsMaterialized, Distinct,
EmptyMatchesMode,
@@ -91,6 +91,7 @@ pub use self::value::{
use crate::ast::helpers::key_value_options::KeyValueOptions;
use crate::ast::helpers::stmt_data_loading::{StageLoadSelectItem,
StageParamsObject};
+
#[cfg(feature = "visitor")]
pub use visitor::*;
diff --git a/src/ast/spans.rs b/src/ast/spans.rs
index 38e9e258..0a64fb8e 100644
--- a/src/ast/spans.rs
+++ b/src/ast/spans.rs
@@ -704,7 +704,7 @@ impl Spanned for CreateIndex {
let CreateIndex {
name,
table_name,
- using,
+ using: _,
columns,
unique: _, // bool
concurrently: _, // bool
@@ -719,8 +719,7 @@ impl Spanned for CreateIndex {
name.iter()
.map(|i| i.span())
.chain(core::iter::once(table_name.span()))
- .chain(using.iter().map(|i| i.span))
- .chain(columns.iter().map(|i| i.span()))
+ .chain(columns.iter().map(|i| i.column.span()))
.chain(include.iter().map(|i| i.span))
.chain(with.iter().map(|i| i.span()))
.chain(predicate.iter().map(|i| i.span())),
diff --git a/src/keywords.rs b/src/keywords.rs
index a6854f07..bda817df 100644
--- a/src/keywords.rs
+++ b/src/keywords.rs
@@ -137,11 +137,13 @@ define_keywords!(
BIT,
BLOB,
BLOCK,
+ BLOOM,
BLOOMFILTER,
BOOL,
BOOLEAN,
BOTH,
BOX,
+ BRIN,
BROWSE,
BTREE,
BUCKET,
@@ -386,6 +388,8 @@ define_keywords!(
GENERATED,
GEOGRAPHY,
GET,
+ GIN,
+ GIST,
GLOBAL,
GRANT,
GRANTED,
@@ -805,6 +809,7 @@ define_keywords!(
SPATIAL,
SPECIFIC,
SPECIFICTYPE,
+ SPGIST,
SQL,
SQLEXCEPTION,
SQLSTATE,
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index b11e5779..b3441538 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -3955,6 +3955,18 @@ impl<'a> Parser<'a> {
true
}
+ /// If the current token is one of the given `keywords`, returns the
keyword
+ /// that matches, without consuming the token. Otherwise, returns [`None`].
+ #[must_use]
+ pub fn peek_one_of_keywords(&self, keywords: &[Keyword]) ->
Option<Keyword> {
+ for keyword in keywords {
+ if self.peek_keyword(*keyword) {
+ return Some(*keyword);
+ }
+ }
+ None
+ }
+
/// If the current token is one of the given `keywords`, consume the token
/// and return the keyword that matches. Otherwise, no tokens are consumed
/// and returns [`None`].
@@ -6406,12 +6418,13 @@ impl<'a> Parser<'a> {
};
let table_name = self.parse_object_name(false)?;
let using = if self.parse_keyword(Keyword::USING) {
- Some(self.parse_identifier()?)
+ Some(self.parse_index_type()?)
} else {
None
};
+
self.expect_token(&Token::LParen)?;
- let columns = self.parse_comma_separated(Parser::parse_order_by_expr)?;
+ let columns =
self.parse_comma_separated(Parser::parse_create_index_expr)?;
self.expect_token(&Token::RParen)?;
let include = if self.parse_keyword(Keyword::INCLUDE) {
@@ -7629,16 +7642,30 @@ impl<'a> Parser<'a> {
}
pub fn parse_index_type(&mut self) -> Result<IndexType, ParserError> {
- if self.parse_keyword(Keyword::BTREE) {
- Ok(IndexType::BTree)
+ Ok(if self.parse_keyword(Keyword::BTREE) {
+ IndexType::BTree
} else if self.parse_keyword(Keyword::HASH) {
- Ok(IndexType::Hash)
- } else {
- self.expected("index type {BTREE | HASH}", self.peek_token())
- }
+ IndexType::Hash
+ } else if self.parse_keyword(Keyword::GIN) {
+ IndexType::GIN
+ } else if self.parse_keyword(Keyword::GIST) {
+ IndexType::GiST
+ } else if self.parse_keyword(Keyword::SPGIST) {
+ IndexType::SPGiST
+ } else if self.parse_keyword(Keyword::BRIN) {
+ IndexType::BRIN
+ } else if self.parse_keyword(Keyword::BLOOM) {
+ IndexType::Bloom
+ } else {
+ IndexType::Custom(self.parse_identifier()?)
+ })
}
- /// Parse [USING {BTREE | HASH}]
+ /// Optionally parse the `USING` keyword, followed by an [IndexType]
+ /// Example:
+ /// ```sql
+ //// USING BTREE (name, age DESC)
+ /// ```
pub fn parse_optional_using_then_index_type(
&mut self,
) -> Result<Option<IndexType>, ParserError> {
@@ -13631,10 +13658,42 @@ impl<'a> Parser<'a> {
}
}
- /// Parse an expression, optionally followed by ASC or DESC (used in ORDER
BY)
+ /// Parse an [OrderByExpr] expression.
pub fn parse_order_by_expr(&mut self) -> Result<OrderByExpr, ParserError> {
+ self.parse_order_by_expr_inner(false)
+ .map(|(order_by, _)| order_by)
+ }
+
+ /// Parse an [IndexColumn].
+ pub fn parse_create_index_expr(&mut self) -> Result<IndexColumn,
ParserError> {
+ self.parse_order_by_expr_inner(true)
+ .map(|(column, operator_class)| IndexColumn {
+ column,
+ operator_class,
+ })
+ }
+
+ fn parse_order_by_expr_inner(
+ &mut self,
+ with_operator_class: bool,
+ ) -> Result<(OrderByExpr, Option<Ident>), ParserError> {
let expr = self.parse_expr()?;
+ let operator_class: Option<Ident> = if with_operator_class {
+ // We check that if non of the following keywords are present,
then we parse an
+ // identifier as operator class.
+ if self
+ .peek_one_of_keywords(&[Keyword::ASC, Keyword::DESC,
Keyword::NULLS, Keyword::WITH])
+ .is_some()
+ {
+ None
+ } else {
+ self.maybe_parse(|parser| parser.parse_identifier())?
+ }
+ } else {
+ None
+ };
+
let options = self.parse_order_by_options()?;
let with_fill = if dialect_of!(self is ClickHouseDialect |
GenericDialect)
@@ -13645,11 +13704,14 @@ impl<'a> Parser<'a> {
None
};
- Ok(OrderByExpr {
- expr,
- options,
- with_fill,
- })
+ Ok((
+ OrderByExpr {
+ expr,
+ options,
+ with_fill,
+ },
+ operator_class,
+ ))
}
fn parse_order_by_options(&mut self) -> Result<OrderByOptions,
ParserError> {
diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs
index 2c35c243..a8ccd70a 100644
--- a/tests/sqlparser_common.rs
+++ b/tests/sqlparser_common.rs
@@ -8842,22 +8842,28 @@ fn ensure_multiple_dialects_are_tested() {
#[test]
fn parse_create_index() {
let sql = "CREATE UNIQUE INDEX IF NOT EXISTS idx_name ON test(name,age
DESC)";
- let indexed_columns = vec![
- OrderByExpr {
- expr: Expr::Identifier(Ident::new("name")),
- options: OrderByOptions {
- asc: None,
- nulls_first: None,
+ let indexed_columns: Vec<IndexColumn> = vec![
+ IndexColumn {
+ operator_class: None,
+ column: OrderByExpr {
+ expr: Expr::Identifier(Ident::new("name")),
+ with_fill: None,
+ options: OrderByOptions {
+ asc: None,
+ nulls_first: None,
+ },
},
- with_fill: None,
},
- OrderByExpr {
- expr: Expr::Identifier(Ident::new("age")),
- options: OrderByOptions {
- asc: Some(false),
- nulls_first: None,
+ IndexColumn {
+ operator_class: None,
+ column: OrderByExpr {
+ expr: Expr::Identifier(Ident::new("age")),
+ with_fill: None,
+ options: OrderByOptions {
+ asc: Some(false),
+ nulls_first: None,
+ },
},
- with_fill: None,
},
];
match verified_stmt(sql) {
@@ -8881,23 +8887,29 @@ fn parse_create_index() {
#[test]
fn test_create_index_with_using_function() {
- let sql = "CREATE UNIQUE INDEX IF NOT EXISTS idx_name ON test USING btree
(name,age DESC)";
- let indexed_columns = vec![
- OrderByExpr {
- expr: Expr::Identifier(Ident::new("name")),
- options: OrderByOptions {
- asc: None,
- nulls_first: None,
+ let sql = "CREATE UNIQUE INDEX IF NOT EXISTS idx_name ON test USING BTREE
(name,age DESC)";
+ let indexed_columns: Vec<IndexColumn> = vec![
+ IndexColumn {
+ operator_class: None,
+ column: OrderByExpr {
+ expr: Expr::Identifier(Ident::new("name")),
+ with_fill: None,
+ options: OrderByOptions {
+ asc: None,
+ nulls_first: None,
+ },
},
- with_fill: None,
},
- OrderByExpr {
- expr: Expr::Identifier(Ident::new("age")),
- options: OrderByOptions {
- asc: Some(false),
- nulls_first: None,
+ IndexColumn {
+ operator_class: None,
+ column: OrderByExpr {
+ expr: Expr::Identifier(Ident::new("age")),
+ with_fill: None,
+ options: OrderByOptions {
+ asc: Some(false),
+ nulls_first: None,
+ },
},
- with_fill: None,
},
];
match verified_stmt(sql) {
@@ -8916,7 +8928,7 @@ fn test_create_index_with_using_function() {
}) => {
assert_eq!("idx_name", name.to_string());
assert_eq!("test", table_name.to_string());
- assert_eq!("btree", using.unwrap().to_string());
+ assert_eq!("BTREE", using.unwrap().to_string());
assert_eq!(indexed_columns, columns);
assert!(unique);
assert!(!concurrently);
@@ -8931,13 +8943,16 @@ fn test_create_index_with_using_function() {
#[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")),
- options: OrderByOptions {
- asc: None,
- nulls_first: None,
+ let indexed_columns: Vec<IndexColumn> = vec![IndexColumn {
+ column: OrderByExpr {
+ expr: Expr::Identifier(Ident::new("title")),
+ options: OrderByOptions {
+ asc: None,
+ nulls_first: None,
+ },
+ with_fill: None,
},
- with_fill: None,
+ operator_class: None,
}];
let with_parameters = vec![
Expr::BinaryOp {
diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs
index 7508218f..0dfcc24e 100644
--- a/tests/sqlparser_postgres.rs
+++ b/tests/sqlparser_postgres.rs
@@ -2509,6 +2509,236 @@ fn parse_create_anonymous_index() {
}
}
+#[test]
+/// Test to verify the correctness of parsing the `CREATE INDEX` statement
with optional operator classes.
+///
+/// # Implementative details
+///
+/// At this time, since the parser library is not intended to take care of the
semantics of the SQL statements,
+/// there is no way to verify the correctness of the operator classes, nor
whether they are valid for the given
+/// index type. This test is only intended to verify that the parser can
correctly parse the statement. For this
+/// reason, the test includes a `totally_not_valid` operator class.
+fn parse_create_indices_with_operator_classes() {
+ let indices = [
+ IndexType::GIN,
+ IndexType::GiST,
+ IndexType::SPGiST,
+ IndexType::Custom("CustomIndexType".into()),
+ ];
+ let operator_classes: [Option<Ident>; 4] = [
+ None,
+ Some("gin_trgm_ops".into()),
+ Some("gist_trgm_ops".into()),
+ Some("totally_not_valid".into()),
+ ];
+
+ for expected_index_type in indices {
+ for expected_operator_class in &operator_classes {
+ let single_column_sql_statement = format!(
+ "CREATE INDEX the_index_name ON users USING
{expected_index_type} (concat_users_name(first_name, last_name){})",
+ expected_operator_class.as_ref().map(|oc| format!(" {}", oc))
+ .unwrap_or_default()
+ );
+ let multi_column_sql_statement = format!(
+ "CREATE INDEX the_index_name ON users USING
{expected_index_type} (column_name,concat_users_name(first_name, last_name){})",
+ expected_operator_class.as_ref().map(|oc| format!(" {}", oc))
+ .unwrap_or_default()
+ );
+
+ let expected_function_column = IndexColumn {
+ column: OrderByExpr {
+ expr: Expr::Function(Function {
+ name: ObjectName(vec![ObjectNamePart::Identifier(Ident
{
+ value: "concat_users_name".to_owned(),
+ quote_style: None,
+ span: Span::empty(),
+ })]),
+ uses_odbc_syntax: false,
+ parameters: FunctionArguments::None,
+ args: FunctionArguments::List(FunctionArgumentList {
+ duplicate_treatment: None,
+ args: vec![
+
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Identifier(
+ Ident {
+ value: "first_name".to_owned(),
+ quote_style: None,
+ span: Span::empty(),
+ },
+ ))),
+
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Identifier(
+ Ident {
+ value: "last_name".to_owned(),
+ quote_style: None,
+ span: Span::empty(),
+ },
+ ))),
+ ],
+ clauses: vec![],
+ }),
+ filter: None,
+ null_treatment: None,
+ over: None,
+ within_group: vec![],
+ }),
+ options: OrderByOptions {
+ asc: None,
+ nulls_first: None,
+ },
+ with_fill: None,
+ },
+ operator_class: expected_operator_class.clone(),
+ };
+
+ match pg().verified_stmt(&single_column_sql_statement) {
+ Statement::CreateIndex(CreateIndex {
+ name: Some(ObjectName(name)),
+ table_name: ObjectName(table_name),
+ using: Some(using),
+ columns,
+ unique: false,
+ concurrently: false,
+ if_not_exists: false,
+ include,
+ nulls_distinct: None,
+ with,
+ predicate: None,
+ }) => {
+ assert_eq_vec(&["the_index_name"], &name);
+ assert_eq_vec(&["users"], &table_name);
+ assert_eq!(expected_index_type, using);
+ assert_eq!(expected_function_column, columns[0],);
+ assert!(include.is_empty());
+ assert!(with.is_empty());
+ }
+ _ => unreachable!(),
+ }
+
+ match pg().verified_stmt(&multi_column_sql_statement) {
+ Statement::CreateIndex(CreateIndex {
+ name: Some(ObjectName(name)),
+ table_name: ObjectName(table_name),
+ using: Some(using),
+ columns,
+ unique: false,
+ concurrently: false,
+ if_not_exists: false,
+ include,
+ nulls_distinct: None,
+ with,
+ predicate: None,
+ }) => {
+ assert_eq_vec(&["the_index_name"], &name);
+ assert_eq_vec(&["users"], &table_name);
+ assert_eq!(expected_index_type, using);
+ assert_eq!(
+ IndexColumn {
+ column: OrderByExpr {
+ expr: Expr::Identifier(Ident {
+ value: "column_name".to_owned(),
+ quote_style: None,
+ span: Span::empty()
+ }),
+ options: OrderByOptions {
+ asc: None,
+ nulls_first: None,
+ },
+ with_fill: None,
+ },
+ operator_class: None
+ },
+ columns[0],
+ );
+ assert_eq!(expected_function_column, columns[1],);
+ assert!(include.is_empty());
+ assert!(with.is_empty());
+ }
+ _ => unreachable!(),
+ }
+ }
+ }
+}
+
+#[test]
+fn parse_create_bloom() {
+ let sql =
+ "CREATE INDEX bloomidx ON tbloom USING BLOOM (i1,i2,i3) WITH (length =
80, col1 = 2, col2 = 2, col3 = 4)";
+ match pg().verified_stmt(sql) {
+ Statement::CreateIndex(CreateIndex {
+ name: Some(ObjectName(name)),
+ table_name: ObjectName(table_name),
+ using: Some(using),
+ columns,
+ unique: false,
+ concurrently: false,
+ if_not_exists: false,
+ include,
+ nulls_distinct: None,
+ with,
+ predicate: None,
+ }) => {
+ assert_eq_vec(&["bloomidx"], &name);
+ assert_eq_vec(&["tbloom"], &table_name);
+ assert_eq!(IndexType::Bloom, using);
+ assert_eq_vec(&["i1", "i2", "i3"], &columns);
+ assert!(include.is_empty());
+ assert_eq!(
+ vec![
+ Expr::BinaryOp {
+ left: Box::new(Expr::Identifier(Ident::new("length"))),
+ op: BinaryOperator::Eq,
+ right: Box::new(Expr::Value(number("80").into())),
+ },
+ Expr::BinaryOp {
+ left: Box::new(Expr::Identifier(Ident::new("col1"))),
+ op: BinaryOperator::Eq,
+ right: Box::new(Expr::Value(number("2").into())),
+ },
+ Expr::BinaryOp {
+ left: Box::new(Expr::Identifier(Ident::new("col2"))),
+ op: BinaryOperator::Eq,
+ right: Box::new(Expr::Value(number("2").into())),
+ },
+ Expr::BinaryOp {
+ left: Box::new(Expr::Identifier(Ident::new("col3"))),
+ op: BinaryOperator::Eq,
+ right: Box::new(Expr::Value(number("4").into())),
+ },
+ ],
+ with
+ );
+ }
+ _ => unreachable!(),
+ }
+}
+
+#[test]
+fn parse_create_brin() {
+ let sql = "CREATE INDEX brin_sensor_data_recorded_at ON sensor_data USING
BRIN (recorded_at)";
+ match pg().verified_stmt(sql) {
+ Statement::CreateIndex(CreateIndex {
+ name: Some(ObjectName(name)),
+ table_name: ObjectName(table_name),
+ using: Some(using),
+ columns,
+ unique: false,
+ concurrently: false,
+ if_not_exists: false,
+ include,
+ nulls_distinct: None,
+ with,
+ predicate: None,
+ }) => {
+ assert_eq_vec(&["brin_sensor_data_recorded_at"], &name);
+ assert_eq_vec(&["sensor_data"], &table_name);
+ assert_eq!(IndexType::BRIN, using);
+ assert_eq_vec(&["recorded_at"], &columns);
+ assert!(include.is_empty());
+ assert!(with.is_empty());
+ }
+ _ => unreachable!(),
+ }
+}
+
#[test]
fn parse_create_index_concurrently() {
let sql = "CREATE INDEX CONCURRENTLY IF NOT EXISTS my_index ON
my_table(col1,col2)";
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]