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