1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//! Binding `RAISE(...)`.
//!
//! Invariant: **a `RAISE` binds only inside a trigger body, and its message is
//! any expression.** A string literal is kept as text, which is what the
//! foreign key bodies the binder synthesises use; anything else is bound over
//! the trigger's row and evaluated when the `RAISE` fires.
use super::{schema_refused, Binder, BoundExpr};
use crate::ast::{ExprId, RaiseAction};
use crate::diagnostic::ParseError;
use crate::lexer::Span;
impl Binder<'_> {
/// Binds `RAISE(action[, message])`.
///
/// **The message is an expression, as SQLite takes it.** `RAISE(ABORT,
/// 'too big: ' || NEW.n)` names the value that broke the rule, which is
/// the reason to write a guard trigger at all; it used to be a syntax
/// error at the `||`.
///
/// @param action - which action was written
/// @param message - the message expression, when the action takes one
/// @param span - where the call was written, for a refusal
pub(super) fn bind_raise(
&mut self,
action: RaiseAction,
message: Option<ExprId>,
span: Span,
) -> Result<BoundExpr, ParseError> {
// Outside a trigger body there is nothing for it to abandon, so
// SQLite refuses it there rather than treating it as a no-op.
if self.row_aliases.is_none() {
// SQLite prints no position for this failure.
let _ = span;
return Err(schema_refused(
"RAISE() may only be used within a trigger-program",
Span::default(),
));
}
let bound = match message {
Some(id) => Some(self.bind_expr(id)?),
None => None,
};
let (message, computed) = match bound {
Some(BoundExpr::Text(text)) => (Some(text), None),
Some(other) => (None, Some(Box::new(other))),
None => (None, None),
};
Ok(BoundExpr::Raise {
action,
message,
computed,
foreign_key: false,
})
}
}