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}