On Feb 27, 2014, at 4:38 PM, Rob Crowell <[email protected]> wrote:

> 
>     # in_ clause with 1 STRING, 1 BINARY
>     filter_cols = tuple_(HashTest.hash_val, HashTest.hash_type)
>     filter_vals = ((encoded_hash, 'md5'),)
> 
>     q = session.query(HashTest)
>     q = q.filter(filter_cols.in_((filter_vals)))
>                                                              ^
> HINT:  No operator matches the given name and argument type(s). You might 
> need to add explicit type casts.
>  'SELECT hashtest.hash_test.hash_val AS hashtest_hash_test_hash_val, 
> hashtest.hash_test.hash_type AS hashtest_hash_test_hash_type, 
> hashtest.hash_test.region AS hashtest_hash_test_region \nFROM 
> hashtest.hash_test \nWHERE (hashtest.hash_test.hash_val, 
> hashtest.hash_test.hash_type) IN ((%(param_1)s, %(param_2)s))' {'param_1': 
> <psycopg2._psycopg.Binary object at 0x2d9d850>, 'param_2': 
> <psycopg2._psycopg.Binary object at 0x2c18940>}
> 
> 
> It's complaining about an improper encoding for the BINARY column.

this has nothing to do with encoding and instead is about typing.   you can see 
in the output that SQLAlchemy is turning both elements of the IN tuple into a 
Binary which would appear to be inappropriate here - the sqlalchemy.sql.Tuple 
object isn’t yet smart enough to handle heterogeneous types.    There’s a patch 
which will resolve this attached to 
https://bitbucket.org/zzzeek/sqlalchemy/issue/2977/tuple_-needs-to-record-heterogeneous-types
 .   

In the meantime you can actually lift and use that Tuple class that’s in the 
patch:

from sqlalchemy.sql.expression import ClauseList, ColumnElement, \
        _literal_as_binds, BindParameter
from sqlalchemy import types

class tuple_(ClauseList, ColumnElement):
    def __init__(self, *clauses, **kw):
        clauses = [_literal_as_binds(c) for c in clauses]
        self.type = types.NULLTYPE
        self._type_tuple = [arg.type for arg in clauses]

        super(tuple_, self).__init__(*clauses, **kw)

    @property
    def _select_iterable(self):
        return (self, )

    def _bind_param(self, operator, obj):
        return tuple_(*[
            BindParameter(None, o, _compared_to_operator=operator,
                             _compared_to_type=type_, unique=True)
            for o, type_ in zip(obj, self._type_tuple)
        ]).self_group()



Attachment: signature.asc
Description: Message signed with OpenPGP using GPGMail

Reply via email to