1mod cluster_info;
16pub mod columns;
17pub mod flow_statistics;
18pub mod flows;
19mod information_memory_table;
20pub mod key_column_usage;
21mod partitions;
22mod procedure_info;
23pub mod process_list;
24#[cfg(feature = "enterprise")]
25mod recycle_bin;
26mod region_info;
27pub mod region_peers;
28mod region_statistics;
29pub mod schemata;
30mod ssts;
31pub mod statistics;
32mod table_constraints;
33mod table_names;
34mod table_semantics;
35pub mod tables;
36mod views;
37
38#[cfg(all(test, feature = "enterprise"))]
39mod recycle_bin_test;
40
41use std::collections::HashMap;
42use std::sync::{Arc, Weak};
43
44use common_catalog::consts::{self, DEFAULT_CATALOG_NAME, INFORMATION_SCHEMA_NAME};
45use common_error::ext::ErrorExt;
46use common_meta::cluster::NodeInfo;
47use common_meta::datanode::RegionStat;
48use common_meta::key::flow::FlowMetadataManager;
49use common_meta::key::flow::flow_state::FlowStat;
50use common_meta::kv_backend::KvBackendRef;
51use common_procedure::ProcedureInfo;
52use common_recordbatch::SendableRecordBatchStream;
53use datafusion::error::DataFusionError;
54use datafusion::logical_expr::LogicalPlan;
55use datafusion::physical_plan::ExecutionPlan;
56use datatypes::schema::SchemaRef;
57use lazy_static::lazy_static;
58use paste::paste;
59use process_list::InformationSchemaProcessList;
60use region_info::InformationSchemaRegionInfo;
61use store_api::metric_engine_consts::{
62 MEMTABLE_PARTITION_TREE_PRIMARY_KEY_ENCODING, PRIMARY_KEY_ENCODING,
63};
64use store_api::region_info::RegionInfoEntry;
65use store_api::sst_entry::{ManifestSstEntry, PuffinIndexMetaEntry, StorageSstEntry};
66use store_api::storage::{ScanRequest, TableId};
67use table::TableRef;
68use table::metadata::TableType;
69pub use table_names::*;
70use views::InformationSchemaViews;
71
72use self::columns::InformationSchemaColumns;
73use crate::CatalogManager;
74use crate::error::{Error, Result};
75use crate::process_manager::ProcessManagerRef;
76use crate::system_schema::information_schema::cluster_info::InformationSchemaClusterInfo;
77use crate::system_schema::information_schema::flow_statistics::InformationSchemaFlowStatistics;
78use crate::system_schema::information_schema::flows::InformationSchemaFlows;
79use crate::system_schema::information_schema::information_memory_table::get_schema_columns;
80use crate::system_schema::information_schema::key_column_usage::InformationSchemaKeyColumnUsage;
81use crate::system_schema::information_schema::partitions::InformationSchemaPartitions;
82#[cfg(feature = "enterprise")]
83use crate::system_schema::information_schema::recycle_bin::InformationSchemaRecycleBin;
84use crate::system_schema::information_schema::region_peers::InformationSchemaRegionPeers;
85use crate::system_schema::information_schema::schemata::InformationSchemaSchemata;
86use crate::system_schema::information_schema::ssts::{
87 InformationSchemaSstsIndexMeta, InformationSchemaSstsManifest, InformationSchemaSstsStorage,
88};
89use crate::system_schema::information_schema::statistics::InformationSchemaStatistics;
90use crate::system_schema::information_schema::table_constraints::InformationSchemaTableConstraints;
91use crate::system_schema::information_schema::table_semantics::InformationSchemaTableSemantics;
92use crate::system_schema::information_schema::tables::InformationSchemaTables;
93use crate::system_schema::memory_table::MemoryTable;
94pub(crate) use crate::system_schema::predicate::Predicates;
95use crate::system_schema::{
96 SystemSchemaProvider, SystemSchemaProviderInner, SystemTable, SystemTableRef,
97};
98
99const DENSE_PRIMARY_KEY_ENCODING: &str = "dense";
100const SPARSE_PRIMARY_KEY_ENCODING: &str = "sparse";
101
102pub(crate) fn primary_key_encoding_index_type(options: &HashMap<String, String>) -> &'static str {
103 options
104 .get(PRIMARY_KEY_ENCODING)
105 .or_else(|| options.get(MEMTABLE_PARTITION_TREE_PRIMARY_KEY_ENCODING))
106 .map(|value| {
107 if value.eq_ignore_ascii_case(SPARSE_PRIMARY_KEY_ENCODING) {
108 SPARSE_PRIMARY_KEY_ENCODING
109 } else {
110 DENSE_PRIMARY_KEY_ENCODING
111 }
112 })
113 .unwrap_or(DENSE_PRIMARY_KEY_ENCODING)
114}
115
116lazy_static! {
117 static ref MEMORY_TABLES: &'static [&'static str] = &[
119 ENGINES,
120 COLUMN_PRIVILEGES,
121 COLUMN_STATISTICS,
122 CHARACTER_SETS,
123 COLLATIONS,
124 COLLATION_CHARACTER_SET_APPLICABILITY,
125 CHECK_CONSTRAINTS,
126 EVENTS,
127 FILES,
128 OPTIMIZER_TRACE,
129 PARAMETERS,
130 PROFILING,
131 REFERENTIAL_CONSTRAINTS,
132 ROUTINES,
133 SCHEMA_PRIVILEGES,
134 TABLE_PRIVILEGES,
135 GLOBAL_STATUS,
136 SESSION_STATUS,
137 PARTITIONS,
138 ];
139}
140
141macro_rules! setup_memory_table {
142 ($name: expr) => {
143 paste! {
144 {
145 let (schema, columns) = get_schema_columns($name);
146 Some(Arc::new(MemoryTable::new(
147 consts::[<INFORMATION_SCHEMA_ $name _TABLE_ID>],
148 $name,
149 schema,
150 columns
151 )) as _)
152 }
153 }
154 };
155}
156
157pub struct MakeInformationTableRequest {
158 pub catalog_name: String,
159 pub catalog_manager: Weak<dyn CatalogManager>,
160 pub kv_backend: KvBackendRef,
161}
162
163pub trait InformationSchemaTableFactory {
168 fn make_information_table(&self, req: MakeInformationTableRequest) -> SystemTableRef;
169}
170
171pub type InformationSchemaTableFactoryRef = Arc<dyn InformationSchemaTableFactory + Send + Sync>;
172
173pub struct InformationSchemaProvider {
175 catalog_name: String,
176 catalog_manager: Weak<dyn CatalogManager>,
177 process_manager: Option<ProcessManagerRef>,
178 flow_metadata_manager: Arc<FlowMetadataManager>,
179 tables: HashMap<String, TableRef>,
180 kv_backend: KvBackendRef,
181 extra_table_factories: HashMap<String, InformationSchemaTableFactoryRef>,
182}
183
184impl SystemSchemaProvider for InformationSchemaProvider {
185 fn tables(&self) -> &HashMap<String, TableRef> {
186 assert!(!self.tables.is_empty());
187
188 &self.tables
189 }
190}
191
192impl SystemSchemaProviderInner for InformationSchemaProvider {
193 fn catalog_name(&self) -> &str {
194 &self.catalog_name
195 }
196 fn schema_name() -> &'static str {
197 INFORMATION_SCHEMA_NAME
198 }
199
200 fn system_table(&self, name: &str) -> Option<SystemTableRef> {
201 if let Some(factory) = self.extra_table_factories.get(name) {
202 let req = MakeInformationTableRequest {
203 catalog_name: self.catalog_name.clone(),
204 catalog_manager: self.catalog_manager.clone(),
205 kv_backend: self.kv_backend.clone(),
206 };
207 return Some(factory.make_information_table(req));
208 }
209
210 match name.to_ascii_lowercase().as_str() {
211 TABLES => Some(Arc::new(InformationSchemaTables::new(
212 self.catalog_name.clone(),
213 self.catalog_manager.clone(),
214 )) as _),
215 COLUMNS => Some(Arc::new(InformationSchemaColumns::new(
216 self.catalog_name.clone(),
217 self.catalog_manager.clone(),
218 )) as _),
219 ENGINES => setup_memory_table!(ENGINES),
220 COLUMN_PRIVILEGES => setup_memory_table!(COLUMN_PRIVILEGES),
221 COLUMN_STATISTICS => setup_memory_table!(COLUMN_STATISTICS),
222 BUILD_INFO => setup_memory_table!(BUILD_INFO),
223 CHARACTER_SETS => setup_memory_table!(CHARACTER_SETS),
224 COLLATIONS => setup_memory_table!(COLLATIONS),
225 COLLATION_CHARACTER_SET_APPLICABILITY => {
226 setup_memory_table!(COLLATION_CHARACTER_SET_APPLICABILITY)
227 }
228 CHECK_CONSTRAINTS => setup_memory_table!(CHECK_CONSTRAINTS),
229 EVENTS => setup_memory_table!(EVENTS),
230 FILES => setup_memory_table!(FILES),
231 OPTIMIZER_TRACE => setup_memory_table!(OPTIMIZER_TRACE),
232 PARAMETERS => setup_memory_table!(PARAMETERS),
233 PROFILING => setup_memory_table!(PROFILING),
234 REFERENTIAL_CONSTRAINTS => setup_memory_table!(REFERENTIAL_CONSTRAINTS),
235 ROUTINES => setup_memory_table!(ROUTINES),
236 SCHEMA_PRIVILEGES => setup_memory_table!(SCHEMA_PRIVILEGES),
237 TABLE_PRIVILEGES => setup_memory_table!(TABLE_PRIVILEGES),
238 GLOBAL_STATUS => setup_memory_table!(GLOBAL_STATUS),
239 SESSION_STATUS => setup_memory_table!(SESSION_STATUS),
240 KEY_COLUMN_USAGE => Some(Arc::new(InformationSchemaKeyColumnUsage::new(
241 self.catalog_name.clone(),
242 self.catalog_manager.clone(),
243 )) as _),
244 SCHEMATA => Some(Arc::new(InformationSchemaSchemata::new(
245 self.catalog_name.clone(),
246 self.catalog_manager.clone(),
247 )) as _),
248 PARTITIONS => Some(Arc::new(InformationSchemaPartitions::new(
249 self.catalog_name.clone(),
250 self.catalog_manager.clone(),
251 )) as _),
252 REGION_PEERS => Some(Arc::new(InformationSchemaRegionPeers::new(
253 self.catalog_name.clone(),
254 self.catalog_manager.clone(),
255 )) as _),
256 TABLE_CONSTRAINTS => Some(Arc::new(InformationSchemaTableConstraints::new(
257 self.catalog_name.clone(),
258 self.catalog_manager.clone(),
259 )) as _),
260 STATISTICS => Some(Arc::new(InformationSchemaStatistics::new(
261 self.catalog_name.clone(),
262 self.catalog_manager.clone(),
263 )) as _),
264 CLUSTER_INFO => Some(Arc::new(InformationSchemaClusterInfo::new(
265 self.catalog_manager.clone(),
266 )) as _),
267 VIEWS => Some(Arc::new(InformationSchemaViews::new(
268 self.catalog_name.clone(),
269 self.catalog_manager.clone(),
270 )) as _),
271 FLOWS => Some(Arc::new(InformationSchemaFlows::new(
272 self.catalog_name.clone(),
273 self.catalog_manager.clone(),
274 self.flow_metadata_manager.clone(),
275 )) as _),
276 FLOW_STATISTICS => Some(Arc::new(InformationSchemaFlowStatistics::new(
277 self.catalog_name.clone(),
278 self.catalog_manager.clone(),
279 self.flow_metadata_manager.clone(),
280 )) as _),
281 PROCEDURE_INFO => Some(
282 Arc::new(procedure_info::InformationSchemaProcedureInfo::new(
283 self.catalog_manager.clone(),
284 )) as _,
285 ),
286 #[cfg(feature = "enterprise")]
287 RECYCLE_BIN => Some(Arc::new(InformationSchemaRecycleBin::new(
288 self.catalog_name.clone(),
289 self.catalog_manager.clone(),
290 )) as _),
291 REGION_STATISTICS => Some(Arc::new(
292 region_statistics::InformationSchemaRegionStatistics::new(
293 self.catalog_manager.clone(),
294 ),
295 ) as _),
296 REGION_INFO => Some(Arc::new(InformationSchemaRegionInfo::new(
297 self.catalog_manager.clone(),
298 )) as _),
299 PROCESS_LIST => self
300 .process_manager
301 .as_ref()
302 .map(|p| Arc::new(InformationSchemaProcessList::new(p.clone())) as _),
303 SSTS_MANIFEST => Some(Arc::new(InformationSchemaSstsManifest::new(
304 self.catalog_manager.clone(),
305 )) as _),
306 SSTS_STORAGE => Some(Arc::new(InformationSchemaSstsStorage::new(
307 self.catalog_manager.clone(),
308 )) as _),
309 SSTS_INDEX_META => Some(Arc::new(InformationSchemaSstsIndexMeta::new(
310 self.catalog_manager.clone(),
311 )) as _),
312 TABLE_SEMANTICS => Some(Arc::new(InformationSchemaTableSemantics::new(
313 self.catalog_name.clone(),
314 self.catalog_manager.clone(),
315 )) as _),
316 _ => None,
317 }
318 }
319}
320
321impl InformationSchemaProvider {
322 pub fn new(
323 catalog_name: String,
324 catalog_manager: Weak<dyn CatalogManager>,
325 flow_metadata_manager: Arc<FlowMetadataManager>,
326 process_manager: Option<ProcessManagerRef>,
327 kv_backend: KvBackendRef,
328 ) -> Self {
329 let mut provider = Self {
330 catalog_name,
331 catalog_manager,
332 flow_metadata_manager,
333 process_manager,
334 tables: HashMap::new(),
335 kv_backend,
336 extra_table_factories: HashMap::new(),
337 };
338
339 provider.build_tables();
340
341 provider
342 }
343
344 pub(crate) fn with_extra_table_factories(
345 mut self,
346 factories: HashMap<String, InformationSchemaTableFactoryRef>,
347 ) -> Self {
348 self.extra_table_factories = factories;
349 self.build_tables();
350 self
351 }
352
353 fn build_tables(&mut self) {
354 let mut tables = HashMap::new();
355
356 if self.catalog_name == DEFAULT_CATALOG_NAME {
361 tables.insert(
362 BUILD_INFO.to_string(),
363 self.build_table(BUILD_INFO).unwrap(),
364 );
365 tables.insert(
366 REGION_PEERS.to_string(),
367 self.build_table(REGION_PEERS).unwrap(),
368 );
369 tables.insert(
370 CLUSTER_INFO.to_string(),
371 self.build_table(CLUSTER_INFO).unwrap(),
372 );
373 tables.insert(
374 PROCEDURE_INFO.to_string(),
375 self.build_table(PROCEDURE_INFO).unwrap(),
376 );
377 tables.insert(
378 REGION_STATISTICS.to_string(),
379 self.build_table(REGION_STATISTICS).unwrap(),
380 );
381 tables.insert(
382 REGION_INFO.to_string(),
383 self.build_table(REGION_INFO).unwrap(),
384 );
385 tables.insert(
386 SSTS_MANIFEST.to_string(),
387 self.build_table(SSTS_MANIFEST).unwrap(),
388 );
389 tables.insert(
390 SSTS_STORAGE.to_string(),
391 self.build_table(SSTS_STORAGE).unwrap(),
392 );
393 tables.insert(
394 SSTS_INDEX_META.to_string(),
395 self.build_table(SSTS_INDEX_META).unwrap(),
396 );
397 }
398
399 tables.insert(TABLES.to_string(), self.build_table(TABLES).unwrap());
400 tables.insert(VIEWS.to_string(), self.build_table(VIEWS).unwrap());
401 tables.insert(SCHEMATA.to_string(), self.build_table(SCHEMATA).unwrap());
402 tables.insert(COLUMNS.to_string(), self.build_table(COLUMNS).unwrap());
403 tables.insert(
404 KEY_COLUMN_USAGE.to_string(),
405 self.build_table(KEY_COLUMN_USAGE).unwrap(),
406 );
407 tables.insert(
408 TABLE_CONSTRAINTS.to_string(),
409 self.build_table(TABLE_CONSTRAINTS).unwrap(),
410 );
411 tables.insert(
412 STATISTICS.to_string(),
413 self.build_table(STATISTICS).unwrap(),
414 );
415 tables.insert(FLOWS.to_string(), self.build_table(FLOWS).unwrap());
416 tables.insert(
417 FLOW_STATISTICS.to_string(),
418 self.build_table(FLOW_STATISTICS).unwrap(),
419 );
420 #[cfg(feature = "enterprise")]
421 tables.insert(
422 RECYCLE_BIN.to_string(),
423 self.build_table(RECYCLE_BIN).unwrap(),
424 );
425 tables.insert(
426 TABLE_SEMANTICS.to_string(),
427 self.build_table(TABLE_SEMANTICS).unwrap(),
428 );
429 if let Some(process_list) = self.build_table(PROCESS_LIST) {
430 tables.insert(PROCESS_LIST.to_string(), process_list);
431 }
432 for name in self.extra_table_factories.keys() {
433 tables.insert(name.clone(), self.build_table(name).expect(name));
434 }
435 for name in MEMORY_TABLES.iter() {
437 tables.insert((*name).to_string(), self.build_table(name).expect(name));
438 }
439 self.tables = tables;
440 }
441}
442
443pub trait InformationTable {
444 fn table_id(&self) -> TableId;
445
446 fn table_name(&self) -> &'static str;
447
448 fn schema(&self) -> SchemaRef;
449
450 fn to_stream(&self, request: ScanRequest) -> Result<SendableRecordBatchStream>;
451
452 fn scan_plan(&self, _request: ScanRequest) -> Result<Option<Arc<dyn ExecutionPlan>>> {
453 Ok(None)
454 }
455
456 fn table_type(&self) -> TableType {
457 TableType::Temporary
458 }
459}
460
461impl<T> SystemTable for T
463where
464 T: InformationTable,
465{
466 fn table_id(&self) -> TableId {
467 InformationTable::table_id(self)
468 }
469
470 fn table_name(&self) -> &'static str {
471 InformationTable::table_name(self)
472 }
473
474 fn schema(&self) -> SchemaRef {
475 InformationTable::schema(self)
476 }
477
478 fn table_type(&self) -> TableType {
479 InformationTable::table_type(self)
480 }
481
482 fn to_stream(&self, request: ScanRequest) -> Result<SendableRecordBatchStream> {
483 InformationTable::to_stream(self, request)
484 }
485
486 fn scan_plan(&self, request: ScanRequest) -> Result<Option<Arc<dyn ExecutionPlan>>> {
487 InformationTable::scan_plan(self, request)
488 }
489}
490
491pub type InformationExtensionRef = Arc<dyn InformationExtension<Error = Error> + Send + Sync>;
492
493#[async_trait::async_trait]
495pub trait InformationExtension {
496 type Error: ErrorExt;
497
498 async fn nodes(&self) -> std::result::Result<Vec<NodeInfo>, Self::Error>;
500
501 async fn procedures(&self) -> std::result::Result<Vec<(String, ProcedureInfo)>, Self::Error>;
503
504 async fn region_stats(&self) -> std::result::Result<Vec<RegionStat>, Self::Error>;
506
507 async fn flow_stats(&self) -> std::result::Result<Option<FlowStat>, Self::Error>;
509
510 async fn inspect_datanode(
512 &self,
513 request: DatanodeInspectRequest,
514 ) -> std::result::Result<SendableRecordBatchStream, Self::Error>;
515
516 fn inspect_datanode_plan(
519 &self,
520 _request: DatanodeInspectRequest,
521 _schema: SchemaRef,
522 ) -> std::result::Result<Option<Arc<dyn ExecutionPlan>>, Self::Error> {
523 Ok(None)
524 }
525}
526
527#[derive(Debug, Clone, PartialEq)]
529pub struct DatanodeInspectRequest {
530 pub kind: DatanodeInspectKind,
532
533 pub scan: ScanRequest,
536}
537
538#[derive(Debug, Clone, Copy, PartialEq, Eq)]
540pub enum DatanodeInspectKind {
541 SstManifest,
543 SstStorage,
545 SstIndexMeta,
547 RegionInfo,
549}
550
551impl DatanodeInspectRequest {
552 pub fn build_plan(self) -> std::result::Result<LogicalPlan, DataFusionError> {
554 match self.kind {
555 DatanodeInspectKind::SstManifest => ManifestSstEntry::build_plan(self.scan),
556 DatanodeInspectKind::SstStorage => StorageSstEntry::build_plan(self.scan),
557 DatanodeInspectKind::SstIndexMeta => PuffinIndexMetaEntry::build_plan(self.scan),
558 DatanodeInspectKind::RegionInfo => RegionInfoEntry::build_plan(self.scan),
559 }
560 }
561}
562pub struct NoopInformationExtension;
563
564#[async_trait::async_trait]
565impl InformationExtension for NoopInformationExtension {
566 type Error = Error;
567
568 async fn nodes(&self) -> std::result::Result<Vec<NodeInfo>, Self::Error> {
569 Ok(vec![])
570 }
571
572 async fn procedures(&self) -> std::result::Result<Vec<(String, ProcedureInfo)>, Self::Error> {
573 Ok(vec![])
574 }
575
576 async fn region_stats(&self) -> std::result::Result<Vec<RegionStat>, Self::Error> {
577 Ok(vec![])
578 }
579
580 async fn flow_stats(&self) -> std::result::Result<Option<FlowStat>, Self::Error> {
581 Ok(None)
582 }
583
584 async fn inspect_datanode(
585 &self,
586 _request: DatanodeInspectRequest,
587 ) -> std::result::Result<SendableRecordBatchStream, Self::Error> {
588 Ok(common_recordbatch::RecordBatches::empty().as_stream())
589 }
590}
591
592#[cfg(test)]
593mod tests {
594 use store_api::region_info::RegionInfoEntry;
595
596 use super::*;
597
598 #[test]
599 fn test_datanode_inspect_region_info_build_plan() {
600 let plan = DatanodeInspectRequest {
601 kind: DatanodeInspectKind::RegionInfo,
602 scan: ScanRequest::default(),
603 }
604 .build_plan()
605 .unwrap();
606
607 let LogicalPlan::TableScan(scan) = plan else {
608 panic!("expected table scan");
609 };
610 assert_eq!(
611 scan.table_name.to_string(),
612 RegionInfoEntry::reserved_table_name_for_inspection()
613 );
614 }
615}