Here's my program, modified as you suggest. It also creates the table
so you can try it on any instance of Oracle. No joy on the result.
Seems like the set_inputsizes isn't called? How can I tell for
certain?

import sqlalchemy.types as sqltypes
from exceptions import NotImplementedError

class OracleChar(sqltypes.CHAR):
    """Patched OracleChar type to fix padding issue
    
http://groups.google.com/group/sqlalchemy/browse_thread/thread/965287c91b790b68
    """
    def get_col_spec(self):
        return "CHAR(%(length)s)" % {'length' : self.length}

    def get_dbapi_type(self, dbapi):
        raise NotImplementedError('gotcha')
        return dbapi.FIXED_CHAR

from sqlalchemy.databases import oracle
oracle.OracleChar = OracleChar

from sqlalchemy import Table, Column, Integer, MetaData
from sqlalchemy.databases.oracle import OracleChar
from sqlalchemy.sql import select, insert
from sqlalchemy import create_engine

metadata = MetaData()

price_sources = Table('victor_price_sources', metadata,
    Column('pricesource', Integer, primary_key=True),
    Column('desciption', OracleChar(100))
)

dburl = "oracle://user:pas...@servername:1521/dbname"

e = create_engine(dburl, echo=True)
metadata.bind = e
metadata.create_all()
con = e.connect()

ins = price_sources.insert().values(pricesource=1, desciption='EJV')
con.execute(ins)

s = select([price_sources], price_sources.c.desciption=='EJV')
all = con.execute(s).fetchall()
print all

s = select([price_sources])
all = con.execute(s).fetchall()
print all

And the results:

In [1]: import sandbox
2009-10-01 13:24:25,015 INFO sqlalchemy.engine.base.Engine.0x...9ccc
SELECT USER FROM DUAL
2009-10-01 13:24:25,018 INFO sqlalchemy.engine.base.Engine.0x...9ccc
{}
2009-10-01 13:24:25,022 INFO sqlalchemy.engine.base.Engine.0x...9ccc
select table_name from all_tables where table_name=:name and
owner=:schema_name
2009-10-01 13:24:25,022 INFO sqlalchemy.engine.base.Engine.0x...9ccc
{'name': 'VICTOR_PRICE_SOURCES', 'schema_name': 'CDOCOLLAT'}
2009-10-01 13:24:25,027 INFO sqlalchemy.engine.base.Engine.0x...9ccc
CREATE TABLE victor_price_sources (
        pricesource INTEGER NOT NULL,
        desciption CHAR(100),
        PRIMARY KEY (pricesource)
)


2009-10-01 13:24:25,027 INFO sqlalchemy.engine.base.Engine.0x...9ccc
{}
2009-10-01 13:24:25,082 INFO sqlalchemy.engine.base.Engine.0x...9ccc
COMMIT
2009-10-01 13:24:25,084 INFO sqlalchemy.engine.base.Engine.0x...9ccc
INSERT INTO victor_price_sources (pricesource, desciption) VALUES
(:pricesource, :desciption)
2009-10-01 13:24:25,084 INFO sqlalchemy.engine.base.Engine.0x...9ccc
{'pricesource': 1, 'desciption': 'EJV'}
2009-10-01 13:24:25,089 INFO sqlalchemy.engine.base.Engine.0x...9ccc
COMMIT
2009-10-01 13:24:25,092 INFO sqlalchemy.engine.base.Engine.0x...9ccc
SELECT victor_price_sources.pricesource,
victor_price_sources.desciption
FROM victor_price_sources
WHERE victor_price_sources.desciption = :desciption_1
2009-10-01 13:24:25,092 INFO sqlalchemy.engine.base.Engine.0x...9ccc
{'desciption_1': 'EJV'}
[]
2009-10-01 13:24:25,105 INFO sqlalchemy.engine.base.Engine.0x...9ccc
SELECT victor_price_sources.pricesource,
victor_price_sources.desciption
FROM victor_price_sources
2009-10-01 13:24:25,105 INFO sqlalchemy.engine.base.Engine.0x...9ccc
{}
[(1,
'EJV
')]



On Oct 1, 10:10 am, "Michael Bayer" <mike...@zzzcomputing.com> wrote:
> volx wrote:
>
> > Micheal:
>
> > Thanks for your help thus far. Unfortunately I don't think the
> > get_dbapi_type method gets called. From reading your code I see how it
> > should be called from pre_exec -> setinputsizes -> get_dbapi_type but
> > empirical evidence shows otherwise. Here's my little harness:
>
> > import sqlalchemy.types as sqltypes
> > from exceptions import NotImplementedError
>
> > class OracleChar(sqltypes.CHAR):
> >     """Patched OracleChar type to fix padding issue
> >    http://groups.google.com/group/sqlalchemy/browse_thread/thread/965287...
> >     """
> >     def get_col_spec(self):
> >         return "CHAR(%(length)s)" % {'length' : self.length}
>
> >     def get_dbapi_type(self, dbapi):
> >         raise NotImplementedError('gotcha')
> >         return dbapi.FIXED_CHAR
>
> > from sqlalchemy.databases import oracle
> > oracle.OracleChar = OracleChar
>
> > from sqlalchemy.ext.sqlsoup import SqlSoup
>
> > dburl = "oracle://....."
> > soup = SqlSoup(dburl)
> > all = soup.price_sources.filter_by(desciption='EJV').all()
> > print all  # shows empty list, we should not even get here due to
> > exception I raise
>
> > all = soup.price_sources.filter_by
> > (desciption='EJV
> > ').all()
> > print all  # shows record in list
>
> > Returns empty list.
>
> SqlSoup uses table reflection and in this case you'd have to ensure that
> the column in question is assigned the CHAR datatype, which its very
> likely that it's not.    I would start by using a hand-constructed Table
> object and testing the behavior against that using simple select()
> constructs.
>
>
>
> > On Sep 30, 3:44 pm, "Michael Bayer" <mike...@zzzcomputing.com> wrote:
> >> volx wrote:
>
> >> > cx_Oracle actually has thread on that a topic at
> >> >http://sourceforge.net/mailarchive/message.php?msg_id=47BED8B8.3983.0...
>
> >> > It boils down to having to specify a type for input parameter. Is that
> >> > something I could "plug-in" as a decorator or would that need to be
> >> > hacked on SqlAlchemy level?
>
> >> here is the thing.  We call setinputsizes() with oracle.  So perhaps
> >> OracleChar() needs to have dbapi.FIXED_CHAR established as its
> >> get_dbapi_type().   would you care to try monkeypatching this (in 0.5,
> >> the
> >> fix for 0.6 would be different) ?
>
> >> class OracleChar(sqltypes.CHAR):
> >>     def get_col_spec(self):
> >>         return "CHAR(%(length)s)" % {'length' : self.length}
>
> >>     def get_dbapi_type(self, dbapi):
> >>         return dbapi.FIXED_CHAR
>
> >> from sqlalchemy.databases import oracle
> >> oracle.OracleChar = OracleChar
>
> >> > Here's how:
>
> >> > In [70]: query = "select * from price_sources where description
> >> > = :someparam"
> >> > In [71]: cursor.setinputsizes(someparam=cx_Oracle.FIXED_CHAR)
> >> > Out[71]: {'someparam': <cx_Oracle.FIXED_CHAR with value None>}
> >> > In [72]: cursor.execute(query, dict(someparam='EJV')).fetchall()
> >> > Out[72]:
> >> > [(149,
>
> >> > 'EJV
> >> > ')]
>
> >> > Any help would be appreciated.
>
> >> > On Sep 30, 2:36 pm, volx <victor.o...@gmail.com> wrote:
> >> >> I have just now and it looks that this post probably belongs on
> >> >> cx_Oracle mailing list.
>
> >> >> In [47]: cursor.execute("select * from price_sources where desciption
> >> >> = :someparam", dict(someparam='EJV')).fetchall()
> >> >> Out[47]: []
> >> >> In [49]: cursor.execute("select * from price_sources where desciption
> >> >> = :someparam", dict
> >> >> (someparam='EJV
> >> >> ')).fetchall()
> >> >> Out[49]:
> >> >> [(149,
>
> >> >> 'EJV
> >> >> ')]
>
> >> >> On Sep 30, 2:18 pm, Michael Bayer <mike...@zzzcomputing.com> wrote:
>
> >> >> > On Sep 30, 2:07 pm, volx <victor.o...@gmail.com> wrote:
>
> >> >> > > Hello all:
>
> >> >> > > Consider table:
>
> >> >> > > CREATE TABLE PRICE_SOURCES (
> >> >> > >    ID decimal(22) PRIMARY KEY NOT NULL,
> >> >> > >    DESCRIPTION char(100) NOT NULL
> >> >> > > )
>
> >> >> > > and this screen dump from ipython session:
>
> >> >> > > In [28]: import cx_Oracle
> >> >> > > In [29]: from sqlalchemy.ext.sqlsoup import SqlSoup
> >> >> > > In [30]: con = cx_Oracle.connect('myuser/myp...@mydb')
> >> >> > > In [31]: cursor = con.cursor()
> >> >> > > In [32]: cursor.execute("select * from price_sources where
> >> >> description
> >> >> > > = 'EJV'").fetchall()
> >> >> > > Out[32]:
> >> >> > > [(149,
>
> >> >> > > 'EJV
> >> >> > > ')]
>
> >> >> > > Note that the result has padding in the column "description" as
> >> it
> >> >> is
> >> >> > > of type CHAR(100), with is fixed length.
>
> >> >> > > Now, let's do the same in SqlAlchemy.
>
> >> >> > > In [33]: soup = SqlSoup('oracle://myuser:myp...@mydb')
> >> >> > > In [34]: soup.price_sources.filter_by(description='EJV').all()
> >> >> > > Out[34]: []
>
> >> >> > > As you can see it returns zero rows. Only after I pad the
> >> parameter
> >> >> > > for where clause will I get my row back:
>
> >> >> > > In [35]: soup.price_sources.filter_by
> >> >> > > (desciption='EJV
> >> >> > > ').all()
> >> >> > > Out[35]: [MappedPrice_sources(pricesource=Decimal
> >> >> > > ('149'),desciption='EJV
> >> >> > > ')]
>
> >> >> > > The same behavior happens even if I use ORM and regardless
> >> whether
> >> >> the
> >> >> > > column metadata is defined with String, OracleString or CHAR.
>
> >> >> > > I can understand the query result being padded as it is
> >> consistent
> >> >> > > with behavior everywhere but the where clasues must not. It is a
> >> big
> >> >> > > problem if you try to use session.merge() because you have to pad
> >> >> > > contents of object fields otherwise the ORM will insert a
> >> duplicate.
>
> >> >> > > Please help. I hope I am doing something wrong or missing
> >> something.
>
> >> >> > that's a little strange.  have you tried:
>
> >> >> > In [28]: import cx_Oracle
> >> >> > In [30]: con = cx_Oracle.connect('myuser/myp...@mydb')
> >> >> > In [31]: cursor = con.cursor()
> >> >> > In [32]: cursor.execute("select * from price_sources where
> >> description
> >> >> > = :someparam", dict(someparam='EJV')).fetchall()
>
> >> >> > ?
>
> >> >> > since the usage of bind parameters is how it actually runs.  If
> >> same
> >> >> > behavior there then it's a cx_oracle behavior.    you can verify
> >> this
> >> >> > by turning on SQL echoing.  As a workaround you can build yourself
> >> a
> >> >> > TypeDecorator that elongates/truncates incoming strings though that
> >> >> > seems a little inconvenient.
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to