#[derive(Debug, Clone, PartialEq)]
pub struct ProceduralBlock {
pub statements: Vec<Statement>,
pub exception_handlers: Vec<ExceptionHandler>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ExceptionHandler {
pub condition: ExceptionCondition,
pub body: Vec<Statement>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum ExceptionCondition {
Others,
SqlState(String),
Named(String),
}
#[derive(Debug, Clone, PartialEq)]
pub enum Statement {
Declare {
name: String,
data_type: String,
default: Option<SqlExpr>,
},
Assign { target: String, expr: SqlExpr },
If {
condition: SqlExpr,
then_block: Vec<Statement>,
elsif_branches: Vec<ElsIfBranch>,
else_block: Option<Vec<Statement>>,
},
Loop { body: Vec<Statement> },
While {
condition: SqlExpr,
body: Vec<Statement>,
},
For {
var: String,
start: SqlExpr,
end: SqlExpr,
reverse: bool,
body: Vec<Statement>,
},
Break,
Continue,
Return { expr: SqlExpr },
ReturnQuery { query: String },
Raise { level: RaiseLevel, message: SqlExpr },
Sql { sql: String },
Commit,
Rollback,
Savepoint { name: String },
RollbackTo { name: String },
ReleaseSavepoint { name: String },
}
#[derive(Debug, Clone, PartialEq)]
pub struct ElsIfBranch {
pub condition: SqlExpr,
pub body: Vec<Statement>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct SqlExpr {
pub sql: String,
}
impl SqlExpr {
pub fn new(sql: impl Into<String>) -> Self {
Self { sql: sql.into() }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RaiseLevel {
Notice,
Warning,
Exception,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BodyKind {
Expression,
Procedural,
}
impl BodyKind {
pub fn detect(body_sql: &str) -> Self {
let trimmed = body_sql.trim().to_uppercase();
if trimmed.starts_with("BEGIN") {
Self::Procedural
} else {
Self::Expression
}
}
}