Repository navigation
Conversation
…value search lower() is undefined for numeric/boolean/date columns on strict engines such as PostgreSQL, so searching a filter value dropdown on a non-text column raised an error. Cast non-string expressions to a string before lower(); string columns are unchanged. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #45892 +/- ##
=======================================
Coverage 84.73% 84.73%
=======================================
Files 3069 3069
Lines 205771 205793 +22
Branches 48396 48400 +4
=======================================
+ Hits 174354 174376 +22
Misses 28123 28123
Partials 3294 3294
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
rebenitez1802
left a comment
There was a problem hiding this comment.
Request changes: the approach is right and fixes the 500 on Postgres and Trino, but the cast type has no length, which breaks Oracle (and Db2) on columns that work today. Details and applyable suggestions inline.
| if not isinstance(expr.type, sa.String): | ||
| expr = sa.cast(expr, sa.String) |
There was a problem hiding this comment.
🔴 High — Cast without a length is invalid SQL on Oracle and Db2
sa.cast(expr, sa.String) has no length. Oracle renders it as CAST(n AS VARCHAR2), which fails with ORA-00906: missing left parenthesis. On a real Oracle Free 23, base lower(n) LIKE '%4%' returns the row, and this branch errors for NUMBER, DATE and untyped calculated columns, all of which Oracle converts implicitly on master. Db2 (ibm_db_sa) renders VARCHAR(None). Typed text columns are not affected.
Giving the cast type a length where the dialect needs one fixes it: VARCHAR2(4000 CHAR) on Oracle and NVARCHAR(max) on MSSQL (see the next comment). Every other dialect is unchanged (VARCHAR/CHAR/STRING):
| if not isinstance(expr.type, sa.String): | |
| expr = sa.cast(expr, sa.String) | |
| if not isinstance(expr.type, sa.String): | |
| # A bare VARCHAR is invalid where a length is required (Oracle renders | |
| # VARCHAR2, Db2 VARCHAR(None)); MSSQL needs NVARCHAR to keep characters | |
| # outside the database code page. | |
| cast_type = ( | |
| sa.String() | |
| .with_variant(sa.String(4000), "oracle") | |
| .with_variant(sa.String(32672), "ibm_db_sa") | |
| .with_variant(sa.Unicode(), "mssql") | |
| ) | |
| expr = sa.cast(expr, cast_type) |
| untyped) are cast to a string first. String columns are left untouched. | ||
| """ | ||
| if not isinstance(expr.type, sa.String): | ||
| expr = sa.cast(expr, sa.String) |
There was a problem hiding this comment.
🟡 Medium — MSSQL: untyped calculated columns lose non-codepage characters
Calculated columns usually have no type, so they now get CAST(... AS VARCHAR(max)), which is non-Unicode. On SQL Server 2022 with the default SQL_Latin1_General_CP1_CI_AS collation, CAST(N'Ñandú 東京' AS VARCHAR(max)) returns Ñandú ??. A search for 東京 on a calculated UPPER(nvc) column returns 1 row on master and 0 on this branch. The sa.Unicode() mssql variant in the suggestion above covers it.
| # BigQuery still has no ESCAPE clause for a non-text column. | ||
| bigquery_sql = compile_sql( | ||
| build_like_predicate(sa.column("n", sa.Numeric()), "0"), BigQueryDialect() | ||
| ) | ||
| assert "ESCAPE" not in bigquery_sql |
There was a problem hiding this comment.
🟡 Medium — Tests miss the untyped and dialect-specific cases
This test only compiles for Postgres and BigQuery. Changing the existing test to sa.column("c", sa.String()) hides the change in behavior for untyped columns rather than asserting it, and a "skip untyped columns" mutation still passes every test. With the fix above applied, this version passes and fails again if the fix is reverted:
| # BigQuery still has no ESCAPE clause for a non-text column. | |
| bigquery_sql = compile_sql( | |
| build_like_predicate(sa.column("n", sa.Numeric()), "0"), BigQueryDialect() | |
| ) | |
| assert "ESCAPE" not in bigquery_sql | |
| # Untyped expressions (e.g. calculated columns) are cast as well. | |
| untyped_sql = compile_sql( | |
| build_like_predicate(sa.literal_column("upper(s)"), "a"), postgres | |
| ) | |
| assert "lower(CAST(upper(s) AS VARCHAR))" in untyped_sql | |
| # Dialects that need a length or a unicode type get one. | |
| oracle_sql = compile_sql( | |
| build_like_predicate(sa.column("n", sa.Numeric()), "0"), | |
| sa.dialects.registry.load("oracle")(), | |
| ) | |
| assert "CAST(n AS VARCHAR2(4000 CHAR))" in oracle_sql | |
| mssql_sql = compile_sql( | |
| build_like_predicate(sa.column("n", sa.Numeric()), "0"), | |
| sa.dialects.registry.load("mssql")(), | |
| ) | |
| assert "CAST(n AS NVARCHAR(max))" in mssql_sql | |
| # BigQuery still has no ESCAPE clause for a non-text column. | |
| bigquery_sql = compile_sql( | |
| build_like_predicate(sa.column("n", sa.Numeric()), "0"), BigQueryDialect() | |
| ) | |
| assert "ESCAPE" not in bigquery_sql |
…le, Db2, MSSQL Address review: bare CAST(... AS VARCHAR) is invalid on Oracle/Db2 and non-Unicode on MSSQL. Use dialect variants and extend unit tests. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
✅ Deploy Preview for superset-docs-preview ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
SUMMARY
Searching (
?q=) in a filter value dropdown on a non-text column (e.g. a NUMERIC column on PostgreSQL) returned a 500, because the generated predicate waslower(<numeric col>) LIKE ...andlower()is not defined for non-string types on strict engines.Root cause:
build_like_predicateinsuperset/models/helpers.pyalways didsa.func.lower(expr).contains(...). It is called fromExploreMixin.values_for_column, so any non-string column failed on engines such as PostgreSQL (function lower(numeric) does not exist).Fix: if
expr.typeis not asa.Stringsubtype (numeric, integer, boolean, date, or untyped/NullType), wrap it insa.cast(expr, sa.String)beforelower(). Text columns are untouched, so their generated SQL is unchanged. BigQuery's no-ESCAPEbehaviour is preserved.Tradeoffs
CAST(... AS VARCHAR)string representation. How engines render floats/booleans as strings differs, so matches on those types are engine-dependent.ESCAPEon this same predicate is a known, separate issue and is not addressed here.BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
N/A
TESTING INSTRUCTIONS
pytest tests/unit_tests/models/helpers_test.py -k like_predicateADDITIONAL INFORMATION
🤖 Generated with Claude Code