mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-05-26 18:00:41 +00:00
feat!: support alter skipping index (#5538)
* feat: support alter skipping index Signed-off-by: Ruihang Xia <waynestxia@gmail.com> * update test results Signed-off-by: Ruihang Xia <waynestxia@gmail.com> * cargo fmt Signed-off-by: Ruihang Xia <waynestxia@gmail.com> * update sqlness result Signed-off-by: Ruihang Xia <waynestxia@gmail.com> * finalize Signed-off-by: Ruihang Xia <waynestxia@gmail.com> --------- Signed-off-by: Ruihang Xia <waynestxia@gmail.com>
This commit is contained in:
@@ -25,7 +25,9 @@ use sqlparser::tokenizer::{Token, TokenWithLocation};
|
||||
use crate::error::{self, InvalidColumnOptionSnafu, Result, SetFulltextOptionSnafu};
|
||||
use crate::parser::ParserContext;
|
||||
use crate::parsers::create_parser::INVERTED;
|
||||
use crate::parsers::utils::validate_column_fulltext_create_option;
|
||||
use crate::parsers::utils::{
|
||||
validate_column_fulltext_create_option, validate_column_skipping_index_create_option,
|
||||
};
|
||||
use crate::statements::alter::{
|
||||
AddColumn, AlterDatabase, AlterDatabaseOperation, AlterTable, AlterTableOperation,
|
||||
KeyValueOption, SetIndexOperation, UnsetIndexOperation,
|
||||
@@ -241,9 +243,14 @@ impl ParserContext<'_> {
|
||||
TokenWithLocation {
|
||||
token: Token::Word(w),
|
||||
..
|
||||
} if w.keyword == Keyword::FULLTEXT => Ok(AlterTableOperation::UnsetIndex {
|
||||
options: UnsetIndexOperation::Fulltext { column_name },
|
||||
}),
|
||||
} if w.keyword == Keyword::FULLTEXT => {
|
||||
self.parser
|
||||
.expect_keyword(Keyword::INDEX)
|
||||
.context(error::SyntaxSnafu)?;
|
||||
Ok(AlterTableOperation::UnsetIndex {
|
||||
options: UnsetIndexOperation::Fulltext { column_name },
|
||||
})
|
||||
}
|
||||
|
||||
TokenWithLocation {
|
||||
token: Token::Word(w),
|
||||
@@ -256,8 +263,24 @@ impl ParserContext<'_> {
|
||||
options: UnsetIndexOperation::Inverted { column_name },
|
||||
})
|
||||
}
|
||||
|
||||
TokenWithLocation {
|
||||
token: Token::Word(w),
|
||||
..
|
||||
} if w.value.eq_ignore_ascii_case("SKIPPING") => {
|
||||
self.parser
|
||||
.expect_keyword(Keyword::INDEX)
|
||||
.context(error::SyntaxSnafu)?;
|
||||
Ok(AlterTableOperation::UnsetIndex {
|
||||
options: UnsetIndexOperation::Skipping { column_name },
|
||||
})
|
||||
}
|
||||
_ => self.expected(
|
||||
format!("{:?} OR INVERTED INDEX", Keyword::FULLTEXT).as_str(),
|
||||
format!(
|
||||
"{:?} OR INVERTED INDEX OR SKIPPING INDEX",
|
||||
Keyword::FULLTEXT
|
||||
)
|
||||
.as_str(),
|
||||
self.parser.peek_token(),
|
||||
),
|
||||
}
|
||||
@@ -268,7 +291,12 @@ impl ParserContext<'_> {
|
||||
TokenWithLocation {
|
||||
token: Token::Word(w),
|
||||
..
|
||||
} if w.keyword == Keyword::FULLTEXT => self.parse_alter_column_fulltext(column_name),
|
||||
} if w.keyword == Keyword::FULLTEXT => {
|
||||
self.parser
|
||||
.expect_keyword(Keyword::INDEX)
|
||||
.context(error::SyntaxSnafu)?;
|
||||
self.parse_alter_column_fulltext(column_name)
|
||||
}
|
||||
|
||||
TokenWithLocation {
|
||||
token: Token::Word(w),
|
||||
@@ -281,8 +309,18 @@ impl ParserContext<'_> {
|
||||
options: SetIndexOperation::Inverted { column_name },
|
||||
})
|
||||
}
|
||||
|
||||
TokenWithLocation {
|
||||
token: Token::Word(w),
|
||||
..
|
||||
} if w.value.eq_ignore_ascii_case("SKIPPING") => {
|
||||
self.parser
|
||||
.expect_keyword(Keyword::INDEX)
|
||||
.context(error::SyntaxSnafu)?;
|
||||
self.parse_alter_column_skipping(column_name)
|
||||
}
|
||||
_ => self.expected(
|
||||
format!("{:?} OR INVERTED INDEX", Keyword::FULLTEXT).as_str(),
|
||||
format!("{:?} OR INVERTED OR SKIPPING INDEX", Keyword::FULLTEXT).as_str(),
|
||||
self.parser.peek_token(),
|
||||
),
|
||||
}
|
||||
@@ -319,6 +357,35 @@ impl ParserContext<'_> {
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_alter_column_skipping(&mut self, column_name: Ident) -> Result<AlterTableOperation> {
|
||||
let options = self
|
||||
.parser
|
||||
.parse_options(Keyword::WITH)
|
||||
.context(error::SyntaxSnafu)?
|
||||
.into_iter()
|
||||
.map(parse_option_string)
|
||||
.collect::<Result<HashMap<String, String>>>()?;
|
||||
|
||||
for key in options.keys() {
|
||||
ensure!(
|
||||
validate_column_skipping_index_create_option(key),
|
||||
InvalidColumnOptionSnafu {
|
||||
name: column_name.to_string(),
|
||||
msg: format!("invalid SKIPPING INDEX option: {key}"),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Ok(AlterTableOperation::SetIndex {
|
||||
options: SetIndexOperation::Skipping {
|
||||
column_name,
|
||||
options: options
|
||||
.try_into()
|
||||
.context(error::SetSkippingIndexOptionSnafu)?,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses a string literal and an optional string literal value.
|
||||
@@ -891,7 +958,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_parse_alter_column_fulltext() {
|
||||
let sql = "ALTER TABLE test_table MODIFY COLUMN a SET FULLTEXT WITH(analyzer='English',case_sensitive='false')";
|
||||
let sql = "ALTER TABLE test_table MODIFY COLUMN a SET FULLTEXT INDEX WITH(analyzer='English',case_sensitive='false')";
|
||||
let mut result =
|
||||
ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
|
||||
.unwrap();
|
||||
@@ -928,7 +995,7 @@ mod tests {
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
let sql = "ALTER TABLE test_table MODIFY COLUMN a UNSET FULLTEXT";
|
||||
let sql = "ALTER TABLE test_table MODIFY COLUMN a UNSET FULLTEXT INDEX";
|
||||
let mut result =
|
||||
ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
|
||||
.unwrap();
|
||||
@@ -955,7 +1022,8 @@ mod tests {
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
let invalid_sql = "ALTER TABLE test_table MODIFY COLUMN a SET FULLTEXT WITH('abcd'='true')";
|
||||
let invalid_sql =
|
||||
"ALTER TABLE test_table MODIFY COLUMN a SET FULLTEXT INDEX WITH('abcd'='true')";
|
||||
let result = ParserContext::create_with_dialect(
|
||||
invalid_sql,
|
||||
&GreptimeDbDialect {},
|
||||
|
||||
@@ -16,7 +16,7 @@ use std::fmt::{Debug, Display};
|
||||
|
||||
use api::v1;
|
||||
use common_query::AddColumnLocation;
|
||||
use datatypes::schema::FulltextOptions;
|
||||
use datatypes::schema::{FulltextOptions, SkippingIndexOptions};
|
||||
use itertools::Itertools;
|
||||
use serde::Serialize;
|
||||
use sqlparser::ast::{ColumnDef, DataType, Ident, ObjectName, TableConstraint};
|
||||
@@ -96,22 +96,28 @@ pub enum AlterTableOperation {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
|
||||
pub enum SetIndexOperation {
|
||||
/// `MODIFY COLUMN <column_name> SET FULLTEXT [WITH <options>]`
|
||||
/// `MODIFY COLUMN <column_name> SET FULLTEXT INDEX [WITH <options>]`
|
||||
Fulltext {
|
||||
column_name: Ident,
|
||||
options: FulltextOptions,
|
||||
},
|
||||
/// `MODIFY COLUMN <column_name> SET INVERTED INDEX`
|
||||
Inverted { column_name: Ident },
|
||||
/// `MODIFY COLUMN <column_name> SET SKIPPING INDEX`
|
||||
Skipping {
|
||||
column_name: Ident,
|
||||
options: SkippingIndexOptions,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
|
||||
pub enum UnsetIndexOperation {
|
||||
/// `MODIFY COLUMN <column_name> UNSET FULLTEXT`
|
||||
/// `MODIFY COLUMN <column_name> UNSET FULLTEXT INDEX`
|
||||
Fulltext { column_name: Ident },
|
||||
|
||||
/// `MODIFY COLUMN <column_name> UNSET INVERTED INDEX`
|
||||
Inverted { column_name: Ident },
|
||||
/// `MODIFY COLUMN <column_name> UNSET SKIPPING INDEX`
|
||||
Skipping { column_name: Ident },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
|
||||
@@ -175,19 +181,28 @@ impl Display for AlterTableOperation {
|
||||
column_name,
|
||||
options,
|
||||
} => {
|
||||
write!(f, "MODIFY COLUMN {column_name} SET FULLTEXT WITH(analyzer={0}, case_sensitive={1})", options.analyzer, options.case_sensitive)
|
||||
write!(f, "MODIFY COLUMN {column_name} SET FULLTEXT INDEX WITH(analyzer={0}, case_sensitive={1})", options.analyzer, options.case_sensitive)
|
||||
}
|
||||
SetIndexOperation::Inverted { column_name } => {
|
||||
write!(f, "MODIFY COLUMN {column_name} SET INVERTED INDEX")
|
||||
}
|
||||
SetIndexOperation::Skipping {
|
||||
column_name,
|
||||
options,
|
||||
} => {
|
||||
write!(f, "MODIFY COLUMN {column_name} SET SKIPPING INDEX WITH(granularity={0}, index_type={1})", options.granularity, options.index_type)
|
||||
}
|
||||
},
|
||||
AlterTableOperation::UnsetIndex { options } => match options {
|
||||
UnsetIndexOperation::Fulltext { column_name } => {
|
||||
write!(f, "MODIFY COLUMN {column_name} UNSET FULLTEXT")
|
||||
write!(f, "MODIFY COLUMN {column_name} UNSET FULLTEXT INDEX")
|
||||
}
|
||||
UnsetIndexOperation::Inverted { column_name } => {
|
||||
write!(f, "MODIFY COLUMN {column_name} UNSET INVERTED INDEX")
|
||||
}
|
||||
UnsetIndexOperation::Skipping { column_name } => {
|
||||
write!(f, "MODIFY COLUMN {column_name} UNSET SKIPPING INDEX")
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -410,7 +425,7 @@ ALTER TABLE monitor RENAME monitor_new"#,
|
||||
}
|
||||
}
|
||||
|
||||
let sql = "ALTER TABLE monitor MODIFY COLUMN a SET FULLTEXT WITH(analyzer='English',case_sensitive='false')";
|
||||
let sql = "ALTER TABLE monitor MODIFY COLUMN a SET FULLTEXT INDEX WITH(analyzer='English',case_sensitive='false')";
|
||||
let stmts =
|
||||
ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
|
||||
.unwrap();
|
||||
@@ -422,7 +437,7 @@ ALTER TABLE monitor RENAME monitor_new"#,
|
||||
let new_sql = format!("\n{}", set);
|
||||
assert_eq!(
|
||||
r#"
|
||||
ALTER TABLE monitor MODIFY COLUMN a SET FULLTEXT WITH(analyzer=English, case_sensitive=false)"#,
|
||||
ALTER TABLE monitor MODIFY COLUMN a SET FULLTEXT INDEX WITH(analyzer=English, case_sensitive=false)"#,
|
||||
&new_sql
|
||||
);
|
||||
}
|
||||
@@ -431,7 +446,7 @@ ALTER TABLE monitor MODIFY COLUMN a SET FULLTEXT WITH(analyzer=English, case_sen
|
||||
}
|
||||
}
|
||||
|
||||
let sql = "ALTER TABLE monitor MODIFY COLUMN a UNSET FULLTEXT";
|
||||
let sql = "ALTER TABLE monitor MODIFY COLUMN a UNSET FULLTEXT INDEX";
|
||||
let stmts =
|
||||
ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
|
||||
.unwrap();
|
||||
@@ -443,7 +458,7 @@ ALTER TABLE monitor MODIFY COLUMN a SET FULLTEXT WITH(analyzer=English, case_sen
|
||||
let new_sql = format!("\n{}", set);
|
||||
assert_eq!(
|
||||
r#"
|
||||
ALTER TABLE monitor MODIFY COLUMN a UNSET FULLTEXT"#,
|
||||
ALTER TABLE monitor MODIFY COLUMN a UNSET FULLTEXT INDEX"#,
|
||||
&new_sql
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user