mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-05-18 22:10:42 +00:00
feat: support Create Table ... Like (#3372)
* feat: support `Create Table ... Like` * fix: `check_permission` for `Create Table ... Like` * style: renaming `name` -> `table_name` & `target` -> `source_name` and make `Create Table ... Like` testcase more complicated * rebase * avoid _ fn Signed-off-by: tison <wander4096@gmail.com> --------- Signed-off-by: tison <wander4096@gmail.com> Co-authored-by: tison <wander4096@gmail.com>
This commit is contained in:
@@ -75,19 +75,23 @@ impl<'a> ParserContext<'a> {
|
||||
}
|
||||
|
||||
pub fn parse_table_name(sql: &'a str, dialect: &dyn Dialect) -> Result<ObjectName> {
|
||||
let mut parser = Parser::new(dialect)
|
||||
let parser = Parser::new(dialect)
|
||||
.with_options(ParserOptions::new().with_trailing_commas(true))
|
||||
.try_with_sql(sql)
|
||||
.context(SyntaxSnafu)?;
|
||||
ParserContext { parser, sql }.intern_parse_table_name()
|
||||
}
|
||||
|
||||
let raw_table_name = parser.parse_object_name().context(error::UnexpectedSnafu {
|
||||
sql,
|
||||
expected: "a table name",
|
||||
actual: parser.peek_token().to_string(),
|
||||
})?;
|
||||
let table_name = Self::canonicalize_object_name(raw_table_name);
|
||||
|
||||
Ok(table_name)
|
||||
pub(crate) fn intern_parse_table_name(&mut self) -> Result<ObjectName> {
|
||||
let raw_table_name = self
|
||||
.parser
|
||||
.parse_object_name()
|
||||
.context(error::UnexpectedSnafu {
|
||||
sql: self.sql,
|
||||
expected: "a table name",
|
||||
actual: self.parser.peek_token().to_string(),
|
||||
})?;
|
||||
Ok(Self::canonicalize_object_name(raw_table_name))
|
||||
}
|
||||
|
||||
pub fn parse_function(sql: &'a str, dialect: &dyn Dialect) -> Result<Expr> {
|
||||
|
||||
@@ -32,7 +32,7 @@ use crate::error::{
|
||||
};
|
||||
use crate::parser::ParserContext;
|
||||
use crate::statements::create::{
|
||||
CreateDatabase, CreateExternalTable, CreateTable, Partitions, TIME_INDEX,
|
||||
CreateDatabase, CreateExternalTable, CreateTable, CreateTableLike, Partitions, TIME_INDEX,
|
||||
};
|
||||
use crate::statements::get_data_type_by_alias_name;
|
||||
use crate::statements::statement::Statement;
|
||||
@@ -66,15 +66,7 @@ impl<'a> ParserContext<'a> {
|
||||
let if_not_exists =
|
||||
self.parser
|
||||
.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
|
||||
let raw_table_name = self
|
||||
.parser
|
||||
.parse_object_name()
|
||||
.context(error::UnexpectedSnafu {
|
||||
sql: self.sql,
|
||||
expected: "a table name",
|
||||
actual: self.peek_token_as_string(),
|
||||
})?;
|
||||
let table_name = Self::canonicalize_object_name(raw_table_name);
|
||||
let table_name = self.intern_parse_table_name()?;
|
||||
let (columns, constraints) = self.parse_columns()?;
|
||||
let engine = self.parse_table_engine(common_catalog::consts::FILE_ENGINE)?;
|
||||
let options = self
|
||||
@@ -136,15 +128,16 @@ impl<'a> ParserContext<'a> {
|
||||
self.parser
|
||||
.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
|
||||
|
||||
let raw_table_name = self
|
||||
.parser
|
||||
.parse_object_name()
|
||||
.context(error::UnexpectedSnafu {
|
||||
sql: self.sql,
|
||||
expected: "a table name",
|
||||
actual: self.peek_token_as_string(),
|
||||
})?;
|
||||
let table_name = Self::canonicalize_object_name(raw_table_name);
|
||||
let table_name = self.intern_parse_table_name()?;
|
||||
|
||||
if self.parser.parse_keyword(Keyword::LIKE) {
|
||||
let source_name = self.intern_parse_table_name()?;
|
||||
|
||||
return Ok(Statement::CreateTableLike(CreateTableLike {
|
||||
table_name,
|
||||
source_name,
|
||||
}));
|
||||
}
|
||||
|
||||
let (columns, constraints) = self.parse_columns()?;
|
||||
|
||||
@@ -739,6 +732,23 @@ mod tests {
|
||||
use crate::dialect::GreptimeDbDialect;
|
||||
use crate::parser::ParseOptions;
|
||||
|
||||
#[test]
|
||||
fn test_parse_create_table_like() {
|
||||
let sql = "CREATE TABLE t1 LIKE t2";
|
||||
let stmts =
|
||||
ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(1, stmts.len());
|
||||
match &stmts[0] {
|
||||
Statement::CreateTableLike(c) => {
|
||||
assert_eq!(c.table_name.to_string(), "t1");
|
||||
assert_eq!(c.source_name.to_string(), "t2");
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_validate_external_table_options() {
|
||||
let sql = "CREATE EXTERNAL TABLE city (
|
||||
|
||||
@@ -219,6 +219,14 @@ pub struct CreateExternalTable {
|
||||
pub engine: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Visit, VisitMut)]
|
||||
pub struct CreateTableLike {
|
||||
/// Table name
|
||||
pub table_name: ObjectName,
|
||||
/// The table that is designated to be imitated by `Like`
|
||||
pub source_name: ObjectName,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::dialect::GreptimeDbDialect;
|
||||
|
||||
@@ -19,7 +19,9 @@ use sqlparser_derive::{Visit, VisitMut};
|
||||
use super::show::ShowVariables;
|
||||
use crate::error::{ConvertToDfStatementSnafu, Error};
|
||||
use crate::statements::alter::AlterTable;
|
||||
use crate::statements::create::{CreateDatabase, CreateExternalTable, CreateTable};
|
||||
use crate::statements::create::{
|
||||
CreateDatabase, CreateExternalTable, CreateTable, CreateTableLike,
|
||||
};
|
||||
use crate::statements::delete::Delete;
|
||||
use crate::statements::describe::DescribeTable;
|
||||
use crate::statements::drop::DropTable;
|
||||
@@ -45,6 +47,8 @@ pub enum Statement {
|
||||
CreateTable(CreateTable),
|
||||
// CREATE EXTERNAL TABLE
|
||||
CreateExternalTable(CreateExternalTable),
|
||||
// CREATE TABLE ... LIKE
|
||||
CreateTableLike(CreateTableLike),
|
||||
// DROP TABLE
|
||||
DropTable(DropTable),
|
||||
// CREATE DATABASE
|
||||
|
||||
Reference in New Issue
Block a user