From c64c20b31bef476648c6acf3ae6c12dc8fbd72af Mon Sep 17 00:00:00 2001 From: taichong Date: Thu, 23 Mar 2023 11:18:15 +0800 Subject: [PATCH 1/2] feat(query): support show columns query --- src/query/ast/src/ast/format/ast_format.rs | 24 ++++ src/query/ast/src/ast/statements/columns.rs | 52 +++++++++ src/query/ast/src/ast/statements/mod.rs | 2 + src/query/ast/src/ast/statements/statement.rs | 3 + src/query/ast/src/parser/statement.rs | 15 +++ src/query/ast/src/parser/token.rs | 2 + src/query/ast/src/visitors/visitor.rs | 2 + src/query/ast/src/visitors/visitor_mut.rs | 2 + src/query/ast/src/visitors/walk.rs | 1 + src/query/ast/src/visitors/walk_mut.rs | 1 + .../access/management_mode_access.rs | 1 + src/query/sql/src/planner/binder/binder.rs | 2 + .../sql/src/planner/binder/ddl/column.rs | 107 ++++++++++++++++++ src/query/sql/src/planner/binder/ddl/mod.rs | 1 + src/query/sql/src/planner/plans/plan.rs | 1 + .../suites/base/06_show/06_0015_show_columns | 52 +++++++++ 16 files changed, 268 insertions(+) create mode 100644 src/query/ast/src/ast/statements/columns.rs create mode 100644 src/query/sql/src/planner/binder/ddl/column.rs create mode 100644 tests/sqllogictests/suites/base/06_show/06_0015_show_columns diff --git a/src/query/ast/src/ast/format/ast_format.rs b/src/query/ast/src/ast/format/ast_format.rs index 4a953209441c3..716d361e7fd69 100644 --- a/src/query/ast/src/ast/format/ast_format.rs +++ b/src/query/ast/src/ast/format/ast_format.rs @@ -1130,6 +1130,30 @@ impl<'ast> Visitor<'ast> for AstFormatVisitor { self.children.push(node); } + fn visit_show_columns(&mut self, stmt: &'ast ShowColumnsStmt) { + let mut children = Vec::new(); + if let Some(database) = &stmt.database { + let database_name = format!("Database {}", database); + let database_format_ctx = AstFormatContext::new(database_name); + let database_node = FormatTreeNode::new(database_format_ctx); + children.push(database_node); + } + + let table_name = format!("Table {}", &stmt.table); + let table_format_ctx = AstFormatContext::new(table_name); + let table_node = FormatTreeNode::new(table_format_ctx); + children.push(table_node); + + if let Some(limit) = &stmt.limit { + self.visit_show_limit(limit); + children.push(self.children.pop().unwrap()); + } + let name = "ShowColumns".to_string(); + let format_ctx = AstFormatContext::with_children(name, children.len()); + let node = FormatTreeNode::with_children(format_ctx, children); + self.children.push(node); + } + fn visit_show_create_table(&mut self, stmt: &'ast ShowCreateTableStmt) { self.visit_table_ref(&stmt.catalog, &stmt.database, &stmt.table); let child = self.children.pop().unwrap(); diff --git a/src/query/ast/src/ast/statements/columns.rs b/src/query/ast/src/ast/statements/columns.rs new file mode 100644 index 0000000000000..344f2ed9644e9 --- /dev/null +++ b/src/query/ast/src/ast/statements/columns.rs @@ -0,0 +1,52 @@ +// Copyright 2023 Datafuse Labs. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::fmt::Display; +use std::fmt::Formatter; + +use crate::ast::Identifier; +use crate::ast::ShowLimit; + +#[derive(Debug, Clone, PartialEq)] // Columns +pub struct ShowColumnsStmt { + pub catalog: Option, + pub database: Option, + pub table: Identifier, + pub full: bool, + pub limit: Option, +} + +impl Display for ShowColumnsStmt { + fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { + write!(f, "SHOW")?; + if self.full { + write!(f, " FULL")?; + } + write!(f, " COLUMNS FROM")?; + + if let Some(database) = &self.database { + if let Some(catalog) = &self.catalog { + write!(f, "{catalog}.",)?; + } + write!(f, "{database}.",)?; + } + + write!(f, " {}", self.table)?; + if let Some(limit) = &self.limit { + write!(f, " {limit}")?; + } + + Ok(()) + } +} diff --git a/src/query/ast/src/ast/statements/mod.rs b/src/query/ast/src/ast/statements/mod.rs index db837e159da50..144a3bc2fd60b 100644 --- a/src/query/ast/src/ast/statements/mod.rs +++ b/src/query/ast/src/ast/statements/mod.rs @@ -14,6 +14,7 @@ mod call; mod catalog; +mod columns; mod copy; mod database; mod explain; @@ -33,6 +34,7 @@ mod view; pub use call::*; pub use catalog::*; +pub use columns::*; pub use copy::*; pub use database::*; pub use explain::*; diff --git a/src/query/ast/src/ast/statements/statement.rs b/src/query/ast/src/ast/statements/statement.rs index d1640c7be6e90..74e51f57c99e5 100644 --- a/src/query/ast/src/ast/statements/statement.rs +++ b/src/query/ast/src/ast/statements/statement.rs @@ -114,6 +114,8 @@ pub enum Statement { OptimizeTable(OptimizeTableStmt), AnalyzeTable(AnalyzeTableStmt), ExistsTable(ExistsTableStmt), + // Columns + ShowColumns(ShowColumnsStmt), // Views CreateView(CreateViewStmt), @@ -343,6 +345,7 @@ impl Display for Statement { Statement::AlterDatabase(stmt) => write!(f, "{stmt}")?, Statement::UseDatabase { database } => write!(f, "USE {database}")?, Statement::ShowTables(stmt) => write!(f, "{stmt}")?, + Statement::ShowColumns(stmt) => write!(f, "{stmt}")?, Statement::ShowCreateTable(stmt) => write!(f, "{stmt}")?, Statement::DescribeTable(stmt) => write!(f, "{stmt}")?, Statement::ShowTablesStatus(stmt) => write!(f, "{stmt}")?, diff --git a/src/query/ast/src/parser/statement.rs b/src/query/ast/src/parser/statement.rs index 745d1b01f2061..6b71feab85dbb 100644 --- a/src/query/ast/src/parser/statement.rs +++ b/src/query/ast/src/parser/statement.rs @@ -397,6 +397,20 @@ pub fn statement(i: Input) -> IResult { }) }, ); + let show_columns = map( + rule! { + SHOW ~ FULL? ~ COLUMNS ~ ( FROM | IN ) ~ #period_separated_idents_1_to_3 ~ #show_limit? + }, + |(_, opt_full, _, _, (catalog, database, table), limit)| { + Statement::ShowColumns(ShowColumnsStmt { + catalog, + database, + table, + full: opt_full.is_some(), + limit, + }) + }, + ); let show_create_table = map( rule! { SHOW ~ CREATE ~ TABLE ~ #period_separated_idents_1_to_3 @@ -1094,6 +1108,7 @@ pub fn statement(i: Input) -> IResult { ), rule!( #show_tables : "`SHOW [FULL] TABLES [FROM ] []`" + | #show_columns : "`SHOW [FULL] COLUMNS FROM [[.]] []`" | #show_create_table : "`SHOW CREATE TABLE [.]
`" | #describe_table : "`DESCRIBE [.]
`" | #show_fields : "`SHOW FIELDS FROM [.]
`" diff --git a/src/query/ast/src/parser/token.rs b/src/query/ast/src/parser/token.rs index b64dbbc445bf0..c98202e316512 100644 --- a/src/query/ast/src/parser/token.rs +++ b/src/query/ast/src/parser/token.rs @@ -315,6 +315,8 @@ pub enum TokenKind { CHAR, #[token("COLUMN", ignore(ascii_case))] COLUMN, + #[token("COLUMNS", ignore(ascii_case))] + COLUMNS, #[token("CHARACTER", ignore(ascii_case))] CHARACTER, #[token("CONFLICT", ignore(ascii_case))] diff --git a/src/query/ast/src/visitors/visitor.rs b/src/query/ast/src/visitors/visitor.rs index f27c17bd3c185..1d8af0b50923c 100644 --- a/src/query/ast/src/visitors/visitor.rs +++ b/src/query/ast/src/visitors/visitor.rs @@ -404,6 +404,8 @@ pub trait Visitor<'ast>: Sized { fn visit_show_tables(&mut self, _stmt: &'ast ShowTablesStmt) {} + fn visit_show_columns(&mut self, _stmt: &'ast ShowColumnsStmt) {} + fn visit_show_create_table(&mut self, _stmt: &'ast ShowCreateTableStmt) {} fn visit_describe_table(&mut self, _stmt: &'ast DescribeTableStmt) {} diff --git a/src/query/ast/src/visitors/visitor_mut.rs b/src/query/ast/src/visitors/visitor_mut.rs index 99489982c3011..cc7697eb061a0 100644 --- a/src/query/ast/src/visitors/visitor_mut.rs +++ b/src/query/ast/src/visitors/visitor_mut.rs @@ -410,6 +410,8 @@ pub trait VisitorMut: Sized { fn visit_show_tables(&mut self, _stmt: &mut ShowTablesStmt) {} + fn visit_show_columns(&mut self, _stmt: &mut ShowColumnsStmt) {} + fn visit_show_create_table(&mut self, _stmt: &mut ShowCreateTableStmt) {} fn visit_describe_table(&mut self, _stmt: &mut DescribeTableStmt) {} diff --git a/src/query/ast/src/visitors/walk.rs b/src/query/ast/src/visitors/walk.rs index 3f625a8d6f585..fad1eaac30fc9 100644 --- a/src/query/ast/src/visitors/walk.rs +++ b/src/query/ast/src/visitors/walk.rs @@ -344,6 +344,7 @@ pub fn walk_statement<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Statem Statement::AlterDatabase(stmt) => visitor.visit_alter_database(stmt), Statement::UseDatabase { database } => visitor.visit_use_database(database), Statement::ShowTables(stmt) => visitor.visit_show_tables(stmt), + Statement::ShowColumns(stmt) => visitor.visit_show_columns(stmt), Statement::ShowCreateTable(stmt) => visitor.visit_show_create_table(stmt), Statement::DescribeTable(stmt) => visitor.visit_describe_table(stmt), Statement::ShowTablesStatus(stmt) => visitor.visit_show_tables_status(stmt), diff --git a/src/query/ast/src/visitors/walk_mut.rs b/src/query/ast/src/visitors/walk_mut.rs index 60420090af373..6615e7d9ec9b3 100644 --- a/src/query/ast/src/visitors/walk_mut.rs +++ b/src/query/ast/src/visitors/walk_mut.rs @@ -344,6 +344,7 @@ pub fn walk_statement_mut(visitor: &mut V, statement: &mut Statem Statement::AlterDatabase(stmt) => visitor.visit_alter_database(stmt), Statement::UseDatabase { database } => visitor.visit_use_database(database), Statement::ShowTables(stmt) => visitor.visit_show_tables(stmt), + Statement::ShowColumns(stmt) => visitor.visit_show_columns(stmt), Statement::ShowCreateTable(stmt) => visitor.visit_show_create_table(stmt), Statement::DescribeTable(stmt) => visitor.visit_describe_table(stmt), Statement::ShowTablesStatus(stmt) => visitor.visit_show_tables_status(stmt), diff --git a/src/query/service/src/interpreters/access/management_mode_access.rs b/src/query/service/src/interpreters/access/management_mode_access.rs index c871f8d4b1149..c6a3c70af55fd 100644 --- a/src/query/service/src/interpreters/access/management_mode_access.rs +++ b/src/query/service/src/interpreters/access/management_mode_access.rs @@ -40,6 +40,7 @@ impl AccessChecker for ManagementModeAccess { Some(ref v) => matches!(v, RewriteKind::ShowDatabases | RewriteKind::ShowTables + | RewriteKind::ShowColumns | RewriteKind::ShowEngines | RewriteKind::ShowSettings | RewriteKind::ShowFunctions diff --git a/src/query/sql/src/planner/binder/binder.rs b/src/query/sql/src/planner/binder/binder.rs index f5fb070063ec8..f015aead888f3 100644 --- a/src/query/sql/src/planner/binder/binder.rs +++ b/src/query/sql/src/planner/binder/binder.rs @@ -167,6 +167,8 @@ impl<'a> Binder { database: database.name.clone(), })) } + // Columns + Statement::ShowColumns(stmt) => self.bind_show_columns(bind_context, stmt).await?, // Tables Statement::ShowTables(stmt) => self.bind_show_tables(bind_context, stmt).await?, Statement::ShowCreateTable(stmt) => self.bind_show_create_table(stmt).await?, diff --git a/src/query/sql/src/planner/binder/ddl/column.rs b/src/query/sql/src/planner/binder/ddl/column.rs new file mode 100644 index 0000000000000..15b7190749a65 --- /dev/null +++ b/src/query/sql/src/planner/binder/ddl/column.rs @@ -0,0 +1,107 @@ +// Copyright 2023 Datafuse Labs. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use common_ast::ast::ShowColumnsStmt; +use common_ast::ast::ShowLimit; +use common_exception::Result; +use tracing::debug; + +use crate::normalize_identifier; +use crate::plans::Plan; +use crate::plans::RewriteKind; +use crate::BindContext; +use crate::Binder; +use crate::SelectBuilder; + +impl Binder { + pub(in crate::planner::binder) async fn bind_show_columns( + &mut self, + bind_context: &mut BindContext, + stmt: &ShowColumnsStmt, + ) -> Result { + let ShowColumnsStmt { + catalog, + database, + table, + full, + limit, + } = stmt; + + let catalog_name = match catalog { + None => self.ctx.get_current_catalog(), + Some(ident) => { + let catalog = normalize_identifier(ident, &self.name_resolution_ctx).name; + self.ctx.get_catalog(&catalog)?; + catalog + } + }; + let catalog = self.ctx.get_catalog(&catalog_name)?; + let database = match database { + None => self.ctx.get_current_database(), + Some(ident) => { + let database = normalize_identifier(ident, &self.name_resolution_ctx).name; + catalog + .get_database(&self.ctx.get_tenant(), &database) + .await?; + database + } + }; + + let table = { + let table = normalize_identifier(table, &self.name_resolution_ctx).name; + catalog + .get_table(&self.ctx.get_tenant(), database.as_str(), &table) + .await?; + table + }; + + let mut select_builder = SelectBuilder::from("system.columns"); + + select_builder + .with_column("name AS Field") + .with_column("type AS Type") + .with_column("is_nullable AS `Null`") + .with_column("data_type AS Data_Type") + .with_column("default_kind AS Default_Kind") + .with_column("default_expression AS Default_Expression"); + + if *full { + select_builder.with_column("comment AS Comment"); + } + + select_builder + .with_order_by("database") + .with_order_by("table") + .with_order_by("name"); + + select_builder + .with_filter(format!("database = '{database}'")) + .with_filter(format!("table = '{table}'")); + + let query = match limit { + None => select_builder.build(), + Some(ShowLimit::Like { pattern }) => { + select_builder.with_filter(format!("name LIKE '{pattern}'")); + select_builder.build() + } + Some(ShowLimit::Where { selection }) => { + select_builder.with_filter(format!("({selection})")); + select_builder.build() + } + }; + debug!("show columns rewrite to: {:?}", query); + self.bind_rewrite_to_query(bind_context, query.as_str(), RewriteKind::ShowColumns) + .await + } +} diff --git a/src/query/sql/src/planner/binder/ddl/mod.rs b/src/query/sql/src/planner/binder/ddl/mod.rs index ab78d34a7adb4..27cd1fe920ee1 100644 --- a/src/query/sql/src/planner/binder/ddl/mod.rs +++ b/src/query/sql/src/planner/binder/ddl/mod.rs @@ -14,6 +14,7 @@ mod account; mod catalog; +mod column; mod database; mod role; mod share; diff --git a/src/query/sql/src/planner/plans/plan.rs b/src/query/sql/src/planner/plans/plan.rs index 5964bd8a945d0..7562beb631fbf 100644 --- a/src/query/sql/src/planner/plans/plan.rs +++ b/src/query/sql/src/planner/plans/plan.rs @@ -230,6 +230,7 @@ pub enum RewriteKind { ShowCatalogs, ShowDatabases, ShowTables, + ShowColumns, ShowTablesStatus, ShowFunctions, diff --git a/tests/sqllogictests/suites/base/06_show/06_0015_show_columns b/tests/sqllogictests/suites/base/06_show/06_0015_show_columns new file mode 100644 index 0000000000000..885dc63839e38 --- /dev/null +++ b/tests/sqllogictests/suites/base/06_show/06_0015_show_columns @@ -0,0 +1,52 @@ +statement ok +DROP DATABASE IF EXISTS showcolumn + +statement ok +CREATE DATABASE showcolumn + +statement ok +CREATE TABLE showcolumn.t1(c1 int) ENGINE = Null + +statement ok +CREATE TABLE showcolumn.t2(c1 int) ENGINE = Null + +statement ok +CREATE TABLE showcolumn.t3(c1 int null default null, c2 Datetime, c3 String Default 'c3') ENGINE = Null; + +query TTTTTT +SHOW COLUMNS FROM showcolumn.t3 +---- +c1 Nullable(Int32) YES INT DEFAULT NULL +c2 Timestamp NO TIMESTAMP (empty) (empty) +c3 String NO VARCHAR DEFAULT 'c3' + +statement ok +use showcolumn + +query TTTTTTT +SHOW FULL COLUMNS IN t3 +---- +c1 Nullable(Int32) YES INT DEFAULT NULL (empty) +c2 Timestamp NO TIMESTAMP (empty) (empty) (empty) +c3 String NO VARCHAR DEFAULT 'c3' (empty) + +query T +explain show full columns in t3 +---- +Sort +├── sort keys: [database ASC NULLS LAST, table ASC NULLS LAST, name ASC NULLS LAST] +├── estimated rows: 0.00 +└── Filter + ├── filters: [columns.database (#1) = "showcolumn", columns.table (#2) = "t3"] + ├── estimated rows: 0.00 + └── TableScan + ├── table: default.system.columns + ├── read rows: 0 + ├── read bytes: 0 + ├── partitions total: 0 + ├── partitions scanned: 0 + ├── push downs: [filters: [columns.database (#1) = "showcolumn" AND columns.table (#2) = "t3"], limit: NONE] + └── estimated rows: 0.00 + +statement ok +DROP DATABASE showcolumn From 82e4ea22357db7c44c34e7313a03b65967aaecaa Mon Sep 17 00:00:00 2001 From: taichong Date: Thu, 23 Mar 2023 14:00:42 +0800 Subject: [PATCH 2/2] fix test_unit --- src/query/ast/src/ast/statements/columns.rs | 6 +- src/query/ast/src/parser/statement.rs | 11 +- src/query/ast/tests/it/parser.rs | 3 + .../ast/tests/it/testdata/statement-error.txt | 2 +- src/query/ast/tests/it/testdata/statement.txt | 102 ++++++++++++++++++ .../sql/src/planner/binder/ddl/column.rs | 29 ++--- .../information-schema/src/columns_table.rs | 4 +- .../suites/base/06_show/06_0015_show_columns | 39 +++---- .../base/20+_others/20_0000_describe_table | 2 + 9 files changed, 159 insertions(+), 39 deletions(-) diff --git a/src/query/ast/src/ast/statements/columns.rs b/src/query/ast/src/ast/statements/columns.rs index 344f2ed9644e9..1b6fe4171f13a 100644 --- a/src/query/ast/src/ast/statements/columns.rs +++ b/src/query/ast/src/ast/statements/columns.rs @@ -33,16 +33,16 @@ impl Display for ShowColumnsStmt { if self.full { write!(f, " FULL")?; } - write!(f, " COLUMNS FROM")?; + write!(f, " COLUMNS FROM {}", self.table)?; if let Some(database) = &self.database { + write!(f, " FROM ")?; if let Some(catalog) = &self.catalog { write!(f, "{catalog}.",)?; } - write!(f, "{database}.",)?; + write!(f, "{database}")?; } - write!(f, " {}", self.table)?; if let Some(limit) = &self.limit { write!(f, " {limit}")?; } diff --git a/src/query/ast/src/parser/statement.rs b/src/query/ast/src/parser/statement.rs index 6b71feab85dbb..d65afe315e915 100644 --- a/src/query/ast/src/parser/statement.rs +++ b/src/query/ast/src/parser/statement.rs @@ -399,9 +399,14 @@ pub fn statement(i: Input) -> IResult { ); let show_columns = map( rule! { - SHOW ~ FULL? ~ COLUMNS ~ ( FROM | IN ) ~ #period_separated_idents_1_to_3 ~ #show_limit? + SHOW ~ FULL? ~ COLUMNS ~ ( FROM | IN ) ~ #ident ~ ((FROM | IN) ~ #period_separated_idents_1_to_2)? ~ #show_limit? }, - |(_, opt_full, _, _, (catalog, database, table), limit)| { + |(_, opt_full, _, _, table, ctl_db, limit)| { + let (catalog, database) = match ctl_db { + Some((_, (Some(c), d))) => (Some(c), Some(d)), + Some((_, (None, d))) => (None, Some(d)), + _ => (None, None), + }; Statement::ShowColumns(ShowColumnsStmt { catalog, database, @@ -1108,7 +1113,7 @@ pub fn statement(i: Input) -> IResult { ), rule!( #show_tables : "`SHOW [FULL] TABLES [FROM ] []`" - | #show_columns : "`SHOW [FULL] COLUMNS FROM [[.]
] []`" + | #show_columns : "`SHOW [FULL] COLUMNS FROM
[FROM|IN .] []`" | #show_create_table : "`SHOW CREATE TABLE [.]
`" | #describe_table : "`DESCRIBE [.]
`" | #show_fields : "`SHOW FIELDS FROM [.]
`" diff --git a/src/query/ast/tests/it/parser.rs b/src/query/ast/tests/it/parser.rs index e4513e07c0a76..7c9e3958fb19d 100644 --- a/src/query/ast/tests/it/parser.rs +++ b/src/query/ast/tests/it/parser.rs @@ -70,6 +70,9 @@ fn test_statement() { r#"show full tables"#, r#"show full tables from db"#, r#"show full tables from ctl.db"#, + r#"show full columns in t in db"#, + r#"show columns in t from ctl.db"#, + r#"show full columns from t from db like 'id%'"#, r#"show processlist;"#, r#"show create table a.b;"#, r#"show create table a.b format TabSeparatedWithNamesAndTypes;"#, diff --git a/src/query/ast/tests/it/testdata/statement-error.txt b/src/query/ast/tests/it/testdata/statement-error.txt index 24df4773b9ad9..85c96d6077d4e 100644 --- a/src/query/ast/tests/it/testdata/statement-error.txt +++ b/src/query/ast/tests/it/testdata/statement-error.txt @@ -275,7 +275,7 @@ error: --> SQL:1:6 | 1 | SHOW GRANT FOR ROLE role1; - | ^^^^^ expected `SETTINGS`, `STAGES`, `ENGINES`, `PROCESSLIST`, `METRICS`, `FUNCTIONS`, or 14 more ... + | ^^^^^ expected `SETTINGS`, `STAGES`, `ENGINES`, `PROCESSLIST`, `METRICS`, `FUNCTIONS`, or 15 more ... ---------- Input ---------- diff --git a/src/query/ast/tests/it/testdata/statement.txt b/src/query/ast/tests/it/testdata/statement.txt index 789e69e718a24..fea3b49a93570 100644 --- a/src/query/ast/tests/it/testdata/statement.txt +++ b/src/query/ast/tests/it/testdata/statement.txt @@ -138,6 +138,108 @@ ShowTables( ) +---------- Input ---------- +show full columns in t in db +---------- Output --------- +SHOW FULL COLUMNS FROM t FROM db +---------- AST ------------ +ShowColumns( + ShowColumnsStmt { + catalog: None, + database: Some( + Identifier { + name: "db", + quote: None, + span: Some( + 26..28, + ), + }, + ), + table: Identifier { + name: "t", + quote: None, + span: Some( + 21..22, + ), + }, + full: true, + limit: None, + }, +) + + +---------- Input ---------- +show columns in t from ctl.db +---------- Output --------- +SHOW COLUMNS FROM t FROM ctl.db +---------- AST ------------ +ShowColumns( + ShowColumnsStmt { + catalog: Some( + Identifier { + name: "ctl", + quote: None, + span: Some( + 23..26, + ), + }, + ), + database: Some( + Identifier { + name: "db", + quote: None, + span: Some( + 27..29, + ), + }, + ), + table: Identifier { + name: "t", + quote: None, + span: Some( + 16..17, + ), + }, + full: false, + limit: None, + }, +) + + +---------- Input ---------- +show full columns from t from db like 'id%' +---------- Output --------- +SHOW FULL COLUMNS FROM t FROM db LIKE 'id%' +---------- AST ------------ +ShowColumns( + ShowColumnsStmt { + catalog: None, + database: Some( + Identifier { + name: "db", + quote: None, + span: Some( + 30..32, + ), + }, + ), + table: Identifier { + name: "t", + quote: None, + span: Some( + 23..24, + ), + }, + full: true, + limit: Some( + Like { + pattern: "id%", + }, + ), + }, +) + + ---------- Input ---------- show processlist; ---------- Output --------- diff --git a/src/query/sql/src/planner/binder/ddl/column.rs b/src/query/sql/src/planner/binder/ddl/column.rs index 15b7190749a65..5153128ff823c 100644 --- a/src/query/sql/src/planner/binder/ddl/column.rs +++ b/src/query/sql/src/planner/binder/ddl/column.rs @@ -66,33 +66,36 @@ impl Binder { table }; - let mut select_builder = SelectBuilder::from("system.columns"); + let mut select_builder = SelectBuilder::from("information_schema.columns"); select_builder - .with_column("name AS Field") - .with_column("type AS Type") + .with_column("column_name AS `Field`") + .with_column("column_type AS `Type`") .with_column("is_nullable AS `Null`") - .with_column("data_type AS Data_Type") - .with_column("default_kind AS Default_Kind") - .with_column("default_expression AS Default_Expression"); + .with_column("default AS `Default`") + .with_column("extra AS `Extra`") + .with_column("column_key AS `Key`"); if *full { - select_builder.with_column("comment AS Comment"); + select_builder + .with_column("collation_name AS `Collation`") + .with_column("privileges AS `Privileges`") + .with_column("column_comment AS Comment"); } select_builder - .with_order_by("database") - .with_order_by("table") - .with_order_by("name"); + .with_order_by("table_schema") + .with_order_by("table_name") + .with_order_by("column_name"); select_builder - .with_filter(format!("database = '{database}'")) - .with_filter(format!("table = '{table}'")); + .with_filter(format!("table_schema = '{database}'")) + .with_filter(format!("table_name = '{table}'")); let query = match limit { None => select_builder.build(), Some(ShowLimit::Like { pattern }) => { - select_builder.with_filter(format!("name LIKE '{pattern}'")); + select_builder.with_filter(format!("column_name LIKE '{pattern}'")); select_builder.build() } Some(ShowLimit::Where { selection }) => { diff --git a/src/query/storages/information-schema/src/columns_table.rs b/src/query/storages/information-schema/src/columns_table.rs index 4d32337ad9404..0f2327189328a 100644 --- a/src/query/storages/information-schema/src/columns_table.rs +++ b/src/query/storages/information-schema/src/columns_table.rs @@ -39,7 +39,7 @@ impl ColumnsTable { when is_nullable='YES' then 1 end as nullable, is_nullable AS is_nullable, - data_type AS data_type, + type AS data_type, data_type AS column_type, NULL AS character_maximum_length, NULL AS character_octet_length, @@ -56,6 +56,8 @@ impl ColumnsTable { NULL AS domain_catalog, NULL AS domain_schema, NULL AS domain_name, + NULL AS privileges, + default_expression as default, NULL AS extra FROM system.columns;"; diff --git a/tests/sqllogictests/suites/base/06_show/06_0015_show_columns b/tests/sqllogictests/suites/base/06_show/06_0015_show_columns index 885dc63839e38..ff4c2db7f6cbd 100644 --- a/tests/sqllogictests/suites/base/06_show/06_0015_show_columns +++ b/tests/sqllogictests/suites/base/06_show/06_0015_show_columns @@ -11,14 +11,14 @@ statement ok CREATE TABLE showcolumn.t2(c1 int) ENGINE = Null statement ok -CREATE TABLE showcolumn.t3(c1 int null default null, c2 Datetime, c3 String Default 'c3') ENGINE = Null; +CREATE TABLE showcolumn.t3(c1 int null default 4, c2 Datetime default '2022-02-02 12:00:00', c3 String Default 'c3') ENGINE = Null; query TTTTTT -SHOW COLUMNS FROM showcolumn.t3 +SHOW COLUMNS FROM t3 FROM showcolumn ---- -c1 Nullable(Int32) YES INT DEFAULT NULL -c2 Timestamp NO TIMESTAMP (empty) (empty) -c3 String NO VARCHAR DEFAULT 'c3' +c1 INT YES 4 NULL NULL +c2 TIMESTAMP NO '2022-02-02 12:00:00' NULL NULL +c3 VARCHAR NO 'c3' NULL NULL statement ok use showcolumn @@ -26,9 +26,9 @@ use showcolumn query TTTTTTT SHOW FULL COLUMNS IN t3 ---- -c1 Nullable(Int32) YES INT DEFAULT NULL (empty) -c2 Timestamp NO TIMESTAMP (empty) (empty) (empty) -c3 String NO VARCHAR DEFAULT 'c3' (empty) +c1 INT YES 4 NULL NULL NULL NULL NULL +c2 TIMESTAMP NO '2022-02-02 12:00:00' NULL NULL NULL NULL NULL +c3 VARCHAR NO 'c3' NULL NULL NULL NULL NULL query T explain show full columns in t3 @@ -36,17 +36,20 @@ explain show full columns in t3 Sort ├── sort keys: [database ASC NULLS LAST, table ASC NULLS LAST, name ASC NULLS LAST] ├── estimated rows: 0.00 -└── Filter - ├── filters: [columns.database (#1) = "showcolumn", columns.table (#2) = "t3"] +└── EvalScalar + ├── expressions: [NULL, NULL, NULL, NULL, NULL] ├── estimated rows: 0.00 - └── TableScan - ├── table: default.system.columns - ├── read rows: 0 - ├── read bytes: 0 - ├── partitions total: 0 - ├── partitions scanned: 0 - ├── push downs: [filters: [columns.database (#1) = "showcolumn" AND columns.table (#2) = "t3"], limit: NONE] - └── estimated rows: 0.00 + └── Filter + ├── filters: [columns.table_schema (#1) = "showcolumn", columns.table_name (#2) = "t3"] + ├── estimated rows: 0.00 + └── TableScan + ├── table: default.system.columns + ├── read rows: 0 + ├── read bytes: 0 + ├── partitions total: 0 + ├── partitions scanned: 0 + ├── push downs: [filters: [columns.table_schema (#1) = "showcolumn" AND columns.table_name (#2) = "t3"], limit: NONE] + └── estimated rows: 0.00 statement ok DROP DATABASE showcolumn diff --git a/tests/sqllogictests/suites/base/20+_others/20_0000_describe_table b/tests/sqllogictests/suites/base/20+_others/20_0000_describe_table index e79ba2a16665b..904c35601664c 100644 --- a/tests/sqllogictests/suites/base/20+_others/20_0000_describe_table +++ b/tests/sqllogictests/suites/base/20+_others/20_0000_describe_table @@ -81,6 +81,8 @@ collation_name NULL NO NULL (empty) domain_catalog NULL NO NULL (empty) domain_schema NULL NO NULL (empty) domain_name NULL NO NULL (empty) +privileges NULL NO NULL (empty) +default VARCHAR NO "" (empty) extra NULL NO NULL (empty) query TTT