Skip to content

Commit 6691037

Browse files
authored
Implement indexes (currently only unique indexes are supported) (#65)
* feat: implement `DataValue::to_index_key` * feat: implement `Index` and encoding in `TableCodec` * feat: implementing when create table, detect the unique field and create a unique index for it * feat: when inserting data, it will check whether the field has a corresponding unique index, insert the index and check whether it already exists * feat: Processing of unique indexes when adding update and delete * feat: Processing of unique indexes when truncate * style: rename Table -> Transaction, Transaction -> Iter * feat: added `ScalarExpression::convert_binary` used to extract the constant binary expression information corresponding to Column in the condition of the where clause * style: code optimization * feat: Implement RBO rule -> `SimplifyFilter` * test: add test case for simplification.rs * feat: add RBO Rule`SimplifyFilter` * perf: `ConstantBinary::scope_aggregation` Fusion of marginal values with values within a range * feat: implement `ConstantBinary::rearrange` constant folding -> expression extraction -> aggregation (and) -> rearrangement (or) * fix: `ConstantBinary::scope_aggregation` selection of Eq/NotEq and Scope * fix: `ConstantBinary::scope_aggregation` the eq condition only aggregates one * feat: add RBO Rule`PushPredicateIntoScan` * feat: implement `IndexScan` * feat: implement offset and limit for `IndexScan` * fix: many bugs - RBO Rule: `PushProjectThroughChild`: fixed the problem of missing fields when pushing down - RBO Rule: `PushLimitThroughJoin`: fixed the problem that when the on condition in Join generates multiple same number of connection rows, the limit limit is exceeded. - * fix: resolve merge conflicts * style: code format * fix: check or in `c1 > c2 or c1 > 1` * docs: supplementary index related * perf: `ScalarExpression::check_or` optimize implementation * feat: implemented for Decimal type `DataValue::to_index_key` * perf: Optimized `DataValue` conversion to bitwise sequence * perf: optimized `DataValue::Utf8` convert to encoding of primary/unique key * refactor: reconstruct the Key encoding of each structure of TableCodec #68
1 parent a696e2a commit 6691037

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+3020
-665
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ Storage Support:
4343
![demo](./static/images/demo.png)
4444

4545
### Features
46+
- SQL field options
47+
- not null
48+
- null
49+
- unique
50+
- Supports index type
51+
- Unique Index
4652
- Supports multiple primary key types
4753
- Tinyint
4854
- UTinyint
@@ -63,6 +69,8 @@ Storage Support:
6369
- [x] Truncate
6470
- DQL
6571
- [x] Select
72+
- SeqScan
73+
- IndexScan
6674
- [x] Where
6775
- [x] Distinct
6876
- [x] Alias

src/binder/create_table.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,15 @@ impl<S: Storage> Binder<S> {
3434
.map(|col| ColumnCatalog::from(col.clone()))
3535
.collect_vec();
3636

37-
if columns.iter().find(|col| col.desc.is_primary).is_none() {
38-
return Err(BindError::InvalidTable("At least one primary key field exists".to_string()));
37+
let primary_key_count = columns
38+
.iter()
39+
.filter(|col| col.desc.is_primary)
40+
.count();
41+
42+
if primary_key_count != 1 {
43+
return Err(BindError::InvalidTable(
44+
"The primary key field must exist and have at least one".to_string()
45+
));
3946
}
4047

4148
let plan = LogicalPlan {
@@ -75,10 +82,10 @@ mod tests {
7582
assert_eq!(op.table_name, Arc::new("t1".to_string()));
7683
assert_eq!(op.columns[0].name, "id".to_string());
7784
assert_eq!(op.columns[0].nullable, false);
78-
assert_eq!(op.columns[0].desc, ColumnDesc::new(LogicalType::Integer, true));
85+
assert_eq!(op.columns[0].desc, ColumnDesc::new(LogicalType::Integer, true, false));
7986
assert_eq!(op.columns[1].name, "name".to_string());
8087
assert_eq!(op.columns[1].nullable, true);
81-
assert_eq!(op.columns[1].desc, ColumnDesc::new(LogicalType::Varchar(Some(10)), false));
88+
assert_eq!(op.columns[1].desc, ColumnDesc::new(LogicalType::Varchar(Some(10)), false, false));
8289
}
8390
_ => unreachable!()
8491
}

src/binder/expr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ impl<S: Storage> Binder<S> {
6464
let table_catalog = self
6565
.context
6666
.storage
67-
.table_catalog(table)
67+
.table(table)
6868
.await
6969
.ok_or_else(|| BindError::InvalidTable(table.to_string()))?;
7070

src/binder/insert.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ impl<S: Storage> Binder<S> {
2424
let (_, name) = split_name(&name)?;
2525
let table_name = Arc::new(name.to_string());
2626

27-
if let Some(table) = self.context.storage.table_catalog(&table_name).await {
27+
if let Some(table) = self.context.storage.table(&table_name).await {
2828
let mut columns = Vec::new();
2929

3030
if idents.is_empty() {

src/binder/mod.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -193,16 +193,16 @@ pub mod test {
193193
let _ = storage.create_table(
194194
Arc::new("t1".to_string()),
195195
vec![
196-
ColumnCatalog::new("c1".to_string(), false, ColumnDesc::new(Integer, true)),
197-
ColumnCatalog::new("c2".to_string(), false, ColumnDesc::new(Integer, false)),
196+
ColumnCatalog::new("c1".to_string(), false, ColumnDesc::new(Integer, true, false)),
197+
ColumnCatalog::new("c2".to_string(), false, ColumnDesc::new(Integer, false, true)),
198198
]
199199
).await?;
200200

201201
let _ = storage.create_table(
202202
Arc::new("t2".to_string()),
203203
vec![
204-
ColumnCatalog::new("c3".to_string(), false, ColumnDesc::new(Integer, true)),
205-
ColumnCatalog::new("c4".to_string(), false, ColumnDesc::new(Integer, false)),
204+
ColumnCatalog::new("c3".to_string(), false, ColumnDesc::new(Integer, true, false)),
205+
ColumnCatalog::new("c4".to_string(), false, ColumnDesc::new(Integer, false, false)),
206206
]
207207
).await?;
208208

@@ -211,7 +211,6 @@ pub mod test {
211211

212212
pub async fn select_sql_run(sql: &str) -> Result<LogicalPlan, ExecutorError> {
213213
let temp_dir = TempDir::new().expect("unable to create temporary working directory");
214-
215214
let storage = build_test_catalog(temp_dir.path()).await?;
216215
let binder = Binder::new(BinderContext::new(storage));
217216
let stmt = crate::parser::parse_sql(sql)?;

src/binder/select.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ impl<S: Storage> Binder<S> {
167167
let table_catalog = self
168168
.context
169169
.storage
170-
.table_catalog(&table_name)
170+
.table(&table_name)
171171
.await
172172
.ok_or_else(|| BindError::InvalidTable(format!("bind table {}", table)))?;
173173

@@ -215,7 +215,7 @@ impl<S: Storage> Binder<S> {
215215
for table_name in self.context.bind_table.keys().cloned() {
216216
let table = self.context
217217
.storage
218-
.table_catalog(&table_name)
218+
.table(&table_name)
219219
.await
220220
.ok_or_else(|| BindError::InvalidTable(table_name.to_string()))?;
221221
for col in table.all_columns() {
@@ -244,12 +244,12 @@ impl<S: Storage> Binder<S> {
244244
let (right_table, right) = self.bind_single_table_ref(relation, Some(join_type)).await?;
245245

246246
let left_table = self.context.storage
247-
.table_catalog(&left_table)
247+
.table(&left_table)
248248
.await
249249
.cloned()
250250
.ok_or_else(|| BindError::InvalidTable(format!("Left: {} not found", left_table)))?;
251251
let right_table = self.context.storage
252-
.table_catalog(&right_table)
252+
.table(&right_table)
253253
.await
254254
.cloned()
255255
.ok_or_else(|| BindError::InvalidTable(format!("Right: {} not found", right_table)))?;

src/catalog/column.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ use serde::{Deserialize, Serialize};
33
use sqlparser::ast::{ColumnDef, ColumnOption};
44
use crate::catalog::TableName;
55

6-
use crate::types::{ColumnId, IdGenerator, LogicalType};
6+
use crate::types::{ColumnId, LogicalType};
77

88
pub type ColumnRef = Arc<ColumnCatalog>;
99

1010
#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
1111
pub struct ColumnCatalog {
12-
pub id: ColumnId,
12+
pub id: Option<ColumnId>,
1313
pub name: String,
1414
pub table_name: Option<TableName>,
1515
pub nullable: bool,
@@ -19,7 +19,7 @@ pub struct ColumnCatalog {
1919
impl ColumnCatalog {
2020
pub(crate) fn new(column_name: String, nullable: bool, column_desc: ColumnDesc) -> ColumnCatalog {
2121
ColumnCatalog {
22-
id: IdGenerator::build(),
22+
id: None,
2323
name: column_name,
2424
table_name: None,
2525
nullable,
@@ -29,11 +29,11 @@ impl ColumnCatalog {
2929

3030
pub(crate) fn new_dummy(column_name: String)-> ColumnCatalog {
3131
ColumnCatalog {
32-
id: 0,
32+
id: Some(0),
3333
name: column_name,
3434
table_name: None,
3535
nullable: false,
36-
desc: ColumnDesc::new(LogicalType::Varchar(None), false),
36+
desc: ColumnDesc::new(LogicalType::Varchar(None), false, false),
3737
}
3838
}
3939

@@ -51,6 +51,7 @@ impl From<ColumnDef> for ColumnCatalog {
5151
let column_name = column_def.name.to_string();
5252
let mut column_desc = ColumnDesc::new(
5353
LogicalType::try_from(column_def.data_type).unwrap(),
54+
false,
5455
false
5556
);
5657
let mut nullable = false;
@@ -60,10 +61,15 @@ impl From<ColumnDef> for ColumnCatalog {
6061
match option_def.option {
6162
ColumnOption::Null => nullable = true,
6263
ColumnOption::NotNull => (),
63-
ColumnOption::Unique { is_primary: true } => {
64-
column_desc.is_primary = true;
65-
// Skip other options when using primary key
66-
break;
64+
ColumnOption::Unique { is_primary } => {
65+
if is_primary {
66+
column_desc.is_primary = true;
67+
nullable = false;
68+
// Skip other options when using primary key
69+
break;
70+
} else {
71+
column_desc.is_unique = true;
72+
}
6773
},
6874
_ => todo!()
6975
}
@@ -78,13 +84,15 @@ impl From<ColumnDef> for ColumnCatalog {
7884
pub struct ColumnDesc {
7985
pub(crate) column_datatype: LogicalType,
8086
pub(crate) is_primary: bool,
87+
pub(crate) is_unique: bool,
8188
}
8289

8390
impl ColumnDesc {
84-
pub(crate) const fn new(column_datatype: LogicalType, is_primary: bool) -> ColumnDesc {
91+
pub(crate) const fn new(column_datatype: LogicalType, is_primary: bool, is_unique: bool) -> ColumnDesc {
8592
ColumnDesc {
8693
column_datatype,
8794
is_primary,
95+
is_unique,
8896
}
8997
}
9098
}

src/catalog/root.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,12 @@ mod tests {
6767
let col0 = ColumnCatalog::new(
6868
"a".to_string(),
6969
false,
70-
ColumnDesc::new(LogicalType::Integer, false),
70+
ColumnDesc::new(LogicalType::Integer, false, false),
7171
);
7272
let col1 = ColumnCatalog::new(
7373
"b".to_string(),
7474
false,
75-
ColumnDesc::new(LogicalType::Boolean, false),
75+
ColumnDesc::new(LogicalType::Boolean, false, false),
7676
);
7777
let col_catalogs = vec![col0, col1];
7878

src/catalog/table.rs

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::sync::Arc;
33

44
use crate::catalog::{CatalogError, ColumnCatalog, ColumnRef};
55
use crate::types::ColumnId;
6+
use crate::types::index::{IndexMeta, IndexMetaRef};
67

78
pub type TableName = Arc<String>;
89

@@ -12,9 +13,16 @@ pub struct TableCatalog {
1213
/// Mapping from column names to column ids
1314
column_idxs: BTreeMap<String, ColumnId>,
1415
pub(crate) columns: BTreeMap<ColumnId, ColumnRef>,
16+
pub indexes: Vec<IndexMetaRef>
1517
}
1618

1719
impl TableCatalog {
20+
pub(crate) fn get_unique_index(&self, col_id: &ColumnId) -> Option<&IndexMetaRef> {
21+
self.indexes
22+
.iter()
23+
.find(|meta| meta.is_unique && &meta.column_ids[0] == col_id)
24+
}
25+
1826
pub(crate) fn get_column_by_id(&self, id: &ColumnId) -> Option<&ColumnRef> {
1927
self.columns.get(id)
2028
}
@@ -54,23 +62,34 @@ impl TableCatalog {
5462
return Err(CatalogError::Duplicated("column", col.name.clone()));
5563
}
5664

57-
let col_id = col.id;
65+
let col_id = self.columns.len() as u32;
5866

67+
col.id = Some(col_id);
5968
col.table_name = Some(self.name.clone());
6069
self.column_idxs.insert(col.name.clone(), col_id);
6170
self.columns.insert(col_id, Arc::new(col));
6271

6372
Ok(col_id)
6473
}
6574

75+
pub(crate) fn add_index_meta(&mut self, mut index: IndexMeta) -> &IndexMeta {
76+
let index_id = self.indexes.len();
77+
78+
index.id = index_id as u32;
79+
self.indexes.push(Arc::new(index));
80+
81+
&self.indexes[index_id]
82+
}
83+
6684
pub(crate) fn new(
6785
name: TableName,
68-
columns: Vec<ColumnCatalog>,
86+
columns: Vec<ColumnCatalog>
6987
) -> Result<TableCatalog, CatalogError> {
7088
let mut table_catalog = TableCatalog {
7189
name,
7290
column_idxs: BTreeMap::new(),
7391
columns: BTreeMap::new(),
92+
indexes: vec![],
7493
};
7594

7695
for col_catalog in columns.into_iter() {
@@ -79,6 +98,17 @@ impl TableCatalog {
7998

8099
Ok(table_catalog)
81100
}
101+
102+
pub(crate) fn new_with_indexes(
103+
name: TableName,
104+
columns: Vec<ColumnCatalog>,
105+
indexes: Vec<IndexMetaRef>
106+
) -> Result<TableCatalog, CatalogError> {
107+
let mut catalog = TableCatalog::new(name, columns)?;
108+
catalog.indexes = indexes;
109+
110+
Ok(catalog)
111+
}
82112
}
83113

84114
#[cfg(test)]
@@ -93,8 +123,8 @@ mod tests {
93123
// | 1 | true |
94124
// | 2 | false |
95125
fn test_table_catalog() {
96-
let col0 = ColumnCatalog::new("a".into(), false, ColumnDesc::new(LogicalType::Integer, false));
97-
let col1 = ColumnCatalog::new("b".into(), false, ColumnDesc::new(LogicalType::Boolean, false));
126+
let col0 = ColumnCatalog::new("a".into(), false, ColumnDesc::new(LogicalType::Integer, false, false));
127+
let col1 = ColumnCatalog::new("b".into(), false, ColumnDesc::new(LogicalType::Boolean, false, false));
98128
let col_catalogs = vec![col0, col1];
99129
let table_catalog = TableCatalog::new(Arc::new("test".to_string()), col_catalogs).unwrap();
100130

0 commit comments

Comments
 (0)