On May 24, 2008, at 7:00 AM, Michael Bayer wrote:

> On May 24, 2008, at 12:25 AM, Jeff Putsch wrote:
>
>> Now, when I add the filter like this:
>>
>> print NisAccount.query().select_from(a1.join(a2, (a1.c.eid ==
>> a2.c.eid) & (a1.c.uid != a2.c.uid))).filter(a1.c.eid.in_(s3) &
>> (a1.c.domain_id == 41)).compile()
>>
>> I get an infinite recursion error.
>
> 0.5 may very well have the same issue.   try closing in the join using
> an alias, like a.join(a2, ...).select().alias().

Thanks, that seems to do the trick.

Doing the join like this: a.join(a2, ...).select(use_labels=True) also
gets rid of the infinite recursion error.

> send along a script that includes sample versions of the Table's in
> question so I can reproduce the same conditions locally.

I've attached a script that demonstrates the problem.

Jeff.


--~--~---------~--~----~------------~-------~--~----~
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 [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---

from sqlalchemy import *
from sqlalchemy.orm import *

engine = create_engine('sqlite:///:memory:', echo=False)
conn = engine.connect()

metadata = MetaData()

Session = sessionmaker(bind=engine, autoflush=True, transactional=True)
session = Session()

domains_table = Table('domains', metadata,
    Column('id', Integer, primary_key = True),
    Column('name', String(40), nullable = False, unique = True),
    Column('master', String(128), nullable = False),
)

nis_users_table = Table('nis_users', metadata,
    Column('id', Integer, primary_key = True),
    Column('eid', String(32), default=""),
    Column('uid', Integer, nullable = False),
    Column('uname', String(256), nullable = False),
    UniqueConstraint('eid', 'uid', 'uname')
)

nis_accounts_table = Table('nis_accounts', metadata,
    Column('id', Integer, primary_key = True),
    Column('domain_id', Integer, ForeignKey('domains.id')),
    Column('nis_user_id', Integer, nullable = False),
    Column('gid', Integer, default=60001),
    Column('gcos', String(256)),
    Column('shell', String(256)),
    Column('home', String(256)),
    Column('terminated', Boolean, default = False),
    Column('reassigned_uid', Boolean, default = False),
    Column('active', Boolean, default = True),
    UniqueConstraint('domain_id', 'nis_user_id'),
    ForeignKeyConstraint(['nis_user_id'],['nis_users.id'], ondelete="CASCADE")
)

metadata.create_all(engine)

conn.execute(domains_table.insert(), [
    {'id':40, 'name':'dom_40', 'master':'dom_40.example.com'},
    {'id':41, 'name':'dom_41', 'master':'dom_41.example.com'},
    {'id':54, 'name':'dom_54', 'master':'dom_54.example.com'},
    {'id':55, 'name':'dom_55', 'master':'dom_55.example.com'},
])

conn.execute(nis_users_table.insert(), [
	{'id':2308, 'eid':'E14093', 'uid':24093, 'uname':'uname_2308', },
	{'id':2307, 'eid':'E12337', 'uid':12337, 'uname':'uname_2307', },
	{'id':6643, 'eid':'E017783', 'uid':17783, 'uname':'uname_6643', },
	{'id':4677, 'eid':'E017607', 'uid':1405, 'uname':'uname_4677', },
	{'id':4277, 'eid':'E018290', 'uid':14291, 'uname':'uname_4277', },
	{'id':4699, 'eid':'E015679', 'uid':1276, 'uname':'uname_4699', },
	{'id':5250, 'eid':'E015318', 'uid':3144, 'uname':'uname_5250', },
	{'id':4536, 'eid':'E002616', 'uid':692, 'uname':'uname_4536', },
	{'id':7135, 'eid':'E003510', 'uid':43510, 'uname':'uname_7135', },
	{'id':4561, 'eid':'E003657', 'uid':10019, 'uname':'uname_4561', },
	{'id':2309, 'eid':'E14093', 'uid':14093, 'uname':'uname_2309', },
	{'id':2306, 'eid':'E13678', 'uid':23678, 'uname':'uname_2306', },
	{'id':5010, 'eid':'E016126', 'uid':1561, 'uname':'uname_5010', },
	{'id':4508, 'eid':'E018290', 'uid':768, 'uname':'uname_4508', },
	{'id':5075, 'eid':'E016126', 'uid':1322, 'uname':'uname_5075', },
	{'id':4871, 'eid':'E003657', 'uid':936, 'uname':'uname_4871', },
	{'id':2334, 'eid':'E13678', 'uid':13678, 'uname':'uname_2334', },
	{'id':5258, 'eid':'E003510', 'uid':901, 'uname':'uname_5258', },
	{'id':4947, 'eid':'E015679', 'uid':723, 'uname':'uname_4947', },
	{'id':4626, 'eid':'E002616', 'uid':513, 'uname':'uname_4626', },
	{'id':4361, 'eid':'E017783', 'uid':1406, 'uname':'uname_4361', },
	{'id':2289, 'eid':'E12337', 'uid':65037, 'uname':'uname_2289', },
	{'id':4991, 'eid':'E015318', 'uid':1237, 'uname':'uname_4991', },
	{'id':7241, 'eid':'E017607', 'uid':17607, 'uname':'uname_7241', },
]);


conn.execute(nis_accounts_table.insert(), [
	{'id':8259, 'nis_user_id':4561, 'active':1, 'reassigned_uid':'', 'domain_id':41, 'shell':'/bin/csh', 'home':'/home/uname_4561', 'gid':20, 'gcos':'Nis User 8259;E003657', },
	{'id':12395, 'nis_user_id':7241, 'active':1, 'reassigned_uid':'', 'domain_id':40, 'shell':'/bin/csh', 'home':'/home/uname_7241', 'gid':4402, 'gcos':'Nis User 12395;E017607', },
	{'id':8910, 'nis_user_id':5075, 'active':1, 'reassigned_uid':'', 'domain_id':41, 'shell':'/bin/csh', 'home':'/home/uname_5075', 'gid':20, 'gcos':'Nis User 8910;E016126', },
	{'id':4406, 'nis_user_id':2334, 'active':1, 'reassigned_uid':'', 'domain_id':54, 'shell':'/bin/csh', 'home':'/home/uname_2334', 'gid':7600, 'gcos':'Nis User 4406;E13678', },
	{'id':8805, 'nis_user_id':4991, 'active':1, 'reassigned_uid':'', 'domain_id':41, 'shell':'/bin/csh', 'home':'/home/uname_4991', 'gid':20, 'gcos':'Nis User 8805;E015318', },
	{'id':8193, 'nis_user_id':4508, 'active':1, 'reassigned_uid':'', 'domain_id':41, 'shell':'/bin/csh', 'home':'/home/uname_4508', 'gid':20, 'gcos':'Nis User 8193;E018290', },
	{'id':5349, 'nis_user_id':2309, 'active':1, 'reassigned_uid':'', 'domain_id':55, 'shell':'/bin/csh', 'home':'/home/uname_2309', 'gid':7600, 'gcos':'Nis User 5349;E14093', },
	{'id':8004, 'nis_user_id':4361, 'active':1, 'reassigned_uid':'', 'domain_id':41, 'shell':'/bin/csh', 'home':'/home/uname_4361', 'gid':20, 'gcos':'Nis User 8004;E017783', },
	{'id':12273, 'nis_user_id':7135, 'active':1, 'reassigned_uid':'', 'domain_id':40, 'shell':'/bin/csh', 'home':'/home/uname_7135', 'gid':4402, 'gcos':'Nis User 12273;E003510', },
	{'id':4369, 'nis_user_id':2308, 'active':1, 'reassigned_uid':'', 'domain_id':54, 'shell':'/bin/csh', 'home':'/home/uname_2308', 'gid':7600, 'gcos':'Nis User 4369;E14093', },
	{'id':8227, 'nis_user_id':4536, 'active':1, 'reassigned_uid':'', 'domain_id':41, 'shell':'/bin/csh', 'home':'/home/uname_4536', 'gid':20, 'gcos':'Nis User 8227;E002616', },
	{'id':4367, 'nis_user_id':2306, 'active':1, 'reassigned_uid':'', 'domain_id':54, 'shell':'/bin/csh', 'home':'/home/uname_2306', 'gid':7600, 'gcos':'Nis User 4367;E13678', },
	{'id':8411, 'nis_user_id':4677, 'active':1, 'reassigned_uid':'', 'domain_id':41, 'shell':'/bin/csh', 'home':'/home/uname_4677', 'gid':20, 'gcos':'Nis User 8411;E017607', },
	{'id':9117, 'nis_user_id':5250, 'active':1, 'reassigned_uid':'', 'domain_id':41, 'shell':'/bin/csh', 'home':'/home/uname_5250', 'gid':20, 'gcos':'Nis User 9117;E015318', },
	{'id':7899, 'nis_user_id':4277, 'active':1, 'reassigned_uid':'', 'domain_id':41, 'shell':'/bin/csh', 'home':'/home/uname_4277', 'gid':20, 'gcos':'Nis User 7899;E018290', },
	{'id':8441, 'nis_user_id':4699, 'active':1, 'reassigned_uid':'', 'domain_id':41, 'shell':'/bin/csh', 'home':'/home/uname_4699', 'gid':20, 'gcos':'Nis User 8441;E015679', },
	{'id':4368, 'nis_user_id':2307, 'active':1, 'reassigned_uid':'', 'domain_id':54, 'shell':'/bin/csh', 'home':'/home/uname_2307', 'gid':7600, 'gcos':'Nis User 4368;E12337', },
	{'id':8651, 'nis_user_id':4871, 'active':1, 'reassigned_uid':'', 'domain_id':41, 'shell':'/bin/csh', 'home':'/home/uname_4871', 'gid':20, 'gcos':'Nis User 8651;E003657', },
	{'id':8827, 'nis_user_id':5010, 'active':1, 'reassigned_uid':'', 'domain_id':41, 'shell':'/bin/csh', 'home':'/home/uname_5010', 'gid':20, 'gcos':'Nis User 8827;E016126', },
	{'id':8749, 'nis_user_id':4947, 'active':1, 'reassigned_uid':'', 'domain_id':41, 'shell':'/bin/csh', 'home':'/home/uname_4947', 'gid':20, 'gcos':'Nis User 8749;E015679', },
	{'id':9127, 'nis_user_id':5258, 'active':1, 'reassigned_uid':'', 'domain_id':41, 'shell':'/bin/csh', 'home':'/home/uname_5258', 'gid':20, 'gcos':'Nis User 9127;E003510', },
	{'id':8346, 'nis_user_id':4626, 'active':1, 'reassigned_uid':'', 'domain_id':41, 'shell':'/bin/csh', 'home':'/home/uname_4626', 'gid':20, 'gcos':'Nis User 8346;E002616', },
	{'id':11123, 'nis_user_id':2309, 'active':1, 'reassigned_uid':'', 'domain_id':40, 'shell':'/bin/csh', 'home':'/home/uname_2309', 'gid':7600, 'gcos':'Nis User 11123;E14093', },
	{'id':11728, 'nis_user_id':6643, 'active':1, 'reassigned_uid':'', 'domain_id':40, 'shell':'/bin/csh', 'home':'/home/uname_6643', 'gid':4402, 'gcos':'Nis User 11728;E017783', },
	{'id':4370, 'nis_user_id':2309, 'active':1, 'reassigned_uid':'', 'domain_id':54, 'shell':'/bin/csh', 'home':'/home/uname_2309', 'gid':7600, 'gcos':'Nis User 4370;E14093', },
	{'id':4349, 'nis_user_id':2289, 'active':1, 'reassigned_uid':'', 'domain_id':54, 'shell':'/bin/csh', 'home':'/home/uname_2289', 'gid':7600, 'gcos':'Nis User 4349;E12337', },
]);

class Domain(object):
    pass

class NisUser(object):
    pass
    
class NisAccount(object):
    pass
    
mapper(Domain, domains_table,     properties = {
    'accounts':relation(NisAccount, backref='domain'),
});

mapper(NisUser, nis_users_table, properties = {
    'accounts':relation(NisAccount, 
    primaryjoin=nis_users_table.c.id == nis_accounts_table.c.nis_user_id,
    backref='user',
    lazy=False)
});

mapper(NisAccount, nis_accounts_table);

# The target query
# select *
# from
# ( select *
#     from nis_accounts a1 inner join nis_users u1 on (a1.nis_user_id = u1.id)
#     where u1.eid != ''
# ) ndu1
# inner join
# ( select *
#     from nis_accounts a2 inner join nis_users u2 on (a2.nis_user_id = u2.id)
#     where u2.eid != ''
# ) ndu2
# on (ndu1.eid = ndu2.eid and ndu1.uid != ndu2.uid)
# where ndu1.eid in (
#     select eid from nis_users
#     group by eid
#     having count(uid) > 1 and eid != '' and uname not like '%_old'
# ) and ndu1.domain_id = 41

# What would be ideal is selecting two NisAccount objects...
# nisA_1, nisA_2 = session.query(NisAccount).some_query...

print "=== The 'inner selects' ==="
s = select([nis_accounts_table, nis_users_table],
           from_obj=[nis_accounts_table.join(nis_users_table)]).where(
               nis_users_table.c.eid != ''
           )
print s.compile()

a1 = s.correlate(None).alias()
a2 = s.correlate(None).alias()
           
# s2 = select([a1, a2], from_obj=[a1.join(a2, (a1.c.eid == a2.c.eid) & (a1.c.uid != a2.c.uid))])

print "=== The set of nis_users objects that have more than one uid for an eid ==="
s3 = select([nis_users_table.c.eid], group_by = nis_users_table.c.eid,
        having = (func.count(nis_users_table.c.uid) > 1)
        & (nis_users_table.c.eid != '')
        & ~(nis_users_table.c.uname.like('%_old'))
    )

print s3.compile()

# This is close to what is needed, it joins the two inner selects
# and gets the "on" clause right, but the selected set of columns comes
# from a1 (the left part of the join) and we'd really like all the columns
# or the columns from the right side of the join.
# I'm too new to SQLAlchemy to understand what to do about it.
print "=== Join of two inner selects, no labels, generates a warning ==="
print session.query(NisAccount).select_from(a1.join(a2, (a1.c.eid == a2.c.eid) 
    & (a1.c.uid != a2.c.uid))).compile()

print len(session.query(NisAccount).select_from(a1.join(a2, (a1.c.eid == a2.c.eid)
    & (a1.c.uid != a2.c.uid))).all()), "objects returned"

print "=== Join of two inner selects, with labels, no warning ==="
print session.query(NisAccount).select_from(a1.join(a2, (a1.c.eid == a2.c.eid) 
    & (a1.c.uid != a2.c.uid)).select(use_labels=True)).compile()

print len(session.query(NisAccount).select_from(a1.join(a2, (a1.c.eid == a2.c.eid)
    & (a1.c.uid != a2.c.uid)).select(use_labels=True)).all()), "objects returned"

# Now, lets try adding a filter on "s3" ... N.B. this doesn't work
# (we get maximum recursion depth exceeded.
print "=== Max Recursion error ==="
# print session.query(NisAccount).select_from(a1.join(a2, (a1.c.eid == a2.c.eid) 
#      & (a1.c.uid != a2.c.uid))).filter(a1.c.eid.in_(s3) &
#      (a1.c.domain_id == 41)).compile()

print "=== labels get rid of Max Recursion error ==="
print session.query(NisAccount).select_from(a1.join(a2, (a1.c.eid == a2.c.eid) 
     & (a1.c.uid != a2.c.uid)).select(use_labels=True)).filter(a1.c.eid.in_(s3) &
     (a1.c.domain_id == 41)).compile()

print len(session.query(NisAccount).select_from(a1.join(a2, (a1.c.eid == a2.c.eid) 
     & (a1.c.uid != a2.c.uid)).select(use_labels=True)).filter(a1.c.eid.in_(s3) &
     (a1.c.domain_id == 41)).all()), "objects returned"

# So try, closing the join with an alias:
print "=== Query with Alias get rid of Max Recursin error ==="
print session.query(NisAccount).select_from(a1.join(a2, (a1.c.eid == a2.c.eid) 
    & (a1.c.uid != a2.c.uid)).select().alias()).compile()

print len(session.query(NisAccount).select_from(a1.join(a2, (a1.c.eid == a2.c.eid) 
    & (a1.c.uid != a2.c.uid)).select().alias()).all()), "objects returned"
    
# So far, so good.
# Now add the filter...
print "=== Now filter the results with labels ==="
print session.query(NisAccount).select_from(a1.join(a2, (a1.c.eid == a2.c.eid) 
    & (a1.c.uid != a2.c.uid)).select(use_labels=True)).filter(a1.c.eid.in_(s3) &
    (a1.c.domain_id == 41)).compile()

print session.query(NisAccount).select_from(a1.join(a2, (a1.c.eid == a2.c.eid) 
    & (a1.c.uid != a2.c.uid)).select(use_labels=True)).filter(a1.c.eid.in_(s3) &
    (a1.c.domain_id == 41)).all()

print len(session.query(NisAccount).select_from(a1.join(a2, (a1.c.eid == a2.c.eid) 
    & (a1.c.uid != a2.c.uid)).select(use_labels=True)).filter(a1.c.eid.in_(s3) &
    (a1.c.domain_id == 41)).all())

print "=== Now filter the results with alias ==="
print session.query(NisAccount).select_from(a1.join(a2, (a1.c.eid == a2.c.eid) 
    & (a1.c.uid != a2.c.uid)).select().alias()).filter(a1.c.eid.in_(s3) &
    (a1.c.domain_id == 41)).compile()

# And run the query:
print session.query(NisAccount).select_from(a1.join(a2, (a1.c.eid == a2.c.eid) 
    & (a1.c.uid != a2.c.uid)).select().alias()).filter(a1.c.eid.in_(s3) &
    (a1.c.domain_id == 41)).all()

print len(session.query(NisAccount).select_from(a1.join(a2, (a1.c.eid == a2.c.eid) 
    & (a1.c.uid != a2.c.uid)).select().alias()).filter(a1.c.eid.in_(s3) &
    (a1.c.domain_id == 41)).all())
    
# the alias() and the "use_label" both seem to be doing the trick!
#
# We're getting the right number of NisAccount objects back an array of (26 objects)
# Is there any way to get back an array of 26 (NisAccount-a1, NisAccount-a2) objects?
#
# Now the question is how to get the all the columns back out of the select, or if not
# all of the columns, then the columns from a2. I suppose since this is an inner join
# then I could use "a2.c.domain_id == 41" int the filter, it should be the equivalent
# to getting the columsns from "a2" returned.






Reply via email to