[sqlalchemy] Composite primary key

2007-01-09 Thread exhuma.twn

Hi,

I have to load a table from 2 different data-sources witch each having
3 different primary keys. This is because those 2 datasources are
already exported from 3 databases from an archaic application.

From those 2 datasources I created  - after normalising - 3 new tables.
The main table keeps the 3 primary keys as one composite primary key.
The two other tables have those 3 fields as foreign keys. Now, if I map
those table definitions onto a table with relations, sqlalchemy
complains with the following error:


sqlalchemy.exceptions.ArgumentError: Error determining primary and/or
secondary join for relationship 'bovines' between mappers
'Mapper|Enterprise|entreprises' and 'Mapper|Bovine|bovines'.  You
should specify the 'primaryjoin' (and 'secondaryjoin', if there is an
association table present) keyword arguments to the relation() function
(or for backrefs, by specifying the backref using the backref()
function with keyword arguments) to explicitly specify the join
conditions.  Nested error is Cant determine join between 'entreprises'
and 'bovines'; tables have more than one foreign key constraint
relationship between them.  Please specify the 'onclause' of this join
explicitly.


Ok, so I have to specify the onclause. But how do I do that? For
reference, here is the (non-working) data definition:

t_bovines = Table( 'bovines', metadata,
  Column('id', Integer, primary_key=True),
  Column('entrydate', Integer),
  Column('key1', Integer, ForeignKey('entreprises.key1')),
  Column('key2',  Integer, ForeignKey('entreprises.key2')),
  Column('key3',   String, ForeignKey('entreprises.key3')),
  Column('var',  Integer),
  Column('val',  Integer),
  )

t_entreprises = Table( 'entreprises', metadata,
  Column('key1', Integer, primary_key=True),
  Column('key2', Integer, primary_key=True, default=0),
  Column('key3',  String, primary_key=True),
  Column('lname',   Unicode(30)),
  Column('fname',   Unicode(30)),
  Column('street',  Unicode(30)),
  Column('country', String(1)),
  Column('zip', String(5)),
  Column('locality', Unicode(30)),
  )

t_surfaces = Table( 'surfaces', metadata,
  Column('id', Integer, primary_key=True),
  Column('entrydate', Integer),
  Column('key1', Integer, ForeignKey('entreprises.key1')),
  Column('key2',  Integer, ForeignKey('entreprises.key2')),
  Column('key3',   String, ForeignKey('entreprises.key3')),
  Column('var', Integer),
  Column('val', Integer),
  )

metadata.create_all()

class Bovine(object):
   pass

class Surface(object):
   pass

class Enterprise(object):
   def __repr__(self):
  return [Entreprise %s %s %s] % (self.key1, self.key2,
self.key3)

usermapper = mapper(Bovine, t_bovines)
usermapper = mapper(Surface, t_surfaces)
usermapper = mapper(Enterprise, t_entreprises, properties={
   'bovines': relation(Bovine),
   'surfaces': relation(Surface)
   })


--~--~-~--~~~---~--~~
 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
-~--~~~~--~~--~--~---



[sqlalchemy] Accessing attributes in many to many relations

2007-01-09 Thread dusty128

Hi,
I'd like to know how to implicitly access attributes in many to many
relations. Let's assume the following existing tables:

person_table=Table('person',metadata,
Column('personid',Integer,primary_key=True),
Column('name',String(50))

address_table=Table('address',metadata,
Column('addressid',Integer,primary_key=True),
Column('street',String(50))

r_pers_addr_table=Table('r_pers_addr',metadata,
Column('r_pers_addrid',Integer,primary_key=True),
# Relation attribute that denotes if an address is the primary location
of a person
Column('prim_addr',String(1), default='N'),
Column('personid',Integer,ForeignKey('person.personid'),
Column('adresseid',Integer,ForeignKey('adresse.adresseid'))

Let's assume that the above scenario is not very optimal, as this many
to many relation can be replaced by a one to many relation, where
prim_addr and personid is stuffed into the address_table.
However, currently I have to deal with this data model but in the
future, it will be migrated - of course this migration should not
result in an extensive code-review.

So, what I'd like to have is an object person and address
(instances of classes Person and Address, where I can access/store
attributes like this:

person.name='abc'
person.address[0].street='xyz'
person.address[0].prim_addr='N'

But how would I create a mapper in this case? I could do something like
this:
---
mapper(Person, person_table, properties = dict(
address = relation(Address, secondary=r_pers_addrid_table)))
---
This would allow access like person.address[0].street but not
person.address[0].prim_addr.

The following mappers allows full access:
---
mapper(Person, person_table, properties={
'r_pers_addr':relation(R_pers_addr)
}
)

mapper(R_pers_addr, r_pers_addr_table,
properties={
'address' : relation(Address)})
---
But now I can not directly address the street, e.g. I have to do:
person.r_pers_addr[0].address.street
But I can access the relation attribute:
person.r_pers_addr[0].prim_addr

What I could do is create specific properties in my class Person for
street and prim_addr but that is quite complicated, moreover I have
to adapt my class in case of a data structure migration. Maybe I could
also do the following:
---
mapper(Person, person_table, properties = dict(
address = relation(Address, secondary=r_pers_addrid_table))
mapper(Address, address_table, properties = dict(
r_pers_addr=relation(R_pers_addr))
---
So I could do: person.address[0].street and
person.address[0].r_pers_addr.prim_addr - but once again I cannot do a
person.address[0].prim_addr

My current data model which I have to access, is full of such relation
attributes, moreover this scenario is probably quite common, so
perhaps there's a good solution?

Best Regards,
Hermann


--~--~-~--~~~---~--~~
 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
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Composite primary key

2007-01-09 Thread Jonathan Ellis

Well, you could specify the primaryjoin as described here:
http://www.sqlalchemy.org/docs/adv_datamapping.myt#advdatamapping_properties_customjoin

but I suspect that your existing mapper will Just Work if you switch
to a composite FK, rather than 3 keys on individual columns

t_bovines = Table( 'bovines', metadata,
  Column('id', Integer, primary_key=True),
  Column('entrydate', Integer),
  Column('key1', Integer),
  Column('key2',  Integer),
  Column('key3',   String),
  Column('var',  Integer),
  Column('val',  Integer),
  ForeignKeyConstraint(['key1', 'key2', 'key3'],
['enterprise.key1', 'enterprise.key2', 'enterprise.key3'])
  )

t_entreprises = Table( 'entreprises', metadata,
  Column('key1', Integer),
  Column('key2', Integer),
  Column('key3',  String),
  Column('lname',   Unicode(30)),
  Column('fname',   Unicode(30)),
  Column('street',  Unicode(30)),
  Column('country', String(1)),
  Column('zip', String(5)),
  Column('locality', Unicode(30)),
  PrimaryKeyConstraint('key1', 'key2', 'key3')
  )

# similarly adjust surfaces

On 1/9/07, exhuma.twn [EMAIL PROTECTED] wrote:

 Hi,

 I have to load a table from 2 different data-sources witch each having
 3 different primary keys. This is because those 2 datasources are
 already exported from 3 databases from an archaic application.

 From those 2 datasources I created  - after normalising - 3 new tables.
 The main table keeps the 3 primary keys as one composite primary key.
 The two other tables have those 3 fields as foreign keys. Now, if I map
 those table definitions onto a table with relations, sqlalchemy
 complains with the following error:

 
 sqlalchemy.exceptions.ArgumentError: Error determining primary and/or
 secondary join for relationship 'bovines' between mappers
 'Mapper|Enterprise|entreprises' and 'Mapper|Bovine|bovines'.  You
 should specify the 'primaryjoin' (and 'secondaryjoin', if there is an
 association table present) keyword arguments to the relation() function
 (or for backrefs, by specifying the backref using the backref()
 function with keyword arguments) to explicitly specify the join
 conditions.  Nested error is Cant determine join between 'entreprises'
 and 'bovines'; tables have more than one foreign key constraint
 relationship between them.  Please specify the 'onclause' of this join
 explicitly.
 

 Ok, so I have to specify the onclause. But how do I do that? For
 reference, here is the (non-working) data definition:

 t_bovines = Table( 'bovines', metadata,
   Column('id', Integer, primary_key=True),
   Column('entrydate', Integer),
   Column('key1', Integer, ForeignKey('entreprises.key1')),
   Column('key2',  Integer, ForeignKey('entreprises.key2')),
   Column('key3',   String, ForeignKey('entreprises.key3')),
   Column('var',  Integer),
   Column('val',  Integer),
   )

 t_entreprises = Table( 'entreprises', metadata,
   Column('key1', Integer, primary_key=True),
   Column('key2', Integer, primary_key=True, default=0),
   Column('key3',  String, primary_key=True),
   Column('lname',   Unicode(30)),
   Column('fname',   Unicode(30)),
   Column('street',  Unicode(30)),
   Column('country', String(1)),
   Column('zip', String(5)),
   Column('locality', Unicode(30)),
   )

 t_surfaces = Table( 'surfaces', metadata,
   Column('id', Integer, primary_key=True),
   Column('entrydate', Integer),
   Column('key1', Integer, ForeignKey('entreprises.key1')),
   Column('key2',  Integer, ForeignKey('entreprises.key2')),
   Column('key3',   String, ForeignKey('entreprises.key3')),
   Column('var', Integer),
   Column('val', Integer),
   )

 metadata.create_all()

 class Bovine(object):
pass

 class Surface(object):
pass

 class Enterprise(object):
def __repr__(self):
   return [Entreprise %s %s %s] % (self.key1, self.key2,
 self.key3)

 usermapper = mapper(Bovine, t_bovines)
 usermapper = mapper(Surface, t_surfaces)
 usermapper = mapper(Enterprise, t_entreprises, properties={
'bovines': relation(Bovine),
'surfaces': relation(Surface)
})


 


--~--~-~--~~~---~--~~
 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
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Composite primary key

2007-01-09 Thread exhuma.twn


Jonathan Ellis wrote:
 Well, you could specify the primaryjoin as described here:
 http://www.sqlalchemy.org/docs/adv_datamapping.myt#advdatamapping_properties_customjoin

 but I suspect that your existing mapper will Just Work if you switch
 to a composite FK, rather than 3 keys on individual columns

 t_bovines = Table( 'bovines', metadata,
   Column('id', Integer, primary_key=True),
   Column('entrydate', Integer),
   Column('key1', Integer),
   Column('key2',  Integer),
   Column('key3',   String),
   Column('var',  Integer),
   Column('val',  Integer),
   ForeignKeyConstraint(['key1', 'key2', 'key3'],
 ['enterprise.key1', 'enterprise.key2', 'enterprise.key3'])
   )

 t_entreprises = Table( 'entreprises', metadata,
   Column('key1', Integer),
   Column('key2', Integer),
   Column('key3',  String),
   Column('lname',   Unicode(30)),
   Column('fname',   Unicode(30)),
   Column('street',  Unicode(30)),
   Column('country', String(1)),
   Column('zip', String(5)),
   Column('locality', Unicode(30)),
   PrimaryKeyConstraint('key1', 'key2', 'key3')
   )

 # similarly adjust surfaces

 On 1/9/07, exhuma.twn [EMAIL PROTECTED] wrote:
 
  Hi,
 
  I have to load a table from 2 different data-sources witch each having
  3 different primary keys. This is because those 2 datasources are
  already exported from 3 databases from an archaic application.
 
  From those 2 datasources I created  - after normalising - 3 new tables.
  The main table keeps the 3 primary keys as one composite primary key.
  The two other tables have those 3 fields as foreign keys. Now, if I map
  those table definitions onto a table with relations, sqlalchemy
  complains with the following error:
 
  
  sqlalchemy.exceptions.ArgumentError: Error determining primary and/or
  secondary join for relationship 'bovines' between mappers
  'Mapper|Enterprise|entreprises' and 'Mapper|Bovine|bovines'.  You
  should specify the 'primaryjoin' (and 'secondaryjoin', if there is an
  association table present) keyword arguments to the relation() function
  (or for backrefs, by specifying the backref using the backref()
  function with keyword arguments) to explicitly specify the join
  conditions.  Nested error is Cant determine join between 'entreprises'
  and 'bovines'; tables have more than one foreign key constraint
  relationship between them.  Please specify the 'onclause' of this join
  explicitly.
  
 
  Ok, so I have to specify the onclause. But how do I do that? For
  reference, here is the (non-working) data definition:
 
  t_bovines = Table( 'bovines', metadata,
Column('id', Integer, primary_key=True),
Column('entrydate', Integer),
Column('key1', Integer, ForeignKey('entreprises.key1')),
Column('key2',  Integer, ForeignKey('entreprises.key2')),
Column('key3',   String, ForeignKey('entreprises.key3')),
Column('var',  Integer),
Column('val',  Integer),
)
 
  t_entreprises = Table( 'entreprises', metadata,
Column('key1', Integer, primary_key=True),
Column('key2', Integer, primary_key=True, default=0),
Column('key3',  String, primary_key=True),
Column('lname',   Unicode(30)),
Column('fname',   Unicode(30)),
Column('street',  Unicode(30)),
Column('country', String(1)),
Column('zip', String(5)),
Column('locality', Unicode(30)),
)
 
  t_surfaces = Table( 'surfaces', metadata,
Column('id', Integer, primary_key=True),
Column('entrydate', Integer),
Column('key1', Integer, ForeignKey('entreprises.key1')),
Column('key2',  Integer, ForeignKey('entreprises.key2')),
Column('key3',   String, ForeignKey('entreprises.key3')),
Column('var', Integer),
Column('val', Integer),
)
 
  metadata.create_all()
 
  class Bovine(object):
 pass
 
  class Surface(object):
 pass
 
  class Enterprise(object):
 def __repr__(self):
return [Entreprise %s %s %s] % (self.key1, self.key2,
  self.key3)
 
  usermapper = mapper(Bovine, t_bovines)
  usermapper = mapper(Surface, t_surfaces)
  usermapper = mapper(Enterprise, t_entreprises, properties={
 'bovines': relation(Bovine),
 'surfaces': relation(Surface)
 })
 
 
  
 

Magical! This worked :)

Thanks a lot


--~--~-~--~~~---~--~~
 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
-~--~~~~--~~--~--~---



[sqlalchemy] Re: [Sqlalchemy-users] named cursor

2007-01-09 Thread Michael Bayer


On Jan 9, 2007, at 5:24 AM, Michele Petrazzo wrote:
 Because, like what I wrote on the psycopg2 ml (lists.initd.org/ 
 pipermail/psycopg/2007-January/005250.html)
 without the server side cursor, the memory usage on the client  
 side is proportionally at the number of records returned by the  
 query (on my example 400k records, 60MB ram). I think because the  
 driver fetch all the data from the server and leave it available  
 with the fetchXXX methods.

really ?  im not sure about psycopg2 specifically, but its been my  
experience with virtually all database client libraries that as you  
fetch rows and discard them, you only pull as much as you fetch into  
memory.  i.e. if you had a resultset of 4000 rows and just fetched 5  
rows, only 5 rows get pulled over the wire.  thats definitely how the  
lower level APIs work and it would be pretty bad if psycopg2 didnt  
maintain that behavior.




--~--~-~--~~~---~--~~
 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
-~--~~~~--~~--~--~---



[sqlalchemy] Oracle autoload problem?

2007-01-09 Thread Sean Davis
I am experimenting with autoloading tables from Oracle (9.2) running on a
remote machine.  Normal selects using cx_Oracle work just fine.  Here is
what I get:

 from sqlalchemy import *
 eng = create_engine('oracle:// ...')
 md = BoundMetaData(eng)
 g2r = Table('gene2refseq',md,autoload=True)
Traceback (most recent call last):
  File stdin, line 1, in module
  File build/bdist.linux-x86_64/egg/sqlalchemy/schema.py, line 143, in
__call__
  File build/bdist.linux-x86_64/egg/sqlalchemy/engine/base.py, line 505,
in reflecttable
  File build/bdist.linux-x86_64/egg/sqlalchemy/databases/oracle.py, line
214, in reflecttable
  File build/bdist.linux-x86_64/egg/sqlalchemy/engine/base.py, line 255,
in execute
  File build/bdist.linux-x86_64/egg/sqlalchemy/engine/base.py, line 259,
in execute_text
  File build/bdist.linux-x86_64/egg/sqlalchemy/engine/base.py, line 329,
in _execute_raw
  File build/bdist.linux-x86_64/egg/sqlalchemy/engine/base.py, line 348,
in _execute
sqlalchemy.exceptions.SQLError: (DatabaseError) ORA-01008: not all variables
bound
 'select distinct OWNER from ALL_TAB_COLUMNS where TABLE_NAME = :table_name'
{'table_name': 'GENE2REFSEQ'}


Any thoughts?

Thanks,
Sean


--~--~-~--~~~---~--~~
 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
-~--~~~~--~~--~--~---


[sqlalchemy] Re: [Sqlalchemy-users] named cursor

2007-01-09 Thread Michele Petrazzo

Michael Bayer wrote:
 
 On Jan 9, 2007, at 5:24 AM, Michele Petrazzo wrote:
 Because, like what I wrote on the psycopg2 ml (lists.initd.org/ 
 pipermail/psycopg/2007-January/005250.html)
 without the server side cursor, the memory usage on the client  
 side is proportionally at the number of records returned by the  
 query (on my example 400k records, 60MB ram). I think because the  
 driver fetch all the data from the server and leave it available  
 with the fetchXXX methods.
 
 really ? im not sure about psycopg2 specifically, 

Here, sure! Assuming the I'm on linux and I have ps utility locally.
The db are on the same machine where I'm making tests. PG are 8.1.5 and
psycopg2 2.0.4.

This is my test:

-code-
import time
import subprocess as SP
import psycopg2

NAMED_CURSOR = 1

def get_mem():
   #Wait for the memory stabilization
   time.sleep(0.5)

   #get the memory usage with ps.
   output = SP.Popen([ps,-eo,rss,args], 
stdout=SP.PIPE).communicate()[0]
   for line in output.split('\n'):
 if not line: continue
 mem, pr_name = line.split(None,1)
 #show only the my python exe
 if not python  + __file__ in pr_name: continue
 return mem

def create_cur():
   if NAMED_CURSOR:
 return con.cursor(test)
   else:
 return con.cursor()

def exec_q(q):
   cur = create_cur()
   print empty cursor , get_mem()
   cur.execute(q)
   print cursor after execute , get_mem()
   print result --, cur.fetchone()
   print after fetchone , get_mem()
   cur.close()
   print cursor closed , get_mem()

print python and modules , get_mem()

con = psycopg2.connect('user=test password=test dbname=book')
print connection , get_mem()

exec_q(SELECT COUNT(id) FROM book)

exec_q(SELECT * FROM book)


/-code-

## with NAMED_CURSOR = 1

michele:~/tmp$ time python test_sql_mem.py
python and modules  3928
connection  4048
empty cursor  4068
cursor after execute  4080
result -- (406500L,)
after fetchone  4088
cursor closed  4092
empty cursor  4092
cursor after execute  4092
result -- (6087, 'title', 15, '18', 'Sonzogno', 508126)
after fetchone  4092
cursor closed  4092

real0m6.107s
user0m0.080s
sys 0m0.076s
michele:~/tmp$

## with NAMED_CURSOR = 0

michele:~/tmp$ time python test_sql_mem.py
python and modules  3932
connection  4048
empty cursor  4068
cursor after execute  4080
result -- (406500L,)
after fetchone  4092
cursor closed  4092
empty cursor  4092
cursor after execute  58440
result -- (6087, 'title', 15, '18', 'Sonzogno', 508126)
after fetchone  58452
cursor closed  58452

real0m11.499s
user0m0.544s
sys 0m0.176s
michele:~/tmp$

 but its been my  
 experience with virtually all database client libraries that as you  
 fetch rows and discard them, you only pull as much as you fetch into  
 memory.  i.e. if you had a resultset of 4000 rows and just fetched 5  
 rows, only 5 rows get pulled over the wire.  thats definitely how the  
 lower level APIs work 


I'm with you, but my code show other results

 and it would be pretty bad if psycopg2 didnt maintain that behavior.

I'll send another email to the psycopg2 ml, with this results, and I'll 
reply you in the near future.

Michele

--~--~-~--~~~---~--~~
 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
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Oracle autoload problem?

2007-01-09 Thread Michael Bayer

thats really weird, since you can see the SQL + bind params right  
there and they are all bound.  We have made some changes to Oracle  
reflection recently but the unit tests were passing on my linux box,  
as well as on the machine of the person who contributed the changes.

so i would ask can you reflect any tables from that database ?  can  
you make a small test table with a very simple layout and reflect  
that ?  does general SQL operation through SQLAlchemy work with this  
database ?  (i.e. dont use reflection, but try out some generated  
queries?)  do you have any other oracle databases which you can try  
reflecting from ?


On Jan 9, 2007, at 2:08 PM, Sean Davis wrote:

 I am experimenting with autoloading tables from Oracle (9.2)  
 running on a remote machine.  Normal selects using cx_Oracle work  
 just fine.  Here is what I get:

  from sqlalchemy import *
  eng = create_engine('oracle:// ...')
  md = BoundMetaData(eng)
  g2r = Table('gene2refseq',md,autoload=True)
 Traceback (most recent call last):
   File stdin, line 1, in module
   File build/bdist.linux-x86_64/egg/sqlalchemy/schema.py, line  
 143, in __call__
   File build/bdist.linux-x86_64/egg/sqlalchemy/engine/base.py,  
 line 505, in reflecttable
   File build/bdist.linux-x86_64/egg/sqlalchemy/databases/ 
 oracle.py, line 214, in reflecttable
   File build/bdist.linux-x86_64/egg/sqlalchemy/engine/base.py,  
 line 255, in execute
   File build/bdist.linux-x86_64/egg/sqlalchemy/engine/base.py,  
 line 259, in execute_text
   File build/bdist.linux-x86_64/egg/sqlalchemy/engine/base.py,  
 line 329, in _execute_raw
   File build/bdist.linux-x86_64/egg/sqlalchemy/engine/base.py,  
 line 348, in _execute
 sqlalchemy.exceptions.SQLError: (DatabaseError) ORA-01008: not all  
 variables bound
  'select distinct OWNER from ALL_TAB_COLUMNS where TABLE_NAME  
 = :table_name' {'table_name': 'GENE2REFSEQ'}


 Any thoughts?

 Thanks,
 Sean


 


--~--~-~--~~~---~--~~
 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
-~--~~~~--~~--~--~---



[sqlalchemy] Re: [Sqlalchemy-users] named cursor

2007-01-09 Thread Michael Bayer

OK well this is all quite disturbing !

I would want to examine this more closely.  but, lets assume this is  
really how it is,  since thats how it looks (eesh).

So, you dont really want to use named cursors, you just want psycopg2  
to use cursors in its underlying operations so that it has more  
efficient operation...and the magical incantation you send to  
psycopg2 in order for it to use cursors is conn.cursor(x) as  
opposed to conn.cursor() (which to me is like, totally arbitrary..and  
at this point i am getting pretty annoyed with how utterly  
undocumented psycopg2 is...but then again so is MySQLDB).  so this is  
total artifact-land, and it has no implication for SA to grow some  
new fine-grained cursor-based API, we are here just looking for a  
hack workaround internally.

My first instinct is to say, ok, then we just use the call  
conn.cursor('x') to get cursors when using the postgres dialect.   
however, im told that this probably wont work for CRUD (i.e. insert,  
update etc) operations, so we would have to keep that in mind (SA  
does scan incoming SQL for INSERT/UPDATE etc so thats not an issue).   
also, is conn.cursor(x) more efficient in all cases ?  or is the  
overhead of creating a cursor significant, and only worthwhile when  
you know you are going to fetch only a subset of rows from an  
enormous result set ?

so my second instinct is to perhaps go with the approach of using  
conn.cursor(x) for all SELECT statements when using the postgres  
dialect, *if* you tell the dialect you want to use that.  im thinking  
a flag use_named_cursors=True when you create_engine().  Id really  
rather not pollute the connect()/Connection/execute() API with this  
concept if at all possible...i was initially thinking of doing  
something like, conn.with_cursor(mycursor).execute(), but thats  
pretty explicit for something that should really be an internal  
optimization.

thats my thoughts so far.  just FYI if you want to hack your SA to  
use named cursors in all cases, its line 282 and 322 of lib/ 
sqlalchemy/engine/base.py .


On Jan 9, 2007, at 11:40 AM, Michele Petrazzo wrote:


 Michael Bayer wrote:

 On Jan 9, 2007, at 5:24 AM, Michele Petrazzo wrote:
 Because, like what I wrote on the psycopg2 ml (lists.initd.org/
 pipermail/psycopg/2007-January/005250.html)
 without the server side cursor, the memory usage on the client
 side is proportionally at the number of records returned by the
 query (on my example 400k records, 60MB ram). I think because the
 driver fetch all the data from the server and leave it available
 with the fetchXXX methods.

 really ? im not sure about psycopg2 specifically,

 Here, sure! Assuming the I'm on linux and I have ps utility locally.
 The db are on the same machine where I'm making tests. PG are 8.1.5  
 and
 psycopg2 2.0.4.

 This is my test:

 -code-
 import time
 import subprocess as SP
 import psycopg2

 NAMED_CURSOR = 1

 def get_mem():
#Wait for the memory stabilization
time.sleep(0.5)

#get the memory usage with ps.
output = SP.Popen([ps,-eo,rss,args],
 stdout=SP.PIPE).communicate()[0]
for line in output.split('\n'):
  if not line: continue
  mem, pr_name = line.split(None,1)
  #show only the my python exe
  if not python  + __file__ in pr_name: continue
  return mem

 def create_cur():
if NAMED_CURSOR:
  return con.cursor(test)
else:
  return con.cursor()

 def exec_q(q):
cur = create_cur()
print empty cursor , get_mem()
cur.execute(q)
print cursor after execute , get_mem()
print result --, cur.fetchone()
print after fetchone , get_mem()
cur.close()
print cursor closed , get_mem()

 print python and modules , get_mem()

 con = psycopg2.connect('user=test password=test dbname=book')
 print connection , get_mem()

 exec_q(SELECT COUNT(id) FROM book)

 exec_q(SELECT * FROM book)


 /-code-

 ## with NAMED_CURSOR = 1

 michele:~/tmp$ time python test_sql_mem.py
 python and modules  3928
 connection  4048
 empty cursor  4068
 cursor after execute  4080
 result -- (406500L,)
 after fetchone  4088
 cursor closed  4092
 empty cursor  4092
 cursor after execute  4092
 result -- (6087, 'title', 15, '18', 'Sonzogno', 508126)
 after fetchone  4092
 cursor closed  4092

 real0m6.107s
 user0m0.080s
 sys 0m0.076s
 michele:~/tmp$

 ## with NAMED_CURSOR = 0

 michele:~/tmp$ time python test_sql_mem.py
 python and modules  3932
 connection  4048
 empty cursor  4068
 cursor after execute  4080
 result -- (406500L,)
 after fetchone  4092
 cursor closed  4092
 empty cursor  4092
 cursor after execute  58440
 result -- (6087, 'title', 15, '18', 'Sonzogno', 508126)
 after fetchone  58452
 cursor closed  58452

 real0m11.499s
 user0m0.544s
 sys 0m0.176s
 michele:~/tmp$

 but its been my
 experience with virtually all database client libraries that as you
 fetch rows and discard them, you only pull as much as you fetch into
 memory.  i.e. if you had a 

[sqlalchemy] customize table creation

2007-01-09 Thread Daniel Haus

Hi alchemists!

Is there any way to have SA do some custom work before it creates a
table? I tried to subclass Table and override create, which
obviously doesn't work that easily. Any suggestions or ideas?

The background is, I have some objects that dynamically add columns to
the table on demand, which seems to work fine. Now, I need to ensure
that these objects can do their work on table creation. And doing it
manually would be painful...

Thanks in advance
Daniel


--~--~-~--~~~---~--~~
 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
-~--~~~~--~~--~--~---



[sqlalchemy] Re: customize table creation

2007-01-09 Thread Jonathan Ellis

On 1/9/07, Daniel Haus [EMAIL PROTECTED] wrote:

 Hi alchemists!

 Is there any way to have SA do some custom work before it creates a
 table? I tried to subclass Table and override create, which
 obviously doesn't work that easily. Any suggestions or ideas?

 The background is, I have some objects that dynamically add columns to
 the table on demand, which seems to work fine. Now, I need to ensure
 that these objects can do their work on table creation. And doing it
 manually would be painful...

You're trying to dynamically add columns to the table in the database,
or just to the Table instance?

--~--~-~--~~~---~--~~
 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
-~--~~~~--~~--~--~---



[sqlalchemy] MSSQL session.flush() doesn't always fetch primary keys

2007-01-09 Thread Paul Johnston

Hi,

Using MSSQL, session.flush() doesn't always fetch primary keys back from 
the database. It works if you explicity specify a sequence, but if the 
sequence is implicitly created it doesn't fetch. I have raised ticket 
#415 for this issue.

In MSSQLExecutionContext, it looks to see if any column has a sequence, 
and if so issues select @@identity afterwards. A couple of simple 
solutions to this:
1) Always issue select @@identity (quick tests show this should be safe)
2) Copy the code from MSSQLSchemaGenerator that determines whether to 
create an implicit sequence, and run it for each query.
Thing is, I'm a bit worried about the performance of both those options.

I'm wondering why the decision to give a column an implicit sequence is 
in the database engine code. The fix that seems logical to me is to put 
the code to create an implicit sequence in Column.__init__. It's down to 
the individual engines how they implement this sequence, but its 
existence or not is engine independent.

Let me know what you think,

Paul

--~--~-~--~~~---~--~~
 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
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Oracle autoload problem?

2007-01-09 Thread Sean Davis
On 1/9/07, Andrija Zarić [EMAIL PROTECTED] wrote:


 This very strange, because SQLAlchemy is issuing the query like it is
 supposed to do. There is bind variable (table_name) but for some
 reason cx_Oracle/Oracle is raising ORA-1008.

 Can you assert that following is working:
  import cx_Oracle as ora
  e = ora.connect('...')
  c = e.cursor()
  c.execute(select distinct OWNER from ALL_TAB_COLUMNS where
 TABLE_NAME = :table_name,{'table_name':'GENE2REFSEQ'})
  c.fetchall()


 I'm using autoload feature with Oracle 8.1.7 and 10XE, both tables
 with unique name and same name with multiple owners without any
 problems. SQLAlchemy is from svn trunk and cx_Oracle is 4.1


cx_Oracle indeed looks to be the issue.  I'll sort it out in more detail,
but bound parameters are not working for me in any queries I have tried.  It
works otherwise, but not with bind params.

Sean

--~--~-~--~~~---~--~~
 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
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Accessing attributes in many to many relations

2007-01-09 Thread Hermann Himmelbauer

Am Dienstag, 9. Januar 2007 17:01 schrieb Michael Bayer:
 we do have an extension called associationproxy that is used for
 something similar with association objects...it may give you some
 ideas on how to proxy attributes across.   i dont think you should
 approach the idea of adding individual properties as quite
 complicated...for example, you could write a function that adds all
 the Address properties to the Person class en-masse:

   for key in class_mapper(Address).props:
   setattr(Person, key, property(...some getter function...))

 if you come up with something generally useful in that idiom, you can
 post to the SA wiki or we can even make another extension if its
 really of general use.

At first, thanks for your quick answer.

My basic idea was to maintain the abstraction between the data model and the 
actual object. So the ideal place to specify such things would be in the 
mapper. To my mind, some magic with the properties could do it, e.g. like 
this:

mapper(Person, person_table, properties = dict(
  address=relation(Address, secondary=r_pers_addrid_table,
 proxy_relation_attributes=True))

In case proxy_relation_attributes is set to True, all columns (except the 
foreign keys which are obsolete) are made accessible through the relation - 
very simple syntax.

Correct me if I'm wrong, but many to many relations are normally done this 
way:

table1  ---  association_table  --- table2

table1 has a one to many relation to association_table and table2 has also a 
one to many relation to association_table. From the perpective of table1, it 
should therefore in any case be  possible to locate association/relation  
attributes along with the attributes of table2 (and the same in the other 
direction). The only problem could be name clashes, which could probably be 
handled in some way (e.g. raise an exception or prefix them).

This may also obsolete the associationproxy - but maybe I don't fully 
understand its concepts.

This solution would make it possible to alter the data model, e.g. make a one 
to many relation from a many to many relation, e.g.:

table1 -  table2

without having to touch the object representing the function - the only thing 
I'd have to change is the mapper.

I have no clue how I would implement such a relation property as I'm very new 
to SA, perhaps it's impossible for some reason. However, I think putting 
attributes in association tables is a common pattern in data models, so this 
could be of use for many SA users.

What do you think of this idea?

Best Regards,
Hermann

-- 
[EMAIL PROTECTED]
GPG key ID: 299893C7 (on keyservers)
FP: 0124 2584 8809 EF2A DBF9  4902 64B4 D16B 2998 93C7

--~--~-~--~~~---~--~~
 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
-~--~~~~--~~--~--~---



[sqlalchemy] Re: MSSQL session.flush() doesn't always fetch primary keys

2007-01-09 Thread Paul Johnston

Hi Rick,

I think we're actually agreeing about almost everything, although I have 
responded to your points individually. Lets see what Michael says about 
this. Actually reading over my post again, my preferred fix was a little 
hidden at the bottom. I will highlight it here:

The fix that seems logical to me is to put
the code to create an implicit sequence in Column.__init__. It's down to
the individual engines how they implement this sequence, but its
existence or not is engine independent.

 If all you're looking for is an implicit generation of an IDENTITY 
 column, you can use the autoincrement=True keyword to the Column 
 constructor.

Yep, that's true, but if I do that then session.flush() doesn't fetch 
the pk, hence my bug report.

 But be careful with the assumption of autoincrementing PKs. It's 
 perfectly valid to have a PK that is not autoincrementing. That's why 
 the pseudo-Sequence() mechanism is there in the first place, to 
 distinguish between the two (and to allow the specification of the 
 IDENTITY seed value).

Yep, hence the fairly complicated code in MSSQLSchemaGenerator

# install a IDENTITY Sequence if we have an implicit IDENTITY column
if column.primary_key and column.autoincrement and 
isinstance(column.type, sqltypes.Integer) and not column.foreign_key:
if column.default is None or (isinstance(column.default, 
schema.Sequence) and column.default.optional):
column.sequence = schema.Sequence(column.name + '_seq')

 Issuing a spurious SELECT @@IDENTITY could be construed as a bit 
 risky as well -- that will simply return the last inserted IDENTITY 
 value on that DB connection -- which could be from a completely 
 different query. Given that SA pools connection, it seems to me that 
 this is bad-tasting recipe.

I agree in principle. In fact, it returns null if your last insert was a 
table without an identity column, at least with SQL Server 2005. But 
still, doing this seems risky.

 I'm not sure I understand the motivation to check each query anew for 
 identity keys. What's wrong with checking for them only at table 
 definition time?

Exactly, hence my last suggestion to move the sequence generation to 
Column.__init__. The thing is, that's just not how SA is setup at the 
moment, so this will need a little jiggery pokery.

Regards,

Paul

--~--~-~--~~~---~--~~
 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
-~--~~~~--~~--~--~---



[sqlalchemy] Re: MSSQL session.flush() doesn't always fetch primary keys

2007-01-09 Thread Michael Bayer

the current behavior of SA is to utilize the databases implicit PK  
generation feature *if one is available*.  the three databases that I  
know have this are sqlite (send None in to a PK INSERT, it gets  
generated), MySQL (AUTOINCREMENT) and Postgres (SERIAL/BIGSERIAL,  
which results in the creation of a sequence with a naming scheme).   
the other database im familiar with, Oracle, does not have such a  
feature.  So with Oracle, you have to create an explicit Sequence  
object if you want PKs to get generated automatically upon INSERT,  
and SA will fire off that sequence.  you can put a Sequence on any  
Column, and it will still work on mysql/sqlite, since in those cases  
its just ignored, and the normal autoincrementing behavior of those  
databases is used instead.

so we dont have anything that is creating named sequences  
automatically.  im not sure what MS-SQL's needs are in this  
department.  but the autoincrement=True on Column is always like  
that, it basically means use the database's auto-incrementing  
feature, *if available*...if MS-SQL doesnt have that then you wont  
get autoincrementing.

Now, if we want to say, SQLAlchemy should automatically create named  
sequences for databases that use them, thats a change we can look  
into making, and of course the question becomes what do we name the  
sequences, and stuff like that.  but at the moment thats not how its  
designed, so thats probably why its not working.

On Jan 9, 2007, at 6:33 PM, Paul Johnston wrote:


 Hi Rick,

 I think we're actually agreeing about almost everything, although I  
 have
 responded to your points individually. Lets see what Michael says  
 about
 this. Actually reading over my post again, my preferred fix was a  
 little
 hidden at the bottom. I will highlight it here:

 The fix that seems logical to me is to put
 the code to create an implicit sequence in Column.__init__. It's  
 down to
 the individual engines how they implement this sequence, but its
 existence or not is engine independent.

 If all you're looking for is an implicit generation of an IDENTITY
 column, you can use the autoincrement=True keyword to the Column
 constructor.

 Yep, that's true, but if I do that then session.flush() doesn't fetch
 the pk, hence my bug report.

 But be careful with the assumption of autoincrementing PKs. It's
 perfectly valid to have a PK that is not autoincrementing. That's why
 the pseudo-Sequence() mechanism is there in the first place, to
 distinguish between the two (and to allow the specification of the
 IDENTITY seed value).

 Yep, hence the fairly complicated code in MSSQLSchemaGenerator

 # install a IDENTITY Sequence if we have an implicit  
 IDENTITY column
 if column.primary_key and column.autoincrement and
 isinstance(column.type, sqltypes.Integer) and not column.foreign_key:
 if column.default is None or (isinstance(column.default,
 schema.Sequence) and column.default.optional):
 column.sequence = schema.Sequence(column.name +  
 '_seq')

 Issuing a spurious SELECT @@IDENTITY could be construed as a bit
 risky as well -- that will simply return the last inserted IDENTITY
 value on that DB connection -- which could be from a completely
 different query. Given that SA pools connection, it seems to me that
 this is bad-tasting recipe.

 I agree in principle. In fact, it returns null if your last insert  
 was a
 table without an identity column, at least with SQL Server 2005. But
 still, doing this seems risky.

 I'm not sure I understand the motivation to check each query anew for
 identity keys. What's wrong with checking for them only at table
 definition time?

 Exactly, hence my last suggestion to move the sequence generation to
 Column.__init__. The thing is, that's just not how SA is setup at the
 moment, so this will need a little jiggery pokery.

 Regards,

 Paul

 


--~--~-~--~~~---~--~~
 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
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Saving all transactions against a database (logging queries?)

2007-01-09 Thread Brian Jarrett

Jose,

Try it without the level=, format=, and datefmt= options in
logging.basicConfig() (leaving in only filename= and filemode=) and I
think it'll work.  Then you can try adding in the other options one at
a time and see if you can get them to work.  When I only had filename
and filemode specified, things worked.  Once I started adding more
parameters, I had similar problems.

Brian

On 1/6/07, jose [EMAIL PROTECTED] wrote:

 Hello Barry,

 I'm trying to get logging work...I put in my model.py the following code
 and I expected to see my queries into /tmp/sa.log file, but...
 what's wrong with it?


 from turbogears import database
 from sqlalchemy import Table, relation
 from sqlalchemy.engine import create_engine
 from sqlalchemy.ext.assignmapper import assign_mapper
 import logging
 database.bind_meta_data()
 session = database.session
 engine = database.metadata.engine
 context = session.context
 engine.echo = False
 logging.basicConfig(level=logging.DEBUG,
 format='%(asctime)s %(levelname)-8s %(message)s',
 datefmt='%a, %d %b %Y %H:%M:%S',
 filename='/tmp/sa.log',
 filemode='w')
 logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)·


 Barry Warsaw wrote:

 
  -BEGIN PGP SIGNED MESSAGE-
  Hash: SHA1
 
  On Jan 5, 2007, at 12:01 PM, Michael Bayer wrote:
 
 
  i havent gotten around to adding docs for logging to the main
  docs...but its using Python's logging module now.  turn off all the
  echo=True flags and go straight to logging:
 
  import logging
  logging.basicConfig()  # see python's logging docs for options
  logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)
 
 
  Sweet.
  - -Barry
 
  -BEGIN PGP SIGNATURE-
  Version: GnuPG v1.4.5 (Darwin)
 
  iQCVAwUBRZ6IsnEjvBPtnXfVAQLINgP+JUdkjNn+CtAA5Uao3Gs+n+4IuuMeiCoz
  8J9yY9XlU74AW4N1ysf0wao0r2p871t2+sgIuFnBpRxO3DficR+iji3LJ24ZeWdH
  KcG/uxUGk4uF7jfMeAdzVVRe/XqVRwI1uwMCN5p2rkXjdEokJp7G8uT872nC7EM5
  3OzCHKORs2M=
  =PBfM
  -END PGP SIGNATURE-
 
  


 


--~--~-~--~~~---~--~~
 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
-~--~~~~--~~--~--~---