here's a full proof-of-concept.   see if it works for you and if you can figure 
out where your real app is diverging from the basic idea:

from sqlalchemy import MetaData, Table, Column, String, Integer, create_engine

e = create_engine("sqlite://", echo=True)

m1 = MetaData()
t1 = Table('t1', m1, Column('data', String(50)))
t1.create(e)
e.execute(t1.insert(), data='d1')

import sqlalchemy.types as types
from sqlalchemy.schema import Table
from sqlalchemy import event

class MyStringType(types.TypeDecorator):
    impl = types.String

    def process_bind_param(self, value, dialect):
        if value is not None:
            value = value.encode('utf-8', 'replace')
        return value

@event.listens_for(Table, 'column_reflect')
def listen_for_reflect(inspector, table, column_info):
    if isinstance(column_info['type'], types.String):
        column_info['type'] = MyStringType(column_info['type'].length)

m2 = MetaData()
t2 = Table('t1', m2, autoload=True, autoload_with=e)

e.execute(t2.select().where(t2.c.data == u'd1')).fetchall()




On Oct 1, 2013, at 4:12 AM, Tobias Bell <tobias.b...@gmail.com> wrote:

> 
> 
> Am Montag, 30. September 2013 19:18:01 UTC+2 schrieb Michael Bayer:
> 
> On Sep 30, 2013, at 9:30 AM, Tobias Bell <tobia...@gmail.com> wrote:
> 
>> Hello
>> 
>> I'm currently migrating a rather old application built with SQLAlchemy 0.6 
>> and also an older cx_oracle to use SQLAlchemy 0.8 and cx_oracle 5.1.2.
>> The problem is, all queries with strings send unicode data to cx_oracle an 
>> cx_oracle uses NVARCHAR2 to talk to the database. The table itself has 
>> VARCHAR2 columns
>> and no SYS_OP_C2C() indexes. So full table scans are the result. What can I 
>> do to enforce that cx_oracle doesn't bind with NVARCHAR2?
>> What I tried till now was
>> Forcing unicode conversion on engine leve - sa.create_engine(connect_url, 
>> convert_unicode=True)
>> encoding parameter = param = param.encode('utf8')
>> I found this post, but couldn't use it because all my table definitions are 
>> autoloaded.
>> What would you suggest?
> 
> I've just gone through that thread for review, seems like nothing is really 
> going to change with cx_oracle.  It would be great if they could send a 
> bytestring through on their end, as any application in Python 3 that naively 
> uses cx_oracle directly with VARCHAR columns is going to perform terribly 
> otherwise.    The issue here is essentially using SQLAlchemy to fix a problem 
> that cx_oracle isn't.
> 
> Anyway, the same recommendations about custom types and/or 
> convert_unicode='force' still apply here.  For reflection, use the column 
> reflect event to upgrade types on each column as it is reflected.  
> 
> http://docs.sqlalchemy.org/en/rel_0_8/core/events.html?highlight=column_reflect#sqlalchemy.events.DDLEvents.column_reflect
> 
> from sqlalchemy.schema import Table
> from sqlalchemy import event
> 
> @event.listens_for(Table, 'column_reflect')
> def listen_for_reflect(inspector, table, column_info):
>    if isinstance(column_info['type'], String):
>        column_info['type'] = MyStringType(column_info['type'].length)
> 
> 
> Thanks for the quick answer Michael. I just tried it now
> 
> import sqlalchemy.types as types
> from sqlalchemy.schema import Table
> from sqlalchemy import event
> 
> class MyStringType(types.TypeDecorator): 
>     impl = types.String
> 
>     def process_bind_param(self, value, dialect): 
>         if value is not None: 
>             value = value.encode('utf-8', 'replace')
> 
> event.listens_for(Table, 'column_reflect')
> def listen_for_reflect(inspector, table, column_info):
>    if isinstance(column_info['type'], types.String):
>        column_info['type'] = MyStringType(column_info['type'].length) 
> 
> But it is not working. Is there something wrong with my code? Do you need to 
> see some more code? Here is an example query
> 
> 2013-10-01 10:04:22,171 INFO:SELECT "POSTEINGANG_ADM".pe_process.status AS 
> "POSTEINGANG_ADM_pe_proce_1", "POSTEINGANG_ADM".pe_process.stack_id AS 
> "POSTEINGANG_ADM_pe_proce_2", "POSTEINGANG_ADM".pe_process.process_id AS 
> "POSTEINGANG_ADM_pe_proce_3", "POSTEINGANG_ADM".pe_process.rout_client AS 
> "POSTEINGANG_ADM_pe_proce_4", "POSTEINGANG_ADM".pe_process.rout_category AS 
> "POSTEINGANG_ADM_pe_proce_5", "POSTEINGANG_ADM".pe_process.rout_message AS 
> "POSTEINGANG_ADM_pe_proce_6", "POSTEINGANG_ADM".pe_process.archive_path AS 
> "POSTEINGANG_ADM_pe_proce_7", "POSTEINGANG_ADM".pe_process.fndoc_id AS 
> "POSTEINGANG_ADM_pe_proce_8", "POSTEINGANG_ADM".pe_process.fndoc_class AS 
> "POSTEINGANG_ADM_pe_proce_9", "POSTEINGANG_ADM".pe_process.fndoc_date AS 
> "POSTEINGANG_ADM_pe_proce_a", "POSTEINGANG_ADM".pe_process.scart AS 
> "POSTEINGANG_ADM_pe_proce_b", "POSTEINGANG_ADM".pe_process.host_stack_id AS 
> "POSTEINGANG_ADM_pe_proce_c", "POSTEINGANG_ADM".pe_process.altered_by AS 
> "POSTEINGANG_ADM_pe_proce_d", "POSTEINGANG_ADM".pe_process.retry_at AS 
> "POSTEINGANG_ADM_pe_proce_e", "POSTEINGANG_ADM".pe_process.discard_at AS 
> "POSTEINGANG_ADM_pe_proce_f", "POSTEINGANG_ADM".pe_process.rout_specification 
> AS "POSTEINGANG_ADM_pe_proce_10" 
> FROM "POSTEINGANG_ADM".pe_process 
> WHERE :param_1 = "POSTEINGANG_ADM".pe_process.stack_id
> 2013-10-01 10:04:22,171 INFO:{'param_1': u'skcla0005982302000'}
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to sqlalchemy+unsubscr...@googlegroups.com.
> To post to this group, send email to sqlalchemy@googlegroups.com.
> Visit this group at http://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/groups/opt_out.

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

Reply via email to