* 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. * 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. * 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. * docs(changelog): make variable cast entry concise and user-oriented The previous entry described internal CAST(? AS TEXT) generation and load-bearing type affinity details. Rephrase for users: focus on the visible fix (MSSQL nvarchar Unicode mangling) and the general simplification (no unnecessary text cast where the database infers the type). * docs(changelog): add issue references for variable cast fix Fixes: #516 (CONTAINS with MSSQL variable fails due to CAST), #1154 (LIMIT/OFFSET with variables fails on MySQL/MariaDB). See: #1317 (per-database logic still scattered, this is a step toward the SqlDialect abstraction). * 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. * test: make variable fixtures self-contained Remove 'same root cause' and inaccurate GH links that referenced other files. Each fixture now describes its own invariant without assuming reader context from another file. * fix: mssql test escaping and improve changelog - Fix variable_mssql_contains test: avoid nested single quotes in sp_executesql string that caused 'Incorrect syntax near It' on CI. Use parameterised expected value instead of embedding 'It works !' inside the inner N'...' string. - Improve CHANGELOG: one main bullet about removing CAST with subpoints for PostgreSQL/MySQL/DuckDB, SQL Server nvarchar/ CONTAINS/EXEC, MySQL LIMIT/OFFSET, and retained cast on SQLite/ ODBC. Move fixes:/see: to PR description. * Refactor SQL variable cast tests to use typed assertions * clippy * Move database-specific SQL tests into per-database subdirectories Restructure tests so files that only work on a single database engine are organized under `database-specific/<engine>/` instead of using long `_no...` suffixes. Add a dedicated test that runs these files only when the current database matches, and simplify the generic test runner by extracting shared execution logic. * rename mssql variable fixture to match its sp_executesql repro The file reproduces issue #516 (CONTAINS rejects CAST expressions), but the query itself uses sp_executesql, which has the same restriction without needing a full-text index. Rename the fixture to reflect that and add a comment explaining why CONTAINS is not used directly.
1.3 KiB
The sql files in this folder are all tested automatically. They are organized in two subdirectories:
component_rendering/
Files that depend on SQLPage's HTML rendering (components, shells, redirects,
etc.). Every file that does not start with error_ must render a page that
contains the text "It works !" and no occurrence of the word "error" (case
insensitive). error_ files should return a page containing the word "error"
and the rest of the file name. Files may include nosqlite, nomssql,
nopostgres or nomysql in their name to skip incompatible backends.
data/
Files that only validate data-processing functions should live here. They must
return rows with an actual column plus either expected (exact match) or
expected_contains (substring match). Tests in this directory are fetched as
JSON and validated row by row.
data/database-specific/
Files that only work on a single database engine (because they use
engine-specific SQL syntax) live in a subdirectory named after that database
(sqlite, postgres, mysql, mssql, oracle, duckdb, snowflake,
generic). They are run by a separate test, only when the current database
matches. Unlike the other directories, their file names do not need _no...
suffixes to exclude incompatible backends.