Skip to content

Commit

Permalink
feat: support like syntax in show tables statement (apache#331)
Browse files Browse the repository at this point in the history
* Show tables statement support like syntax
  • Loading branch information
QuintinTao authored Nov 8, 2022
1 parent 2b04cb9 commit a2b4b08
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 26 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

98 changes: 86 additions & 12 deletions interpreters/src/show.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ use arrow::{
};
use async_trait::async_trait;
use catalog::{manager::ManagerRef, schema::Schema, Catalog};
use regex::Regex;
use snafu::{Backtrace, OptionExt, ResultExt, Snafu};
use sql::{
ast::ShowCreateObject,
plan::{ShowCreatePlan, ShowPlan},
plan::{ShowCreatePlan, ShowPlan, ShowTablesPlan},
};

use crate::{
Expand Down Expand Up @@ -94,16 +95,27 @@ impl ShowInterpreter {
show_create.execute_show_create()
}

fn show_tables(ctx: Context, catalog_manager: ManagerRef) -> Result<Output> {
fn show_tables(
ctx: Context,
catalog_manager: ManagerRef,
plan: ShowTablesPlan,
) -> Result<Output> {
let schema = get_default_schema(&ctx, &catalog_manager)?;

let tables_names = schema
.all_tables()
.context(FetchTables)?
.iter()
.map(|t| t.name().to_string())
.collect::<Vec<_>>();

let tables_names = match plan.pattern {
Some(sc) => schema
.all_tables()
.context(FetchTables)?
.iter()
.filter(|t| is_table_matched(t.name(), &sc).unwrap())
.map(|t| t.name().to_string())
.collect::<Vec<_>>(),
None => schema
.all_tables()
.context(FetchTables)?
.iter()
.map(|t| t.name().to_string())
.collect::<Vec<_>>(),
};
let schema = DataSchema::new(vec![Field::new(
SHOW_TABLES_COLUMN_SCHEMA,
DataType::Utf8,
Expand Down Expand Up @@ -146,13 +158,24 @@ impl ShowInterpreter {
}
}

fn is_table_matched(str: &str, search_re: &str) -> Result<bool> {
let regex_str = search_re.replace('_', ".");
let regex_st = if regex_str.contains('%') {
regex_str.replace('%', ".*")
} else {
format!("^{}$", &regex_str)
};
let re = Regex::new(&regex_st).unwrap();
Ok(re.is_match(str))
}

#[async_trait]
impl Interpreter for ShowInterpreter {
async fn execute(self: Box<Self>) -> InterpreterResult<Output> {
match self.plan {
ShowPlan::ShowCreatePlan(t) => Self::show_create(t).context(ShowCreateTable),
ShowPlan::ShowTables => {
Self::show_tables(self.ctx, self.catalog_manager).context(ShowTables)
ShowPlan::ShowTablesPlan(t) => {
Self::show_tables(self.ctx, self.catalog_manager, t).context(ShowTables)
}
ShowPlan::ShowDatabase => {
Self::show_databases(self.ctx, self.catalog_manager).context(ShowDatabases)
Expand Down Expand Up @@ -188,3 +211,54 @@ fn get_default_schema(
name: default_schema,
})
}

#[cfg(test)]
mod tests {
use crate::show::is_table_matched;
#[test]

fn test_is_table_matched() {
assert_eq!(
"true".to_string(),
is_table_matched("01_system_table1", "01%")
.unwrap()
.to_string()
);
assert_eq!(
"true".to_string(),
is_table_matched("01_system_table1", "01_%")
.unwrap()
.to_string()
);
assert_eq!(
"false".to_string(),
is_table_matched("01_system_table1", "01_system_table")
.unwrap()
.to_string()
);
assert_eq!(
"true".to_string(),
is_table_matched("01_system_table1", "01_system_table1")
.unwrap()
.to_string()
);
assert_eq!(
"true".to_string(),
is_table_matched("01_system_table1", "01_system_table.")
.unwrap()
.to_string()
);
assert_eq!(
"false".to_string(),
is_table_matched("01_system_table1", "01_system_tabl.")
.unwrap()
.to_string()
);
assert_eq!(
"true".to_string(),
is_table_matched("01_system_table1", "%system%")
.unwrap()
.to_string()
);
}
}
8 changes: 7 additions & 1 deletion sql/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub enum Statement {
/// SHOW CREATE TABLE
ShowCreate(ShowCreate),
ShowDatabases,
ShowTables,
ShowTables(ShowTables),
Exists(ExistsTable),
}

Expand Down Expand Up @@ -96,6 +96,12 @@ pub struct AlterAddColumn {
pub columns: Vec<ColumnDef>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct ShowTables {
/// Like pattern
pub pattern: Option<String>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct ShowCreate {
pub obj_type: ShowCreateObject,
Expand Down
15 changes: 13 additions & 2 deletions sql/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use table_engine::ANALYTIC_ENGINE_TYPE;

use crate::ast::{
AlterAddColumn, AlterModifySetting, CreateTable, DescribeTable, DropTable, ExistsTable,
ShowCreate, ShowCreateObject, Statement,
ShowCreate, ShowCreateObject, ShowTables, Statement,
};

define_result!(ParserError);
Expand Down Expand Up @@ -223,7 +223,7 @@ impl<'a> Parser<'a> {

pub fn parse_show(&mut self) -> Result<Statement> {
if self.consume_token("TABLES") {
Ok(Statement::ShowTables)
Ok(self.parse_show_tables()?)
} else if self.consume_token("DATABASES") {
Ok(Statement::ShowDatabases)
} else if self.consume_token("CREATE") {
Expand All @@ -233,6 +233,17 @@ impl<'a> Parser<'a> {
}
}

fn parse_show_tables(&mut self) -> Result<Statement> {
let pattern = match self.parser.next_token() {
Token::Word(w) => match w.keyword {
Keyword::LIKE => Some(self.parser.parse_literal_string()?),
_ => None,
},
_ => None,
};
Ok(Statement::ShowTables(ShowTables { pattern }))
}

fn parse_show_create(&mut self) -> Result<Statement> {
let obj_type = match self.parser.expect_one_of_keywords(&[Keyword::TABLE])? {
Keyword::TABLE => Ok(ShowCreateObject::Table),
Expand Down
8 changes: 7 additions & 1 deletion sql/src/plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,12 +156,18 @@ pub struct ShowCreatePlan {
pub obj_type: ShowCreateObject,
}

#[derive(Debug, PartialEq, Eq)]
pub struct ShowTablesPlan {
/// Like pattern
pub pattern: Option<String>,
}

#[derive(Debug)]
pub enum ShowPlan {
/// show create table
ShowCreatePlan(ShowCreatePlan),
/// show tables
ShowTables,
ShowTablesPlan(ShowTablesPlan),
/// show database
ShowDatabase,
}
Expand Down
20 changes: 13 additions & 7 deletions sql/src/planner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ use table_engine::table::TableRef;
use crate::{
ast::{
AlterAddColumn, AlterModifySetting, CreateTable, DescribeTable, DropTable, ExistsTable,
ShowCreate, Statement, TableName,
ShowCreate, ShowTables, Statement, TableName,
},
container::TableReference,
parser,
plan::{
AlterTableOperation, AlterTablePlan, CreateTablePlan, DescribeTablePlan, DropTablePlan,
ExistsTablePlan, InsertPlan, Plan, QueryPlan, ShowCreatePlan, ShowPlan,
ExistsTablePlan, InsertPlan, Plan, QueryPlan, ShowCreatePlan, ShowPlan, ShowTablesPlan,
},
promql::{ColumnNames, Expr as PromExpr},
provider::{ContextProviderAdapter, MetaProvider},
Expand Down Expand Up @@ -253,7 +253,7 @@ impl<'a, P: MetaProvider> Planner<'a, P> {
Statement::AlterModifySetting(s) => planner.alter_modify_setting_to_plan(s),
Statement::AlterAddColumn(s) => planner.alter_add_column_to_plan(s),
Statement::ShowCreate(s) => planner.show_create_to_plan(s),
Statement::ShowTables => planner.show_tables_to_plan(),
Statement::ShowTables(s) => planner.show_tables_to_plan(s),
Statement::ShowDatabases => planner.show_databases_to_plan(),
Statement::Exists(s) => planner.exists_table_to_plan(s),
}
Expand Down Expand Up @@ -614,8 +614,11 @@ impl<'a, P: MetaProvider> PlannerDelegate<'a, P> {
Ok(Plan::Show(ShowPlan::ShowCreatePlan(plan)))
}

fn show_tables_to_plan(&self) -> Result<Plan> {
Ok(Plan::Show(ShowPlan::ShowTables))
fn show_tables_to_plan(&self, show_tables: ShowTables) -> Result<Plan> {
let plan = ShowTablesPlan {
pattern: show_tables.pattern,
};
Ok(Plan::Show(ShowPlan::ShowTablesPlan(plan)))
}

fn show_databases_to_plan(&self) -> Result<Plan> {
Expand Down Expand Up @@ -1649,14 +1652,17 @@ mod tests {
)
.unwrap();
}

#[test]
fn test_show_tables_statement_to_plan() {
let sql = "SHOW TABLES;";
quick_test(
sql,
r#"Show(
ShowTables,
ShowTablesPlan(
ShowTablesPlan {
pattern: None,
},
),
)"#,
)
.unwrap();
Expand Down
6 changes: 4 additions & 2 deletions tests/cases/local/01_system/system_tables.result
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ timestamp,catalog,schema,table_name,engine,
Timestamp(Timestamp(0)),String(StringBytes(b"ceresdb")),String(StringBytes(b"public")),String(StringBytes(b"01_system_table1")),String(StringBytes(b"Analytic")),


SHOW TABLES `name` LIKE '01_system_table1';
SHOW TABLES LIKE '01%';

Tables,
String(StringBytes(b"01_system_table1")),

Failed to execute query, err: Server(ServerError { code: 400, msg: "failed to parse sql. Caused by: Invalid sql, sql: SHOW TABLES `name` LIKE '01_system_table1';, err:sql parser error: Expected end of statement, found: `name`" })

2 changes: 1 addition & 1 deletion tests/cases/local/01_system/system_tables.sql
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ WHERE


-- FIXME
SHOW TABLES `name` LIKE '01_system_table1';
SHOW TABLES LIKE '01%';

0 comments on commit a2b4b08

Please sign in to comment.