|
1 | 1 | use super::container::{BaseContainer, TailContainer}; |
2 | 2 | use super::page::PhysicalPage; |
3 | 3 | use pyo3::prelude::*; |
| 4 | +use std::collections::BTreeMap; |
4 | 5 | use std::collections::HashMap; |
5 | 6 | use std::sync::{Arc, Mutex}; |
6 | 7 |
|
| 8 | +/* A data strucutre holding indices for various columns of a table. |
| 9 | +Key column should be indexd by default, other columns can be indexed through this object. |
| 10 | +Indices are usually B-Trees, but other data structures can be used as well. */ |
| 11 | + |
| 12 | +#[pyclass] |
| 13 | +#[derive(Clone)] |
| 14 | +pub struct RIndex { |
| 15 | + /* EXPLANATION OF BTree, NOT TOO SURE ABOUT THIS. |
| 16 | +
|
| 17 | + A vector of BTreeMaps, can be either Some::BTreeMap or None as its elements. |
| 18 | +
|
| 19 | + BTreeMap<i64, Vec<[usize; 3]>>: |
| 20 | + -- BTreeMap: A balanced binary search tree (B-Tree), for maintaining sorted key-value pairs. -- |
| 21 | +
|
| 22 | + Map primary key to RID |
| 23 | + */ |
| 24 | + indices: Vec<Option<BTreeMap<u64, Vec<u64>>>>, |
| 25 | +} |
| 26 | + |
| 27 | +impl RIndex { |
| 28 | + // Mandatory: One index for each table. All our empty initially. |
| 29 | + pub fn new(primary_key_column: u64, num_columns: usize) -> RIndex { |
| 30 | + let mut indices = vec![None; num_columns]; // table.columns.len() |
| 31 | + indices[primary_key_column as usize] = Some(BTreeMap::new()); |
| 32 | + RIndex { indices } |
| 33 | + } |
| 34 | + |
| 35 | + /// Returns the location of all records with the given value on column "column" |
| 36 | + pub fn locate(&self, column: usize, value: u64) -> Option<&Vec<u64>> { |
| 37 | + if let Some(tree) = &self.indices[column] { |
| 38 | + return tree.get(&value); |
| 39 | + } |
| 40 | + None |
| 41 | + } |
| 42 | + |
| 43 | + /// Returns the RIDs of all records with values in column "column" between "begin" and "end" |
| 44 | + pub fn locate_range(&self, begin: u64, end: u64, column: usize) -> Vec<u64> { |
| 45 | + if let Some(tree) = &self.indices[column] { |
| 46 | + // Gets all entries where the key is between begin and end |
| 47 | + let keys = tree.range(begin..=end); |
| 48 | + |
| 49 | + let all_records: Vec<u64> = keys.flat_map(|(_, rids)| rids.clone()).collect(); |
| 50 | + return all_records; |
| 51 | + } |
| 52 | + Vec::new() |
| 53 | + } |
| 54 | + |
| 55 | + /// Create index on specific column |
| 56 | + pub fn create_index(&mut self, column: usize) { |
| 57 | + // Create BTree for column |
| 58 | + if self.indices[column].is_none() { |
| 59 | + self.indices[column] = Some(BTreeMap::new()); |
| 60 | + // Populate new index with existing records |
| 61 | + |
| 62 | + // let table = self.table.lock().unwrap(); |
| 63 | + // for rid in table.page_directory.keys() { |
| 64 | + // let row = table.fetch_row(*rid); |
| 65 | + // let value = row[column]; |
| 66 | + |
| 67 | + // // Add RID to index |
| 68 | + // self.update_index(value, [*rid as usize, column, 0], column).unwrap(); |
| 69 | + // } |
| 70 | + } |
| 71 | + } |
| 72 | + |
| 73 | + /// Insert or update index for a specific column |
| 74 | + pub fn update_index(&mut self, key: u64, rid: u64, column: usize) -> Result<(), String> { |
| 75 | + if column >= self.indices.len() { |
| 76 | + return Err(format!("Column {} does not exist'", column)); |
| 77 | + } |
| 78 | + // Gets column Some::BTreeMap, creates one if None |
| 79 | + let tree = self.indices[column].get_or_insert_with(BTreeMap::new); |
| 80 | + |
| 81 | + // Insert or update key |
| 82 | + // Searches for the given key in the BTree, If the key exists, it returns a mutable reference to the corresponding value, |
| 83 | + // If the key does not exist, it creates a new entry in the BTree for the key, If the key does not exist, this initializes an empty vector (Vec::new) as the value for the key. |
| 84 | + // Appends the provided RID to the vector associated with the key |
| 85 | + tree.entry(key).or_insert_with(Vec::new).push(rid); |
| 86 | + Ok(()) |
| 87 | + } |
| 88 | + |
| 89 | + pub fn delete_from_index(&mut self, column: usize, key: u64, rid: u64) { |
| 90 | + if let Some(tree) = &mut self.indices[column] { |
| 91 | + if let Some(rids) = tree.get_mut(&key) { |
| 92 | + // Find the position of the RID to remove |
| 93 | + if let Some(pos) = rids.iter().position(|&p| p == rid) { |
| 94 | + rids.remove(pos); |
| 95 | + } |
| 96 | + // If no more RID's exist for this key, remove the key |
| 97 | + if rids.is_empty() { |
| 98 | + tree.remove(&key); |
| 99 | + } |
| 100 | + } |
| 101 | + } |
| 102 | + } |
| 103 | + |
| 104 | + /// Drop index of specific column |
| 105 | + pub fn drop_index(&mut self, column: usize) { |
| 106 | + self.indices[column] = None; |
| 107 | + } |
| 108 | +} |
| 109 | + |
7 | 110 | #[derive(Clone)] |
8 | 111 | pub struct PageRange { |
9 | 112 | base_container: BaseContainer, |
@@ -80,7 +183,9 @@ pub struct RTable { |
80 | 183 | pub num_records: u64, |
81 | 184 |
|
82 | 185 | #[pyo3(get)] |
83 | | - pub num_columns: i64, |
| 186 | + pub num_columns: usize, |
| 187 | + |
| 188 | + pub index: RIndex, |
84 | 189 | } |
85 | 190 |
|
86 | 191 | impl RTable { |
@@ -154,19 +259,15 @@ impl RDatabase { |
154 | 259 | unreachable!("Not used in milestone 1"); |
155 | 260 | } |
156 | 261 |
|
157 | | - fn create_table( |
158 | | - &mut self, |
159 | | - name: String, |
160 | | - num_columns: i64, |
161 | | - primary_key_column: usize, |
162 | | - ) -> RTable { |
| 262 | + fn create_table(&mut self, name: String, num_columns: u64, primary_key_column: u64) -> RTable { |
163 | 263 | let t = RTable { |
164 | 264 | name: name.clone(), |
165 | 265 | page_range: PageRange::new(num_columns as u64), |
166 | | - primary_key_column, |
| 266 | + primary_key_column: primary_key_column as usize, |
167 | 267 | page_directory: HashMap::new(), |
168 | | - num_columns: 1, |
| 268 | + num_columns: num_columns as usize, |
169 | 269 | num_records: 0, |
| 270 | + index: RIndex::new(primary_key_column, num_columns as usize), |
170 | 271 | }; |
171 | 272 |
|
172 | 273 | let i = self.tables.len(); |
|
0 commit comments