support create external table

This commit is contained in:
Zhiyuan Zheng 2019-04-08 21:36:02 +08:00
parent d1b5668fd3
commit f0f6082eff
3 changed files with 150 additions and 49 deletions

1
sql.sql Normal file
View file

@ -0,0 +1 @@
CREATE EXTERNAL TABLE T (X INT) STORED AS TEXTFILE LOCATION '/home/admin/a.csv';

View file

@ -250,6 +250,15 @@ pub enum SQLStatement {
/// Optional schema /// Optional schema
columns: Vec<SQLColumnDef>, columns: Vec<SQLColumnDef>,
}, },
/// CREATE EXTERNAL TABLE
SQLCreateExternalTable {
/// Table name
name: SQLObjectName,
/// Optional schema
columns: Vec<SQLColumnDef>,
file_format: FileFormat,
location: String,
},
/// ALTER TABLE /// ALTER TABLE
SQLAlterTable { SQLAlterTable {
/// Table name /// Table name
@ -370,6 +379,17 @@ impl ToString for SQLStatement {
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join(", ") .join(", ")
), ),
SQLStatement::SQLCreateExternalTable { name, columns, file_format, location } => format!(
"CREATE TABLE {} ({}) STORED AS {} LOCATION {}",
name.to_string(),
columns
.iter()
.map(|c| c.to_string())
.collect::<Vec<String>>()
.join(", "),
file_format.to_string(),
location
),
SQLStatement::SQLAlterTable { name, operation } => { SQLStatement::SQLAlterTable { name, operation } => {
format!("ALTER TABLE {} {}", name.to_string(), operation.to_string()) format!("ALTER TABLE {} {}", name.to_string(), operation.to_string())
} }
@ -429,3 +449,53 @@ impl ToString for SQLColumnDef {
s s
} }
} }
/// External table's available file format
#[derive(Debug, Clone, PartialEq)]
pub enum FileFormat {
TEXTFILE,
SEQUENCEFILE,
ORC,
PARQUET,
AVRO,
RCFILE,
JSONFILE,
}
impl ToString for FileFormat {
fn to_string(&self) -> String {
use self::FileFormat::*;
match self {
TEXTFILE => "TEXTFILE".to_string(),
SEQUENCEFILE => "SEQUENCEFILE".to_string(),
ORC => "ORC".to_string(),
PARQUET => "PARQUET".to_string(),
AVRO => "AVRO".to_string(),
RCFILE => "RCFILE".to_string(),
JSONFILE => "TEXTFILE".to_string(),
}
}
}
use std::str::FromStr;
use sqlparser::ParserError;
impl FromStr for FileFormat {
type Err = ParserError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
use self::FileFormat::*;
match s {
"TEXTFILE" => Ok(TEXTFILE),
"SEQUENCEFILE" => Ok(SEQUENCEFILE),
"ORC" => Ok(ORC),
"PARQUET" => Ok(PARQUET),
"AVRO" => Ok(AVRO),
"RCFILE" => Ok(RCFILE),
"JSONFILE" => Ok(JSONFILE),
_ => Err(ParserError::ParserError(format!(
"Unexpected token for file format: {}",
s
)))
}
}
}

View file

@ -620,6 +620,8 @@ impl Parser {
} else if self.parse_keyword("MATERIALIZED") || self.parse_keyword("VIEW") { } else if self.parse_keyword("MATERIALIZED") || self.parse_keyword("VIEW") {
self.prev_token(); self.prev_token();
self.parse_create_view() self.parse_create_view()
} else if self.parse_keyword("EXTERNAL") {
self.parse_create_external_table()
} else { } else {
parser_err!(format!( parser_err!(format!(
"Unexpected token after CREATE: {:?}", "Unexpected token after CREATE: {:?}",
@ -628,6 +630,25 @@ impl Parser {
} }
} }
pub fn parse_create_external_table(&mut self) -> Result<SQLStatement, ParserError> {
self.expect_keyword("TABLE")?;
let table_name = self.parse_object_name()?;
let columns = self.parse_columns()?;
self.expect_keyword("STORED")?;
self.expect_keyword("AS")?;
let file_format = self.parse_identifier()?.parse::<FileFormat>()?;
self.expect_keyword("LOCATION")?;
let location = self.parse_literal_string()?;
Ok(SQLStatement::SQLCreateExternalTable {
name: table_name,
columns,
file_format,
location
})
}
pub fn parse_create_view(&mut self) -> Result<SQLStatement, ParserError> { pub fn parse_create_view(&mut self) -> Result<SQLStatement, ParserError> {
let materialized = self.parse_keyword("MATERIALIZED"); let materialized = self.parse_keyword("MATERIALIZED");
self.expect_keyword("VIEW")?; self.expect_keyword("VIEW")?;
@ -650,8 +671,20 @@ impl Parser {
pub fn parse_create_table(&mut self) -> Result<SQLStatement, ParserError> { pub fn parse_create_table(&mut self) -> Result<SQLStatement, ParserError> {
let table_name = self.parse_object_name()?; let table_name = self.parse_object_name()?;
// parse optional column list (schema) // parse optional column list (schema)
let columns = self.parse_columns()?;
Ok(SQLStatement::SQLCreateTable {
name: table_name,
columns,
})
}
fn parse_columns(&mut self) -> Result<Vec<SQLColumnDef>, ParserError> {
let mut columns = vec![]; let mut columns = vec![];
if self.consume_token(&Token::LParen) { if !self.consume_token(&Token::LParen) {
return Ok(columns);
}
loop { loop {
match self.next_token() { match self.next_token() {
Some(Token::SQLWord(column_name)) => { Some(Token::SQLWord(column_name)) => {
@ -675,7 +708,7 @@ impl Parser {
columns.push(SQLColumnDef { columns.push(SQLColumnDef {
name: column_name.as_sql_ident(), name: column_name.as_sql_ident(),
data_type: data_type, data_type,
allow_null, allow_null,
is_primary, is_primary,
is_unique, is_unique,
@ -699,11 +732,8 @@ impl Parser {
} }
} }
} }
}
Ok(SQLStatement::SQLCreateTable { Ok(columns)
name: table_name,
columns,
})
} }
pub fn parse_table_key(&mut self, constraint_name: SQLIdent) -> Result<TableKey, ParserError> { pub fn parse_table_key(&mut self, constraint_name: SQLIdent) -> Result<TableKey, ParserError> {