llkv_runtime/runtime_storage_namespace/
namespace.rs1use std::any::Any;
10use std::sync::{Arc, RwLock};
11
12use llkv_executor::ExecutorTable;
13use llkv_plan::{
14 AlterTablePlan, CreateIndexPlan, CreateTablePlan, CreateViewPlan, DropIndexPlan, DropTablePlan,
15 DropViewPlan, PlanOperation, RenameTablePlan,
16};
17use llkv_result::Error;
18use llkv_storage::pager::BoxedPager;
19use llkv_transaction::TransactionResult;
20
21use crate::{RuntimeContext, RuntimeStatementResult};
22use llkv_table::{CatalogDdl, SingleColumnIndexDescriptor};
23
24pub type RuntimeNamespaceId = String;
26
27pub const PERSISTENT_NAMESPACE_ID: &str = "main";
29pub const TEMPORARY_NAMESPACE_ID: &str = "temp";
31
32pub trait RuntimeStorageNamespace: Send + Sync + 'static {
39 fn namespace_id(&self) -> &RuntimeNamespaceId;
41
42 fn context(&self) -> Arc<RuntimeContext<BoxedPager>>;
44
45 fn create_table(
47 &self,
48 plan: CreateTablePlan,
49 ) -> crate::Result<RuntimeStatementResult<BoxedPager>>;
50
51 fn drop_table(&self, plan: DropTablePlan) -> crate::Result<()>;
53
54 fn rename_table(&self, plan: RenameTablePlan) -> crate::Result<()>;
56
57 fn alter_table(
59 &self,
60 plan: AlterTablePlan,
61 ) -> crate::Result<RuntimeStatementResult<BoxedPager>>;
62
63 fn create_index(
65 &self,
66 plan: CreateIndexPlan,
67 ) -> crate::Result<RuntimeStatementResult<BoxedPager>>;
68
69 fn drop_index(&self, plan: DropIndexPlan)
71 -> crate::Result<Option<SingleColumnIndexDescriptor>>;
72
73 fn create_view(&self, plan: CreateViewPlan) -> crate::Result<()>;
75
76 fn drop_view(&self, plan: DropViewPlan) -> crate::Result<()>;
78
79 fn execute_operation(
82 &self,
83 operation: PlanOperation,
84 ) -> crate::Result<TransactionResult<BoxedPager>> {
85 let _ = operation;
86 Err(Error::Internal(format!(
87 "runtime namespace '{}' does not yet support execute_operation",
88 self.namespace_id()
89 )))
90 }
91
92 fn lookup_table(&self, canonical: &str) -> crate::Result<Arc<ExecutorTable<BoxedPager>>>;
94
95 fn list_tables(&self) -> Vec<String>;
97}
98
99pub trait RuntimeStorageNamespaceOps: Send + Sync {
102 fn namespace_id(&self) -> &RuntimeNamespaceId;
103 fn list_tables(&self) -> Vec<String>;
104 fn as_any(&self) -> &dyn Any;
105}
106
107impl<T> RuntimeStorageNamespaceOps for T
108where
109 T: RuntimeStorageNamespace,
110{
111 fn namespace_id(&self) -> &RuntimeNamespaceId {
112 RuntimeStorageNamespace::namespace_id(self)
113 }
114
115 fn list_tables(&self) -> Vec<String> {
116 RuntimeStorageNamespace::list_tables(self)
117 }
118
119 fn as_any(&self) -> &dyn Any {
120 self
121 }
122}
123
124#[derive(Clone)]
126pub struct PersistentRuntimeNamespace {
127 id: RuntimeNamespaceId,
128 context: Arc<RuntimeContext<BoxedPager>>,
129}
130
131impl PersistentRuntimeNamespace {
132 pub fn new(id: RuntimeNamespaceId, context: Arc<RuntimeContext<BoxedPager>>) -> Self {
133 Self { id, context }
134 }
135}
136
137impl RuntimeStorageNamespace for PersistentRuntimeNamespace {
138 fn namespace_id(&self) -> &RuntimeNamespaceId {
139 &self.id
140 }
141
142 fn context(&self) -> Arc<RuntimeContext<BoxedPager>> {
143 Arc::clone(&self.context)
144 }
145
146 fn create_table(
147 &self,
148 plan: CreateTablePlan,
149 ) -> crate::Result<RuntimeStatementResult<BoxedPager>> {
150 CatalogDdl::create_table(self.context.as_ref(), plan)
151 }
152
153 fn drop_table(&self, plan: DropTablePlan) -> crate::Result<()> {
154 CatalogDdl::drop_table(self.context.as_ref(), plan)
155 }
156
157 fn rename_table(&self, plan: RenameTablePlan) -> crate::Result<()> {
158 CatalogDdl::rename_table(self.context.as_ref(), plan)
159 }
160
161 fn alter_table(
162 &self,
163 plan: AlterTablePlan,
164 ) -> crate::Result<RuntimeStatementResult<BoxedPager>> {
165 CatalogDdl::alter_table(self.context.as_ref(), plan)
166 }
167
168 fn create_index(
169 &self,
170 plan: CreateIndexPlan,
171 ) -> crate::Result<RuntimeStatementResult<BoxedPager>> {
172 CatalogDdl::create_index(self.context.as_ref(), plan)
173 }
174
175 fn drop_index(
176 &self,
177 plan: DropIndexPlan,
178 ) -> crate::Result<Option<SingleColumnIndexDescriptor>> {
179 CatalogDdl::drop_index(self.context.as_ref(), plan)
180 }
181
182 fn create_view(&self, plan: CreateViewPlan) -> crate::Result<()> {
183 let view_definition = plan.view_definition.clone();
184 let select_plan = *plan.select_plan.clone();
185 let context_arc = Arc::clone(&self.context);
186 context_arc.create_view(&plan.name, view_definition, select_plan, plan.if_not_exists)
187 }
188
189 fn drop_view(&self, plan: DropViewPlan) -> crate::Result<()> {
190 self.context.drop_view(&plan.name, plan.if_exists)
191 }
192
193 fn lookup_table(&self, canonical: &str) -> crate::Result<Arc<ExecutorTable<BoxedPager>>> {
194 self.context.lookup_table(canonical)
195 }
196
197 fn list_tables(&self) -> Vec<String> {
198 self.context.table_names()
199 }
200}
201
202#[derive(Clone)]
204pub struct TemporaryRuntimeNamespace {
205 id: RuntimeNamespaceId,
206 context: Arc<RwLock<Arc<RuntimeContext<BoxedPager>>>>,
207}
208
209impl TemporaryRuntimeNamespace {
210 pub fn new(id: RuntimeNamespaceId, context: Arc<RuntimeContext<BoxedPager>>) -> Self {
211 Self {
212 id,
213 context: Arc::new(RwLock::new(context)),
214 }
215 }
216
217 pub fn replace_context(&self, context: Arc<RuntimeContext<BoxedPager>>) {
218 let mut guard = self
219 .context
220 .write()
221 .expect("temporary context lock poisoned");
222 *guard = context;
223 }
224
225 pub fn clear_tables<I>(&self, canonical_names: I)
226 where
227 I: IntoIterator<Item = String>,
228 {
229 let canonical_names: Vec<String> = canonical_names.into_iter().collect();
230 if canonical_names.is_empty() {
231 return;
232 }
233
234 let catalog = self.context().table_catalog();
235 for canonical in canonical_names {
236 if let Some(table_id) = catalog.table_id(&canonical)
237 && catalog.unregister_table(table_id)
238 {
239 tracing::debug!(
240 "[TEMP] Unregistered temporary table '{}' from shared catalog",
241 canonical
242 );
243 }
244 }
245 }
246
247 pub fn context(&self) -> Arc<RuntimeContext<BoxedPager>> {
248 Arc::clone(
249 &self
250 .context
251 .read()
252 .expect("temporary context lock poisoned"),
253 )
254 }
255}
256
257impl RuntimeStorageNamespace for TemporaryRuntimeNamespace {
258 fn namespace_id(&self) -> &RuntimeNamespaceId {
259 &self.id
260 }
261
262 fn context(&self) -> Arc<RuntimeContext<BoxedPager>> {
263 self.context()
264 }
265
266 fn create_table(
267 &self,
268 plan: CreateTablePlan,
269 ) -> crate::Result<RuntimeStatementResult<BoxedPager>> {
270 let context = self.context();
271 let result = CatalogDdl::create_table(context.as_ref(), plan)?;
272 Ok(result)
273 }
274
275 fn drop_table(&self, plan: DropTablePlan) -> crate::Result<()> {
276 let context = self.context();
277 CatalogDdl::drop_table(context.as_ref(), plan)?;
278 Ok(())
279 }
280
281 fn rename_table(&self, plan: RenameTablePlan) -> crate::Result<()> {
282 let context = self.context();
283 CatalogDdl::rename_table(context.as_ref(), plan)?;
284 Ok(())
285 }
286
287 fn alter_table(
288 &self,
289 plan: AlterTablePlan,
290 ) -> crate::Result<RuntimeStatementResult<BoxedPager>> {
291 let context = self.context();
292 CatalogDdl::alter_table(context.as_ref(), plan)
293 }
294
295 fn create_index(
296 &self,
297 plan: CreateIndexPlan,
298 ) -> crate::Result<RuntimeStatementResult<BoxedPager>> {
299 let context = self.context();
300 CatalogDdl::create_index(context.as_ref(), plan)
301 }
302
303 fn drop_index(
304 &self,
305 plan: DropIndexPlan,
306 ) -> crate::Result<Option<SingleColumnIndexDescriptor>> {
307 let context = self.context();
308 CatalogDdl::drop_index(context.as_ref(), plan)
309 }
310
311 fn create_view(&self, plan: CreateViewPlan) -> crate::Result<()> {
312 let context = self.context(); let view_definition = plan.view_definition.clone();
314 let select_plan = *plan.select_plan.clone();
315 context.create_view(&plan.name, view_definition, select_plan, plan.if_not_exists)
316 }
317
318 fn drop_view(&self, plan: DropViewPlan) -> crate::Result<()> {
319 let context = self.context();
320 context.drop_view(&plan.name, plan.if_exists)
321 }
322
323 fn lookup_table(&self, canonical: &str) -> crate::Result<Arc<ExecutorTable<BoxedPager>>> {
324 self.context().lookup_table(canonical)
326 }
327
328 fn list_tables(&self) -> Vec<String> {
329 self.context().table_names()
330 }
331}