Skip to main content

radixdb_procedural/
host.rs

1use radixdb_catalog::ObjectId;
2use radixdb_core::Value;
3use radixdb_sql::{Expression, InfixOperator, Statement};
4
5use crate::{BudgetOwner, ProceduralResult, RuntimeValue};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub struct SavepointToken(pub u64);
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub struct CursorToken(pub u64);
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub struct PrincipalContext {
15    pub session_principal: ObjectId,
16    pub invoker_principal: ObjectId,
17    pub effective_principal: ObjectId,
18}
19
20#[derive(Debug, Clone, PartialEq)]
21pub struct AuditEvent {
22    pub object_id: ObjectId,
23    pub command_fingerprint: [u8; 32],
24    /// Validated JSON object. The executor enforces size and secret-bearing
25    /// key restrictions before inserting the system-owned row.
26    pub metadata: Value,
27}
28
29#[derive(Debug, Clone, PartialEq)]
30pub struct OutboxMessage {
31    pub idempotency_key: String,
32    pub schema_version: u32,
33    pub payload: Value,
34}
35
36#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
37pub struct SqlOutcome {
38    pub affected_rows: u64,
39}
40
41/// Pull-free row sink used by the executor bridge. The host may produce rows
42/// incrementally and never needs to materialize the full result in this crate.
43pub trait SqlRowSink {
44    fn push_row(&mut self, row: Vec<RuntimeValue>) -> ProceduralResult<()>;
45}
46
47pub trait SqlHost {
48    /// Evaluate a semantically bound SQL expression using the same expression
49    /// compiler/evaluator as ordinary SQL execution.
50    fn evaluate_expression(
51        &mut self,
52        expression: &Expression,
53        parameters: &[RuntimeValue],
54        budget: &BudgetOwner,
55    ) -> ProceduralResult<RuntimeValue>;
56
57    /// Evaluate one already-admitted SQL binary operator over materialized
58    /// operands. This is used when a procedural intrinsic (for example
59    /// `SQL%ROWCOUNT`) appears inside a larger expression. The executor remains
60    /// the sole owner of SQL NULL, comparison and arithmetic semantics.
61    fn evaluate_binary(
62        &mut self,
63        _operator: InfixOperator,
64        _left: &RuntimeValue,
65        _right: &RuntimeValue,
66        _budget: &BudgetOwner,
67    ) -> ProceduralResult<RuntimeValue> {
68        Err(crate::Diagnostic::new(
69            crate::DiagnosticKind::VerifyCapabilityDenied,
70            "SQL binary evaluation is not implemented by this executor host",
71        ))
72    }
73
74    fn execute_sql(
75        &mut self,
76        statement: &Statement,
77        parameters: &[RuntimeValue],
78        rows: &mut dyn SqlRowSink,
79        budget: &BudgetOwner,
80    ) -> ProceduralResult<SqlOutcome>;
81
82    /// Parse and execute one dynamically produced SQL statement. Executor
83    /// implementations must route this through the shared SQL parser, binder,
84    /// ACL checks and statement executor. The default implementation is fail
85    /// closed so a host cannot accidentally admit a second SQL path.
86    fn execute_dynamic_sql(
87        &mut self,
88        _source: &str,
89        _parameters: &[RuntimeValue],
90        _rows: &mut dyn SqlRowSink,
91        _budget: &BudgetOwner,
92    ) -> ProceduralResult<SqlOutcome> {
93        Err(crate::Diagnostic::new(
94            crate::DiagnosticKind::VerifyCapabilityDenied,
95            "dynamic SQL is not implemented by this executor host",
96        ))
97    }
98}
99
100/// Streaming cursor boundary. Cursor state remains owned by the executor and
101/// tied to the caller transaction; the procedural frame retains only an
102/// opaque token.
103pub trait CursorHost {
104    fn open_cursor(
105        &mut self,
106        _statement: &Statement,
107        _parameters: &[RuntimeValue],
108        _budget: &BudgetOwner,
109    ) -> ProceduralResult<CursorToken> {
110        Err(crate::Diagnostic::new(
111            crate::DiagnosticKind::VerifyCapabilityDenied,
112            "streaming cursors are not implemented by this executor host",
113        ))
114    }
115
116    fn fetch_cursor(
117        &mut self,
118        _cursor: CursorToken,
119        _budget: &BudgetOwner,
120    ) -> ProceduralResult<Option<Vec<RuntimeValue>>> {
121        Err(crate::Diagnostic::new(
122            crate::DiagnosticKind::VerifyCapabilityDenied,
123            "streaming cursors are not implemented by this executor host",
124        ))
125    }
126
127    fn close_cursor(&mut self, _cursor: CursorToken) -> ProceduralResult<()> {
128        Err(crate::Diagnostic::new(
129            crate::DiagnosticKind::VerifyCapabilityDenied,
130            "streaming cursors are not implemented by this executor host",
131        ))
132    }
133}
134
135pub trait TransactionHost {
136    fn create_savepoint(&mut self) -> ProceduralResult<SavepointToken>;
137    fn rollback_savepoint(&mut self, savepoint: SavepointToken) -> ProceduralResult<()>;
138    fn release_savepoint(&mut self, savepoint: SavepointToken) -> ProceduralResult<()>;
139}
140
141pub trait PrincipalHost {
142    fn principal_context(&self) -> PrincipalContext;
143    fn push_definer(&mut self, owner: ObjectId) -> ProceduralResult<()>;
144    fn pop_definer(&mut self) -> ProceduralResult<()>;
145}
146
147pub trait RoutineCallHost {
148    fn call_routine(
149        &mut self,
150        routine: ObjectId,
151        arguments: &[RuntimeValue],
152        budget: &BudgetOwner,
153    ) -> ProceduralResult<Vec<RuntimeValue>>;
154}
155
156pub trait AuditHost {
157    fn append_audit(&mut self, event: AuditEvent) -> ProceduralResult<()>;
158}
159
160pub trait OutboxHost {
161    fn append_outbox(&mut self, message: OutboxMessage) -> ProceduralResult<()>;
162}
163
164pub trait RuntimeHost:
165    SqlHost + CursorHost + TransactionHost + PrincipalHost + RoutineCallHost + AuditHost + OutboxHost
166{
167}
168
169impl<T> RuntimeHost for T where
170    T: SqlHost
171        + CursorHost
172        + TransactionHost
173        + PrincipalHost
174        + RoutineCallHost
175        + AuditHost
176        + OutboxHost
177{
178}