vibesql_storage/database/
core.rs

1// ============================================================================
2// Database - Core struct definition and coordination
3// ============================================================================
4//
5// The Database struct is the main entry point for database operations.
6// Methods are organized into focused modules:
7// - transaction_api.rs: Transaction management (begin, commit, rollback, savepoints)
8// - table_api.rs: Table operations (create, drop, insert, update)
9// - point_lookup.rs: High-performance point lookups by primary key
10// - change_events_api.rs: Reactive change event broadcasting
11// - persistence_api.rs: WAL persistence and AUTO_INCREMENT support
12// - cache.rs: Columnar cache management
13// - session.rs: Session variables and SQL mode
14// - constructors.rs: Database creation and configuration
15
16use std::collections::HashMap;
17#[allow(unused_imports)]
18use std::sync::atomic::{AtomicU64, Ordering};
19#[allow(unused_imports)]
20use std::sync::Arc;
21
22pub use super::operations::SpatialIndexMetadata as ExportedSpatialIndexMetadata;
23use super::{lifecycle::Lifecycle, metadata::Metadata, operations::Operations};
24use crate::{
25    change_events::ChangeEventSender, columnar_cache::ColumnarCache, wal::PersistenceEngine,
26    QueryBufferPool, Table,
27};
28
29/// In-memory database - manages catalog and tables through focused modules
30///
31/// The Database struct coordinates between multiple internal modules to provide
32/// a complete database implementation. Each aspect of database functionality
33/// is organized into a focused module:
34///
35/// - **Transaction management**: `begin_transaction()`, `commit_transaction()`,
36///   `rollback_transaction()`, `create_savepoint()`, `rollback_to_savepoint()`
37/// - **Table operations**: `create_table()`, `drop_table()`, `get_table()`,
38///   `insert_row()`, `insert_rows_batch()`, `update_row_by_pk()`
39/// - **Point lookups**: `get_row_by_pk()`, `get_column_by_pk()`,
40///   `get_row_by_composite_pk()`
41/// - **Change events**: `enable_change_events()`, `subscribe_changes()`,
42///   `notify_update()`, `notify_deletes()`
43/// - **Persistence**: `enable_persistence()`, `sync_persistence()`,
44///   `last_insert_rowid()`
45/// - **Caching**: `get_columnar()`, `invalidate_columnar_cache()`,
46///   `columnar_cache_stats()`
47/// - **Session**: `set_sql_mode()`, `sql_mode()`, `get_session_variable()`,
48///   `set_session_variable()`
49#[derive(Debug)]
50pub struct Database {
51    /// Public catalog access for backward compatibility
52    pub catalog: vibesql_catalog::Catalog,
53    pub(super) lifecycle: Lifecycle,
54    pub(super) metadata: Metadata,
55    pub(super) operations: Operations,
56    pub tables: HashMap<String, Table>,
57    /// SQL compatibility mode (MySQL, SQLite, etc.)
58    pub(super) sql_mode: vibesql_types::SqlMode,
59    /// Buffer pool for reducing query execution allocations
60    pub(super) query_buffer_pool: QueryBufferPool,
61    /// LRU cache for columnar table representations
62    /// Shared via Arc to allow cloning without duplicating cache data
63    pub(super) columnar_cache: Arc<ColumnarCache>,
64    /// Optional broadcast channel for change event notifications
65    /// Enables reactive subscriptions when enabled
66    pub(super) change_sender: Option<ChangeEventSender>,
67    /// Last generated AUTO_INCREMENT value for LAST_INSERT_ROWID()
68    /// Tracks the most recent auto-generated ID from INSERT operations
69    pub(super) last_insert_rowid: i64,
70    /// Number of rows changed by the last INSERT/UPDATE/DELETE statement
71    /// Used by the changes() function for SQLite compatibility
72    pub(super) last_changes_count: usize,
73    /// Total number of rows changed since the database connection was opened
74    /// Used by the total_changes() function for SQLite compatibility
75    pub(super) total_changes_count: usize,
76    /// Search count for sqlite_search_count() compatibility
77    /// Tracks the number of rows examined during query execution
78    /// Used by SQLite TCL tests to verify query optimization behavior
79    pub(super) search_count: AtomicU64,
80    /// Optional persistence engine for WAL-based async persistence
81    /// Enables durable storage when enabled
82    pub(super) persistence_engine: Option<PersistenceEngine>,
83    /// Next table ID to assign (for WAL table_id tracking)
84    pub(super) next_table_id: u32,
85    /// Reserved rowids for REPLACE operations (SQLite semantics)
86    /// During REPLACE, the rowid for the new row is allocated BEFORE firing
87    /// BEFORE DELETE triggers. Any INSERT within those triggers that tries
88    /// to allocate the same rowid will fail with a UNIQUE constraint violation.
89    /// Maps table name to (reserved_rowid, is_explicit).
90    /// - is_explicit: true if the rowid comes from an explicit INTEGER PRIMARY KEY value
91    ///   in the REPLACE statement, false if it's auto-allocated.
92    pub(super) reserved_rowids: HashMap<String, (u64, bool)>,
93}
94
95impl Database {
96    // ============================================================================
97    // Query Buffer Pool
98    // ============================================================================
99
100    /// Get a reference to the query buffer pool for reusing allocations
101    pub fn query_buffer_pool(&self) -> &QueryBufferPool {
102        &self.query_buffer_pool
103    }
104
105    // ============================================================================
106    // Procedure/Function Body Cache Methods (Phase 6 Performance)
107    // ============================================================================
108
109    /// Get cached procedure body or cache it on first access
110    pub fn get_cached_procedure_body(
111        &mut self,
112        name: &str,
113    ) -> Result<&vibesql_catalog::ProcedureBody, crate::StorageError> {
114        if self.metadata.get_cached_procedure_body(name).is_none() {
115            let procedure = &self.catalog.get_procedure(name).ok_or_else(|| {
116                crate::StorageError::CatalogError(format!("Procedure '{}' not found", name))
117            })?;
118
119            self.metadata.cache_procedure_body(name.to_string(), procedure.body.clone());
120        }
121
122        Ok(self.metadata.get_cached_procedure_body(name).unwrap())
123    }
124
125    /// Invalidate cached procedure body (call when procedure is dropped or replaced)
126    pub fn invalidate_procedure_cache(&mut self, name: &str) {
127        self.metadata.invalidate_procedure_cache(name);
128    }
129
130    /// Clear all cached procedure/function bodies
131    pub fn clear_routine_cache(&mut self) {
132        self.metadata.clear_routine_cache();
133    }
134
135    // NOTE: Other method groups are defined in their respective modules:
136    // - Transaction methods: transaction_api.rs
137    // - Table methods: table_api.rs
138    // - Point lookup methods: point_lookup.rs
139    // - Change event methods: change_events_api.rs
140    // - Persistence methods: persistence_api.rs
141    // - Cache methods: cache.rs
142    // - Session methods: session.rs
143    // - Constructor: constructors.rs
144}