mod data_type;
mod ddl;
mod operator;
mod query;
mod value;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::fmt;
pub use self::data_type::DataType;
pub use self::ddl::{
AlterTableOperation, ColumnDef, ColumnOption, ColumnOptionDef, ReferentialAction,
TableConstraint,
};
pub use self::operator::{BinaryOperator, UnaryOperator};
pub use self::query::{
Cte, Fetch, Join, JoinConstraint, JoinOperator, LateralView, Offset, OffsetRows, OrderByExpr,
Query, Select, SelectItem, SetExpr, SetOperator, TableAlias, TableFactor, TableWithJoins, Top,
Values, With,
};
pub use self::value::{DateTimeField, Value};
struct DisplaySeparated<'a, T>
where
T: fmt::Display,
{
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: ", " }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Ident {
pub value: String,
pub quote_style: Option<char>,
}
impl Ident {
pub fn new<S>(value: S) -> Self
where
S: Into<String>,
{
Ident {
value: value.into(),
quote_style: None,
}
}
pub fn with_quote<S>(quote: char, value: S) -> Self
where
S: Into<String>,
{
assert!(quote == '\'' || quote == '"' || quote == '`' || quote == '[');
Ident {
value: value.into(),
quote_style: Some(quote),
}
}
}
impl From<&str> for Ident {
fn from(value: &str) -> Self {
Ident {
value: value.to_string(),
quote_style: None,
}
}
}
impl fmt::Display for Ident {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.quote_style {
Some(q) if q == '"' || q == '\'' || q == '`' => write!(f, "{}{}{}", q, self.value, q),
Some(q) if q == '[' => write!(f, "[{}]", self.value),
None => f.write_str(&self.value),
_ => panic!("unexpected quote style"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ObjectName(pub Vec<Ident>);
impl fmt::Display for ObjectName {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", display_separated(&self.0, "."))
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Expr {
Identifier(Ident),
Wildcard,
QualifiedWildcard(Vec<Ident>),
CompoundIdentifier(Vec<Ident>),
IsNull(Box<Expr>),
IsNotNull(Box<Expr>),
InList {
expr: Box<Expr>,
list: Vec<Expr>,
negated: bool,
},
InSubquery {
expr: Box<Expr>,
subquery: Box<Query>,
negated: bool,
},
Between {
expr: Box<Expr>,
negated: bool,
low: Box<Expr>,
high: Box<Expr>,
},
BinaryOp {
left: Box<Expr>,
op: BinaryOperator,
right: Box<Expr>,
},
UnaryOp {
op: UnaryOperator,
expr: Box<Expr>,
},
Cast {
expr: Box<Expr>,
data_type: DataType,
},
Extract {
field: DateTimeField,
expr: Box<Expr>,
},
Substring {
expr: Box<Expr>,
substring_from: Option<Box<Expr>>,
substring_for: Option<Box<Expr>>,
},
Collate {
expr: Box<Expr>,
collation: ObjectName,
},
Nested(Box<Expr>),
Value(Value),
TypedString {
data_type: DataType,
value: String,
},
MapAccess {
column: Box<Expr>,
key: String,
},
Function(Function),
Case {
operand: Option<Box<Expr>>,
conditions: Vec<Expr>,
results: Vec<Expr>,
else_result: Option<Box<Expr>>,
},
Exists(Box<Query>),
Subquery(Box<Query>),
ListAgg(ListAgg),
}
impl fmt::Display for Expr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Expr::Identifier(s) => write!(f, "{}", s),
Expr::MapAccess { column, key } => write!(f, "{}[\"{}\"]", column, key),
Expr::Wildcard => f.write_str("*"),
Expr::QualifiedWildcard(q) => write!(f, "{}.*", display_separated(q, ".")),
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,
} => write!(
f,
"{} {}IN ({})",
expr,
if *negated { "NOT " } else { "" },
display_comma_separated(list)
),
Expr::InSubquery {
expr,
subquery,
negated,
} => write!(
f,
"{} {}IN ({})",
expr,
if *negated { "NOT " } else { "" },
subquery
),
Expr::Between {
expr,
negated,
low,
high,
} => write!(
f,
"{} {}BETWEEN {} AND {}",
expr,
if *negated { "NOT " } else { "" },
low,
high
),
Expr::BinaryOp { left, op, right } => write!(f, "{} {} {}", left, op, right),
Expr::UnaryOp { op, expr } => {
if op == &UnaryOperator::PGPostfixFactorial {
write!(f, "{}{}", expr, op)
} else {
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::TypedString { data_type, value } => {
write!(f, "{}", data_type)?;
write!(f, " '{}'", &value::escape_single_quote_string(value))
}
Expr::Function(fun) => write!(f, "{}", fun),
Expr::Case {
operand,
conditions,
results,
else_result,
} => {
write!(f, "CASE")?;
if let Some(operand) = operand {
write!(f, " {}", operand)?;
}
for (c, r) in conditions.iter().zip(results) {
write!(f, " WHEN {} THEN {}", c, r)?;
}
if let Some(else_result) = else_result {
write!(f, " ELSE {}", else_result)?;
}
write!(f, " END")
}
Expr::Exists(s) => write!(f, "EXISTS ({})", s),
Expr::Subquery(s) => write!(f, "({})", s),
Expr::ListAgg(listagg) => write!(f, "{}", listagg),
Expr::Substring {
expr,
substring_from,
substring_for,
} => {
write!(f, "SUBSTRING({}", expr)?;
if let Some(from_part) = substring_from {
write!(f, " FROM {}", from_part)?;
}
if let Some(from_part) = substring_for {
write!(f, " FOR {}", from_part)?;
}
write!(f, ")")
}
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct WindowSpec {
pub partition_by: Vec<Expr>,
pub order_by: Vec<OrderByExpr>,
pub window_frame: Option<WindowFrame>,
}
impl fmt::Display for WindowSpec {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut delim = "";
if !self.partition_by.is_empty() {
delim = " ";
write!(
f,
"PARTITION BY {}",
display_comma_separated(&self.partition_by)
)?;
}
if !self.order_by.is_empty() {
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 {
f.write_str(delim)?;
write!(
f,
"{} BETWEEN {} AND {}",
window_frame.units, window_frame.start_bound, end_bound
)?;
} else {
f.write_str(delim)?;
write!(f, "{} {}", window_frame.units, window_frame.start_bound)?;
}
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct WindowFrame {
pub units: WindowFrameUnits,
pub start_bound: WindowFrameBound,
pub end_bound: Option<WindowFrameBound>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum WindowFrameUnits {
Rows,
Range,
Groups,
}
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",
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum WindowFrameBound {
CurrentRow,
Preceding(Option<u64>),
Following(Option<u64>),
}
impl fmt::Display for WindowFrameBound {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
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),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum AddDropSync {
ADD,
DROP,
SYNC,
}
impl fmt::Display for AddDropSync {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AddDropSync::SYNC => f.write_str("SYNC PARTITIONS"),
AddDropSync::DROP => f.write_str("DROP PARTITIONS"),
AddDropSync::ADD => f.write_str("ADD PARTITIONS"),
}
}
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Statement {
Analyze {
table_name: ObjectName,
partitions: Option<Vec<Expr>>,
for_columns: bool,
columns: Vec<Ident>,
cache_metadata: bool,
noscan: bool,
compute_statistics: bool,
},
Truncate {
table_name: ObjectName,
partitions: Option<Vec<Expr>>,
},
Msck {
table_name: ObjectName,
repair: bool,
partition_action: Option<AddDropSync>,
},
Query(Box<Query>),
Insert {
or: Option<SqliteOnConflict>,
table_name: ObjectName,
columns: Vec<Ident>,
overwrite: bool,
source: Box<Query>,
partitioned: Option<Vec<Expr>>,
after_columns: Vec<Ident>,
table: bool,
},
Directory {
overwrite: bool,
local: bool,
path: String,
file_format: Option<FileFormat>,
source: Box<Query>,
},
Copy {
table_name: ObjectName,
columns: Vec<Ident>,
values: Vec<Option<String>>,
},
Update {
table_name: ObjectName,
assignments: Vec<Assignment>,
selection: Option<Expr>,
},
Delete {
table_name: ObjectName,
selection: Option<Expr>,
},
CreateView {
or_replace: bool,
materialized: bool,
name: ObjectName,
columns: Vec<Ident>,
query: Box<Query>,
with_options: Vec<SqlOption>,
},
CreateTable {
or_replace: bool,
temporary: bool,
external: bool,
if_not_exists: bool,
name: ObjectName,
columns: Vec<ColumnDef>,
constraints: Vec<TableConstraint>,
hive_distribution: HiveDistributionStyle,
hive_formats: Option<HiveFormat>,
table_properties: Vec<SqlOption>,
with_options: Vec<SqlOption>,
file_format: Option<FileFormat>,
location: Option<String>,
query: Option<Box<Query>>,
without_rowid: bool,
like: Option<ObjectName>,
},
CreateVirtualTable {
name: ObjectName,
if_not_exists: bool,
module_name: Ident,
module_args: Vec<Ident>,
},
CreateIndex {
name: ObjectName,
table_name: ObjectName,
columns: Vec<OrderByExpr>,
unique: bool,
if_not_exists: bool,
},
AlterTable {
name: ObjectName,
operation: AlterTableOperation,
},
Drop {
object_type: ObjectType,
if_exists: bool,
names: Vec<ObjectName>,
cascade: bool,
purge: bool,
},
SetVariable {
local: bool,
hivevar: bool,
variable: Ident,
value: Vec<SetVariableValue>,
},
ShowVariable { variable: Vec<Ident> },
ShowColumns {
extended: bool,
full: bool,
table_name: ObjectName,
filter: Option<ShowStatementFilter>,
},
StartTransaction { modes: Vec<TransactionMode> },
SetTransaction { modes: Vec<TransactionMode> },
Commit { chain: bool },
Rollback { chain: bool },
CreateSchema {
schema_name: ObjectName,
if_not_exists: bool,
},
CreateDatabase {
db_name: ObjectName,
if_not_exists: bool,
location: Option<String>,
managed_location: Option<String>,
},
Assert {
condition: Expr,
message: Option<Expr>,
},
Deallocate { name: Ident, prepare: bool },
Execute { name: Ident, parameters: Vec<Expr> },
Prepare {
name: Ident,
data_types: Vec<DataType>,
statement: Box<Statement>,
},
Explain {
analyze: bool,
verbose: bool,
statement: Box<Statement>,
},
}
impl fmt::Display for Statement {
#[allow(clippy::cognitive_complexity)]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Statement::Explain {
verbose,
analyze,
statement,
} => {
write!(f, "EXPLAIN ")?;
if *analyze {
write!(f, "ANALYZE ")?;
}
if *verbose {
write!(f, "VERBOSE ")?;
}
write!(f, "{}", statement)
}
Statement::Query(s) => write!(f, "{}", s),
Statement::Directory {
overwrite,
local,
path,
file_format,
source,
} => {
write!(
f,
"INSERT{overwrite}{local} DIRECTORY '{path}'",
overwrite = if *overwrite { " OVERWRITE" } else { "" },
local = if *local { " LOCAL" } else { "" },
path = path
)?;
if let Some(ref ff) = file_format {
write!(f, " STORED AS {}", ff)?
}
write!(f, " {}", source)
}
Statement::Msck {
table_name,
repair,
partition_action,
} => {
write!(
f,
"MSCK {repair}TABLE {table}",
repair = if *repair { "REPAIR " } else { "" },
table = table_name
)?;
if let Some(pa) = partition_action {
write!(f, " {}", pa)?;
}
Ok(())
}
Statement::Truncate {
table_name,
partitions,
} => {
write!(f, "TRUNCATE TABLE {}", table_name)?;
if let Some(ref parts) = partitions {
if !parts.is_empty() {
write!(f, " PARTITION ({})", display_comma_separated(parts))?;
}
}
Ok(())
}
Statement::Analyze {
table_name,
partitions,
for_columns,
columns,
cache_metadata,
noscan,
compute_statistics,
} => {
write!(f, "ANALYZE TABLE {}", table_name)?;
if let Some(ref parts) = partitions {
if !parts.is_empty() {
write!(f, " PARTITION ({})", display_comma_separated(parts))?;
}
}
if *compute_statistics {
write!(f, " COMPUTE STATISTICS")?;
}
if *noscan {
write!(f, " NOSCAN")?;
}
if *cache_metadata {
write!(f, " CACHE METADATA")?;
}
if *for_columns {
write!(f, " FOR COLUMNS")?;
if !columns.is_empty() {
write!(f, " {}", display_comma_separated(columns))?;
}
}
Ok(())
}
Statement::Insert {
or,
table_name,
overwrite,
partitioned,
columns,
after_columns,
source,
table,
} => {
if let Some(action) = or {
write!(f, "INSERT OR {} INTO {} ", action, table_name)?;
} else {
write!(
f,
"INSERT {act}{tbl} {table_name} ",
table_name = table_name,
act = if *overwrite { "OVERWRITE" } else { "INTO" },
tbl = if *table { " TABLE" } else { "" }
)?;
}
if !columns.is_empty() {
write!(f, "({}) ", display_comma_separated(columns))?;
}
if let Some(ref parts) = partitioned {
if !parts.is_empty() {
write!(f, "PARTITION ({}) ", display_comma_separated(parts))?;
}
}
if !after_columns.is_empty() {
write!(f, "({}) ", display_comma_separated(after_columns))?;
}
write!(f, "{}", source)
}
Statement::Copy {
table_name,
columns,
values,
} => {
write!(f, "COPY {}", table_name)?;
if !columns.is_empty() {
write!(f, " ({})", display_comma_separated(columns))?;
}
write!(f, " FROM stdin; ")?;
if !values.is_empty() {
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")?;
}
}
}
write!(f, "\n\\.")
}
Statement::Update {
table_name,
assignments,
selection,
} => {
write!(f, "UPDATE {}", table_name)?;
if !assignments.is_empty() {
write!(f, " SET {}", display_comma_separated(assignments))?;
}
if let Some(selection) = selection {
write!(f, " WHERE {}", selection)?;
}
Ok(())
}
Statement::Delete {
table_name,
selection,
} => {
write!(f, "DELETE FROM {}", table_name)?;
if let Some(selection) = selection {
write!(f, " WHERE {}", selection)?;
}
Ok(())
}
Statement::CreateDatabase {
db_name,
if_not_exists,
location,
managed_location,
} => {
write!(f, "CREATE")?;
if *if_not_exists {
write!(f, " IF NOT EXISTS")?;
}
write!(f, " {}", db_name)?;
if let Some(l) = location {
write!(f, " LOCATION '{}'", l)?;
}
if let Some(ml) = managed_location {
write!(f, " MANAGEDLOCATION '{}'", ml)?;
}
Ok(())
}
Statement::CreateView {
name,
or_replace,
columns,
query,
materialized,
with_options,
} => {
write!(
f,
"CREATE {or_replace}{materialized}VIEW {name}",
or_replace = if *or_replace { "OR REPLACE " } else { "" },
materialized = if *materialized { "MATERIALIZED " } else { "" },
name = 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,
columns,
constraints,
table_properties,
with_options,
or_replace,
if_not_exists,
hive_distribution,
hive_formats,
external,
temporary,
file_format,
location,
query,
without_rowid,
like,
} => {
write!(
f,
"CREATE {or_replace}{external}{temporary}TABLE {if_not_exists}{name}",
or_replace = if *or_replace { "OR REPLACE " } else { "" },
external = if *external { "EXTERNAL " } else { "" },
if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
temporary = if *temporary { "TEMPORARY " } else { "" },
name = name,
)?;
if !columns.is_empty() || !constraints.is_empty() {
write!(f, " ({}", display_comma_separated(columns))?;
if !columns.is_empty() && !constraints.is_empty() {
write!(f, ", ")?;
}
write!(f, "{})", display_comma_separated(constraints))?;
} else if query.is_none() && like.is_none() {
write!(f, " ()")?;
}
if *without_rowid {
write!(f, " WITHOUT ROWID")?;
}
if let Some(l) = like {
write!(f, " LIKE {}", l)?;
}
match hive_distribution {
HiveDistributionStyle::PARTITIONED { columns } => {
write!(f, " PARTITIONED BY ({})", display_comma_separated(&columns))?;
}
HiveDistributionStyle::CLUSTERED {
columns,
sorted_by,
num_buckets,
} => {
write!(f, " CLUSTERED BY ({})", display_comma_separated(&columns))?;
if !sorted_by.is_empty() {
write!(f, " SORTED BY ({})", display_comma_separated(&sorted_by))?;
}
if *num_buckets > 0 {
write!(f, " INTO {} BUCKETS", num_buckets)?;
}
}
HiveDistributionStyle::SKEWED {
columns,
on,
stored_as_directories,
} => {
write!(
f,
" SKEWED BY ({})) ON ({})",
display_comma_separated(&columns),
display_comma_separated(&on)
)?;
if *stored_as_directories {
write!(f, " STORED AS DIRECTORIES")?;
}
}
_ => (),
}
if let Some(HiveFormat {
row_format,
storage,
location,
}) = hive_formats
{
match row_format {
Some(HiveRowFormat::SERDE { class }) => {
write!(f, " ROW FORMAT SERDE '{}'", class)?
}
Some(HiveRowFormat::DELIMITED) => write!(f, " ROW FORMAT DELIMITED")?,
None => (),
}
match storage {
Some(HiveIOFormat::IOF {
input_format,
output_format,
}) => write!(
f,
" STORED AS INPUTFORMAT {} OUTPUTFORMAT {}",
input_format, output_format
)?,
Some(HiveIOFormat::FileFormat { format }) if !*external => {
write!(f, " STORED AS {}", format)?
}
_ => (),
}
if !*external {
if let Some(loc) = location {
write!(f, " LOCATION '{}'", loc)?;
}
}
}
if *external {
write!(
f,
" STORED AS {} LOCATION '{}'",
file_format.as_ref().unwrap(),
location.as_ref().unwrap()
)?;
}
if !table_properties.is_empty() {
write!(
f,
" TBLPROPERTIES ({})",
display_comma_separated(table_properties)
)?;
}
if !with_options.is_empty() {
write!(f, " WITH ({})", display_comma_separated(with_options))?;
}
if let Some(query) = query {
write!(f, " AS {}", query)?;
}
Ok(())
}
Statement::CreateVirtualTable {
name,
if_not_exists,
module_name,
module_args,
} => {
write!(
f,
"CREATE VIRTUAL TABLE {if_not_exists}{name} USING {module_name}",
if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
name = name,
module_name = module_name
)?;
if !module_args.is_empty() {
write!(f, " ({})", display_comma_separated(module_args))?;
}
Ok(())
}
Statement::CreateIndex {
name,
table_name,
columns,
unique,
if_not_exists,
} => write!(
f,
"CREATE {unique}INDEX {if_not_exists}{name} ON {table_name}({columns})",
unique = if *unique { "UNIQUE " } else { "" },
if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
name = name,
table_name = table_name,
columns = display_separated(columns, ",")
),
Statement::AlterTable { name, operation } => {
write!(f, "ALTER TABLE {} {}", name, operation)
}
Statement::Drop {
object_type,
if_exists,
names,
cascade,
purge,
} => write!(
f,
"DROP {}{} {}{}{}",
object_type,
if *if_exists { " IF EXISTS" } else { "" },
display_comma_separated(names),
if *cascade { " CASCADE" } else { "" },
if *purge { " PURGE" } else { "" }
),
Statement::SetVariable {
local,
variable,
hivevar,
value,
} => {
f.write_str("SET ")?;
if *local {
f.write_str("LOCAL ")?;
}
write!(
f,
"{hivevar}{name} = {value}",
hivevar = if *hivevar { "HIVEVAR:" } else { "" },
name = variable,
value = display_comma_separated(value)
)
}
Statement::ShowVariable { variable } => {
write!(f, "SHOW")?;
if !variable.is_empty() {
write!(f, " {}", display_separated(variable, " "))?;
}
Ok(())
}
Statement::ShowColumns {
extended,
full,
table_name,
filter,
} => {
write!(
f,
"SHOW {extended}{full}COLUMNS FROM {table_name}",
extended = if *extended { "EXTENDED " } else { "" },
full = if *full { "FULL " } else { "" },
table_name = table_name,
)?;
if let Some(filter) = filter {
write!(f, " {}", filter)?;
}
Ok(())
}
Statement::StartTransaction { modes } => {
write!(f, "START TRANSACTION")?;
if !modes.is_empty() {
write!(f, " {}", display_comma_separated(modes))?;
}
Ok(())
}
Statement::SetTransaction { modes } => {
write!(f, "SET TRANSACTION")?;
if !modes.is_empty() {
write!(f, " {}", display_comma_separated(modes))?;
}
Ok(())
}
Statement::Commit { chain } => {
write!(f, "COMMIT{}", if *chain { " AND CHAIN" } else { "" },)
}
Statement::Rollback { chain } => {
write!(f, "ROLLBACK{}", if *chain { " AND CHAIN" } else { "" },)
}
Statement::CreateSchema {
schema_name,
if_not_exists,
} => write!(
f,
"CREATE SCHEMA {if_not_exists}{name}",
if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
name = schema_name
),
Statement::Assert { condition, message } => {
write!(f, "ASSERT {}", condition)?;
if let Some(m) = message {
write!(f, " AS {}", m)?;
}
Ok(())
}
Statement::Deallocate { name, prepare } => write!(
f,
"DEALLOCATE {prepare}{name}",
prepare = if *prepare { "PREPARE " } else { "" },
name = name,
),
Statement::Execute { name, parameters } => {
write!(f, "EXECUTE {}", name)?;
if !parameters.is_empty() {
write!(f, "({})", display_comma_separated(parameters))?;
}
Ok(())
}
Statement::Prepare {
name,
data_types,
statement,
} => {
write!(f, "PREPARE {} ", name)?;
if !data_types.is_empty() {
write!(f, "({}) ", display_comma_separated(data_types))?;
}
write!(f, "AS {}", statement)
}
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Assignment {
pub id: Ident,
pub value: Expr,
}
impl fmt::Display for Assignment {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = {}", self.id, self.value)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum FunctionArg {
Named { name: Ident, arg: Expr },
Unnamed(Expr),
}
impl fmt::Display for FunctionArg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
FunctionArg::Named { name, arg } => write!(f, "{} => {}", name, arg),
FunctionArg::Unnamed(unnamed_arg) => write!(f, "{}", unnamed_arg),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Function {
pub name: ObjectName,
pub args: Vec<FunctionArg>,
pub over: Option<WindowSpec>,
pub distinct: bool,
}
impl fmt::Display for Function {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}({}{})",
self.name,
if self.distinct { "DISTINCT " } else { "" },
display_comma_separated(&self.args),
)?;
if let Some(o) = &self.over {
write!(f, " OVER ({})", o)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum FileFormat {
TEXTFILE,
SEQUENCEFILE,
ORC,
PARQUET,
AVRO,
RCFILE,
JSONFILE,
}
impl fmt::Display for FileFormat {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::FileFormat::*;
f.write_str(match self {
TEXTFILE => "TEXTFILE",
SEQUENCEFILE => "SEQUENCEFILE",
ORC => "ORC",
PARQUET => "PARQUET",
AVRO => "AVRO",
RCFILE => "RCFILE",
JSONFILE => "JSONFILE",
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ListAgg {
pub distinct: bool,
pub expr: Box<Expr>,
pub separator: Option<Box<Expr>>,
pub on_overflow: Option<ListAggOnOverflow>,
pub within_group: Vec<OrderByExpr>,
}
impl fmt::Display for ListAgg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"LISTAGG({}{}",
if self.distinct { "DISTINCT " } else { "" },
self.expr
)?;
if let Some(separator) = &self.separator {
write!(f, ", {}", separator)?;
}
if let Some(on_overflow) = &self.on_overflow {
write!(f, "{}", on_overflow)?;
}
write!(f, ")")?;
if !self.within_group.is_empty() {
write!(
f,
" WITHIN GROUP (ORDER BY {})",
display_comma_separated(&self.within_group)
)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum ListAggOnOverflow {
Error,
Truncate {
filler: Option<Box<Expr>>,
with_count: bool,
},
}
impl fmt::Display for ListAggOnOverflow {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, " ON OVERFLOW")?;
match self {
ListAggOnOverflow::Error => write!(f, " ERROR"),
ListAggOnOverflow::Truncate { filler, with_count } => {
write!(f, " TRUNCATE")?;
if let Some(filler) = filler {
write!(f, " {}", filler)?;
}
if *with_count {
write!(f, " WITH")?;
} else {
write!(f, " WITHOUT")?;
}
write!(f, " COUNT")
}
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum ObjectType {
Table,
View,
Index,
Schema,
}
impl fmt::Display for ObjectType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match self {
ObjectType::Table => "TABLE",
ObjectType::View => "VIEW",
ObjectType::Index => "INDEX",
ObjectType::Schema => "SCHEMA",
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum HiveDistributionStyle {
PARTITIONED {
columns: Vec<ColumnDef>,
},
CLUSTERED {
columns: Vec<Ident>,
sorted_by: Vec<ColumnDef>,
num_buckets: i32,
},
SKEWED {
columns: Vec<ColumnDef>,
on: Vec<ColumnDef>,
stored_as_directories: bool,
},
NONE,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum HiveRowFormat {
SERDE { class: String },
DELIMITED,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum HiveIOFormat {
IOF {
input_format: Expr,
output_format: Expr,
},
FileFormat {
format: FileFormat,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct HiveFormat {
pub row_format: Option<HiveRowFormat>,
pub storage: Option<HiveIOFormat>,
pub location: Option<String>,
}
impl Default for HiveFormat {
fn default() -> Self {
HiveFormat {
row_format: None,
location: None,
storage: None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct SqlOption {
pub name: Ident,
pub value: Value,
}
impl fmt::Display for SqlOption {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = {}", self.name, self.value)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum TransactionMode {
AccessMode(TransactionAccessMode),
IsolationLevel(TransactionIsolationLevel),
}
impl fmt::Display for TransactionMode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use TransactionMode::*;
match self {
AccessMode(access_mode) => write!(f, "{}", access_mode),
IsolationLevel(iso_level) => write!(f, "ISOLATION LEVEL {}", iso_level),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum TransactionAccessMode {
ReadOnly,
ReadWrite,
}
impl fmt::Display for TransactionAccessMode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use TransactionAccessMode::*;
f.write_str(match self {
ReadOnly => "READ ONLY",
ReadWrite => "READ WRITE",
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum TransactionIsolationLevel {
ReadUncommitted,
ReadCommitted,
RepeatableRead,
Serializable,
}
impl fmt::Display for TransactionIsolationLevel {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use TransactionIsolationLevel::*;
f.write_str(match self {
ReadUncommitted => "READ UNCOMMITTED",
ReadCommitted => "READ COMMITTED",
RepeatableRead => "REPEATABLE READ",
Serializable => "SERIALIZABLE",
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum ShowStatementFilter {
Like(String),
Where(Expr),
}
impl fmt::Display for ShowStatementFilter {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use ShowStatementFilter::*;
match self {
Like(pattern) => write!(f, "LIKE '{}'", value::escape_single_quote_string(pattern)),
Where(expr) => write!(f, "WHERE {}", expr),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum SetVariableValue {
Ident(Ident),
Literal(Value),
}
impl fmt::Display for SetVariableValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use SetVariableValue::*;
match self {
Ident(ident) => write!(f, "{}", ident),
Literal(literal) => write!(f, "{}", literal),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum SqliteOnConflict {
Rollback,
Abort,
Fail,
Ignore,
Replace,
}
impl fmt::Display for SqliteOnConflict {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use SqliteOnConflict::*;
match self {
Rollback => write!(f, "ROLLBACK"),
Abort => write!(f, "ABORT"),
Fail => write!(f, "FAIL"),
Ignore => write!(f, "IGNORE"),
Replace => write!(f, "REPLACE"),
}
}
}