Skip to content

Floor division between decimal numerator and integer denominator is wrong #10528

Description

@CaselIT

Describe the bug

Doing a floor division // between a decimal numerator (float / numeric) and an int denominator results in the wrong sql

Optional link from https://docs.sqlalchemy.org which documents the behavior that is expected

No response

SQLAlchemy Version in Use

2.x

DBAPI (i.e. the database driver)

any

Database Vendor and Major Version

pg, any

Python Version

any

Operating system

any

To Reproduce

import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import dialect

pg = dialect()

t = sa.Table(
    "foo",
    sa.MetaData(),
    sa.Column("int_col", sa.Integer()),
    sa.Column("float_col", sa.Float()),
    sa.Column("numeric_col", sa.Numeric()),
    sa.Column("int_col2", sa.Integer()),
    sa.Column("float_col2", sa.Float()),
    sa.Column("numeric_col2", sa.Numeric()),
)


def go(a_name, b_name, inverse):
    a, b = t.c[a_name], t.c[b_name]
    print(f"{a_name} / {b_name}:>", (a / b).compile(dialect=pg).string)
    print(f"{a_name} // {b_name}:>", (a // b).compile(dialect=pg).string)
    if inverse:
        print(f"{b_name} / {a_name}:>", (b / a).compile(dialect=pg).string)
        print(f"{b_name} // {a_name}:>", (b // a).compile(dialect=pg).string)


go("int_col", "int_col2", False)
go("float_col", "float_col2", False)
go("numeric_col", "numeric_col2", False)
go("int_col", "float_col", True)
go("int_col", "numeric_col", True)
go("float_col", "numeric_col", True)

Error

The above code prints

int_col / int_col2:>             foo.int_col / CAST(foo.int_col2 AS NUMERIC)
int_col // int_col2:>            foo.int_col / foo.int_col2
float_col / float_col2:>         foo.float_col / CAST(foo.float_col2 AS FLOAT)
float_col // float_col2:>        FLOOR(foo.float_col / foo.float_col2)
numeric_col / numeric_col2:>     foo.numeric_col / CAST(foo.numeric_col2 AS NUMERIC)
numeric_col // numeric_col2:>    FLOOR(foo.numeric_col / foo.numeric_col2)
int_col / float_col:>            foo.int_col / CAST(foo.float_col AS FLOAT)
int_col // float_col:>           FLOOR(foo.int_col / foo.float_col)
float_col / int_col:>            foo.float_col / CAST(foo.int_col AS NUMERIC)
float_col // int_col:>           foo.float_col / foo.int_col
int_col / numeric_col:>          foo.int_col / CAST(foo.numeric_col AS NUMERIC)
int_col // numeric_col:>         FLOOR(foo.int_col / foo.numeric_col)
numeric_col / int_col:>          foo.numeric_col / CAST(foo.int_col AS NUMERIC)
numeric_col // int_col:>         foo.numeric_col / foo.int_col
float_col / numeric_col:>        foo.float_col / CAST(foo.numeric_col AS NUMERIC)
float_col // numeric_col:>       FLOOR(foo.float_col / foo.numeric_col)
numeric_col / float_col:>        foo.numeric_col / CAST(foo.float_col AS FLOAT)
numeric_col // float_col:>       FLOOR(foo.numeric_col / foo.float_col)

These cases are wrong.

float_col // int_col:>           foo.float_col / foo.int_col
numeric_col // int_col:>         foo.numeric_col / foo.int_col

That code seems to try and detect int denominators and do something different, while it does not do the same for the other datatypes (example float/float gets an unnecessary cast: float_col / float_col2:> foo.float_col / CAST(foo.float_col2 AS FLOAT)) so I think it can probably remove this special logic for the int denominator and do in every case the floor logic

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcode review in progresscode has been provided that's in review as PR and/or gerritdatatypesthings to do with database types, like VARCHAR and othersgreat mcveAn issue with a great mcvesql

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions