1mod show_create_table;
16
17use std::collections::HashMap;
18use std::ops::ControlFlow;
19use std::sync::Arc;
20
21use catalog::CatalogManagerRef;
22use catalog::information_schema::{
23 CHARACTER_SETS, COLLATIONS, COLUMNS, FLOW_STATISTICS, FLOWS, REGION_PEERS, SCHEMATA,
24 STATISTICS, TABLES, VIEWS, columns, flow_statistics, flows, process_list, region_peers,
25 schemata, statistics, tables,
26};
27use common_catalog::consts::{
28 INFORMATION_SCHEMA_NAME, SEMANTIC_TYPE_FIELD, SEMANTIC_TYPE_PRIMARY_KEY,
29 SEMANTIC_TYPE_TIME_INDEX,
30};
31use common_catalog::format_full_table_name;
32use common_datasource::file_format::{FileFormat, Format, infer_schemas};
33use common_datasource::lister::{Lister, Source};
34use common_datasource::object_store::{LocalFileAccess, build_backend_with_path};
35use common_error::ext::BoxedError;
36use common_meta::SchemaOptions;
37use common_meta::ddl::create_flow::{FlowType, effective_eval_schedule_from_flow_info};
38use common_meta::key::flow::flow_info::FlowInfoValue;
39use common_query::Output;
40use common_query::prelude::greptime_timestamp;
41use common_recordbatch::RecordBatches;
42use common_recordbatch::adapter::RecordBatchStreamAdapter;
43use common_time::Timestamp;
44use common_time::timezone::get_timezone;
45use datafusion::dataframe::DataFrame;
46use datafusion::prelude::SessionContext;
47use datafusion_expr::{Expr, SortExpr, col, lit};
48use datatypes::prelude::*;
49use datatypes::schema::{ColumnDefaultConstraint, ColumnSchema, Schema};
50use datatypes::vectors::StringVector;
51use itertools::Itertools;
52use object_store::ObjectStore;
53use once_cell::sync::Lazy;
54use regex::Regex;
55use session::context::{Channel, QueryContextRef};
56pub use show_create_table::create_table_stmt;
57use snafu::{OptionExt, ResultExt, ensure};
58use sql::ast::{Ident, visit_expressions_mut};
59use sql::parser::ParserContext;
60use sql::statements::OptionMap;
61use sql::statements::create::{CreateDatabase, CreateFlow, CreateView, Partitions, SqlOrTql};
62use sql::statements::show::{
63 ShowColumns, ShowDatabases, ShowFlowStatus, ShowFlows, ShowIndex, ShowKind, ShowProcessList,
64 ShowRegion, ShowTableStatus, ShowTables, ShowVariables, ShowViews,
65};
66use sql::statements::statement::Statement;
67use sqlparser::ast::ObjectName;
68use store_api::metric_engine_consts::{is_metric_engine, is_metric_engine_internal_column};
69use table::TableRef;
70use table::metadata::TableInfoRef;
71use table::requests::{FILE_TABLE_LOCATION_KEY, FILE_TABLE_PATTERN_KEY};
72
73use crate::QueryEngineRef;
74use crate::error::{self, Result, UnsupportedVariableSnafu};
75use crate::planner::DfLogicalPlanner;
76
77const SCHEMAS_COLUMN: &str = "Database";
78const OPTIONS_COLUMN: &str = "Options";
79const VIEWS_COLUMN: &str = "Views";
80const FLOWS_COLUMN: &str = "Flows";
81const FIELD_COLUMN: &str = "Field";
82const TABLE_TYPE_COLUMN: &str = "Table_type";
83
84const COLUMN_NAME_COLUMN: &str = "Column";
85const COLUMN_GREPTIME_TYPE_COLUMN: &str = "Greptime_type";
86const COLUMN_TYPE_COLUMN: &str = "Type";
87const COLUMN_KEY_COLUMN: &str = "Key";
88const COLUMN_EXTRA_COLUMN: &str = "Extra";
89const COLUMN_PRIVILEGES_COLUMN: &str = "Privileges";
90const COLUMN_COLLATION_COLUMN: &str = "Collation";
91const COLUMN_NULLABLE_COLUMN: &str = "Null";
92const COLUMN_DEFAULT_COLUMN: &str = "Default";
93const COLUMN_COMMENT_COLUMN: &str = "Comment";
94const COLUMN_SEMANTIC_TYPE_COLUMN: &str = "Semantic Type";
95
96const YES_STR: &str = "YES";
97const NO_STR: &str = "NO";
98const PRI_KEY: &str = "PRI";
99
100const INDEX_TABLE_COLUMN: &str = "Table";
102const INDEX_NONT_UNIQUE_COLUMN: &str = "Non_unique";
103const INDEX_CARDINALITY_COLUMN: &str = "Cardinality";
104const INDEX_SUB_PART_COLUMN: &str = "Sub_part";
105const INDEX_PACKED_COLUMN: &str = "Packed";
106const INDEX_INDEX_TYPE_COLUMN: &str = "Index_type";
107const INDEX_COMMENT_COLUMN: &str = "Index_comment";
108const INDEX_VISIBLE_COLUMN: &str = "Visible";
109const INDEX_EXPRESSION_COLUMN: &str = "Expression";
110const INDEX_KEY_NAME_COLUMN: &str = "Key_name";
111const INDEX_SEQ_IN_INDEX_COLUMN: &str = "Seq_in_index";
112const INDEX_COLUMN_NAME_COLUMN: &str = "Column_name";
113
114pub static DESCRIBE_TABLE_OUTPUT_SCHEMA: Lazy<Arc<Schema>> = Lazy::new(|| {
115 Arc::new(Schema::new(vec![
116 ColumnSchema::new(
117 COLUMN_NAME_COLUMN,
118 ConcreteDataType::string_datatype(),
119 false,
120 ),
121 ColumnSchema::new(
122 COLUMN_TYPE_COLUMN,
123 ConcreteDataType::string_datatype(),
124 false,
125 ),
126 ColumnSchema::new(COLUMN_KEY_COLUMN, ConcreteDataType::string_datatype(), true),
127 ColumnSchema::new(
128 COLUMN_NULLABLE_COLUMN,
129 ConcreteDataType::string_datatype(),
130 false,
131 ),
132 ColumnSchema::new(
133 COLUMN_DEFAULT_COLUMN,
134 ConcreteDataType::string_datatype(),
135 false,
136 ),
137 ColumnSchema::new(
138 COLUMN_SEMANTIC_TYPE_COLUMN,
139 ConcreteDataType::string_datatype(),
140 false,
141 ),
142 ]))
143});
144
145static SHOW_CREATE_DATABASE_OUTPUT_SCHEMA: Lazy<Arc<Schema>> = Lazy::new(|| {
146 Arc::new(Schema::new(vec![
147 ColumnSchema::new("Database", ConcreteDataType::string_datatype(), false),
148 ColumnSchema::new(
149 "Create Database",
150 ConcreteDataType::string_datatype(),
151 false,
152 ),
153 ]))
154});
155
156static SHOW_CREATE_TABLE_OUTPUT_SCHEMA: Lazy<Arc<Schema>> = Lazy::new(|| {
157 Arc::new(Schema::new(vec![
158 ColumnSchema::new("Table", ConcreteDataType::string_datatype(), false),
159 ColumnSchema::new("Create Table", ConcreteDataType::string_datatype(), false),
160 ]))
161});
162
163static SHOW_CREATE_FLOW_OUTPUT_SCHEMA: Lazy<Arc<Schema>> = Lazy::new(|| {
164 Arc::new(Schema::new(vec![
165 ColumnSchema::new("Flow", ConcreteDataType::string_datatype(), false),
166 ColumnSchema::new("Create Flow", ConcreteDataType::string_datatype(), false),
167 ]))
168});
169
170static SHOW_CREATE_VIEW_OUTPUT_SCHEMA: Lazy<Arc<Schema>> = Lazy::new(|| {
171 Arc::new(Schema::new(vec![
172 ColumnSchema::new("View", ConcreteDataType::string_datatype(), false),
173 ColumnSchema::new("Create View", ConcreteDataType::string_datatype(), false),
174 ]))
175});
176
177pub async fn show_databases(
178 stmt: ShowDatabases,
179 query_engine: &QueryEngineRef,
180 catalog_manager: &CatalogManagerRef,
181 query_ctx: QueryContextRef,
182) -> Result<Output> {
183 let dataframe =
184 show_databases_dataframe(&stmt, query_engine, catalog_manager, query_ctx).await?;
185 dataframe_to_output(dataframe).await
186}
187
188pub async fn show_databases_dataframe(
190 stmt: &ShowDatabases,
191 query_engine: &QueryEngineRef,
192 catalog_manager: &CatalogManagerRef,
193 query_ctx: QueryContextRef,
194) -> Result<DataFrame> {
195 let projects = if stmt.full {
196 vec![
197 (schemata::SCHEMA_NAME, SCHEMAS_COLUMN),
198 (schemata::SCHEMA_OPTS, OPTIONS_COLUMN),
199 ]
200 } else {
201 vec![(schemata::SCHEMA_NAME, SCHEMAS_COLUMN)]
202 };
203
204 let filters = vec![col(schemata::CATALOG_NAME).eq(lit(query_ctx.current_catalog()))];
205 let like_field = Some(schemata::SCHEMA_NAME);
206 let sort = vec![col(schemata::SCHEMA_NAME).sort(true, true)];
207
208 query_from_information_schema_dataframe(
209 query_engine,
210 catalog_manager,
211 query_ctx,
212 SCHEMATA,
213 vec![],
214 projects,
215 filters,
216 like_field,
217 sort,
218 &stmt.kind,
219 )
220 .await
221}
222
223fn replace_column_in_expr(expr: &mut sqlparser::ast::Expr, from_column: &str, to_column: &str) {
226 let _ = visit_expressions_mut(expr, |e| {
227 match e {
228 sqlparser::ast::Expr::Identifier(ident)
229 if ident.value.eq_ignore_ascii_case(from_column) =>
230 {
231 ident.value = to_column.to_string();
232 }
233 sqlparser::ast::Expr::CompoundIdentifier(idents) => {
234 if let Some(last) = idents.last_mut()
235 && last.value.eq_ignore_ascii_case(from_column)
236 {
237 last.value = to_column.to_string();
238 }
239 }
240 _ => {}
241 }
242 ControlFlow::<()>::Continue(())
243 });
244}
245
246#[allow(clippy::too_many_arguments)]
254async fn query_from_information_schema_table(
255 query_engine: &QueryEngineRef,
256 catalog_manager: &CatalogManagerRef,
257 query_ctx: QueryContextRef,
258 table_name: &str,
259 select: Vec<Expr>,
260 projects: Vec<(&str, &str)>,
261 filters: Vec<Expr>,
262 like_field: Option<&str>,
263 sort: Vec<SortExpr>,
264 kind: ShowKind,
265) -> Result<Output> {
266 let dataframe = query_from_information_schema_dataframe(
267 query_engine,
268 catalog_manager,
269 query_ctx,
270 table_name,
271 select,
272 projects,
273 filters,
274 like_field,
275 sort,
276 &kind,
277 )
278 .await?;
279 dataframe_to_output(dataframe).await
280}
281
282async fn dataframe_to_output(dataframe: DataFrame) -> Result<Output> {
283 let stream = dataframe.execute_stream().await?;
284 Ok(Output::new_with_stream(Box::pin(
285 RecordBatchStreamAdapter::try_new(stream).context(error::CreateRecordBatchSnafu)?,
286 )))
287}
288
289#[allow(clippy::too_many_arguments)]
293async fn query_from_information_schema_dataframe(
294 query_engine: &QueryEngineRef,
295 catalog_manager: &CatalogManagerRef,
296 query_ctx: QueryContextRef,
297 table_name: &str,
298 select: Vec<Expr>,
299 projects: Vec<(&str, &str)>,
300 filters: Vec<Expr>,
301 like_field: Option<&str>,
302 sort: Vec<SortExpr>,
303 kind: &ShowKind,
304) -> Result<DataFrame> {
305 let table = catalog_manager
306 .table(
307 query_ctx.current_catalog(),
308 INFORMATION_SCHEMA_NAME,
309 table_name,
310 Some(&query_ctx),
311 )
312 .await
313 .context(error::CatalogSnafu)?
314 .with_context(|| error::TableNotFoundSnafu {
315 table: format_full_table_name(
316 query_ctx.current_catalog(),
317 INFORMATION_SCHEMA_NAME,
318 table_name,
319 ),
320 })?;
321
322 let dataframe = query_engine.read_table(table)?;
323
324 let dataframe = filters.into_iter().try_fold(dataframe, |df, expr| {
326 df.filter(expr).context(error::PlanSqlSnafu)
327 })?;
328
329 let dataframe = if let (ShowKind::Like(ident), Some(field)) = (&kind, like_field) {
331 dataframe
332 .filter(col(field).like(lit(ident.value.clone())))
333 .context(error::PlanSqlSnafu)?
334 } else {
335 dataframe
336 };
337
338 let dataframe = if sort.is_empty() {
340 dataframe
341 } else {
342 dataframe.sort(sort).context(error::PlanSqlSnafu)?
343 };
344
345 let dataframe = if select.is_empty() {
347 if projects.is_empty() {
348 dataframe
349 } else {
350 let projection = projects
351 .iter()
352 .map(|x| col(x.0).alias(x.1))
353 .collect::<Vec<_>>();
354 dataframe.select(projection).context(error::PlanSqlSnafu)?
355 }
356 } else {
357 dataframe.select(select).context(error::PlanSqlSnafu)?
358 };
359
360 let dataframe = projects
362 .into_iter()
363 .try_fold(dataframe, |df, (column, renamed_column)| {
364 df.with_column_renamed(column, renamed_column)
365 .context(error::PlanSqlSnafu)
366 })?;
367
368 let dataframe = match kind {
369 ShowKind::All | ShowKind::Like(_) => {
370 dataframe
372 }
373 ShowKind::Where(filter) => {
374 let view = dataframe.into_view();
377 let dataframe = SessionContext::new_with_state(
378 query_engine
379 .engine_context(query_ctx.clone())?
380 .state()
381 .clone(),
382 )
383 .read_table(view)?;
384
385 let planner = query_engine.planner();
386 let planner = planner
387 .as_any()
388 .downcast_ref::<DfLogicalPlanner>()
389 .expect("Must be the datafusion planner");
390
391 let filter = planner
392 .sql_to_expr(filter.clone(), dataframe.schema(), false, query_ctx)
393 .await?;
394
395 dataframe.filter(filter).context(error::PlanSqlSnafu)?
397 }
398 };
399
400 Ok(dataframe)
401}
402
403pub async fn show_columns(
405 stmt: ShowColumns,
406 query_engine: &QueryEngineRef,
407 catalog_manager: &CatalogManagerRef,
408 query_ctx: QueryContextRef,
409) -> Result<Output> {
410 let dataframe = show_columns_dataframe(&stmt, query_engine, catalog_manager, query_ctx).await?;
411 dataframe_to_output(dataframe).await
412}
413
414pub async fn show_columns_dataframe(
416 stmt: &ShowColumns,
417 query_engine: &QueryEngineRef,
418 catalog_manager: &CatalogManagerRef,
419 query_ctx: QueryContextRef,
420) -> Result<DataFrame> {
421 let schema_name = if let Some(database) = &stmt.database {
422 database.clone()
423 } else {
424 query_ctx.current_schema()
425 };
426
427 let projects = if stmt.full {
428 vec![
429 (columns::COLUMN_NAME, FIELD_COLUMN),
430 (columns::DATA_TYPE, COLUMN_TYPE_COLUMN),
431 (columns::COLLATION_NAME, COLUMN_COLLATION_COLUMN),
432 (columns::IS_NULLABLE, COLUMN_NULLABLE_COLUMN),
433 (columns::COLUMN_KEY, COLUMN_KEY_COLUMN),
434 (columns::COLUMN_DEFAULT, COLUMN_DEFAULT_COLUMN),
435 (columns::COLUMN_COMMENT, COLUMN_COMMENT_COLUMN),
436 (columns::PRIVILEGES, COLUMN_PRIVILEGES_COLUMN),
437 (columns::EXTRA, COLUMN_EXTRA_COLUMN),
438 (columns::GREPTIME_DATA_TYPE, COLUMN_GREPTIME_TYPE_COLUMN),
439 ]
440 } else {
441 vec![
442 (columns::COLUMN_NAME, FIELD_COLUMN),
443 (columns::DATA_TYPE, COLUMN_TYPE_COLUMN),
444 (columns::IS_NULLABLE, COLUMN_NULLABLE_COLUMN),
445 (columns::COLUMN_KEY, COLUMN_KEY_COLUMN),
446 (columns::COLUMN_DEFAULT, COLUMN_DEFAULT_COLUMN),
447 (columns::EXTRA, COLUMN_EXTRA_COLUMN),
448 (columns::GREPTIME_DATA_TYPE, COLUMN_GREPTIME_TYPE_COLUMN),
449 ]
450 };
451
452 let filters = vec![
453 col(columns::TABLE_NAME).eq(lit(&stmt.table)),
454 col(columns::TABLE_SCHEMA).eq(lit(schema_name.clone())),
455 col(columns::TABLE_CATALOG).eq(lit(query_ctx.current_catalog())),
456 ];
457 let like_field = Some(columns::COLUMN_NAME);
458 let sort = vec![col(columns::COLUMN_NAME).sort(true, true)];
459
460 query_from_information_schema_dataframe(
461 query_engine,
462 catalog_manager,
463 query_ctx,
464 COLUMNS,
465 vec![],
466 projects,
467 filters,
468 like_field,
469 sort,
470 &stmt.kind,
471 )
472 .await
473}
474
475pub async fn show_index(
477 stmt: ShowIndex,
478 query_engine: &QueryEngineRef,
479 catalog_manager: &CatalogManagerRef,
480 query_ctx: QueryContextRef,
481) -> Result<Output> {
482 let dataframe = show_index_dataframe(&stmt, query_engine, catalog_manager, query_ctx).await?;
483 dataframe_to_output(dataframe).await
484}
485
486pub async fn show_index_dataframe(
488 stmt: &ShowIndex,
489 query_engine: &QueryEngineRef,
490 catalog_manager: &CatalogManagerRef,
491 query_ctx: QueryContextRef,
492) -> Result<DataFrame> {
493 let schema_name = if let Some(database) = &stmt.database {
494 database.clone()
495 } else {
496 query_ctx.current_schema()
497 };
498
499 let select = vec![
500 col(statistics::TABLE_NAME).alias(INDEX_TABLE_COLUMN),
501 col(statistics::NON_UNIQUE).alias(INDEX_NONT_UNIQUE_COLUMN),
502 col(statistics::INDEX_NAME).alias(INDEX_KEY_NAME_COLUMN),
503 col(statistics::SEQ_IN_INDEX).alias(INDEX_SEQ_IN_INDEX_COLUMN),
504 col(statistics::COLUMN_NAME).alias(INDEX_COLUMN_NAME_COLUMN),
505 col(statistics::COLLATION).alias(COLUMN_COLLATION_COLUMN),
506 col(statistics::CARDINALITY).alias(INDEX_CARDINALITY_COLUMN),
507 col(statistics::SUB_PART).alias(INDEX_SUB_PART_COLUMN),
508 col(statistics::PACKED).alias(INDEX_PACKED_COLUMN),
509 col(statistics::NULLABLE).alias(COLUMN_NULLABLE_COLUMN),
510 col(statistics::INDEX_TYPE).alias(INDEX_INDEX_TYPE_COLUMN),
511 col(statistics::COMMENT).alias(COLUMN_COMMENT_COLUMN),
512 col(statistics::INDEX_COMMENT).alias(INDEX_COMMENT_COLUMN),
513 col(statistics::IS_VISIBLE).alias(INDEX_VISIBLE_COLUMN),
514 col(statistics::EXPRESSION).alias(INDEX_EXPRESSION_COLUMN),
515 ];
516
517 let projects = vec![
518 (statistics::TABLE_NAME, INDEX_TABLE_COLUMN),
519 (INDEX_NONT_UNIQUE_COLUMN, INDEX_NONT_UNIQUE_COLUMN),
520 (statistics::INDEX_NAME, INDEX_KEY_NAME_COLUMN),
521 (statistics::SEQ_IN_INDEX, INDEX_SEQ_IN_INDEX_COLUMN),
522 (statistics::COLUMN_NAME, INDEX_COLUMN_NAME_COLUMN),
523 (COLUMN_COLLATION_COLUMN, COLUMN_COLLATION_COLUMN),
524 (INDEX_CARDINALITY_COLUMN, INDEX_CARDINALITY_COLUMN),
525 (INDEX_SUB_PART_COLUMN, INDEX_SUB_PART_COLUMN),
526 (INDEX_PACKED_COLUMN, INDEX_PACKED_COLUMN),
527 (COLUMN_NULLABLE_COLUMN, COLUMN_NULLABLE_COLUMN),
528 (statistics::INDEX_TYPE, INDEX_INDEX_TYPE_COLUMN),
529 (COLUMN_COMMENT_COLUMN, COLUMN_COMMENT_COLUMN),
530 (INDEX_COMMENT_COLUMN, INDEX_COMMENT_COLUMN),
531 (INDEX_VISIBLE_COLUMN, INDEX_VISIBLE_COLUMN),
532 (INDEX_EXPRESSION_COLUMN, INDEX_EXPRESSION_COLUMN),
533 ];
534
535 let filters = vec![
536 col(statistics::TABLE_NAME).eq(lit(&stmt.table)),
537 col(statistics::TABLE_SCHEMA).eq(lit(schema_name.clone())),
538 ];
539 let like_field = None;
540 let sort = vec![
541 col(statistics::INDEX_NAME).sort(true, true),
542 col(statistics::SEQ_IN_INDEX).sort(true, true),
543 ];
544
545 query_from_information_schema_dataframe(
546 query_engine,
547 catalog_manager,
548 query_ctx,
549 STATISTICS,
550 select,
551 projects,
552 filters,
553 like_field,
554 sort,
555 &stmt.kind,
556 )
557 .await
558}
559
560pub async fn show_region(
562 stmt: ShowRegion,
563 query_engine: &QueryEngineRef,
564 catalog_manager: &CatalogManagerRef,
565 query_ctx: QueryContextRef,
566) -> Result<Output> {
567 let dataframe = show_region_dataframe(&stmt, query_engine, catalog_manager, query_ctx).await?;
568 dataframe_to_output(dataframe).await
569}
570
571pub async fn show_region_dataframe(
573 stmt: &ShowRegion,
574 query_engine: &QueryEngineRef,
575 catalog_manager: &CatalogManagerRef,
576 query_ctx: QueryContextRef,
577) -> Result<DataFrame> {
578 let schema_name = if let Some(database) = &stmt.database {
579 database.clone()
580 } else {
581 query_ctx.current_schema()
582 };
583
584 let filters = vec![
585 col(region_peers::TABLE_NAME).eq(lit(&stmt.table)),
586 col(region_peers::TABLE_SCHEMA).eq(lit(schema_name.clone())),
587 col(region_peers::TABLE_CATALOG).eq(lit(query_ctx.current_catalog())),
588 ];
589 let projects = vec![
590 (region_peers::TABLE_NAME, "Table"),
591 (region_peers::REGION_ID, "Region"),
592 (region_peers::PEER_ID, "Peer"),
593 (region_peers::IS_LEADER, "Leader"),
594 ];
595
596 let like_field = None;
597 let sort = vec![
598 col(columns::REGION_ID).sort(true, true),
599 col(columns::PEER_ID).sort(true, true),
600 ];
601
602 query_from_information_schema_dataframe(
603 query_engine,
604 catalog_manager,
605 query_ctx,
606 REGION_PEERS,
607 vec![],
608 projects,
609 filters,
610 like_field,
611 sort,
612 &stmt.kind,
613 )
614 .await
615}
616
617pub async fn show_tables(
619 stmt: ShowTables,
620 query_engine: &QueryEngineRef,
621 catalog_manager: &CatalogManagerRef,
622 query_ctx: QueryContextRef,
623) -> Result<Output> {
624 let dataframe = show_tables_dataframe(&stmt, query_engine, catalog_manager, query_ctx).await?;
625 dataframe_to_output(dataframe).await
626}
627
628pub async fn show_tables_dataframe(
630 stmt: &ShowTables,
631 query_engine: &QueryEngineRef,
632 catalog_manager: &CatalogManagerRef,
633 query_ctx: QueryContextRef,
634) -> Result<DataFrame> {
635 let schema_name = if let Some(database) = &stmt.database {
636 database.clone()
637 } else {
638 query_ctx.current_schema()
639 };
640
641 let tables_column = format!("Tables_in_{}", schema_name);
643 let projects = if stmt.full {
644 vec![
645 (tables::TABLE_NAME, tables_column.as_str()),
646 (tables::TABLE_TYPE, TABLE_TYPE_COLUMN),
647 ]
648 } else {
649 vec![(tables::TABLE_NAME, tables_column.as_str())]
650 };
651 let filters = vec![
652 col(tables::TABLE_SCHEMA).eq(lit(schema_name.clone())),
653 col(tables::TABLE_CATALOG).eq(lit(query_ctx.current_catalog())),
654 ];
655 let like_field = Some(tables::TABLE_NAME);
656 let sort = vec![col(tables::TABLE_NAME).sort(true, true)];
657
658 let rewritten_kind = match &stmt.kind {
661 ShowKind::Where(filter) => {
662 let mut filter = filter.clone();
663 replace_column_in_expr(&mut filter, "Tables", &tables_column);
664 ShowKind::Where(filter)
665 }
666 kind => kind.clone(),
667 };
668
669 query_from_information_schema_dataframe(
670 query_engine,
671 catalog_manager,
672 query_ctx,
673 TABLES,
674 vec![],
675 projects,
676 filters,
677 like_field,
678 sort,
679 &rewritten_kind,
680 )
681 .await
682}
683
684pub async fn show_table_status(
686 stmt: ShowTableStatus,
687 query_engine: &QueryEngineRef,
688 catalog_manager: &CatalogManagerRef,
689 query_ctx: QueryContextRef,
690) -> Result<Output> {
691 let dataframe =
692 show_table_status_dataframe(&stmt, query_engine, catalog_manager, query_ctx).await?;
693 dataframe_to_output(dataframe).await
694}
695
696pub async fn show_table_status_dataframe(
698 stmt: &ShowTableStatus,
699 query_engine: &QueryEngineRef,
700 catalog_manager: &CatalogManagerRef,
701 query_ctx: QueryContextRef,
702) -> Result<DataFrame> {
703 let schema_name = if let Some(database) = &stmt.database {
704 database.clone()
705 } else {
706 query_ctx.current_schema()
707 };
708
709 let projects = vec![
711 (tables::TABLE_NAME, "Name"),
712 (tables::ENGINE, "Engine"),
713 (tables::VERSION, "Version"),
714 (tables::ROW_FORMAT, "Row_format"),
715 (tables::TABLE_ROWS, "Rows"),
716 (tables::AVG_ROW_LENGTH, "Avg_row_length"),
717 (tables::DATA_LENGTH, "Data_length"),
718 (tables::MAX_DATA_LENGTH, "Max_data_length"),
719 (tables::INDEX_LENGTH, "Index_length"),
720 (tables::DATA_FREE, "Data_free"),
721 (tables::AUTO_INCREMENT, "Auto_increment"),
722 (tables::CREATE_TIME, "Create_time"),
723 (tables::UPDATE_TIME, "Update_time"),
724 (tables::CHECK_TIME, "Check_time"),
725 (tables::TABLE_COLLATION, "Collation"),
726 (tables::CHECKSUM, "Checksum"),
727 (tables::CREATE_OPTIONS, "Create_options"),
728 (tables::TABLE_COMMENT, "Comment"),
729 ];
730
731 let filters = vec![
732 col(tables::TABLE_SCHEMA).eq(lit(schema_name.clone())),
733 col(tables::TABLE_CATALOG).eq(lit(query_ctx.current_catalog())),
734 ];
735 let like_field = Some(tables::TABLE_NAME);
736 let sort = vec![col(tables::TABLE_NAME).sort(true, true)];
737
738 query_from_information_schema_dataframe(
739 query_engine,
740 catalog_manager,
741 query_ctx,
742 TABLES,
743 vec![],
744 projects,
745 filters,
746 like_field,
747 sort,
748 &stmt.kind,
749 )
750 .await
751}
752
753pub async fn show_collations(
755 kind: ShowKind,
756 query_engine: &QueryEngineRef,
757 catalog_manager: &CatalogManagerRef,
758 query_ctx: QueryContextRef,
759) -> Result<Output> {
760 let dataframe =
761 show_collations_dataframe(&kind, query_engine, catalog_manager, query_ctx).await?;
762 dataframe_to_output(dataframe).await
763}
764
765pub async fn show_collations_dataframe(
767 kind: &ShowKind,
768 query_engine: &QueryEngineRef,
769 catalog_manager: &CatalogManagerRef,
770 query_ctx: QueryContextRef,
771) -> Result<DataFrame> {
772 let projects = vec![
774 ("collation_name", "Collation"),
775 ("character_set_name", "Charset"),
776 ("id", "Id"),
777 ("is_default", "Default"),
778 ("is_compiled", "Compiled"),
779 ("sortlen", "Sortlen"),
780 ];
781
782 let filters = vec![];
783 let like_field = Some("collation_name");
784 let sort = vec![];
785
786 query_from_information_schema_dataframe(
787 query_engine,
788 catalog_manager,
789 query_ctx,
790 COLLATIONS,
791 vec![],
792 projects,
793 filters,
794 like_field,
795 sort,
796 kind,
797 )
798 .await
799}
800
801pub async fn show_charsets(
803 kind: ShowKind,
804 query_engine: &QueryEngineRef,
805 catalog_manager: &CatalogManagerRef,
806 query_ctx: QueryContextRef,
807) -> Result<Output> {
808 let dataframe =
809 show_charsets_dataframe(&kind, query_engine, catalog_manager, query_ctx).await?;
810 dataframe_to_output(dataframe).await
811}
812
813pub async fn show_charsets_dataframe(
815 kind: &ShowKind,
816 query_engine: &QueryEngineRef,
817 catalog_manager: &CatalogManagerRef,
818 query_ctx: QueryContextRef,
819) -> Result<DataFrame> {
820 let projects = vec![
822 ("character_set_name", "Charset"),
823 ("description", "Description"),
824 ("default_collate_name", "Default collation"),
825 ("maxlen", "Maxlen"),
826 ];
827
828 let filters = vec![];
829 let like_field = Some("character_set_name");
830 let sort = vec![];
831
832 query_from_information_schema_dataframe(
833 query_engine,
834 catalog_manager,
835 query_ctx,
836 CHARACTER_SETS,
837 vec![],
838 projects,
839 filters,
840 like_field,
841 sort,
842 kind,
843 )
844 .await
845}
846
847pub fn show_query_option(
849 stmt: ShowVariables,
850 query_ctx: QueryContextRef,
851 engine: &dyn crate::QueryEngine,
852) -> Result<Option<Output>> {
853 let name = sql::ast::object_name_to_string_unquoted(&stmt.variable);
854 let Some(canonical) = session::query_options::canonical_query_option_name(&name) else {
855 if name.to_ascii_lowercase().starts_with("query.")
856 || name.to_ascii_lowercase().starts_with("datafusion.")
857 {
858 session::query_options::parse_query_option(
859 &name,
860 "",
861 session::query_options::MAX_PUBLIC_PARALLELISM,
862 )
863 .map_err(|error| {
864 error::InvalidQueryContextExtensionSnafu {
865 reason: error.to_string(),
866 }
867 .build()
868 })?;
869 }
870 return Ok(None);
871 };
872 let context = engine.engine_context(query_ctx.clone())?;
873 let value = match canonical.as_str() {
874 "query.allow_query_fallback" => context
875 .state()
876 .config_options()
877 .extensions
878 .get::<crate::dist_plan::DistPlannerOptions>()
879 .map(|options| options.allow_query_fallback)
880 .unwrap_or(false)
881 .to_string(),
882 "query.enable_remote_dynamic_filter_pushdown" => {
883 crate::options::remote_dyn_filter_pushdown_enabled_from_extensions(
884 &context.query_ctx().extensions(),
885 )?
886 .to_string()
887 }
888 "query.parallelism" => context.state().config().target_partitions().to_string(),
889 "datafusion.optimizer.filter_null_join_keys"
890 if context
891 .state()
892 .analyzer()
893 .rules
894 .iter()
895 .any(|rule| rule.name() == "DistPlannerAnalyzer")
896 && context
897 .query_ctx()
898 .extension("datafusion.optimizer.filter_null_join_keys")
899 .is_none() =>
900 {
901 "true".to_string()
902 }
903 _ => context
904 .state()
905 .config_options()
906 .entries()
907 .into_iter()
908 .find(|entry| entry.key == canonical)
909 .and_then(|entry| entry.value)
910 .ok_or_else(|| {
911 error::InvalidQueryContextExtensionSnafu {
912 reason: format!(
913 "No DataFusion configuration entry for supported option {canonical}"
914 ),
915 }
916 .build()
917 })?,
918 };
919 let schema = Arc::new(Schema::new(vec![ColumnSchema::new(
920 name.clone(),
921 ConcreteDataType::string_datatype(),
922 false,
923 )]));
924 let records = RecordBatches::try_from_columns(
925 schema,
926 vec![Arc::new(StringVector::from(vec![value])) as _],
927 )
928 .context(error::CreateRecordBatchSnafu)?;
929 Ok(Some(Output::new_with_record_batches(records)))
930}
931
932pub fn show_variable(stmt: ShowVariables, query_ctx: QueryContextRef) -> Result<Output> {
933 let variable = stmt.variable.to_string().to_uppercase();
934 let value = match variable.as_str() {
935 "SYSTEM_TIME_ZONE" | "SYSTEM_TIMEZONE" => get_timezone(None).to_string(),
936 "TIME_ZONE" | "TIMEZONE" => query_ctx.timezone().to_string(),
937 "READ_PREFERENCE" => query_ctx.read_preference().to_string(),
938 "DATESTYLE" => {
939 let (style, order) = *query_ctx.configuration_parameter().pg_datetime_style();
940 format!("{}, {}", style, order)
941 }
942 "INTERVALSTYLE" => {
943 let style = *query_ctx
944 .configuration_parameter()
945 .pg_intervalstyle_format();
946 style.to_string()
947 }
948 "MAX_EXECUTION_TIME"
949 if query_ctx.channel() == Channel::Mysql => {
950 query_ctx.query_timeout_as_millis().to_string()
951 }
952 "STATEMENT_TIMEOUT"
953 if query_ctx.channel() == Channel::Postgres => {
955 let mut timeout = query_ctx.query_timeout_as_millis().to_string();
956 timeout.push_str("ms");
957 timeout
958 }
959 _ => return UnsupportedVariableSnafu { name: variable }.fail(),
960 };
961 let schema = Arc::new(Schema::new(vec![ColumnSchema::new(
962 variable,
963 ConcreteDataType::string_datatype(),
964 false,
965 )]));
966 let records = RecordBatches::try_from_columns(
967 schema,
968 vec![Arc::new(StringVector::from(vec![value])) as _],
969 )
970 .context(error::CreateRecordBatchSnafu)?;
971 Ok(Output::new_with_record_batches(records))
972}
973
974pub async fn show_status(_query_ctx: QueryContextRef) -> Result<Output> {
975 let schema = Arc::new(Schema::new(vec![
976 ColumnSchema::new("Variable_name", ConcreteDataType::string_datatype(), false),
977 ColumnSchema::new("Value", ConcreteDataType::string_datatype(), true),
978 ]));
979 let records = RecordBatches::try_from_columns(
980 schema,
981 vec![
982 Arc::new(StringVector::from(Vec::<&str>::new())) as _,
983 Arc::new(StringVector::from(Vec::<&str>::new())) as _,
984 ],
985 )
986 .context(error::CreateRecordBatchSnafu)?;
987 Ok(Output::new_with_record_batches(records))
988}
989
990pub async fn show_search_path(_query_ctx: QueryContextRef) -> Result<Output> {
991 let schema = Arc::new(Schema::new(vec![ColumnSchema::new(
992 "search_path",
993 ConcreteDataType::string_datatype(),
994 false,
995 )]));
996 let records = RecordBatches::try_from_columns(
997 schema,
998 vec![Arc::new(StringVector::from(vec![_query_ctx.current_schema()])) as _],
999 )
1000 .context(error::CreateRecordBatchSnafu)?;
1001 Ok(Output::new_with_record_batches(records))
1002}
1003
1004pub fn show_create_database(database_name: &str, options: OptionMap) -> Result<Output> {
1005 let stmt = CreateDatabase {
1006 name: ObjectName::from(vec![Ident::new(database_name)]),
1007 if_not_exists: true,
1008 options,
1009 };
1010 let sql = format!("{stmt}");
1011 let columns = vec![
1012 Arc::new(StringVector::from(vec![database_name.to_string()])) as _,
1013 Arc::new(StringVector::from(vec![sql])) as _,
1014 ];
1015 let records =
1016 RecordBatches::try_from_columns(SHOW_CREATE_DATABASE_OUTPUT_SCHEMA.clone(), columns)
1017 .context(error::CreateRecordBatchSnafu)?;
1018 Ok(Output::new_with_record_batches(records))
1019}
1020
1021pub fn show_create_table(
1022 table_info: TableInfoRef,
1023 schema_options: Option<SchemaOptions>,
1024 partitions: Option<Partitions>,
1025 query_ctx: QueryContextRef,
1026) -> Result<Output> {
1027 let table_name = table_info.name.clone();
1028
1029 let quote_style = query_ctx.quote_style();
1030
1031 let mut stmt = create_table_stmt(&table_info, schema_options, quote_style)?;
1032 stmt.partitions = partitions.map(|mut p| {
1033 p.set_quote(quote_style);
1034 p
1035 });
1036 let sql = format!("{}", stmt);
1037 let columns = vec![
1038 Arc::new(StringVector::from(vec![table_name])) as _,
1039 Arc::new(StringVector::from(vec![sql])) as _,
1040 ];
1041 let records = RecordBatches::try_from_columns(SHOW_CREATE_TABLE_OUTPUT_SCHEMA.clone(), columns)
1042 .context(error::CreateRecordBatchSnafu)?;
1043
1044 Ok(Output::new_with_record_batches(records))
1045}
1046
1047pub fn show_create_foreign_table_for_pg(
1048 table: TableRef,
1049 _query_ctx: QueryContextRef,
1050) -> Result<Output> {
1051 let table_info = table.table_info();
1052
1053 let table_meta = &table_info.meta;
1054 let table_name = &table_info.name;
1055 let schema = &table_info.meta.schema;
1056 let is_metric_engine = is_metric_engine(&table_meta.engine);
1057
1058 let columns = schema
1059 .column_schemas()
1060 .iter()
1061 .filter_map(|c| {
1062 if is_metric_engine && is_metric_engine_internal_column(&c.name) {
1063 None
1064 } else {
1065 Some(format!(
1066 "\"{}\" {}",
1067 c.name,
1068 c.data_type.postgres_datatype_name()
1069 ))
1070 }
1071 })
1072 .join(",\n ");
1073
1074 let sql = format!(
1075 r#"CREATE FOREIGN TABLE ft_{} (
1076 {}
1077)
1078SERVER greptimedb
1079OPTIONS (table_name '{}')"#,
1080 table_name, columns, table_name
1081 );
1082
1083 let columns = vec![
1084 Arc::new(StringVector::from(vec![table_name.clone()])) as _,
1085 Arc::new(StringVector::from(vec![sql])) as _,
1086 ];
1087 let records = RecordBatches::try_from_columns(SHOW_CREATE_TABLE_OUTPUT_SCHEMA.clone(), columns)
1088 .context(error::CreateRecordBatchSnafu)?;
1089
1090 Ok(Output::new_with_record_batches(records))
1091}
1092
1093pub fn show_create_view(
1094 view_name: ObjectName,
1095 definition: &str,
1096 query_ctx: QueryContextRef,
1097) -> Result<Output> {
1098 let mut parser_ctx =
1099 ParserContext::new(query_ctx.sql_dialect(), definition).context(error::SqlSnafu)?;
1100
1101 let Statement::CreateView(create_view) =
1102 parser_ctx.parse_statement().context(error::SqlSnafu)?
1103 else {
1104 unreachable!();
1106 };
1107
1108 let stmt = CreateView {
1109 name: view_name.clone(),
1110 columns: create_view.columns,
1111 query: create_view.query,
1112 or_replace: create_view.or_replace,
1113 if_not_exists: create_view.if_not_exists,
1114 };
1115
1116 let sql = format!("{}", stmt);
1117 let columns = vec![
1118 Arc::new(StringVector::from(vec![view_name.to_string()])) as _,
1119 Arc::new(StringVector::from(vec![sql])) as _,
1120 ];
1121 let records = RecordBatches::try_from_columns(SHOW_CREATE_VIEW_OUTPUT_SCHEMA.clone(), columns)
1122 .context(error::CreateRecordBatchSnafu)?;
1123
1124 Ok(Output::new_with_record_batches(records))
1125}
1126
1127pub async fn show_views(
1129 stmt: ShowViews,
1130 query_engine: &QueryEngineRef,
1131 catalog_manager: &CatalogManagerRef,
1132 query_ctx: QueryContextRef,
1133) -> Result<Output> {
1134 let dataframe = show_views_dataframe(&stmt, query_engine, catalog_manager, query_ctx).await?;
1135 dataframe_to_output(dataframe).await
1136}
1137
1138pub async fn show_views_dataframe(
1140 stmt: &ShowViews,
1141 query_engine: &QueryEngineRef,
1142 catalog_manager: &CatalogManagerRef,
1143 query_ctx: QueryContextRef,
1144) -> Result<DataFrame> {
1145 let schema_name = if let Some(database) = &stmt.database {
1146 database.clone()
1147 } else {
1148 query_ctx.current_schema()
1149 };
1150
1151 let projects = vec![(tables::TABLE_NAME, VIEWS_COLUMN)];
1152 let filters = vec![
1153 col(tables::TABLE_SCHEMA).eq(lit(schema_name.clone())),
1154 col(tables::TABLE_CATALOG).eq(lit(query_ctx.current_catalog())),
1155 ];
1156 let like_field = Some(tables::TABLE_NAME);
1157 let sort = vec![col(tables::TABLE_NAME).sort(true, true)];
1158
1159 query_from_information_schema_dataframe(
1160 query_engine,
1161 catalog_manager,
1162 query_ctx,
1163 VIEWS,
1164 vec![],
1165 projects,
1166 filters,
1167 like_field,
1168 sort,
1169 &stmt.kind,
1170 )
1171 .await
1172}
1173
1174pub async fn show_flows(
1176 stmt: ShowFlows,
1177 query_engine: &QueryEngineRef,
1178 catalog_manager: &CatalogManagerRef,
1179 query_ctx: QueryContextRef,
1180) -> Result<Output> {
1181 let dataframe = show_flows_dataframe(&stmt, query_engine, catalog_manager, query_ctx).await?;
1182 dataframe_to_output(dataframe).await
1183}
1184
1185pub async fn show_flows_dataframe(
1187 stmt: &ShowFlows,
1188 query_engine: &QueryEngineRef,
1189 catalog_manager: &CatalogManagerRef,
1190 query_ctx: QueryContextRef,
1191) -> Result<DataFrame> {
1192 let projects = vec![(flows::FLOW_NAME, FLOWS_COLUMN)];
1193 let filters = vec![col(flows::TABLE_CATALOG).eq(lit(query_ctx.current_catalog()))];
1194 let like_field = Some(flows::FLOW_NAME);
1195 let sort = vec![col(flows::FLOW_NAME).sort(true, true)];
1196
1197 query_from_information_schema_dataframe(
1198 query_engine,
1199 catalog_manager,
1200 query_ctx,
1201 FLOWS,
1202 vec![],
1203 projects,
1204 filters,
1205 like_field,
1206 sort,
1207 &stmt.kind,
1208 )
1209 .await
1210}
1211
1212pub async fn show_flow_status(
1214 stmt: ShowFlowStatus,
1215 query_engine: &QueryEngineRef,
1216 catalog_manager: &CatalogManagerRef,
1217 query_ctx: QueryContextRef,
1218) -> Result<Output> {
1219 let projects = vec![
1220 (flow_statistics::FLOW_ID, flow_statistics::FLOW_ID),
1221 (flow_statistics::FLOW_NAME, flow_statistics::FLOW_NAME),
1222 (flow_statistics::START_TIME, flow_statistics::START_TIME),
1223 (
1224 flow_statistics::LAST_EXECUTION_TIME,
1225 flow_statistics::LAST_EXECUTION_TIME,
1226 ),
1227 (
1228 flow_statistics::UPTIME_SECONDS,
1229 flow_statistics::UPTIME_SECONDS,
1230 ),
1231 (flow_statistics::STATE_SIZE, flow_statistics::STATE_SIZE),
1232 ];
1233 let like_field = Some(flow_statistics::FLOW_NAME);
1234 let sort = vec![col(flow_statistics::FLOW_NAME).sort(true, true)];
1235
1236 query_from_information_schema_table(
1237 query_engine,
1238 catalog_manager,
1239 query_ctx,
1240 FLOW_STATISTICS,
1241 vec![],
1242 projects,
1243 vec![],
1244 like_field,
1245 sort,
1246 stmt.kind,
1247 )
1248 .await
1249}
1250
1251#[cfg(feature = "enterprise")]
1252pub async fn show_triggers(
1253 stmt: sql::statements::show::trigger::ShowTriggers,
1254 query_engine: &QueryEngineRef,
1255 catalog_manager: &CatalogManagerRef,
1256 query_ctx: QueryContextRef,
1257) -> Result<Output> {
1258 const TRIGGER_NAME: &str = "trigger_name";
1259 const TRIGGERS_COLUMN: &str = "Triggers";
1260
1261 let projects = vec![(TRIGGER_NAME, TRIGGERS_COLUMN)];
1262 let like_field = Some(TRIGGER_NAME);
1263 let sort = vec![col(TRIGGER_NAME).sort(true, true)];
1264
1265 query_from_information_schema_table(
1266 query_engine,
1267 catalog_manager,
1268 query_ctx,
1269 catalog::information_schema::TRIGGERS,
1270 vec![],
1271 projects,
1272 vec![],
1273 like_field,
1274 sort,
1275 stmt.kind,
1276 )
1277 .await
1278}
1279
1280pub fn show_create_flow(
1281 flow_name: ObjectName,
1282 flow_val: FlowInfoValue,
1283 query_ctx: QueryContextRef,
1284) -> Result<Output> {
1285 let mut parser_ctx =
1286 ParserContext::new(query_ctx.sql_dialect(), flow_val.raw_sql()).context(error::SqlSnafu)?;
1287
1288 let query = parser_ctx.parse_statement().context(error::SqlSnafu)?;
1289
1290 let raw_query = match &query {
1292 Statement::Tql(_) => flow_val.raw_sql().clone(),
1293 _ => query.to_string(),
1294 };
1295
1296 let query = Box::new(SqlOrTql::try_from_statement(query, &raw_query).context(error::SqlSnafu)?);
1297
1298 let comment = if flow_val.comment().is_empty() {
1299 None
1300 } else {
1301 Some(flow_val.comment().clone())
1302 };
1303
1304 let stmt = CreateFlow {
1305 flow_name,
1306 sink_table_name: ObjectName::from(vec![
1307 Ident::new(&flow_val.sink_table_name().schema_name),
1308 Ident::new(&flow_val.sink_table_name().table_name),
1309 ]),
1310 or_replace: false,
1313 if_not_exists: true,
1314 expire_after: flow_val.expire_after(),
1315 eval_interval: flow_val.eval_interval(),
1316 eval_offset: effective_eval_schedule_from_flow_info(&flow_val)
1317 .map_err(BoxedError::new)
1318 .context(error::QueryExecutionSnafu)?
1319 .map(|schedule| schedule.anchor_secs)
1320 .filter(|anchor_secs| *anchor_secs != 0),
1321 comment,
1322 flow_options: OptionMap::from_filtered_string_map(
1323 flow_val.options(),
1324 &[FlowType::FLOW_TYPE_KEY],
1325 ),
1326 query,
1327 };
1328
1329 let sql = format!("{}", stmt);
1330 let columns = vec![
1331 Arc::new(StringVector::from(vec![flow_val.flow_name().clone()])) as _,
1332 Arc::new(StringVector::from(vec![sql])) as _,
1333 ];
1334 let records = RecordBatches::try_from_columns(SHOW_CREATE_FLOW_OUTPUT_SCHEMA.clone(), columns)
1335 .context(error::CreateRecordBatchSnafu)?;
1336
1337 Ok(Output::new_with_record_batches(records))
1338}
1339
1340pub fn describe_table(table: TableRef) -> Result<Output> {
1341 let table_info = table.table_info();
1342 let columns_schemas = table_info.meta.schema.column_schemas();
1343 let columns = vec![
1344 describe_column_names(columns_schemas),
1345 describe_column_types(columns_schemas),
1346 describe_column_keys(columns_schemas, &table_info.meta.primary_key_indices),
1347 describe_column_nullables(columns_schemas),
1348 describe_column_defaults(columns_schemas),
1349 describe_column_semantic_types(columns_schemas, &table_info.meta.primary_key_indices),
1350 ];
1351 let records = RecordBatches::try_from_columns(DESCRIBE_TABLE_OUTPUT_SCHEMA.clone(), columns)
1352 .context(error::CreateRecordBatchSnafu)?;
1353 Ok(Output::new_with_record_batches(records))
1354}
1355
1356fn describe_column_names(columns_schemas: &[ColumnSchema]) -> VectorRef {
1357 Arc::new(StringVector::from_iterator(
1358 columns_schemas.iter().map(|cs| cs.name.as_str()),
1359 ))
1360}
1361
1362fn describe_column_types(columns_schemas: &[ColumnSchema]) -> VectorRef {
1363 Arc::new(StringVector::from(
1364 columns_schemas
1365 .iter()
1366 .map(|cs| describe_column_type_name(&cs.data_type))
1367 .collect::<Vec<_>>(),
1368 ))
1369}
1370
1371fn describe_column_type_name(data_type: &ConcreteDataType) -> String {
1372 match data_type {
1373 ConcreteDataType::Json(json_type) if json_type.is_json2() => "Json2".to_string(),
1374 data_type => data_type.name(),
1375 }
1376}
1377
1378fn describe_column_keys(
1379 columns_schemas: &[ColumnSchema],
1380 primary_key_indices: &[usize],
1381) -> VectorRef {
1382 Arc::new(StringVector::from_iterator(
1383 columns_schemas.iter().enumerate().map(|(i, cs)| {
1384 if cs.is_time_index() || primary_key_indices.contains(&i) {
1385 PRI_KEY
1386 } else {
1387 ""
1388 }
1389 }),
1390 ))
1391}
1392
1393fn describe_column_nullables(columns_schemas: &[ColumnSchema]) -> VectorRef {
1394 Arc::new(StringVector::from_iterator(columns_schemas.iter().map(
1395 |cs| {
1396 if cs.is_nullable() { YES_STR } else { NO_STR }
1397 },
1398 )))
1399}
1400
1401fn describe_column_defaults(columns_schemas: &[ColumnSchema]) -> VectorRef {
1402 Arc::new(StringVector::from(
1403 columns_schemas
1404 .iter()
1405 .map(|cs| {
1406 cs.default_constraint()
1407 .map_or(String::from(""), |dc| dc.to_string())
1408 })
1409 .collect::<Vec<String>>(),
1410 ))
1411}
1412
1413fn describe_column_semantic_types(
1414 columns_schemas: &[ColumnSchema],
1415 primary_key_indices: &[usize],
1416) -> VectorRef {
1417 Arc::new(StringVector::from_iterator(
1418 columns_schemas.iter().enumerate().map(|(i, cs)| {
1419 if primary_key_indices.contains(&i) {
1420 SEMANTIC_TYPE_PRIMARY_KEY
1421 } else if cs.is_time_index() {
1422 SEMANTIC_TYPE_TIME_INDEX
1423 } else {
1424 SEMANTIC_TYPE_FIELD
1425 }
1426 }),
1427 ))
1428}
1429
1430pub async fn prepare_file_table_files(
1432 options: &HashMap<String, String>,
1433 local_file_access: &LocalFileAccess,
1434) -> Result<(ObjectStore, Vec<String>)> {
1435 let url = options
1436 .get(FILE_TABLE_LOCATION_KEY)
1437 .context(error::MissingRequiredFieldSnafu {
1438 name: FILE_TABLE_LOCATION_KEY,
1439 })?;
1440
1441 let regex = options
1442 .get(FILE_TABLE_PATTERN_KEY)
1443 .map(|x| Regex::new(x))
1444 .transpose()
1445 .context(error::BuildRegexSnafu)?;
1446 let backend = build_backend_with_path(url, options, local_file_access)
1447 .await
1448 .context(error::BuildBackendSnafu)?;
1449 let source = if let Some(filename) = backend.object_path {
1450 Source::Filename(filename)
1451 } else {
1452 Source::Dir
1453 };
1454 let lister = Lister::new(backend.object_store.clone(), source, url.clone(), regex);
1455 let files = lister
1460 .list()
1461 .await
1462 .context(error::ListObjectsSnafu)?
1463 .into_iter()
1464 .filter_map(|entry| {
1465 if entry.path().ends_with('/') {
1466 None
1467 } else {
1468 Some(entry.path().to_string())
1469 }
1470 })
1471 .collect::<Vec<_>>();
1472 Ok((backend.object_store, files))
1473}
1474
1475pub async fn infer_file_table_schema(
1476 object_store: &ObjectStore,
1477 files: &[String],
1478 options: &HashMap<String, String>,
1479) -> Result<Schema> {
1480 let format = parse_file_table_format(options)?;
1481 let merged = infer_schemas(object_store, files, format.as_ref())
1482 .await
1483 .context(error::InferSchemaSnafu)?;
1484 Schema::try_from(merged).context(error::ConvertSchemaSnafu)
1485}
1486
1487pub fn file_column_schemas_to_table(
1497 file_column_schemas: &[ColumnSchema],
1498) -> (Vec<ColumnSchema>, String) {
1499 let mut column_schemas = file_column_schemas.to_owned();
1500 if let Some(time_index_column) = column_schemas.iter().find(|c| c.is_time_index()) {
1501 let time_index = time_index_column.name.clone();
1502 return (column_schemas, time_index);
1503 }
1504
1505 let timestamp_type = ConcreteDataType::timestamp_millisecond_datatype();
1506 let default_zero = Value::Timestamp(Timestamp::new_millisecond(0));
1507 let timestamp_column_schema = ColumnSchema::new(greptime_timestamp(), timestamp_type, false)
1508 .with_time_index(true)
1509 .with_default_constraint(Some(ColumnDefaultConstraint::Value(default_zero)))
1510 .unwrap();
1511
1512 if let Some(column_schema) = column_schemas
1513 .iter_mut()
1514 .find(|column_schema| column_schema.name == greptime_timestamp())
1515 {
1516 *column_schema = timestamp_column_schema;
1518 } else {
1519 column_schemas.push(timestamp_column_schema);
1520 }
1521
1522 (column_schemas, greptime_timestamp().to_string())
1523}
1524
1525pub fn check_file_to_table_schema_compatibility(
1534 file_column_schemas: &[ColumnSchema],
1535 table_column_schemas: &[ColumnSchema],
1536) -> Result<()> {
1537 let file_schemas_map = file_column_schemas
1538 .iter()
1539 .map(|s| (s.name.clone(), s))
1540 .collect::<HashMap<_, _>>();
1541
1542 for table_column in table_column_schemas {
1543 if let Some(file_column) = file_schemas_map.get(&table_column.name) {
1544 ensure!(
1546 file_column
1547 .data_type
1548 .can_arrow_type_cast_to(&table_column.data_type),
1549 error::ColumnSchemaIncompatibleSnafu {
1550 column: table_column.name.clone(),
1551 file_type: file_column.data_type.clone(),
1552 table_type: table_column.data_type.clone(),
1553 }
1554 );
1555 } else {
1556 ensure!(
1557 table_column.is_nullable() || table_column.default_constraint().is_some(),
1558 error::ColumnSchemaNoDefaultSnafu {
1559 column: table_column.name.clone(),
1560 }
1561 );
1562 }
1563 }
1564
1565 Ok(())
1566}
1567
1568fn parse_file_table_format(options: &HashMap<String, String>) -> Result<Box<dyn FileFormat>> {
1569 Ok(
1570 match Format::try_from(options).context(error::ParseFileFormatSnafu)? {
1571 Format::Csv(format) => Box::new(format),
1572 Format::Json(format) => Box::new(format),
1573 Format::Parquet(format) => Box::new(format),
1574 Format::Orc(format) => Box::new(format),
1575 },
1576 )
1577}
1578
1579pub async fn show_processlist(
1580 stmt: ShowProcessList,
1581 query_engine: &QueryEngineRef,
1582 catalog_manager: &CatalogManagerRef,
1583 query_ctx: QueryContextRef,
1584) -> Result<Output> {
1585 let dataframe =
1586 show_processlist_dataframe(&stmt, query_engine, catalog_manager, query_ctx).await?;
1587 dataframe_to_output(dataframe).await
1588}
1589
1590pub async fn show_processlist_dataframe(
1592 stmt: &ShowProcessList,
1593 query_engine: &QueryEngineRef,
1594 catalog_manager: &CatalogManagerRef,
1595 query_ctx: QueryContextRef,
1596) -> Result<DataFrame> {
1597 let projects = if stmt.full {
1598 vec![
1599 (process_list::ID, "Id"),
1600 (process_list::CATALOG, "Catalog"),
1601 (process_list::SCHEMAS, "Schema"),
1602 (process_list::CLIENT, "Client"),
1603 (process_list::FRONTEND, "Frontend"),
1604 (process_list::START_TIMESTAMP, "Start Time"),
1605 (process_list::ELAPSED_TIME, "Elapsed Time"),
1606 (process_list::QUERY, "Query"),
1607 ]
1608 } else {
1609 vec![
1610 (process_list::ID, "Id"),
1611 (process_list::CATALOG, "Catalog"),
1612 (process_list::QUERY, "Query"),
1613 (process_list::ELAPSED_TIME, "Elapsed Time"),
1614 ]
1615 };
1616
1617 let filters = if query_ctx.current_user().is_admin() {
1618 vec![]
1619 } else {
1620 vec![col(process_list::CATALOG).eq(lit(query_ctx.current_catalog()))]
1621 };
1622 let like_field = None;
1623 let sort = vec![col("id").sort(true, true)];
1624 query_from_information_schema_dataframe(
1625 query_engine,
1626 catalog_manager,
1627 query_ctx.clone(),
1628 "process_list",
1629 vec![],
1630 projects,
1631 filters,
1632 like_field,
1633 sort,
1634 &ShowKind::All,
1635 )
1636 .await
1637}
1638
1639#[cfg(test)]
1640mod test {
1641 use std::sync::Arc;
1642
1643 use common_query::{Output, OutputData};
1644 use common_recordbatch::{RecordBatch, RecordBatches};
1645 use common_time::Timezone;
1646 use common_time::timestamp::TimeUnit;
1647 use datatypes::prelude::ConcreteDataType;
1648 use datatypes::schema::{ColumnDefaultConstraint, ColumnSchema, Schema, SchemaRef};
1649 use datatypes::types::json_type::JsonNativeType;
1650 use datatypes::vectors::{StringVector, TimestampMillisecondVector, UInt32Vector, VectorRef};
1651 use session::context::QueryContextBuilder;
1652 use snafu::ResultExt;
1653 use sql::ast::{Ident, ObjectName};
1654 use sql::statements::show::ShowVariables;
1655 use table::TableRef;
1656 use table::test_util::MemTable;
1657
1658 use super::{describe_column_type_name, show_variable};
1659 use crate::error;
1660 use crate::error::Result;
1661 use crate::sql::{
1662 DESCRIBE_TABLE_OUTPUT_SCHEMA, NO_STR, SEMANTIC_TYPE_FIELD, SEMANTIC_TYPE_TIME_INDEX,
1663 YES_STR, describe_table,
1664 };
1665
1666 #[test]
1667 fn test_describe_table_multiple_columns() -> Result<()> {
1668 let table_name = "test_table";
1669 let schema = vec![
1670 ColumnSchema::new("t1", ConcreteDataType::uint32_datatype(), true),
1671 ColumnSchema::new(
1672 "t2",
1673 ConcreteDataType::timestamp_datatype(TimeUnit::Millisecond),
1674 false,
1675 )
1676 .with_default_constraint(Some(ColumnDefaultConstraint::Function(String::from(
1677 "current_timestamp()",
1678 ))))
1679 .unwrap()
1680 .with_time_index(true),
1681 ];
1682 let data = vec![
1683 Arc::new(UInt32Vector::from_slice([0])) as _,
1684 Arc::new(TimestampMillisecondVector::from_slice([0])) as _,
1685 ];
1686 let expected_columns = vec![
1687 Arc::new(StringVector::from(vec!["t1", "t2"])) as _,
1688 Arc::new(StringVector::from(vec!["UInt32", "TimestampMillisecond"])) as _,
1689 Arc::new(StringVector::from(vec!["", "PRI"])) as _,
1690 Arc::new(StringVector::from(vec![YES_STR, NO_STR])) as _,
1691 Arc::new(StringVector::from(vec!["", "current_timestamp()"])) as _,
1692 Arc::new(StringVector::from(vec![
1693 SEMANTIC_TYPE_FIELD,
1694 SEMANTIC_TYPE_TIME_INDEX,
1695 ])) as _,
1696 ];
1697
1698 describe_table_test_by_schema(table_name, schema, data, expected_columns)
1699 }
1700
1701 #[test]
1702 fn test_describe_column_type_name_json2() {
1703 assert_eq!(
1704 describe_column_type_name(&ConcreteDataType::json2(JsonNativeType::Null)),
1705 "Json2"
1706 );
1707 assert_eq!(
1708 describe_column_type_name(&ConcreteDataType::uint32_datatype()),
1709 "UInt32"
1710 );
1711 }
1712
1713 fn describe_table_test_by_schema(
1714 table_name: &str,
1715 schema: Vec<ColumnSchema>,
1716 data: Vec<VectorRef>,
1717 expected_columns: Vec<VectorRef>,
1718 ) -> Result<()> {
1719 let table_schema = SchemaRef::new(Schema::new(schema));
1720 let table = prepare_describe_table(table_name, table_schema, data);
1721
1722 let expected =
1723 RecordBatches::try_from_columns(DESCRIBE_TABLE_OUTPUT_SCHEMA.clone(), expected_columns)
1724 .context(error::CreateRecordBatchSnafu)?;
1725
1726 if let OutputData::RecordBatches(res) = describe_table(table)?.data {
1727 assert_eq!(res.take(), expected.take());
1728 } else {
1729 panic!("describe table must return record batch");
1730 }
1731
1732 Ok(())
1733 }
1734
1735 fn prepare_describe_table(
1736 table_name: &str,
1737 table_schema: SchemaRef,
1738 data: Vec<VectorRef>,
1739 ) -> TableRef {
1740 let record_batch = RecordBatch::new(table_schema, data).unwrap();
1741 MemTable::table(table_name, record_batch)
1742 }
1743
1744 #[test]
1745 fn test_show_variable() {
1746 assert_eq!(
1747 exec_show_variable("SYSTEM_TIME_ZONE", "Asia/Shanghai").unwrap(),
1748 "UTC"
1749 );
1750 assert_eq!(
1751 exec_show_variable("SYSTEM_TIMEZONE", "Asia/Shanghai").unwrap(),
1752 "UTC"
1753 );
1754 assert_eq!(
1755 exec_show_variable("TIME_ZONE", "Asia/Shanghai").unwrap(),
1756 "Asia/Shanghai"
1757 );
1758 assert_eq!(
1759 exec_show_variable("TIMEZONE", "Asia/Shanghai").unwrap(),
1760 "Asia/Shanghai"
1761 );
1762 assert!(exec_show_variable("TIME ZONE", "Asia/Shanghai").is_err());
1763 assert!(exec_show_variable("SYSTEM TIME ZONE", "Asia/Shanghai").is_err());
1764 }
1765
1766 fn exec_show_variable(variable: &str, tz: &str) -> Result<String> {
1767 let stmt = ShowVariables {
1768 variable: ObjectName::from(vec![Ident::new(variable)]),
1769 };
1770 let ctx = Arc::new(
1771 QueryContextBuilder::default()
1772 .timezone(Timezone::from_tz_string(tz).unwrap())
1773 .build(),
1774 );
1775 match show_variable(stmt, ctx) {
1776 Ok(Output {
1777 data: OutputData::RecordBatches(record),
1778 ..
1779 }) => {
1780 let record = record.take().first().cloned().unwrap();
1781 Ok(record.iter_column_as_string(0).next().unwrap().unwrap())
1782 }
1783 Ok(_) => unreachable!(),
1784 Err(e) => Err(e),
1785 }
1786 }
1787}