use core::fmt::{self, Display};
#[cfg(not(feature = "std"))]
use alloc::{boxed::Box, vec::Vec};
#[cfg(feature = "std")]
use std::boxed::Box;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "visitor")]
use sqlparser_derive::{Visit, VisitMut};
use super::{DataType, Expr, Ident, ObjectName, Statement, ValueWithSpan};
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct PlPgSqlBlock {
pub declarations: Vec<PlPgSqlDeclaration>,
pub statements: Vec<PlPgSqlStatement>,
}
impl Display for PlPgSqlBlock {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if !self.declarations.is_empty() {
write!(f, "DECLARE ")?;
for declaration in &self.declarations {
write!(f, "{declaration}; ")?;
}
}
write!(f, "BEGIN")?;
for statement in &self.statements {
write!(f, " {statement};")?;
}
write!(f, " END")
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct PlPgSqlDeclaration {
pub name: Ident,
pub data_type: DataType,
pub initializer: Option<Expr>,
}
impl Display for PlPgSqlDeclaration {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {}", self.name, self.data_type)?;
if let Some(initializer) = &self.initializer {
write!(f, " := {initializer}")?;
}
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 PlPgSqlStatement {
Assignment {
target: ObjectName,
value: Expr,
},
If {
branches: Vec<PlPgSqlIfBranch>,
else_statements: Option<Vec<PlPgSqlStatement>>,
},
Return(Expr),
Sql(Box<Statement>),
GetRowCount {
target: Ident,
},
RaiseException {
format: ValueWithSpan,
arguments: Vec<Expr>,
hint: Option<Expr>,
},
}
impl Display for PlPgSqlStatement {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Assignment { target, value } => write!(f, "{target} := {value}"),
Self::If {
branches,
else_statements,
} => {
for (index, branch) in branches.iter().enumerate() {
if index == 0 {
write!(f, "IF {} THEN", branch.condition)?;
} else {
write!(f, " ELSIF {} THEN", branch.condition)?;
}
for statement in &branch.statements {
write!(f, " {statement};")?;
}
}
if let Some(statements) = else_statements {
write!(f, " ELSE")?;
for statement in statements {
write!(f, " {statement};")?;
}
}
write!(f, " END IF")
}
Self::Return(expression) => write!(f, "RETURN {expression}"),
Self::Sql(statement) => statement.fmt(f),
Self::GetRowCount { target } => {
write!(f, "GET DIAGNOSTICS {target} = ROW_COUNT")
}
Self::RaiseException {
format,
arguments,
hint,
} => {
write!(f, "RAISE EXCEPTION {format}")?;
for argument in arguments {
write!(f, ", {argument}")?;
}
if let Some(hint) = hint {
write!(f, " USING HINT = {hint}")?;
}
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 PlPgSqlIfBranch {
pub condition: Expr,
pub statements: Vec<PlPgSqlStatement>,
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct DoStatement {
pub body: ValueWithSpan,
pub language: Option<Ident>,
pub language_before_body: bool,
}
impl Display for DoStatement {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "DO")?;
if self.language_before_body {
if let Some(language) = &self.language {
write!(f, " LANGUAGE {language}")?;
}
}
write!(f, " {}", self.body)?;
if !self.language_before_body {
if let Some(language) = &self.language {
write!(f, " LANGUAGE {language}")?;
}
}
Ok(())
}
}