Keep Float(asdecimal=True) result conversion with the ibm_db driver; declare DOUBLE as Float - #202
aminghadersohi wants to merge 2 commits into
Conversation
The ibm_db dialect maps Numeric to _IBM_Numeric_ibm_db. Float subclasses Numeric and has no entry of its own, so Float columns are adapted to _IBM_Numeric_ibm_db, whose result processor returns the DBAPI value unchanged when asdecimal is true. Float(asdecimal=True) therefore returns float instead of Decimal. Map Float to itself so SQLAlchemy's Float result handling applies. Signed-off-by: Amin Ghadersohi <amin.ghadersohi@gmail.com>
ibm_db_sa's DOUBLE subclassed Numeric, so reflected DOUBLE columns declared asdecimal=True and python_type Decimal, although DB2 DOUBLE is binary floating point and the ibm_db DBAPI returns float for it. Base DOUBLE on Float (asdecimal=False, python_type float). Returned values do not change; DDL still renders DOUBLE. Signed-off-by: Amin Ghadersohi <amin.ghadersohi@gmail.com>
|
Added a second commit,
Tests: Separately observed on current master and not changed here: |
Problem
Float(asdecimal=True)returnsfloatresults, notDecimal, with theibm_dbdialect:DB2Dialect_ibm_db.colspecsmapsNumericto_IBM_Numeric_ibm_db.FloatsubclassesNumericand has no entry of its own, so SQLAlchemy'sadapt_typeadapts everyFloat(includingREAL,DOUBLE_PRECISIONandFloat(precision=...)) to_IBM_Numeric_ibm_db. That type returns no result processor whenasdecimalis true, so the DBAPI'sfloatpasses through and theasdecimal=Truecontract is broken.Related:
ibm_db_sa.base.DOUBLEsubclassedNumeric, so reflectedDOUBLEcolumns declaredasdecimal=Trueandpython_typeDecimal, although DB2DOUBLEis binary floating point and the DBAPI returnsfloat.Fix
Add
Float: Floatto theibm_dbdialect'scolspecs.adapt_typethen findsFloatfirst in the MRO and keeps the original type, so SQLAlchemy's ownFloat.result_processorapplies.Numeric/DECIMALstill adapt to_IBM_Numeric_ibm_db; nothing else changes. DDL is unaffected (compilation uses the declared type). This is independent of #201 and works with or without it.Second commit (2e6f403):
DOUBLEis now based onFloat(asdecimal=False,python_typefloat). Returned values don't change and DDL still rendersDOUBLE. Compatibility note: theFloatconstructor has noscaleargument, so a caller passingDOUBLE(precision, scale)positionally would need adjusting; nothing in this repository does that.Regression tests
test/test_float.py, same style as the existing tests: connectionless result-processor checks forFloat(asdecimal=True),REAL(asdecimal=True)and defaultFloat(), plus live round trips forFloat(asdecimal=True)andFloat(), comparing values and Python types exactly (no tolerances). ForDOUBLE:test_double_is_float(declaration, compilation and result processing) and a livetest_reflected_double(reflected type isDOUBLE,asdecimalis False,python_typeisfloat, values/types round-trip asfloat).First commit (
Floatcolspec) — same test file, Python, SQLAlchemy, DBAPI and server; onlyibm_db_sa/ibm_db.pydiffers between upstream master7f3866e3a827924055323fd5f10ac40b7a9fb2a7and this patch:The failures are type mismatches (
floatwhereDecimalis expected); the defaultFloat()tests pass before and after, confirming unchanged behaviour there.Second commit (
DOUBLE) — onlyibm_db_sa/base.pydiffering, fulltest/test_float.py: 2 FAIL / 5 PASS before, 7 PASS after. Both failures are the declaration assertions; value assertions pass before and after. The live reflection test passes the current schema explicitly, becausedefault_schema_nameis''on current master (fixed separately in #203).python -m pytest -p sqlalchemy.testing.plugin.pytestplugin --db sqlite -q test/test_float.py::TestFloatResults python -m pytest -p sqlalchemy.testing.plugin.pytestplugin --dburi "$DB2_TEST_URL" -q test/test_float.pyValidation: Python 3.11, SQLAlchemy 2.0.52, ibm-db 3.2.3, pytest 9.1.1, local throwaway DB2 Community Edition 11.5.9.0 container. The connectionless tests also pass on SQLAlchemy 1.4.54 (the live class is skipped there on sqlite). Ruff 0.5.0 check/format on the new test file and
git diff --checkpass. The entire legacy upstream suite was not run.