mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-01-17 10:42:55 +00:00
feat: show create database (#4642)
* feat: show create database * feat: add sqlness test * chore: reorder mod and use * feat: show create schema * Update src/frontend/src/instance.rs
This commit is contained in:
@@ -12,19 +12,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bench::BenchTableMetadataCommand;
|
||||
use clap::Parser;
|
||||
use common_telemetry::logging::{LoggingOptions, TracingOptions};
|
||||
pub use repl::Repl;
|
||||
use tracing_appender::non_blocking::WorkerGuard;
|
||||
|
||||
use self::export::ExportCommand;
|
||||
use crate::cli::import::ImportCommand;
|
||||
use crate::error::Result;
|
||||
use crate::options::GlobalOptions;
|
||||
use crate::App;
|
||||
|
||||
mod bench;
|
||||
|
||||
// Wait for https://github.com/GreptimeTeam/greptimedb/issues/2373
|
||||
@@ -39,6 +26,19 @@ mod import;
|
||||
#[allow(unused)]
|
||||
mod repl;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bench::BenchTableMetadataCommand;
|
||||
use clap::Parser;
|
||||
use common_telemetry::logging::{LoggingOptions, TracingOptions};
|
||||
pub use repl::Repl;
|
||||
use tracing_appender::non_blocking::WorkerGuard;
|
||||
|
||||
use self::export::ExportCommand;
|
||||
use crate::cli::import::ImportCommand;
|
||||
use crate::error::Result;
|
||||
use crate::options::GlobalOptions;
|
||||
use crate::App;
|
||||
|
||||
pub const APP_NAME: &str = "greptime-cli";
|
||||
|
||||
#[async_trait]
|
||||
|
||||
@@ -89,6 +89,19 @@ impl TryFrom<&HashMap<String, String>> for SchemaNameValue {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SchemaNameValue> for HashMap<String, String> {
|
||||
fn from(value: SchemaNameValue) -> Self {
|
||||
let mut opts = HashMap::new();
|
||||
if let Some(ttl) = value.ttl {
|
||||
opts.insert(
|
||||
OPT_KEY_TTL.to_string(),
|
||||
format!("{}", humantime::format_duration(ttl)),
|
||||
);
|
||||
}
|
||||
opts
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SchemaNameKey<'a> {
|
||||
pub fn new(catalog: &'a str, schema: &'a str) -> Self {
|
||||
Self { catalog, schema }
|
||||
|
||||
@@ -79,9 +79,9 @@ pub use standalone::StandaloneDatanodeManager;
|
||||
|
||||
use self::prom_store::ExportMetricHandler;
|
||||
use crate::error::{
|
||||
self, Error, ExecLogicalPlanSnafu, ExecutePromqlSnafu, ExternalSnafu, ParseSqlSnafu,
|
||||
PermissionSnafu, PlanStatementSnafu, Result, SqlExecInterceptedSnafu, StartServerSnafu,
|
||||
TableOperationSnafu,
|
||||
self, Error, ExecLogicalPlanSnafu, ExecutePromqlSnafu, ExternalSnafu, InvalidSqlSnafu,
|
||||
ParseSqlSnafu, PermissionSnafu, PlanStatementSnafu, Result, SqlExecInterceptedSnafu,
|
||||
StartServerSnafu, TableOperationSnafu,
|
||||
};
|
||||
use crate::frontend::FrontendOptions;
|
||||
use crate::heartbeat::HeartbeatTask;
|
||||
@@ -452,6 +452,9 @@ pub fn check_permission(
|
||||
| Statement::DropDatabase(_)
|
||||
| Statement::DropFlow(_)
|
||||
| Statement::Use(_) => {}
|
||||
Statement::ShowCreateDatabase(stmt) => {
|
||||
validate_database(&stmt.database_name, query_ctx)?;
|
||||
}
|
||||
Statement::ShowCreateTable(stmt) => {
|
||||
validate_param(&stmt.table_name, query_ctx)?;
|
||||
}
|
||||
@@ -527,8 +530,8 @@ pub fn check_permission(
|
||||
},
|
||||
Statement::Copy(sql::statements::copy::Copy::CopyDatabase(copy_database)) => {
|
||||
match copy_database {
|
||||
CopyDatabase::To(stmt) => validate_param(&stmt.database_name, query_ctx)?,
|
||||
CopyDatabase::From(stmt) => validate_param(&stmt.database_name, query_ctx)?,
|
||||
CopyDatabase::To(stmt) => validate_database(&stmt.database_name, query_ctx)?,
|
||||
CopyDatabase::From(stmt) => validate_database(&stmt.database_name, query_ctx)?,
|
||||
}
|
||||
}
|
||||
Statement::TruncateTable(stmt) => {
|
||||
@@ -548,6 +551,26 @@ fn validate_param(name: &ObjectName, query_ctx: &QueryContextRef) -> Result<()>
|
||||
.context(SqlExecInterceptedSnafu)
|
||||
}
|
||||
|
||||
fn validate_database(name: &ObjectName, query_ctx: &QueryContextRef) -> Result<()> {
|
||||
let (catalog, schema) = match &name.0[..] {
|
||||
[schema] => (
|
||||
query_ctx.current_catalog().to_string(),
|
||||
schema.value.clone(),
|
||||
),
|
||||
[catalog, schema] => (catalog.value.clone(), schema.value.clone()),
|
||||
_ => InvalidSqlSnafu {
|
||||
err_msg: format!(
|
||||
"expect database name to be <catalog>.<schema> or <schema>, actual: {name}",
|
||||
),
|
||||
}
|
||||
.fail()?,
|
||||
};
|
||||
|
||||
validate_catalog_and_schema(&catalog, &schema, query_ctx)
|
||||
.map_err(BoxedError::new)
|
||||
.context(SqlExecInterceptedSnafu)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::HashMap;
|
||||
|
||||
@@ -784,6 +784,12 @@ pub enum Error {
|
||||
#[snafu(implicit)]
|
||||
location: Location,
|
||||
},
|
||||
|
||||
#[snafu(display("Failed to upgrade catalog manager reference"))]
|
||||
UpgradeCatalogManagerRef {
|
||||
#[snafu(implicit)]
|
||||
location: Location,
|
||||
},
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
@@ -931,6 +937,8 @@ impl ErrorExt for Error {
|
||||
|
||||
Error::ExecuteAdminFunction { source, .. } => source.status_code(),
|
||||
Error::BuildRecordBatch { source, .. } => source.status_code(),
|
||||
|
||||
Error::UpgradeCatalogManagerRef { .. } => StatusCode::Internal,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,10 @@ mod set;
|
||||
mod show;
|
||||
mod tql;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use catalog::kvbackend::KvBackendCatalogManager;
|
||||
use catalog::CatalogManagerRef;
|
||||
use client::RecordBatches;
|
||||
use common_error::ext::BoxedError;
|
||||
@@ -32,6 +34,7 @@ use common_meta::cache::TableRouteCacheRef;
|
||||
use common_meta::cache_invalidator::CacheInvalidatorRef;
|
||||
use common_meta::ddl::ProcedureExecutorRef;
|
||||
use common_meta::key::flow::{FlowMetadataManager, FlowMetadataManagerRef};
|
||||
use common_meta::key::schema_name::SchemaNameKey;
|
||||
use common_meta::key::view_info::{ViewInfoManager, ViewInfoManagerRef};
|
||||
use common_meta::key::{TableMetadataManager, TableMetadataManagerRef};
|
||||
use common_meta::kv_backend::KvBackendRef;
|
||||
@@ -60,7 +63,8 @@ use table::TableRef;
|
||||
use self::set::{set_bytea_output, set_datestyle, set_timezone, validate_client_encoding};
|
||||
use crate::error::{
|
||||
self, CatalogSnafu, ExecLogicalPlanSnafu, ExternalSnafu, InvalidSqlSnafu, NotSupportedSnafu,
|
||||
PlanStatementSnafu, Result, SchemaNotFoundSnafu, TableNotFoundSnafu,
|
||||
PlanStatementSnafu, Result, SchemaNotFoundSnafu, TableMetadataManagerSnafu, TableNotFoundSnafu,
|
||||
UpgradeCatalogManagerRefSnafu,
|
||||
};
|
||||
use crate::insert::InserterRef;
|
||||
use crate::statement::copy_database::{COPY_DATABASE_TIME_END_KEY, COPY_DATABASE_TIME_START_KEY};
|
||||
@@ -251,6 +255,29 @@ impl StatementExecutor {
|
||||
)
|
||||
.await
|
||||
}
|
||||
Statement::ShowCreateDatabase(show) => {
|
||||
let (catalog, database) =
|
||||
idents_to_full_database_name(&show.database_name, &query_ctx)
|
||||
.map_err(BoxedError::new)
|
||||
.context(ExternalSnafu)?;
|
||||
let table_metadata_manager = self
|
||||
.catalog_manager
|
||||
.as_any()
|
||||
.downcast_ref::<KvBackendCatalogManager>()
|
||||
.map(|manager| manager.table_metadata_manager_ref().clone())
|
||||
.context(UpgradeCatalogManagerRefSnafu)?;
|
||||
let opts: HashMap<String, String> = table_metadata_manager
|
||||
.schema_manager()
|
||||
.get(SchemaNameKey::new(&catalog, &database))
|
||||
.await
|
||||
.context(TableMetadataManagerSnafu)?
|
||||
.context(SchemaNotFoundSnafu {
|
||||
schema_info: &database,
|
||||
})?
|
||||
.into();
|
||||
|
||||
self.show_create_database(&database, opts.into()).await
|
||||
}
|
||||
Statement::ShowCreateTable(show) => {
|
||||
let (catalog, schema, table) =
|
||||
table_idents_to_full_name(&show.table_name, &query_ctx)
|
||||
|
||||
@@ -26,6 +26,7 @@ use sql::statements::show::{
|
||||
ShowColumns, ShowCreateFlow, ShowCreateView, ShowDatabases, ShowFlows, ShowIndex, ShowKind,
|
||||
ShowTableStatus, ShowTables, ShowVariables, ShowViews,
|
||||
};
|
||||
use sql::statements::OptionMap;
|
||||
use table::metadata::TableType;
|
||||
use table::table_name::TableName;
|
||||
use table::TableRef;
|
||||
@@ -92,6 +93,15 @@ impl StatementExecutor {
|
||||
.context(ExecuteStatementSnafu)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub async fn show_create_database(
|
||||
&self,
|
||||
database_name: &str,
|
||||
opts: OptionMap,
|
||||
) -> Result<Output> {
|
||||
query::sql::show_create_database(database_name, opts).context(ExecuteStatementSnafu)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub async fn show_create_table(
|
||||
&self,
|
||||
@@ -118,8 +128,7 @@ impl StatementExecutor {
|
||||
|
||||
let partitions = create_partitions_stmt(partitions)?;
|
||||
|
||||
query::sql::show_create_table(table, partitions, query_ctx)
|
||||
.context(error::ExecuteStatementSnafu)
|
||||
query::sql::show_create_table(table, partitions, query_ctx).context(ExecuteStatementSnafu)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
|
||||
@@ -52,12 +52,13 @@ pub use show_create_table::create_table_stmt;
|
||||
use snafu::{ensure, OptionExt, ResultExt};
|
||||
use sql::ast::Ident;
|
||||
use sql::parser::ParserContext;
|
||||
use sql::statements::create::{CreateFlow, CreateView, Partitions};
|
||||
use sql::statements::create::{CreateDatabase, CreateFlow, CreateView, Partitions};
|
||||
use sql::statements::show::{
|
||||
ShowColumns, ShowDatabases, ShowFlows, ShowIndex, ShowKind, ShowTableStatus, ShowTables,
|
||||
ShowVariables, ShowViews,
|
||||
};
|
||||
use sql::statements::statement::Statement;
|
||||
use sql::statements::OptionMap;
|
||||
use sqlparser::ast::ObjectName;
|
||||
use table::requests::{FILE_TABLE_LOCATION_KEY, FILE_TABLE_PATTERN_KEY};
|
||||
use table::TableRef;
|
||||
@@ -136,6 +137,17 @@ static DESCRIBE_TABLE_OUTPUT_SCHEMA: Lazy<Arc<Schema>> = Lazy::new(|| {
|
||||
]))
|
||||
});
|
||||
|
||||
static SHOW_CREATE_DATABASE_OUTPUT_SCHEMA: Lazy<Arc<Schema>> = Lazy::new(|| {
|
||||
Arc::new(Schema::new(vec![
|
||||
ColumnSchema::new("Database", ConcreteDataType::string_datatype(), false),
|
||||
ColumnSchema::new(
|
||||
"Create Database",
|
||||
ConcreteDataType::string_datatype(),
|
||||
false,
|
||||
),
|
||||
]))
|
||||
});
|
||||
|
||||
static SHOW_CREATE_TABLE_OUTPUT_SCHEMA: Lazy<Arc<Schema>> = Lazy::new(|| {
|
||||
Arc::new(Schema::new(vec![
|
||||
ColumnSchema::new("Table", ConcreteDataType::string_datatype(), false),
|
||||
@@ -668,6 +680,26 @@ pub async fn show_status(_query_ctx: QueryContextRef) -> Result<Output> {
|
||||
Ok(Output::new_with_record_batches(records))
|
||||
}
|
||||
|
||||
pub fn show_create_database(database_name: &str, options: OptionMap) -> Result<Output> {
|
||||
let stmt = CreateDatabase {
|
||||
name: ObjectName(vec![Ident {
|
||||
value: database_name.to_string(),
|
||||
quote_style: None,
|
||||
}]),
|
||||
if_not_exists: true,
|
||||
options,
|
||||
};
|
||||
let sql = format!("{stmt}");
|
||||
let columns = vec![
|
||||
Arc::new(StringVector::from(vec![database_name.to_string()])) as _,
|
||||
Arc::new(StringVector::from(vec![sql])) as _,
|
||||
];
|
||||
let records =
|
||||
RecordBatches::try_from_columns(SHOW_CREATE_DATABASE_OUTPUT_SCHEMA.clone(), columns)
|
||||
.context(error::CreateRecordBatchSnafu)?;
|
||||
Ok(Output::new_with_record_batches(records))
|
||||
}
|
||||
|
||||
pub fn show_create_table(
|
||||
table: TableRef,
|
||||
partitions: Option<Partitions>,
|
||||
|
||||
@@ -21,8 +21,9 @@ use crate::error::{
|
||||
};
|
||||
use crate::parser::ParserContext;
|
||||
use crate::statements::show::{
|
||||
ShowColumns, ShowCreateFlow, ShowCreateTable, ShowCreateView, ShowDatabases, ShowFlows,
|
||||
ShowIndex, ShowKind, ShowStatus, ShowTableStatus, ShowTables, ShowVariables, ShowViews,
|
||||
ShowColumns, ShowCreateDatabase, ShowCreateFlow, ShowCreateTable, ShowCreateView,
|
||||
ShowDatabases, ShowFlows, ShowIndex, ShowKind, ShowStatus, ShowTableStatus, ShowTables,
|
||||
ShowVariables, ShowViews,
|
||||
};
|
||||
use crate::statements::statement::Statement;
|
||||
|
||||
@@ -74,7 +75,9 @@ impl<'a> ParserContext<'a> {
|
||||
// SHOW {INDEX | INDEXES | KEYS}
|
||||
self.parse_show_index()
|
||||
} else if self.consume_token("CREATE") {
|
||||
if self.consume_token("TABLE") {
|
||||
if self.consume_token("DATABASE") || self.consume_token("SCHEMA") {
|
||||
self.parse_show_create_database()
|
||||
} else if self.consume_token("TABLE") {
|
||||
self.parse_show_create_table()
|
||||
} else if self.consume_token("FLOW") {
|
||||
self.parse_show_create_flow()
|
||||
@@ -109,6 +112,25 @@ impl<'a> ParserContext<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_show_create_database(&mut self) -> Result<Statement> {
|
||||
let raw_database_name =
|
||||
self.parse_object_name()
|
||||
.with_context(|_| error::UnexpectedSnafu {
|
||||
expected: "a database name",
|
||||
actual: self.peek_token_as_string(),
|
||||
})?;
|
||||
let database_name = Self::canonicalize_object_name(raw_database_name);
|
||||
ensure!(
|
||||
!database_name.0.is_empty(),
|
||||
InvalidDatabaseNameSnafu {
|
||||
name: database_name.to_string(),
|
||||
}
|
||||
);
|
||||
Ok(Statement::ShowCreateDatabase(ShowCreateDatabase {
|
||||
database_name,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Parse SHOW CREATE TABLE statement
|
||||
fn parse_show_create_table(&mut self) -> Result<Statement> {
|
||||
let raw_table_name = self
|
||||
|
||||
@@ -161,6 +161,19 @@ impl Display for ShowTableStatus {
|
||||
}
|
||||
}
|
||||
|
||||
/// SQL structure for `SHOW CREATE DATABASE`.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut)]
|
||||
pub struct ShowCreateDatabase {
|
||||
pub database_name: ObjectName,
|
||||
}
|
||||
|
||||
impl Display for ShowCreateDatabase {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let database_name = &self.database_name;
|
||||
write!(f, r#"SHOW CREATE DATABASE {database_name}"#)
|
||||
}
|
||||
}
|
||||
|
||||
/// SQL structure for `SHOW CREATE TABLE`.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut)]
|
||||
pub struct ShowCreateTable {
|
||||
|
||||
@@ -32,8 +32,9 @@ use crate::statements::insert::Insert;
|
||||
use crate::statements::query::Query;
|
||||
use crate::statements::set_variables::SetVariables;
|
||||
use crate::statements::show::{
|
||||
ShowColumns, ShowCreateFlow, ShowCreateTable, ShowCreateView, ShowDatabases, ShowFlows,
|
||||
ShowIndex, ShowKind, ShowStatus, ShowTableStatus, ShowTables, ShowVariables, ShowViews,
|
||||
ShowColumns, ShowCreateDatabase, ShowCreateFlow, ShowCreateTable, ShowCreateView,
|
||||
ShowDatabases, ShowFlows, ShowIndex, ShowKind, ShowStatus, ShowTableStatus, ShowTables,
|
||||
ShowVariables, ShowViews,
|
||||
};
|
||||
use crate::statements::tql::Tql;
|
||||
use crate::statements::truncate::TruncateTable;
|
||||
@@ -84,6 +85,8 @@ pub enum Statement {
|
||||
ShowCollation(ShowKind),
|
||||
// SHOW INDEX
|
||||
ShowIndex(ShowIndex),
|
||||
// SHOW CREATE DATABASE
|
||||
ShowCreateDatabase(ShowCreateDatabase),
|
||||
// SHOW CREATE TABLE
|
||||
ShowCreateTable(ShowCreateTable),
|
||||
// SHOW CREATE FLOW
|
||||
@@ -139,6 +142,7 @@ impl Display for Statement {
|
||||
Statement::ShowCreateTable(s) => s.fmt(f),
|
||||
Statement::ShowCreateFlow(s) => s.fmt(f),
|
||||
Statement::ShowFlows(s) => s.fmt(f),
|
||||
Statement::ShowCreateDatabase(s) => s.fmt(f),
|
||||
Statement::ShowCreateView(s) => s.fmt(f),
|
||||
Statement::ShowViews(s) => s.fmt(f),
|
||||
Statement::ShowStatus(s) => s.fmt(f),
|
||||
|
||||
@@ -26,6 +26,17 @@ SHOW FULL DATABASES;
|
||||
| public | |
|
||||
+--------------------+----------+
|
||||
|
||||
SHOW CREATE DATABASE mydb;
|
||||
|
||||
+----------+------------------------------------+
|
||||
| Database | Create Database |
|
||||
+----------+------------------------------------+
|
||||
| mydb | CREATE DATABASE IF NOT EXISTS mydb |
|
||||
| | WITH( |
|
||||
| | ttl = '1h' |
|
||||
| | ) |
|
||||
+----------+------------------------------------+
|
||||
|
||||
USE mydb;
|
||||
|
||||
Affected Rows: 0
|
||||
|
||||
@@ -4,6 +4,8 @@ SHOW DATABASES;
|
||||
|
||||
SHOW FULL DATABASES;
|
||||
|
||||
SHOW CREATE DATABASE mydb;
|
||||
|
||||
USE mydb;
|
||||
|
||||
CREATE TABLE test(host STRING, cpu DOUBLE, ts TIMESTAMP TIME INDEX);
|
||||
|
||||
Reference in New Issue
Block a user