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:
Kould
2024-03-02 14:34:13 +08:00
committed by GitHub
parent 7d30c2484b
commit 00cbbc97ae
13 changed files with 179 additions and 44 deletions

View File

@@ -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> {

View File

@@ -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 (

View File

@@ -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;

View File

@@ -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