mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-05-16 13:00:40 +00:00
feat: support show views statement (#4360)
This commit enables show view statement which will display a list of views names.
This commit is contained in:
@@ -506,6 +506,9 @@ pub fn check_permission(
|
||||
Statement::ShowIndex(stmt) => {
|
||||
validate_db_permission!(stmt, query_ctx);
|
||||
}
|
||||
Statement::ShowViews(stmt) => {
|
||||
validate_db_permission!(stmt, query_ctx);
|
||||
}
|
||||
Statement::ShowStatus(_stmt) => {}
|
||||
Statement::DescribeTable(stmt) => {
|
||||
validate_param(stmt.name(), query_ctx)?;
|
||||
|
||||
@@ -136,6 +136,8 @@ impl StatementExecutor {
|
||||
|
||||
Statement::ShowCharset(kind) => self.show_charset(kind, query_ctx).await,
|
||||
|
||||
Statement::ShowViews(stmt) => self.show_views(stmt, query_ctx).await,
|
||||
|
||||
Statement::Copy(sql::statements::copy::Copy::CopyTable(stmt)) => {
|
||||
let req = to_copy_table_request(stmt, query_ctx.clone())?;
|
||||
match req.direction {
|
||||
|
||||
@@ -24,7 +24,7 @@ use sql::ast::Ident;
|
||||
use sql::statements::create::Partitions;
|
||||
use sql::statements::show::{
|
||||
ShowColumns, ShowCreateFlow, ShowCreateView, ShowDatabases, ShowIndex, ShowKind,
|
||||
ShowTableStatus, ShowTables, ShowVariables,
|
||||
ShowTableStatus, ShowTables, ShowVariables, ShowViews,
|
||||
};
|
||||
use table::metadata::TableType;
|
||||
use table::table_name::TableName;
|
||||
@@ -152,6 +152,17 @@ impl StatementExecutor {
|
||||
.context(error::ExecuteStatementSnafu)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub(super) async fn show_views(
|
||||
&self,
|
||||
stmt: ShowViews,
|
||||
query_ctx: QueryContextRef,
|
||||
) -> Result<Output> {
|
||||
query::sql::show_views(stmt, &self.query_engine, &self.catalog_manager, query_ctx)
|
||||
.await
|
||||
.context(ExecuteStatementSnafu)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub async fn show_create_flow(
|
||||
&self,
|
||||
|
||||
@@ -19,7 +19,7 @@ use std::sync::Arc;
|
||||
|
||||
use catalog::information_schema::{
|
||||
columns, key_column_usage, schemata, tables, CHARACTER_SETS, COLLATIONS, COLUMNS,
|
||||
KEY_COLUMN_USAGE, SCHEMATA, TABLES,
|
||||
KEY_COLUMN_USAGE, SCHEMATA, TABLES, VIEWS,
|
||||
};
|
||||
use catalog::CatalogManagerRef;
|
||||
use common_catalog::consts::{
|
||||
@@ -55,6 +55,7 @@ use sql::parser::ParserContext;
|
||||
use sql::statements::create::{CreateFlow, CreateView, Partitions};
|
||||
use sql::statements::show::{
|
||||
ShowColumns, ShowDatabases, ShowIndex, ShowKind, ShowTableStatus, ShowTables, ShowVariables,
|
||||
ShowViews,
|
||||
};
|
||||
use sql::statements::statement::Statement;
|
||||
use sqlparser::ast::ObjectName;
|
||||
@@ -69,6 +70,7 @@ use crate::QueryEngineRef;
|
||||
const SCHEMAS_COLUMN: &str = "Database";
|
||||
const OPTIONS_COLUMN: &str = "Options";
|
||||
const TABLES_COLUMN: &str = "Tables";
|
||||
const VIEWS_COLUMN: &str = "Views";
|
||||
const FIELD_COLUMN: &str = "Field";
|
||||
const TABLE_TYPE_COLUMN: &str = "Table_type";
|
||||
const COLUMN_NAME_COLUMN: &str = "Column";
|
||||
@@ -725,6 +727,42 @@ pub fn show_create_view(
|
||||
Ok(Output::new_with_record_batches(records))
|
||||
}
|
||||
|
||||
/// Execute [`ShowViews`] statement and return the [`Output`] if success.
|
||||
pub async fn show_views(
|
||||
stmt: ShowViews,
|
||||
query_engine: &QueryEngineRef,
|
||||
catalog_manager: &CatalogManagerRef,
|
||||
query_ctx: QueryContextRef,
|
||||
) -> Result<Output> {
|
||||
let schema_name = if let Some(database) = stmt.database {
|
||||
database
|
||||
} else {
|
||||
query_ctx.current_schema()
|
||||
};
|
||||
|
||||
let projects = vec![(tables::TABLE_NAME, VIEWS_COLUMN)];
|
||||
let filters = vec![
|
||||
col(tables::TABLE_SCHEMA).eq(lit(schema_name.clone())),
|
||||
col(tables::TABLE_CATALOG).eq(lit(query_ctx.current_catalog())),
|
||||
];
|
||||
let like_field = Some(tables::TABLE_NAME);
|
||||
let sort = vec![col(tables::TABLE_NAME).sort(true, true)];
|
||||
|
||||
query_from_information_schema_table(
|
||||
query_engine,
|
||||
catalog_manager,
|
||||
query_ctx,
|
||||
VIEWS,
|
||||
vec![],
|
||||
projects,
|
||||
filters,
|
||||
like_field,
|
||||
sort,
|
||||
stmt.kind,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub fn show_create_flow(
|
||||
flow_name: ObjectName,
|
||||
flow_val: FlowInfoValue,
|
||||
|
||||
@@ -22,7 +22,7 @@ use crate::error::{
|
||||
use crate::parser::ParserContext;
|
||||
use crate::statements::show::{
|
||||
ShowColumns, ShowCreateFlow, ShowCreateTable, ShowCreateView, ShowDatabases, ShowIndex,
|
||||
ShowKind, ShowStatus, ShowTableStatus, ShowTables, ShowVariables,
|
||||
ShowKind, ShowStatus, ShowTableStatus, ShowTables, ShowVariables, ShowViews,
|
||||
};
|
||||
use crate::statements::statement::Statement;
|
||||
|
||||
@@ -44,6 +44,8 @@ impl<'a> ParserContext<'a> {
|
||||
} else {
|
||||
self.unsupported(self.peek_token_as_string())
|
||||
}
|
||||
} else if self.consume_token("VIEWS") {
|
||||
self.parse_show_views()
|
||||
} else if self.matches_keyword(Keyword::CHARSET) {
|
||||
self.parser.next_token();
|
||||
Ok(Statement::ShowCharset(self.parse_show_kind()?))
|
||||
@@ -430,6 +432,28 @@ impl<'a> ParserContext<'a> {
|
||||
_ => self.unsupported(self.peek_token_as_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_show_views(&mut self) -> Result<Statement> {
|
||||
let database = match self.parser.peek_token().token {
|
||||
Token::EOF | Token::SemiColon => {
|
||||
return Ok(Statement::ShowViews(ShowViews {
|
||||
kind: ShowKind::All,
|
||||
database: None,
|
||||
}));
|
||||
}
|
||||
|
||||
// SHOW VIEWS [in | FROM] [DATABASE]
|
||||
Token::Word(w) => match w.keyword {
|
||||
Keyword::IN | Keyword::FROM => self.parse_db_name()?,
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let kind = self.parse_show_kind()?;
|
||||
|
||||
Ok(Statement::ShowViews(ShowViews { kind, database }))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -942,4 +966,38 @@ mod tests {
|
||||
);
|
||||
assert_eq!(sql, stmts[0].to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_show_views() {
|
||||
let sql = "SHOW VIEWS";
|
||||
let result =
|
||||
ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
|
||||
let stmts = result.unwrap();
|
||||
assert_eq!(1, stmts.len());
|
||||
assert_eq!(
|
||||
stmts[0],
|
||||
Statement::ShowViews(ShowViews {
|
||||
kind: ShowKind::All,
|
||||
database: None,
|
||||
})
|
||||
);
|
||||
assert_eq!(sql, stmts[0].to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_show_views_in_db() {
|
||||
let sql = "SHOW VIEWS IN d1";
|
||||
let result =
|
||||
ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
|
||||
let stmts = result.unwrap();
|
||||
assert_eq!(1, stmts.len());
|
||||
assert_eq!(
|
||||
stmts[0],
|
||||
Statement::ShowViews(ShowViews {
|
||||
kind: ShowKind::All,
|
||||
database: Some("d1".to_string()),
|
||||
})
|
||||
);
|
||||
assert_eq!(sql, stmts[0].to_string());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,6 +200,25 @@ impl Display for ShowCreateView {
|
||||
}
|
||||
}
|
||||
|
||||
/// SQL structure for `SHOW VIEWS`.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut)]
|
||||
pub struct ShowViews {
|
||||
pub kind: ShowKind,
|
||||
pub database: Option<String>,
|
||||
}
|
||||
|
||||
impl Display for ShowViews {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "SHOW VIEWS")?;
|
||||
if let Some(database) = &self.database {
|
||||
write!(f, " IN {database}")?;
|
||||
}
|
||||
format_kind!(self, f);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// SQL structure for `SHOW VARIABLES xxx`.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut)]
|
||||
pub struct ShowVariables {
|
||||
@@ -473,6 +492,49 @@ SHOW FULL TABLES"#,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_display_show_views() {
|
||||
let sql = r"show views in d1;";
|
||||
let stmts: Vec<Statement> =
|
||||
ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
|
||||
.unwrap();
|
||||
assert_eq!(1, stmts.len());
|
||||
assert_matches!(&stmts[0], Statement::ShowViews { .. });
|
||||
match &stmts[0] {
|
||||
Statement::ShowViews(show) => {
|
||||
let new_sql = format!("\n{}", show);
|
||||
assert_eq!(
|
||||
r#"
|
||||
SHOW VIEWS IN d1"#,
|
||||
&new_sql
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
let sql = r"show views;";
|
||||
let stmts: Vec<Statement> =
|
||||
ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
|
||||
.unwrap();
|
||||
assert_eq!(1, stmts.len());
|
||||
assert_matches!(&stmts[0], Statement::ShowViews { .. });
|
||||
match &stmts[0] {
|
||||
Statement::ShowViews(show) => {
|
||||
let new_sql = format!("\n{}", show);
|
||||
assert_eq!(
|
||||
r#"
|
||||
SHOW VIEWS"#,
|
||||
&new_sql
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_display_show_databases() {
|
||||
let sql = r"show databases;";
|
||||
|
||||
@@ -32,7 +32,7 @@ use crate::statements::query::Query;
|
||||
use crate::statements::set_variables::SetVariables;
|
||||
use crate::statements::show::{
|
||||
ShowColumns, ShowCreateFlow, ShowCreateTable, ShowCreateView, ShowDatabases, ShowIndex,
|
||||
ShowKind, ShowStatus, ShowTableStatus, ShowTables, ShowVariables,
|
||||
ShowKind, ShowStatus, ShowTableStatus, ShowTables, ShowVariables, ShowViews,
|
||||
};
|
||||
use crate::statements::tql::Tql;
|
||||
use crate::statements::truncate::TruncateTable;
|
||||
@@ -91,6 +91,8 @@ pub enum Statement {
|
||||
ShowCreateView(ShowCreateView),
|
||||
// SHOW STATUS
|
||||
ShowStatus(ShowStatus),
|
||||
// SHOW VIEWS
|
||||
ShowViews(ShowViews),
|
||||
// DESCRIBE TABLE
|
||||
DescribeTable(DescribeTable),
|
||||
// EXPLAIN QUERY
|
||||
@@ -132,6 +134,7 @@ impl Display for Statement {
|
||||
Statement::ShowCreateTable(s) => s.fmt(f),
|
||||
Statement::ShowCreateFlow(s) => s.fmt(f),
|
||||
Statement::ShowCreateView(s) => s.fmt(f),
|
||||
Statement::ShowViews(s) => s.fmt(f),
|
||||
Statement::ShowStatus(s) => s.fmt(f),
|
||||
Statement::DescribeTable(s) => s.fmt(f),
|
||||
Statement::Explain(s) => s.fmt(f),
|
||||
|
||||
@@ -52,6 +52,14 @@ CREATE VIEW v1 AS SELECT * FROM dontexist;
|
||||
|
||||
Error: 3000(PlanQuery), Failed to plan SQL: Error during planning: Table not found: greptime.public.dontexist
|
||||
|
||||
SHOW VIEWS;
|
||||
|
||||
+-------+
|
||||
| Views |
|
||||
+-------+
|
||||
| v1 |
|
||||
+-------+
|
||||
|
||||
DROP VIEW v1;
|
||||
|
||||
Affected Rows: 0
|
||||
@@ -81,3 +89,8 @@ SHOW TABLES;
|
||||
| numbers |
|
||||
+---------+
|
||||
|
||||
SHOW VIEWS;
|
||||
|
||||
++
|
||||
++
|
||||
|
||||
|
||||
@@ -30,6 +30,8 @@ INSERT INTO v1 VALUES (1);
|
||||
|
||||
CREATE VIEW v1 AS SELECT * FROM dontexist;
|
||||
|
||||
SHOW VIEWS;
|
||||
|
||||
DROP VIEW v1;
|
||||
|
||||
SELECT * FROM v1;
|
||||
@@ -42,3 +44,5 @@ DROP VIEW IF EXISTS v2;
|
||||
DROP TABLE t1;
|
||||
|
||||
SHOW TABLES;
|
||||
|
||||
SHOW VIEWS;
|
||||
|
||||
Reference in New Issue
Block a user