use crate::Engine;
use uqa_core::Value;
use uqa_execution::routines::{
context::{RoutineExpressions, RoutinePortals, RoutineStatements, RoutineTransactions},
transaction::RoutineSessionId,
RoutineContext,
};
use uqa_sql::{
assignment::routines::RoutineValueContext,
ast::{ColumnType, Expr, FetchCursorStmt, Statement},
plan::{ExpressionPlan, UnifiedPlan},
SQLError, SQLParam, SQLResult,
};
impl Engine {
pub(crate) fn routine_session_id(&self) -> RoutineSessionId {
RoutineSessionId(std::sync::Arc::as_ptr(&self.session) as usize)
}
pub(crate) fn routine_execution_context(&self) -> RoutineContext<'_> {
RoutineContext {
expressions: self,
statements: self,
transactions: self,
portals: self,
session: self.routine_session_id(),
runtime: self.query_runtime_view(),
}
}
}
impl RoutineValueContext for Engine {
fn catalog_column_type(&self, name: &str) -> Option<ColumnType> {
uqa_execution::catalog::projection::resolve_catalog_column_type(
&self.catalog_execution(),
name,
)
}
}
impl RoutineExpressions for Engine {
fn column_type_name(&self, name: &str) -> Result<ColumnType, SQLError> {
uqa_execution::catalog::projection::resolve_catalog_column_type_name(
&self.catalog_execution(),
name,
)
}
fn evaluate(&self, expression: &Expr) -> Result<Value, SQLError> {
crate::capabilities::query_expressions::eval_lowered_expression(self, expression, None, &[])
}
fn evaluate_with_type(
&self,
expression: &Expr,
) -> Result<(Value, Option<ColumnType>), SQLError> {
crate::capabilities::query_expressions::eval_lowered_expression_with_type(
self,
expression,
None,
&[],
)
}
fn expression_type(&self, plan: &ExpressionPlan) -> Result<Option<ColumnType>, SQLError> {
let mut scope = super::query_scope::new_for_current_routine(self);
scope.scalar_subqueries.clone_from(&plan.subqueries);
let hook = uqa_execution::query::relational::context::QueryExpressionFactory::bind_scope(
self, scope,
);
uqa_execution::scalar_type_with_resolver(
&plan.scalar,
&uqa_execution::RowSchema::default(),
&[],
hook.as_ref(),
)
}
}
impl RoutineStatements for Engine {
fn execute_plan(&self, plan: &UnifiedPlan, params: &[SQLParam]) -> Result<SQLResult, SQLError> {
uqa_execution::statement::compiled::execute_plan(
&self.compiled_statement_context(),
plan.clone(),
params,
)
}
fn execute_bound(
&self,
statement: Statement,
params: &[SQLParam],
) -> Result<SQLResult, SQLError> {
uqa_execution::statement::compiled::execute(
&self.compiled_statement_context(),
statement,
params,
)
}
fn execute_text(&self, text: &str, params: &[SQLParam]) -> Result<SQLResult, SQLError> {
uqa_execution::statement::batch::execute_nested(
&self.batch_execution_context(),
text,
params,
)
}
fn optimize_plan(&self, plan: UnifiedPlan) -> Result<UnifiedPlan, SQLError> {
crate::capabilities::statement_planning::optimize_engine_plan(self, plan)
}
fn assertions_enabled(&self) -> bool {
self.plpgsql_asserts_enabled()
}
}
impl RoutineTransactions for Engine {
fn depth(&self) -> usize {
self.transaction_depth()
}
fn begin(&self) -> Result<(), SQLError> {
self.begin()
}
fn commit(&self) -> Result<(), SQLError> {
self.commit()
}
fn rollback(&self) -> Result<(), SQLError> {
self.rollback()
}
fn finish_procedural_transaction(&self, commit: bool, chain: bool) -> Result<(), SQLError> {
self.finish_procedural_transaction(commit, chain)
}
}
impl RoutinePortals for Engine {
fn ensure_available(&self, name: &str) -> Result<(), SQLError> {
uqa_execution::statement::portal::declaration::ensure_plpgsql_session_portal_available(
self, name,
)
}
fn open(
&self,
params: &[SQLParam],
name: &str,
scroll: Option<bool>,
plan: &UnifiedPlan,
) -> Result<(), SQLError> {
uqa_execution::statement::portal::declaration::open_plpgsql_session_portal(
&self.portal_execution_context(),
params,
name,
scroll,
plan,
)
}
fn fetch(&self, request: &FetchCursorStmt) -> Result<SQLResult, SQLError> {
self.fetch_session_portal(request)
}
fn close(&self, name: &str) -> Result<(), SQLError> {
self.close_session_portal(name)
}
fn allocate_name(&self) -> String {
self.allocate_session_portal_name()
}
fn pin(&self, name: &str) -> Result<(), SQLError> {
self.pin_session_portal(name)
}
fn unpin(&self, name: &str) -> Result<(), SQLError> {
self.unpin_session_portal(name)
}
}