feat: Frontend show tables and databases (#504)

* feat: Frontend show tables and databases

Co-authored-by: luofucong <luofucong@greptime.com>
This commit is contained in:
LFC
2022-11-15 14:21:50 +08:00
committed by GitHub
parent 6e93c5e1de
commit 2c0d2da5a7
16 changed files with 299 additions and 239 deletions

View File

@@ -1,7 +1,6 @@
use std::any::Any;
use common_error::prelude::*;
use datatypes::arrow::error::ArrowError;
use storage::error::Error as StorageError;
use table::error::Error as TableError;
@@ -233,30 +232,6 @@ pub enum Error {
source: common_time::error::Error,
},
#[snafu(display("Failed to create a new RecordBatch, source: {}", source))]
NewRecordBatch {
#[snafu(backtrace)]
source: common_recordbatch::error::Error,
},
#[snafu(display("Failed to create a new RecordBatches, source: {}", source))]
NewRecordBatches {
#[snafu(backtrace)]
source: common_recordbatch::error::Error,
},
#[snafu(display("Arrow computation error, source: {}", source))]
ArrowComputation {
backtrace: Backtrace,
source: ArrowError,
},
#[snafu(display("Failed to cast an arrow array into vector, source: {}", source))]
CastVector {
#[snafu(backtrace)]
source: datatypes::error::Error,
},
#[snafu(display("Failed to access catalog, source: {}", source))]
Catalog {
#[snafu(backtrace)]
@@ -294,6 +269,12 @@ pub enum Error {
#[snafu(backtrace)]
source: table::error::Error,
},
#[snafu(display("Failed to do vector computation, source: {}", source))]
VectorComputation {
#[snafu(backtrace)]
source: datatypes::error::Error,
},
}
pub type Result<T> = std::result::Result<T, Error>;
@@ -319,10 +300,10 @@ impl ErrorExt for Error {
source.status_code()
}
Error::CastVector { source, .. }
| Error::ColumnDefaultConstraint { source, .. }
Error::ColumnDefaultConstraint { source, .. }
| Error::CreateSchema { source, .. }
| Error::ConvertSchema { source, .. } => source.status_code(),
| Error::ConvertSchema { source, .. }
| Error::VectorComputation { source } => source.status_code(),
Error::ColumnValuesNumberMismatch { .. }
| Error::InvalidSql { .. }
@@ -354,11 +335,8 @@ impl ErrorExt for Error {
Error::StartScriptManager { source } => source.status_code(),
Error::OpenStorageEngine { source } => source.status_code(),
Error::RuntimeResource { .. } => StatusCode::RuntimeResourcesExhausted,
Error::NewRecordBatch { source }
| Error::NewRecordBatches { source }
| Error::CollectRecordBatches { source } => source.status_code(),
Error::CollectRecordBatches { source } => source.status_code(),
Error::ArrowComputation { .. } => StatusCode::Unexpected,
Error::MetaClientInit { source, .. } => source.status_code(),
Error::InsertData { source, .. } => source.status_code(),
Error::EmptyInsertBatch => StatusCode::InvalidArguments,
@@ -403,10 +381,6 @@ mod tests {
})
}
fn throw_arrow_error() -> std::result::Result<(), ArrowError> {
Err(ArrowError::NotYetImplemented("test".to_string()))
}
fn assert_internal_error(err: &Error) {
assert!(err.backtrace_opt().is_some());
assert_eq!(StatusCode::Internal, err.status_code());
@@ -417,17 +391,6 @@ mod tests {
assert_eq!(s.code(), tonic::Code::Internal);
}
#[test]
fn test_arrow_computation_error() {
let err = throw_arrow_error()
.context(ArrowComputationSnafu)
.unwrap_err();
assert!(matches!(err, Error::ArrowComputation { .. }));
assert!(err.backtrace_opt().is_some());
assert_eq!(StatusCode::Unexpected, err.status_code());
}
#[test]
fn test_error() {
let err = throw_query_error().context(ExecuteSqlSnafu).err().unwrap();

View File

@@ -1,23 +1,19 @@
//! sql handler
use catalog::{schema::SchemaProviderRef, CatalogManagerRef, CatalogProviderRef};
use common_catalog::consts::{DEFAULT_CATALOG_NAME, DEFAULT_SCHEMA_NAME};
use catalog::CatalogManagerRef;
use common_query::Output;
use query::sql::{show_databases, show_tables};
use snafu::{OptionExt, ResultExt};
use sql::statements::show::{ShowDatabases, ShowTables};
use table::engine::{EngineContext, TableEngineRef, TableReference};
use table::requests::*;
use table::TableRef;
use crate::error::{
CatalogNotFoundSnafu, CatalogSnafu, GetTableSnafu, Result, SchemaNotFoundSnafu,
TableNotFoundSnafu,
};
use crate::error::{self, GetTableSnafu, Result, TableNotFoundSnafu};
mod alter;
mod create;
mod insert;
mod show;
#[derive(Debug)]
pub enum SqlRequest {
@@ -49,8 +45,12 @@ impl SqlHandler {
SqlRequest::CreateTable(req) => self.create_table(req).await,
SqlRequest::CreateDatabase(req) => self.create_database(req).await,
SqlRequest::Alter(req) => self.alter(req).await,
SqlRequest::ShowDatabases(stmt) => self.show_databases(stmt).await,
SqlRequest::ShowTables(stmt) => self.show_tables(stmt).await,
SqlRequest::ShowDatabases(stmt) => {
show_databases(stmt, self.catalog_manager.clone()).context(error::ExecuteSqlSnafu)
}
SqlRequest::ShowTables(stmt) => {
show_tables(stmt, self.catalog_manager.clone()).context(error::ExecuteSqlSnafu)
}
}
}
@@ -65,29 +65,6 @@ impl SqlHandler {
})
}
pub(crate) fn get_default_catalog(&self) -> Result<CatalogProviderRef> {
self.catalog_manager
.catalog(DEFAULT_CATALOG_NAME)
.context(CatalogSnafu)?
.context(CatalogNotFoundSnafu {
name: DEFAULT_CATALOG_NAME,
})
}
pub(crate) fn get_default_schema(&self) -> Result<SchemaProviderRef> {
self.catalog_manager
.catalog(DEFAULT_CATALOG_NAME)
.context(CatalogSnafu)?
.context(CatalogNotFoundSnafu {
name: DEFAULT_CATALOG_NAME,
})?
.schema(DEFAULT_SCHEMA_NAME)
.context(CatalogSnafu)?
.context(SchemaNotFoundSnafu {
name: DEFAULT_SCHEMA_NAME,
})
}
pub fn table_engine(&self) -> TableEngineRef {
self.table_engine.clone()
}

View File

@@ -1,140 +0,0 @@
use std::sync::Arc;
use common_query::Output;
use common_recordbatch::{RecordBatch, RecordBatches};
use datatypes::arrow::compute;
use datatypes::arrow_array::StringArray;
use datatypes::prelude::ConcreteDataType;
use datatypes::schema::{ColumnSchema, Schema};
use datatypes::vectors::{Helper, StringVector, VectorRef};
use snafu::{ensure, OptionExt, ResultExt};
use sql::statements::show::{ShowDatabases, ShowKind, ShowTables};
use crate::error::{
ArrowComputationSnafu, CastVectorSnafu, CatalogSnafu, NewRecordBatchSnafu,
NewRecordBatchesSnafu, Result, SchemaNotFoundSnafu, UnsupportedExprSnafu,
};
use crate::sql::SqlHandler;
const TABLES_COLUMN: &str = "Tables";
const SCHEMAS_COLUMN: &str = "Schemas";
impl SqlHandler {
fn like_utf8(names: Vec<String>, s: &str) -> Result<VectorRef> {
let array = StringArray::from_slice(&names);
let boolean_array =
compute::like::like_utf8_scalar(&array, s).context(ArrowComputationSnafu)?;
Helper::try_into_vector(
compute::filter::filter(&array, &boolean_array).context(ArrowComputationSnafu)?,
)
.context(CastVectorSnafu)
}
pub(crate) async fn show_databases(&self, stmt: ShowDatabases) -> Result<Output> {
// TODO(dennis): supports WHERE
ensure!(
matches!(stmt.kind, ShowKind::All | ShowKind::Like(_)),
UnsupportedExprSnafu {
name: stmt.kind.to_string(),
}
);
let catalog = self.get_default_catalog()?;
// TODO(dennis): return an iterator or stream would be better.
let schemas = catalog.schema_names().context(CatalogSnafu)?;
let column_schemas = vec![ColumnSchema::new(
SCHEMAS_COLUMN,
ConcreteDataType::string_datatype(),
false,
)];
let schema = Arc::new(Schema::new(column_schemas));
let schemas_vector = if let ShowKind::Like(ident) = stmt.kind {
Self::like_utf8(schemas, &ident.value)?
} else {
Arc::new(StringVector::from(schemas))
};
let columns: Vec<VectorRef> = vec![schemas_vector];
let recordbatch = RecordBatch::new(schema.clone(), columns).context(NewRecordBatchSnafu)?;
Ok(Output::RecordBatches(
RecordBatches::try_new(schema, vec![recordbatch]).context(NewRecordBatchesSnafu)?,
))
}
pub(crate) async fn show_tables(&self, stmt: ShowTables) -> Result<Output> {
// TODO(dennis): supports WHERE
ensure!(
matches!(stmt.kind, ShowKind::All | ShowKind::Like(_)),
UnsupportedExprSnafu {
name: stmt.kind.to_string(),
}
);
let schema = if let Some(name) = &stmt.database {
let catalog = self.get_default_catalog()?;
catalog
.schema(name)
.context(CatalogSnafu)?
.context(SchemaNotFoundSnafu { name })?
} else {
self.get_default_schema()?
};
let tables = schema.table_names().context(CatalogSnafu)?;
let column_schemas = vec![ColumnSchema::new(
TABLES_COLUMN,
ConcreteDataType::string_datatype(),
false,
)];
let schema = Arc::new(Schema::new(column_schemas));
let tables_vector = if let ShowKind::Like(ident) = stmt.kind {
Self::like_utf8(tables, &ident.value)?
} else {
Arc::new(StringVector::from(tables))
};
let columns: Vec<VectorRef> = vec![tables_vector];
let recordbatch = RecordBatch::new(schema.clone(), columns).context(NewRecordBatchSnafu)?;
Ok(Output::RecordBatches(
RecordBatches::try_new(schema, vec![recordbatch]).context(NewRecordBatchesSnafu)?,
))
}
}
#[cfg(test)]
mod tests {
use super::*;
fn assert_vector(expected: Vec<&str>, actual: &VectorRef) {
let actual = actual.as_any().downcast_ref::<StringVector>().unwrap();
assert_eq!(*actual, StringVector::from(expected));
}
#[test]
fn test_like_utf8() {
let names: Vec<String> = vec!["greptime", "hello", "public", "world"]
.into_iter()
.map(|x| x.to_string())
.collect();
let ret = SqlHandler::like_utf8(names.clone(), "%ll%").unwrap();
assert_vector(vec!["hello"], &ret);
let ret = SqlHandler::like_utf8(names.clone(), "%time").unwrap();
assert_vector(vec!["greptime"], &ret);
let ret = SqlHandler::like_utf8(names.clone(), "%ld").unwrap();
assert_vector(vec!["world"], &ret);
let ret = SqlHandler::like_utf8(names, "%").unwrap();
assert_vector(vec!["greptime", "hello", "public", "world"], &ret);
}
}