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