ran cargo fmt

This commit is contained in:
Andy Grove 2018-10-06 09:39:26 -06:00
parent 9daba3ab49
commit 722ea7a91b
11 changed files with 662 additions and 615 deletions

View file

@ -32,5 +32,3 @@ pub trait Dialect {
/// Determine if a character is a valid identifier character
fn is_identifier_part(&self, ch: char) -> bool;
}

View file

@ -6,67 +6,12 @@ pub struct GenericSqlDialect {}
impl Dialect for GenericSqlDialect {
fn keywords(&self) -> Vec<&'static str> {
return vec![
SELECT,
FROM,
WHERE,
LIMIT,
ORDER,
GROUP,
BY,
HAVING,
UNION,
ALL,
INSERT,
INTO,
UPDATE,
DELETE,
IN,
IS,
NULL,
SET,
CREATE,
EXTERNAL,
TABLE,
ASC,
DESC,
AND,
OR,
NOT,
AS,
STORED,
CSV,
PARQUET,
LOCATION,
WITH,
WITHOUT,
HEADER,
ROW,
// SQL types
CHAR,
CHARACTER,
VARYING,
LARGE,
OBJECT,
VARCHAR,
CLOB,
BINARY,
VARBINARY,
BLOB,
FLOAT,
REAL,
DOUBLE,
PRECISION,
INT,
INTEGER,
SMALLINT,
BIGINT,
NUMERIC,
DECIMAL,
DEC,
BOOLEAN,
DATE,
TIME,
TIMESTAMP,
SELECT, FROM, WHERE, LIMIT, ORDER, GROUP, BY, HAVING, UNION, ALL, INSERT, INTO, UPDATE,
DELETE, IN, IS, NULL, SET, CREATE, EXTERNAL, TABLE, ASC, DESC, AND, OR, NOT, AS,
STORED, CSV, PARQUET, LOCATION, WITH, WITHOUT, HEADER, ROW, // SQL types
CHAR, CHARACTER, VARYING, LARGE, OBJECT, VARCHAR, CLOB, BINARY, VARBINARY, BLOB, FLOAT,
REAL, DOUBLE, PRECISION, INT, INTEGER, SMALLINT, BIGINT, NUMERIC, DECIMAL, DEC,
BOOLEAN, DATE, TIME, TIMESTAMP,
];
}
@ -82,4 +27,3 @@ impl Dialect for GenericSqlDialect {
|| ch == '_'
}
}

View file

@ -7,83 +7,13 @@ pub struct PostgreSqlDialect {}
impl Dialect for PostgreSqlDialect {
fn keywords(&self) -> Vec<&'static str> {
return vec![
ALTER,
ONLY,
SELECT,
FROM,
WHERE,
LIMIT,
ORDER,
GROUP,
BY,
HAVING,
UNION,
ALL,
INSERT,
INTO,
UPDATE,
DELETE,
IN,
IS,
NULL,
SET,
CREATE,
EXTERNAL,
TABLE,
ASC,
DESC,
AND,
OR,
NOT,
AS,
STORED,
CSV,
WITH,
WITHOUT,
ROW,
// SQL types
CHAR,
CHARACTER,
VARYING,
LARGE,
VARCHAR,
CLOB,
BINARY,
VARBINARY,
BLOB,
FLOAT,
REAL,
DOUBLE,
PRECISION,
INT,
INTEGER,
SMALLINT,
BIGINT,
NUMERIC,
DECIMAL,
DEC,
BOOLEAN,
DATE,
TIME,
TIMESTAMP,
VALUES,
DEFAULT,
ZONE,
REGCLASS,
TEXT,
BYTEA,
TRUE,
FALSE,
COPY,
STDIN,
PRIMARY,
KEY,
UNIQUE,
UUID,
ADD,
CONSTRAINT,
FOREIGN,
REFERENCES,
ALTER, ONLY, SELECT, FROM, WHERE, LIMIT, ORDER, GROUP, BY, HAVING, UNION, ALL, INSERT,
INTO, UPDATE, DELETE, IN, IS, NULL, SET, CREATE, EXTERNAL, TABLE, ASC, DESC, AND, OR,
NOT, AS, STORED, CSV, WITH, WITHOUT, ROW, // SQL types
CHAR, CHARACTER, VARYING, LARGE, VARCHAR, CLOB, BINARY, VARBINARY, BLOB, FLOAT, REAL,
DOUBLE, PRECISION, INT, INTEGER, SMALLINT, BIGINT, NUMERIC, DECIMAL, DEC, BOOLEAN,
DATE, TIME, TIMESTAMP, VALUES, DEFAULT, ZONE, REGCLASS, TEXT, BYTEA, TRUE, FALSE, COPY,
STDIN, PRIMARY, KEY, UNIQUE, UUID, ADD, CONSTRAINT, FOREIGN, REFERENCES,
];
}

View file

@ -14,31 +14,22 @@
//! SQL Abstract Syntax Tree (AST) types
//!
use chrono::{NaiveDate,
NaiveDateTime,
NaiveTime,
offset::{FixedOffset,
TimeZone,
},
DateTime,
Utc,
use chrono::{
offset::{FixedOffset, TimeZone},
DateTime, NaiveDate, NaiveDateTime, NaiveTime, Utc,
};
use uuid::Uuid;
pub use self::value::Value;
pub use self::sqltype::SQLType;
pub use self::table_key::{
AlterOperation,
TableKey,
Key
};
pub use self::table_key::{AlterOperation, Key, TableKey};
pub use self::value::Value;
use uuid::Uuid;
pub use self::sql_operator::SQLOperator;
mod value;
mod sql_operator;
mod sqltype;
mod table_key;
mod sql_operator;
mod value;
/// SQL Abstract Syntax Tree (AST)
#[derive(Debug, Clone, PartialEq)]
@ -139,12 +130,10 @@ pub enum ASTNode {
/// Table name
name: String,
operation: AlterOperation,
},
}
}
impl ToString for ASTNode {
fn to_string(&self) -> String {
match self {
ASTNode::SQLIdentifier(s) => s.to_string(),
@ -153,18 +142,30 @@ impl ToString for ASTNode{
ASTNode::SQLAssignment(ass) => ass.to_string(),
ASTNode::SQLIsNull(ast) => format!("{} IS NULL", ast.as_ref().to_string()),
ASTNode::SQLIsNotNull(ast) => format!("{} IS NOT NULL", ast.as_ref().to_string()),
ASTNode::SQLBinaryExpr{left, op, right} => {
format!("{} {} {}", left.as_ref().to_string(), op.to_string(), right.as_ref().to_string())
}
ASTNode::SQLCast{expr, data_type} => {
format!("CAST({} AS {})", expr.as_ref().to_string(), data_type.to_string())
}
ASTNode::SQLBinaryExpr { left, op, right } => format!(
"{} {} {}",
left.as_ref().to_string(),
op.to_string(),
right.as_ref().to_string()
),
ASTNode::SQLCast { expr, data_type } => format!(
"CAST({} AS {})",
expr.as_ref().to_string(),
data_type.to_string()
),
ASTNode::SQLNested(ast) => format!("({})", ast.as_ref().to_string()),
ASTNode::SQLUnary { operator, rex } => {
format!("{} {}", operator.to_string(), rex.as_ref().to_string())
}
ASTNode::SQLValue(v) => v.to_string(),
ASTNode::SQLFunction{id, args} => format!("{}({})", id, args.iter().map(|a|a.to_string()).collect::<Vec<String>>().join(", ")),
ASTNode::SQLFunction { id, args } => format!(
"{}({})",
id,
args.iter()
.map(|a| a.to_string())
.collect::<Vec<String>>()
.join(", ")
),
ASTNode::SQLSelect {
projection,
relation,
@ -174,7 +175,14 @@ impl ToString for ASTNode{
having,
limit,
} => {
let mut s = format!("SELECT {}", projection.iter().map(|p|p.to_string()).collect::<Vec<String>>().join(", "));
let mut s = format!(
"SELECT {}",
projection
.iter()
.map(|p| p.to_string())
.collect::<Vec<String>>()
.join(", ")
);
if let Some(relation) = relation {
s += &format!(" FROM {}", relation.as_ref().to_string());
}
@ -182,61 +190,113 @@ impl ToString for ASTNode{
s += &format!(" WHERE {}", selection.as_ref().to_string());
}
if let Some(group_by) = group_by {
s += &format!(" GROUP BY {}", group_by.iter().map(|g|g.to_string()).collect::<Vec<String>>().join(", "));
s += &format!(
" GROUP BY {}",
group_by
.iter()
.map(|g| g.to_string())
.collect::<Vec<String>>()
.join(", ")
);
}
if let Some(having) = having {
s += &format!(" HAVING {}", having.as_ref().to_string());
}
if let Some(order_by) = order_by {
s += &format!(" ORDER BY {}", order_by.iter().map(|o|o.to_string()).collect::<Vec<String>>().join(", "));
s += &format!(
" ORDER BY {}",
order_by
.iter()
.map(|o| o.to_string())
.collect::<Vec<String>>()
.join(", ")
);
}
if let Some(limit) = limit {
s += &format!(" LIMIT {}", limit.as_ref().to_string());
}
s
}
ASTNode::SQLInsert{ table_name, columns, values } => {
ASTNode::SQLInsert {
table_name,
columns,
values,
} => {
let mut s = format!("INSERT INTO {}", table_name);
if columns.len() > 0 {
s += &format!(" ({})", columns.join(", "));
}
if values.len() > 0 {
s += &format!(" VALUES({})",
values.iter()
.map(|row|row.iter().map(|c|c.to_string())
.collect::<Vec<String>>().join(", ")
).collect::<Vec<String>>().join(", ")
s += &format!(
" VALUES({})",
values
.iter()
.map(|row| row
.iter()
.map(|c| c.to_string())
.collect::<Vec<String>>()
.join(", "))
.collect::<Vec<String>>()
.join(", ")
);
}
s
}
ASTNode::SQLCopy{table_name, columns, values} => {
ASTNode::SQLCopy {
table_name,
columns,
values,
} => {
let mut s = format!("COPY {}", table_name);
if columns.len() > 0 {
s += &format!(" ({})", columns.iter().map(|c|c.to_string()).collect::<Vec<String>>().join(", "));
s += &format!(
" ({})",
columns
.iter()
.map(|c| c.to_string())
.collect::<Vec<String>>()
.join(", ")
);
}
s += " FROM stdin; ";
if values.len() > 0 {
s += &format!("\n{}",
values.iter()
s += &format!(
"\n{}",
values
.iter()
.map(|v| v.to_string())
.collect::<Vec<String>>().join("\t")
.collect::<Vec<String>>()
.join("\t")
);
}
s += "\n\\.";
s
}
ASTNode::SQLUpdate{table_name, assignments, selection} => {
ASTNode::SQLUpdate {
table_name,
assignments,
selection,
} => {
let mut s = format!("UPDATE {}", table_name);
if assignments.len() > 0 {
s += &format!("{}", assignments.iter().map(|ass|ass.to_string()).collect::<Vec<String>>().join(", "));
s += &format!(
"{}",
assignments
.iter()
.map(|ass| ass.to_string())
.collect::<Vec<String>>()
.join(", ")
);
}
if let Some(selection) = selection {
s += &format!(" WHERE {}", selection.as_ref().to_string());
}
s
}
ASTNode::SQLDelete{relation, selection} => {
ASTNode::SQLDelete {
relation,
selection,
} => {
let mut s = String::from("DELETE");
if let Some(relation) = relation {
s += &format!(" FROM {}", relation.as_ref().to_string());
@ -246,9 +306,15 @@ impl ToString for ASTNode{
}
s
}
ASTNode::SQLCreateTable{name, columns} => {
format!("CREATE TABLE {} ({})", name, columns.iter().map(|c|c.to_string()).collect::<Vec<String>>().join(", "))
}
ASTNode::SQLCreateTable { name, columns } => format!(
"CREATE TABLE {} ({})",
name,
columns
.iter()
.map(|c| c.to_string())
.collect::<Vec<String>>()
.join(", ")
),
ASTNode::SQLAlterTable { name, operation } => {
format!("ALTER TABLE {} {}", name, operation.to_string())
}
@ -265,7 +331,6 @@ pub struct SQLAssignment {
}
impl ToString for SQLAssignment {
fn to_string(&self) -> String {
format!("SET {} = {}", self.id, self.value.as_ref().to_string())
}
@ -305,9 +370,7 @@ pub struct SQLColumnDef {
pub allow_null: bool,
}
impl ToString for SQLColumnDef {
fn to_string(&self) -> String {
let mut s = format!("{} {}", self.name, self.data_type.to_string());
if self.is_primary {
@ -325,4 +388,3 @@ impl ToString for SQLColumnDef{
s
}
}

View file

@ -1,4 +1,3 @@
/// SQL Operator
#[derive(Debug, PartialEq, Clone)]
pub enum SQLOperator {
@ -18,7 +17,6 @@ pub enum SQLOperator {
}
impl ToString for SQLOperator {
fn to_string(&self) -> String {
match self {
SQLOperator::Plus => "+".to_string(),
@ -37,4 +35,3 @@ impl ToString for SQLOperator{
}
}
}

View file

@ -1,4 +1,3 @@
/// SQL datatypes for literals in SQL statements
#[derive(Debug, Clone, PartialEq)]
pub enum SQLType {
@ -51,37 +50,44 @@ pub enum SQLType {
}
impl ToString for SQLType {
fn to_string(&self) -> String {
match self {
SQLType::Char(size) => if let Some(size) = size {
SQLType::Char(size) => {
if let Some(size) = size {
format!("char({})", size)
} else {
"char".to_string()
}
SQLType::Varchar(size) => if let Some(size) = size{
}
SQLType::Varchar(size) => {
if let Some(size) = size {
format!("character varying({})", size)
} else {
"character varying".to_string()
}
}
SQLType::Uuid => "uuid".to_string(),
SQLType::Clob(size) => format!("clob({})", size),
SQLType::Binary(size) => format!("binary({})", size),
SQLType::Varbinary(size) => format!("varbinary({})", size),
SQLType::Blob(size) => format!("blob({})", size),
SQLType::Decimal(precision, scale) => if let Some(scale) = scale{
SQLType::Decimal(precision, scale) => {
if let Some(scale) = scale {
format!("numeric({},{})", precision, scale)
} else {
format!("numeric({})", precision)
},
}
}
SQLType::SmallInt => "smallint".to_string(),
SQLType::Int => "int".to_string(),
SQLType::BigInt => "bigint".to_string(),
SQLType::Float(size) => if let Some(size) = size{
SQLType::Float(size) => {
if let Some(size) = size {
format!("float({})", size)
} else {
"float".to_string()
},
}
}
SQLType::Real => "real".to_string(),
SQLType::Double => "double".to_string(),
SQLType::Boolean => "boolean".to_string(),

View file

@ -1,23 +1,20 @@
#[derive(Debug, PartialEq, Clone)]
pub enum AlterOperation {
AddConstraint(TableKey),
RemoveConstraint{
name: String,
}
RemoveConstraint { name: String },
}
impl ToString for AlterOperation {
fn to_string(&self) -> String {
match self {
AlterOperation::AddConstraint(table_key) => format!("ADD CONSTRAINT {}", table_key.to_string()),
AlterOperation::AddConstraint(table_key) => {
format!("ADD CONSTRAINT {}", table_key.to_string())
}
AlterOperation::RemoveConstraint { name } => format!("REMOVE CONSTRAINT {}", name),
}
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct Key {
pub name: String,
@ -33,12 +30,10 @@ pub enum TableKey{
key: Key,
foreign_table: String,
referred_columns: Vec<String>,
},
}
}
impl ToString for TableKey {
fn to_string(&self) -> String {
match self {
TableKey::PrimaryKey(ref key) => {
@ -47,12 +42,18 @@ impl ToString for TableKey{
TableKey::UniqueKey(ref key) => {
format!("{} UNIQUE KEY ({})", key.name, key.columns.join(", "))
}
TableKey::Key(ref key) => {
format!("{} KEY ({})", key.name, key.columns.join(", "))
}
TableKey::ForeignKey{key, foreign_table, referred_columns} => {
format!("{} FOREIGN KEY ({}) REFERENCES {}({})", key.name, key.columns.join(", "), foreign_table, referred_columns.join(", "))
}
TableKey::Key(ref key) => format!("{} KEY ({})", key.name, key.columns.join(", ")),
TableKey::ForeignKey {
key,
foreign_table,
referred_columns,
} => format!(
"{} FOREIGN KEY ({}) REFERENCES {}({})",
key.name,
key.columns.join(", "),
foreign_table,
referred_columns.join(", ")
),
}
}
}

View file

@ -1,12 +1,6 @@
use chrono::{NaiveDate,
NaiveDateTime,
NaiveTime,
offset::{FixedOffset,
TimeZone,
},
DateTime,
Utc,
use chrono::{
offset::{FixedOffset, TimeZone},
DateTime, NaiveDate, NaiveDateTime, NaiveTime, Utc,
};
use uuid::Uuid;
@ -40,9 +34,7 @@ pub enum Value{
Null,
}
impl ToString for Value {
fn to_string(&self) -> String {
match self {
Value::Long(v) => v.to_string(),

View file

@ -17,14 +17,9 @@
use super::dialect::Dialect;
use super::sqlast::*;
use super::sqltokenizer::*;
use chrono::{NaiveDate,
NaiveDateTime,
NaiveTime,
offset::{FixedOffset,
TimeZone,
},
DateTime,
Utc,
use chrono::{
offset::{FixedOffset, TimeZone},
DateTime, NaiveDate, NaiveDateTime, NaiveTime, Utc,
};
#[derive(Debug, Clone)]
@ -95,8 +90,7 @@ impl Parser {
/// Parse an expression prefix
pub fn parse_prefix(&mut self) -> Result<ASTNode, ParserError> {
match self.next_token() {
Some(t) => {
match t {
Some(t) => match t {
Token::Keyword(k) => match k.to_uppercase().as_ref() {
"SELECT" => Ok(self.parse_select()?),
"CREATE" => Ok(self.parse_create()?),
@ -124,9 +118,7 @@ impl Parser {
self.parse_cast_expression()
} else {
match self.peek_token() {
Some(Token::LParen) => {
self.parse_function_or_pg_cast(&id)
}
Some(Token::LParen) => self.parse_function_or_pg_cast(&id),
Some(Token::Period) => {
let mut id_parts: Vec<String> = vec![id];
while self.peek_token() == Some(Token::Period) {
@ -149,7 +141,7 @@ impl Parser {
Token::Number(ref n) => {
self.prev_token();
self.parse_sql_value()
},
}
Token::String(ref s) => {
self.prev_token();
self.parse_sql_value()
@ -166,8 +158,7 @@ impl Parser {
"Prefix parser expected a keyword but found {:?}",
t
)),
}
}
},
None => parser_err!(format!("Prefix parser expected a keyword but hit EOF")),
}
}
@ -184,11 +175,17 @@ impl Parser {
pub fn parse_function(&mut self, id: &str) -> Result<ASTNode, ParserError> {
self.consume_token(&Token::LParen)?;
if let Ok(true) = self.consume_token(&Token::RParen) {
Ok(ASTNode::SQLFunction { id: id.to_string(), args: vec![] })
Ok(ASTNode::SQLFunction {
id: id.to_string(),
args: vec![],
})
} else {
let args = self.parse_expr_list()?;
self.consume_token(&Token::RParen)?;
Ok(ASTNode::SQLFunction { id: id.to_string(), args })
Ok(ASTNode::SQLFunction {
id: id.to_string(),
args,
})
}
}
@ -205,7 +202,6 @@ impl Parser {
})
}
/// Parse a postgresql casting style which is in the form or expr::datatype
pub fn parse_pg_cast(&mut self, expr: ASTNode) -> Result<ASTNode, ParserError> {
let ast = self.consume_token(&Token::DoubleColon)?;
@ -236,7 +232,8 @@ impl Parser {
debug!("parsing infix");
match self.next_token() {
Some(tok) => match tok {
Token::Keyword(ref k) => if k == "IS" {
Token::Keyword(ref k) => {
if k == "IS" {
if self.parse_keywords(vec!["NULL"]) {
Ok(Some(ASTNode::SQLIsNull(Box::new(expr))))
} else if self.parse_keywords(vec!["NOT", "NULL"]) {
@ -250,7 +247,8 @@ impl Parser {
op: self.to_sql_operator(&tok)?,
right: Box::new(self.parse_expr(precedence)?),
}))
},
}
}
Token::Eq
| Token::Neq
| Token::Gt
@ -266,10 +264,10 @@ impl Parser {
op: self.to_sql_operator(&tok)?,
right: Box::new(self.parse_expr(precedence)?),
})),
| Token::DoubleColon => {
Token::DoubleColon => {
let pg_cast = self.parse_pg_cast(expr)?;
Ok(Some(pg_cast))
},
}
_ => parser_err!(format!("No infix parser for token {:?}", tok)),
},
None => Ok(None),
@ -327,7 +325,6 @@ impl Parser {
self.peek_token_skip_whitespace()
}
pub fn skip_whitespace(&mut self) -> Option<Token> {
loop {
match self.next_token_no_skip() {
@ -376,7 +373,6 @@ impl Parser {
}
}
/// Get the next token skipping whitespace and increment the token index
pub fn next_token(&mut self) -> Option<Token> {
self.skip_whitespace()
@ -401,7 +397,7 @@ impl Parser {
}
token => {
return token;
},
}
}
}
}
@ -454,20 +450,17 @@ impl Parser {
/// Consume the next token if it matches the expected token, otherwise return an error
pub fn consume_token(&mut self, expected: &Token) -> Result<bool, ParserError> {
match self.peek_token() {
Some(ref t) => if *t == *expected {
Some(ref t) => {
if *t == *expected {
self.next_token();
Ok(true)
} else {
Ok(false)
},
other => parser_err!(format!(
"expected token {:?} but was {:?}",
expected,
other,
)),
}
}
other => parser_err!(format!("expected token {:?} but was {:?}", expected, other,)),
}
}
/// Parse a SQL CREATE statement
pub fn parse_create(&mut self) -> Result<ASTNode, ParserError> {
@ -527,16 +520,20 @@ impl Parser {
}
}
} else {
return parser_err!(
format!("Error parsing data type in column definition near: {:?}", self.peek_token())
);
return parser_err!(format!(
"Error parsing data type in column definition near: {:?}",
self.peek_token()
));
}
} else {
return parser_err!("Error parsing column name");
}
}
}
Ok(ASTNode::SQLCreateTable { name: table_name, columns })
Ok(ASTNode::SQLCreateTable {
name: table_name,
columns,
})
} else {
parser_err!(format!(
"Unexpected token after CREATE: {:?}",
@ -554,15 +551,13 @@ impl Parser {
self.consume_token(&Token::RParen)?;
let key = Key {
name: constraint_name.to_string(),
columns: column_names
columns: column_names,
};
if is_primary_key {
Ok(TableKey::PrimaryKey(key))
}
else if is_unique_key{
} else if is_unique_key {
Ok(TableKey::UniqueKey(key))
}
else if is_foreign_key{
} else if is_foreign_key {
if self.parse_keyword("REFERENCES") {
let foreign_table = self.parse_tablename()?;
self.consume_token(&Token::LParen)?;
@ -577,7 +572,10 @@ impl Parser {
parser_err!("Expecting references")
}
} else {
parser_err!(format!("Expecting primary key, unique key, or foreign key, found: {:?}", self.peek_token()))
parser_err!(format!(
"Expecting primary key, unique key, or foreign key, found: {:?}",
self.peek_token()
))
}
}
@ -585,29 +583,38 @@ impl Parser {
if self.parse_keyword("TABLE") {
let is_only = self.parse_keyword("ONLY");
let table_name = self.parse_tablename()?;
let operation:Result<AlterOperation,ParserError> = if self.parse_keywords(vec!["ADD", "CONSTRAINT"]){
let operation: Result<AlterOperation, ParserError> =
if self.parse_keywords(vec!["ADD", "CONSTRAINT"]) {
match self.next_token() {
Some(Token::Identifier(ref id)) => {
let table_key = self.parse_table_key(id)?;
Ok(AlterOperation::AddConstraint(table_key))
}
_ => {
return parser_err!(format!("Expecting identifier, found : {:?}", self.peek_token()));
return parser_err!(format!(
"Expecting identifier, found : {:?}",
self.peek_token()
));
}
}
} else {
return parser_err!(format!("Expecting ADD CONSTRAINT, found :{:?}", self.peek_token()));
return parser_err!(format!(
"Expecting ADD CONSTRAINT, found :{:?}",
self.peek_token()
));
};
Ok(ASTNode::SQLAlterTable {
name: table_name,
operation: operation?,
})
} else {
parser_err!(format!("Expecting TABLE after ALTER, found {:?}", self.peek_token()))
parser_err!(format!(
"Expecting TABLE after ALTER, found {:?}",
self.peek_token()
))
}
}
/// Parse a copy statement
pub fn parse_copy(&mut self) -> Result<ASTNode, ParserError> {
let table_name = self.parse_tablename()?;
@ -622,7 +629,11 @@ impl Parser {
self.parse_keyword("STDIN");
self.consume_token(&Token::SemiColon);
let values = self.parse_tsv()?;
Ok(ASTNode::SQLCopy{table_name, columns, values})
Ok(ASTNode::SQLCopy {
table_name,
columns,
values,
})
}
/// Parse a tab separated values in
@ -630,7 +641,6 @@ impl Parser {
fn parse_tsv(&mut self) -> Result<Vec<Value>, ParserError> {
let values = self.parse_tab_value()?;
Ok(values)
}
fn parse_sql_value(&mut self) -> Result<ASTNode, ParserError> {
@ -653,7 +663,8 @@ impl Parser {
Token::Backslash => {
if let Ok(true) = self.consume_token(&Token::Period) {
return Ok(values);
}if let Some(token) = self.next_token(){
}
if let Some(token) = self.next_token() {
if token == Token::Identifier("N".to_string()) {
values.push(Value::Null);
}
@ -707,8 +718,12 @@ impl Parser {
},
Token::Identifier(id) => Ok(Value::String(id.to_string())),
Token::String(ref s) => Ok(Value::String(s.to_string())),
Token::SingleQuotedString(ref s) => Ok(Value::SingleQuotedString(s.to_string())),
Token::DoubleQuotedString(ref s) => Ok(Value::DoubleQuotedString(s.to_string())),
Token::SingleQuotedString(ref s) => {
Ok(Value::SingleQuotedString(s.to_string()))
}
Token::DoubleQuotedString(ref s) => {
Ok(Value::DoubleQuotedString(s.to_string()))
}
other => parser_err!(format!("Unsupported value: {:?}", self.peek_token())),
}
}
@ -744,7 +759,6 @@ impl Parser {
}
}
pub fn parse_timezone_offset(&mut self) -> Result<i8, ParserError> {
match self.next_token() {
Some(Token::Plus) => {
@ -755,11 +769,13 @@ impl Parser {
let n = self.parse_literal_int()?;
Ok(-n as i8)
}
other => parser_err!(format!("Expecting `+` or `-` in timezone, but found {:?}", other)),
other => parser_err!(format!(
"Expecting `+` or `-` in timezone, but found {:?}",
other
)),
}
}
pub fn parse_timestamp_value(&mut self) -> Result<Value, ParserError> {
let year = self.parse_literal_int()?;
let date = self.parse_date(year)?;
@ -777,7 +793,10 @@ impl Parser {
_ => Ok(Value::DateTime(date_time)),
}
} else {
parser_err!(format!("Expecting time after date, but found {:?}", self.peek_token()))
parser_err!(format!(
"Expecting time after date, but found {:?}",
self.peek_token()
))
}
}
@ -789,12 +808,17 @@ impl Parser {
let date = NaiveDate::from_ymd(year as i32, month as u32, day as u32);
Ok(date)
} else {
parser_err!(format!("Expecting `-` for date separator, found {:?}", self.peek_token()))
parser_err!(format!(
"Expecting `-` for date separator, found {:?}",
self.peek_token()
))
}
} else {
parser_err!(format!("Expecting `-` for date separator, found {:?}", self.peek_token()))
parser_err!(format!(
"Expecting `-` for date separator, found {:?}",
self.peek_token()
))
}
}
pub fn parse_time(&mut self) -> Result<NaiveTime, ParserError> {
@ -806,7 +830,12 @@ impl Parser {
let ms = (sec.fract() * 1000.0).round();
if let Ok(true) = self.consume_token(&Token::Period) {
let ms = self.parse_literal_int()?;
Ok(NaiveTime::from_hms_milli(hour as u32, min as u32, sec as u32, ms as u32))
Ok(NaiveTime::from_hms_milli(
hour as u32,
min as u32,
sec as u32,
ms as u32,
))
} else {
Ok(NaiveTime::from_hms(hour as u32, min as u32, sec as u32))
}
@ -819,11 +848,13 @@ impl Parser {
"BOOLEAN" => Ok(SQLType::Boolean),
"FLOAT" => Ok(SQLType::Float(self.parse_optional_precision()?)),
"REAL" => Ok(SQLType::Real),
"DOUBLE" => if self.parse_keyword("PRECISION"){
"DOUBLE" => {
if self.parse_keyword("PRECISION") {
Ok(SQLType::Double)
} else {
Ok(SQLType::Double)
}
}
"SMALLINT" => Ok(SQLType::SmallInt),
"INT" | "INTEGER" => Ok(SQLType::Int),
"BIGINT" => Ok(SQLType::BigInt),
@ -837,36 +868,52 @@ impl Parser {
}
"UUID" => Ok(SQLType::Uuid),
"DATE" => Ok(SQLType::Date),
"TIMESTAMP" => if self.parse_keyword("WITH"){
"TIMESTAMP" => {
if self.parse_keyword("WITH") {
if self.parse_keywords(vec!["TIME", "ZONE"]) {
Ok(SQLType::Timestamp)
} else {
parser_err!(format!("Expecting 'time zone', found: {:?}", self.peek_token()))
parser_err!(format!(
"Expecting 'time zone', found: {:?}",
self.peek_token()
))
}
} else if self.parse_keyword("WITHOUT") {
if self.parse_keywords(vec!["TIME", "ZONE"]) {
Ok(SQLType::Timestamp)
} else {
parser_err!(format!("Expecting 'time zone', found: {:?}", self.peek_token()))
parser_err!(format!(
"Expecting 'time zone', found: {:?}",
self.peek_token()
))
}
} else {
Ok(SQLType::Timestamp)
}
"TIME" => if self.parse_keyword("WITH"){
}
"TIME" => {
if self.parse_keyword("WITH") {
if self.parse_keywords(vec!["TIME", "ZONE"]) {
Ok(SQLType::Time)
} else {
parser_err!(format!("Expecting 'time zone', found: {:?}", self.peek_token()))
parser_err!(format!(
"Expecting 'time zone', found: {:?}",
self.peek_token()
))
}
} else if self.parse_keyword("WITHOUT") {
if self.parse_keywords(vec!["TIME", "ZONE"]) {
Ok(SQLType::Time)
} else {
parser_err!(format!("Expecting 'time zone', found: {:?}", self.peek_token()))
parser_err!(format!(
"Expecting 'time zone', found: {:?}",
self.peek_token()
))
}
} else {
Ok(SQLType::Timestamp)
}
}
"REGCLASS" => Ok(SQLType::Regclass),
"TEXT" => {
if let Ok(true) = self.consume_token(&Token::LBracket) {
@ -895,7 +942,6 @@ impl Parser {
}
}
pub fn parse_compound_identifier(&mut self, separator: &Token) -> Result<ASTNode, ParserError> {
let mut idents = vec![];
let mut expect_identifier = true;
@ -903,13 +949,15 @@ impl Parser {
let token = &self.next_token();
match token {
Some(token) => match token {
Token::Identifier(s) => if expect_identifier{
Token::Identifier(s) => {
if expect_identifier {
expect_identifier = false;
idents.push(s.to_string());
} else {
self.prev_token();
break;
}
}
token if token == separator => {
if expect_identifier {
return parser_err!(format!("Expecting identifier, found {:?}", token));
@ -922,7 +970,7 @@ impl Parser {
self.prev_token();
break;
}
}
},
None => {
self.prev_token();
break;
@ -964,7 +1012,9 @@ impl Parser {
}
}
pub fn parse_optional_precision_scale(&mut self) -> Result<(usize, Option<usize>), ParserError> {
pub fn parse_optional_precision_scale(
&mut self,
) -> Result<(usize, Option<usize>), ParserError> {
if self.consume_token(&Token::LParen)? {
let n = self.parse_literal_int()?;
let scale = if let Ok(true) = self.consume_token(&Token::Comma) {
@ -1081,7 +1131,11 @@ impl Parser {
self.consume_token(&Token::LParen)?;
let values = self.parse_expr_list()?;
self.consume_token(&Token::RParen)?;
Ok(ASTNode::SQLInsert{table_name, columns, values: vec![values]})
Ok(ASTNode::SQLInsert {
table_name,
columns,
values: vec![values],
})
}
/// Parse a comma-delimited list of SQL expressions
@ -1157,4 +1211,3 @@ impl Parser {
}
}
}

View file

@ -134,7 +134,7 @@ impl ToString for Token{
pub enum Whitespace {
Space,
Newline,
Tab
Tab,
}
impl ToString for Whitespace {
@ -349,9 +349,7 @@ impl<'a> Tokenizer<'a> {
match chars.peek() {
Some(&ch) => match ch {
// double colon
':' => {
self.consume_and_return(chars, Token::DoubleColon)
}
':' => self.consume_and_return(chars, Token::DoubleColon),
_ => Ok(Some(Token::Colon)),
},
None => Ok(Some(Token::Colon)),
@ -365,13 +363,17 @@ impl<'a> Tokenizer<'a> {
'&' => self.consume_and_return(chars, Token::Ampersand),
'{' => self.consume_and_return(chars, Token::LBrace),
'}' => self.consume_and_return(chars, Token::RBrace),
other => self.consume_and_return(chars, Token::Char(other))
other => self.consume_and_return(chars, Token::Char(other)),
},
None => Ok(None),
}
}
fn consume_and_return(&self, chars: &mut Peekable<Chars>, t: Token) -> Result<Option<Token>, TokenizerError> {
fn consume_and_return(
&self,
chars: &mut Peekable<Chars>,
t: Token,
) -> Result<Option<Token>, TokenizerError> {
chars.next();
Ok(Some(t))
}
@ -492,10 +494,9 @@ mod tests {
Token::Char('ط'),
Token::Char('ف'),
Token::Char('ى'),
Token::Identifier("h".to_string())
Token::Identifier("h".to_string()),
];
compare(expected, tokens);
}
#[test]

View file

@ -1,10 +1,10 @@
extern crate log;
extern crate sqlparser;
use sqlparser::sqlast::*;
use sqlparser::sqltokenizer::*;
use sqlparser::sqlparser::*;
use sqlparser::dialect::PostgreSqlDialect;
use sqlparser::sqlast::*;
use sqlparser::sqlparser::*;
use sqlparser::sqltokenizer::*;
use log::*;
@ -14,9 +14,18 @@ fn test_prev_index(){
let mut parser = parser(sql);
assert_eq!(parser.prev_token(), None);
assert_eq!(parser.next_token(), Some(Token::Keyword("SELECT".into())));
assert_eq!(parser.next_token(), Some(Token::Identifier("version".into())));
assert_eq!(parser.prev_token(), Some(Token::Identifier("version".into())));
assert_eq!(parser.peek_token(), Some(Token::Identifier("version".into())));
assert_eq!(
parser.next_token(),
Some(Token::Identifier("version".into()))
);
assert_eq!(
parser.prev_token(),
Some(Token::Identifier("version".into()))
);
assert_eq!(
parser.peek_token(),
Some(Token::Identifier("version".into()))
);
assert_eq!(parser.prev_token(), Some(Token::Keyword("SELECT".into())));
assert_eq!(parser.prev_token(), None);
}
@ -30,7 +39,9 @@ fn parse_delete_statement() {
match parse_sql(&sql) {
ASTNode::SQLDelete { relation, .. } => {
assert_eq!(
Some(Box::new(ASTNode::SQLValue(Value::SingleQuotedString("table".to_string())))),
Some(Box::new(ASTNode::SQLValue(Value::SingleQuotedString(
"table".to_string()
)))),
relation
);
}
@ -56,7 +67,9 @@ fn parse_where_delete_statement() {
..
} => {
assert_eq!(
Some(Box::new(ASTNode::SQLValue(Value::SingleQuotedString("table".to_string())))),
Some(Box::new(ASTNode::SQLValue(Value::SingleQuotedString(
"table".to_string()
)))),
relation
);
@ -97,11 +110,21 @@ fn parse_simple_insert() {
assert_eq!(sql, ast.to_string());
match ast {
ASTNode::SQLInsert {
table_name, columns, values, ..
table_name,
columns,
values,
..
} => {
assert_eq!(table_name, "customer");
assert!(columns.is_empty());
assert_eq!(vec![vec![ASTNode::SQLValue(Value::Long(1)),ASTNode::SQLValue(Value::Long(2)),ASTNode::SQLValue(Value::Long(3))]], values);
assert_eq!(
vec![vec![
ASTNode::SQLValue(Value::Long(1)),
ASTNode::SQLValue(Value::Long(2)),
ASTNode::SQLValue(Value::Long(3))
]],
values
);
}
_ => assert!(false),
}
@ -114,11 +137,21 @@ fn parse_common_insert() {
assert_eq!(sql, ast.to_string());
match ast {
ASTNode::SQLInsert {
table_name, columns, values, ..
table_name,
columns,
values,
..
} => {
assert_eq!(table_name, "public.customer");
assert!(columns.is_empty());
assert_eq!(vec![vec![ASTNode::SQLValue(Value::Long(1)),ASTNode::SQLValue(Value::Long(2)),ASTNode::SQLValue(Value::Long(3))]], values);
assert_eq!(
vec![vec![
ASTNode::SQLValue(Value::Long(1)),
ASTNode::SQLValue(Value::Long(2)),
ASTNode::SQLValue(Value::Long(3))
]],
values
);
}
_ => assert!(false),
}
@ -131,11 +164,21 @@ fn parse_complex_insert() {
assert_eq!(sql, ast.to_string());
match ast {
ASTNode::SQLInsert {
table_name, columns, values, ..
table_name,
columns,
values,
..
} => {
assert_eq!(table_name, "db.public.customer");
assert!(columns.is_empty());
assert_eq!(vec![vec![ASTNode::SQLValue(Value::Long(1)),ASTNode::SQLValue(Value::Long(2)),ASTNode::SQLValue(Value::Long(3))]], values);
assert_eq!(
vec![vec![
ASTNode::SQLValue(Value::Long(1)),
ASTNode::SQLValue(Value::Long(2)),
ASTNode::SQLValue(Value::Long(3))
]],
values
);
}
_ => assert!(false),
}
@ -155,11 +198,24 @@ fn parse_insert_with_columns() {
assert_eq!(sql, ast.to_string());
match ast {
ASTNode::SQLInsert {
table_name, columns, values, ..
table_name,
columns,
values,
..
} => {
assert_eq!(table_name, "public.customer");
assert_eq!(columns, vec!["id".to_string(), "name".to_string(), "active".to_string()]);
assert_eq!(vec![vec![ASTNode::SQLValue(Value::Long(1)),ASTNode::SQLValue(Value::Long(2)),ASTNode::SQLValue(Value::Long(3))]], values);
assert_eq!(
columns,
vec!["id".to_string(), "name".to_string(), "active".to_string()]
);
assert_eq!(
vec![vec![
ASTNode::SQLValue(Value::Long(1)),
ASTNode::SQLValue(Value::Long(2)),
ASTNode::SQLValue(Value::Long(3))
]],
values
);
}
_ => assert!(false),
}
@ -412,7 +468,8 @@ fn parse_create_table_with_defaults() {
activebool boolean DEFAULT true NOT NULL,
create_date date DEFAULT now()::text NOT NULL,
last_update timestamp without time zone DEFAULT now() NOT NULL,
active integer NOT NULL)");
active integer NOT NULL)",
);
let ast = parse_sql(&sql);
match ast {
ASTNode::SQLCreateTable { name, columns } => {
@ -481,13 +538,15 @@ fn parse_create_table_from_pg_dump() {
#[test]
fn parse_create_table_with_inherit() {
let sql = String::from("\
let sql = String::from(
"\
CREATE TABLE bazaar.settings (\
settings_id uuid PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL, \
user_id uuid UNIQUE, \
value text[], \
use_metric boolean DEFAULT true\
)");
)",
);
let ast = parse_sql(&sql);
assert_eq!(sql, ast.to_string());
match ast {
@ -514,9 +573,11 @@ fn parse_create_table_with_inherit() {
#[test]
fn parse_alter_table_constraint_primary_key() {
let sql = String::from("\
let sql = String::from(
"\
ALTER TABLE bazaar.address \
ADD CONSTRAINT address_pkey PRIMARY KEY (address_id)");
ADD CONSTRAINT address_pkey PRIMARY KEY (address_id)",
);
let ast = parse_sql(&sql);
println!("ast: {:?}", ast);
assert_eq!(sql, ast.to_string());
@ -623,7 +684,10 @@ fn parse_literal_string() {
assert_eq!(sql, ast.to_string());
match ast {
ASTNode::SQLSelect { ref projection, .. } => {
assert_eq!(projection[0], ASTNode::SQLValue(Value::SingleQuotedString("one".to_string())));
assert_eq!(
projection[0],
ASTNode::SQLValue(Value::SingleQuotedString("one".to_string()))
);
}
_ => panic!(),
}
@ -666,4 +730,3 @@ fn parser(sql: &str) -> Parser {
debug!("tokens: {:#?}", tokens);
Parser::new(tokens)
}