fix(search): restrict the /filter expression grammar (#3416)
The `where` and `orderby` validators accepted any lowercase function name
after a column reference, so expressions such as `"col".read_text()` or
`"col".read_blob(...)` passed validation and were handed to DuckDB. The
engine sandbox (allowed_paths, enable_external_access=false,
lock_configuration=true) refuses the file access, so such requests fail
instead of returning data, but the validator was no longer contributing a
layer of its own.
- restrict chained functions to an allowlist (len, length, lower, replace, upper)
- replace the repeated operator character class, which also matched spaces
and `*`, with an explicit alternation
- use fullmatch instead of match, and compile the patterns with IGNORECASE
rather than spelling out both cases
- accept signed and fractional numbers, and reject malformed ones such as 1.2.3
- log the length of `where` and `orderby` instead of their values
Regression tests cover the chained-function forms and confirm that the
allowlisted functions still pass.