feat: implement DESCRIBE TABLE (#558)

Also need to support describe table in other catalog/schema
This commit is contained in:
Igor Morozov
2022-11-18 16:34:00 +08:00
committed by GitHub
parent 6d762aa9dc
commit e1f326295f
15 changed files with 620 additions and 7 deletions
+40
View File
@@ -21,8 +21,10 @@ use sqlparser::tokenizer::{Token, Tokenizer};
use crate::error::{
self, InvalidDatabaseNameSnafu, InvalidTableNameSnafu, Result, SyntaxSnafu, TokenizerSnafu,
};
use crate::statements::describe::DescribeTable;
use crate::statements::show::{ShowCreateTable, ShowDatabases, ShowKind, ShowTables};
use crate::statements::statement::Statement;
use crate::statements::table_idents_to_full_name;
/// GrepTime SQL parser context, a simple wrapper for Datafusion SQL parser.
pub struct ParserContext<'a> {
@@ -85,6 +87,11 @@ impl<'a> ParserContext<'a> {
self.parse_show()
}
Keyword::DESCRIBE | Keyword::DESC => {
self.parser.next_token();
self.parse_describe()
}
Keyword::INSERT => self.parse_insert(),
Keyword::SELECT | Keyword::WITH | Keyword::VALUES => self.parse_query(),
@@ -217,6 +224,39 @@ impl<'a> ParserContext<'a> {
Ok(Statement::ShowTables(ShowTables { kind, database }))
}
/// Parses DESCRIBE statements
fn parse_describe(&mut self) -> Result<Statement> {
if self.matches_keyword(Keyword::TABLE) {
self.parser.next_token();
self.parse_describe_table()
} else {
self.unsupported(self.peek_token_as_string())
}
}
fn parse_describe_table(&mut self) -> Result<Statement> {
let table_idents =
self.parser
.parse_object_name()
.with_context(|_| error::UnexpectedSnafu {
sql: self.sql,
expected: "a table name",
actual: self.peek_token_as_string(),
})?;
ensure!(
!table_idents.0.is_empty(),
InvalidTableNameSnafu {
name: table_idents.to_string(),
}
);
let (catalog_name, schema_name, table_name) = table_idents_to_full_name(&table_idents)?;
Ok(Statement::DescribeTable(DescribeTable {
catalog_name,
schema_name,
table_name,
}))
}
fn parse_explain(&mut self) -> Result<Statement> {
todo!()
}
+1
View File
@@ -14,6 +14,7 @@
pub mod alter;
pub mod create;
pub mod describe;
pub mod insert;
pub mod query;
pub mod show;
+102
View File
@@ -0,0 +1,102 @@
// Copyright 2022 Greptime Team
//
// 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.
/// SQL structure for `DESCRIBE TABLE`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DescribeTable {
pub catalog_name: String,
pub schema_name: String,
pub table_name: String,
}
impl DescribeTable {
/// Creates a statement for `DESCRIBE TABLE`
pub fn new(catalog_name: String, schema_name: String, table_name: String) -> Self {
DescribeTable {
catalog_name,
schema_name,
table_name,
}
}
}
#[cfg(test)]
mod tests {
use std::assert_matches::assert_matches;
use sqlparser::dialect::GenericDialect;
use crate::parser::ParserContext;
use crate::statements::statement::Statement;
#[test]
pub fn test_describe_table() {
let sql = "DESCRIBE TABLE test";
let stmts: Vec<Statement> =
ParserContext::create_with_dialect(sql, &GenericDialect {}).unwrap();
assert_eq!(1, stmts.len());
assert_matches!(&stmts[0], Statement::DescribeTable { .. });
match &stmts[0] {
Statement::DescribeTable(show) => {
assert_eq!(show.table_name.as_str(), "test");
}
_ => {
unreachable!();
}
}
}
#[test]
pub fn test_describe_schema_table() {
let sql = "DESCRIBE TABLE test_schema.test";
let stmts: Vec<Statement> =
ParserContext::create_with_dialect(sql, &GenericDialect {}).unwrap();
assert_eq!(1, stmts.len());
assert_matches!(&stmts[0], Statement::DescribeTable { .. });
match &stmts[0] {
Statement::DescribeTable(show) => {
assert_eq!(show.schema_name.as_str(), "test_schema");
assert_eq!(show.table_name.as_str(), "test");
}
_ => {
unreachable!();
}
}
}
#[test]
pub fn test_describe_catalog_schema_table() {
let sql = "DESCRIBE TABLE test_catalog.test_schema.test";
let stmts: Vec<Statement> =
ParserContext::create_with_dialect(sql, &GenericDialect {}).unwrap();
assert_eq!(1, stmts.len());
assert_matches!(&stmts[0], Statement::DescribeTable { .. });
match &stmts[0] {
Statement::DescribeTable(show) => {
assert_eq!(show.catalog_name.as_str(), "test_catalog");
assert_eq!(show.schema_name.as_str(), "test_schema");
assert_eq!(show.table_name.as_str(), "test");
}
_ => {
unreachable!();
}
}
}
#[test]
pub fn test_describe_missing_table_name() {
let sql = "DESCRIBE TABLE";
ParserContext::create_with_dialect(sql, &GenericDialect {}).unwrap_err();
}
}
+6
View File
@@ -17,6 +17,7 @@ use sqlparser::parser::ParserError;
use crate::statements::alter::AlterTable;
use crate::statements::create::{CreateDatabase, CreateTable};
use crate::statements::describe::DescribeTable;
use crate::statements::insert::Insert;
use crate::statements::query::Query;
use crate::statements::show::{ShowCreateTable, ShowDatabases, ShowTables};
@@ -40,6 +41,8 @@ pub enum Statement {
ShowTables(ShowTables),
// SHOW CREATE TABLE
ShowCreateTable(ShowCreateTable),
// DESCRIBE TABLE
DescribeTable(DescribeTable),
}
/// Converts Statement to sqlparser statement
@@ -57,6 +60,9 @@ impl TryFrom<Statement> for SpStatement {
Statement::ShowCreateTable(_) => Err(ParserError::ParserError(
"sqlparser does not support SHOW CREATE TABLE query.".to_string(),
)),
Statement::DescribeTable(_) => Err(ParserError::ParserError(
"sqlparser does not support DESCRIBE TABLE query.".to_string(),
)),
Statement::Query(s) => Ok(SpStatement::Query(Box::new(s.inner))),
Statement::Insert(i) => Ok(i.inner),
Statement::CreateDatabase(_) | Statement::CreateTable(_) | Statement::Alter(_) => {