On May 15, 2012, at 5:52 AM, FrancescaL wrote:

> 
> Another possibility to get desired result could be use of
> "EMPTY_CLOB()" into insert statements.
> 
> For example:
> stmt = u"INSERT INTO t_tmp_sqla_upgrade (id, text) VALUES (:text_id,
> EMPTY_CLOB())"
> 
> Is there any way, using SqlAlchemy, to define a custom data type (?)
> that behaves exactly like sqlalchemy.types.Text except for the insert/
> update of an empty text (that should be "adjusted" with "EMPTY_CLOB")?
> 
> (Mad question, maybe)

this is a great question, which is that of combining typing information with 
SQL rules to affect the compilation of the statement.   SQLAlchemy doesn't 
support exactly that operation just yet, however - an old ticket 1534 is in 
place for when this feature gets implemented directly.

Here's a recipe that should be able to do it for now:


from sqlalchemy import Text
from sqlalchemy.sql.expression import _BindParamClause
from sqlalchemy.ext.compiler import compiles

class EmptyClobParam(_BindParamClause):
    def __init__(self, value):
        self.value = value
        super(EmptyClobParam, self).__init__(
            key=None, value=value, type_=Text)


@compiles(EmptyClobParam)
def _empt_clob(element, compiler, **kw):
    if element.value == '':
        return "EMPTY_CLOB()"
    else:
        return compiler.visit_bindparam(element)

You need now to use EmptyClobParam explicitly to set this value:

from sqlalchemy import *
m = MetaData()
t1 = Table('t_tmp', m, Column('id', Integer), Column('text', Text))

print t1.insert().values(id=1, text=EmptyClobParam("some value"))
print t1.insert().values(id=1, text=EmptyClobParam(""))


if using the ORM, you can assign EmptyClobParam directly.   One easy way to get 
it automatic is to use @validates, such as below:

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session, validates

Base = declarative_base()

class Foo(Base):
    __tablename__ = 'foo'

    id = Column(Integer, primary_key=True)
    text = Column(Text)

    @validates("text")
    def _set_empty(self, key, value):
        if value == "":
            return EmptyClobParam(value)
        else:
            return value








> 
> Thank you,
> Francesca
> 
> 
> 
> On 14 Mag, 19:26, "Michael Bayer" <[email protected]> wrote:
>> Michael Bayer wrote:
>>> FrancescaL wrote:
>>>> Hi group,
>> 
>>>> I have a question about Oracle CLOBs.
>> 
>>>> I expect to be able to manage all 3 different LOB column states:
>>>> (a) Populated
>>>> (b) Empty
>>>> (c) NULL
>>>> First of all: is it my expectation correct?
>> 
>>> possibly not.  my experience with oracle CLOB is that a "blank" ends up
>>> being a single blank string.
>> 
>> correction, I meant a "single space", that is, a string of length one
>> consisting of " ".
>> 
>> 
>> 
>> 
>> 
>> 
>> 
>> 
>> 
>>> SQLAlchemy doesn't do anything here, data is passed directly from
>>> cx_oracle and back, my advise would be to create a cx_oracle-only test
>>> case (see the docs on cx_oracle's site, I can't copy and paste a URL on
>>> this terminal unfortunately) and email the cx_oracle list if you believe
>>> the DBAPI's direct behavior is erroneous, however this is sort of how it
>>> goes with Oracle and there might not be a workaround.
>> 
>>>> I'm in process of upgrading to SqlAlchemy 0.6.9 and this seems (to me)
>>>> no more possible.
>> 
>>>> Here it is how to build 3 examples (one for each column state).
>> 
>>>> # ------------------------------
>>>> # SQL for manual table creation:
>>>> DROP TABLE t_tmp_sqla_upgrade;
>>>> CREATE TABLE t_tmp_sqla_upgrade (
>>>>  id   NUMBER (20) not null,
>>>>  text CLOB
>>>> );
>> 
>>>> # ------------------------------
>>>> # Python code:
>>>> from sqlalchemy import MetaData, Table, Column, Integer, Text,
>>>> create_engine
>>>> from sqlalchemy.orm import mapper, sessionmaker
>> 
>>>> metadata = MetaData()
>>>> table = Table('t_tmp_sqla_upgrade', metadata,
>>>>        Column('id', Integer, primary_key=True),
>>>>        Column('text', Text())
>>>> )
>> 
>>>> class TmpTableEntity(object):
>>>>        pass
>> 
>>>> mapper(TmpTableEntity, table)
>> 
>>>> kwargs = {}
>>>> kwargs['encoding'] = 'utf-8'
>>>> engine = create_engine(u"oracle+cx_oracle://user:pwd@db", **kwargs)
>>>> Session = sessionmaker(bind=engine, autoflush=False)
>> 
>>>> def createItem(session, text):
>>>>        e = TmpTableEntity()
>>>>        e.id = 1
>>>>        e.text = text
>>>>        session.add(e)
>>>>        session.commit()
>>>>        session.expunge_all()
>>>>        return e
>> 
>>>> def readItem(session, id):
>>>>        return
>>>> session.query(TmpTableEntity).filter(TmpTableEntity.id==id).one()
>> 
>>>> session = Session()
>> 
>>>> # 3 cases (setup and teardown is needed for each case)
>> 
>>>> # Case (a): some text (OK)
>>>> text = u'some plain ascii text'
>>>> item = createItem(session, text)
>>>> rItem = readItem(session, 1)
>>>> assert rItem.text == text
>> 
>>>> # Case (b): empty text (KO)
>>>> text = u''
>>>> item = createItem(session, text)
>>>> rItem = readItem(session, 1)
>>>> assert rItem.text == None
>>>> # But I expect: assert rItem.text == u''
>>>> # since this is a CLOB field and not a VARCHAR2 one.
>> 
>>>> # Case (c): null text (OK)
>>>> text = None
>>>> item = createItem(session, text)
>>>> rItem = readItem(session, 1)
>>>> assert rItem.text == None
>> 
>>>> Thank you for your time,
>>>> Francesca
>> 
>>>> --
>>>> You received this message because you are subscribed to the Google
>>>> Groups
>>>> "sqlalchemy" group.
>>>> To post to this group, send email to [email protected].
>>>> To unsubscribe from this group, send email to
>>>> [email protected].
>>>> For more options, visit this group at
>>>> http://groups.google.com/group/sqlalchemy?hl=en.
>> 
>>> --
>>> You received this message because you are subscribed to the Google Groups
>>> "sqlalchemy" group.
>>> To post to this group, send email to [email protected].
>>> To unsubscribe from this group, send email to
>>> [email protected].
>>> For more options, visit this group at
>>> http://groups.google.com/group/sqlalchemy?hl=en.
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "sqlalchemy" group.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to 
> [email protected].
> For more options, visit this group at 
> http://groups.google.com/group/sqlalchemy?hl=en.
> 

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.

Reply via email to