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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
//! SQLite function behavior flags for custom SQL functions.
#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
extern crate libsqlite3_sys as ffi;
#[cfg(all(target_family = "wasm", target_os = "unknown"))]
use sqlite_wasm_rs as ffi;
bitflags::bitflags! {
/// Flags controlling SQLite custom function behavior.
///
/// These flags are passed to `sqlite3_create_function_v2()` and control
/// how SQLite treats the function in various contexts.
///
/// # Availability
///
/// - [`DETERMINISTIC`][Self::DETERMINISTIC]: SQLite 3.8.3 (2014-02)
/// - [`DIRECTONLY`][Self::DIRECTONLY], [`INNOCUOUS`][Self::INNOCUOUS]: SQLite 3.31.0 (2020-01)
/// - [`SUBTYPE`][Self::SUBTYPE]: SQLite 3.30.0 (2019-10)
///
/// # Security Considerations
///
/// When using [`SqliteConnection::set_trusted_schema(false)`][crate::sqlite::SqliteConnection::set_trusted_schema]
/// for security hardening, custom functions must be marked with [`INNOCUOUS`][Self::INNOCUOUS]
/// to be callable from views, triggers, CHECK constraints, DEFAULT expressions,
/// generated columns, and expression indexes.
///
/// Conversely, functions with side effects or that expose sensitive state
/// should be marked with [`DIRECTONLY`][Self::DIRECTONLY] to prevent them from being called
/// via malicious schema objects in untrusted database files.
///
/// # Example
///
/// ```rust
/// use diesel::sqlite::SqliteFunctionBehavior;
///
/// // Deterministic function (most common case)
/// let flags = SqliteFunctionBehavior::DETERMINISTIC;
/// assert!(flags.contains(SqliteFunctionBehavior::DETERMINISTIC));
///
/// // Non-deterministic function (e.g., random())
/// let flags = SqliteFunctionBehavior::empty();
/// assert!(flags.is_empty());
///
/// // Safe for use in untrusted schemas (views, triggers, etc.)
/// let flags = SqliteFunctionBehavior::DETERMINISTIC | SqliteFunctionBehavior::INNOCUOUS;
/// assert!(flags.contains(SqliteFunctionBehavior::DETERMINISTIC));
/// assert!(flags.contains(SqliteFunctionBehavior::INNOCUOUS));
///
/// // Has side effects, block from schema objects
/// let flags = SqliteFunctionBehavior::DIRECTONLY;
/// assert!(flags.contains(SqliteFunctionBehavior::DIRECTONLY));
/// ```
///
/// When registering a custom SQL function:
///
/// ```rust
/// # include!("../doctest_setup.rs");
/// use diesel::sqlite::SqliteFunctionBehavior;
/// use diesel::prelude::*;
///
/// # // This test registers a Rust callback that sqlite invokes through the
/// # // FFI boundary, which is not supported by miri `-Zmiri-native-lib`.
/// # #[cfg(miri)]
/// # fn main() {}
/// # #[cfg(not(miri))]
/// # fn main() {
/// # run_test().unwrap();
/// # }
/// #
/// # fn run_test() -> diesel::result::QueryResult<()> {
/// # let mut conn = establish_connection();
/// // Use SqliteFunctionBehavior when registering SQL functions
/// conn.register_sql_function::<diesel::sql_types::Text, diesel::sql_types::Text, _, _, _>(
/// "my_upper",
/// SqliteFunctionBehavior::DETERMINISTIC | SqliteFunctionBehavior::INNOCUOUS,
/// |x: String| x.to_uppercase(),
/// )?;
/// # Ok(())
/// # }
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SqliteFunctionBehavior: i32 {
/// The function always returns the same result given the same inputs
/// within a single SQL statement.
///
/// This allows SQLite to optimize by caching results and factoring
/// the function out of inner loops. Most pure functions should use this flag.
///
/// # Availability
///
/// Requires SQLite 3.8.3 (2014-02) or later.
///
/// # Example
///
/// `abs(x)` is deterministic. `random()` is not.
const DETERMINISTIC = ffi::SQLITE_DETERMINISTIC;
/// The function cannot be called from schema objects (views, triggers,
/// CHECK constraints, DEFAULT expressions, generated columns, or
/// expression indexes).
///
/// Use this for functions that:
/// - Have side effects (network, file I/O, logging, etc.)
/// - Return sensitive application state
/// - Should not be triggered by opening an untrusted database
///
/// # Availability
///
/// Requires SQLite 3.31.0 (2020-01) or later.
///
/// # Security Recommendation
///
/// Mark all functions with side effects or that expose internal state
/// with `DIRECTONLY` to prevent schema injection attacks.
const DIRECTONLY = ffi::SQLITE_DIRECTONLY;
/// The function is safe to call from untrusted schema contexts.
///
/// When [`SqliteConnection::set_trusted_schema(false)`][crate::sqlite::SqliteConnection::set_trusted_schema]
/// is set, only functions marked `INNOCUOUS` can be called from schema
/// objects (views, triggers, CHECK constraints, DEFAULT expressions,
/// generated columns, expression indexes).
///
/// # Availability
///
/// Requires SQLite 3.31.0 (2020-01) or later.
///
/// # Safety Requirements
///
/// **Only mark a function as INNOCUOUS if it:**
/// - Has no side effects
/// - Does not reveal internal application state
/// - Output depends solely on its input parameters
///
/// # Security Warning
///
/// Incorrectly marking a function as `INNOCUOUS` can create security
/// vulnerabilities when processing untrusted database files. An attacker
/// could craft a database with malicious views or triggers that invoke
/// your function in unexpected ways.
const INNOCUOUS = ffi::SQLITE_INNOCUOUS;
/// The function may call `sqlite3_value_subtype()` to inspect the
/// subtype of its arguments.
///
/// # Availability
///
/// Requires SQLite 3.30.0 (2019-10) or later.
const SUBTYPE = ffi::SQLITE_SUBTYPE;
}
}
impl Default for SqliteFunctionBehavior {
/// Returns `Self::empty()`
fn default() -> Self {
Self::empty()
}
}
impl SqliteFunctionBehavior {
/// Returns the raw flags value including UTF8 encoding flag.
///
/// This is used internally when calling `sqlite3_create_function_v2`.
pub(crate) fn to_flags(self) -> i32 {
ffi::SQLITE_UTF8 | self.bits()
}
}