1use std::sync::Arc;
16
17use common_error::ext::BoxedError;
18use common_meta::key::schema_name::SchemaNameKey;
19use common_query::Output;
20use common_telemetry::tracing;
21use partition::manager::PartitionInfoWithVersion;
22use session::context::QueryContextRef;
23use session::table_name::table_idents_to_full_name;
24use snafu::{OptionExt, ResultExt};
25use sql::ast::ObjectNamePartExt;
26use sql::statements::OptionMap;
27use sql::statements::create::Partitions;
28use sql::statements::show::{
29 ShowColumns, ShowCreateFlow, ShowCreateView, ShowDatabases, ShowFlowStatus, ShowFlows,
30 ShowIndex, ShowKind, ShowProcessList, ShowRegion, ShowTableStatus, ShowTables, ShowVariables,
31 ShowViews,
32};
33use table::TableRef;
34use table::metadata::{TableInfo, TableType};
35use table::table_name::TableName;
36
37use crate::error::{
38 self, CatalogSnafu, ExecLogicalPlanSnafu, ExecuteStatementSnafu, ExternalSnafu,
39 FindViewInfoSnafu, InvalidSqlSnafu, Result, TableMetadataManagerSnafu, ViewInfoNotFoundSnafu,
40 ViewNotFoundSnafu,
41};
42use crate::statement::StatementExecutor;
43
44impl StatementExecutor {
45 #[tracing::instrument(skip_all)]
46 pub(super) async fn show_databases(
47 &self,
48 stmt: ShowDatabases,
49 query_ctx: QueryContextRef,
50 ) -> Result<Output> {
51 query::sql::show_databases(stmt, &self.query_engine, &self.catalog_manager, query_ctx)
52 .await
53 .context(ExecuteStatementSnafu)
54 }
55
56 #[tracing::instrument(skip_all)]
57 pub(super) async fn show_tables(
58 &self,
59 stmt: ShowTables,
60 query_ctx: QueryContextRef,
61 ) -> Result<Output> {
62 query::sql::show_tables(stmt, &self.query_engine, &self.catalog_manager, query_ctx)
63 .await
64 .context(ExecuteStatementSnafu)
65 }
66
67 #[tracing::instrument(skip_all)]
68 pub(super) async fn show_table_status(
69 &self,
70 stmt: ShowTableStatus,
71 query_ctx: QueryContextRef,
72 ) -> Result<Output> {
73 query::sql::show_table_status(stmt, &self.query_engine, &self.catalog_manager, query_ctx)
74 .await
75 .context(ExecuteStatementSnafu)
76 }
77
78 #[tracing::instrument(skip_all)]
79 pub(super) async fn show_columns(
80 &self,
81 stmt: ShowColumns,
82 query_ctx: QueryContextRef,
83 ) -> Result<Output> {
84 query::sql::show_columns(stmt, &self.query_engine, &self.catalog_manager, query_ctx)
85 .await
86 .context(ExecuteStatementSnafu)
87 }
88
89 #[tracing::instrument(skip_all)]
90 pub(super) async fn show_index(
91 &self,
92 stmt: ShowIndex,
93 query_ctx: QueryContextRef,
94 ) -> Result<Output> {
95 query::sql::show_index(stmt, &self.query_engine, &self.catalog_manager, query_ctx)
96 .await
97 .context(ExecuteStatementSnafu)
98 }
99
100 pub(super) async fn show_region(
101 &self,
102 stmt: ShowRegion,
103 query_ctx: QueryContextRef,
104 ) -> Result<Output> {
105 query::sql::show_region(stmt, &self.query_engine, &self.catalog_manager, query_ctx)
106 .await
107 .context(ExecuteStatementSnafu)
108 }
109
110 #[tracing::instrument(skip_all)]
111 pub async fn show_create_database(
112 &self,
113 database_name: &str,
114 opts: OptionMap,
115 ) -> Result<Output> {
116 query::sql::show_create_database(database_name, opts).context(ExecuteStatementSnafu)
117 }
118
119 #[tracing::instrument(skip_all)]
120 pub async fn show_create_table(
121 &self,
122 table_name: TableName,
123 table: TableRef,
124 query_ctx: QueryContextRef,
125 ) -> Result<Output> {
126 let mut table_info = table.table_info();
127 let partition_column_names: Vec<_> =
128 table_info.meta.partition_column_names().cloned().collect();
129
130 if let Some(latest) = self
131 .table_metadata_manager
132 .table_info_manager()
133 .get(table_info.table_id())
134 .await
135 .context(TableMetadataManagerSnafu)?
136 {
137 let mut latest_info = latest.into_inner().table_info;
138
139 if !partition_column_names.is_empty() {
140 latest_info.meta.partition_key_indices = partition_column_names
141 .iter()
142 .filter_map(|name| latest_info.meta.schema.column_index_by_name(name.as_str()))
143 .collect();
144 }
145
146 table_info = Arc::new(latest_info);
147 }
148
149 if table_info.table_type != TableType::Base {
150 return error::ShowCreateTableBaseOnlySnafu {
151 table_name: table_name.to_string(),
152 table_type: table_info.table_type,
153 }
154 .fail();
155 }
156
157 let schema_options = self
158 .table_metadata_manager
159 .schema_manager()
160 .get(SchemaNameKey {
161 catalog: &table_name.catalog_name,
162 schema: &table_name.schema_name,
163 })
164 .await
165 .context(TableMetadataManagerSnafu)?
166 .map(|v| v.into_inner());
167
168 let partition_info = self
169 .partition_manager
170 .find_physical_partition_info(table_info.table_id())
171 .await
172 .context(error::FindTablePartitionRuleSnafu {
173 table_name: &table_name.table_name,
174 })?;
175
176 let partitions = create_partitions_stmt(&table_info, &partition_info.partitions)?;
177
178 query::sql::show_create_table(table_info, schema_options, partitions, query_ctx)
179 .context(ExecuteStatementSnafu)
180 }
181
182 #[tracing::instrument(skip_all)]
183 pub async fn show_create_table_for_pg(
184 &self,
185 table_name: TableName,
186 table: TableRef,
187 query_ctx: QueryContextRef,
188 ) -> Result<Output> {
189 let table_info = table.table_info();
190 if table_info.table_type != TableType::Base {
191 return error::ShowCreateTableBaseOnlySnafu {
192 table_name: table_name.to_string(),
193 table_type: table_info.table_type,
194 }
195 .fail();
196 }
197
198 query::sql::show_create_foreign_table_for_pg(table, query_ctx)
199 .context(ExecuteStatementSnafu)
200 }
201
202 #[tracing::instrument(skip_all)]
203 pub async fn show_create_view(
204 &self,
205 show: ShowCreateView,
206 query_ctx: QueryContextRef,
207 ) -> Result<Output> {
208 let (catalog, schema, view) = table_idents_to_full_name(&show.view_name, &query_ctx)
209 .map_err(BoxedError::new)
210 .context(ExternalSnafu)?;
211
212 let table_ref = self
213 .catalog_manager
214 .table(&catalog, &schema, &view, Some(&query_ctx))
215 .await
216 .context(CatalogSnafu)?
217 .context(ViewNotFoundSnafu { view_name: &view })?;
218
219 let view_id = table_ref.table_info().ident.table_id;
220
221 let view_info = self
222 .view_info_manager
223 .get(view_id)
224 .await
225 .context(FindViewInfoSnafu { view_name: &view })?
226 .context(ViewInfoNotFoundSnafu { view_name: &view })?;
227
228 query::sql::show_create_view(show.view_name, &view_info.definition, query_ctx)
229 .context(error::ExecuteStatementSnafu)
230 }
231
232 #[tracing::instrument(skip_all)]
233 pub(super) async fn show_views(
234 &self,
235 stmt: ShowViews,
236 query_ctx: QueryContextRef,
237 ) -> Result<Output> {
238 query::sql::show_views(stmt, &self.query_engine, &self.catalog_manager, query_ctx)
239 .await
240 .context(ExecuteStatementSnafu)
241 }
242
243 #[tracing::instrument(skip_all)]
244 pub(super) async fn show_flows(
245 &self,
246 stmt: ShowFlows,
247 query_ctx: QueryContextRef,
248 ) -> Result<Output> {
249 query::sql::show_flows(stmt, &self.query_engine, &self.catalog_manager, query_ctx)
250 .await
251 .context(ExecuteStatementSnafu)
252 }
253
254 #[tracing::instrument(skip_all)]
255 pub(super) async fn show_flow_status(
256 &self,
257 stmt: ShowFlowStatus,
258 query_ctx: QueryContextRef,
259 ) -> Result<Output> {
260 query::sql::show_flow_status(stmt, &self.query_engine, &self.catalog_manager, query_ctx)
261 .await
262 .context(ExecuteStatementSnafu)
263 }
264
265 #[cfg(feature = "enterprise")]
266 #[tracing::instrument(skip_all)]
267 pub(super) async fn show_triggers(
268 &self,
269 stmt: sql::statements::show::trigger::ShowTriggers,
270 query_ctx: QueryContextRef,
271 ) -> Result<Output> {
272 query::sql::show_triggers(stmt, &self.query_engine, &self.catalog_manager, query_ctx)
273 .await
274 .context(ExecuteStatementSnafu)
275 }
276
277 #[tracing::instrument(skip_all)]
278 pub async fn show_create_flow(
279 &self,
280 show: ShowCreateFlow,
281 query_ctx: QueryContextRef,
282 ) -> Result<Output> {
283 let obj_name = &show.flow_name;
284 let (catalog_name, flow_name) = match &obj_name.0[..] {
285 [flow] => (query_ctx.current_catalog().to_string(), flow.to_string_unquoted()),
286 [catalog, flow] => (catalog.to_string_unquoted(), flow.to_string_unquoted()),
287 _ => {
288 return InvalidSqlSnafu {
289 err_msg: format!(
290 "expect flow name to be <catalog>.<flow_name> or <flow_name>, actual: {obj_name}",
291 ),
292 }
293 .fail()
294 }
295 };
296
297 let flow_name_val = self
298 .flow_metadata_manager
299 .flow_name_manager()
300 .get(&catalog_name, &flow_name)
301 .await
302 .context(error::TableMetadataManagerSnafu)?
303 .context(error::FlowNotFoundSnafu {
304 flow_name: &flow_name,
305 })?;
306
307 let flow_val = self
308 .flow_metadata_manager
309 .flow_info_manager()
310 .get(flow_name_val.flow_id())
311 .await
312 .context(error::TableMetadataManagerSnafu)?
313 .context(error::FlowNotFoundSnafu {
314 flow_name: &flow_name,
315 })?;
316
317 query::sql::show_create_flow(obj_name.clone(), flow_val, query_ctx)
318 .context(error::ExecuteStatementSnafu)
319 }
320
321 #[cfg(feature = "enterprise")]
322 #[tracing::instrument(skip_all)]
323 pub async fn show_create_trigger(
324 &self,
325 show: sql::statements::show::trigger::ShowCreateTrigger,
326 query_ctx: QueryContextRef,
327 ) -> Result<Output> {
328 let Some(trigger_querier) = self.trigger_querier.as_ref() else {
329 return error::MissingTriggerQuerierSnafu.fail();
330 };
331
332 let obj_name = &show.trigger_name;
333 let (catalog_name, trigger_name) = match &obj_name.0[..] {
334 [trigger] => (query_ctx.current_catalog().to_string(), trigger.to_string_unquoted()),
335 [catalog, trigger] => (catalog.to_string_unquoted(), trigger.to_string_unquoted()),
336 _ => {
337 return InvalidSqlSnafu {
338 err_msg: format!(
339 "expect trigger name to be <catalog>.<trigger_name> or <trigger_name>, actual: {obj_name}",
340 ),
341 }
342 .fail()
343 }
344 };
345 trigger_querier
346 .show_create_trigger(&catalog_name, &trigger_name, &query_ctx)
347 .await
348 .context(error::TriggerQuerierSnafu)
349 }
350
351 #[tracing::instrument(skip_all)]
352 pub fn show_variable(&self, stmt: ShowVariables, query_ctx: QueryContextRef) -> Result<Output> {
353 query::sql::show_variable(stmt, query_ctx).context(error::ExecuteStatementSnafu)
354 }
355
356 #[tracing::instrument(skip_all)]
357 pub async fn show_collation(
358 &self,
359 kind: ShowKind,
360 query_ctx: QueryContextRef,
361 ) -> Result<Output> {
362 query::sql::show_collations(kind, &self.query_engine, &self.catalog_manager, query_ctx)
363 .await
364 .context(error::ExecuteStatementSnafu)
365 }
366
367 #[tracing::instrument(skip_all)]
368 pub async fn show_charset(&self, kind: ShowKind, query_ctx: QueryContextRef) -> Result<Output> {
369 query::sql::show_charsets(kind, &self.query_engine, &self.catalog_manager, query_ctx)
370 .await
371 .context(error::ExecuteStatementSnafu)
372 }
373
374 #[tracing::instrument(skip_all)]
375 pub async fn show_status(&self, query_ctx: QueryContextRef) -> Result<Output> {
376 query::sql::show_status(query_ctx)
377 .await
378 .context(error::ExecuteStatementSnafu)
379 }
380 pub async fn show_search_path(&self, query_ctx: QueryContextRef) -> Result<Output> {
381 query::sql::show_search_path(query_ctx)
382 .await
383 .context(error::ExecuteStatementSnafu)
384 }
385
386 pub async fn show_processlist(
387 &self,
388 stmt: ShowProcessList,
389 query_ctx: QueryContextRef,
390 ) -> Result<Output> {
391 query::sql::show_processlist(stmt, &self.query_engine, &self.catalog_manager, query_ctx)
392 .await
393 .context(ExecLogicalPlanSnafu)
394 }
395}
396
397pub(crate) fn create_partitions_stmt(
398 table_info: &TableInfo,
399 partitions: &[PartitionInfoWithVersion],
400) -> Result<Option<Partitions>> {
401 if partitions.is_empty() {
402 return Ok(None);
403 }
404
405 let column_list = table_info
406 .meta
407 .partition_column_names()
408 .map(|name| name[..].into())
409 .collect();
410
411 let exprs = partitions
412 .iter()
413 .filter_map(|partition| {
414 partition
415 .partition_expr
416 .as_ref()
417 .map(|expr| expr.to_parser_expr())
418 })
419 .collect();
420
421 Ok(Some(Partitions { column_list, exprs }))
422}