use super::common::{lower_data_type, lower_expr, lower_object_name};
use super::dml::lower_select;
use super::lower_statement;
use crate::ast as executor_ast;
use crate::error::DbError;
use crate::parser::ast;
pub fn lower_procedural(
proc: ast::ProceduralStatement,
) -> Result<executor_ast::Statement, DbError> {
match proc {
ast::ProceduralStatement::Declare(vars) => {
if vars.len() == 1 {
let var = match vars.into_iter().next() {
Some(var) => var,
None => {
return Err(DbError::Parse(
"DECLARE requires at least one variable".into(),
))
}
};
Ok(executor_ast::Statement::Procedural(
executor_ast::statements::ProceduralStatement::Declare(
executor_ast::statements::procedural::DeclareStmt {
name: var.name,
data_type: lower_data_type(var.data_type)?,
default: var.initial_value.map(lower_expr).transpose()?,
},
),
))
} else {
let mut stmts = Vec::new();
for var in vars {
stmts.push(executor_ast::Statement::Procedural(
executor_ast::statements::ProceduralStatement::Declare(
executor_ast::statements::procedural::DeclareStmt {
name: var.name,
data_type: lower_data_type(var.data_type)?,
default: var.initial_value.map(lower_expr).transpose()?,
},
),
));
}
Ok(executor_ast::Statement::Procedural(
executor_ast::statements::ProceduralStatement::BeginEnd(stmts),
))
}
}
ast::ProceduralStatement::DeclareTableVar {
name,
columns,
constraints,
} => Ok(executor_ast::Statement::Procedural(
executor_ast::statements::ProceduralStatement::DeclareTableVar(
executor_ast::statements::procedural::DeclareTableVarStmt {
name,
columns: columns
.into_iter()
.map(super::ddl::lower_column_def)
.collect::<Result<Vec<_>, _>>()?,
table_constraints: constraints
.into_iter()
.map(super::ddl::lower_table_constraint)
.collect::<Result<Vec<_>, _>>()?,
},
),
)),
ast::ProceduralStatement::Synonym { name, base_object } => Ok(
executor_ast::Statement::Ddl(executor_ast::statements::DdlStatement::CreateSynonym(
executor_ast::statements::ddl::CreateSynonymStmt {
name: lower_object_name(name),
base_object: lower_object_name(base_object),
},
)),
),
ast::ProceduralStatement::Sequence {
name,
data_type,
start_with,
increment_by,
min_value,
max_value,
cycle,
} => Ok(executor_ast::Statement::Ddl(
executor_ast::statements::DdlStatement::CreateSequence(
executor_ast::statements::ddl::CreateSequenceStmt {
name: lower_object_name(name),
data_type: data_type
.map(lower_data_type)
.transpose()?
.unwrap_or(executor_ast::data_types::DataTypeSpec::BigInt),
start_value: start_with.unwrap_or(1),
increment: increment_by.unwrap_or(1),
minimum_value: min_value.unwrap_or(i64::MIN),
maximum_value: max_value.unwrap_or(i64::MAX),
is_cycling: cycle,
},
),
)),
ast::ProceduralStatement::DeclareCursor { name, query } => {
Ok(executor_ast::Statement::Procedural(
executor_ast::statements::ProceduralStatement::DeclareCursor(
executor_ast::statements::procedural::DeclareCursorStmt {
name,
query: lower_select(query)?,
},
),
))
}
ast::ProceduralStatement::Set { variable, expr } => {
Ok(executor_ast::Statement::Procedural(
executor_ast::statements::ProceduralStatement::Set(
executor_ast::statements::procedural::SetStmt {
name: variable,
expr: lower_expr(expr)?,
},
),
))
}
ast::ProceduralStatement::If {
condition,
then_stmt,
else_stmt,
} => {
let then_body = match lower_statement(*then_stmt)? {
executor_ast::Statement::Procedural(
executor_ast::statements::ProceduralStatement::BeginEnd(stmts),
) => stmts,
other => vec![other],
};
let else_body = match else_stmt {
Some(s) => Some(match lower_statement(*s)? {
executor_ast::Statement::Procedural(
executor_ast::statements::ProceduralStatement::BeginEnd(stmts),
) => stmts,
other => vec![other],
}),
None => None,
};
Ok(executor_ast::Statement::Procedural(
executor_ast::statements::ProceduralStatement::If(
executor_ast::statements::procedural::IfStmt {
condition: lower_expr(condition)?,
then_body,
else_body,
},
),
))
}
ast::ProceduralStatement::BeginEnd(stmts) => Ok(executor_ast::Statement::Procedural(
executor_ast::statements::ProceduralStatement::BeginEnd(
stmts
.into_iter()
.map(lower_statement)
.collect::<Result<Vec<_>, _>>()?,
),
)),
ast::ProceduralStatement::While { condition, stmt } => {
let body = match lower_statement(*stmt)? {
executor_ast::Statement::Procedural(
executor_ast::statements::ProceduralStatement::BeginEnd(stmts),
) => stmts,
other => vec![other],
};
Ok(executor_ast::Statement::Procedural(
executor_ast::statements::ProceduralStatement::While(
executor_ast::statements::procedural::WhileStmt {
condition: lower_expr(condition)?,
body,
},
),
))
}
ast::ProceduralStatement::Break => Ok(executor_ast::Statement::Procedural(
executor_ast::statements::ProceduralStatement::Break,
)),
ast::ProceduralStatement::Continue => Ok(executor_ast::Statement::Procedural(
executor_ast::statements::ProceduralStatement::Continue,
)),
ast::ProceduralStatement::Return(expr) => Ok(executor_ast::Statement::Procedural(
executor_ast::statements::ProceduralStatement::Return(
expr.map(lower_expr).transpose()?,
),
)),
ast::ProceduralStatement::Print(expr) => Ok(executor_ast::Statement::Procedural(
executor_ast::statements::ProceduralStatement::Print(lower_expr(expr)?),
)),
ast::ProceduralStatement::Raiserror {
message,
severity,
state,
} => Ok(executor_ast::Statement::Procedural(
executor_ast::statements::ProceduralStatement::Raiserror(
executor_ast::statements::procedural::RaiserrorStmt {
message: lower_expr(message)?,
severity: lower_expr(severity)?,
state: lower_expr(state)?,
},
),
)),
ast::ProceduralStatement::Throw {
error_number,
message,
state,
} => Ok(executor_ast::Statement::Procedural(
executor_ast::statements::ProceduralStatement::Throw(
executor_ast::statements::procedural::ThrowStmt {
error_number: error_number.map(lower_expr).transpose()?,
message: message.map(lower_expr).transpose()?,
state: state.map(lower_expr).transpose()?,
},
),
)),
ast::ProceduralStatement::TryCatch {
try_body,
catch_body,
} => Ok(executor_ast::Statement::Procedural(
executor_ast::statements::ProceduralStatement::TryCatch(
executor_ast::statements::procedural::TryCatchStmt {
try_body: try_body
.into_iter()
.map(lower_statement)
.collect::<Result<Vec<_>, _>>()?,
catch_body: catch_body
.into_iter()
.map(lower_statement)
.collect::<Result<Vec<_>, _>>()?,
},
),
)),
ast::ProceduralStatement::ExecDynamic { sql_expr } => {
Ok(executor_ast::Statement::Procedural(
executor_ast::statements::ProceduralStatement::ExecDynamic(
executor_ast::statements::procedural::ExecStmt {
sql_expr: lower_expr(sql_expr)?,
},
),
))
}
ast::ProceduralStatement::ExecProcedure {
return_variable,
name,
args,
} => Ok(executor_ast::Statement::Procedural(
executor_ast::statements::ProceduralStatement::ExecProcedure(
executor_ast::statements::procedural::ExecProcedureStmt {
return_variable,
name: lower_object_name(name),
args: args
.into_iter()
.map(lower_exec_arg)
.collect::<Result<Vec<_>, _>>()?,
},
),
)),
ast::ProceduralStatement::SpExecuteSql {
sql_expr,
params_def,
args,
} => Ok(executor_ast::Statement::Procedural(
executor_ast::statements::ProceduralStatement::SpExecuteSql(
executor_ast::statements::procedural::SpExecuteSqlStmt {
sql_expr: lower_expr(sql_expr)?,
params_def: params_def.map(lower_expr).transpose()?,
args: args
.into_iter()
.map(lower_exec_arg)
.collect::<Result<Vec<_>, _>>()?,
},
),
)),
}
}
pub fn lower_transaction(
txn: ast::TransactionStatement,
) -> Result<executor_ast::Statement, DbError> {
match txn {
ast::TransactionStatement::Begin(name) => Ok(executor_ast::Statement::Transaction(
executor_ast::statements::TransactionStatement::Begin(name),
)),
ast::TransactionStatement::Commit(name) => Ok(executor_ast::Statement::Transaction(
executor_ast::statements::TransactionStatement::Commit(name),
)),
ast::TransactionStatement::Rollback(name) => Ok(executor_ast::Statement::Transaction(
executor_ast::statements::TransactionStatement::Rollback(name),
)),
ast::TransactionStatement::Save(name) => Ok(executor_ast::Statement::Transaction(
executor_ast::statements::TransactionStatement::Save(name),
)),
}
}
pub fn lower_cursor(cursor: ast::CursorStatement) -> Result<executor_ast::Statement, DbError> {
match cursor {
ast::CursorStatement::Open(name) => Ok(executor_ast::Statement::Cursor(
executor_ast::statements::CursorStatement::OpenCursor(name),
)),
ast::CursorStatement::Fetch {
name,
direction,
into_vars,
} => Ok(executor_ast::Statement::Cursor(
executor_ast::statements::CursorStatement::FetchCursor(
executor_ast::statements::procedural::FetchCursorStmt {
name,
direction: lower_fetch_direction(direction)?,
into: into_vars,
},
),
)),
ast::CursorStatement::Close(name) => Ok(executor_ast::Statement::Cursor(
executor_ast::statements::CursorStatement::CloseCursor(name),
)),
ast::CursorStatement::Deallocate(name) => Ok(executor_ast::Statement::Cursor(
executor_ast::statements::CursorStatement::DeallocateCursor(name),
)),
}
}
pub fn lower_session(session: ast::SessionStatement) -> Result<executor_ast::Statement, DbError> {
match session {
ast::SessionStatement::SetTransactionIsolationLevel(iso) => {
Ok(executor_ast::Statement::Session(
executor_ast::statements::SessionStatement::SetTransactionIsolationLevel(
match iso {
ast::IsolationLevel::ReadUncommitted => {
executor_ast::IsolationLevel::ReadUncommitted
}
ast::IsolationLevel::ReadCommitted => {
executor_ast::IsolationLevel::ReadCommitted
}
ast::IsolationLevel::RepeatableRead => {
executor_ast::IsolationLevel::RepeatableRead
}
ast::IsolationLevel::Serializable => {
executor_ast::IsolationLevel::Serializable
}
ast::IsolationLevel::Snapshot => executor_ast::IsolationLevel::Snapshot,
},
),
))
}
ast::SessionStatement::UseDatabase(database) => Ok(executor_ast::Statement::Session(
executor_ast::statements::SessionStatement::UseDatabase(database),
)),
ast::SessionStatement::SetOption { option, value } => Ok(executor_ast::Statement::Session(
executor_ast::statements::SessionStatement::SetOption(
executor_ast::statements::procedural::SetOptionStmt {
option: match option {
ast::SessionOption::AnsiNulls => executor_ast::SessionOption::AnsiNulls,
ast::SessionOption::QuotedIdentifier => {
executor_ast::SessionOption::QuotedIdentifier
}
ast::SessionOption::NoCount => executor_ast::SessionOption::NoCount,
ast::SessionOption::XactAbort => executor_ast::SessionOption::XactAbort,
ast::SessionOption::FmtOnly => executor_ast::SessionOption::FmtOnly,
ast::SessionOption::NoExec => executor_ast::SessionOption::NoExec,
ast::SessionOption::DateFirst => executor_ast::SessionOption::DateFirst,
ast::SessionOption::Language => executor_ast::SessionOption::Language,
ast::SessionOption::DateFormat => executor_ast::SessionOption::DateFormat,
ast::SessionOption::LockTimeout => executor_ast::SessionOption::LockTimeout,
ast::SessionOption::RowCount => executor_ast::SessionOption::RowCount,
ast::SessionOption::TextSize => executor_ast::SessionOption::TextSize,
ast::SessionOption::ConcatNullYieldsNull => {
executor_ast::SessionOption::ConcatNullYieldsNull
}
ast::SessionOption::ArithAbort => executor_ast::SessionOption::ArithAbort,
ast::SessionOption::QueryGovernorCostLimit => {
executor_ast::SessionOption::QueryGovernorCostLimit
}
ast::SessionOption::DeadlockPriority => {
executor_ast::SessionOption::DeadlockPriority
}
ast::SessionOption::AnsiNullDfltOn => {
executor_ast::SessionOption::AnsiNullDfltOn
}
ast::SessionOption::AnsiPadding => executor_ast::SessionOption::AnsiPadding,
ast::SessionOption::AnsiWarnings => {
executor_ast::SessionOption::AnsiWarnings
}
ast::SessionOption::CursorCloseOnCommit => {
executor_ast::SessionOption::CursorCloseOnCommit
}
ast::SessionOption::ImplicitTransactions => {
executor_ast::SessionOption::ImplicitTransactions
}
ast::SessionOption::StatisticsIo => {
executor_ast::SessionOption::StatisticsIo
}
ast::SessionOption::StatisticsTime => {
executor_ast::SessionOption::StatisticsTime
}
ast::SessionOption::ShowplanAll => executor_ast::SessionOption::ShowplanAll,
ast::SessionOption::AnsiDefaults => {
executor_ast::SessionOption::AnsiDefaults
}
ast::SessionOption::Unsupported(v) => {
executor_ast::SessionOption::Unsupported(v)
}
},
value: match value {
ast::SessionOptionValue::Bool(v) => {
executor_ast::SessionOptionValue::Bool(v)
}
ast::SessionOptionValue::Int(v) => executor_ast::SessionOptionValue::Int(v),
ast::SessionOptionValue::Text(v) => {
executor_ast::SessionOptionValue::Text(v)
}
},
},
),
)),
ast::SessionStatement::SetIdentityInsert { table, on } => {
Ok(executor_ast::Statement::Session(
executor_ast::statements::SessionStatement::SetIdentityInsert(
executor_ast::statements::SetIdentityInsertStmt {
table: lower_object_name(table),
on,
},
),
))
}
ast::SessionStatement::SetContextInfo(expr) => Ok(executor_ast::Statement::Session(
executor_ast::statements::SessionStatement::SetContextInfo(lower_expr(expr)?),
)),
}
}
pub fn lower_exec_arg(
a: ast::ExecArg,
) -> Result<executor_ast::statements::procedural::ExecArgument, DbError> {
Ok(executor_ast::statements::procedural::ExecArgument {
name: a.name,
expr: lower_expr(a.expr)?,
is_output: a.is_output,
})
}
pub fn lower_fetch_direction(
d: ast::FetchDirection,
) -> Result<executor_ast::statements::procedural::FetchDirection, DbError> {
match d {
ast::FetchDirection::Next => Ok(executor_ast::statements::procedural::FetchDirection::Next),
ast::FetchDirection::Prior => {
Ok(executor_ast::statements::procedural::FetchDirection::Prior)
}
ast::FetchDirection::First => {
Ok(executor_ast::statements::procedural::FetchDirection::First)
}
ast::FetchDirection::Last => Ok(executor_ast::statements::procedural::FetchDirection::Last),
ast::FetchDirection::Absolute(expr) => {
Ok(executor_ast::statements::procedural::FetchDirection::Absolute(lower_expr(expr)?))
}
ast::FetchDirection::Relative(expr) => {
Ok(executor_ast::statements::procedural::FetchDirection::Relative(lower_expr(expr)?))
}
}
}