Commit Graph

921 Commits

Author SHA1 Message Date
lovasoa 08988a9c64 clippy 2026-08-23 09:45:08 +02:00
lovasoa e62a91f856 Refactor SQL variable cast tests to use typed assertions 2026-08-23 09:05:47 +02:00
Ophir Lojkine c96bbc0fe2 test: simplify variable cast tests and add focused repros for #516 and #1154
- Replace verbose pattern-matching in sql.rs with helpers sql_for/
  odbc_sql_for and table-driven asserts; keep coverage but drop
  ceremony and duplicated error messages.
- Keep limit and mssql tests as one-liners checking the generated
  SQL string.
- Trim .sql fixtures to minimal scaffold and add GH issue links as
  comments. New fixtures:
  * variable_limit_offset (MySQL, fixes #1154) — LIMIT/OFFSET with SET
    variables must not be wrapped in CAST.
  * variable_mssql_contains (MSSQL, fixes #516) — EXEC sp_executesql
    with a variable must not be wrapped in CAST.
- Simplify existing variable fixtures and add issue links, keep them
  short and readable.
2026-08-22 21:03:39 +00:00
Ophir Lojkine 903be5b185 refine: drop the text cast on MySQL, SQL Server and DuckDB behind ODBC too
ODBC connections were conservatively keeping the cast for every database.
Testing against real ODBC drivers shows the cast is needed only where the
parameter type cannot be determined without it:

- psqlodbc -> PostgreSQL: needed. Without it, context-free parameters fail
  with 'could not determine data type of parameter' (the earlier CI failure).
- sqliteodbc -> SQLite: needed. Without it, '? = 1' compares text against an
  integer and silently returns false, like on native SQLite.
- duckdb-odbc: not needed. The full test suite passes without the cast, as
  DuckDB defaults untyped parameters to VARCHAR.

The cast is therefore dropped for MySQL, SQL Server and DuckDB behind ODBC,
mirroring their native behavior (MySQL and SQL Server convert the bound
string at execution time, which also fixes the unicode mangling for SQL
Server reached through ODBC), and kept for PostgreSQL, SQLite, Oracle,
Snowflake and unknown databases.

Verified with the full test suite on native SQLite, PostgreSQL, MySQL and
SQL Server, and through ODBC on PostgreSQL, SQLite and DuckDB. The only
ODBC failure is a pre-existing database-filesystem timestamp test that also
fails on main.
2026-08-22 20:39:39 +00:00
Ophir Lojkine 42cf5b619a fix(odbc) :: keep the text cast around variables on ODBC connections
The ODBC job in CI failed because the cast was removed based on the
database name behind the driver: PostgreSQL reached through psqlodbc no
longer received CAST(? AS TEXT), and the driver could not determine the
type of context-free parameters such as in 'WHERE ? <> ? OR ? IS NULL',
failing with 'could not determine data type of parameter'.

The cast decision now keys off the connection kind: native PostgreSQL,
MySQL and SQL Server connections keep no cast, while every ODBC
connection keeps the previous per-database cast, since ODBC drivers
provide no parameter type information.

Adds a fixture comparing variables without any surrounding type context,
which exercises exactly this scenario on every database.
2026-08-22 20:19:20 +00:00
Ophir Lojkine 7e9adb14e5 feat(database) :: stop casting variables to TEXT on PostgreSQL, MySQL and SQL Server
SQLPage binds every variable as a string. The generated CAST(? AS TEXT)
forced the database to type the parameter as text, which is only needed
where parameter type inference is unpredictable (SQLite, ODBC). On the
natively supported databases the cast was redundant, and on SQL Server it
was harmful: the parameter is bound as NVARCHAR(MAX), and casting it to a
narrow VARCHAR mangled non-ASCII values before comparing them to nvarchar
columns. Generated SQL is now cleaner, e.g. WHERE id = $1 instead of
WHERE id = CAST($1 AS TEXT).

SQLite and ODBC-backed databases (Oracle, DuckDB, Snowflake, Generic)
keep the cast to preserve their comparison semantics.

Verified with the full test suite against SQLite, PostgreSQL, MySQL and
SQL Server, including new fixtures for integer-column comparisons,
numeric-literal comparisons, and unicode nvarchar comparisons on SQL
Server.
2026-08-22 15:44:13 +00:00
Prayag Bhakar 6fb9a35336 fix(rust): enforce lint on all files + fix lint issues (#1394) 2026-08-21 07:38:45 +02:00
Prayag Bhakar e99957bc93 fix(request_body) :: return NULL when the request has no body' (#1392) 2026-08-18 12:39:54 +02:00
lovasoa 0e9673a6ff Add body_md parameter to sqlpage.send_mail
Renders Markdown to HTML and sends as multipart/alternative
with raw Markdown as the plain-text body. When body_md is
provided, body becomes optional. body_md cannot be combined
with body_html.
2026-07-25 00:12:28 +02:00
lovasoa c6554a213d Add HTML body alternative to send_mail
The optional `body_html` field sends a multipart/alternative
message alongside the plain-text `body`, which remains required.
2026-07-24 23:51:43 +02:00
Ophir LOJKINE 91a28d1631 Remove unused SQLx macro facade
Depend directly on sqlx-core-oldapi and use its module-level runtime APIs. SQLPage uses no SQLx query or derive macros, so this removes sqlx-oldapi and sqlx-macros-oldapi from the resolved graph.

macOS arm64 cargo build --release: 43,037,040 -> 43,020,288 bytes (-16,752 bytes, -0.04%).
2026-07-17 23:54:40 +02:00
Ophir LOJKINE 69699b23cb Replace stale Lambda web adapter
Use AWS-maintained lambda_http for event and Runtime API handling, with a small channel-backed bridge to the non-Send Actix service. This adds maintained support for API Gateway v1/v2/WebSockets, ALB, Function URLs, and VPC Lattice while preserving duplicate headers and binary responses.

Stripped macOS arm64 release with --features lambda-web: 37,231,944 -> 36,657,200 bytes (-574,744 bytes, -1.5%).
2026-07-17 23:48:42 +02:00
Ophir LOJKINE 93afed919c Email sending improvement 2026-07-17 15:22:53 +02:00
Ophir LOJKINE 1839738f67 Merge branch 'main' into add-documented-send_mail-function 2026-07-17 13:53:51 +02:00
Ophir LOJKINE 214a986adf Merge remote-tracking branch 'origin/main' into add-documented-send_mail-function 2026-07-17 13:40:14 +02:00
Ophir LOJKINE 099366e4e4 Validate WHERE clause for invalid references 2026-07-16 11:58:32 +02:00
Ophir LOJKINE 5449033f7b Comments 2026-07-16 11:51:25 +02:00
Ophir LOJKINE 7be608212f fix tests on oracle odbc 2026-07-16 11:01:29 +02:00
Ophir LOJKINE 2276b31b91 Merge branch 'main' into lazy-fn-eval-in-set 2026-07-15 18:11:18 +02:00
Ophir LOJKINE 614c6303f5 Handle parentheses around computed projections 2026-07-15 18:03:14 +02:00
Ophir LOJKINE b60d834fd7 Reject computed aliases in database clauses 2026-07-15 17:55:50 +02:00
Ophir LOJKINE c2d27314bf quotes 2026-07-15 17:33:12 +02:00
Ophir LOJKINE f4052d3b83 Order positional bindings by rendered SQL 2026-07-15 17:21:03 +02:00
Ophir LOJKINE a175fd4215 Avoid dropping shared filesystem test tables 2026-07-15 16:06:18 +02:00
Ophir LOJKINE b0145c6d1c Reject grouping by computed projections 2026-07-15 16:06:11 +02:00
Ophir LOJKINE 8a35fa1e0d Match concat operator null semantics 2026-07-15 15:53:08 +02:00
Ophir LOJKINE 85254539fb improve error messages 2026-07-15 15:42:20 +02:00
Ophir LOJKINE c84eb68d77 Keep private inputs after wildcard projections 2026-07-15 15:33:39 +02:00
Ophir LOJKINE 556c62a573 Match CONCAT null semantics to the database 2026-07-15 15:05:54 +02:00
Ophir LOJKINE 709153b0e9 Validate SET columns before computed expressions 2026-07-15 15:01:07 +02:00
Ophir LOJKINE 5c45103eb2 Preserve backend scalar subquery semantics 2026-07-15 14:43:15 +02:00
Ophir LOJKINE 8427d4c323 Reject ordinal ordering with computed projections 2026-07-15 14:29:17 +02:00
Ophir LOJKINE 106aafc4c1 Preserve computed projection input positions 2026-07-15 14:28:33 +02:00
Ophir LOJKINE c181c21784 Add regressions for computed projection ordering 2026-07-15 14:24:39 +02:00
Ophir LOJKINE 947b189020 Add tests for mixed database and row expression rewriting
Cover cases where SQLPage functions span database and per-row
boundaries, including predicates, projections, and shared request/row
values.

Also add documentation to `QueryResult` and `BoundQuery`, tidy up
borrow expressions in the OIDC client, and rename a conflicting `rows`
alias in a test fixture.
2026-07-15 13:58:14 +02:00
Ophir LOJKINE e07594579b Refactor SQL parameter handling into unified expression tree
Replace the `StmtParam`/`ParameterExtractor` machinery with a shared
`SqlPageExpr` type parameterized over its input source, distinguishing
standalone expressions from per-row expressions via the type system.

Rename `ParsedSqlFile` to `SqlFile` and split SQL parsing into dedicated
`dialect`, `rewrite`, and `statement` submodules. Queries are now
rewritten into either a database query with bindings and computed
columns, or a single-row query evaluated without a database round trip.

Make `SqlPageFunctionName` parsing case-insensitive and support
SQLPage-computed projections and nested functions over query results.
2026-07-15 13:44:31 +02:00
lovasoa 00b969fe7d Add support for email attachments in sqlpage.send_mail
Introduce a `max_email_attachment_size` configuration option and support
for attaching files via data URLs with CC recipients in the send_mail
function. Refactor data URL decoding into a shared utility.
2026-07-14 16:50:37 +02:00
lovasoa 7b72bd5d1a Preserve session state for delayed run_sql 2026-07-11 00:34:44 +02:00
lovasoa 6ec26700ab Fix delayed concat detection 2026-07-11 00:27:24 +02:00
lovasoa 181805613c Retain delayed evaluation for non-concat projections 2026-07-11 00:27:00 +02:00
lovasoa 02bd98d953 Merge remote-tracking branch 'origin/lazy-fn-eval-in-set' into lazy-fn-eval-in-set 2026-07-11 00:25:35 +02:00
lovasoa 9659fedede Harden send_mail API and TLS configuration 2026-07-11 00:25:06 +02:00
lovasoa 9b4970d4c9 Preserve NULL semantics for constant SQLPage functions 2026-07-11 00:23:10 +02:00
Ophir LOJKINE 3f030aa1b4 Clarify SQL preprocessing pipeline 2026-07-11 00:19:50 +02:00
Ophir LOJKINE 77797c909e Fix SMTP config typo and add TLS mode support
Rename the misspelled `stmp_*` configuration options to `smtp_*`
and add a new `smtp_tls_mode` option (`starttls`, `tls`, `none`)
to control encryption when connecting to the SMTP server. Reject
credentials in plaintext mode.

Change `sqlpage.send_mail` to return its JSON argument unchanged
on success and update the example to use a local Mailpit SMTP
server via Docker Compose.
2026-07-10 18:10:04 +02:00
Ophir LOJKINE 5a15e18951 Fix nested request params in SQLPage functions 2026-07-10 17:46:41 +02:00
Ophir LOJKINE 72e695ec4a Add sqlpage.send_mail function and STMP_HOST configuration
### Motivation
- Provide a built-in `sqlpage.send_mail(...)` SQL function so pages can send plain-text emails from SQL code.
- Allow the SMTP server to be configured via an environment / configuration option so the function can target a deployable SMTP endpoint.

### Description
- Added a new function implementation at `src/webserver/database/sqlpage_functions/functions/send_mail.rs` implementing `sqlpage.send_mail(json)` which accepts a JSON object with required `recipient`, `subject`, and `body` and optional `sender` and `reply_to`, sends the message and returns `sent` on success.
- Registered the function in the SQLPage function registry by adding `send_mail` to `src/webserver/database/sqlpage_functions/functions.rs`.
- Added a configuration option `stmp_host: Option<String>` to `AppConfig` in `src/app_config.rs`, with `parse_stmp_host`/`validate_stmp_host` helpers that accept either `host` or `host:port` and default to port 25 when none is provided; validation is run from `AppConfig::validate`.
- Added `lettre` to `Cargo.toml` and updated `Cargo.lock` to enable SMTP sending, and added official-site documentation and a migration at `examples/official-site/sqlpage/migrations/75_send_mail.sql` describing usage and parameters.
- Documented the `stmp_host` option in `configuration.md`.

### Testing
- Ran `cargo fmt --all`, which completed successfully.
- Ran `git diff --check` which reported no immediate style errors.
- Attempted `cargo clippy --all-targets --all-features -- -D warnings`, but it was blocked by a toolchain/build issue (a dependency `libsqlite3-sys` build script uses the unstable `cfg_select` feature) and did not complete.
- Attempted `cargo test`, but it was similarly blocked by the same `libsqlite3-sys` build-script error and did not complete.
2026-07-10 15:54:15 +02:00
Ophir LOJKINE 8b67a06af4 Prevent caching OIDC redirects (#1344)
* Prevent caching of OIDC redirects

* Clarify OIDC cache replay test comments
2026-07-10 14:37:28 +02:00
Ophir LOJKINE 1ab77de705 Make SQLPage function evaluation deterministic
SQLPage functions that are the whole value of a selected column now
execute after the database query, once per returned row. If the query
returns no rows, the function is not called. This ensures deterministic
behavior and prevents expensive or side-effectful operations from
running unnecessarily.
2026-07-08 10:50:39 +02:00
Ophir LOJKINE df306acd82 Emit database query spans as OpenTelemetry clients (#1334)
* Emit database query spans as OTel clients

* Update telemetry example span assertions
2026-06-21 19:52:28 +02:00