TableClause.count() gives the wrong answer

Issue #3724 resolved
Craig Weber created an issue

For tables without a primary key, TableClause.count() surprisingly compiles down to SELECT count(<first-column-in-ColumnCollection>)... instead of SELECT count(*).... As a consequence, the returned result is incorrect by the number of NULLs in the first column in the column collection. This behavior is unexpected, and I couldn't find any documentation on the subject.

Here is the offending code (from https://bitbucket.org/zzzeek/sqlalchemy/src/7189d0bc82598c2d6dcbb55b054837416db2ee7d/lib/sqlalchemy/sql/selectable.py?at=master&fileviewer=file-view-default):

    @util.dependencies("sqlalchemy.sql.functions")
    def count(self, functions, whereclause=None, **params):
        """return a SELECT COUNT generated against this
        :class:`.TableClause`."""

        if self.primary_key:
            col = list(self.primary_key)[0]
        else:
            col = list(self.columns)[0]
        return Select(
            [functions.func.count(col).label('tbl_row_count')],
            whereclause,
            from_obj=[self],
            **params)

Comments (7)

  1. Mike Bayer repo owner

    oh count on core, wow. Don't use that. going to deprecate that right now. there's too many varieties of behavior here and this has to be explicit.

  2. Craig Weber reporter

    I'm not familiar with gerrit, but it looks like this landed in master already? If so, I consider this resolved. Thanks for your prompt action.

  3. Mike Bayer repo owner

    Deprecate FromClause.count() (pending for 1.1)

    count() here is misleading in that it not only counts from an arbitrary column in the table, it also does not make accommodations for DISTINCT, JOIN, etc. as the ORM-level function does. Core should not be attempting to provide a function like this.

    Change-Id: I9916fc51ef744389a92c54660ab08e9695b8afc2 Fixes: #3724

    → <<cset e7ea2a4e198f>>

  4. Mike Bayer repo owner

    Deprecate FromClause.count()

    count() here is misleading in that it not only counts from an arbitrary column in the table, it also does not make accommodations for DISTINCT, JOIN, etc. as the ORM-level function does. Core should not be attempting to provide a function like this.

    Change-Id: I9916fc51ef744389a92c54660ab08e9695b8afc2 Fixes: #3724

    → <<cset f38f89084970>>

  5. Log in to comment