Skip to content

Fix sql.false()/sql.true() rendering under use_native_boolean=False#656

Open
antonioyanez wants to merge 1 commit into
SAP:mainfrom
antonioyanez:fix/native-boolean-false-int-compare
Open

Fix sql.false()/sql.true() rendering under use_native_boolean=False#656
antonioyanez wants to merge 1 commit into
SAP:mainfrom
antonioyanez:fix/native-boolean-false-int-compare

Conversation

@antonioyanez

Copy link
Copy Markdown

Summary

HANAStatementCompiler.visit_is_true_unary_operator and
visit_is_false_unary_operator unconditionally emit ... = TRUE /
... = FALSE. When the dialect is configured with
use_native_boolean=False, SQLAlchemy's base visit_true/visit_false
render the wrapped element as an INT literal (1/0), so the compiled
WHERE becomes e.g. WHERE 0 = TRUE — which HANA rejects with error
266 "BOOLEAN type is not comparable with INT".

This PR makes both overrides branch on
self.dialect.supports_native_boolean and fall back to an INT compare
in non-native mode. Native-mode behaviour is unchanged: the existing
= TRUE / = FALSE path is preserved, which is why these overrides
exist in the first place (HANA rejects a bare WHERE TRUE /
WHERE FALSE, per the comment above the methods).

Reproducer

from sqlalchemy import literal_column, select, sql
from sqlalchemy_hana.dialect import HANAHDBCLIDialect

dialect = HANAHDBCLIDialect(use_native_boolean=False)
stmt = select(literal_column("id")).where(sql.false())
print(stmt.compile(dialect=dialect))
# Before this PR:  SELECT id FROM DUMMY WHERE 0 = TRUE   <-- HANA error 266
# After this PR:   SELECT id FROM DUMMY WHERE 0 = 1

Before / After

select(literal_column("id")).where(sql.false()) with
use_native_boolean=False:

Before After
Compiled SQL WHERE 0 = TRUE WHERE 0 = 1
HANA response error 266 executes; predicate is always false

Same statement with use_native_boolean=True (unchanged):

Before After
Compiled SQL WHERE false = TRUE WHERE false = TRUE

Test evidence

Added test_sql_unary_boolean_non_native in test/test_sql_compile.py
that instantiates the dialect with use_native_boolean=False and
asserts:

  • where(sql.false()) compiles to WHERE 0 = 1
  • where(sql.true()) compiles to WHERE 1 = 1
  • where(and_(sql.false(), other_clause)) compiles to WHERE 0 = 1
    (SQLAlchemy short-circuits and_(false, ...) to just false, and
    the resulting predicate is safe on HANA)

Verified locally that without this patch the same test asserts
WHERE 0 = TRUE (which reproduces the runtime failure), and with
the patch it asserts the safe INT compare. Existing
test_sql_unary_boolean (native-mode) still passes unchanged.

Motivation

Discovered while running SQLAlchemy against a HANA schema that stores
booleans as INTEGER for legacy reasons (use_native_boolean=False).
Any query construct that produced sql.false() / sql.true() — which
SQLAlchemy emits under a number of internal shortcuts — hit error 266
at execution time, requiring a local workaround. This PR removes the
need for that workaround.

Files changed

  • sqlalchemy_hana/dialect.py — the two-method patch.
  • test/test_sql_compile.py — regression test.
  • CHANGES.rst — 4.6.1 entry under Fixes.

HANAStatementCompiler.visit_is_true_unary_operator and
visit_is_false_unary_operator unconditionally emitted `... = TRUE` /
`... = FALSE`. With use_native_boolean=False, SQLAlchemy's base
visit_true/visit_false renders the wrapped element as an INT literal
(1/0), so a WHERE became e.g. `WHERE 0 = TRUE` — which HANA rejects
with error 266 "BOOLEAN type is not comparable with INT".

Branch on self.dialect.supports_native_boolean and fall back to an INT
compare in non-native mode. Native-mode behaviour is unchanged.
@cla-assistant

cla-assistant Bot commented Jul 2, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@kasium

kasium commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Thanks for the PR. Please have a look at the failing tests and checks

@antonioyanez

Copy link
Copy Markdown
Author

Heads up — CI failed on this PR at the checkout step, before any of the fix code was executed. Every job (matrix tests, pre-commit, coverage) errored with:

Refusing to check out fork pull request code from a pull_request_target workflow. […] set allow-unsafe-pr-checkout: true on the actions/checkout step.

This is actions/checkout@v7 refusing fork-PR checkouts under pull_request_target unless explicitly opted in. It looks like this is the first external-fork PR since actions/checkout was bumped to v7, so the config change likely hadn't surfaced yet.

Since the workflow used for pull_request_target runs comes from the base branch, I can't fix this from my fork. Would you consider one of:

  1. Recommended: add allow-unsafe-pr-checkout: true to the actions/checkout step in .github/workflows/main.yml. The existing testing environment approval gate already provides the human safety check that GitHub's warning is asking for — reviewers approve → checkout runs.
  2. Pin actions/checkout back to v6.

(Switching the trigger to pull_request isn't viable since the tests need secrets.TEST_DBURI, which pull_request can't access.)

Happy to open a follow-up PR against main with the one-line workflow change if that helps — just let me know. Once the workflow is fixed, a re-run of this PR's CI should exercise the actual fix.

@kasium

kasium commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Fix #662

@kasium

kasium commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Fixed, please try again

# SELECT 1 FROM DUMMY WHERE FALSE
# When the dialect is configured with ``use_native_boolean=False`` (schemas
# that store booleans as integer/tinyint), ``sql.true()``/``sql.false()``
# render as ``1``/``0``; comparing those to the boolean literals ``TRUE``/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Within comments, rst formatting (double packticks) are not needed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants