1use crate::streaming::StreamingTable;
23use crate::table::TableFunction;
24use crate::{CatalogProviderList, SchemaProvider, TableProvider};
25use arrow::array::builder::{BooleanBuilder, UInt8Builder};
26use arrow::{
27 array::{StringBuilder, UInt64Builder},
28 datatypes::{DataType, Field, FieldRef, Schema, SchemaRef},
29 record_batch::RecordBatch,
30};
31use async_trait::async_trait;
32use datafusion_common::DataFusionError;
33use datafusion_common::config::{ConfigEntry, ConfigOptions};
34use datafusion_common::error::Result;
35use datafusion_common::types::NativeType;
36use datafusion_execution::TaskContext;
37use datafusion_execution::runtime_env::RuntimeEnv;
38use datafusion_expr::function::WindowUDFFieldArgs;
39use datafusion_expr::{
40 AggregateUDF, ReturnFieldArgs, ScalarUDF, Signature, TypeSignature, WindowUDF,
41};
42use datafusion_expr::{TableType, Volatility};
43use datafusion_physical_plan::SendableRecordBatchStream;
44use datafusion_physical_plan::stream::RecordBatchStreamAdapter;
45use datafusion_physical_plan::streaming::PartitionStream;
46use std::collections::{BTreeSet, HashMap, HashSet};
47use std::fmt::Debug;
48use std::sync::Arc;
49
50pub const INFORMATION_SCHEMA: &str = "information_schema";
51pub(crate) const TABLES: &str = "tables";
52pub(crate) const VIEWS: &str = "views";
53pub(crate) const COLUMNS: &str = "columns";
54pub(crate) const DF_SETTINGS: &str = "df_settings";
55pub(crate) const SCHEMATA: &str = "schemata";
56pub(crate) const ROUTINES: &str = "routines";
57pub(crate) const PARAMETERS: &str = "parameters";
58
59pub const INFORMATION_SCHEMA_TABLES: &[&str] = &[
61 TABLES,
62 VIEWS,
63 COLUMNS,
64 DF_SETTINGS,
65 SCHEMATA,
66 ROUTINES,
67 PARAMETERS,
68];
69
70#[derive(Debug)]
77pub struct InformationSchemaProvider {
78 config: InformationSchemaConfig,
79}
80
81impl InformationSchemaProvider {
82 pub fn new(catalog_list: Arc<dyn CatalogProviderList>) -> Self {
84 Self {
85 config: InformationSchemaConfig {
86 catalog_list,
87 table_functions: HashMap::new(),
88 },
89 }
90 }
91
92 pub fn with_table_functions(
95 mut self,
96 table_functions: HashMap<String, Arc<TableFunction>>,
97 ) -> Self {
98 self.config.table_functions = table_functions;
99 self
100 }
101}
102
103#[derive(Clone, Debug)]
104struct InformationSchemaConfig {
105 catalog_list: Arc<dyn CatalogProviderList>,
106 table_functions: HashMap<String, Arc<TableFunction>>,
107}
108
109impl InformationSchemaConfig {
110 async fn make_tables(
112 &self,
113 builder: &mut InformationSchemaTablesBuilder,
114 ) -> Result<(), DataFusionError> {
115 for catalog_name in self.catalog_list.catalog_names() {
118 let catalog = self.catalog_list.catalog(&catalog_name).unwrap();
119
120 for schema_name in catalog.schema_names() {
121 if schema_name != INFORMATION_SCHEMA {
122 if let Some(schema) = catalog.schema(&schema_name) {
124 for table_name in schema.table_names() {
125 if let Some(table_type) =
126 schema.table_type(&table_name).await?
127 {
128 builder.add_table(
129 &catalog_name,
130 &schema_name,
131 &table_name,
132 table_type,
133 );
134 }
135 }
136 }
137 }
138 }
139
140 for table_name in INFORMATION_SCHEMA_TABLES {
142 builder.add_table(
143 &catalog_name,
144 INFORMATION_SCHEMA,
145 table_name,
146 TableType::View,
147 );
148 }
149 }
150
151 Ok(())
152 }
153
154 fn make_schemata(&self, builder: &mut InformationSchemataBuilder) {
155 for catalog_name in self.catalog_list.catalog_names() {
156 let catalog = self.catalog_list.catalog(&catalog_name).unwrap();
157
158 for schema_name in catalog.schema_names() {
159 if schema_name != INFORMATION_SCHEMA
160 && let Some(schema) = catalog.schema(&schema_name)
161 {
162 let schema_owner = schema.owner_name();
163 builder.add_schemata(&catalog_name, &schema_name, schema_owner);
164 }
165 }
166 }
167 }
168
169 async fn make_views(
170 &self,
171 builder: &mut InformationSchemaViewBuilder,
172 ) -> Result<(), DataFusionError> {
173 for catalog_name in self.catalog_list.catalog_names() {
174 let catalog = self.catalog_list.catalog(&catalog_name).unwrap();
175
176 for schema_name in catalog.schema_names() {
177 if schema_name != INFORMATION_SCHEMA {
178 if let Some(schema) = catalog.schema(&schema_name) {
180 for table_name in schema.table_names() {
181 if let Some(table) = schema.table(&table_name).await? {
182 builder.add_view(
183 &catalog_name,
184 &schema_name,
185 &table_name,
186 table.get_table_definition(),
187 )
188 }
189 }
190 }
191 }
192 }
193 }
194
195 Ok(())
196 }
197
198 async fn make_columns(
200 &self,
201 builder: &mut InformationSchemaColumnsBuilder,
202 ) -> Result<(), DataFusionError> {
203 for catalog_name in self.catalog_list.catalog_names() {
204 let catalog = self.catalog_list.catalog(&catalog_name).unwrap();
205
206 for schema_name in catalog.schema_names() {
207 if schema_name != INFORMATION_SCHEMA {
208 if let Some(schema) = catalog.schema(&schema_name) {
210 for table_name in schema.table_names() {
211 if let Some(table) = schema.table(&table_name).await? {
212 for (field_position, field) in
213 table.schema().fields().iter().enumerate()
214 {
215 builder.add_column(
216 &catalog_name,
217 &schema_name,
218 &table_name,
219 field_position,
220 field,
221 )
222 }
223 }
224 }
225 }
226 }
227 }
228 }
229
230 Ok(())
231 }
232
233 fn make_df_settings(
235 &self,
236 config_options: &ConfigOptions,
237 runtime_env: &Arc<RuntimeEnv>,
238 builder: &mut InformationSchemaDfSettingsBuilder,
239 ) {
240 for entry in config_options.entries() {
241 builder.add_setting(entry);
242 }
243 for entry in runtime_env.config_entries() {
245 builder.add_setting(entry);
246 }
247 }
248
249 fn make_routines(
250 &self,
251 udfs: &HashMap<String, Arc<ScalarUDF>>,
252 udafs: &HashMap<String, Arc<AggregateUDF>>,
253 udwfs: &HashMap<String, Arc<WindowUDF>>,
254 config_options: &ConfigOptions,
255 builder: &mut InformationSchemaRoutinesBuilder,
256 ) -> Result<()> {
257 let catalog_name = &config_options.catalog.default_catalog;
258 let schema_name = &config_options.catalog.default_schema;
259
260 for (name, udf) in udfs {
261 let return_types = get_udf_args_and_return_types(udf)?
262 .into_iter()
263 .map(|(_, return_type)| return_type)
264 .collect::<HashSet<_>>();
265 for return_type in return_types {
266 builder.add_routine(
267 catalog_name,
268 schema_name,
269 name,
270 "FUNCTION",
271 Self::is_deterministic(udf.signature()),
272 return_type.as_ref(),
273 "SCALAR",
274 udf.documentation().map(|d| d.description.to_string()),
275 udf.documentation().map(|d| d.syntax_example.to_string()),
276 )
277 }
278 }
279
280 for (name, udaf) in udafs {
281 let return_types = get_udaf_args_and_return_types(udaf)?
282 .into_iter()
283 .map(|(_, return_type)| return_type)
284 .collect::<HashSet<_>>();
285 for return_type in return_types {
286 builder.add_routine(
287 catalog_name,
288 schema_name,
289 name,
290 "FUNCTION",
291 Self::is_deterministic(udaf.signature()),
292 return_type.as_ref(),
293 "AGGREGATE",
294 udaf.documentation().map(|d| d.description.to_string()),
295 udaf.documentation().map(|d| d.syntax_example.to_string()),
296 )
297 }
298 }
299
300 for (name, udwf) in udwfs {
301 let return_types = get_udwf_args_and_return_types(udwf)?
302 .into_iter()
303 .map(|(_, return_type)| return_type)
304 .collect::<HashSet<_>>();
305 for return_type in return_types {
306 builder.add_routine(
307 catalog_name,
308 schema_name,
309 name,
310 "FUNCTION",
311 Self::is_deterministic(udwf.signature()),
312 return_type.as_ref(),
313 "WINDOW",
314 udwf.documentation().map(|d| d.description.to_string()),
315 udwf.documentation().map(|d| d.syntax_example.to_string()),
316 )
317 }
318 }
319
320 for name in self.table_functions.keys() {
325 builder.add_routine(
326 catalog_name,
327 schema_name,
328 name,
329 "FUNCTION",
330 false,
333 Some(&"TABLE"),
334 "TABLE",
335 None::<String>,
336 None::<String>,
337 )
338 }
339 Ok(())
340 }
341
342 fn is_deterministic(signature: &Signature) -> bool {
343 signature.volatility == Volatility::Immutable
344 }
345 fn make_parameters(
346 &self,
347 udfs: &HashMap<String, Arc<ScalarUDF>>,
348 udafs: &HashMap<String, Arc<AggregateUDF>>,
349 udwfs: &HashMap<String, Arc<WindowUDF>>,
350 config_options: &ConfigOptions,
351 builder: &mut InformationSchemaParametersBuilder,
352 ) -> Result<()> {
353 let catalog_name = &config_options.catalog.default_catalog;
354 let schema_name = &config_options.catalog.default_schema;
355 let mut add_parameters = |func_name: &str,
356 args: Option<&Vec<(String, String)>>,
357 arg_types: Vec<String>,
358 return_type: Option<String>,
359 is_variadic: bool,
360 rid: u8| {
361 for (position, type_name) in arg_types.iter().enumerate() {
362 let param_name =
363 args.and_then(|a| a.get(position).map(|arg| arg.0.as_str()));
364 builder.add_parameter(
365 catalog_name,
366 schema_name,
367 func_name,
368 position as u64 + 1,
369 "IN",
370 param_name,
371 type_name,
372 None::<&str>,
373 is_variadic,
374 rid,
375 );
376 }
377 if let Some(return_type) = return_type {
378 builder.add_parameter(
379 catalog_name,
380 schema_name,
381 func_name,
382 1,
383 "OUT",
384 None::<&str>,
385 return_type.as_str(),
386 None::<&str>,
387 false,
388 rid,
389 );
390 }
391 };
392
393 for (func_name, udf) in udfs {
394 let args = udf.documentation().and_then(|d| d.arguments.clone());
395 let combinations = get_udf_args_and_return_types(udf)?;
396 for (rid, (arg_types, return_type)) in combinations.into_iter().enumerate() {
397 add_parameters(
398 func_name,
399 args.as_ref(),
400 arg_types,
401 return_type,
402 Self::is_variadic(udf.signature()),
403 rid as u8,
404 );
405 }
406 }
407
408 for (func_name, udaf) in udafs {
409 let args = udaf.documentation().and_then(|d| d.arguments.clone());
410 let combinations = get_udaf_args_and_return_types(udaf)?;
411 for (rid, (arg_types, return_type)) in combinations.into_iter().enumerate() {
412 add_parameters(
413 func_name,
414 args.as_ref(),
415 arg_types,
416 return_type,
417 Self::is_variadic(udaf.signature()),
418 rid as u8,
419 );
420 }
421 }
422
423 for (func_name, udwf) in udwfs {
424 let args = udwf.documentation().and_then(|d| d.arguments.clone());
425 let combinations = get_udwf_args_and_return_types(udwf)?;
426 for (rid, (arg_types, return_type)) in combinations.into_iter().enumerate() {
427 add_parameters(
428 func_name,
429 args.as_ref(),
430 arg_types,
431 return_type,
432 Self::is_variadic(udwf.signature()),
433 rid as u8,
434 );
435 }
436 }
437
438 Ok(())
447 }
448
449 fn is_variadic(signature: &Signature) -> bool {
450 matches!(
451 signature.type_signature,
452 TypeSignature::Variadic(_) | TypeSignature::VariadicAny
453 )
454 }
455}
456
457fn get_udf_args_and_return_types(
460 udf: &Arc<ScalarUDF>,
461) -> Result<BTreeSet<(Vec<String>, Option<String>)>> {
462 let signature = udf.signature();
463 let arg_types = signature.type_signature.get_example_types();
464 if arg_types.is_empty() {
465 Ok(vec![(vec![], None)].into_iter().collect::<BTreeSet<_>>())
466 } else {
467 Ok(arg_types
468 .into_iter()
469 .map(|arg_types| {
470 let arg_fields: Vec<FieldRef> = arg_types
471 .iter()
472 .enumerate()
473 .map(|(i, t)| {
474 Arc::new(Field::new(format!("arg_{i}"), t.clone(), true))
475 })
476 .collect();
477 let scalar_arguments = vec![None; arg_fields.len()];
478 let return_type = udf
479 .return_field_from_args(ReturnFieldArgs {
480 arg_fields: &arg_fields,
481 scalar_arguments: &scalar_arguments,
482 })
483 .map(|f| {
484 remove_native_type_prefix(&NativeType::from(
485 f.data_type().clone(),
486 ))
487 })
488 .ok();
489 let arg_types = arg_types
490 .into_iter()
491 .map(|t| remove_native_type_prefix(&NativeType::from(t)))
492 .collect::<Vec<_>>();
493 (arg_types, return_type)
494 })
495 .collect::<BTreeSet<_>>())
496 }
497}
498
499fn get_udaf_args_and_return_types(
500 udaf: &Arc<AggregateUDF>,
501) -> Result<BTreeSet<(Vec<String>, Option<String>)>> {
502 let signature = udaf.signature();
503 let arg_types = signature.type_signature.get_example_types();
504 if arg_types.is_empty() {
505 Ok(vec![(vec![], None)].into_iter().collect::<BTreeSet<_>>())
506 } else {
507 Ok(arg_types
508 .into_iter()
509 .map(|arg_types| {
510 let arg_fields: Vec<FieldRef> = arg_types
511 .iter()
512 .enumerate()
513 .map(|(i, t)| {
514 Arc::new(Field::new(format!("arg_{i}"), t.clone(), true))
515 })
516 .collect();
517 let return_type = udaf
518 .return_field(&arg_fields)
519 .map(|f| {
520 remove_native_type_prefix(&NativeType::from(
521 f.data_type().clone(),
522 ))
523 })
524 .ok();
525 let arg_types = arg_types
526 .into_iter()
527 .map(|t| remove_native_type_prefix(&NativeType::from(t)))
528 .collect::<Vec<_>>();
529 (arg_types, return_type)
530 })
531 .collect::<BTreeSet<_>>())
532 }
533}
534
535fn get_udwf_args_and_return_types(
536 udwf: &Arc<WindowUDF>,
537) -> Result<BTreeSet<(Vec<String>, Option<String>)>> {
538 let signature = udwf.signature();
539 let arg_types = signature.type_signature.get_example_types();
540 if arg_types.is_empty() {
541 Ok(vec![(vec![], None)].into_iter().collect::<BTreeSet<_>>())
542 } else {
543 Ok(arg_types
544 .into_iter()
545 .map(|arg_types| {
546 let arg_fields: Vec<FieldRef> = arg_types
547 .iter()
548 .enumerate()
549 .map(|(i, t)| {
550 Arc::new(Field::new(format!("arg_{i}"), t.clone(), true))
551 })
552 .collect();
553 let return_type = udwf
554 .field(WindowUDFFieldArgs::new(&arg_fields, udwf.name()))
555 .map(|f| {
556 remove_native_type_prefix(&NativeType::from(
557 f.data_type().clone(),
558 ))
559 })
560 .ok();
561 let arg_types = arg_types
562 .into_iter()
563 .map(|t| remove_native_type_prefix(&NativeType::from(t)))
564 .collect::<Vec<_>>();
565 (arg_types, return_type)
566 })
567 .collect::<BTreeSet<_>>())
568 }
569}
570
571#[inline]
572fn remove_native_type_prefix(native_type: &NativeType) -> String {
573 format!("{native_type}")
574}
575
576#[async_trait]
577impl SchemaProvider for InformationSchemaProvider {
578 fn table_names(&self) -> Vec<String> {
579 INFORMATION_SCHEMA_TABLES
580 .iter()
581 .map(|t| (*t).to_string())
582 .collect()
583 }
584
585 async fn table(
586 &self,
587 name: &str,
588 ) -> Result<Option<Arc<dyn TableProvider>>, DataFusionError> {
589 let config = self.config.clone();
590 let table: Arc<dyn PartitionStream> = match name.to_ascii_lowercase().as_str() {
591 TABLES => Arc::new(InformationSchemaTables::new(config)),
592 COLUMNS => Arc::new(InformationSchemaColumns::new(config)),
593 VIEWS => Arc::new(InformationSchemaViews::new(config)),
594 DF_SETTINGS => Arc::new(InformationSchemaDfSettings::new(config)),
595 SCHEMATA => Arc::new(InformationSchemata::new(config)),
596 ROUTINES => Arc::new(InformationSchemaRoutines::new(config)),
597 PARAMETERS => Arc::new(InformationSchemaParameters::new(config)),
598 _ => return Ok(None),
599 };
600
601 Ok(Some(Arc::new(
602 StreamingTable::try_new(Arc::clone(table.schema()), vec![table]).unwrap(),
603 )))
604 }
605
606 fn table_exist(&self, name: &str) -> bool {
607 INFORMATION_SCHEMA_TABLES.contains(&name.to_ascii_lowercase().as_str())
608 }
609}
610
611#[derive(Debug)]
612struct InformationSchemaTables {
613 schema: SchemaRef,
614 config: InformationSchemaConfig,
615}
616
617impl InformationSchemaTables {
618 fn new(config: InformationSchemaConfig) -> Self {
619 let schema = Arc::new(Schema::new(vec![
620 Field::new("table_catalog", DataType::Utf8, false),
621 Field::new("table_schema", DataType::Utf8, false),
622 Field::new("table_name", DataType::Utf8, false),
623 Field::new("table_type", DataType::Utf8, false),
624 ]));
625
626 Self { schema, config }
627 }
628
629 fn builder(&self) -> InformationSchemaTablesBuilder {
630 InformationSchemaTablesBuilder {
631 catalog_names: StringBuilder::new(),
632 schema_names: StringBuilder::new(),
633 table_names: StringBuilder::new(),
634 table_types: StringBuilder::new(),
635 schema: Arc::clone(&self.schema),
636 }
637 }
638}
639
640impl PartitionStream for InformationSchemaTables {
641 fn schema(&self) -> &SchemaRef {
642 &self.schema
643 }
644
645 fn execute(&self, _ctx: Arc<TaskContext>) -> SendableRecordBatchStream {
646 let mut builder = self.builder();
647 let config = self.config.clone();
648 Box::pin(RecordBatchStreamAdapter::new(
649 Arc::clone(&self.schema),
650 futures::stream::once(async move {
652 config.make_tables(&mut builder).await?;
653 Ok(builder.finish())
654 }),
655 ))
656 }
657}
658
659struct InformationSchemaTablesBuilder {
663 schema: SchemaRef,
664 catalog_names: StringBuilder,
665 schema_names: StringBuilder,
666 table_names: StringBuilder,
667 table_types: StringBuilder,
668}
669
670impl InformationSchemaTablesBuilder {
671 fn add_table(
672 &mut self,
673 catalog_name: impl AsRef<str>,
674 schema_name: impl AsRef<str>,
675 table_name: impl AsRef<str>,
676 table_type: TableType,
677 ) {
678 self.catalog_names.append_value(catalog_name.as_ref());
680 self.schema_names.append_value(schema_name.as_ref());
681 self.table_names.append_value(table_name.as_ref());
682 self.table_types.append_value(match table_type {
683 TableType::Base => "BASE TABLE",
684 TableType::View => "VIEW",
685 TableType::Temporary => "LOCAL TEMPORARY",
686 });
687 }
688
689 fn finish(&mut self) -> RecordBatch {
690 RecordBatch::try_new(
691 Arc::clone(&self.schema),
692 vec![
693 Arc::new(self.catalog_names.finish()),
694 Arc::new(self.schema_names.finish()),
695 Arc::new(self.table_names.finish()),
696 Arc::new(self.table_types.finish()),
697 ],
698 )
699 .unwrap()
700 }
701}
702
703#[derive(Debug)]
704struct InformationSchemaViews {
705 schema: SchemaRef,
706 config: InformationSchemaConfig,
707}
708
709impl InformationSchemaViews {
710 fn new(config: InformationSchemaConfig) -> Self {
711 let schema = Arc::new(Schema::new(vec![
712 Field::new("table_catalog", DataType::Utf8, false),
713 Field::new("table_schema", DataType::Utf8, false),
714 Field::new("table_name", DataType::Utf8, false),
715 Field::new("definition", DataType::Utf8, true),
716 ]));
717
718 Self { schema, config }
719 }
720
721 fn builder(&self) -> InformationSchemaViewBuilder {
722 InformationSchemaViewBuilder {
723 catalog_names: StringBuilder::new(),
724 schema_names: StringBuilder::new(),
725 table_names: StringBuilder::new(),
726 definitions: StringBuilder::new(),
727 schema: Arc::clone(&self.schema),
728 }
729 }
730}
731
732impl PartitionStream for InformationSchemaViews {
733 fn schema(&self) -> &SchemaRef {
734 &self.schema
735 }
736
737 fn execute(&self, _ctx: Arc<TaskContext>) -> SendableRecordBatchStream {
738 let mut builder = self.builder();
739 let config = self.config.clone();
740 Box::pin(RecordBatchStreamAdapter::new(
741 Arc::clone(&self.schema),
742 futures::stream::once(async move {
744 config.make_views(&mut builder).await?;
745 Ok(builder.finish())
746 }),
747 ))
748 }
749}
750
751struct InformationSchemaViewBuilder {
755 schema: SchemaRef,
756 catalog_names: StringBuilder,
757 schema_names: StringBuilder,
758 table_names: StringBuilder,
759 definitions: StringBuilder,
760}
761
762impl InformationSchemaViewBuilder {
763 fn add_view(
764 &mut self,
765 catalog_name: impl AsRef<str>,
766 schema_name: impl AsRef<str>,
767 table_name: impl AsRef<str>,
768 definition: Option<&(impl AsRef<str> + ?Sized)>,
769 ) {
770 self.catalog_names.append_value(catalog_name.as_ref());
772 self.schema_names.append_value(schema_name.as_ref());
773 self.table_names.append_value(table_name.as_ref());
774 self.definitions.append_option(definition.as_ref());
775 }
776
777 fn finish(&mut self) -> RecordBatch {
778 RecordBatch::try_new(
779 Arc::clone(&self.schema),
780 vec![
781 Arc::new(self.catalog_names.finish()),
782 Arc::new(self.schema_names.finish()),
783 Arc::new(self.table_names.finish()),
784 Arc::new(self.definitions.finish()),
785 ],
786 )
787 .unwrap()
788 }
789}
790
791#[derive(Debug)]
792struct InformationSchemaColumns {
793 schema: SchemaRef,
794 config: InformationSchemaConfig,
795}
796
797impl InformationSchemaColumns {
798 fn new(config: InformationSchemaConfig) -> Self {
799 let schema = Arc::new(Schema::new(vec![
800 Field::new("table_catalog", DataType::Utf8, false),
801 Field::new("table_schema", DataType::Utf8, false),
802 Field::new("table_name", DataType::Utf8, false),
803 Field::new("column_name", DataType::Utf8, false),
804 Field::new("ordinal_position", DataType::UInt64, false),
805 Field::new("column_default", DataType::Utf8, true),
806 Field::new("is_nullable", DataType::Utf8, false),
807 Field::new("data_type", DataType::Utf8, false),
808 Field::new("character_maximum_length", DataType::UInt64, true),
809 Field::new("character_octet_length", DataType::UInt64, true),
810 Field::new("numeric_precision", DataType::UInt64, true),
811 Field::new("numeric_precision_radix", DataType::UInt64, true),
812 Field::new("numeric_scale", DataType::UInt64, true),
813 Field::new("datetime_precision", DataType::UInt64, true),
814 Field::new("interval_type", DataType::Utf8, true),
815 ]));
816
817 Self { schema, config }
818 }
819
820 fn builder(&self) -> InformationSchemaColumnsBuilder {
821 let default_capacity = 10;
825
826 InformationSchemaColumnsBuilder {
827 catalog_names: StringBuilder::new(),
828 schema_names: StringBuilder::new(),
829 table_names: StringBuilder::new(),
830 column_names: StringBuilder::new(),
831 ordinal_positions: UInt64Builder::with_capacity(default_capacity),
832 column_defaults: StringBuilder::new(),
833 is_nullables: StringBuilder::new(),
834 data_types: StringBuilder::new(),
835 character_maximum_lengths: UInt64Builder::with_capacity(default_capacity),
836 character_octet_lengths: UInt64Builder::with_capacity(default_capacity),
837 numeric_precisions: UInt64Builder::with_capacity(default_capacity),
838 numeric_precision_radixes: UInt64Builder::with_capacity(default_capacity),
839 numeric_scales: UInt64Builder::with_capacity(default_capacity),
840 datetime_precisions: UInt64Builder::with_capacity(default_capacity),
841 interval_types: StringBuilder::new(),
842 schema: Arc::clone(&self.schema),
843 }
844 }
845}
846
847impl PartitionStream for InformationSchemaColumns {
848 fn schema(&self) -> &SchemaRef {
849 &self.schema
850 }
851
852 fn execute(&self, _ctx: Arc<TaskContext>) -> SendableRecordBatchStream {
853 let mut builder = self.builder();
854 let config = self.config.clone();
855 Box::pin(RecordBatchStreamAdapter::new(
856 Arc::clone(&self.schema),
857 futures::stream::once(async move {
859 config.make_columns(&mut builder).await?;
860 Ok(builder.finish())
861 }),
862 ))
863 }
864}
865
866struct InformationSchemaColumnsBuilder {
870 schema: SchemaRef,
871 catalog_names: StringBuilder,
872 schema_names: StringBuilder,
873 table_names: StringBuilder,
874 column_names: StringBuilder,
875 ordinal_positions: UInt64Builder,
876 column_defaults: StringBuilder,
877 is_nullables: StringBuilder,
878 data_types: StringBuilder,
879 character_maximum_lengths: UInt64Builder,
880 character_octet_lengths: UInt64Builder,
881 numeric_precisions: UInt64Builder,
882 numeric_precision_radixes: UInt64Builder,
883 numeric_scales: UInt64Builder,
884 datetime_precisions: UInt64Builder,
885 interval_types: StringBuilder,
886}
887
888impl InformationSchemaColumnsBuilder {
889 fn add_column(
890 &mut self,
891 catalog_name: &str,
892 schema_name: &str,
893 table_name: &str,
894 field_position: usize,
895 field: &Field,
896 ) {
897 use DataType::*;
898
899 self.catalog_names.append_value(catalog_name);
901 self.schema_names.append_value(schema_name);
902 self.table_names.append_value(table_name);
903
904 self.column_names.append_value(field.name());
905
906 self.ordinal_positions.append_value(field_position as u64);
907
908 self.column_defaults.append_null();
910
911 let nullable_str = if field.is_nullable() { "YES" } else { "NO" };
913 self.is_nullables.append_value(nullable_str);
914
915 self.data_types.append_value(field.data_type().to_string());
917
918 let max_chars = None;
924 self.character_maximum_lengths.append_option(max_chars);
925
926 let char_len: Option<u64> = match field.data_type() {
929 Utf8 | Binary => Some(i32::MAX as u64),
930 LargeBinary | LargeUtf8 => Some(i64::MAX as u64),
931 _ => None,
932 };
933 self.character_octet_lengths.append_option(char_len);
934
935 let (numeric_precision, numeric_radix, numeric_scale) = match field.data_type() {
958 Int8 | UInt8 => (Some(8), Some(2), None),
959 Int16 | UInt16 => (Some(16), Some(2), None),
960 Int32 | UInt32 => (Some(32), Some(2), None),
961 Float16 => (Some(15), Some(2), None),
964 Float32 => (Some(24), Some(2), None),
966 Float64 => (Some(24), Some(2), None),
968 Decimal128(precision, scale) => {
969 (Some(*precision as u64), Some(10), Some(*scale as u64))
970 }
971 _ => (None, None, None),
972 };
973
974 self.numeric_precisions.append_option(numeric_precision);
975 self.numeric_precision_radixes.append_option(numeric_radix);
976 self.numeric_scales.append_option(numeric_scale);
977
978 self.datetime_precisions.append_option(None);
979 self.interval_types.append_null();
980 }
981
982 fn finish(&mut self) -> RecordBatch {
983 RecordBatch::try_new(
984 Arc::clone(&self.schema),
985 vec![
986 Arc::new(self.catalog_names.finish()),
987 Arc::new(self.schema_names.finish()),
988 Arc::new(self.table_names.finish()),
989 Arc::new(self.column_names.finish()),
990 Arc::new(self.ordinal_positions.finish()),
991 Arc::new(self.column_defaults.finish()),
992 Arc::new(self.is_nullables.finish()),
993 Arc::new(self.data_types.finish()),
994 Arc::new(self.character_maximum_lengths.finish()),
995 Arc::new(self.character_octet_lengths.finish()),
996 Arc::new(self.numeric_precisions.finish()),
997 Arc::new(self.numeric_precision_radixes.finish()),
998 Arc::new(self.numeric_scales.finish()),
999 Arc::new(self.datetime_precisions.finish()),
1000 Arc::new(self.interval_types.finish()),
1001 ],
1002 )
1003 .unwrap()
1004 }
1005}
1006
1007#[derive(Debug)]
1008struct InformationSchemata {
1009 schema: SchemaRef,
1010 config: InformationSchemaConfig,
1011}
1012
1013pub fn schemata_schema() -> SchemaRef {
1024 Arc::new(Schema::new(vec![
1025 Field::new("catalog_name", DataType::Utf8, false),
1026 Field::new("schema_name", DataType::Utf8, false),
1027 Field::new("schema_owner", DataType::Utf8, true),
1028 Field::new("default_character_set_catalog", DataType::Utf8, true),
1029 Field::new("default_character_set_schema", DataType::Utf8, true),
1030 Field::new("default_character_set_name", DataType::Utf8, true),
1031 Field::new("sql_path", DataType::Utf8, true),
1032 ]))
1033}
1034
1035impl InformationSchemata {
1036 fn new(config: InformationSchemaConfig) -> Self {
1037 Self {
1038 schema: schemata_schema(),
1039 config,
1040 }
1041 }
1042
1043 fn builder(&self) -> InformationSchemataBuilder {
1044 InformationSchemataBuilder {
1045 schema: Arc::clone(&self.schema),
1046 catalog_name: StringBuilder::new(),
1047 schema_name: StringBuilder::new(),
1048 schema_owner: StringBuilder::new(),
1049 default_character_set_catalog: StringBuilder::new(),
1050 default_character_set_schema: StringBuilder::new(),
1051 default_character_set_name: StringBuilder::new(),
1052 sql_path: StringBuilder::new(),
1053 }
1054 }
1055}
1056
1057#[derive(Debug)]
1066pub struct InformationSchemataBuilder {
1067 schema: SchemaRef,
1068 catalog_name: StringBuilder,
1069 schema_name: StringBuilder,
1070 schema_owner: StringBuilder,
1071 default_character_set_catalog: StringBuilder,
1072 default_character_set_schema: StringBuilder,
1073 default_character_set_name: StringBuilder,
1074 sql_path: StringBuilder,
1075}
1076
1077impl Default for InformationSchemataBuilder {
1078 fn default() -> Self {
1079 Self::new()
1080 }
1081}
1082
1083impl InformationSchemataBuilder {
1084 pub fn new() -> Self {
1086 Self {
1087 schema: schemata_schema(),
1088 catalog_name: StringBuilder::new(),
1089 schema_name: StringBuilder::new(),
1090 schema_owner: StringBuilder::new(),
1091 default_character_set_catalog: StringBuilder::new(),
1092 default_character_set_schema: StringBuilder::new(),
1093 default_character_set_name: StringBuilder::new(),
1094 sql_path: StringBuilder::new(),
1095 }
1096 }
1097
1098 pub fn add_schemata(
1103 &mut self,
1104 catalog_name: &str,
1105 schema_name: &str,
1106 schema_owner: Option<&str>,
1107 ) {
1108 self.catalog_name.append_value(catalog_name);
1109 self.schema_name.append_value(schema_name);
1110 match schema_owner {
1111 Some(owner) => self.schema_owner.append_value(owner),
1112 None => self.schema_owner.append_null(),
1113 }
1114 self.default_character_set_catalog.append_null();
1115 self.default_character_set_schema.append_null();
1116 self.default_character_set_name.append_null();
1117 self.sql_path.append_null();
1118 }
1119
1120 pub fn finish(&mut self) -> Result<RecordBatch> {
1127 RecordBatch::try_new(
1128 Arc::clone(&self.schema),
1129 vec![
1130 Arc::new(self.catalog_name.finish()),
1131 Arc::new(self.schema_name.finish()),
1132 Arc::new(self.schema_owner.finish()),
1133 Arc::new(self.default_character_set_catalog.finish()),
1134 Arc::new(self.default_character_set_schema.finish()),
1135 Arc::new(self.default_character_set_name.finish()),
1136 Arc::new(self.sql_path.finish()),
1137 ],
1138 )
1139 .map_err(DataFusionError::from)
1140 }
1141}
1142
1143impl PartitionStream for InformationSchemata {
1144 fn schema(&self) -> &SchemaRef {
1145 &self.schema
1146 }
1147
1148 fn execute(&self, _ctx: Arc<TaskContext>) -> SendableRecordBatchStream {
1149 let mut builder = self.builder();
1150 let config = self.config.clone();
1151 Box::pin(RecordBatchStreamAdapter::new(
1152 Arc::clone(&self.schema),
1153 futures::stream::once(async move {
1155 config.make_schemata(&mut builder);
1156 builder.finish()
1157 }),
1158 ))
1159 }
1160}
1161
1162#[derive(Debug)]
1163struct InformationSchemaDfSettings {
1164 schema: SchemaRef,
1165 config: InformationSchemaConfig,
1166}
1167
1168impl InformationSchemaDfSettings {
1169 fn new(config: InformationSchemaConfig) -> Self {
1170 let schema = Arc::new(Schema::new(vec![
1171 Field::new("name", DataType::Utf8, false),
1172 Field::new("value", DataType::Utf8, true),
1173 Field::new("description", DataType::Utf8, true),
1174 ]));
1175
1176 Self { schema, config }
1177 }
1178
1179 fn builder(&self) -> InformationSchemaDfSettingsBuilder {
1180 InformationSchemaDfSettingsBuilder {
1181 names: StringBuilder::new(),
1182 values: StringBuilder::new(),
1183 descriptions: StringBuilder::new(),
1184 schema: Arc::clone(&self.schema),
1185 }
1186 }
1187}
1188
1189impl PartitionStream for InformationSchemaDfSettings {
1190 fn schema(&self) -> &SchemaRef {
1191 &self.schema
1192 }
1193
1194 fn execute(&self, ctx: Arc<TaskContext>) -> SendableRecordBatchStream {
1195 let config = self.config.clone();
1196 let mut builder = self.builder();
1197 Box::pin(RecordBatchStreamAdapter::new(
1198 Arc::clone(&self.schema),
1199 futures::stream::once(async move {
1201 let runtime_env = ctx.runtime_env();
1203 config.make_df_settings(
1204 ctx.session_config().options(),
1205 &runtime_env,
1206 &mut builder,
1207 );
1208 Ok(builder.finish())
1209 }),
1210 ))
1211 }
1212}
1213
1214struct InformationSchemaDfSettingsBuilder {
1215 schema: SchemaRef,
1216 names: StringBuilder,
1217 values: StringBuilder,
1218 descriptions: StringBuilder,
1219}
1220
1221impl InformationSchemaDfSettingsBuilder {
1222 fn add_setting(&mut self, entry: ConfigEntry) {
1223 self.names.append_value(entry.key);
1224 self.values.append_option(entry.value);
1225 self.descriptions.append_value(entry.description);
1226 }
1227
1228 fn finish(&mut self) -> RecordBatch {
1229 RecordBatch::try_new(
1230 Arc::clone(&self.schema),
1231 vec![
1232 Arc::new(self.names.finish()),
1233 Arc::new(self.values.finish()),
1234 Arc::new(self.descriptions.finish()),
1235 ],
1236 )
1237 .unwrap()
1238 }
1239}
1240
1241#[derive(Debug)]
1242struct InformationSchemaRoutines {
1243 schema: SchemaRef,
1244 config: InformationSchemaConfig,
1245}
1246
1247impl InformationSchemaRoutines {
1248 fn new(config: InformationSchemaConfig) -> Self {
1249 let schema = Arc::new(Schema::new(vec![
1250 Field::new("specific_catalog", DataType::Utf8, false),
1251 Field::new("specific_schema", DataType::Utf8, false),
1252 Field::new("specific_name", DataType::Utf8, false),
1253 Field::new("routine_catalog", DataType::Utf8, false),
1254 Field::new("routine_schema", DataType::Utf8, false),
1255 Field::new("routine_name", DataType::Utf8, false),
1256 Field::new("routine_type", DataType::Utf8, false),
1257 Field::new("is_deterministic", DataType::Boolean, true),
1258 Field::new("data_type", DataType::Utf8, true),
1259 Field::new("function_type", DataType::Utf8, true),
1260 Field::new("description", DataType::Utf8, true),
1261 Field::new("syntax_example", DataType::Utf8, true),
1262 ]));
1263
1264 Self { schema, config }
1265 }
1266
1267 fn builder(&self) -> InformationSchemaRoutinesBuilder {
1268 InformationSchemaRoutinesBuilder {
1269 schema: Arc::clone(&self.schema),
1270 specific_catalog: StringBuilder::new(),
1271 specific_schema: StringBuilder::new(),
1272 specific_name: StringBuilder::new(),
1273 routine_catalog: StringBuilder::new(),
1274 routine_schema: StringBuilder::new(),
1275 routine_name: StringBuilder::new(),
1276 routine_type: StringBuilder::new(),
1277 is_deterministic: BooleanBuilder::new(),
1278 data_type: StringBuilder::new(),
1279 function_type: StringBuilder::new(),
1280 description: StringBuilder::new(),
1281 syntax_example: StringBuilder::new(),
1282 }
1283 }
1284}
1285
1286struct InformationSchemaRoutinesBuilder {
1287 schema: SchemaRef,
1288 specific_catalog: StringBuilder,
1289 specific_schema: StringBuilder,
1290 specific_name: StringBuilder,
1291 routine_catalog: StringBuilder,
1292 routine_schema: StringBuilder,
1293 routine_name: StringBuilder,
1294 routine_type: StringBuilder,
1295 is_deterministic: BooleanBuilder,
1296 data_type: StringBuilder,
1297 function_type: StringBuilder,
1298 description: StringBuilder,
1299 syntax_example: StringBuilder,
1300}
1301
1302impl InformationSchemaRoutinesBuilder {
1303 #[expect(clippy::too_many_arguments)]
1304 fn add_routine(
1305 &mut self,
1306 catalog_name: impl AsRef<str>,
1307 schema_name: impl AsRef<str>,
1308 routine_name: impl AsRef<str>,
1309 routine_type: impl AsRef<str>,
1310 is_deterministic: bool,
1311 data_type: Option<&impl AsRef<str>>,
1312 function_type: impl AsRef<str>,
1313 description: Option<impl AsRef<str>>,
1314 syntax_example: Option<impl AsRef<str>>,
1315 ) {
1316 self.specific_catalog.append_value(catalog_name.as_ref());
1317 self.specific_schema.append_value(schema_name.as_ref());
1318 self.specific_name.append_value(routine_name.as_ref());
1319 self.routine_catalog.append_value(catalog_name.as_ref());
1320 self.routine_schema.append_value(schema_name.as_ref());
1321 self.routine_name.append_value(routine_name.as_ref());
1322 self.routine_type.append_value(routine_type.as_ref());
1323 self.is_deterministic.append_value(is_deterministic);
1324 self.data_type.append_option(data_type.as_ref());
1325 self.function_type.append_value(function_type.as_ref());
1326 self.description.append_option(description);
1327 self.syntax_example.append_option(syntax_example);
1328 }
1329
1330 fn finish(&mut self) -> RecordBatch {
1331 RecordBatch::try_new(
1332 Arc::clone(&self.schema),
1333 vec![
1334 Arc::new(self.specific_catalog.finish()),
1335 Arc::new(self.specific_schema.finish()),
1336 Arc::new(self.specific_name.finish()),
1337 Arc::new(self.routine_catalog.finish()),
1338 Arc::new(self.routine_schema.finish()),
1339 Arc::new(self.routine_name.finish()),
1340 Arc::new(self.routine_type.finish()),
1341 Arc::new(self.is_deterministic.finish()),
1342 Arc::new(self.data_type.finish()),
1343 Arc::new(self.function_type.finish()),
1344 Arc::new(self.description.finish()),
1345 Arc::new(self.syntax_example.finish()),
1346 ],
1347 )
1348 .unwrap()
1349 }
1350}
1351
1352impl PartitionStream for InformationSchemaRoutines {
1353 fn schema(&self) -> &SchemaRef {
1354 &self.schema
1355 }
1356
1357 fn execute(&self, ctx: Arc<TaskContext>) -> SendableRecordBatchStream {
1358 let config = self.config.clone();
1359 let mut builder = self.builder();
1360 Box::pin(RecordBatchStreamAdapter::new(
1361 Arc::clone(&self.schema),
1362 futures::stream::once(async move {
1363 config.make_routines(
1364 ctx.scalar_functions(),
1365 ctx.aggregate_functions(),
1366 ctx.window_functions(),
1367 ctx.session_config().options(),
1368 &mut builder,
1369 )?;
1370 Ok(builder.finish())
1371 }),
1372 ))
1373 }
1374}
1375
1376#[derive(Debug)]
1377struct InformationSchemaParameters {
1378 schema: SchemaRef,
1379 config: InformationSchemaConfig,
1380}
1381
1382impl InformationSchemaParameters {
1383 fn new(config: InformationSchemaConfig) -> Self {
1384 let schema = Arc::new(Schema::new(vec![
1385 Field::new("specific_catalog", DataType::Utf8, false),
1386 Field::new("specific_schema", DataType::Utf8, false),
1387 Field::new("specific_name", DataType::Utf8, false),
1388 Field::new("ordinal_position", DataType::UInt64, false),
1389 Field::new("parameter_mode", DataType::Utf8, false),
1390 Field::new("parameter_name", DataType::Utf8, true),
1391 Field::new("data_type", DataType::Utf8, false),
1392 Field::new("parameter_default", DataType::Utf8, true),
1393 Field::new("is_variadic", DataType::Boolean, false),
1394 Field::new("rid", DataType::UInt8, false),
1400 ]));
1401
1402 Self { schema, config }
1403 }
1404
1405 fn builder(&self) -> InformationSchemaParametersBuilder {
1406 InformationSchemaParametersBuilder {
1407 schema: Arc::clone(&self.schema),
1408 specific_catalog: StringBuilder::new(),
1409 specific_schema: StringBuilder::new(),
1410 specific_name: StringBuilder::new(),
1411 ordinal_position: UInt64Builder::new(),
1412 parameter_mode: StringBuilder::new(),
1413 parameter_name: StringBuilder::new(),
1414 data_type: StringBuilder::new(),
1415 parameter_default: StringBuilder::new(),
1416 is_variadic: BooleanBuilder::new(),
1417 rid: UInt8Builder::new(),
1418 }
1419 }
1420}
1421
1422struct InformationSchemaParametersBuilder {
1423 schema: SchemaRef,
1424 specific_catalog: StringBuilder,
1425 specific_schema: StringBuilder,
1426 specific_name: StringBuilder,
1427 ordinal_position: UInt64Builder,
1428 parameter_mode: StringBuilder,
1429 parameter_name: StringBuilder,
1430 data_type: StringBuilder,
1431 parameter_default: StringBuilder,
1432 is_variadic: BooleanBuilder,
1433 rid: UInt8Builder,
1434}
1435
1436impl InformationSchemaParametersBuilder {
1437 #[expect(clippy::too_many_arguments)]
1438 fn add_parameter(
1439 &mut self,
1440 specific_catalog: impl AsRef<str>,
1441 specific_schema: impl AsRef<str>,
1442 specific_name: impl AsRef<str>,
1443 ordinal_position: u64,
1444 parameter_mode: impl AsRef<str>,
1445 parameter_name: Option<&(impl AsRef<str> + ?Sized)>,
1446 data_type: impl AsRef<str>,
1447 parameter_default: Option<impl AsRef<str>>,
1448 is_variadic: bool,
1449 rid: u8,
1450 ) {
1451 self.specific_catalog
1452 .append_value(specific_catalog.as_ref());
1453 self.specific_schema.append_value(specific_schema.as_ref());
1454 self.specific_name.append_value(specific_name.as_ref());
1455 self.ordinal_position.append_value(ordinal_position);
1456 self.parameter_mode.append_value(parameter_mode.as_ref());
1457 self.parameter_name.append_option(parameter_name.as_ref());
1458 self.data_type.append_value(data_type.as_ref());
1459 self.parameter_default.append_option(parameter_default);
1460 self.is_variadic.append_value(is_variadic);
1461 self.rid.append_value(rid);
1462 }
1463
1464 fn finish(&mut self) -> RecordBatch {
1465 RecordBatch::try_new(
1466 Arc::clone(&self.schema),
1467 vec![
1468 Arc::new(self.specific_catalog.finish()),
1469 Arc::new(self.specific_schema.finish()),
1470 Arc::new(self.specific_name.finish()),
1471 Arc::new(self.ordinal_position.finish()),
1472 Arc::new(self.parameter_mode.finish()),
1473 Arc::new(self.parameter_name.finish()),
1474 Arc::new(self.data_type.finish()),
1475 Arc::new(self.parameter_default.finish()),
1476 Arc::new(self.is_variadic.finish()),
1477 Arc::new(self.rid.finish()),
1478 ],
1479 )
1480 .unwrap()
1481 }
1482}
1483
1484impl PartitionStream for InformationSchemaParameters {
1485 fn schema(&self) -> &SchemaRef {
1486 &self.schema
1487 }
1488
1489 fn execute(&self, ctx: Arc<TaskContext>) -> SendableRecordBatchStream {
1490 let config = self.config.clone();
1491 let mut builder = self.builder();
1492 Box::pin(RecordBatchStreamAdapter::new(
1493 Arc::clone(&self.schema),
1494 futures::stream::once(async move {
1495 config.make_parameters(
1496 ctx.scalar_functions(),
1497 ctx.aggregate_functions(),
1498 ctx.window_functions(),
1499 ctx.session_config().options(),
1500 &mut builder,
1501 )?;
1502 Ok(builder.finish())
1503 }),
1504 ))
1505 }
1506}
1507
1508#[cfg(test)]
1509mod tests {
1510 use super::*;
1511 use crate::CatalogProvider;
1512 use arrow::array::Array;
1513
1514 #[test]
1515 fn schemata_builder_emits_canonical_schema_and_rows() {
1516 let mut builder = InformationSchemataBuilder::default();
1519 builder.add_schemata("cat", "schema_one", Some("alice"));
1520 builder.add_schemata("cat", "schema_two", None);
1521 let batch = builder.finish().expect("finish should not fail");
1522
1523 assert_eq!(batch.schema(), schemata_schema());
1524 assert_eq!(batch.num_rows(), 2);
1525
1526 let col = |name: &str| {
1527 batch
1528 .column_by_name(name)
1529 .unwrap_or_else(|| panic!("missing column {name}"))
1530 };
1531 let string_col = |name: &str| {
1532 col(name)
1533 .as_any()
1534 .downcast_ref::<arrow::array::StringArray>()
1535 .unwrap_or_else(|| panic!("{name} should be a StringArray"))
1536 };
1537
1538 let catalog = string_col("catalog_name");
1539 assert_eq!(catalog.value(0), "cat");
1540 assert_eq!(catalog.value(1), "cat");
1541
1542 let schema = string_col("schema_name");
1543 assert_eq!(schema.value(0), "schema_one");
1544 assert_eq!(schema.value(1), "schema_two");
1545
1546 let owner = string_col("schema_owner");
1547 assert_eq!(owner.value(0), "alice");
1548 assert!(owner.is_null(1));
1549
1550 for name in [
1553 "default_character_set_catalog",
1554 "default_character_set_schema",
1555 "default_character_set_name",
1556 "sql_path",
1557 ] {
1558 let c = string_col(name);
1559 assert!(c.is_null(0), "{name} row 0 should be null");
1560 assert!(c.is_null(1), "{name} row 1 should be null");
1561 }
1562 }
1563
1564 #[tokio::test]
1565 async fn make_tables_uses_table_type() {
1566 let config = InformationSchemaConfig {
1567 catalog_list: Arc::new(Fixture),
1568 table_functions: HashMap::new(),
1569 };
1570 let mut builder = InformationSchemaTablesBuilder {
1571 catalog_names: StringBuilder::new(),
1572 schema_names: StringBuilder::new(),
1573 table_names: StringBuilder::new(),
1574 table_types: StringBuilder::new(),
1575 schema: Arc::new(Schema::empty()),
1576 };
1577
1578 assert!(config.make_tables(&mut builder).await.is_ok());
1579
1580 assert_eq!("BASE TABLE", builder.table_types.finish().value(0));
1581 }
1582
1583 #[derive(Debug)]
1584 struct Fixture;
1585
1586 #[async_trait]
1587 impl SchemaProvider for Fixture {
1588 async fn table_type(&self, _: &str) -> Result<Option<TableType>> {
1590 Ok(Some(TableType::Base))
1591 }
1592
1593 async fn table(&self, _: &str) -> Result<Option<Arc<dyn TableProvider>>> {
1596 panic!(
1597 "InformationSchemaConfig::make_tables called SchemaProvider::table instead of table_type"
1598 )
1599 }
1600
1601 fn table_names(&self) -> Vec<String> {
1602 vec!["atable".to_string()]
1603 }
1604
1605 fn table_exist(&self, _: &str) -> bool {
1606 unimplemented!("not required for these tests")
1607 }
1608 }
1609
1610 impl CatalogProviderList for Fixture {
1611 fn register_catalog(
1612 &self,
1613 _: String,
1614 _: Arc<dyn CatalogProvider>,
1615 ) -> Option<Arc<dyn CatalogProvider>> {
1616 unimplemented!("not required for these tests")
1617 }
1618
1619 fn catalog_names(&self) -> Vec<String> {
1620 vec!["acatalog".to_string()]
1621 }
1622
1623 fn catalog(&self, _: &str) -> Option<Arc<dyn CatalogProvider>> {
1624 Some(Arc::new(Self))
1625 }
1626 }
1627
1628 impl CatalogProvider for Fixture {
1629 fn schema_names(&self) -> Vec<String> {
1630 vec!["aschema".to_string()]
1631 }
1632
1633 fn schema(&self, _: &str) -> Option<Arc<dyn SchemaProvider>> {
1634 Some(Arc::new(Self))
1635 }
1636 }
1637}