Skip to content

DDL parsing improvements #65

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions src/sqlast/ddl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//! AST types specific to CREATE/ALTER variants of `SQLStatement`
//! (commonly referred to as Data Definition Language, or DDL)
use super::{ASTNode, SQLIdent, SQLObjectName};

/// An `ALTER TABLE` (`SQLStatement::SQLAlterTable`) operation
#[derive(Debug, Clone, PartialEq)]
pub enum AlterTableOperation {
/// `ADD <table_constraint>`
AddConstraint(TableConstraint),
/// TODO: implement `DROP CONSTRAINT <name>`
DropConstraint { name: SQLIdent },
}

impl ToString for AlterTableOperation {
fn to_string(&self) -> String {
match self {
AlterTableOperation::AddConstraint(c) => format!("ADD {}", c.to_string()),
AlterTableOperation::DropConstraint { name } => format!("DROP CONSTRAINT {}", name),
}
}
}

/// A table-level constraint, specified in a `CREATE TABLE` or an
/// `ALTER TABLE ADD <constraint>` statement.
#[derive(Debug, Clone, PartialEq)]
pub enum TableConstraint {
/// `[ CONSTRAINT <name> ] { PRIMARY KEY | UNIQUE } (<columns>)`
Unique {
name: Option<SQLIdent>,
columns: Vec<SQLIdent>,
/// Whether this is a `PRIMARY KEY` or just a `UNIQUE` constraint
is_primary: bool,
},
/// A referential integrity constraint (`[ CONSTRAINT <name> ] FOREIGN KEY (<columns>)
/// REFERENCES <foreign_table> (<referred_columns>)`)
ForeignKey {
name: Option<SQLIdent>,
columns: Vec<SQLIdent>,
foreign_table: SQLObjectName,
referred_columns: Vec<SQLIdent>,
},
/// `[ CONSTRAINT <name> ] CHECK (<expr>)`
Check {
name: Option<SQLIdent>,
expr: Box<ASTNode>,
},
}

impl ToString for TableConstraint {
fn to_string(&self) -> String {
fn format_constraint_name(name: &Option<SQLIdent>) -> String {
name.as_ref()
.map(|name| format!("CONSTRAINT {} ", name))
.unwrap_or_default()
}
match self {
TableConstraint::Unique {
name,
columns,
is_primary,
} => format!(
"{}{} ({})",
format_constraint_name(name),
if *is_primary { "PRIMARY KEY" } else { "UNIQUE" },
columns.join(", ")
),
TableConstraint::ForeignKey {
name,
columns,
foreign_table,
referred_columns,
} => format!(
"{}FOREIGN KEY ({}) REFERENCES {}({})",
format_constraint_name(name),
columns.join(", "),
foreign_table.to_string(),
referred_columns.join(", ")
),
TableConstraint::Check { name, expr } => format!(
"{}CHECK ({})",
format_constraint_name(name),
expr.to_string()
),
}
}
}
40 changes: 25 additions & 15 deletions src/sqlast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@

//! SQL Abstract Syntax Tree (AST) types

mod ddl;
mod query;
mod sql_operator;
mod sqltype;
mod table_key;
mod value;

pub use self::ddl::{AlterTableOperation, TableConstraint};
pub use self::query::{
Cte, Fetch, Join, JoinConstraint, JoinOperator, SQLOrderByExpr, SQLQuery, SQLSelect,
SQLSelectItem, SQLSetExpr, SQLSetOperator, TableFactor,
};
pub use self::sqltype::SQLType;
pub use self::table_key::{AlterOperation, Key, TableKey};
pub use self::value::Value;

pub use self::sql_operator::SQLOperator;
Expand Down Expand Up @@ -396,6 +396,7 @@ pub enum SQLStatement {
name: SQLObjectName,
/// Optional schema
columns: Vec<SQLColumnDef>,
constraints: Vec<TableConstraint>,
external: bool,
file_format: Option<FileFormat>,
location: Option<String>,
Expand All @@ -404,7 +405,7 @@ pub enum SQLStatement {
SQLAlterTable {
/// Table name
name: SQLObjectName,
operation: AlterOperation,
operation: AlterTableOperation,
},
/// DROP TABLE
SQLDrop {
Expand Down Expand Up @@ -503,21 +504,30 @@ impl ToString for SQLStatement {
SQLStatement::SQLCreateTable {
name,
columns,
constraints,
external,
file_format,
location,
} if *external => format!(
"CREATE EXTERNAL TABLE {} ({}) STORED AS {} LOCATION '{}'",
name.to_string(),
comma_separated_string(columns),
file_format.as_ref().unwrap().to_string(),
location.as_ref().unwrap()
),
SQLStatement::SQLCreateTable { name, columns, .. } => format!(
"CREATE TABLE {} ({})",
name.to_string(),
comma_separated_string(columns)
),
} => {
let mut s = format!(
"CREATE {}TABLE {} ({}",
if *external { "EXTERNAL " } else { "" },
name.to_string(),
comma_separated_string(columns)
);
if !constraints.is_empty() {
s += &format!(", {}", comma_separated_string(constraints));
}
s += ")";
if *external {
s += &format!(
" STORED AS {} LOCATION '{}'",
file_format.as_ref().unwrap().to_string(),
location.as_ref().unwrap()
);
}
s
}
SQLStatement::SQLAlterTable { name, operation } => {
format!("ALTER TABLE {} {}", name.to_string(), operation.to_string())
}
Expand Down
20 changes: 10 additions & 10 deletions src/sqlast/sqltype.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
use super::SQLObjectName;

/// SQL datatypes for literals in SQL statements
/// SQL data types
#[derive(Debug, Clone, PartialEq)]
pub enum SQLType {
/// Fixed-length character type e.g. CHAR(10)
Char(Option<usize>),
Char(Option<u64>),
/// Variable-length character type e.g. VARCHAR(10)
Varchar(Option<usize>),
Varchar(Option<u64>),
/// Uuid type
Uuid,
/// Large character object e.g. CLOB(1000)
Clob(usize),
Clob(u64),
/// Fixed-length binary type e.g. BINARY(10)
Binary(usize),
Binary(u64),
/// Variable-length binary type e.g. VARBINARY(10)
Varbinary(usize),
Varbinary(u64),
/// Large binary object e.g. BLOB(1000)
Blob(usize),
Blob(u64),
/// Decimal type with optional precision and scale e.g. DECIMAL(10,2)
Decimal(Option<usize>, Option<usize>),
Decimal(Option<u64>, Option<u64>),
/// Floating point with optional precision e.g. FLOAT(8)
Float(Option<usize>),
Float(Option<u64>),
/// Small integer
SmallInt,
/// Integer
Expand Down Expand Up @@ -87,7 +87,7 @@ impl ToString for SQLType {
}
}

fn format_type_with_optional_length(sql_type: &str, len: &Option<usize>) -> String {
fn format_type_with_optional_length(sql_type: &str, len: &Option<u64>) -> String {
let mut s = sql_type.to_string();
if let Some(len) = len {
s += &format!("({})", len);
Expand Down
61 changes: 0 additions & 61 deletions src/sqlast/table_key.rs

This file was deleted.

10 changes: 5 additions & 5 deletions src/sqlast/value.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
/// SQL values such as int, double, string, timestamp
/// Primitive SQL values such as number and string
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
/// Literal signed long
Long(i64),
/// Literal floating point value
/// Unsigned integer value
Long(u64),
/// Unsigned floating point value
Double(f64),
/// 'string value'
SingleQuotedString(String),
/// N'string value'
NationalStringLiteral(String),
/// Boolean value true or false,
/// Boolean value true or false
Boolean(bool),
/// NULL value in insert statements,
Null,
Expand Down
Loading