Files
turso/core/vtab_view.rs
Glauber Costa 145d6eede7 Implement very basic views using DBSP
This is just the bare minimum that I needed to convince myself that this
approach will work. The only views that we support are slices of the
main table: no aggregations, no joins, no projections.

drop view is implemented.
view population is implemented.
deletes, inserts and updates are implemented.

much like indexes before, a flag must be passed to enable views.
2025-08-10 23:34:04 -05:00

102 lines
3.1 KiB
Rust

use crate::incremental::view::IncrementalView;
use crate::{Connection, LimboError, Value, VirtualTable};
use std::sync::{Arc, Mutex};
/// Create a virtual table wrapper for a view
pub fn create_view_virtual_table(
view_name: &str,
view: Arc<Mutex<IncrementalView>>,
) -> crate::Result<Arc<VirtualTable>> {
// Use the VirtualTable::view method we added
let view_locked = view.lock().map_err(|_| {
LimboError::InternalError("Failed to lock view for virtual table creation".to_string())
})?;
let columns = view_locked.columns.clone();
drop(view_locked); // Release the lock before passing the Arc
VirtualTable::view(view_name, columns, view)
}
/// Virtual table wrapper for incremental views
#[derive(Clone, Debug)]
pub struct ViewVirtualTable {
pub view: Arc<Mutex<IncrementalView>>,
}
impl ViewVirtualTable {
pub fn best_index(&self) -> Result<turso_ext::IndexInfo, turso_ext::ResultCode> {
// Views don't use indexes - return a simple index info
Ok(turso_ext::IndexInfo {
idx_num: 0,
idx_str: None,
order_by_consumed: false,
estimated_cost: 1000000.0,
estimated_rows: 1000,
constraint_usages: Vec::new(),
})
}
pub fn open(&self, conn: Arc<Connection>) -> crate::Result<ViewVirtualTableCursor> {
// Views are now populated during schema parsing (in parse_schema_rows)
// so we just get the current data from the view.
let view = self.view.lock().map_err(|_| {
LimboError::InternalError("Failed to lock view for reading".to_string())
})?;
let tx_states = conn.view_transaction_states.borrow();
let tx_state = tx_states.get(view.name());
let data: Vec<(i64, Vec<Value>)> = view.current_data(tx_state);
Ok(ViewVirtualTableCursor {
data,
current_pos: 0,
})
}
}
/// Cursor for iterating over view data
pub struct ViewVirtualTableCursor {
data: Vec<(i64, Vec<Value>)>,
current_pos: usize,
}
impl ViewVirtualTableCursor {
pub fn next(&mut self) -> crate::Result<bool> {
if self.current_pos < self.data.len() {
self.current_pos += 1;
Ok(self.current_pos < self.data.len())
} else {
Ok(false)
}
}
pub fn rowid(&self) -> i64 {
if self.current_pos < self.data.len() {
self.data[self.current_pos].0
} else {
-1
}
}
pub fn column(&self, column: usize) -> crate::Result<Value> {
if self.current_pos >= self.data.len() {
return Ok(Value::Null);
}
let (_row_key, values) = &self.data[self.current_pos];
// Return the value at the requested column index
if let Some(value) = values.get(column) {
Ok(value.clone())
} else {
Ok(Value::Null)
}
}
pub fn filter(&mut self, _args: Vec<Value>) -> crate::Result<bool> {
// Reset to beginning for new filter
self.current_pos = 0;
Ok(!self.data.is_empty())
}
}