mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-25 08:24:05 +00:00
implement fmt::Display instead of ToString
This commit is contained in:
parent
cdba43682f
commit
b2b159fed1
8 changed files with 605 additions and 550 deletions
|
@ -11,6 +11,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
use super::ObjectName;
|
||||
use std::fmt;
|
||||
|
||||
/// SQL data types
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
@ -65,47 +66,53 @@ pub enum DataType {
|
|||
Array(Box<DataType>),
|
||||
}
|
||||
|
||||
impl ToString for DataType {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for DataType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
DataType::Char(size) => format_type_with_optional_length("char", size),
|
||||
DataType::Varchar(size) => format_type_with_optional_length("character varying", size),
|
||||
DataType::Uuid => "uuid".to_string(),
|
||||
DataType::Clob(size) => format!("clob({})", size),
|
||||
DataType::Binary(size) => format!("binary({})", size),
|
||||
DataType::Varbinary(size) => format!("varbinary({})", size),
|
||||
DataType::Blob(size) => format!("blob({})", size),
|
||||
DataType::Char(size) => format_type_with_optional_length(f, "char", size),
|
||||
DataType::Varchar(size) => {
|
||||
format_type_with_optional_length(f, "character varying", size)
|
||||
}
|
||||
DataType::Uuid => write!(f, "uuid"),
|
||||
DataType::Clob(size) => write!(f, "clob({})", size),
|
||||
DataType::Binary(size) => write!(f, "binary({})", size),
|
||||
DataType::Varbinary(size) => write!(f, "varbinary({})", size),
|
||||
DataType::Blob(size) => write!(f, "blob({})", size),
|
||||
DataType::Decimal(precision, scale) => {
|
||||
if let Some(scale) = scale {
|
||||
format!("numeric({},{})", precision.unwrap(), scale)
|
||||
write!(f, "numeric({},{})", precision.unwrap(), scale)
|
||||
} else {
|
||||
format_type_with_optional_length("numeric", precision)
|
||||
format_type_with_optional_length(f, "numeric", precision)
|
||||
}
|
||||
}
|
||||
DataType::Float(size) => format_type_with_optional_length("float", size),
|
||||
DataType::SmallInt => "smallint".to_string(),
|
||||
DataType::Int => "int".to_string(),
|
||||
DataType::BigInt => "bigint".to_string(),
|
||||
DataType::Real => "real".to_string(),
|
||||
DataType::Double => "double".to_string(),
|
||||
DataType::Boolean => "boolean".to_string(),
|
||||
DataType::Date => "date".to_string(),
|
||||
DataType::Time => "time".to_string(),
|
||||
DataType::Timestamp => "timestamp".to_string(),
|
||||
DataType::Interval => "interval".to_string(),
|
||||
DataType::Regclass => "regclass".to_string(),
|
||||
DataType::Text => "text".to_string(),
|
||||
DataType::Bytea => "bytea".to_string(),
|
||||
DataType::Array(ty) => format!("{}[]", ty.to_string()),
|
||||
DataType::Custom(ty) => ty.to_string(),
|
||||
DataType::Float(size) => format_type_with_optional_length(f, "float", size),
|
||||
DataType::SmallInt => write!(f, "smallint"),
|
||||
DataType::Int => write!(f, "int"),
|
||||
DataType::BigInt => write!(f, "bigint"),
|
||||
DataType::Real => write!(f, "real"),
|
||||
DataType::Double => write!(f, "double"),
|
||||
DataType::Boolean => write!(f, "boolean"),
|
||||
DataType::Date => write!(f, "date"),
|
||||
DataType::Time => write!(f, "time"),
|
||||
DataType::Timestamp => write!(f, "timestamp"),
|
||||
DataType::Interval => write!(f, "interval"),
|
||||
DataType::Regclass => write!(f, "regclass"),
|
||||
DataType::Text => write!(f, "text"),
|
||||
DataType::Bytea => write!(f, "bytea"),
|
||||
DataType::Array(ty) => write!(f, "{}[]", ty),
|
||||
DataType::Custom(ty) => write!(f, "{}", ty),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn format_type_with_optional_length(sql_type: &str, len: &Option<u64>) -> String {
|
||||
let mut s = sql_type.to_string();
|
||||
fn format_type_with_optional_length(
|
||||
f: &mut fmt::Formatter,
|
||||
sql_type: &'static str,
|
||||
len: &Option<u64>,
|
||||
) -> fmt::Result {
|
||||
write!(f, "{}", sql_type)?;
|
||||
if let Some(len) = len {
|
||||
s += &format!("({})", len);
|
||||
write!(f, "({})", len)?;
|
||||
}
|
||||
s
|
||||
Ok(())
|
||||
}
|
||||
|
|
110
src/ast/ddl.rs
110
src/ast/ddl.rs
|
@ -1,6 +1,7 @@
|
|||
//! AST types specific to CREATE/ALTER variants of `SQLStatement`
|
||||
//! (commonly referred to as Data Definition Language, or DDL)
|
||||
use super::{DataType, Expr, Ident, ObjectName};
|
||||
use super::{display_comma_separated, DataType, Expr, Ident, ObjectName};
|
||||
use std::fmt;
|
||||
|
||||
/// An `ALTER TABLE` (`SQLStatement::SQLAlterTable`) operation
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
@ -11,11 +12,11 @@ pub enum AlterTableOperation {
|
|||
DropConstraint { name: Ident },
|
||||
}
|
||||
|
||||
impl ToString for AlterTableOperation {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for AlterTableOperation {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
AlterTableOperation::AddConstraint(c) => format!("ADD {}", c.to_string()),
|
||||
AlterTableOperation::DropConstraint { name } => format!("DROP CONSTRAINT {}", name),
|
||||
AlterTableOperation::AddConstraint(c) => write!(f, "ADD {}", c),
|
||||
AlterTableOperation::DropConstraint { name } => write!(f, "DROP CONSTRAINT {}", name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,36 +47,36 @@ pub enum TableConstraint {
|
|||
},
|
||||
}
|
||||
|
||||
impl ToString for TableConstraint {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for TableConstraint {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
TableConstraint::Unique {
|
||||
name,
|
||||
columns,
|
||||
is_primary,
|
||||
} => format!(
|
||||
} => write!(
|
||||
f,
|
||||
"{}{} ({})",
|
||||
format_constraint_name(name),
|
||||
display_constraint_name(name),
|
||||
if *is_primary { "PRIMARY KEY" } else { "UNIQUE" },
|
||||
columns.join(", ")
|
||||
display_comma_separated(columns)
|
||||
),
|
||||
TableConstraint::ForeignKey {
|
||||
name,
|
||||
columns,
|
||||
foreign_table,
|
||||
referred_columns,
|
||||
} => format!(
|
||||
} => write!(
|
||||
f,
|
||||
"{}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()
|
||||
display_constraint_name(name),
|
||||
display_comma_separated(columns),
|
||||
foreign_table,
|
||||
display_comma_separated(referred_columns)
|
||||
),
|
||||
TableConstraint::Check { name, expr } => {
|
||||
write!(f, "{}CHECK ({})", display_constraint_name(name), expr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -89,18 +90,13 @@ pub struct ColumnDef {
|
|||
pub options: Vec<ColumnOptionDef>,
|
||||
}
|
||||
|
||||
impl ToString for ColumnDef {
|
||||
fn to_string(&self) -> String {
|
||||
format!(
|
||||
"{} {}{}",
|
||||
self.name,
|
||||
self.data_type.to_string(),
|
||||
self.options
|
||||
.iter()
|
||||
.map(|c| format!(" {}", c.to_string()))
|
||||
.collect::<Vec<_>>()
|
||||
.join("")
|
||||
)
|
||||
impl fmt::Display for ColumnDef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{} {}", self.name, self.data_type)?;
|
||||
for option in &self.options {
|
||||
write!(f, " {}", option)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,13 +122,9 @@ pub struct ColumnOptionDef {
|
|||
pub option: ColumnOption,
|
||||
}
|
||||
|
||||
impl ToString for ColumnOptionDef {
|
||||
fn to_string(&self) -> String {
|
||||
format!(
|
||||
"{}{}",
|
||||
format_constraint_name(&self.name),
|
||||
self.option.to_string()
|
||||
)
|
||||
impl fmt::Display for ColumnOptionDef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}{}", display_constraint_name(&self.name), self.option)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,35 +152,39 @@ pub enum ColumnOption {
|
|||
Check(Expr),
|
||||
}
|
||||
|
||||
impl ToString for ColumnOption {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for ColumnOption {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use ColumnOption::*;
|
||||
match self {
|
||||
Null => "NULL".to_string(),
|
||||
NotNull => "NOT NULL".to_string(),
|
||||
Default(expr) => format!("DEFAULT {}", expr.to_string()),
|
||||
Null => write!(f, "NULL"),
|
||||
NotNull => write!(f, "NOT NULL"),
|
||||
Default(expr) => write!(f, "DEFAULT {}", expr),
|
||||
Unique { is_primary } => {
|
||||
if *is_primary {
|
||||
"PRIMARY KEY".to_string()
|
||||
} else {
|
||||
"UNIQUE".to_string()
|
||||
}
|
||||
write!(f, "{}", if *is_primary { "PRIMARY KEY" } else { "UNIQUE" })
|
||||
}
|
||||
ForeignKey {
|
||||
foreign_table,
|
||||
referred_columns,
|
||||
} => format!(
|
||||
} => write!(
|
||||
f,
|
||||
"REFERENCES {} ({})",
|
||||
foreign_table.to_string(),
|
||||
referred_columns.join(", ")
|
||||
foreign_table,
|
||||
display_comma_separated(referred_columns)
|
||||
),
|
||||
Check(expr) => format!("CHECK ({})", expr.to_string(),),
|
||||
Check(expr) => write!(f, "CHECK ({})", expr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn format_constraint_name(name: &Option<Ident>) -> String {
|
||||
name.as_ref()
|
||||
.map(|name| format!("CONSTRAINT {} ", name))
|
||||
.unwrap_or_default()
|
||||
fn display_constraint_name<'a>(name: &'a Option<Ident>) -> impl fmt::Display + 'a {
|
||||
struct ConstraintName<'a>(&'a Option<Ident>);
|
||||
impl<'a> fmt::Display for ConstraintName<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if let Some(name) = self.0 {
|
||||
write!(f, "CONSTRAINT {} ", name)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
ConstraintName(name)
|
||||
}
|
||||
|
|
474
src/ast/mod.rs
474
src/ast/mod.rs
|
@ -18,7 +18,7 @@ mod operator;
|
|||
mod query;
|
||||
mod value;
|
||||
|
||||
use std::ops::Deref;
|
||||
use std::fmt;
|
||||
|
||||
pub use self::data_type::DataType;
|
||||
pub use self::ddl::{
|
||||
|
@ -31,17 +31,41 @@ pub use self::query::{
|
|||
};
|
||||
pub use self::value::{DateTimeField, Value};
|
||||
|
||||
/// Like `vec.join(", ")`, but for any types implementing ToString.
|
||||
fn comma_separated_string<I>(iter: I) -> String
|
||||
struct DisplaySeparated<'a, T>
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: Deref,
|
||||
<I::Item as Deref>::Target: ToString,
|
||||
T: fmt::Display,
|
||||
{
|
||||
iter.into_iter()
|
||||
.map(|t| t.deref().to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
slice: &'a [T],
|
||||
sep: &'static str,
|
||||
}
|
||||
|
||||
impl<'a, T> fmt::Display for DisplaySeparated<'a, T>
|
||||
where
|
||||
T: fmt::Display,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut delim = "";
|
||||
for t in self.slice {
|
||||
write!(f, "{}", delim)?;
|
||||
delim = self.sep;
|
||||
write!(f, "{}", t)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn display_separated<'a, T>(slice: &'a [T], sep: &'static str) -> DisplaySeparated<'a, T>
|
||||
where
|
||||
T: fmt::Display,
|
||||
{
|
||||
DisplaySeparated { slice, sep }
|
||||
}
|
||||
|
||||
fn display_comma_separated<T>(slice: &[T]) -> DisplaySeparated<'_, T>
|
||||
where
|
||||
T: fmt::Display,
|
||||
{
|
||||
DisplaySeparated { slice, sep: ", " }
|
||||
}
|
||||
|
||||
/// Identifier name, in the originally quoted form (e.g. `"id"`)
|
||||
|
@ -138,95 +162,82 @@ pub enum Expr {
|
|||
Subquery(Box<Query>),
|
||||
}
|
||||
|
||||
impl ToString for Expr {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for Expr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Expr::Identifier(s) => s.to_string(),
|
||||
Expr::Wildcard => "*".to_string(),
|
||||
Expr::QualifiedWildcard(q) => q.join(".") + ".*",
|
||||
Expr::CompoundIdentifier(s) => s.join("."),
|
||||
Expr::IsNull(ast) => format!("{} IS NULL", ast.as_ref().to_string()),
|
||||
Expr::IsNotNull(ast) => format!("{} IS NOT NULL", ast.as_ref().to_string()),
|
||||
Expr::Identifier(s) => write!(f, "{}", s),
|
||||
Expr::Wildcard => f.write_str("*"),
|
||||
Expr::QualifiedWildcard(q) => {
|
||||
write!(f, "{}", display_separated(q, "."))?;
|
||||
f.write_str(".*")
|
||||
}
|
||||
Expr::CompoundIdentifier(s) => write!(f, "{}", display_separated(s, ".")),
|
||||
Expr::IsNull(ast) => write!(f, "{} IS NULL", ast),
|
||||
Expr::IsNotNull(ast) => write!(f, "{} IS NOT NULL", ast),
|
||||
Expr::InList {
|
||||
expr,
|
||||
list,
|
||||
negated,
|
||||
} => format!(
|
||||
} => write!(
|
||||
f,
|
||||
"{} {}IN ({})",
|
||||
expr.as_ref().to_string(),
|
||||
expr,
|
||||
if *negated { "NOT " } else { "" },
|
||||
comma_separated_string(list)
|
||||
display_comma_separated(list)
|
||||
),
|
||||
Expr::InSubquery {
|
||||
expr,
|
||||
subquery,
|
||||
negated,
|
||||
} => format!(
|
||||
} => write!(
|
||||
f,
|
||||
"{} {}IN ({})",
|
||||
expr.as_ref().to_string(),
|
||||
expr,
|
||||
if *negated { "NOT " } else { "" },
|
||||
subquery.to_string()
|
||||
subquery
|
||||
),
|
||||
Expr::Between {
|
||||
expr,
|
||||
negated,
|
||||
low,
|
||||
high,
|
||||
} => format!(
|
||||
} => write!(
|
||||
f,
|
||||
"{} {}BETWEEN {} AND {}",
|
||||
expr.to_string(),
|
||||
expr,
|
||||
if *negated { "NOT " } else { "" },
|
||||
low.to_string(),
|
||||
high.to_string()
|
||||
low,
|
||||
high
|
||||
),
|
||||
Expr::BinaryOp { left, op, right } => format!(
|
||||
"{} {} {}",
|
||||
left.as_ref().to_string(),
|
||||
op.to_string(),
|
||||
right.as_ref().to_string()
|
||||
),
|
||||
Expr::UnaryOp { op, expr } => {
|
||||
format!("{} {}", op.to_string(), expr.as_ref().to_string())
|
||||
}
|
||||
Expr::Cast { expr, data_type } => format!(
|
||||
"CAST({} AS {})",
|
||||
expr.as_ref().to_string(),
|
||||
data_type.to_string()
|
||||
),
|
||||
Expr::Extract { field, expr } => {
|
||||
format!("EXTRACT({} FROM {})", field.to_string(), expr.to_string())
|
||||
}
|
||||
Expr::Collate { expr, collation } => format!(
|
||||
"{} COLLATE {}",
|
||||
expr.as_ref().to_string(),
|
||||
collation.to_string()
|
||||
),
|
||||
Expr::Nested(ast) => format!("({})", ast.as_ref().to_string()),
|
||||
Expr::Value(v) => v.to_string(),
|
||||
Expr::Function(f) => f.to_string(),
|
||||
Expr::BinaryOp { left, op, right } => write!(f, "{} {} {}", left, op, right),
|
||||
Expr::UnaryOp { op, expr } => write!(f, "{} {}", op, expr),
|
||||
Expr::Cast { expr, data_type } => write!(f, "CAST({} AS {})", expr, data_type),
|
||||
Expr::Extract { field, expr } => write!(f, "EXTRACT({} FROM {})", field, expr),
|
||||
Expr::Collate { expr, collation } => write!(f, "{} COLLATE {}", expr, collation),
|
||||
Expr::Nested(ast) => write!(f, "({})", ast),
|
||||
Expr::Value(v) => write!(f, "{}", v),
|
||||
Expr::Function(fun) => write!(f, "{}", fun),
|
||||
Expr::Case {
|
||||
operand,
|
||||
conditions,
|
||||
results,
|
||||
else_result,
|
||||
} => {
|
||||
let mut s = "CASE".to_string();
|
||||
f.write_str("CASE")?;
|
||||
if let Some(operand) = operand {
|
||||
s += &format!(" {}", operand.to_string());
|
||||
write!(f, " {}", operand)?;
|
||||
}
|
||||
s += &conditions
|
||||
.iter()
|
||||
.zip(results)
|
||||
.map(|(c, r)| format!(" WHEN {} THEN {}", c.to_string(), r.to_string()))
|
||||
.collect::<Vec<String>>()
|
||||
.join("");
|
||||
for (c, r) in conditions.iter().zip(results) {
|
||||
write!(f, " WHEN {} THEN {}", c, r)?;
|
||||
}
|
||||
|
||||
if let Some(else_result) = else_result {
|
||||
s += &format!(" ELSE {}", else_result.to_string())
|
||||
write!(f, " ELSE {}", else_result)?;
|
||||
}
|
||||
s + " END"
|
||||
f.write_str(" END")
|
||||
}
|
||||
Expr::Exists(s) => format!("EXISTS ({})", s.to_string()),
|
||||
Expr::Subquery(s) => format!("({})", s.to_string()),
|
||||
Expr::Exists(s) => write!(f, "EXISTS ({})", s),
|
||||
Expr::Subquery(s) => write!(f, "({})", s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -239,38 +250,36 @@ pub struct WindowSpec {
|
|||
pub window_frame: Option<WindowFrame>,
|
||||
}
|
||||
|
||||
impl ToString for WindowSpec {
|
||||
fn to_string(&self) -> String {
|
||||
let mut clauses = vec![];
|
||||
impl fmt::Display for WindowSpec {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut delim = "";
|
||||
if !self.partition_by.is_empty() {
|
||||
clauses.push(format!(
|
||||
delim = " ";
|
||||
write!(
|
||||
f,
|
||||
"PARTITION BY {}",
|
||||
comma_separated_string(&self.partition_by)
|
||||
))
|
||||
};
|
||||
display_comma_separated(&self.partition_by)
|
||||
)?;
|
||||
}
|
||||
if !self.order_by.is_empty() {
|
||||
clauses.push(format!(
|
||||
"ORDER BY {}",
|
||||
comma_separated_string(&self.order_by)
|
||||
))
|
||||
};
|
||||
f.write_str(delim)?;
|
||||
delim = " ";
|
||||
write!(f, "ORDER BY {}", display_comma_separated(&self.order_by))?;
|
||||
}
|
||||
if let Some(window_frame) = &self.window_frame {
|
||||
if let Some(end_bound) = &window_frame.end_bound {
|
||||
clauses.push(format!(
|
||||
f.write_str(delim)?;
|
||||
write!(
|
||||
f,
|
||||
"{} BETWEEN {} AND {}",
|
||||
window_frame.units.to_string(),
|
||||
window_frame.start_bound.to_string(),
|
||||
end_bound.to_string()
|
||||
));
|
||||
window_frame.units, window_frame.start_bound, end_bound
|
||||
)?;
|
||||
} else {
|
||||
clauses.push(format!(
|
||||
"{} {}",
|
||||
window_frame.units.to_string(),
|
||||
window_frame.start_bound.to_string()
|
||||
));
|
||||
f.write_str(delim)?;
|
||||
write!(f, "{} {}", window_frame.units, window_frame.start_bound)?;
|
||||
}
|
||||
}
|
||||
clauses.join(" ")
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -292,13 +301,13 @@ pub enum WindowFrameUnits {
|
|||
Groups,
|
||||
}
|
||||
|
||||
impl ToString for WindowFrameUnits {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
WindowFrameUnits::Rows => "ROWS".to_string(),
|
||||
WindowFrameUnits::Range => "RANGE".to_string(),
|
||||
WindowFrameUnits::Groups => "GROUPS".to_string(),
|
||||
}
|
||||
impl fmt::Display for WindowFrameUnits {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(match self {
|
||||
WindowFrameUnits::Rows => "ROWS",
|
||||
WindowFrameUnits::Range => "RANGE",
|
||||
WindowFrameUnits::Groups => "GROUPS",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -329,14 +338,14 @@ pub enum WindowFrameBound {
|
|||
Following(Option<u64>),
|
||||
}
|
||||
|
||||
impl ToString for WindowFrameBound {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for WindowFrameBound {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
WindowFrameBound::CurrentRow => "CURRENT ROW".to_string(),
|
||||
WindowFrameBound::Preceding(None) => "UNBOUNDED PRECEDING".to_string(),
|
||||
WindowFrameBound::Following(None) => "UNBOUNDED FOLLOWING".to_string(),
|
||||
WindowFrameBound::Preceding(Some(n)) => format!("{} PRECEDING", n),
|
||||
WindowFrameBound::Following(Some(n)) => format!("{} FOLLOWING", n),
|
||||
WindowFrameBound::CurrentRow => f.write_str("CURRENT ROW"),
|
||||
WindowFrameBound::Preceding(None) => f.write_str("UNBOUNDED PRECEDING"),
|
||||
WindowFrameBound::Following(None) => f.write_str("UNBOUNDED FOLLOWING"),
|
||||
WindowFrameBound::Preceding(Some(n)) => write!(f, "{} PRECEDING", n),
|
||||
WindowFrameBound::Following(Some(n)) => write!(f, "{} FOLLOWING", n),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -424,69 +433,70 @@ pub enum Statement {
|
|||
Rollback { chain: bool },
|
||||
}
|
||||
|
||||
impl ToString for Statement {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for Statement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Statement::Query(s) => s.to_string(),
|
||||
Statement::Query(s) => write!(f, "{}", s),
|
||||
Statement::Insert {
|
||||
table_name,
|
||||
columns,
|
||||
source,
|
||||
} => {
|
||||
let mut s = format!("INSERT INTO {} ", table_name.to_string());
|
||||
write!(f, "INSERT INTO {} ", table_name)?;
|
||||
if !columns.is_empty() {
|
||||
s += &format!("({}) ", columns.join(", "));
|
||||
write!(f, "({}) ", display_comma_separated(columns))?;
|
||||
}
|
||||
s += &source.to_string();
|
||||
s
|
||||
write!(f, "{}", source)
|
||||
}
|
||||
Statement::Copy {
|
||||
table_name,
|
||||
columns,
|
||||
values,
|
||||
} => {
|
||||
let mut s = format!("COPY {}", table_name.to_string());
|
||||
write!(f, "COPY {}", table_name)?;
|
||||
if !columns.is_empty() {
|
||||
s += &format!(" ({})", comma_separated_string(columns));
|
||||
write!(f, " ({})", display_comma_separated(columns))?;
|
||||
}
|
||||
s += " FROM stdin; ";
|
||||
write!(f, " FROM stdin; ")?;
|
||||
if !values.is_empty() {
|
||||
s += &format!(
|
||||
"\n{}",
|
||||
values
|
||||
.iter()
|
||||
.map(|v| v.clone().unwrap_or_else(|| "\\N".to_string()))
|
||||
.collect::<Vec<String>>()
|
||||
.join("\t")
|
||||
);
|
||||
writeln!(f)?;
|
||||
let mut delim = "";
|
||||
for v in values {
|
||||
write!(f, "{}", delim)?;
|
||||
delim = "\t";
|
||||
if let Some(v) = v {
|
||||
write!(f, "{}", v)?;
|
||||
} else {
|
||||
write!(f, "\\N")?;
|
||||
}
|
||||
s += "\n\\.";
|
||||
s
|
||||
}
|
||||
}
|
||||
write!(f, "\n\\.")
|
||||
}
|
||||
Statement::Update {
|
||||
table_name,
|
||||
assignments,
|
||||
selection,
|
||||
} => {
|
||||
let mut s = format!("UPDATE {}", table_name.to_string());
|
||||
write!(f, "UPDATE {}", table_name)?;
|
||||
if !assignments.is_empty() {
|
||||
s += " SET ";
|
||||
s += &comma_separated_string(assignments);
|
||||
write!(f, " SET ")?;
|
||||
write!(f, "{}", display_comma_separated(assignments))?;
|
||||
}
|
||||
if let Some(selection) = selection {
|
||||
s += &format!(" WHERE {}", selection.to_string());
|
||||
write!(f, " WHERE {}", selection)?;
|
||||
}
|
||||
s
|
||||
Ok(())
|
||||
}
|
||||
Statement::Delete {
|
||||
table_name,
|
||||
selection,
|
||||
} => {
|
||||
let mut s = format!("DELETE FROM {}", table_name.to_string());
|
||||
write!(f, "DELETE FROM {}", table_name)?;
|
||||
if let Some(selection) = selection {
|
||||
s += &format!(" WHERE {}", selection.to_string());
|
||||
write!(f, " WHERE {}", selection)?;
|
||||
}
|
||||
s
|
||||
Ok(())
|
||||
}
|
||||
Statement::CreateView {
|
||||
name,
|
||||
|
@ -495,25 +505,22 @@ impl ToString for Statement {
|
|||
materialized,
|
||||
with_options,
|
||||
} => {
|
||||
let modifier = if *materialized { " MATERIALIZED" } else { "" };
|
||||
let with_options = if !with_options.is_empty() {
|
||||
format!(" WITH ({})", comma_separated_string(with_options))
|
||||
} else {
|
||||
"".into()
|
||||
};
|
||||
let columns = if !columns.is_empty() {
|
||||
format!(" ({})", comma_separated_string(columns))
|
||||
} else {
|
||||
"".into()
|
||||
};
|
||||
format!(
|
||||
"CREATE{} VIEW {}{}{} AS {}",
|
||||
modifier,
|
||||
name.to_string(),
|
||||
with_options,
|
||||
columns,
|
||||
query.to_string(),
|
||||
)
|
||||
write!(f, "CREATE")?;
|
||||
if *materialized {
|
||||
write!(f, " MATERIALIZED")?;
|
||||
}
|
||||
|
||||
write!(f, " VIEW {}", name)?;
|
||||
|
||||
if !with_options.is_empty() {
|
||||
write!(f, " WITH ({})", display_comma_separated(with_options))?;
|
||||
}
|
||||
|
||||
if !columns.is_empty() {
|
||||
write!(f, " ({})", display_comma_separated(columns))?;
|
||||
}
|
||||
|
||||
write!(f, " AS {}", query)
|
||||
}
|
||||
Statement::CreateTable {
|
||||
name,
|
||||
|
@ -524,64 +531,66 @@ impl ToString for Statement {
|
|||
file_format,
|
||||
location,
|
||||
} => {
|
||||
let mut s = format!(
|
||||
write!(
|
||||
f,
|
||||
"CREATE {}TABLE {} ({}",
|
||||
if *external { "EXTERNAL " } else { "" },
|
||||
name.to_string(),
|
||||
comma_separated_string(columns)
|
||||
);
|
||||
name,
|
||||
display_comma_separated(columns)
|
||||
)?;
|
||||
if !constraints.is_empty() {
|
||||
s += &format!(", {}", comma_separated_string(constraints));
|
||||
write!(f, ", {}", display_comma_separated(constraints))?;
|
||||
}
|
||||
s += ")";
|
||||
write!(f, ")")?;
|
||||
|
||||
if *external {
|
||||
s += &format!(
|
||||
write!(
|
||||
f,
|
||||
" STORED AS {} LOCATION '{}'",
|
||||
file_format.as_ref().unwrap().to_string(),
|
||||
file_format.as_ref().unwrap(),
|
||||
location.as_ref().unwrap()
|
||||
);
|
||||
)?;
|
||||
}
|
||||
if !with_options.is_empty() {
|
||||
s += &format!(" WITH ({})", comma_separated_string(with_options));
|
||||
write!(f, " WITH ({})", display_comma_separated(with_options))?;
|
||||
}
|
||||
s
|
||||
Ok(())
|
||||
}
|
||||
Statement::AlterTable { name, operation } => {
|
||||
format!("ALTER TABLE {} {}", name.to_string(), operation.to_string())
|
||||
write!(f, "ALTER TABLE {} {}", name, operation)
|
||||
}
|
||||
Statement::Drop {
|
||||
object_type,
|
||||
if_exists,
|
||||
names,
|
||||
cascade,
|
||||
} => format!(
|
||||
} => write!(
|
||||
f,
|
||||
"DROP {}{} {}{}",
|
||||
object_type.to_string(),
|
||||
object_type,
|
||||
if *if_exists { " IF EXISTS" } else { "" },
|
||||
comma_separated_string(names),
|
||||
display_comma_separated(names),
|
||||
if *cascade { " CASCADE" } else { "" },
|
||||
),
|
||||
Statement::StartTransaction { modes } => format!(
|
||||
"START TRANSACTION{}",
|
||||
if modes.is_empty() {
|
||||
"".into()
|
||||
} else {
|
||||
format!(" {}", comma_separated_string(modes))
|
||||
Statement::StartTransaction { modes } => {
|
||||
write!(f, "START TRANSACTION")?;
|
||||
if !modes.is_empty() {
|
||||
write!(f, " {}", display_comma_separated(modes))?;
|
||||
}
|
||||
),
|
||||
Statement::SetTransaction { modes } => format!(
|
||||
"SET TRANSACTION{}",
|
||||
if modes.is_empty() {
|
||||
"".into()
|
||||
} else {
|
||||
format!(" {}", comma_separated_string(modes))
|
||||
Ok(())
|
||||
}
|
||||
Statement::SetTransaction { modes } => {
|
||||
write!(f, "SET TRANSACTION")?;
|
||||
if !modes.is_empty() {
|
||||
write!(f, " {}", display_comma_separated(modes))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
),
|
||||
Statement::Commit { chain } => {
|
||||
format!("COMMIT{}", if *chain { " AND CHAIN" } else { "" },)
|
||||
write!(f, "COMMIT{}", if *chain { " AND CHAIN" } else { "" },)
|
||||
}
|
||||
Statement::Rollback { chain } => {
|
||||
format!("ROLLBACK{}", if *chain { " AND CHAIN" } else { "" },)
|
||||
write!(f, "ROLLBACK{}", if *chain { " AND CHAIN" } else { "" },)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -591,9 +600,9 @@ impl ToString for Statement {
|
|||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct ObjectName(pub Vec<Ident>);
|
||||
|
||||
impl ToString for ObjectName {
|
||||
fn to_string(&self) -> String {
|
||||
self.0.join(".")
|
||||
impl fmt::Display for ObjectName {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", display_separated(&self.0, "."))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -604,9 +613,9 @@ pub struct Assignment {
|
|||
pub value: Expr,
|
||||
}
|
||||
|
||||
impl ToString for Assignment {
|
||||
fn to_string(&self) -> String {
|
||||
format!("{} = {}", self.id, self.value.to_string())
|
||||
impl fmt::Display for Assignment {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{} = {}", self.id, self.value)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -620,18 +629,19 @@ pub struct Function {
|
|||
pub distinct: bool,
|
||||
}
|
||||
|
||||
impl ToString for Function {
|
||||
fn to_string(&self) -> String {
|
||||
let mut s = format!(
|
||||
impl fmt::Display for Function {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}({}{})",
|
||||
self.name.to_string(),
|
||||
self.name,
|
||||
if self.distinct { "DISTINCT " } else { "" },
|
||||
comma_separated_string(&self.args),
|
||||
);
|
||||
display_comma_separated(&self.args),
|
||||
)?;
|
||||
if let Some(o) = &self.over {
|
||||
s += &format!(" OVER ({})", o.to_string())
|
||||
write!(f, " OVER ({})", o)?;
|
||||
}
|
||||
s
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -647,18 +657,22 @@ pub enum FileFormat {
|
|||
JSONFILE,
|
||||
}
|
||||
|
||||
impl ToString for FileFormat {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for FileFormat {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use self::FileFormat::*;
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
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(),
|
||||
TEXTFILE => "TEXTFILE",
|
||||
SEQUENCEFILE => "SEQUENCEFILE",
|
||||
ORC => "ORC",
|
||||
PARQUET => "PARQUET",
|
||||
AVRO => "AVRO",
|
||||
RCFILE => "RCFILE",
|
||||
JSONFILE => "TEXTFILE",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -691,12 +705,16 @@ pub enum ObjectType {
|
|||
View,
|
||||
}
|
||||
|
||||
impl ObjectType {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for ObjectType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
ObjectType::Table => "TABLE".into(),
|
||||
ObjectType::View => "VIEW".into(),
|
||||
ObjectType::Table => "TABLE",
|
||||
ObjectType::View => "VIEW",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -706,9 +724,9 @@ pub struct SqlOption {
|
|||
pub value: Value,
|
||||
}
|
||||
|
||||
impl ToString for SqlOption {
|
||||
fn to_string(&self) -> String {
|
||||
format!("{} = {}", self.name.to_string(), self.value.to_string())
|
||||
impl fmt::Display for SqlOption {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{} = {}", self.name, self.value)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -718,12 +736,12 @@ pub enum TransactionMode {
|
|||
IsolationLevel(TransactionIsolationLevel),
|
||||
}
|
||||
|
||||
impl ToString for TransactionMode {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for TransactionMode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use TransactionMode::*;
|
||||
match self {
|
||||
AccessMode(access_mode) => access_mode.to_string(),
|
||||
IsolationLevel(iso_level) => format!("ISOLATION LEVEL {}", iso_level.to_string()),
|
||||
AccessMode(access_mode) => write!(f, "{}", access_mode.to_string()),
|
||||
IsolationLevel(iso_level) => write!(f, "ISOLATION LEVEL {}", iso_level),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -734,13 +752,17 @@ pub enum TransactionAccessMode {
|
|||
ReadWrite,
|
||||
}
|
||||
|
||||
impl ToString for TransactionAccessMode {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for TransactionAccessMode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use TransactionAccessMode::*;
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
ReadOnly => "READ ONLY".into(),
|
||||
ReadWrite => "READ WRITE".into(),
|
||||
ReadOnly => "READ ONLY",
|
||||
ReadWrite => "READ WRITE",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -752,14 +774,18 @@ pub enum TransactionIsolationLevel {
|
|||
Serializable,
|
||||
}
|
||||
|
||||
impl ToString for TransactionIsolationLevel {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for TransactionIsolationLevel {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use TransactionIsolationLevel::*;
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
ReadUncommitted => "READ UNCOMMITTED".into(),
|
||||
ReadCommitted => "READ COMMITTED".into(),
|
||||
RepeatableRead => "REPEATABLE READ".into(),
|
||||
Serializable => "SERIALIZABLE".into(),
|
||||
ReadUncommitted => "READ UNCOMMITTED",
|
||||
ReadCommitted => "READ COMMITTED",
|
||||
RepeatableRead => "REPEATABLE READ",
|
||||
Serializable => "SERIALIZABLE",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::fmt;
|
||||
|
||||
/// Unary operators
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum UnaryOperator {
|
||||
|
@ -18,13 +20,17 @@ pub enum UnaryOperator {
|
|||
Not,
|
||||
}
|
||||
|
||||
impl ToString for UnaryOperator {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for UnaryOperator {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
UnaryOperator::Plus => "+".to_string(),
|
||||
UnaryOperator::Minus => "-".to_string(),
|
||||
UnaryOperator::Not => "NOT".to_string(),
|
||||
UnaryOperator::Plus => "+",
|
||||
UnaryOperator::Minus => "-",
|
||||
UnaryOperator::Not => "NOT",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,24 +54,28 @@ pub enum BinaryOperator {
|
|||
NotLike,
|
||||
}
|
||||
|
||||
impl ToString for BinaryOperator {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for BinaryOperator {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
BinaryOperator::Plus => "+".to_string(),
|
||||
BinaryOperator::Minus => "-".to_string(),
|
||||
BinaryOperator::Multiply => "*".to_string(),
|
||||
BinaryOperator::Divide => "/".to_string(),
|
||||
BinaryOperator::Modulus => "%".to_string(),
|
||||
BinaryOperator::Gt => ">".to_string(),
|
||||
BinaryOperator::Lt => "<".to_string(),
|
||||
BinaryOperator::GtEq => ">=".to_string(),
|
||||
BinaryOperator::LtEq => "<=".to_string(),
|
||||
BinaryOperator::Eq => "=".to_string(),
|
||||
BinaryOperator::NotEq => "<>".to_string(),
|
||||
BinaryOperator::And => "AND".to_string(),
|
||||
BinaryOperator::Or => "OR".to_string(),
|
||||
BinaryOperator::Like => "LIKE".to_string(),
|
||||
BinaryOperator::NotLike => "NOT LIKE".to_string(),
|
||||
BinaryOperator::Plus => "+",
|
||||
BinaryOperator::Minus => "-",
|
||||
BinaryOperator::Multiply => "*",
|
||||
BinaryOperator::Divide => "/",
|
||||
BinaryOperator::Modulus => "%",
|
||||
BinaryOperator::Gt => ">",
|
||||
BinaryOperator::Lt => "<",
|
||||
BinaryOperator::GtEq => ">=",
|
||||
BinaryOperator::LtEq => "<=",
|
||||
BinaryOperator::Eq => "=",
|
||||
BinaryOperator::NotEq => "<>",
|
||||
BinaryOperator::And => "AND",
|
||||
BinaryOperator::Or => "OR",
|
||||
BinaryOperator::Like => "LIKE",
|
||||
BinaryOperator::NotLike => "NOT LIKE",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
236
src/ast/query.rs
236
src/ast/query.rs
|
@ -30,27 +30,25 @@ pub struct Query {
|
|||
pub fetch: Option<Fetch>,
|
||||
}
|
||||
|
||||
impl ToString for Query {
|
||||
fn to_string(&self) -> String {
|
||||
let mut s = String::new();
|
||||
impl fmt::Display for Query {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if !self.ctes.is_empty() {
|
||||
s += &format!("WITH {} ", comma_separated_string(&self.ctes))
|
||||
write!(f, "WITH {} ", display_comma_separated(&self.ctes))?;
|
||||
}
|
||||
s += &self.body.to_string();
|
||||
write!(f, "{}", self.body)?;
|
||||
if !self.order_by.is_empty() {
|
||||
s += &format!(" ORDER BY {}", comma_separated_string(&self.order_by));
|
||||
write!(f, " ORDER BY {}", display_comma_separated(&self.order_by))?;
|
||||
}
|
||||
if let Some(ref limit) = self.limit {
|
||||
s += &format!(" LIMIT {}", limit.to_string());
|
||||
write!(f, " LIMIT {}", limit)?;
|
||||
}
|
||||
if let Some(ref offset) = self.offset {
|
||||
s += &format!(" OFFSET {} ROWS", offset.to_string());
|
||||
write!(f, " OFFSET {} ROWS", offset)?;
|
||||
}
|
||||
if let Some(ref fetch) = self.fetch {
|
||||
s.push(' ');
|
||||
s += &fetch.to_string();
|
||||
write!(f, " {}", fetch)?;
|
||||
}
|
||||
s
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,12 +72,12 @@ pub enum SetExpr {
|
|||
// TODO: ANSI SQL supports `TABLE` here.
|
||||
}
|
||||
|
||||
impl ToString for SetExpr {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for SetExpr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
SetExpr::Select(s) => s.to_string(),
|
||||
SetExpr::Query(q) => format!("({})", q.to_string()),
|
||||
SetExpr::Values(v) => v.to_string(),
|
||||
SetExpr::Select(s) => write!(f, "{}", s),
|
||||
SetExpr::Query(q) => write!(f, "({})", q),
|
||||
SetExpr::Values(v) => write!(f, "{}", v),
|
||||
SetExpr::SetOperation {
|
||||
left,
|
||||
right,
|
||||
|
@ -87,13 +85,7 @@ impl ToString for SetExpr {
|
|||
all,
|
||||
} => {
|
||||
let all_str = if *all { " ALL" } else { "" };
|
||||
format!(
|
||||
"{} {}{} {}",
|
||||
left.to_string(),
|
||||
op.to_string(),
|
||||
all_str,
|
||||
right.to_string()
|
||||
)
|
||||
write!(f, "{} {}{} {}", left, op, all_str, right)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,13 +98,17 @@ pub enum SetOperator {
|
|||
Intersect,
|
||||
}
|
||||
|
||||
impl ToString for SetOperator {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for SetOperator {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
SetOperator::Union => "UNION".to_string(),
|
||||
SetOperator::Except => "EXCEPT".to_string(),
|
||||
SetOperator::Intersect => "INTERSECT".to_string(),
|
||||
SetOperator::Union => "UNION",
|
||||
SetOperator::Except => "EXCEPT",
|
||||
SetOperator::Intersect => "INTERSECT",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,26 +130,27 @@ pub struct Select {
|
|||
pub having: Option<Expr>,
|
||||
}
|
||||
|
||||
impl ToString for Select {
|
||||
fn to_string(&self) -> String {
|
||||
let mut s = format!(
|
||||
impl fmt::Display for Select {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"SELECT{} {}",
|
||||
if self.distinct { " DISTINCT" } else { "" },
|
||||
comma_separated_string(&self.projection)
|
||||
);
|
||||
display_comma_separated(&self.projection)
|
||||
)?;
|
||||
if !self.from.is_empty() {
|
||||
s += &format!(" FROM {}", comma_separated_string(&self.from));
|
||||
write!(f, " FROM {}", display_comma_separated(&self.from))?;
|
||||
}
|
||||
if let Some(ref selection) = self.selection {
|
||||
s += &format!(" WHERE {}", selection.to_string());
|
||||
write!(f, " WHERE {}", selection)?;
|
||||
}
|
||||
if !self.group_by.is_empty() {
|
||||
s += &format!(" GROUP BY {}", comma_separated_string(&self.group_by));
|
||||
write!(f, " GROUP BY {}", display_comma_separated(&self.group_by))?;
|
||||
}
|
||||
if let Some(ref having) = self.having {
|
||||
s += &format!(" HAVING {}", having.to_string());
|
||||
write!(f, " HAVING {}", having)?;
|
||||
}
|
||||
s
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,9 +164,9 @@ pub struct Cte {
|
|||
pub query: Query,
|
||||
}
|
||||
|
||||
impl ToString for Cte {
|
||||
fn to_string(&self) -> String {
|
||||
format!("{} AS ({})", self.alias.to_string(), self.query.to_string())
|
||||
impl fmt::Display for Cte {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{} AS ({})", self.alias, self.query)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,15 +183,13 @@ pub enum SelectItem {
|
|||
Wildcard,
|
||||
}
|
||||
|
||||
impl ToString for SelectItem {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for SelectItem {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match &self {
|
||||
SelectItem::UnnamedExpr(expr) => expr.to_string(),
|
||||
SelectItem::ExprWithAlias { expr, alias } => {
|
||||
format!("{} AS {}", expr.to_string(), alias)
|
||||
}
|
||||
SelectItem::QualifiedWildcard(prefix) => format!("{}.*", prefix.to_string()),
|
||||
SelectItem::Wildcard => "*".to_string(),
|
||||
SelectItem::UnnamedExpr(expr) => write!(f, "{}", expr),
|
||||
SelectItem::ExprWithAlias { expr, alias } => write!(f, "{} AS {}", expr, alias),
|
||||
SelectItem::QualifiedWildcard(prefix) => write!(f, "{}.*", prefix),
|
||||
SelectItem::Wildcard => write!(f, "*"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -205,13 +200,13 @@ pub struct TableWithJoins {
|
|||
pub joins: Vec<Join>,
|
||||
}
|
||||
|
||||
impl ToString for TableWithJoins {
|
||||
fn to_string(&self) -> String {
|
||||
let mut s = self.relation.to_string();
|
||||
impl fmt::Display for TableWithJoins {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.relation)?;
|
||||
for join in &self.joins {
|
||||
s += &join.to_string();
|
||||
write!(f, "{}", join)?;
|
||||
}
|
||||
s
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,8 +235,8 @@ pub enum TableFactor {
|
|||
NestedJoin(Box<TableWithJoins>),
|
||||
}
|
||||
|
||||
impl ToString for TableFactor {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for TableFactor {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
TableFactor::Table {
|
||||
name,
|
||||
|
@ -249,36 +244,33 @@ impl ToString for TableFactor {
|
|||
args,
|
||||
with_hints,
|
||||
} => {
|
||||
let mut s = name.to_string();
|
||||
write!(f, "{}", name)?;
|
||||
if !args.is_empty() {
|
||||
s += &format!("({})", comma_separated_string(args))
|
||||
};
|
||||
write!(f, "({})", display_comma_separated(args))?;
|
||||
}
|
||||
if let Some(alias) = alias {
|
||||
s += &format!(" AS {}", alias.to_string());
|
||||
write!(f, " AS {}", alias)?;
|
||||
}
|
||||
if !with_hints.is_empty() {
|
||||
s += &format!(" WITH ({})", comma_separated_string(with_hints));
|
||||
write!(f, " WITH ({})", display_comma_separated(with_hints))?;
|
||||
}
|
||||
s
|
||||
Ok(())
|
||||
}
|
||||
TableFactor::Derived {
|
||||
lateral,
|
||||
subquery,
|
||||
alias,
|
||||
} => {
|
||||
let mut s = String::new();
|
||||
if *lateral {
|
||||
s += "LATERAL ";
|
||||
write!(f, "LATERAL ")?;
|
||||
}
|
||||
s += &format!("({})", subquery.to_string());
|
||||
write!(f, "({})", subquery)?;
|
||||
if let Some(alias) = alias {
|
||||
s += &format!(" AS {}", alias.to_string());
|
||||
write!(f, " AS {}", alias)?;
|
||||
}
|
||||
s
|
||||
}
|
||||
TableFactor::NestedJoin(table_reference) => {
|
||||
format!("({})", table_reference.to_string())
|
||||
Ok(())
|
||||
}
|
||||
TableFactor::NestedJoin(table_reference) => write!(f, "({})", table_reference),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -289,13 +281,13 @@ pub struct TableAlias {
|
|||
pub columns: Vec<Ident>,
|
||||
}
|
||||
|
||||
impl ToString for TableAlias {
|
||||
fn to_string(&self) -> String {
|
||||
let mut s = self.name.clone();
|
||||
impl fmt::Display for TableAlias {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.name)?;
|
||||
if !self.columns.is_empty() {
|
||||
s += &format!(" ({})", comma_separated_string(&self.columns));
|
||||
write!(f, " ({})", display_comma_separated(&self.columns))?;
|
||||
}
|
||||
s
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -305,49 +297,61 @@ pub struct Join {
|
|||
pub join_operator: JoinOperator,
|
||||
}
|
||||
|
||||
impl ToString for Join {
|
||||
fn to_string(&self) -> String {
|
||||
fn prefix(constraint: &JoinConstraint) -> String {
|
||||
impl fmt::Display for Join {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fn prefix(constraint: &JoinConstraint) -> &'static str {
|
||||
match constraint {
|
||||
JoinConstraint::Natural => "NATURAL ".to_string(),
|
||||
_ => "".to_string(),
|
||||
JoinConstraint::Natural => "NATURAL ",
|
||||
_ => "",
|
||||
}
|
||||
}
|
||||
fn suffix(constraint: &JoinConstraint) -> String {
|
||||
match constraint {
|
||||
JoinConstraint::On(expr) => format!(" ON {}", expr.to_string()),
|
||||
JoinConstraint::Using(attrs) => format!(" USING({})", attrs.join(", ")),
|
||||
_ => "".to_string(),
|
||||
fn suffix<'a>(constraint: &'a JoinConstraint) -> impl fmt::Display + 'a {
|
||||
struct Suffix<'a>(&'a JoinConstraint);
|
||||
impl<'a> fmt::Display for Suffix<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.0 {
|
||||
JoinConstraint::On(expr) => write!(f, " ON {}", expr),
|
||||
JoinConstraint::Using(attrs) => {
|
||||
write!(f, " USING({})", display_comma_separated(attrs))
|
||||
}
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
Suffix(constraint)
|
||||
}
|
||||
match &self.join_operator {
|
||||
JoinOperator::Inner(constraint) => format!(
|
||||
JoinOperator::Inner(constraint) => write!(
|
||||
f,
|
||||
" {}JOIN {}{}",
|
||||
prefix(constraint),
|
||||
self.relation.to_string(),
|
||||
self.relation,
|
||||
suffix(constraint)
|
||||
),
|
||||
JoinOperator::LeftOuter(constraint) => format!(
|
||||
JoinOperator::LeftOuter(constraint) => write!(
|
||||
f,
|
||||
" {}LEFT JOIN {}{}",
|
||||
prefix(constraint),
|
||||
self.relation.to_string(),
|
||||
self.relation,
|
||||
suffix(constraint)
|
||||
),
|
||||
JoinOperator::RightOuter(constraint) => format!(
|
||||
JoinOperator::RightOuter(constraint) => write!(
|
||||
f,
|
||||
" {}RIGHT JOIN {}{}",
|
||||
prefix(constraint),
|
||||
self.relation.to_string(),
|
||||
self.relation,
|
||||
suffix(constraint)
|
||||
),
|
||||
JoinOperator::FullOuter(constraint) => format!(
|
||||
JoinOperator::FullOuter(constraint) => write!(
|
||||
f,
|
||||
" {}FULL JOIN {}{}",
|
||||
prefix(constraint),
|
||||
self.relation.to_string(),
|
||||
self.relation,
|
||||
suffix(constraint)
|
||||
),
|
||||
JoinOperator::CrossJoin => format!(" CROSS JOIN {}", self.relation.to_string()),
|
||||
JoinOperator::CrossApply => format!(" CROSS APPLY {}", self.relation.to_string()),
|
||||
JoinOperator::OuterApply => format!(" OUTER APPLY {}", self.relation.to_string()),
|
||||
JoinOperator::CrossJoin => write!(f, " CROSS JOIN {}", self.relation),
|
||||
JoinOperator::CrossApply => write!(f, " CROSS APPLY {}", self.relation),
|
||||
JoinOperator::OuterApply => write!(f, " OUTER APPLY {}", self.relation),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -379,12 +383,12 @@ pub struct OrderByExpr {
|
|||
pub asc: Option<bool>,
|
||||
}
|
||||
|
||||
impl ToString for OrderByExpr {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for OrderByExpr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.asc {
|
||||
Some(true) => format!("{} ASC", self.expr.to_string()),
|
||||
Some(false) => format!("{} DESC", self.expr.to_string()),
|
||||
None => self.expr.to_string(),
|
||||
Some(true) => write!(f, "{} ASC", self.expr),
|
||||
Some(false) => write!(f, "{} DESC", self.expr),
|
||||
None => write!(f, "{}", self.expr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -396,19 +400,14 @@ pub struct Fetch {
|
|||
pub quantity: Option<Expr>,
|
||||
}
|
||||
|
||||
impl ToString for Fetch {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for Fetch {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let extension = if self.with_ties { "WITH TIES" } else { "ONLY" };
|
||||
if let Some(ref quantity) = self.quantity {
|
||||
let percent = if self.percent { " PERCENT" } else { "" };
|
||||
format!(
|
||||
"FETCH FIRST {}{} ROWS {}",
|
||||
quantity.to_string(),
|
||||
percent,
|
||||
extension
|
||||
)
|
||||
write!(f, "FETCH FIRST {}{} ROWS {}", quantity, percent, extension)
|
||||
} else {
|
||||
format!("FETCH FIRST ROWS {}", extension)
|
||||
write!(f, "FETCH FIRST ROWS {}", extension)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -416,12 +415,15 @@ impl ToString for Fetch {
|
|||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Values(pub Vec<Vec<Expr>>);
|
||||
|
||||
impl ToString for Values {
|
||||
fn to_string(&self) -> String {
|
||||
let rows = self
|
||||
.0
|
||||
.iter()
|
||||
.map(|row| format!("({})", comma_separated_string(row)));
|
||||
format!("VALUES {}", comma_separated_string(rows))
|
||||
impl fmt::Display for Values {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "VALUES ")?;
|
||||
let mut delim = "";
|
||||
for row in &self.0 {
|
||||
write!(f, "{}", delim)?;
|
||||
delim = ", ";
|
||||
write!(f, "({})", display_comma_separated(row))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
use ordered_float::OrderedFloat;
|
||||
use std::fmt;
|
||||
|
||||
/// Primitive SQL values such as number and string
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
@ -56,18 +57,18 @@ pub enum Value {
|
|||
Null,
|
||||
}
|
||||
|
||||
impl ToString for Value {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for Value {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Value::Long(v) => v.to_string(),
|
||||
Value::Double(v) => v.to_string(),
|
||||
Value::SingleQuotedString(v) => format!("'{}'", escape_single_quote_string(v)),
|
||||
Value::NationalStringLiteral(v) => format!("N'{}'", v),
|
||||
Value::HexStringLiteral(v) => format!("X'{}'", v),
|
||||
Value::Boolean(v) => v.to_string(),
|
||||
Value::Date(v) => format!("DATE '{}'", escape_single_quote_string(v)),
|
||||
Value::Time(v) => format!("TIME '{}'", escape_single_quote_string(v)),
|
||||
Value::Timestamp(v) => format!("TIMESTAMP '{}'", escape_single_quote_string(v)),
|
||||
Value::Long(v) => write!(f, "{}", v),
|
||||
Value::Double(v) => write!(f, "{}", v),
|
||||
Value::SingleQuotedString(v) => write!(f, "'{}'", escape_single_quote_string(v)),
|
||||
Value::NationalStringLiteral(v) => write!(f, "N'{}'", v),
|
||||
Value::HexStringLiteral(v) => write!(f, "X'{}'", v),
|
||||
Value::Boolean(v) => write!(f, "{}", v),
|
||||
Value::Date(v) => write!(f, "DATE '{}'", escape_single_quote_string(v)),
|
||||
Value::Time(v) => write!(f, "TIME '{}'", escape_single_quote_string(v)),
|
||||
Value::Timestamp(v) => write!(f, "TIMESTAMP '{}'", escape_single_quote_string(v)),
|
||||
Value::Interval {
|
||||
value,
|
||||
leading_field: DateTimeField::Second,
|
||||
|
@ -78,7 +79,8 @@ impl ToString for Value {
|
|||
// When the leading field is SECOND, the parser guarantees that
|
||||
// the last field is None.
|
||||
assert!(last_field.is_none());
|
||||
format!(
|
||||
write!(
|
||||
f,
|
||||
"INTERVAL '{}' SECOND ({}, {})",
|
||||
escape_single_quote_string(value),
|
||||
leading_precision,
|
||||
|
@ -92,23 +94,24 @@ impl ToString for Value {
|
|||
last_field,
|
||||
fractional_seconds_precision,
|
||||
} => {
|
||||
let mut s = format!(
|
||||
write!(
|
||||
f,
|
||||
"INTERVAL '{}' {}",
|
||||
escape_single_quote_string(value),
|
||||
leading_field.to_string()
|
||||
);
|
||||
leading_field
|
||||
)?;
|
||||
if let Some(leading_precision) = leading_precision {
|
||||
s += &format!(" ({})", leading_precision);
|
||||
write!(f, " ({})", leading_precision)?;
|
||||
}
|
||||
if let Some(last_field) = last_field {
|
||||
s += &format!(" TO {}", last_field.to_string());
|
||||
write!(f, " TO {}", last_field)?;
|
||||
}
|
||||
if let Some(fractional_seconds_precision) = fractional_seconds_precision {
|
||||
s += &format!(" ({})", fractional_seconds_precision);
|
||||
write!(f, " ({})", fractional_seconds_precision)?;
|
||||
}
|
||||
s
|
||||
Ok(())
|
||||
}
|
||||
Value::Null => "NULL".to_string(),
|
||||
Value::Null => write!(f, "NULL"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -123,27 +126,36 @@ pub enum DateTimeField {
|
|||
Second,
|
||||
}
|
||||
|
||||
impl ToString for DateTimeField {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for DateTimeField {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
DateTimeField::Year => "YEAR".to_string(),
|
||||
DateTimeField::Month => "MONTH".to_string(),
|
||||
DateTimeField::Day => "DAY".to_string(),
|
||||
DateTimeField::Hour => "HOUR".to_string(),
|
||||
DateTimeField::Minute => "MINUTE".to_string(),
|
||||
DateTimeField::Second => "SECOND".to_string(),
|
||||
DateTimeField::Year => "YEAR",
|
||||
DateTimeField::Month => "MONTH",
|
||||
DateTimeField::Day => "DAY",
|
||||
DateTimeField::Hour => "HOUR",
|
||||
DateTimeField::Minute => "MINUTE",
|
||||
DateTimeField::Second => "SECOND",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn escape_single_quote_string(s: &str) -> String {
|
||||
let mut escaped = String::new();
|
||||
for c in s.chars() {
|
||||
struct EscapeSingleQuoteString<'a>(&'a str);
|
||||
impl<'a> fmt::Display for EscapeSingleQuoteString<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
for c in self.0.chars() {
|
||||
if c == '\'' {
|
||||
escaped.push_str("\'\'");
|
||||
write!(f, "\'\'")?;
|
||||
} else {
|
||||
escaped.push(c);
|
||||
write!(f, "{}", c)?;
|
||||
}
|
||||
}
|
||||
escaped
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
fn escape_single_quote_string(s: &str) -> EscapeSingleQuoteString<'_> {
|
||||
EscapeSingleQuoteString(s)
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ use super::dialect::keywords;
|
|||
use super::dialect::Dialect;
|
||||
use super::tokenizer::*;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum ParserError {
|
||||
|
@ -52,8 +53,8 @@ impl From<TokenizerError> for ParserError {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ParserError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
impl fmt::Display for ParserError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"sql parser error: {}",
|
||||
|
@ -728,7 +729,7 @@ impl Parser {
|
|||
parser_err!(format!(
|
||||
"Expected {}, found: {}",
|
||||
expected,
|
||||
found.map_or("EOF".to_string(), |t| t.to_string())
|
||||
found.map_or_else(|| "EOF".to_string(), |t| format!("{}", t))
|
||||
))
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ use std::str::Chars;
|
|||
|
||||
use super::dialect::keywords::ALL_KEYWORDS;
|
||||
use super::dialect::Dialect;
|
||||
use std::fmt;
|
||||
|
||||
/// SQL Token enumeration
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
@ -89,40 +90,40 @@ pub enum Token {
|
|||
RBrace,
|
||||
}
|
||||
|
||||
impl ToString for Token {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for Token {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Token::Word(ref w) => w.to_string(),
|
||||
Token::Number(ref n) => n.to_string(),
|
||||
Token::Char(ref c) => c.to_string(),
|
||||
Token::SingleQuotedString(ref s) => format!("'{}'", s),
|
||||
Token::NationalStringLiteral(ref s) => format!("N'{}'", s),
|
||||
Token::HexStringLiteral(ref s) => format!("X'{}'", s),
|
||||
Token::Comma => ",".to_string(),
|
||||
Token::Whitespace(ws) => ws.to_string(),
|
||||
Token::Eq => "=".to_string(),
|
||||
Token::Neq => "<>".to_string(),
|
||||
Token::Lt => "<".to_string(),
|
||||
Token::Gt => ">".to_string(),
|
||||
Token::LtEq => "<=".to_string(),
|
||||
Token::GtEq => ">=".to_string(),
|
||||
Token::Plus => "+".to_string(),
|
||||
Token::Minus => "-".to_string(),
|
||||
Token::Mult => "*".to_string(),
|
||||
Token::Div => "/".to_string(),
|
||||
Token::Mod => "%".to_string(),
|
||||
Token::LParen => "(".to_string(),
|
||||
Token::RParen => ")".to_string(),
|
||||
Token::Period => ".".to_string(),
|
||||
Token::Colon => ":".to_string(),
|
||||
Token::DoubleColon => "::".to_string(),
|
||||
Token::SemiColon => ";".to_string(),
|
||||
Token::Backslash => "\\".to_string(),
|
||||
Token::LBracket => "[".to_string(),
|
||||
Token::RBracket => "]".to_string(),
|
||||
Token::Ampersand => "&".to_string(),
|
||||
Token::LBrace => "{".to_string(),
|
||||
Token::RBrace => "}".to_string(),
|
||||
Token::Word(ref w) => write!(f, "{}", w),
|
||||
Token::Number(ref n) => f.write_str(n),
|
||||
Token::Char(ref c) => write!(f, "{}", c),
|
||||
Token::SingleQuotedString(ref s) => write!(f, "'{}'", s),
|
||||
Token::NationalStringLiteral(ref s) => write!(f, "N'{}'", s),
|
||||
Token::HexStringLiteral(ref s) => write!(f, "X'{}'", s),
|
||||
Token::Comma => f.write_str(","),
|
||||
Token::Whitespace(ws) => write!(f, "{}", ws),
|
||||
Token::Eq => f.write_str("="),
|
||||
Token::Neq => f.write_str("<>"),
|
||||
Token::Lt => f.write_str("<"),
|
||||
Token::Gt => f.write_str(">"),
|
||||
Token::LtEq => f.write_str("<="),
|
||||
Token::GtEq => f.write_str(">="),
|
||||
Token::Plus => f.write_str("+"),
|
||||
Token::Minus => f.write_str("-"),
|
||||
Token::Mult => f.write_str("*"),
|
||||
Token::Div => f.write_str("/"),
|
||||
Token::Mod => f.write_str("%"),
|
||||
Token::LParen => f.write_str("("),
|
||||
Token::RParen => f.write_str(")"),
|
||||
Token::Period => f.write_str("."),
|
||||
Token::Colon => f.write_str(":"),
|
||||
Token::DoubleColon => f.write_str("::"),
|
||||
Token::SemiColon => f.write_str(";"),
|
||||
Token::Backslash => f.write_str("\\"),
|
||||
Token::LBracket => f.write_str("["),
|
||||
Token::RBracket => f.write_str("]"),
|
||||
Token::Ampersand => f.write_str("&"),
|
||||
Token::LBrace => f.write_str("{"),
|
||||
Token::RBrace => f.write_str("}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,13 +165,13 @@ pub struct Word {
|
|||
pub keyword: String,
|
||||
}
|
||||
|
||||
impl ToString for Word {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for Word {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.quote_style {
|
||||
Some(s) if s == '"' || s == '[' || s == '`' => {
|
||||
format!("{}{}{}", s, self.value, Word::matching_end_quote(s))
|
||||
write!(f, "{}{}{}", s, self.value, Word::matching_end_quote(s))
|
||||
}
|
||||
None => self.value.clone(),
|
||||
None => f.write_str(&self.value),
|
||||
_ => panic!("Unexpected quote_style!"),
|
||||
}
|
||||
}
|
||||
|
@ -195,14 +196,14 @@ pub enum Whitespace {
|
|||
MultiLineComment(String),
|
||||
}
|
||||
|
||||
impl ToString for Whitespace {
|
||||
fn to_string(&self) -> String {
|
||||
impl fmt::Display for Whitespace {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Whitespace::Space => " ".to_string(),
|
||||
Whitespace::Newline => "\n".to_string(),
|
||||
Whitespace::Tab => "\t".to_string(),
|
||||
Whitespace::SingleLineComment(s) => format!("--{}", s),
|
||||
Whitespace::MultiLineComment(s) => format!("/*{}*/", s),
|
||||
Whitespace::Space => f.write_str(" "),
|
||||
Whitespace::Newline => f.write_str("\n"),
|
||||
Whitespace::Tab => f.write_str("\t"),
|
||||
Whitespace::SingleLineComment(s) => write!(f, "--{}", s),
|
||||
Whitespace::MultiLineComment(s) => write!(f, "/*{}*/", s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue