Skip to content

Commit 9d97ba7

Browse files
authored
feat(query): create table support add inverted index (#15547)
1 parent 6ffceb8 commit 9d97ba7

File tree

23 files changed

+534
-138
lines changed

23 files changed

+534
-138
lines changed

src/meta/api/src/schema_api_impl.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1557,6 +1557,26 @@ impl<KV: kvapi::KVApi<Error = MetaError> + ?Sized> SchemaApi for KV {
15571557
.collect::<Vec<_>>()
15581558
};
15591559

1560+
if !req.table_meta.indexes.is_empty() {
1561+
// check the index column id exists and not be duplicated.
1562+
let mut index_column_ids = HashSet::new();
1563+
for (_, index) in req.table_meta.indexes.iter() {
1564+
for column_id in &index.column_ids {
1565+
if req.table_meta.schema.is_column_deleted(*column_id) {
1566+
return Err(KVAppError::AppError(AppError::IndexColumnIdNotFound(
1567+
IndexColumnIdNotFound::new(*column_id, &index.name),
1568+
)));
1569+
}
1570+
if index_column_ids.contains(column_id) {
1571+
return Err(KVAppError::AppError(AppError::DuplicatedIndexColumnId(
1572+
DuplicatedIndexColumnId::new(*column_id, &index.name),
1573+
)));
1574+
}
1575+
index_column_ids.insert(column_id);
1576+
}
1577+
}
1578+
}
1579+
15601580
let mut trials = txn_backoff(None, func_name!());
15611581
loop {
15621582
trials.next().unwrap()?.await;

src/query/ast/src/ast/format/ast_format.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1470,12 +1470,18 @@ impl<'ast> Visitor<'ast> for AstFormatVisitor {
14701470

14711471
fn visit_create_table_source(&mut self, source: &'ast CreateTableSource) {
14721472
match source {
1473-
CreateTableSource::Columns(columns) => {
1473+
CreateTableSource::Columns(columns, inverted_indexes) => {
14741474
let mut children = Vec::with_capacity(columns.len());
14751475
for column in columns.iter() {
14761476
self.visit_column_definition(column);
14771477
children.push(self.children.pop().unwrap());
14781478
}
1479+
if let Some(inverted_indexes) = inverted_indexes {
1480+
for inverted_index in inverted_indexes {
1481+
self.visit_inverted_index_definition(inverted_index);
1482+
children.push(self.children.pop().unwrap());
1483+
}
1484+
}
14791485
let name = "ColumnsDefinition".to_string();
14801486
let format_ctx = AstFormatContext::with_children(name, children.len());
14811487
let node = FormatTreeNode::with_children(format_ctx, children);
@@ -1507,6 +1513,26 @@ impl<'ast> Visitor<'ast> for AstFormatVisitor {
15071513
self.children.push(node);
15081514
}
15091515

1516+
fn visit_inverted_index_definition(
1517+
&mut self,
1518+
inverted_index_definition: &'ast InvertedIndexDefinition,
1519+
) {
1520+
let mut column_nodes = Vec::with_capacity(inverted_index_definition.columns.len());
1521+
for column in &inverted_index_definition.columns {
1522+
let column_name = format!("Column {}", column);
1523+
let column_format_ctx = AstFormatContext::new(column_name);
1524+
let column_node = FormatTreeNode::new(column_format_ctx);
1525+
column_nodes.push(column_node);
1526+
}
1527+
let name = format!(
1528+
"InvertedIndexDefinition {}",
1529+
inverted_index_definition.index_name
1530+
);
1531+
let format_ctx = AstFormatContext::with_children(name, column_nodes.len());
1532+
let node = FormatTreeNode::with_children(format_ctx, column_nodes);
1533+
self.children.push(node);
1534+
}
1535+
15101536
fn visit_drop_table(&mut self, stmt: &'ast DropTableStmt) {
15111537
self.visit_table_ref(&stmt.catalog, &stmt.database, &stmt.table);
15121538
let child = self.children.pop().unwrap();

src/query/ast/src/ast/format/syntax/ddl.rs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -113,14 +113,27 @@ pub(crate) fn pretty_create_table(stmt: CreateTableStmt) -> RcDoc<'static> {
113113

114114
fn pretty_table_source(source: CreateTableSource) -> RcDoc<'static> {
115115
match source {
116-
CreateTableSource::Columns(columns) => RcDoc::space().append(parenthesized(
117-
interweave_comma(
118-
columns
119-
.into_iter()
120-
.map(|column| RcDoc::text(column.to_string())),
121-
)
122-
.group(),
123-
)),
116+
CreateTableSource::Columns(columns, inverted_indexes) => RcDoc::space()
117+
.append(parenthesized(
118+
interweave_comma(
119+
columns
120+
.into_iter()
121+
.map(|column| RcDoc::text(column.to_string())),
122+
)
123+
.group(),
124+
))
125+
.append(if let Some(inverted_indexes) = inverted_indexes {
126+
parenthesized(
127+
interweave_comma(
128+
inverted_indexes
129+
.into_iter()
130+
.map(|inverted_index| RcDoc::text(inverted_index.to_string())),
131+
)
132+
.group(),
133+
)
134+
} else {
135+
RcDoc::nil()
136+
}),
124137
CreateTableSource::Like {
125138
catalog,
126139
database,

src/query/ast/src/ast/statements/table.rs

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ impl Display for AttachTableStmt {
233233

234234
#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
235235
pub enum CreateTableSource {
236-
Columns(Vec<ColumnDefinition>),
236+
Columns(Vec<ColumnDefinition>, Option<Vec<InvertedIndexDefinition>>),
237237
Like {
238238
catalog: Option<Identifier>,
239239
database: Option<Identifier>,
@@ -244,9 +244,13 @@ pub enum CreateTableSource {
244244
impl Display for CreateTableSource {
245245
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
246246
match self {
247-
CreateTableSource::Columns(columns) => {
247+
CreateTableSource::Columns(columns, inverted_indexes) => {
248248
write!(f, "(")?;
249249
write_comma_separated_list(f, columns)?;
250+
if let Some(inverted_indexes) = inverted_indexes {
251+
write!(f, ", ")?;
252+
write_comma_separated_list(f, inverted_indexes)?;
253+
}
250254
write!(f, ")")
251255
}
252256
CreateTableSource::Like {
@@ -834,6 +838,56 @@ impl Display for ColumnDefinition {
834838
}
835839
}
836840

841+
#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
842+
pub struct InvertedIndexDefinition {
843+
pub index_name: Identifier,
844+
pub columns: Vec<Identifier>,
845+
#[drive(skip)]
846+
pub sync_creation: bool,
847+
#[drive(skip)]
848+
pub index_options: BTreeMap<String, String>,
849+
}
850+
851+
impl Display for InvertedIndexDefinition {
852+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
853+
if !self.sync_creation {
854+
write!(f, "ASYNC ")?;
855+
}
856+
write!(f, "INVERTED INDEX")?;
857+
write!(f, " {}", self.index_name)?;
858+
write!(f, " (")?;
859+
write_comma_separated_list(f, &self.columns)?;
860+
write!(f, ")")?;
861+
862+
if !self.index_options.is_empty() {
863+
write!(f, " ")?;
864+
write_space_separated_string_map(f, &self.index_options)?;
865+
}
866+
867+
Ok(())
868+
}
869+
}
870+
871+
#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
872+
pub enum CreateDefinition {
873+
Column(ColumnDefinition),
874+
InvertedIndex(InvertedIndexDefinition),
875+
}
876+
877+
impl Display for CreateDefinition {
878+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
879+
match self {
880+
CreateDefinition::Column(column_def) => {
881+
write!(f, "{}", column_def)?;
882+
}
883+
CreateDefinition::InvertedIndex(inverted_index_def) => {
884+
write!(f, "{}", inverted_index_def)?;
885+
}
886+
}
887+
Ok(())
888+
}
889+
}
890+
837891
#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
838892
pub enum ModifyColumnAction {
839893
// (column name id, masking policy name)

src/query/ast/src/ast/visitors/visitor.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,12 @@ pub trait Visitor<'ast>: Sized {
528528

529529
fn visit_column_definition(&mut self, _column_definition: &'ast ColumnDefinition) {}
530530

531+
fn visit_inverted_index_definition(
532+
&mut self,
533+
_inverted_index_definition: &'ast InvertedIndexDefinition,
534+
) {
535+
}
536+
531537
fn visit_drop_table(&mut self, _stmt: &'ast DropTableStmt) {}
532538

533539
fn visit_undrop_table(&mut self, _stmt: &'ast UndropTableStmt) {}

src/query/ast/src/ast/visitors/visitor_mut.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,12 @@ pub trait VisitorMut: Sized {
540540

541541
fn visit_column_definition(&mut self, _column_definition: &mut ColumnDefinition) {}
542542

543+
fn visit_inverted_index_definition(
544+
&mut self,
545+
_inverted_index_definition: &mut InvertedIndexDefinition,
546+
) {
547+
}
548+
543549
fn visit_drop_table(&mut self, _stmt: &mut DropTableStmt) {}
544550

545551
fn visit_undrop_table(&mut self, _stmt: &mut UndropTableStmt) {}

src/query/ast/src/parser/statement.rs

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2725,6 +2725,36 @@ pub fn column_def(i: Input) -> IResult<ColumnDefinition> {
27252725
Ok((i, def))
27262726
}
27272727

2728+
pub fn inverted_index_def(i: Input) -> IResult<InvertedIndexDefinition> {
2729+
map_res(
2730+
rule! {
2731+
ASYNC?
2732+
~ INVERTED ~ ^INDEX
2733+
~ #ident
2734+
~ ^"(" ~ ^#comma_separated_list1(ident) ~ ^")"
2735+
~ ( #table_option )?
2736+
},
2737+
|(opt_async, _, _, index_name, _, columns, _, opt_index_options)| {
2738+
Ok(InvertedIndexDefinition {
2739+
index_name,
2740+
columns,
2741+
sync_creation: opt_async.is_none(),
2742+
index_options: opt_index_options.unwrap_or_default(),
2743+
})
2744+
},
2745+
)(i)
2746+
}
2747+
2748+
pub fn create_def(i: Input) -> IResult<CreateDefinition> {
2749+
alt((
2750+
map(rule! { #column_def }, CreateDefinition::Column),
2751+
map(
2752+
rule! { #inverted_index_def },
2753+
CreateDefinition::InvertedIndex,
2754+
),
2755+
))(i)
2756+
}
2757+
27282758
pub fn role_name(i: Input) -> IResult<String> {
27292759
let role_ident = map(
27302760
rule! {
@@ -3036,9 +3066,28 @@ pub fn grant_option(i: Input) -> IResult<PrincipalIdentity> {
30363066
pub fn create_table_source(i: Input) -> IResult<CreateTableSource> {
30373067
let columns = map(
30383068
rule! {
3039-
"(" ~ ^#comma_separated_list1(column_def) ~ ^")"
3069+
"(" ~ ^#comma_separated_list1(create_def) ~ ^")"
3070+
},
3071+
|(_, create_defs, _)| {
3072+
let mut columns = Vec::with_capacity(create_defs.len());
3073+
let mut inverted_indexes = Vec::new();
3074+
for create_def in create_defs {
3075+
match create_def {
3076+
CreateDefinition::Column(column) => {
3077+
columns.push(column);
3078+
}
3079+
CreateDefinition::InvertedIndex(inverted_index) => {
3080+
inverted_indexes.push(inverted_index);
3081+
}
3082+
}
3083+
}
3084+
let opt_inverted_indexes = if !inverted_indexes.is_empty() {
3085+
Some(inverted_indexes)
3086+
} else {
3087+
None
3088+
};
3089+
CreateTableSource::Columns(columns, opt_inverted_indexes)
30403090
},
3041-
|(_, columns, _)| CreateTableSource::Columns(columns),
30423091
);
30433092
let like = map(
30443093
rule! {

src/query/ast/tests/it/parser.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ fn test_statement() {
129129
r#"create table if not exists a.b (c tuple(m integer, n string), d tuple(integer, string));"#,
130130
r#"create table if not exists a.b (a string, b string, c string as (concat(a, ' ', b)) stored );"#,
131131
r#"create table if not exists a.b (a int, b int, c int generated always as (a + b) virtual );"#,
132+
r#"create table if not exists a.b (a string, b string, inverted index idx1 (a,b) tokenizer='chinese');"#,
132133
r#"create table a.b like c.d;"#,
133134
r#"create table t like t2 engine = memory;"#,
134135
r#"create table if not exists a.b (a int) 's3://testbucket/admin/data/' connection=(aws_key_id='minioadmin' aws_secret_key='minioadmin' endpoint_url='http://127.0.0.1:9900');"#,

0 commit comments

Comments
 (0)