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
//! Shared SQLite `LIKE` pattern construction for operator-supplied text.
//!
//! Any filter that puts operator text into a `LIKE` pattern has to escape
//! the metacharacters first, or the text stops being text: `%` matches
//! everything and `_` matches any single character, so an unescaped
//! search silently widens to far more rows than asked for and comes back
//! looking like a match. For a fleet filter that is not cosmetic — a
//! metadata search for `_` would return the whole fleet and read as
//! "every machine has this attribute".
//!
//! The rule lives here because it kept being re-derived. `agents.rs`
//! already carried a note that three copies had drifted apart, and by the
//! time #1343 wanted the same escaping for `obs_events` there were still
//! two more open-coded closures in `inventory.rs`. A rule that is
//! security-relevant and duplicated per call site is a rule that will
//! diverge; sharing it the way `time_bounds` is shared (a small submodule
//! several `api` handlers import) makes divergence impossible rather than
//! merely discouraged.
//!
//! Every caller must declare `ESCAPE '\'` in its SQL. Note that in a Rust
//! string literal that has to be written `ESCAPE '\\'` — writing `'\'`
//! produces an EMPTY escape clause, which SQLite rejects only when the
//! `LIKE` is actually evaluated, so the mistake hides behind any
//! short-circuiting `IS NULL` gate and passes every unfiltered query.
/// Escape the LIKE metacharacters (`\` `%` `_`) so `s` matches literally
/// under a `LIKE … ESCAPE '\'` clause. Single source of truth for the
/// escape rule; the `*_like` wrappers add their own `%` framing on top.
///
/// The backslash must be replaced FIRST — escaping `%` and `_` introduces
/// new backslashes, and a later pass over them would double the ones this
/// function just added.
pub
/// `LIKE '%value%'` — a contains match.
pub
/// `LIKE 'value%'` — a starts-with match.
pub