1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//! Database Table Management
//!
//! Extracted from database_legacy.rs
//! Contains table schema management and helper methods
use crate::types::{TableSchema, IndexDef, RowId};
use crate::{Result, StorageError};
use super::core::MoteDB;
impl MoteDB {
/// Create a new table with schema
///
/// Automatically creates a primary key index if defined
///
/// # Example
/// ```ignore
/// use motedb::types::{TableSchema, ColumnDef, ColumnType};
///
/// let schema = TableSchema::new("users")
/// .with_column(ColumnDef::new("id", ColumnType::Integer).primary_key())
/// .with_column(ColumnDef::new("name", ColumnType::Text));
///
/// db.create_table(schema)?;
/// ```
pub fn create_table(&self, schema: TableSchema) -> Result<()> {
// Register table in catalog (acquires metadata.write() lock)
self.table_registry.create_table(schema.clone())?;
// 🔓 Lock released here
// ✅ P0 FIX: Primary key index will be auto-created on first INSERT via incremental indexing
// No need to create empty index here - saves memory and avoids complexity
Ok(())
}
/// Drop a table
///
/// Note: This only removes the table metadata.
/// Existing rows and indexes are not automatically deleted.
///
/// # Example
/// ```ignore
/// db.drop_table("users")?;
/// ```
pub fn drop_table(&self, table_name: &str) -> Result<()> {
self.table_registry.drop_table(table_name)
}
/// Get table schema
///
/// # Example
/// ```ignore
/// let schema = db.get_table_schema("users")?;
/// println!("Table has {} columns", schema.column_count());
/// ```
pub fn get_table_schema(&self, table_name: &str) -> Result<TableSchema> {
self.table_registry.get_table(table_name)
}
/// List all tables
///
/// # Example
/// ```ignore
/// let tables = db.list_tables()?;
/// for table in tables {
/// println!("Table: {}", table);
/// }
/// ```
pub fn list_tables(&self) -> Result<Vec<String>> {
self.table_registry.list_tables()
}
/// Check if table exists
///
/// # Example
/// ```ignore
/// if db.table_exists("users") {
/// println!("Table exists");
/// }
/// ```
pub fn table_exists(&self, table_name: &str) -> bool {
self.table_registry.table_exists(table_name)
}
/// Add index to existing table
///
/// # Example
/// ```ignore
/// use motedb::types::{IndexDef, IndexType};
///
/// let index = IndexDef::new(
/// "users_name_idx".into(),
/// "users".into(),
/// "name".into(),
/// IndexType::FullText,
/// );
///
/// db.add_table_index(index)?;
/// ```
pub fn add_table_index(&self, index: IndexDef) -> Result<()> {
self.table_registry.add_index(index)
}
// ==================== Internal Helper Methods ====================
/// Make composite key from table name and row ID
///
/// Format: [table_id:32bits][row_id:32bits]
///
/// Uses stable sequential table_id from registry (collision-free),
/// replacing the old hash-based scheme that had birthday-attack collision risk.
pub(crate) fn make_composite_key(&self, table_name: &str, row_id: RowId) -> u64 {
let table_id = self.table_registry.get_table_id(table_name)
.unwrap_or(0); // fallback to 0 for unregistered tables
((table_id as u64) << 32) | (row_id & 0xFFFFFFFF)
}
/// Compute table prefix (upper 32 bits of composite key)
///
/// Uses stable sequential table_id from registry (collision-free).
pub(crate) fn compute_table_prefix(&self, table_name: &str) -> u64 {
let table_id = self.table_registry.get_table_id(table_name)
.unwrap_or(0);
table_id as u64
}
/// Extract row_id from composite key
#[allow(dead_code)]
pub(crate) fn extract_row_id(&self, composite_key: u64) -> RowId {
composite_key & 0xFFFFFFFF
}
/// Check if composite key belongs to table
#[allow(dead_code)]
pub(crate) fn key_matches_table(&self, composite_key: u64, table_name: &str) -> bool {
let table_id = self.table_registry.get_table_id(table_name)
.unwrap_or(0);
(composite_key >> 32) == table_id as u64
}
/// 🚀 P2: Get row cache for statistics and monitoring
pub fn get_row_cache(&self) -> &std::sync::Arc<crate::cache::RowCache> {
&self.row_cache
}
/// Decode row data from LSM storage format
///
/// Internal helper for query operations
pub(crate) fn decode_row_data(data: &[u8]) -> Result<crate::types::Row> {
bincode::deserialize(data)
.map_err(|e| StorageError::Serialization(format!("Failed to decode row: {}", e)))
}
// Note: create_column_index() has been moved to indexes/column.rs
// Removed duplicate definition to avoid E0592
}