#[cfg(not(feature = "std"))]
use alloc::{boxed::Box, vec::Vec};
use helpers::attached_token::AttachedToken;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "visitor")]
use sqlparser_derive::{Visit, VisitMut};
use crate::{
ast::*,
display_utils::{indented_list, SpaceOrNewline},
tokenizer::{Token, TokenWithSpan},
};
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
#[cfg_attr(feature = "visitor", visit(with = "visit_query"))]
pub struct Query {
pub with: Option<With>,
pub body: Box<SetExpr>,
pub order_by: Option<OrderBy>,
pub limit_clause: Option<LimitClause>,
pub fetch: Option<Fetch>,
pub locks: Vec<LockClause>,
pub for_clause: Option<ForClause>,
pub settings: Option<Vec<Setting>>,
pub format_clause: Option<FormatClause>,
pub pipe_operators: Vec<PipeOperator>,
}
impl fmt::Display for Query {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(ref with) = self.with {
with.fmt(f)?;
SpaceOrNewline.fmt(f)?;
}
self.body.fmt(f)?;
if let Some(ref order_by) = self.order_by {
f.write_str(" ")?;
order_by.fmt(f)?;
}
if let Some(ref limit_clause) = self.limit_clause {
limit_clause.fmt(f)?;
}
if let Some(ref settings) = self.settings {
f.write_str(" SETTINGS ")?;
display_comma_separated(settings).fmt(f)?;
}
if let Some(ref fetch) = self.fetch {
f.write_str(" ")?;
fetch.fmt(f)?;
}
if !self.locks.is_empty() {
f.write_str(" ")?;
display_separated(&self.locks, " ").fmt(f)?;
}
if let Some(ref for_clause) = self.for_clause {
f.write_str(" ")?;
for_clause.fmt(f)?;
}
if let Some(ref format) = self.format_clause {
f.write_str(" ")?;
format.fmt(f)?;
}
for pipe_operator in &self.pipe_operators {
f.write_str(" |> ")?;
pipe_operator.fmt(f)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct ProjectionSelect {
pub projection: Vec<SelectItem>,
pub order_by: Option<OrderBy>,
pub group_by: Option<GroupByExpr>,
}
impl fmt::Display for ProjectionSelect {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "SELECT {}", display_comma_separated(&self.projection))?;
if let Some(ref group_by) = self.group_by {
write!(f, " {group_by}")?;
}
if let Some(ref order_by) = self.order_by {
write!(f, " {order_by}")?;
}
Ok(())
}
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum SetExpr {
Select(Box<Select>),
Query(Box<Query>),
SetOperation {
op: SetOperator,
set_quantifier: SetQuantifier,
left: Box<SetExpr>,
right: Box<SetExpr>,
},
Values(Values),
Insert(Statement),
Update(Statement),
Delete(Statement),
Merge(Statement),
Table(Box<Table>),
}
impl SetExpr {
pub fn as_select(&self) -> Option<&Select> {
if let Self::Select(select) = self {
Some(&**select)
} else {
None
}
}
}
impl fmt::Display for SetExpr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
SetExpr::Select(s) => s.fmt(f),
SetExpr::Query(q) => {
f.write_str("(")?;
q.fmt(f)?;
f.write_str(")")
}
SetExpr::Values(v) => v.fmt(f),
SetExpr::Insert(v) => v.fmt(f),
SetExpr::Update(v) => v.fmt(f),
SetExpr::Delete(v) => v.fmt(f),
SetExpr::Merge(v) => v.fmt(f),
SetExpr::Table(t) => t.fmt(f),
SetExpr::SetOperation {
left,
right,
op,
set_quantifier,
} => {
left.fmt(f)?;
SpaceOrNewline.fmt(f)?;
op.fmt(f)?;
match set_quantifier {
SetQuantifier::All
| SetQuantifier::Distinct
| SetQuantifier::ByName
| SetQuantifier::AllByName
| SetQuantifier::DistinctByName => {
f.write_str(" ")?;
set_quantifier.fmt(f)?;
}
SetQuantifier::None => {}
}
SpaceOrNewline.fmt(f)?;
right.fmt(f)?;
Ok(())
}
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum SetOperator {
Union,
Except,
Intersect,
Minus,
}
impl fmt::Display for SetOperator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match self {
SetOperator::Union => "UNION",
SetOperator::Except => "EXCEPT",
SetOperator::Intersect => "INTERSECT",
SetOperator::Minus => "MINUS",
})
}
}
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum SetQuantifier {
All,
Distinct,
ByName,
AllByName,
DistinctByName,
None,
}
impl fmt::Display for SetQuantifier {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
SetQuantifier::All => write!(f, "ALL"),
SetQuantifier::Distinct => write!(f, "DISTINCT"),
SetQuantifier::ByName => write!(f, "BY NAME"),
SetQuantifier::AllByName => write!(f, "ALL BY NAME"),
SetQuantifier::DistinctByName => write!(f, "DISTINCT BY NAME"),
SetQuantifier::None => Ok(()),
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct Table {
pub table_name: Option<String>,
pub schema_name: Option<String>,
}
impl fmt::Display for Table {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(ref schema_name) = self.schema_name {
write!(
f,
"TABLE {}.{}",
schema_name,
self.table_name.as_ref().unwrap(),
)?;
} else {
write!(f, "TABLE {}", self.table_name.as_ref().unwrap(),)?;
}
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum SelectFlavor {
Standard,
FromFirst,
FromFirstNoSelect,
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct SelectModifiers {
pub high_priority: bool,
pub straight_join: bool,
pub sql_small_result: bool,
pub sql_big_result: bool,
pub sql_buffer_result: bool,
pub sql_no_cache: bool,
pub sql_calc_found_rows: bool,
}
impl fmt::Display for SelectModifiers {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.high_priority {
f.write_str(" HIGH_PRIORITY")?;
}
if self.straight_join {
f.write_str(" STRAIGHT_JOIN")?;
}
if self.sql_small_result {
f.write_str(" SQL_SMALL_RESULT")?;
}
if self.sql_big_result {
f.write_str(" SQL_BIG_RESULT")?;
}
if self.sql_buffer_result {
f.write_str(" SQL_BUFFER_RESULT")?;
}
if self.sql_no_cache {
f.write_str(" SQL_NO_CACHE")?;
}
if self.sql_calc_found_rows {
f.write_str(" SQL_CALC_FOUND_ROWS")?;
}
Ok(())
}
}
impl SelectModifiers {
pub fn is_any_set(&self) -> bool {
let Self {
high_priority,
straight_join,
sql_small_result,
sql_big_result,
sql_buffer_result,
sql_no_cache,
sql_calc_found_rows,
} = self;
*high_priority
|| *straight_join
|| *sql_small_result
|| *sql_big_result
|| *sql_buffer_result
|| *sql_no_cache
|| *sql_calc_found_rows
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct Select {
pub select_token: AttachedToken,
pub optimizer_hint: Option<OptimizerHint>,
pub distinct: Option<Distinct>,
pub select_modifiers: Option<SelectModifiers>,
pub top: Option<Top>,
pub top_before_distinct: bool,
pub projection: Vec<SelectItem>,
pub exclude: Option<ExcludeSelectItem>,
pub into: Option<SelectInto>,
pub from: Vec<TableWithJoins>,
pub lateral_views: Vec<LateralView>,
pub prewhere: Option<Expr>,
pub selection: Option<Expr>,
pub connect_by: Vec<ConnectByKind>,
pub group_by: GroupByExpr,
pub cluster_by: Vec<Expr>,
pub distribute_by: Vec<Expr>,
pub sort_by: Vec<OrderByExpr>,
pub having: Option<Expr>,
pub named_window: Vec<NamedWindowDefinition>,
pub qualify: Option<Expr>,
pub window_before_qualify: bool,
pub value_table_mode: Option<ValueTableMode>,
pub flavor: SelectFlavor,
}
impl fmt::Display for Select {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.flavor {
SelectFlavor::Standard => {
write!(f, "SELECT")?;
}
SelectFlavor::FromFirst => {
write!(f, "FROM {} SELECT", display_comma_separated(&self.from))?;
}
SelectFlavor::FromFirstNoSelect => {
write!(f, "FROM {}", display_comma_separated(&self.from))?;
}
}
if let Some(hint) = self.optimizer_hint.as_ref() {
f.write_str(" ")?;
hint.fmt(f)?;
}
if let Some(value_table_mode) = self.value_table_mode {
f.write_str(" ")?;
value_table_mode.fmt(f)?;
}
if let Some(ref top) = self.top {
if self.top_before_distinct {
f.write_str(" ")?;
top.fmt(f)?;
}
}
if let Some(ref distinct) = self.distinct {
f.write_str(" ")?;
distinct.fmt(f)?;
}
if let Some(ref top) = self.top {
if !self.top_before_distinct {
f.write_str(" ")?;
top.fmt(f)?;
}
}
if let Some(ref select_modifiers) = self.select_modifiers {
select_modifiers.fmt(f)?;
}
if !self.projection.is_empty() {
indented_list(f, &self.projection)?;
}
if let Some(exclude) = &self.exclude {
write!(f, " {exclude}")?;
}
if let Some(ref into) = self.into {
f.write_str(" ")?;
into.fmt(f)?;
}
if self.flavor == SelectFlavor::Standard && !self.from.is_empty() {
SpaceOrNewline.fmt(f)?;
f.write_str("FROM")?;
indented_list(f, &self.from)?;
}
if !self.lateral_views.is_empty() {
for lv in &self.lateral_views {
lv.fmt(f)?;
}
}
if let Some(ref prewhere) = self.prewhere {
f.write_str(" PREWHERE ")?;
prewhere.fmt(f)?;
}
if let Some(ref selection) = self.selection {
SpaceOrNewline.fmt(f)?;
f.write_str("WHERE")?;
SpaceOrNewline.fmt(f)?;
Indent(selection).fmt(f)?;
}
for clause in &self.connect_by {
SpaceOrNewline.fmt(f)?;
clause.fmt(f)?;
}
match &self.group_by {
GroupByExpr::All(_) => {
SpaceOrNewline.fmt(f)?;
self.group_by.fmt(f)?;
}
GroupByExpr::Expressions(exprs, _) => {
if !exprs.is_empty() {
SpaceOrNewline.fmt(f)?;
self.group_by.fmt(f)?;
}
}
}
if !self.cluster_by.is_empty() {
SpaceOrNewline.fmt(f)?;
f.write_str("CLUSTER BY")?;
SpaceOrNewline.fmt(f)?;
Indent(display_comma_separated(&self.cluster_by)).fmt(f)?;
}
if !self.distribute_by.is_empty() {
SpaceOrNewline.fmt(f)?;
f.write_str("DISTRIBUTE BY")?;
SpaceOrNewline.fmt(f)?;
display_comma_separated(&self.distribute_by).fmt(f)?;
}
if !self.sort_by.is_empty() {
SpaceOrNewline.fmt(f)?;
f.write_str("SORT BY")?;
SpaceOrNewline.fmt(f)?;
Indent(display_comma_separated(&self.sort_by)).fmt(f)?;
}
if let Some(ref having) = self.having {
SpaceOrNewline.fmt(f)?;
f.write_str("HAVING")?;
SpaceOrNewline.fmt(f)?;
Indent(having).fmt(f)?;
}
if self.window_before_qualify {
if !self.named_window.is_empty() {
SpaceOrNewline.fmt(f)?;
f.write_str("WINDOW")?;
SpaceOrNewline.fmt(f)?;
display_comma_separated(&self.named_window).fmt(f)?;
}
if let Some(ref qualify) = self.qualify {
SpaceOrNewline.fmt(f)?;
f.write_str("QUALIFY")?;
SpaceOrNewline.fmt(f)?;
qualify.fmt(f)?;
}
} else {
if let Some(ref qualify) = self.qualify {
SpaceOrNewline.fmt(f)?;
f.write_str("QUALIFY")?;
SpaceOrNewline.fmt(f)?;
qualify.fmt(f)?;
}
if !self.named_window.is_empty() {
SpaceOrNewline.fmt(f)?;
f.write_str("WINDOW")?;
SpaceOrNewline.fmt(f)?;
display_comma_separated(&self.named_window).fmt(f)?;
}
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct LateralView {
pub lateral_view: Expr,
pub lateral_view_name: ObjectName,
pub lateral_col_alias: Vec<Ident>,
pub outer: bool,
}
impl fmt::Display for LateralView {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
" LATERAL VIEW{outer} {} {}",
self.lateral_view,
self.lateral_view_name,
outer = if self.outer { " OUTER" } else { "" }
)?;
if !self.lateral_col_alias.is_empty() {
write!(
f,
" AS {}",
display_comma_separated(&self.lateral_col_alias)
)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum NamedWindowExpr {
NamedWindow(Ident),
WindowSpec(WindowSpec),
}
impl fmt::Display for NamedWindowExpr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
NamedWindowExpr::NamedWindow(named_window) => {
write!(f, "{named_window}")?;
}
NamedWindowExpr::WindowSpec(window_spec) => {
write!(f, "({window_spec})")?;
}
};
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct NamedWindowDefinition(pub Ident, pub NamedWindowExpr);
impl fmt::Display for NamedWindowDefinition {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} AS {}", self.0, self.1)
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct With {
pub with_token: AttachedToken,
pub recursive: bool,
pub cte_tables: Vec<Cte>,
}
impl fmt::Display for With {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("WITH ")?;
if self.recursive {
f.write_str("RECURSIVE ")?;
}
display_comma_separated(&self.cte_tables).fmt(f)?;
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum CteAsMaterialized {
Materialized,
NotMaterialized,
}
impl fmt::Display for CteAsMaterialized {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
CteAsMaterialized::Materialized => {
write!(f, "MATERIALIZED")?;
}
CteAsMaterialized::NotMaterialized => {
write!(f, "NOT MATERIALIZED")?;
}
};
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct Cte {
pub alias: TableAlias,
pub query: Box<Query>,
pub from: Option<Ident>,
pub materialized: Option<CteAsMaterialized>,
pub closing_paren_token: AttachedToken,
}
impl fmt::Display for Cte {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.materialized.as_ref() {
None => {
self.alias.fmt(f)?;
f.write_str(" AS (")?;
NewLine.fmt(f)?;
Indent(&self.query).fmt(f)?;
NewLine.fmt(f)?;
f.write_str(")")?;
}
Some(materialized) => {
self.alias.fmt(f)?;
f.write_str(" AS ")?;
materialized.fmt(f)?;
f.write_str(" (")?;
NewLine.fmt(f)?;
Indent(&self.query).fmt(f)?;
NewLine.fmt(f)?;
f.write_str(")")?;
}
};
if let Some(ref fr) = self.from {
write!(f, " FROM {fr}")?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum SelectItemQualifiedWildcardKind {
ObjectName(ObjectName),
Expr(Expr),
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum SelectItem {
UnnamedExpr(Expr),
ExprWithAlias {
expr: Expr,
alias: Ident,
},
QualifiedWildcard(SelectItemQualifiedWildcardKind, WildcardAdditionalOptions),
Wildcard(WildcardAdditionalOptions),
}
impl fmt::Display for SelectItemQualifiedWildcardKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self {
SelectItemQualifiedWildcardKind::ObjectName(object_name) => {
write!(f, "{object_name}.*")
}
SelectItemQualifiedWildcardKind::Expr(expr) => write!(f, "{expr}.*"),
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct IdentWithAlias {
pub ident: Ident,
pub alias: Ident,
}
impl fmt::Display for IdentWithAlias {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} AS {}", self.ident, self.alias)
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct WildcardAdditionalOptions {
pub wildcard_token: AttachedToken,
pub opt_ilike: Option<IlikeSelectItem>,
pub opt_exclude: Option<ExcludeSelectItem>,
pub opt_except: Option<ExceptSelectItem>,
pub opt_replace: Option<ReplaceSelectItem>,
pub opt_rename: Option<RenameSelectItem>,
}
impl Default for WildcardAdditionalOptions {
fn default() -> Self {
Self {
wildcard_token: TokenWithSpan::wrap(Token::Mul).into(),
opt_ilike: None,
opt_exclude: None,
opt_except: None,
opt_replace: None,
opt_rename: None,
}
}
}
impl fmt::Display for WildcardAdditionalOptions {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(ilike) = &self.opt_ilike {
write!(f, " {ilike}")?;
}
if let Some(exclude) = &self.opt_exclude {
write!(f, " {exclude}")?;
}
if let Some(except) = &self.opt_except {
write!(f, " {except}")?;
}
if let Some(replace) = &self.opt_replace {
write!(f, " {replace}")?;
}
if let Some(rename) = &self.opt_rename {
write!(f, " {rename}")?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct IlikeSelectItem {
pub pattern: String,
}
impl fmt::Display for IlikeSelectItem {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"ILIKE '{}'",
value::escape_single_quote_string(&self.pattern)
)?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum ExcludeSelectItem {
Single(Ident),
Multiple(Vec<Ident>),
}
impl fmt::Display for ExcludeSelectItem {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "EXCLUDE")?;
match self {
Self::Single(column) => {
write!(f, " {column}")?;
}
Self::Multiple(columns) => {
write!(f, " ({})", display_comma_separated(columns))?;
}
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum RenameSelectItem {
Single(IdentWithAlias),
Multiple(Vec<IdentWithAlias>),
}
impl fmt::Display for RenameSelectItem {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "RENAME")?;
match self {
Self::Single(column) => {
write!(f, " {column}")?;
}
Self::Multiple(columns) => {
write!(f, " ({})", display_comma_separated(columns))?;
}
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct ExceptSelectItem {
pub first_element: Ident,
pub additional_elements: Vec<Ident>,
}
impl fmt::Display for ExceptSelectItem {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "EXCEPT ")?;
if self.additional_elements.is_empty() {
write!(f, "({})", self.first_element)?;
} else {
write!(
f,
"({}, {})",
self.first_element,
display_comma_separated(&self.additional_elements)
)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct ReplaceSelectItem {
pub items: Vec<Box<ReplaceSelectElement>>,
}
impl fmt::Display for ReplaceSelectItem {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "REPLACE")?;
write!(f, " ({})", display_comma_separated(&self.items))?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct ReplaceSelectElement {
pub expr: Expr,
pub column_name: Ident,
pub as_keyword: bool,
}
impl fmt::Display for ReplaceSelectElement {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.as_keyword {
write!(f, "{} AS {}", self.expr, self.column_name)
} else {
write!(f, "{} {}", self.expr, self.column_name)
}
}
}
impl fmt::Display for SelectItem {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use core::fmt::Write;
match &self {
SelectItem::UnnamedExpr(expr) => expr.fmt(f),
SelectItem::ExprWithAlias { expr, alias } => {
expr.fmt(f)?;
f.write_str(" AS ")?;
alias.fmt(f)
}
SelectItem::QualifiedWildcard(kind, additional_options) => {
kind.fmt(f)?;
additional_options.fmt(f)
}
SelectItem::Wildcard(additional_options) => {
f.write_char('*')?;
additional_options.fmt(f)
}
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct TableWithJoins {
pub relation: TableFactor,
pub joins: Vec<Join>,
}
impl fmt::Display for TableWithJoins {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.relation.fmt(f)?;
for join in &self.joins {
SpaceOrNewline.fmt(f)?;
join.fmt(f)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum ConnectByKind {
ConnectBy {
connect_token: AttachedToken,
nocycle: bool,
relationships: Vec<Expr>,
},
StartWith {
start_token: AttachedToken,
condition: Box<Expr>,
},
}
impl fmt::Display for ConnectByKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ConnectByKind::ConnectBy {
connect_token: _,
nocycle,
relationships,
} => {
write!(
f,
"CONNECT BY {nocycle}{relationships}",
nocycle = if *nocycle { "NOCYCLE " } else { "" },
relationships = display_comma_separated(relationships)
)
}
ConnectByKind::StartWith {
start_token: _,
condition,
} => {
write!(f, "START WITH {condition}")
}
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct Setting {
pub key: Ident,
pub value: Expr,
}
impl fmt::Display for Setting {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = {}", self.key, self.value)
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct ExprWithAlias {
pub expr: Expr,
pub alias: Option<Ident>,
}
impl fmt::Display for ExprWithAlias {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let ExprWithAlias { expr, alias } = self;
write!(f, "{expr}")?;
if let Some(alias) = alias {
write!(f, " AS {alias}")?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct ExprWithAliasAndOrderBy {
pub expr: ExprWithAlias,
pub order_by: OrderByOptions,
}
impl fmt::Display for ExprWithAliasAndOrderBy {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{}", self.expr, self.order_by)
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct TableFunctionArgs {
pub args: Vec<FunctionArg>,
pub settings: Option<Vec<Setting>>,
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum TableIndexHintType {
Use,
Ignore,
Force,
}
impl fmt::Display for TableIndexHintType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match self {
TableIndexHintType::Use => "USE",
TableIndexHintType::Ignore => "IGNORE",
TableIndexHintType::Force => "FORCE",
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum TableIndexType {
Index,
Key,
}
impl fmt::Display for TableIndexType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match self {
TableIndexType::Index => "INDEX",
TableIndexType::Key => "KEY",
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum TableIndexHintForClause {
Join,
OrderBy,
GroupBy,
}
impl fmt::Display for TableIndexHintForClause {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match self {
TableIndexHintForClause::Join => "JOIN",
TableIndexHintForClause::OrderBy => "ORDER BY",
TableIndexHintForClause::GroupBy => "GROUP BY",
})
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct TableIndexHints {
pub hint_type: TableIndexHintType,
pub index_type: TableIndexType,
pub for_clause: Option<TableIndexHintForClause>,
pub index_names: Vec<Ident>,
}
impl fmt::Display for TableIndexHints {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {} ", self.hint_type, self.index_type)?;
if let Some(for_clause) = &self.for_clause {
write!(f, "FOR {for_clause} ")?;
}
write!(f, "({})", display_comma_separated(&self.index_names))
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
#[cfg_attr(feature = "visitor", visit(with = "visit_table_factor"))]
pub enum TableFactor {
Table {
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
name: ObjectName,
alias: Option<TableAlias>,
args: Option<TableFunctionArgs>,
with_hints: Vec<Expr>,
version: Option<TableVersion>,
with_ordinality: bool,
partitions: Vec<Ident>,
json_path: Option<JsonPath>,
sample: Option<TableSampleKind>,
index_hints: Vec<TableIndexHints>,
},
Derived {
lateral: bool,
subquery: Box<Query>,
alias: Option<TableAlias>,
sample: Option<TableSampleKind>,
},
TableFunction {
expr: Expr,
alias: Option<TableAlias>,
},
Function {
lateral: bool,
name: ObjectName,
args: Vec<FunctionArg>,
alias: Option<TableAlias>,
},
UNNEST {
alias: Option<TableAlias>,
array_exprs: Vec<Expr>,
with_offset: bool,
with_offset_alias: Option<Ident>,
with_ordinality: bool,
},
JsonTable {
json_expr: Expr,
json_path: Value,
columns: Vec<JsonTableColumn>,
alias: Option<TableAlias>,
},
OpenJsonTable {
json_expr: Expr,
json_path: Option<Value>,
columns: Vec<OpenJsonTableColumn>,
alias: Option<TableAlias>,
},
NestedJoin {
table_with_joins: Box<TableWithJoins>,
alias: Option<TableAlias>,
},
Pivot {
table: Box<TableFactor>,
aggregate_functions: Vec<ExprWithAlias>, value_column: Vec<Expr>,
value_source: PivotValueSource,
default_on_null: Option<Expr>,
alias: Option<TableAlias>,
},
Unpivot {
table: Box<TableFactor>,
value: Expr,
name: Ident,
columns: Vec<ExprWithAlias>,
null_inclusion: Option<NullInclusion>,
alias: Option<TableAlias>,
},
MatchRecognize {
table: Box<TableFactor>,
partition_by: Vec<Expr>,
order_by: Vec<OrderByExpr>,
measures: Vec<Measure>,
rows_per_match: Option<RowsPerMatch>,
after_match_skip: Option<AfterMatchSkip>,
pattern: MatchRecognizePattern,
symbols: Vec<SymbolDefinition>,
alias: Option<TableAlias>,
},
XmlTable {
namespaces: Vec<XmlNamespaceDefinition>,
row_expression: Expr,
passing: XmlPassingClause,
columns: Vec<XmlTableColumn>,
alias: Option<TableAlias>,
},
SemanticView {
name: ObjectName,
dimensions: Vec<Expr>,
metrics: Vec<Expr>,
facts: Vec<Expr>,
where_clause: Option<Expr>,
alias: Option<TableAlias>,
},
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum TableSampleKind {
BeforeTableAlias(Box<TableSample>),
AfterTableAlias(Box<TableSample>),
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct TableSample {
pub modifier: TableSampleModifier,
pub name: Option<TableSampleMethod>,
pub quantity: Option<TableSampleQuantity>,
pub seed: Option<TableSampleSeed>,
pub bucket: Option<TableSampleBucket>,
pub offset: Option<Expr>,
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum TableSampleModifier {
Sample,
TableSample,
}
impl fmt::Display for TableSampleModifier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TableSampleModifier::Sample => write!(f, "SAMPLE")?,
TableSampleModifier::TableSample => write!(f, "TABLESAMPLE")?,
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct TableSampleQuantity {
pub parenthesized: bool,
pub value: Expr,
pub unit: Option<TableSampleUnit>,
}
impl fmt::Display for TableSampleQuantity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.parenthesized {
write!(f, "(")?;
}
write!(f, "{}", self.value)?;
if let Some(unit) = &self.unit {
write!(f, " {unit}")?;
}
if self.parenthesized {
write!(f, ")")?;
}
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum TableSampleMethod {
Row,
Bernoulli,
System,
Block,
}
impl fmt::Display for TableSampleMethod {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TableSampleMethod::Bernoulli => write!(f, "BERNOULLI"),
TableSampleMethod::Row => write!(f, "ROW"),
TableSampleMethod::System => write!(f, "SYSTEM"),
TableSampleMethod::Block => write!(f, "BLOCK"),
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct TableSampleSeed {
pub modifier: TableSampleSeedModifier,
pub value: Value,
}
impl fmt::Display for TableSampleSeed {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} ({})", self.modifier, self.value)?;
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum TableSampleSeedModifier {
Repeatable,
Seed,
}
impl fmt::Display for TableSampleSeedModifier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TableSampleSeedModifier::Repeatable => write!(f, "REPEATABLE"),
TableSampleSeedModifier::Seed => write!(f, "SEED"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum TableSampleUnit {
Rows,
Percent,
}
impl fmt::Display for TableSampleUnit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TableSampleUnit::Percent => write!(f, "PERCENT"),
TableSampleUnit::Rows => write!(f, "ROWS"),
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct TableSampleBucket {
pub bucket: Value,
pub total: Value,
pub on: Option<Expr>,
}
impl fmt::Display for TableSampleBucket {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "BUCKET {} OUT OF {}", self.bucket, self.total)?;
if let Some(on) = &self.on {
write!(f, " ON {on}")?;
}
Ok(())
}
}
impl fmt::Display for TableSample {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.modifier)?;
if let Some(name) = &self.name {
write!(f, " {name}")?;
}
if let Some(quantity) = &self.quantity {
write!(f, " {quantity}")?;
}
if let Some(seed) = &self.seed {
write!(f, " {seed}")?;
}
if let Some(bucket) = &self.bucket {
write!(f, " ({bucket})")?;
}
if let Some(offset) = &self.offset {
write!(f, " OFFSET {offset}")?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum PivotValueSource {
List(Vec<ExprWithAlias>),
Any(Vec<OrderByExpr>),
Subquery(Box<Query>),
}
impl fmt::Display for PivotValueSource {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
PivotValueSource::List(values) => write!(f, "{}", display_comma_separated(values)),
PivotValueSource::Any(order_by) => {
write!(f, "ANY")?;
if !order_by.is_empty() {
write!(f, " ORDER BY {}", display_comma_separated(order_by))?;
}
Ok(())
}
PivotValueSource::Subquery(query) => write!(f, "{query}"),
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct Measure {
pub expr: Expr,
pub alias: Ident,
}
impl fmt::Display for Measure {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} AS {}", self.expr, self.alias)
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum RowsPerMatch {
OneRow,
AllRows(Option<EmptyMatchesMode>),
}
impl fmt::Display for RowsPerMatch {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
RowsPerMatch::OneRow => write!(f, "ONE ROW PER MATCH"),
RowsPerMatch::AllRows(mode) => {
write!(f, "ALL ROWS PER MATCH")?;
if let Some(mode) = mode {
write!(f, " {mode}")?;
}
Ok(())
}
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum AfterMatchSkip {
PastLastRow,
ToNextRow,
ToFirst(Ident),
ToLast(Ident),
}
impl fmt::Display for AfterMatchSkip {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "AFTER MATCH SKIP ")?;
match self {
AfterMatchSkip::PastLastRow => write!(f, "PAST LAST ROW"),
AfterMatchSkip::ToNextRow => write!(f, " TO NEXT ROW"),
AfterMatchSkip::ToFirst(symbol) => write!(f, "TO FIRST {symbol}"),
AfterMatchSkip::ToLast(symbol) => write!(f, "TO LAST {symbol}"),
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum EmptyMatchesMode {
Show,
Omit,
WithUnmatched,
}
impl fmt::Display for EmptyMatchesMode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
EmptyMatchesMode::Show => write!(f, "SHOW EMPTY MATCHES"),
EmptyMatchesMode::Omit => write!(f, "OMIT EMPTY MATCHES"),
EmptyMatchesMode::WithUnmatched => write!(f, "WITH UNMATCHED ROWS"),
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct SymbolDefinition {
pub symbol: Ident,
pub definition: Expr,
}
impl fmt::Display for SymbolDefinition {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} AS {}", self.symbol, self.definition)
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum MatchRecognizeSymbol {
Named(Ident),
Start,
End,
}
impl fmt::Display for MatchRecognizeSymbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MatchRecognizeSymbol::Named(symbol) => write!(f, "{symbol}"),
MatchRecognizeSymbol::Start => write!(f, "^"),
MatchRecognizeSymbol::End => write!(f, "$"),
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum MatchRecognizePattern {
Symbol(MatchRecognizeSymbol),
Exclude(MatchRecognizeSymbol),
Permute(Vec<MatchRecognizeSymbol>),
Concat(Vec<MatchRecognizePattern>),
Group(Box<MatchRecognizePattern>),
Alternation(Vec<MatchRecognizePattern>),
Repetition(Box<MatchRecognizePattern>, RepetitionQuantifier),
}
impl fmt::Display for MatchRecognizePattern {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use MatchRecognizePattern::*;
match self {
Symbol(symbol) => write!(f, "{symbol}"),
Exclude(symbol) => write!(f, "{{- {symbol} -}}"),
Permute(symbols) => write!(f, "PERMUTE({})", display_comma_separated(symbols)),
Concat(patterns) => write!(f, "{}", display_separated(patterns, " ")),
Group(pattern) => write!(f, "( {pattern} )"),
Alternation(patterns) => write!(f, "{}", display_separated(patterns, " | ")),
Repetition(pattern, op) => write!(f, "{pattern}{op}"),
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum RepetitionQuantifier {
ZeroOrMore,
OneOrMore,
AtMostOne,
Exactly(u32),
AtLeast(u32),
AtMost(u32),
Range(u32, u32),
}
impl fmt::Display for RepetitionQuantifier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use RepetitionQuantifier::*;
match self {
ZeroOrMore => write!(f, "*"),
OneOrMore => write!(f, "+"),
AtMostOne => write!(f, "?"),
Exactly(n) => write!(f, "{{{n}}}"),
AtLeast(n) => write!(f, "{{{n},}}"),
AtMost(n) => write!(f, "{{,{n}}}"),
Range(n, m) => write!(f, "{{{n},{m}}}"),
}
}
}
impl fmt::Display for TableFactor {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
TableFactor::Table {
name,
alias,
args,
with_hints,
version,
partitions,
with_ordinality,
json_path,
sample,
index_hints,
} => {
name.fmt(f)?;
if let Some(json_path) = json_path {
json_path.fmt(f)?;
}
if !partitions.is_empty() {
write!(f, "PARTITION ({})", display_comma_separated(partitions))?;
}
if let Some(args) = args {
write!(f, "(")?;
write!(f, "{}", display_comma_separated(&args.args))?;
if let Some(ref settings) = args.settings {
if !args.args.is_empty() {
write!(f, ", ")?;
}
write!(f, "SETTINGS {}", display_comma_separated(settings))?;
}
write!(f, ")")?;
}
if *with_ordinality {
write!(f, " WITH ORDINALITY")?;
}
if let Some(TableSampleKind::BeforeTableAlias(sample)) = sample {
write!(f, " {sample}")?;
}
if let Some(alias) = alias {
write!(f, " {alias}")?;
}
if !index_hints.is_empty() {
write!(f, " {}", display_separated(index_hints, " "))?;
}
if !with_hints.is_empty() {
write!(f, " WITH ({})", display_comma_separated(with_hints))?;
}
if let Some(version) = version {
write!(f, " {version}")?;
}
if let Some(TableSampleKind::AfterTableAlias(sample)) = sample {
write!(f, " {sample}")?;
}
Ok(())
}
TableFactor::Derived {
lateral,
subquery,
alias,
sample,
} => {
if *lateral {
write!(f, "LATERAL ")?;
}
f.write_str("(")?;
NewLine.fmt(f)?;
Indent(subquery).fmt(f)?;
NewLine.fmt(f)?;
f.write_str(")")?;
if let Some(alias) = alias {
write!(f, " {alias}")?;
}
if let Some(TableSampleKind::AfterTableAlias(sample)) = sample {
write!(f, " {sample}")?;
}
Ok(())
}
TableFactor::Function {
lateral,
name,
args,
alias,
} => {
if *lateral {
write!(f, "LATERAL ")?;
}
write!(f, "{name}")?;
write!(f, "({})", display_comma_separated(args))?;
if let Some(alias) = alias {
write!(f, " {alias}")?;
}
Ok(())
}
TableFactor::TableFunction { expr, alias } => {
write!(f, "TABLE({expr})")?;
if let Some(alias) = alias {
write!(f, " {alias}")?;
}
Ok(())
}
TableFactor::UNNEST {
alias,
array_exprs,
with_offset,
with_offset_alias,
with_ordinality,
} => {
write!(f, "UNNEST({})", display_comma_separated(array_exprs))?;
if *with_ordinality {
write!(f, " WITH ORDINALITY")?;
}
if let Some(alias) = alias {
write!(f, " {alias}")?;
}
if *with_offset {
write!(f, " WITH OFFSET")?;
}
if let Some(alias) = with_offset_alias {
write!(f, " {alias}")?;
}
Ok(())
}
TableFactor::JsonTable {
json_expr,
json_path,
columns,
alias,
} => {
write!(
f,
"JSON_TABLE({json_expr}, {json_path} COLUMNS({columns}))",
columns = display_comma_separated(columns)
)?;
if let Some(alias) = alias {
write!(f, " {alias}")?;
}
Ok(())
}
TableFactor::OpenJsonTable {
json_expr,
json_path,
columns,
alias,
} => {
write!(f, "OPENJSON({json_expr}")?;
if let Some(json_path) = json_path {
write!(f, ", {json_path}")?;
}
write!(f, ")")?;
if !columns.is_empty() {
write!(f, " WITH ({})", display_comma_separated(columns))?;
}
if let Some(alias) = alias {
write!(f, " {alias}")?;
}
Ok(())
}
TableFactor::NestedJoin {
table_with_joins,
alias,
} => {
write!(f, "({table_with_joins})")?;
if let Some(alias) = alias {
write!(f, " {alias}")?;
}
Ok(())
}
TableFactor::Pivot {
table,
aggregate_functions,
value_column,
value_source,
default_on_null,
alias,
} => {
write!(
f,
"{table} PIVOT({} FOR ",
display_comma_separated(aggregate_functions),
)?;
if value_column.len() == 1 {
write!(f, "{}", value_column[0])?;
} else {
write!(f, "({})", display_comma_separated(value_column))?;
}
write!(f, " IN ({value_source})")?;
if let Some(expr) = default_on_null {
write!(f, " DEFAULT ON NULL ({expr})")?;
}
write!(f, ")")?;
if let Some(alias) = alias {
write!(f, " {alias}")?;
}
Ok(())
}
TableFactor::Unpivot {
table,
null_inclusion,
value,
name,
columns,
alias,
} => {
write!(f, "{table} UNPIVOT")?;
if let Some(null_inclusion) = null_inclusion {
write!(f, " {null_inclusion} ")?;
}
write!(
f,
"({} FOR {} IN ({}))",
value,
name,
display_comma_separated(columns)
)?;
if let Some(alias) = alias {
write!(f, " {alias}")?;
}
Ok(())
}
TableFactor::MatchRecognize {
table,
partition_by,
order_by,
measures,
rows_per_match,
after_match_skip,
pattern,
symbols,
alias,
} => {
write!(f, "{table} MATCH_RECOGNIZE(")?;
if !partition_by.is_empty() {
write!(f, "PARTITION BY {} ", display_comma_separated(partition_by))?;
}
if !order_by.is_empty() {
write!(f, "ORDER BY {} ", display_comma_separated(order_by))?;
}
if !measures.is_empty() {
write!(f, "MEASURES {} ", display_comma_separated(measures))?;
}
if let Some(rows_per_match) = rows_per_match {
write!(f, "{rows_per_match} ")?;
}
if let Some(after_match_skip) = after_match_skip {
write!(f, "{after_match_skip} ")?;
}
write!(f, "PATTERN ({pattern}) ")?;
write!(f, "DEFINE {})", display_comma_separated(symbols))?;
if let Some(alias) = alias {
write!(f, " {alias}")?;
}
Ok(())
}
TableFactor::XmlTable {
row_expression,
passing,
columns,
alias,
namespaces,
} => {
write!(f, "XMLTABLE(")?;
if !namespaces.is_empty() {
write!(
f,
"XMLNAMESPACES({}), ",
display_comma_separated(namespaces)
)?;
}
write!(
f,
"{row_expression}{passing} COLUMNS {columns})",
columns = display_comma_separated(columns)
)?;
if let Some(alias) = alias {
write!(f, " {alias}")?;
}
Ok(())
}
TableFactor::SemanticView {
name,
dimensions,
metrics,
facts,
where_clause,
alias,
} => {
write!(f, "SEMANTIC_VIEW({name}")?;
if !dimensions.is_empty() {
write!(f, " DIMENSIONS {}", display_comma_separated(dimensions))?;
}
if !metrics.is_empty() {
write!(f, " METRICS {}", display_comma_separated(metrics))?;
}
if !facts.is_empty() {
write!(f, " FACTS {}", display_comma_separated(facts))?;
}
if let Some(where_clause) = where_clause {
write!(f, " WHERE {where_clause}")?;
}
write!(f, ")")?;
if let Some(alias) = alias {
write!(f, " {alias}")?;
}
Ok(())
}
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct TableAlias {
pub explicit: bool,
pub name: Ident,
pub columns: Vec<TableAliasColumnDef>,
}
impl fmt::Display for TableAlias {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{}", if self.explicit { "AS " } else { "" }, self.name)?;
if !self.columns.is_empty() {
write!(f, " ({})", display_comma_separated(&self.columns))?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct TableAliasColumnDef {
pub name: Ident,
pub data_type: Option<DataType>,
}
impl TableAliasColumnDef {
pub fn from_name<S: Into<String>>(name: S) -> Self {
TableAliasColumnDef {
name: Ident::new(name),
data_type: None,
}
}
}
impl fmt::Display for TableAliasColumnDef {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name)?;
if let Some(ref data_type) = self.data_type {
write!(f, " {data_type}")?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum TableVersion {
ForSystemTimeAsOf(Expr),
TimestampAsOf(Expr),
VersionAsOf(Expr),
Function(Expr),
}
impl Display for TableVersion {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
TableVersion::ForSystemTimeAsOf(e) => write!(f, "FOR SYSTEM_TIME AS OF {e}")?,
TableVersion::TimestampAsOf(e) => write!(f, "TIMESTAMP AS OF {e}")?,
TableVersion::VersionAsOf(e) => write!(f, "VERSION AS OF {e}")?,
TableVersion::Function(func) => write!(f, "{func}")?,
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct Join {
pub relation: TableFactor,
pub global: bool,
pub join_operator: JoinOperator,
}
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 ",
_ => "",
}
}
fn suffix(constraint: &'_ JoinConstraint) -> impl fmt::Display + '_ {
struct Suffix<'a>(&'a JoinConstraint);
impl fmt::Display for Suffix<'_> {
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)
}
if self.global {
write!(f, "GLOBAL ")?;
}
match &self.join_operator {
JoinOperator::Join(constraint) => f.write_fmt(format_args!(
"{}JOIN {}{}",
prefix(constraint),
self.relation,
suffix(constraint)
)),
JoinOperator::Inner(constraint) => f.write_fmt(format_args!(
"{}INNER JOIN {}{}",
prefix(constraint),
self.relation,
suffix(constraint)
)),
JoinOperator::Left(constraint) => f.write_fmt(format_args!(
"{}LEFT JOIN {}{}",
prefix(constraint),
self.relation,
suffix(constraint)
)),
JoinOperator::LeftOuter(constraint) => f.write_fmt(format_args!(
"{}LEFT OUTER JOIN {}{}",
prefix(constraint),
self.relation,
suffix(constraint)
)),
JoinOperator::Right(constraint) => f.write_fmt(format_args!(
"{}RIGHT JOIN {}{}",
prefix(constraint),
self.relation,
suffix(constraint)
)),
JoinOperator::RightOuter(constraint) => f.write_fmt(format_args!(
"{}RIGHT OUTER JOIN {}{}",
prefix(constraint),
self.relation,
suffix(constraint)
)),
JoinOperator::FullOuter(constraint) => f.write_fmt(format_args!(
"{}FULL JOIN {}{}",
prefix(constraint),
self.relation,
suffix(constraint)
)),
JoinOperator::CrossJoin(constraint) => f.write_fmt(format_args!(
"CROSS JOIN {}{}",
self.relation,
suffix(constraint)
)),
JoinOperator::Semi(constraint) => f.write_fmt(format_args!(
"{}SEMI JOIN {}{}",
prefix(constraint),
self.relation,
suffix(constraint)
)),
JoinOperator::LeftSemi(constraint) => f.write_fmt(format_args!(
"{}LEFT SEMI JOIN {}{}",
prefix(constraint),
self.relation,
suffix(constraint)
)),
JoinOperator::RightSemi(constraint) => f.write_fmt(format_args!(
"{}RIGHT SEMI JOIN {}{}",
prefix(constraint),
self.relation,
suffix(constraint)
)),
JoinOperator::Anti(constraint) => f.write_fmt(format_args!(
"{}ANTI JOIN {}{}",
prefix(constraint),
self.relation,
suffix(constraint)
)),
JoinOperator::LeftAnti(constraint) => f.write_fmt(format_args!(
"{}LEFT ANTI JOIN {}{}",
prefix(constraint),
self.relation,
suffix(constraint)
)),
JoinOperator::RightAnti(constraint) => f.write_fmt(format_args!(
"{}RIGHT ANTI JOIN {}{}",
prefix(constraint),
self.relation,
suffix(constraint)
)),
JoinOperator::CrossApply => f.write_fmt(format_args!("CROSS APPLY {}", self.relation)),
JoinOperator::OuterApply => f.write_fmt(format_args!("OUTER APPLY {}", self.relation)),
JoinOperator::AsOf {
match_condition,
constraint,
} => f.write_fmt(format_args!(
"ASOF JOIN {} MATCH_CONDITION ({match_condition}){}",
self.relation,
suffix(constraint)
)),
JoinOperator::StraightJoin(constraint) => f.write_fmt(format_args!(
"STRAIGHT_JOIN {}{}",
self.relation,
suffix(constraint)
)),
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum JoinOperator {
Join(JoinConstraint),
Inner(JoinConstraint),
Left(JoinConstraint),
LeftOuter(JoinConstraint),
Right(JoinConstraint),
RightOuter(JoinConstraint),
FullOuter(JoinConstraint),
CrossJoin(JoinConstraint),
Semi(JoinConstraint),
LeftSemi(JoinConstraint),
RightSemi(JoinConstraint),
Anti(JoinConstraint),
LeftAnti(JoinConstraint),
RightAnti(JoinConstraint),
CrossApply,
OuterApply,
AsOf {
match_condition: Expr,
constraint: JoinConstraint,
},
StraightJoin(JoinConstraint),
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum JoinConstraint {
On(Expr),
Using(Vec<ObjectName>),
Natural,
None,
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum OrderByKind {
All(OrderByOptions),
Expressions(Vec<OrderByExpr>),
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct OrderBy {
pub kind: OrderByKind,
pub interpolate: Option<Interpolate>,
}
impl fmt::Display for OrderBy {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ORDER BY")?;
match &self.kind {
OrderByKind::Expressions(exprs) => {
write!(f, " {}", display_comma_separated(exprs))?;
}
OrderByKind::All(all) => {
write!(f, " ALL{all}")?;
}
}
if let Some(ref interpolate) = self.interpolate {
match &interpolate.exprs {
Some(exprs) => write!(f, " INTERPOLATE ({})", display_comma_separated(exprs))?,
None => write!(f, " INTERPOLATE")?,
}
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct OrderByExpr {
pub expr: Expr,
pub options: OrderByOptions,
pub with_fill: Option<WithFill>,
}
impl From<Ident> for OrderByExpr {
fn from(ident: Ident) -> Self {
OrderByExpr {
expr: Expr::Identifier(ident),
options: OrderByOptions::default(),
with_fill: None,
}
}
}
impl fmt::Display for OrderByExpr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{}", self.expr, self.options)?;
if let Some(ref with_fill) = self.with_fill {
write!(f, " {with_fill}")?
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct WithFill {
pub from: Option<Expr>,
pub to: Option<Expr>,
pub step: Option<Expr>,
}
impl fmt::Display for WithFill {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "WITH FILL")?;
if let Some(ref from) = self.from {
write!(f, " FROM {from}")?;
}
if let Some(ref to) = self.to {
write!(f, " TO {to}")?;
}
if let Some(ref step) = self.step {
write!(f, " STEP {step}")?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct InterpolateExpr {
pub column: Ident,
pub expr: Option<Expr>,
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct Interpolate {
pub exprs: Option<Vec<InterpolateExpr>>,
}
impl fmt::Display for InterpolateExpr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.column)?;
if let Some(ref expr) = self.expr {
write!(f, " AS {expr}")?;
}
Ok(())
}
}
#[derive(Default, Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct OrderByOptions {
pub asc: Option<bool>,
pub nulls_first: Option<bool>,
}
impl fmt::Display for OrderByOptions {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.asc {
Some(true) => write!(f, " ASC")?,
Some(false) => write!(f, " DESC")?,
None => (),
}
match self.nulls_first {
Some(true) => write!(f, " NULLS FIRST")?,
Some(false) => write!(f, " NULLS LAST")?,
None => (),
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum LimitClause {
LimitOffset {
limit: Option<Expr>,
offset: Option<Offset>,
limit_by: Vec<Expr>,
},
OffsetCommaLimit {
offset: Expr,
limit: Expr,
},
}
impl fmt::Display for LimitClause {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
LimitClause::LimitOffset {
limit,
limit_by,
offset,
} => {
if let Some(ref limit) = limit {
write!(f, " LIMIT {limit}")?;
}
if let Some(ref offset) = offset {
write!(f, " {offset}")?;
}
if !limit_by.is_empty() {
debug_assert!(limit.is_some());
write!(f, " BY {}", display_separated(limit_by, ", "))?;
}
Ok(())
}
LimitClause::OffsetCommaLimit { offset, limit } => {
write!(f, " LIMIT {offset}, {limit}")
}
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct Offset {
pub value: Expr,
pub rows: OffsetRows,
}
impl fmt::Display for Offset {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "OFFSET {}{}", self.value, self.rows)
}
}
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum OffsetRows {
None,
Row,
Rows,
}
impl fmt::Display for OffsetRows {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
OffsetRows::None => Ok(()),
OffsetRows::Row => write!(f, " ROW"),
OffsetRows::Rows => write!(f, " ROWS"),
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum PipeOperator {
Limit {
expr: Expr,
offset: Option<Expr>,
},
Where {
expr: Expr,
},
OrderBy {
exprs: Vec<OrderByExpr>,
},
Select {
exprs: Vec<SelectItem>,
},
Extend {
exprs: Vec<SelectItem>,
},
Set {
assignments: Vec<Assignment>,
},
Drop {
columns: Vec<Ident>,
},
As {
alias: Ident,
},
Aggregate {
full_table_exprs: Vec<ExprWithAliasAndOrderBy>,
group_by_expr: Vec<ExprWithAliasAndOrderBy>,
},
TableSample {
sample: Box<TableSample>,
},
Rename {
mappings: Vec<IdentWithAlias>,
},
Union {
set_quantifier: SetQuantifier,
queries: Vec<Query>,
},
Intersect {
set_quantifier: SetQuantifier,
queries: Vec<Query>,
},
Except {
set_quantifier: SetQuantifier,
queries: Vec<Query>,
},
Call {
function: Function,
alias: Option<Ident>,
},
Pivot {
aggregate_functions: Vec<ExprWithAlias>,
value_column: Vec<Ident>,
value_source: PivotValueSource,
alias: Option<Ident>,
},
Unpivot {
value_column: Ident,
name_column: Ident,
unpivot_columns: Vec<Ident>,
alias: Option<Ident>,
},
Join(Join),
}
impl fmt::Display for PipeOperator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
PipeOperator::Select { exprs } => {
write!(f, "SELECT {}", display_comma_separated(exprs.as_slice()))
}
PipeOperator::Extend { exprs } => {
write!(f, "EXTEND {}", display_comma_separated(exprs.as_slice()))
}
PipeOperator::Set { assignments } => {
write!(f, "SET {}", display_comma_separated(assignments.as_slice()))
}
PipeOperator::Drop { columns } => {
write!(f, "DROP {}", display_comma_separated(columns.as_slice()))
}
PipeOperator::As { alias } => {
write!(f, "AS {alias}")
}
PipeOperator::Limit { expr, offset } => {
write!(f, "LIMIT {expr}")?;
if let Some(offset) = offset {
write!(f, " OFFSET {offset}")?;
}
Ok(())
}
PipeOperator::Aggregate {
full_table_exprs,
group_by_expr,
} => {
write!(f, "AGGREGATE")?;
if !full_table_exprs.is_empty() {
write!(
f,
" {}",
display_comma_separated(full_table_exprs.as_slice())
)?;
}
if !group_by_expr.is_empty() {
write!(f, " GROUP BY {}", display_comma_separated(group_by_expr))?;
}
Ok(())
}
PipeOperator::Where { expr } => {
write!(f, "WHERE {expr}")
}
PipeOperator::OrderBy { exprs } => {
write!(f, "ORDER BY {}", display_comma_separated(exprs.as_slice()))
}
PipeOperator::TableSample { sample } => {
write!(f, "{sample}")
}
PipeOperator::Rename { mappings } => {
write!(f, "RENAME {}", display_comma_separated(mappings))
}
PipeOperator::Union {
set_quantifier,
queries,
} => Self::fmt_set_operation(f, "UNION", set_quantifier, queries),
PipeOperator::Intersect {
set_quantifier,
queries,
} => Self::fmt_set_operation(f, "INTERSECT", set_quantifier, queries),
PipeOperator::Except {
set_quantifier,
queries,
} => Self::fmt_set_operation(f, "EXCEPT", set_quantifier, queries),
PipeOperator::Call { function, alias } => {
write!(f, "CALL {function}")?;
Self::fmt_optional_alias(f, alias)
}
PipeOperator::Pivot {
aggregate_functions,
value_column,
value_source,
alias,
} => {
write!(
f,
"PIVOT({} FOR {} IN ({}))",
display_comma_separated(aggregate_functions),
Expr::CompoundIdentifier(value_column.to_vec()),
value_source
)?;
Self::fmt_optional_alias(f, alias)
}
PipeOperator::Unpivot {
value_column,
name_column,
unpivot_columns,
alias,
} => {
write!(
f,
"UNPIVOT({} FOR {} IN ({}))",
value_column,
name_column,
display_comma_separated(unpivot_columns)
)?;
Self::fmt_optional_alias(f, alias)
}
PipeOperator::Join(join) => write!(f, "{join}"),
}
}
}
impl PipeOperator {
fn fmt_optional_alias(f: &mut fmt::Formatter<'_>, alias: &Option<Ident>) -> fmt::Result {
if let Some(alias) = alias {
write!(f, " AS {alias}")?;
}
Ok(())
}
fn fmt_set_operation(
f: &mut fmt::Formatter<'_>,
operation: &str,
set_quantifier: &SetQuantifier,
queries: &[Query],
) -> fmt::Result {
write!(f, "{operation}")?;
match set_quantifier {
SetQuantifier::None => {}
_ => {
write!(f, " {set_quantifier}")?;
}
}
write!(f, " ")?;
let parenthesized_queries: Vec<String> =
queries.iter().map(|query| format!("({query})")).collect();
write!(f, "{}", display_comma_separated(&parenthesized_queries))
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct Fetch {
pub with_ties: bool,
pub percent: bool,
pub quantity: Option<Expr>,
}
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 { "" };
write!(f, "FETCH FIRST {quantity}{percent} ROWS {extension}")
} else {
write!(f, "FETCH FIRST ROWS {extension}")
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct LockClause {
pub lock_type: LockType,
pub of: Option<ObjectName>,
pub nonblock: Option<NonBlock>,
}
impl fmt::Display for LockClause {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "FOR {}", &self.lock_type)?;
if let Some(ref of) = self.of {
write!(f, " OF {of}")?;
}
if let Some(ref nb) = self.nonblock {
write!(f, " {nb}")?;
}
Ok(())
}
}
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum LockType {
Share,
Update,
}
impl fmt::Display for LockType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let select_lock = match self {
LockType::Share => "SHARE",
LockType::Update => "UPDATE",
};
write!(f, "{select_lock}")
}
}
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum NonBlock {
Nowait,
SkipLocked,
}
impl fmt::Display for NonBlock {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let nonblock = match self {
NonBlock::Nowait => "NOWAIT",
NonBlock::SkipLocked => "SKIP LOCKED",
};
write!(f, "{nonblock}")
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum Distinct {
All,
Distinct,
On(Vec<Expr>),
}
impl fmt::Display for Distinct {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Distinct::All => write!(f, "ALL"),
Distinct::Distinct => write!(f, "DISTINCT"),
Distinct::On(col_names) => {
let col_names = display_comma_separated(col_names);
write!(f, "DISTINCT ON ({col_names})")
}
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct Top {
pub with_ties: bool,
pub percent: bool,
pub quantity: Option<TopQuantity>,
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum TopQuantity {
Expr(Expr),
Constant(u64),
}
impl fmt::Display for Top {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let extension = if self.with_ties { " WITH TIES" } else { "" };
if let Some(ref quantity) = self.quantity {
let percent = if self.percent { " PERCENT" } else { "" };
match quantity {
TopQuantity::Expr(quantity) => write!(f, "TOP ({quantity}){percent}{extension}"),
TopQuantity::Constant(quantity) => {
write!(f, "TOP {quantity}{percent}{extension}")
}
}
} else {
write!(f, "TOP{extension}")
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct Values {
pub explicit_row: bool,
pub value_keyword: bool,
pub rows: Vec<Vec<Expr>>,
}
impl fmt::Display for Values {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.value_keyword {
true => f.write_str("VALUE")?,
false => f.write_str("VALUES")?,
};
let prefix = if self.explicit_row { "ROW" } else { "" };
let mut delim = "";
for row in &self.rows {
f.write_str(delim)?;
delim = ",";
SpaceOrNewline.fmt(f)?;
Indent(format_args!("{prefix}({})", display_comma_separated(row))).fmt(f)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct SelectInto {
pub temporary: bool,
pub unlogged: bool,
pub table: bool,
pub name: ObjectName,
}
impl fmt::Display for SelectInto {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let temporary = if self.temporary { " TEMPORARY" } else { "" };
let unlogged = if self.unlogged { " UNLOGGED" } else { "" };
let table = if self.table { " TABLE" } else { "" };
write!(f, "INTO{}{}{} {}", temporary, unlogged, table, self.name)
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum GroupByWithModifier {
Rollup,
Cube,
Totals,
GroupingSets(Expr),
}
impl fmt::Display for GroupByWithModifier {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
GroupByWithModifier::Rollup => write!(f, "WITH ROLLUP"),
GroupByWithModifier::Cube => write!(f, "WITH CUBE"),
GroupByWithModifier::Totals => write!(f, "WITH TOTALS"),
GroupByWithModifier::GroupingSets(expr) => {
write!(f, "{expr}")
}
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum GroupByExpr {
All(Vec<GroupByWithModifier>),
Expressions(Vec<Expr>, Vec<GroupByWithModifier>),
}
impl fmt::Display for GroupByExpr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
GroupByExpr::All(modifiers) => {
write!(f, "GROUP BY ALL")?;
if !modifiers.is_empty() {
write!(f, " {}", display_separated(modifiers, " "))?;
}
Ok(())
}
GroupByExpr::Expressions(col_names, modifiers) => {
f.write_str("GROUP BY")?;
SpaceOrNewline.fmt(f)?;
Indent(display_comma_separated(col_names)).fmt(f)?;
if !modifiers.is_empty() {
write!(f, " {}", display_separated(modifiers, " "))?;
}
Ok(())
}
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum FormatClause {
Identifier(Ident),
Null,
}
impl fmt::Display for FormatClause {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
FormatClause::Identifier(ident) => write!(f, "FORMAT {ident}"),
FormatClause::Null => write!(f, "FORMAT NULL"),
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct InputFormatClause {
pub ident: Ident,
pub values: Vec<Expr>,
}
impl fmt::Display for InputFormatClause {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "FORMAT {}", self.ident)?;
if !self.values.is_empty() {
write!(f, " {}", display_comma_separated(self.values.as_slice()))?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum ForClause {
Browse,
Json {
for_json: ForJson,
root: Option<String>,
include_null_values: bool,
without_array_wrapper: bool,
},
Xml {
for_xml: ForXml,
elements: bool,
binary_base64: bool,
root: Option<String>,
r#type: bool,
},
}
impl fmt::Display for ForClause {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ForClause::Browse => write!(f, "FOR BROWSE"),
ForClause::Json {
for_json,
root,
include_null_values,
without_array_wrapper,
} => {
write!(f, "FOR JSON ")?;
write!(f, "{for_json}")?;
if let Some(root) = root {
write!(f, ", ROOT('{root}')")?;
}
if *include_null_values {
write!(f, ", INCLUDE_NULL_VALUES")?;
}
if *without_array_wrapper {
write!(f, ", WITHOUT_ARRAY_WRAPPER")?;
}
Ok(())
}
ForClause::Xml {
for_xml,
elements,
binary_base64,
root,
r#type,
} => {
write!(f, "FOR XML ")?;
write!(f, "{for_xml}")?;
if *binary_base64 {
write!(f, ", BINARY BASE64")?;
}
if *r#type {
write!(f, ", TYPE")?;
}
if let Some(root) = root {
write!(f, ", ROOT('{root}')")?;
}
if *elements {
write!(f, ", ELEMENTS")?;
}
Ok(())
}
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum ForXml {
Raw(Option<String>),
Auto,
Explicit,
Path(Option<String>),
}
impl fmt::Display for ForXml {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ForXml::Raw(root) => {
write!(f, "RAW")?;
if let Some(root) = root {
write!(f, "('{root}')")?;
}
Ok(())
}
ForXml::Auto => write!(f, "AUTO"),
ForXml::Explicit => write!(f, "EXPLICIT"),
ForXml::Path(root) => {
write!(f, "PATH")?;
if let Some(root) = root {
write!(f, "('{root}')")?;
}
Ok(())
}
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum ForJson {
Auto,
Path,
}
impl fmt::Display for ForJson {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ForJson::Auto => write!(f, "AUTO"),
ForJson::Path => write!(f, "PATH"),
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum JsonTableColumn {
Named(JsonTableNamedColumn),
ForOrdinality(Ident),
Nested(JsonTableNestedColumn),
}
impl fmt::Display for JsonTableColumn {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
JsonTableColumn::Named(json_table_named_column) => {
write!(f, "{json_table_named_column}")
}
JsonTableColumn::ForOrdinality(ident) => write!(f, "{ident} FOR ORDINALITY"),
JsonTableColumn::Nested(json_table_nested_column) => {
write!(f, "{json_table_nested_column}")
}
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct JsonTableNestedColumn {
pub path: Value,
pub columns: Vec<JsonTableColumn>,
}
impl fmt::Display for JsonTableNestedColumn {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"NESTED PATH {} COLUMNS ({})",
self.path,
display_comma_separated(&self.columns)
)
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct JsonTableNamedColumn {
pub name: Ident,
pub r#type: DataType,
pub path: Value,
pub exists: bool,
pub on_empty: Option<JsonTableColumnErrorHandling>,
pub on_error: Option<JsonTableColumnErrorHandling>,
}
impl fmt::Display for JsonTableNamedColumn {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{} {}{} PATH {}",
self.name,
self.r#type,
if self.exists { " EXISTS" } else { "" },
self.path
)?;
if let Some(on_empty) = &self.on_empty {
write!(f, " {on_empty} ON EMPTY")?;
}
if let Some(on_error) = &self.on_error {
write!(f, " {on_error} ON ERROR")?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum JsonTableColumnErrorHandling {
Null,
Default(Value),
Error,
}
impl fmt::Display for JsonTableColumnErrorHandling {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
JsonTableColumnErrorHandling::Null => write!(f, "NULL"),
JsonTableColumnErrorHandling::Default(json_string) => {
write!(f, "DEFAULT {json_string}")
}
JsonTableColumnErrorHandling::Error => write!(f, "ERROR"),
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct OpenJsonTableColumn {
pub name: Ident,
pub r#type: DataType,
pub path: Option<String>,
pub as_json: bool,
}
impl fmt::Display for OpenJsonTableColumn {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {}", self.name, self.r#type)?;
if let Some(path) = &self.path {
write!(f, " '{}'", value::escape_single_quote_string(path))?;
}
if self.as_json {
write!(f, " AS JSON")?;
}
Ok(())
}
}
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum ValueTableMode {
AsStruct,
AsValue,
DistinctAsStruct,
DistinctAsValue,
}
impl fmt::Display for ValueTableMode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ValueTableMode::AsStruct => write!(f, "AS STRUCT"),
ValueTableMode::AsValue => write!(f, "AS VALUE"),
ValueTableMode::DistinctAsStruct => write!(f, "DISTINCT AS STRUCT"),
ValueTableMode::DistinctAsValue => write!(f, "DISTINCT AS VALUE"),
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum UpdateTableFromKind {
BeforeSet(Vec<TableWithJoins>),
AfterSet(Vec<TableWithJoins>),
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum XmlTableColumnOption {
NamedInfo {
r#type: DataType,
path: Option<Expr>,
default: Option<Expr>,
nullable: bool,
},
ForOrdinality,
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct XmlTableColumn {
pub name: Ident,
pub option: XmlTableColumnOption,
}
impl fmt::Display for XmlTableColumn {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name)?;
match &self.option {
XmlTableColumnOption::NamedInfo {
r#type,
path,
default,
nullable,
} => {
write!(f, " {type}")?;
if let Some(p) = path {
write!(f, " PATH {p}")?;
}
if let Some(d) = default {
write!(f, " DEFAULT {d}")?;
}
if !*nullable {
write!(f, " NOT NULL")?;
}
Ok(())
}
XmlTableColumnOption::ForOrdinality => {
write!(f, " FOR ORDINALITY")
}
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct XmlPassingArgument {
pub expr: Expr,
pub alias: Option<Ident>,
pub by_value: bool,
}
impl fmt::Display for XmlPassingArgument {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.by_value {
write!(f, "BY VALUE ")?;
}
write!(f, "{}", self.expr)?;
if let Some(alias) = &self.alias {
write!(f, " AS {alias}")?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct XmlPassingClause {
pub arguments: Vec<XmlPassingArgument>,
}
impl fmt::Display for XmlPassingClause {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if !self.arguments.is_empty() {
write!(f, " PASSING {}", display_comma_separated(&self.arguments))?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct XmlNamespaceDefinition {
pub uri: Expr,
pub name: Ident,
}
impl fmt::Display for XmlNamespaceDefinition {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} AS {}", self.uri, self.name)
}
}