mirror of
https://github.com/aljazceru/turso.git
synced 2026-01-31 13:54:27 +01:00
add more integration in order to properly skip backing_btree index_method
This commit is contained in:
@@ -70,6 +70,7 @@ pub fn create_dbsp_state_index(root_page: i64) -> Index {
|
||||
ephemeral: false,
|
||||
has_rowid: true,
|
||||
where_clause: None,
|
||||
index_method: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
use crate::{
|
||||
io::clock::DefaultClock, Clock, Completion, File, Instant, LimboError, OpenFlags, Result, IO,
|
||||
};
|
||||
use crate::{io::clock::DefaultClock, Clock, Completion, File, Instant, OpenFlags, Result, IO};
|
||||
use parking_lot::RwLock;
|
||||
use std::io::{Read, Seek, Write};
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use crate::function::Func;
|
||||
use crate::incremental::view::IncrementalView;
|
||||
use crate::index_method::{IndexMethodAttachment, IndexMethodConfiguration};
|
||||
use crate::translate::expr::{
|
||||
bind_and_rewrite_expr, walk_expr, BindingBehavior, ParamState, WalkControl,
|
||||
};
|
||||
use crate::translate::index::resolve_sorted_columns;
|
||||
use crate::translate::index::{resolve_index_method_parameters, resolve_sorted_columns};
|
||||
use crate::translate::planner::ROWID_STRS;
|
||||
use parking_lot::RwLock;
|
||||
|
||||
@@ -368,6 +369,7 @@ impl Schema {
|
||||
.get(&name)
|
||||
.map(|v| v.iter())
|
||||
.unwrap_or_default()
|
||||
.filter(|i| !i.is_backing_btree_index())
|
||||
}
|
||||
|
||||
pub fn get_index(&self, table_name: &str, index_name: &str) -> Option<&Arc<Index>> {
|
||||
@@ -485,7 +487,7 @@ impl Schema {
|
||||
|
||||
pager.end_read_tx();
|
||||
|
||||
self.populate_indices(from_sql_indexes, automatic_indices)?;
|
||||
self.populate_indices(syms, from_sql_indexes, automatic_indices)?;
|
||||
|
||||
self.populate_materialized_views(
|
||||
materialized_view_info,
|
||||
@@ -501,6 +503,7 @@ impl Schema {
|
||||
/// automatic_indices: indices created automatically for primary key and unique constraints
|
||||
pub fn populate_indices(
|
||||
&mut self,
|
||||
syms: &SymbolTable,
|
||||
from_sql_indexes: Vec<UnparsedFromSqlIndex>,
|
||||
automatic_indices: std::collections::HashMap<String, Vec<(String, i64)>>,
|
||||
) -> Result<()> {
|
||||
@@ -512,6 +515,7 @@ impl Schema {
|
||||
.get_btree_table(&unparsed_sql_from_index.table_name)
|
||||
.unwrap();
|
||||
let index = Index::from_sql(
|
||||
syms,
|
||||
&unparsed_sql_from_index.sql,
|
||||
unparsed_sql_from_index.root_page,
|
||||
table.as_ref(),
|
||||
@@ -2419,6 +2423,7 @@ pub struct Index {
|
||||
/// and SELECT DISTINCT ephemeral indexes will not have a rowid.
|
||||
pub has_rowid: bool,
|
||||
pub where_clause: Option<Box<Expr>>,
|
||||
pub index_method: Option<Arc<dyn IndexMethodAttachment>>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@@ -2437,7 +2442,12 @@ pub struct IndexColumn {
|
||||
}
|
||||
|
||||
impl Index {
|
||||
pub fn from_sql(sql: &str, root_page: i64, table: &BTreeTable) -> Result<Index> {
|
||||
pub fn from_sql(
|
||||
syms: &SymbolTable,
|
||||
sql: &str,
|
||||
root_page: i64,
|
||||
table: &BTreeTable,
|
||||
) -> Result<Index> {
|
||||
let mut parser = Parser::new(sql.as_bytes());
|
||||
let cmd = parser.next_cmd()?;
|
||||
match cmd {
|
||||
@@ -2447,25 +2457,66 @@ impl Index {
|
||||
columns,
|
||||
unique,
|
||||
where_clause,
|
||||
using,
|
||||
with_clause,
|
||||
..
|
||||
})) => {
|
||||
let index_name = normalize_ident(idx_name.name.as_str());
|
||||
let index_columns = resolve_sorted_columns(table, &columns)?;
|
||||
Ok(Index {
|
||||
name: index_name,
|
||||
table_name: normalize_ident(tbl_name.as_str()),
|
||||
root_page,
|
||||
columns: index_columns,
|
||||
unique,
|
||||
ephemeral: false,
|
||||
has_rowid: table.has_rowid,
|
||||
where_clause,
|
||||
})
|
||||
if let Some(using) = using {
|
||||
if where_clause.is_some() {
|
||||
bail_parse_error!("custom index module do not support partial indices");
|
||||
}
|
||||
if unique {
|
||||
bail_parse_error!("custom index module do not support UNIQUE indices");
|
||||
}
|
||||
let parameters = resolve_index_method_parameters(with_clause)?;
|
||||
let Some(module) = syms.index_methods.get(using.as_str()) else {
|
||||
bail_parse_error!("unknown module name: '{}'", using);
|
||||
};
|
||||
let configuration = IndexMethodConfiguration {
|
||||
table_name: table.name.clone(),
|
||||
index_name: index_name.clone(),
|
||||
columns: index_columns.clone(),
|
||||
parameters,
|
||||
};
|
||||
let descriptor = module.attach(&configuration)?;
|
||||
Ok(Index {
|
||||
name: index_name,
|
||||
table_name: normalize_ident(tbl_name.as_str()),
|
||||
root_page,
|
||||
columns: index_columns,
|
||||
unique: false,
|
||||
ephemeral: false,
|
||||
has_rowid: table.has_rowid,
|
||||
where_clause: None,
|
||||
index_method: Some(descriptor),
|
||||
})
|
||||
} else {
|
||||
Ok(Index {
|
||||
name: index_name,
|
||||
table_name: normalize_ident(tbl_name.as_str()),
|
||||
root_page,
|
||||
columns: index_columns,
|
||||
unique,
|
||||
ephemeral: false,
|
||||
has_rowid: table.has_rowid,
|
||||
where_clause,
|
||||
index_method: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
_ => todo!("Expected create index statement"),
|
||||
}
|
||||
}
|
||||
|
||||
/// check if this is special backing_btree index created and managed by custom index_method
|
||||
pub fn is_backing_btree_index(&self) -> bool {
|
||||
self.index_method
|
||||
.as_ref()
|
||||
.is_some_and(|x| x.definition().backing_btree)
|
||||
}
|
||||
|
||||
pub fn automatic_from_primary_key(
|
||||
table: &BTreeTable,
|
||||
auto_index: (String, i64), // name, root_page
|
||||
@@ -2505,6 +2556,7 @@ impl Index {
|
||||
ephemeral: false,
|
||||
has_rowid: table.has_rowid,
|
||||
where_clause: None,
|
||||
index_method: None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2542,6 +2594,7 @@ impl Index {
|
||||
ephemeral: false,
|
||||
has_rowid: table.has_rowid,
|
||||
where_clause: None,
|
||||
index_method: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -8553,6 +8553,7 @@ mod tests {
|
||||
unique: false,
|
||||
ephemeral: false,
|
||||
has_rowid: false,
|
||||
index_method: None,
|
||||
};
|
||||
let num_columns = index_def.columns.len();
|
||||
let mut cursor =
|
||||
@@ -8712,6 +8713,7 @@ mod tests {
|
||||
unique: false,
|
||||
ephemeral: false,
|
||||
has_rowid: false,
|
||||
index_method: None,
|
||||
};
|
||||
let mut cursor = BTreeCursor::new_index(pager.clone(), index_root_page, &index_def, 1);
|
||||
|
||||
|
||||
@@ -432,6 +432,7 @@ fn create_dedupe_index(
|
||||
unique: false,
|
||||
has_rowid: false,
|
||||
where_clause: None,
|
||||
index_method: None,
|
||||
});
|
||||
let cursor_id = program.alloc_cursor_id(CursorType::BTreeIndex(dedupe_index.clone()));
|
||||
program.emit_insn(Insn::OpenEphemeral {
|
||||
|
||||
@@ -719,30 +719,24 @@ fn emit_delete_insns(
|
||||
});
|
||||
} else {
|
||||
// Delete from all indexes before deleting from the main table.
|
||||
let indexes = t_ctx.resolver.schema.indexes.get(table_name);
|
||||
let indexes = t_ctx.resolver.schema.get_indices(table_name);
|
||||
|
||||
// Get the index that is being used to iterate the deletion loop, if there is one.
|
||||
let iteration_index = unsafe { &*table_reference }.op.index();
|
||||
// Get all indexes that are not the iteration index.
|
||||
let other_indexes = indexes
|
||||
.map(|indexes| {
|
||||
indexes
|
||||
.iter()
|
||||
.filter(|index| {
|
||||
iteration_index
|
||||
.as_ref()
|
||||
.is_none_or(|it_idx| !Arc::ptr_eq(it_idx, index))
|
||||
})
|
||||
.map(|index| {
|
||||
(
|
||||
index.clone(),
|
||||
program
|
||||
.resolve_cursor_id(&CursorKey::index(internal_id, index.clone())),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.filter(|index| {
|
||||
iteration_index
|
||||
.as_ref()
|
||||
.is_none_or(|it_idx| !Arc::ptr_eq(it_idx, index))
|
||||
})
|
||||
.unwrap_or_default();
|
||||
.map(|index| {
|
||||
(
|
||||
index.clone(),
|
||||
program.resolve_cursor_id(&CursorKey::index(internal_id, index.clone())),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for (index, index_cursor_id) in other_indexes {
|
||||
let skip_delete_label = if index.where_clause.is_some() {
|
||||
|
||||
@@ -119,7 +119,7 @@ pub fn translate_create_index(
|
||||
);
|
||||
}
|
||||
|
||||
let mut module = None;
|
||||
let mut index_method = None;
|
||||
if let Some(using) = &using {
|
||||
let index_modules = &resolver.symbol_table.index_methods;
|
||||
let using = using.as_str();
|
||||
@@ -129,7 +129,7 @@ pub fn translate_create_index(
|
||||
}
|
||||
if let Some(index_module) = index_module {
|
||||
let parameters = resolve_index_method_parameters(with_clause)?;
|
||||
module = Some(index_module.attach(&IndexMethodConfiguration {
|
||||
index_method = Some(index_module.attach(&IndexMethodConfiguration {
|
||||
table_name: tbl.name.clone(),
|
||||
index_name: idx_name.clone(),
|
||||
columns: columns.clone(),
|
||||
@@ -148,6 +148,7 @@ pub fn translate_create_index(
|
||||
// store the *original* where clause, because we need to rewrite it
|
||||
// before translating, and it cannot reference a table alias
|
||||
where_clause: where_clause.clone(),
|
||||
index_method: index_method.clone(),
|
||||
});
|
||||
|
||||
if !idx.validate_where_expr(table) {
|
||||
@@ -225,7 +226,7 @@ pub fn translate_create_index(
|
||||
Some(sql),
|
||||
)?;
|
||||
|
||||
if module.is_none() {
|
||||
if index_method.is_none() {
|
||||
// determine the order of the columns in the index for the sorter
|
||||
let order = idx.columns.iter().map(|c| c.order).collect();
|
||||
// open the sorter and the pseudo table
|
||||
|
||||
@@ -99,6 +99,7 @@ pub fn init_distinct(program: &mut ProgramBuilder, plan: &SelectPlan) -> Result<
|
||||
unique: false,
|
||||
has_rowid: false,
|
||||
where_clause: None,
|
||||
index_method: None,
|
||||
});
|
||||
let cursor_id = program.alloc_cursor_id(CursorType::BTreeIndex(index.clone()));
|
||||
let ctx = DistinctCtx {
|
||||
@@ -173,6 +174,7 @@ pub fn init_loop(
|
||||
has_rowid: false,
|
||||
unique: false,
|
||||
where_clause: None,
|
||||
index_method: None,
|
||||
});
|
||||
let cursor_id = program.alloc_cursor_id(CursorType::BTreeIndex(index.clone()));
|
||||
if group_by.is_none() {
|
||||
@@ -240,25 +242,23 @@ pub fn init_loop(
|
||||
});
|
||||
}
|
||||
// For delete, we need to open all the other indexes too for writing
|
||||
if let Some(indexes) = t_ctx.resolver.schema.indexes.get(&btree.name) {
|
||||
for index in indexes {
|
||||
if table
|
||||
.op
|
||||
.index()
|
||||
.is_some_and(|table_index| table_index.name == index.name)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let cursor_id = program.alloc_cursor_id_keyed(
|
||||
CursorKey::index(table.internal_id, index.clone()),
|
||||
CursorType::BTreeIndex(index.clone()),
|
||||
);
|
||||
program.emit_insn(Insn::OpenWrite {
|
||||
cursor_id,
|
||||
root_page: index.root_page.into(),
|
||||
db: table.database_id,
|
||||
});
|
||||
for index in t_ctx.resolver.schema.get_indices(&btree.name) {
|
||||
if table
|
||||
.op
|
||||
.index()
|
||||
.is_some_and(|table_index| table_index.name == index.name)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let cursor_id = program.alloc_cursor_id_keyed(
|
||||
CursorKey::index(table.internal_id, index.clone()),
|
||||
CursorType::BTreeIndex(index.clone()),
|
||||
);
|
||||
program.emit_insn(Insn::OpenWrite {
|
||||
cursor_id,
|
||||
root_page: index.root_page.into(),
|
||||
db: table.database_id,
|
||||
});
|
||||
}
|
||||
}
|
||||
(OperationMode::UPDATE(update_mode), Table::BTree(btree)) => {
|
||||
@@ -335,27 +335,23 @@ pub fn init_loop(
|
||||
// For DELETE, we need to open all the indexes for writing
|
||||
// UPDATE opens these in emit_program_for_update() separately
|
||||
if matches!(mode, OperationMode::DELETE) {
|
||||
if let Some(indexes) =
|
||||
t_ctx.resolver.schema.indexes.get(table.table.get_name())
|
||||
{
|
||||
for index in indexes {
|
||||
if table
|
||||
.op
|
||||
.index()
|
||||
.is_some_and(|table_index| table_index.name == index.name)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let cursor_id = program.alloc_cursor_id_keyed(
|
||||
CursorKey::index(table.internal_id, index.clone()),
|
||||
CursorType::BTreeIndex(index.clone()),
|
||||
);
|
||||
program.emit_insn(Insn::OpenWrite {
|
||||
cursor_id,
|
||||
root_page: index.root_page.into(),
|
||||
db: table.database_id,
|
||||
});
|
||||
for index in t_ctx.resolver.schema.get_indices(table.table.get_name()) {
|
||||
if table
|
||||
.op
|
||||
.index()
|
||||
.is_some_and(|table_index| table_index.name == index.name)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let cursor_id = program.alloc_cursor_id_keyed(
|
||||
CursorKey::index(table.internal_id, index.clone()),
|
||||
CursorType::BTreeIndex(index.clone()),
|
||||
);
|
||||
program.emit_insn(Insn::OpenWrite {
|
||||
cursor_id,
|
||||
root_page: index.root_page.into(),
|
||||
db: table.database_id,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -675,6 +675,7 @@ mod tests {
|
||||
ephemeral: false,
|
||||
root_page: 1,
|
||||
has_rowid: true,
|
||||
index_method: None,
|
||||
});
|
||||
available_indexes.insert("test_table".to_string(), VecDeque::from([index]));
|
||||
|
||||
@@ -744,6 +745,7 @@ mod tests {
|
||||
ephemeral: false,
|
||||
root_page: 1,
|
||||
has_rowid: true,
|
||||
index_method: None,
|
||||
});
|
||||
available_indexes.insert("table1".to_string(), VecDeque::from([index1]));
|
||||
|
||||
@@ -861,6 +863,7 @@ mod tests {
|
||||
ephemeral: false,
|
||||
root_page: 1,
|
||||
has_rowid: true,
|
||||
index_method: None,
|
||||
});
|
||||
available_indexes.insert(table_name.to_string(), VecDeque::from([index]));
|
||||
});
|
||||
@@ -879,6 +882,7 @@ mod tests {
|
||||
ephemeral: false,
|
||||
root_page: 1,
|
||||
has_rowid: true,
|
||||
index_method: None,
|
||||
});
|
||||
let order_id_idx = Arc::new(Index {
|
||||
name: "order_items_order_id_idx".to_string(),
|
||||
@@ -895,6 +899,7 @@ mod tests {
|
||||
ephemeral: false,
|
||||
root_page: 1,
|
||||
has_rowid: true,
|
||||
index_method: None,
|
||||
});
|
||||
|
||||
available_indexes
|
||||
@@ -1318,6 +1323,7 @@ mod tests {
|
||||
root_page: 2,
|
||||
ephemeral: false,
|
||||
has_rowid: true,
|
||||
index_method: None,
|
||||
});
|
||||
|
||||
let mut available_indexes = HashMap::new();
|
||||
@@ -1412,6 +1418,7 @@ mod tests {
|
||||
root_page: 2,
|
||||
ephemeral: false,
|
||||
has_rowid: true,
|
||||
index_method: None,
|
||||
});
|
||||
available_indexes.insert("t1".to_string(), VecDeque::from([index]));
|
||||
|
||||
@@ -1524,6 +1531,7 @@ mod tests {
|
||||
ephemeral: false,
|
||||
has_rowid: true,
|
||||
unique: false,
|
||||
index_method: None,
|
||||
});
|
||||
available_indexes.insert("t1".to_string(), VecDeque::from([index]));
|
||||
|
||||
|
||||
@@ -1076,6 +1076,7 @@ fn ephemeral_index_build(
|
||||
.table
|
||||
.btree()
|
||||
.is_some_and(|btree| btree.has_rowid),
|
||||
index_method: None,
|
||||
};
|
||||
|
||||
ephemeral_index
|
||||
|
||||
@@ -109,6 +109,7 @@ pub fn init_order_by(
|
||||
unique: false,
|
||||
has_rowid: false,
|
||||
where_clause: None,
|
||||
index_method: None,
|
||||
});
|
||||
program.alloc_cursor_id(CursorType::BTreeIndex(index))
|
||||
} else {
|
||||
|
||||
@@ -1000,6 +1000,9 @@ impl JoinedTable {
|
||||
if self.col_used_mask.is_empty() {
|
||||
return false;
|
||||
}
|
||||
if index.index_method.is_some() {
|
||||
return false;
|
||||
}
|
||||
let mut index_cols_mask = ColumnUsedMask::default();
|
||||
for col in index.columns.iter() {
|
||||
index_cols_mask.set(col.pos_in_table);
|
||||
|
||||
@@ -182,7 +182,7 @@ pub fn parse_schema_rows(
|
||||
}
|
||||
}
|
||||
|
||||
schema.populate_indices(from_sql_indexes, automatic_indices)?;
|
||||
schema.populate_indices(syms, from_sql_indexes, automatic_indices)?;
|
||||
schema.populate_materialized_views(
|
||||
materialized_view_info,
|
||||
dbsp_state_roots,
|
||||
|
||||
Reference in New Issue
Block a user