Mike,

When using use_ansi=False for Oracle (8) in conjunction with joinedload-ing 
an inline view property, SQLAlchemy-0.8.7 renders an inner join instead of 
an outer join.  This has been fixed in SQLAlchemy-0.9.0, but, as I'm not 
prepared for the migration yet, I was hoping and failing to find the bug 
ticket and hopefully a patch.  Do you know when/where this was fixed and 
whether the fix would be patch'able in 0.7 or at least 0.8?

The attached script runs on 0.9.0+ but the assertion fails on 0.8.7.

The only difference in SQL output is the outer join "(+)":

SELECT products.productid AS products_productid, anon_1.productid AS 
anon_1_productid, anon_1.siteid AS anon_1_siteid, anon_1.qty AS anon_1_qty
FROM products, (SELECT inventory.productid AS productid, inventory.siteid 
AS siteid, sum(inventory.qty) AS qty
FROM inventory GROUP BY inventory.productid, inventory.siteid) anon_1
WHERE anon_1.productid*(+)* = products.productid ORDER BY anon_1.siteid

Interestingly, use-ansi=True correctly renders "LEFT OUTER JOIN" in 0.8.7 
but it fails to render as an outer join with use-ansi=False.

Thanks for you time and exceptional software,
Kent


-- 
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/d/optout.
from sqlalchemy import *
from sqlalchemy.orm import *

eng_url = 'oracle://kent:kent@localhost:1521/xe?use_ansi=False'

engine = create_engine(eng_url, echo=True)
metadata = MetaData(engine)
Session = sessionmaker(bind=engine)


products_table = Table("products", metadata,
    Column("productid", Unicode(255), primary_key=True),
)


inventory_table = Table("inventory", metadata,
    Column("inventoryid", Integer, primary_key=True),

    Column("productid", Unicode(255), ForeignKey('products.productid'), nullable=False),

    Column("siteid", Unicode(255), nullable=False),

    Column("qty", Integer, nullable=False),
)


def repr_attrs(obj, *attrs):
    return '<%s: ' % obj.__class__.__name__ +  \
        ' '.join('{0[%s]}=[{1[%s]}]' % (i,i) for i in range(len(attrs)))\
            .format(attrs, map(obj.__dict__.get, attrs)) + ">"
            
            
class Base(object):
    def __init__(self, session, **attrs):
        self.__dict__.update(attrs)
        session.add(self)


class SiteStockLevel(object):
    def __repr__(self):
        return repr_attrs(self,'productid','siteid','qty')


class Product(Base):
    def __repr__(self):
        return repr_attrs(self,'productid')


class Inventory(Base):
    pass


sitestocklevels_view = select([
        inventory_table.c.productid, 
        inventory_table.c.siteid, 
        func.sum(inventory_table.c.qty).label('qty')],
    group_by=[inventory_table.c.productid, inventory_table.c.siteid]).alias('sitestocklevels')


mapper(Inventory, inventory_table)


mapper(Product, products_table, 
    properties={
            'sitestocklevels': relationship(SiteStockLevel,
                primaryjoin=sitestocklevels_view.c.productid==products_table.c.productid,
                order_by=sitestocklevels_view.c.siteid,
                viewonly=True),
    })
    

mapper(SiteStockLevel, sitestocklevels_view, 
    primary_key=[sitestocklevels_view.c.productid, sitestocklevels_view.c.siteid])
        

metadata.create_all()
try:
    sess = Session()
    Product(sess, productid=u'SKUA')
    Product(sess, productid=u'SKUB')
    sess.commit()
    Inventory(sess, inventoryid=1, productid=u'SKUA', siteid=u'S1', qty=1)
    Inventory(sess, inventoryid=2, productid=u'SKUA', siteid=u'S1', qty=2)
    Inventory(sess, inventoryid=3, productid=u'SKUA', siteid=u'S1', qty=3)
    Inventory(sess, inventoryid=4, productid=u'SKUA', siteid=u'S2', qty=1)
    sess.commit()
    
    allproducts = sess.query(Product).options(joinedload(Product.sitestocklevels)).all()
    
    assert len(allproducts) == 2
     
finally:
    metadata.drop_all()
    

Reply via email to