Re: [sqlalchemy] More efficient Insert mechanism

2010-02-02 Thread Mati Skiva

Michael Bayer wrote:

matiskiva wrote:

  

Naturally, the problem is that SA collects the generated id, that is
why every statement is executed alone, and than the generated id is
retrieved.


I was wondering though, is there some kind of a more efficient
mechanism?
At least on MySQL, under InnoDB [or with table locking] all the items
can be inserted, and individual Id's can be calculated.
Is there any development there?



within the ORM side, very unlikely.  DBAPI supports no generalized system
of returning newly generated primary key identifiers across a
multi-insert, and the ORM does not use the same INSERT statement for every
row - some may have values missing for which those columns are omitted
from the ultimate INSERT so as to allow a server-side default to fire off.

In the case you describe, I assume you mean that the IDs can be guessed
by assuming 30K new rows means max(id)max(id) + 3.  I'm not
aware of another system, but let me know if there's some feature of InnoDB
at play here.

If indeed that's the idea, that scheme relies upon specifics not just of
your database but also the scenario, that is your 30K inserts are all of
the identical set of columns, using a sequential integer generator with no
skipping of ids which may already exist out of sequence within the table
(i.e. that the inserts really start at max(id) and not just available
slots), with no concurrent inserts elsewhere that may change the
sequencing as it goes (or the table were locked entirely).   All fine
things but nothing that the ORM can assume.   Also, if you're inserting
30K rows, I doubt you really *need* the newly generated IDs or live
objects at that point, it sounds much more like you're just dumping a
huge amount of rows to be individually accessed at some later time.

If you *do* actually assume all these things, then you really should just
be using an executemany - particularly since you're assuming you know the
exact structure of rows to be inserted.

I'm assuming you're familiar with executemany, or if not, its described here:

http://www.sqlalchemy.org/docs/sqlexpression.html#executing-multiple-statements



  

Regards,
Mati

--
You received this message because you are subscribed to the Google Groups
sqlalchemy group.
To post to this group, send email to sqlalch...@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.





  

Thank you for your feedback.

In the case I mentioned, I cannot just dump the 30K items. Because I 
need their generated id's for other inserted rows (I have relations)
In more detail, I am inserting resource items, and also mission items, 
each mission connects to a resource via id.
So dumping all the data, without connecting python object to id is not 
an option.



About the strategy for resolving the matter - I need to have some 
assumptions, such as table locking.
Obviously this is not a good general approach, however in many cases a 
functionality of bulk-insert-and-acquire-generated-id is desired. If the 
functionality requires a special configuration and error handling, than 
we guarantee that the developers are not surprised by failures.


So, I would like to implement it. Hopefully with your guidance.

As I see it, I need to perform the following steps:
* group insert actions by destination table (and order, not breaking 
dependencies)
  this will allow me to perform bulk operations, as I am working on a 
list of items, rather than one item.
* perform configuration and environment defendant SQL operations, or 
withdraw to original insert operation


I need your help in the followings:
* some description of how the session.add results in insert commands
* a pointer to the code that deals with the inserts

Regards,
Mati

This mail was sent via Mobileye Mail-SeCure system.


--
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@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.



Re: [sqlalchemy] UserDefinedType and result_processor

2010-02-02 Thread Manlio Perillo
-BEGIN PGP SIGNED MESSAGE-
Hash: SHA1

Michael Bayer ha scritto:
 On Feb 1, 2010, at 8:31 PM, Manlio Perillo wrote:
 
 Hi.
 
 I have defined a custom type for PostgreSQL ltree support.
 
 [...]
 This works, when I create the table and insert some values.
 However when I select data from the database, result_processor is not
 called.
 
 nothing unusual above and UserDefinedType.result_processor is covered in 
 tests (which fail if I change result_processor, so its called),  so you'll 
 have to provide more specifics.   
 

Ok, sorry again for the noise.
The cause was a literal value ('*') specified in the column clause in
the select statement.

Unfortunately SQLAlchemy is not (yet?) smart enough to deduce the types
for literal queries.


Thanks   Manlio
-BEGIN PGP SIGNATURE-
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAktoDekACgkQscQJ24LbaUTSLQCgjc8egOSlx3Qq8spcyczRjKpJ
HkcAoItDI4+sCGSTUaMkbBL7JDGxBT95
=kG1g
-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 sqlalch...@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.



[sqlalchemy] session commit and the GIL

2010-02-02 Thread Eyal Gordon
Hello,

I'm running sqlalchemy on python 2.4.3, with postgresql. My
application is multi-threaded, commits and queries are protected by a
python thread lock. I suspect that when running session.commit(), the
python global interpreter lock (GIL) remains owned by this thread
until the commit completes, such that other threads can not run until
the commit action completes (even thread that have nothing to do with
the database).
Is this correct?

Thanks,
 Eyal

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@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.



[sqlalchemy] Re: Access property in query.

2010-02-02 Thread Andy
Thanks, that worked like a charm. Look forward to your PyCon
presentation.

On Feb 2, 12:56 am, Michael Bayer mike...@zzzcomputing.com wrote:
 On Feb 1, 2010, at 9:24 PM, Andy (Zenom) wrote:





  I don't know if my terminology is correct etc. But the basic idea is
  the following.

  In my model I have something like

  from mylib.helpers import slugify

  class MyModel(Base):
     __tablename__ = testing

    id = Column(Integer, primary_key)
    title = Column(Unicode)
    description = Column(Unicode)

    @property
    def slug(self):
         return slugify(self.title)

  Now I want to be able to do something like.
  session.query(MyModel.id, MyModel.title, MyModel.slug).all()

  The table obviously doesn't have a slug column, I just want to return
  my title as a pseudo-column named slug, with it passed through my
  slugify method first.

  I tried to do something like the following:

  @synonym_for(title)
  @property
  def slug(self):
     return slugify(self.title)

  And this did not work.  It seems to just return another column just
  like title (not sent through slugify first).  Any idea how I can do
  what I am looking for?

 part of the approach depends on if slugify can be defined as a SQL function 
 or if it must be executed in Python.  If the latter, you probably want 
 MyModel.slug to resolve into a column that also defines a custom type.

 Assuming its a Python function, note that your column can't be used 
 effectively in a comparison operation, like MyModel.slug == 'foo', since 
 the slugify() operation would have to be applied in aggregate.

 Anyway assuming non-SQL function, here's a hack I came up with that will do 
 it:

 from sqlalchemy import *
 from sqlalchemy.orm import *
 from sqlalchemy.ext.declarative import declarative_base
 from sqlalchemy.sql.expression import _UnaryExpression
 from sqlalchemy.types import UserDefinedType

 Base = declarative_base()

 def slugify(text):
     return SLUG ! + text

 class MySlugType(UserDefinedType):
     def result_processor(self, dialect, coltype):
         return slugify

 class MyModel(Base):
     __tablename__ = testing

     id = Column(Integer, primary_key=True)
     title = Column(Unicode)
     description = Column(Unicode)

     slug = column_property(_UnaryExpression(title, type_=MySlugType()))

 engine = create_engine('sqlite://', echo=True)
 Base.metadata.create_all(engine)
 session = sessionmaker(engine)()

 session.add(MyModel(title=u'title', description=u'description'))
 session.commit()

 print session.query(MyModel.title, MyModel.slug).all()





  --
  You received this message because you are subscribed to the Google Groups 
  sqlalchemy group.
  To post to this group, send email to sqlalch...@googlegroups.com.
  To unsubscribe from this group, send email to 
  sqlalchemy+unsubscr...@googlegroups.com.
  For more options, visit this group 
  athttp://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 sqlalch...@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.



Re: [sqlalchemy] Re: session.add() vs session.merge() and delete child

2010-02-02 Thread Michael Bayer
avdd wrote:
 On Feb 2, 2:52 am, Michael Bayer mike...@zzzcomputing.com wrote:

 the behavior you first illustrated, that of merge() and add() not acting
 the same regarding pending changes, was a behavior that was somewhat in
 the realm of a bug.   I mentioned the other day it was fixed in r6711.  

 Well no, not in 0.5 (r6712).

its not an entirely backwards compatible change, since it is add()ing an
object that otherwise would not be added, thus causing an error if that
object is attached to some other session.

I'd recommend upgrading to 0.6, beta1 release is any day this week I get a
chance to do it.



 --
 You received this message because you are subscribed to the Google Groups
 sqlalchemy group.
 To post to this group, send email to sqlalch...@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.



-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@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.



Re: [sqlalchemy] session commit and the GIL

2010-02-02 Thread Antoine Pitrou
Le mardi 02 février 2010 à 01:08 -0800, Eyal Gordon a écrit :
 Hello,
 
 I'm running sqlalchemy on python 2.4.3, with postgresql. My
 application is multi-threaded, commits and queries are protected by a
 python thread lock. I suspect that when running session.commit(), the
 python global interpreter lock (GIL) remains owned by this thread
 until the commit completes, such that other threads can not run until
 the commit action completes (even thread that have nothing to do with
 the database).

Touching any Python object requires holding the GIL. The GIL can only be
released when issueing a query to the database (that query can be
COMMIT of course), which I suppose the various database drivers
already do (if they don't, you can certainly issue a bug/feature request
to them).


Antoine.


-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@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.



Re: [sqlalchemy] More efficient Insert mechanism

2010-02-02 Thread Michael Bayer
Mati Skiva wrote:
 Thank you for your feedback.

 In the case I mentioned, I cannot just dump the 30K items. Because I
 need their generated id's for other inserted rows (I have relations)
 In more detail, I am inserting resource items, and also mission items,
 each mission connects to a resource via id.
 So dumping all the data, without connecting python object to id is not
 an option.


 About the strategy for resolving the matter - I need to have some
 assumptions, such as table locking.
 Obviously this is not a good general approach, however in many cases a
 functionality of bulk-insert-and-acquire-generated-id is desired. If the
 functionality requires a special configuration and error handling, than
 we guarantee that the developers are not surprised by failures.

 So, I would like to implement it. Hopefully with your guidance.

 As I see it, I need to perform the following steps:
 * group insert actions by destination table (and order, not breaking
 dependencies)
this will allow me to perform bulk operations, as I am working on a
 list of items, rather than one item.
 * perform configuration and environment defendant SQL operations, or
 withdraw to original insert operation

 I need your help in the followings:
 * some description of how the session.add results in insert commands
 * a pointer to the code that deals with the inserts

I think if you familiarize yourself with the workings of the unit of work,
you'll see that inserts are already grouped about as much as they can be.

Your series of steps does not take into account the main issue I raised,
that the list of insert statements are not all of the same structure, thus
making insertmany impossible regardless of primary key fetching unless
each statement were carefully grouped by what parameters or embedded SQL
expressions are present - a procedure that will usually just add needless
overhead, since executemany() can almost never be used except in this very
rare lock the tables and assume sequential ids scenario.

The biggest reason to keep exotic edge cases out of the core ORM is that
everything you want to do is already possible outside of the ORM.   You
can apply your guess the generated IDs scheme on top of an executemany
yourself.   I can show you the public API that would allow you to mark
your inserted objects as persistent/clean as well after the insert so
that it would look like a flush() just occurred.





 Regards,
 Mati

 This mail was sent via Mobileye Mail-SeCure system.


 --
 You received this message because you are subscribed to the Google Groups
 sqlalchemy group.
 To post to this group, send email to sqlalch...@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.



-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@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.



Re: [sqlalchemy] session commit and the GIL

2010-02-02 Thread Michael Bayer
Eyal Gordon wrote:
 Hello,

 I'm running sqlalchemy on python 2.4.3, with postgresql. My
 application is multi-threaded, commits and queries are protected by a
 python thread lock. I suspect that when running session.commit(), the
 python global interpreter lock (GIL) remains owned by this thread
 until the commit completes, such that other threads can not run until
 the commit action completes (even thread that have nothing to do with
 the database).
 Is this correct?

at most it would only remain under the GIL while the psycopg2 connection
is performing its own commit(), which is a tiny portion of the
session.commit() procedure.   If OTOH you are applying a mutex around
Session.commit() yourself (which is what commits and queries are
protected by a python thread lock sounds like), then its your own mutex
that would be serializing the Session.commit() operation across threads.




 Thanks,
  Eyal

 --
 You received this message because you are subscribed to the Google Groups
 sqlalchemy group.
 To post to this group, send email to sqlalch...@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.



-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@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.



[sqlalchemy] Re: Access property in query.

2010-02-02 Thread Andy (Zenom)
The one thing that is frustrating is it is re-querying the database.
So if I create a simple server side function how would I do that? I am
currently using trunk.



On Feb 2, 8:57 am, Andy andy.hol...@belator.com wrote:
 Thanks, that worked like a charm. Look forward to your PyCon
 presentation.

 On Feb 2, 12:56 am, Michael Bayer mike...@zzzcomputing.com wrote:



  On Feb 1, 2010, at 9:24 PM, Andy (Zenom) wrote:

   I don't know if my terminology is correct etc. But the basic idea is
   the following.

   In my model I have something like

   from mylib.helpers import slugify

   class MyModel(Base):
      __tablename__ = testing

     id = Column(Integer, primary_key)
     title = Column(Unicode)
     description = Column(Unicode)

     @property
     def slug(self):
          return slugify(self.title)

   Now I want to be able to do something like.
   session.query(MyModel.id, MyModel.title, MyModel.slug).all()

   The table obviously doesn't have a slug column, I just want to return
   my title as a pseudo-column named slug, with it passed through my
   slugify method first.

   I tried to do something like the following:

   @synonym_for(title)
   @property
   def slug(self):
      return slugify(self.title)

   And this did not work.  It seems to just return another column just
   like title (not sent through slugify first).  Any idea how I can do
   what I am looking for?

  part of the approach depends on if slugify can be defined as a SQL 
  function or if it must be executed in Python.  If the latter, you probably 
  want MyModel.slug to resolve into a column that also defines a custom type.

  Assuming its a Python function, note that your column can't be used 
  effectively in a comparison operation, like MyModel.slug == 'foo', since 
  the slugify() operation would have to be applied in aggregate.

  Anyway assuming non-SQL function, here's a hack I came up with that will do 
  it:

  from sqlalchemy import *
  from sqlalchemy.orm import *
  from sqlalchemy.ext.declarative import declarative_base
  from sqlalchemy.sql.expression import _UnaryExpression
  from sqlalchemy.types import UserDefinedType

  Base = declarative_base()

  def slugify(text):
      return SLUG ! + text

  class MySlugType(UserDefinedType):
      def result_processor(self, dialect, coltype):
          return slugify

  class MyModel(Base):
      __tablename__ = testing

      id = Column(Integer, primary_key=True)
      title = Column(Unicode)
      description = Column(Unicode)

      slug = column_property(_UnaryExpression(title, type_=MySlugType()))

  engine = create_engine('sqlite://', echo=True)
  Base.metadata.create_all(engine)
  session = sessionmaker(engine)()

  session.add(MyModel(title=u'title', description=u'description'))
  session.commit()

  print session.query(MyModel.title, MyModel.slug).all()

   --
   You received this message because you are subscribed to the Google Groups 
   sqlalchemy group.
   To post to this group, send email to sqlalch...@googlegroups.com.
   To unsubscribe from this group, send email to 
   sqlalchemy+unsubscr...@googlegroups.com.
   For more options, visit this group 
   athttp://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 sqlalch...@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.



Re: [sqlalchemy] Re: Access property in query.

2010-02-02 Thread Michael Bayer
Andy (Zenom) wrote:
 The one thing that is frustrating is it is re-querying the database.
 So if I create a simple server side function how would I do that? I am
 currently using trunk.

how to create the server side function or how to use it from SQLA ?  the
column_property() thing is where you'd use func.foo().







 On Feb 2, 8:57 am, Andy andy.hol...@belator.com wrote:
 Thanks, that worked like a charm. Look forward to your PyCon
 presentation.

 On Feb 2, 12:56 am, Michael Bayer mike...@zzzcomputing.com wrote:



  On Feb 1, 2010, at 9:24 PM, Andy (Zenom) wrote:

   I don't know if my terminology is correct etc. But the basic idea is
   the following.

   In my model I have something like

   from mylib.helpers import slugify

   class MyModel(Base):
      __tablename__ = testing

     id = Column(Integer, primary_key)
     title = Column(Unicode)
     description = Column(Unicode)

     @property
     def slug(self):
          return slugify(self.title)

   Now I want to be able to do something like.
   session.query(MyModel.id, MyModel.title, MyModel.slug).all()

   The table obviously doesn't have a slug column, I just want to
 return
   my title as a pseudo-column named slug, with it passed through my
   slugify method first.

   I tried to do something like the following:

   @synonym_for(title)
   @property
   def slug(self):
      return slugify(self.title)

   And this did not work.  It seems to just return another column just
   like title (not sent through slugify first).  Any idea how I can do
   what I am looking for?

  part of the approach depends on if slugify can be defined as a SQL
 function or if it must be executed in Python.  If the latter, you
 probably want MyModel.slug to resolve into a column that also defines
 a custom type.

  Assuming its a Python function, note that your column can't be used
 effectively in a comparison operation, like MyModel.slug == 'foo',
 since the slugify() operation would have to be applied in aggregate.

  Anyway assuming non-SQL function, here's a hack I came up with that
 will do it:

  from sqlalchemy import *
  from sqlalchemy.orm import *
  from sqlalchemy.ext.declarative import declarative_base
  from sqlalchemy.sql.expression import _UnaryExpression
  from sqlalchemy.types import UserDefinedType

  Base = declarative_base()

  def slugify(text):
      return SLUG ! + text

  class MySlugType(UserDefinedType):
      def result_processor(self, dialect, coltype):
          return slugify

  class MyModel(Base):
      __tablename__ = testing

      id = Column(Integer, primary_key=True)
      title = Column(Unicode)
      description = Column(Unicode)

      slug = column_property(_UnaryExpression(title,
 type_=MySlugType()))

  engine = create_engine('sqlite://', echo=True)
  Base.metadata.create_all(engine)
  session = sessionmaker(engine)()

  session.add(MyModel(title=u'title', description=u'description'))
  session.commit()

  print session.query(MyModel.title, MyModel.slug).all()

   --
   You received this message because you are subscribed to the Google
 Groups sqlalchemy group.
   To post to this group, send email to sqlalch...@googlegroups.com.
   To unsubscribe from this group, send email to
 sqlalchemy+unsubscr...@googlegroups.com.
   For more options, visit this group
 athttp://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 sqlalch...@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.



-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@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.



[sqlalchemy] Re: Access property in query.

2010-02-02 Thread Andy (Zenom)
I got the server side one created in schema cms, function name is
slugify.

I am trying to figure out how to let sqlalchemy know about the
function and the schema its in.  On postgresql I can do like SELECT
cms.slugify(title) FROM cms.tablename, and it returns the slugified
title, but to get that in sqlalchemy? Sorry should have been more
clear.  I was assuming I needed to somehow create my own sqlalchemy
function, but havn't found the right answer yet.

On Feb 2, 10:50 am, Michael Bayer mike...@zzzcomputing.com wrote:
 Andy (Zenom) wrote:
  The one thing that is frustrating is it is re-querying the database.
  So if I create a simple server side function how would I do that? I am
  currently using trunk.

 how to create the server side function or how to use it from SQLA ?  the
 column_property() thing is where you'd use func.foo().





  On Feb 2, 8:57 am, Andy andy.hol...@belator.com wrote:
  Thanks, that worked like a charm. Look forward to your PyCon
  presentation.

  On Feb 2, 12:56 am, Michael Bayer mike...@zzzcomputing.com wrote:

   On Feb 1, 2010, at 9:24 PM, Andy (Zenom) wrote:

I don't know if my terminology is correct etc. But the basic idea is
the following.

In my model I have something like

from mylib.helpers import slugify

class MyModel(Base):
__tablename__ = testing

id = Column(Integer, primary_key)
title = Column(Unicode)
description = Column(Unicode)

@property
def slug(self):
return slugify(self.title)

Now I want to be able to do something like.
session.query(MyModel.id, MyModel.title, MyModel.slug).all()

The table obviously doesn't have a slug column, I just want to
  return
my title as a pseudo-column named slug, with it passed through my
slugify method first.

I tried to do something like the following:

@synonym_for(title)
@property
def slug(self):
return slugify(self.title)

And this did not work. It seems to just return another column just
like title (not sent through slugify first). Any idea how I can do
what I am looking for?

   part of the approach depends on if slugify can be defined as a SQL
  function or if it must be executed in Python. If the latter, you
  probably want MyModel.slug to resolve into a column that also defines
  a custom type.

   Assuming its a Python function, note that your column can't be used
  effectively in a comparison operation, like MyModel.slug == 'foo',
  since the slugify() operation would have to be applied in aggregate.

   Anyway assuming non-SQL function, here's a hack I came up with that
  will do it:

   from sqlalchemy import *
   from sqlalchemy.orm import *
   from sqlalchemy.ext.declarative import declarative_base
   from sqlalchemy.sql.expression import _UnaryExpression
   from sqlalchemy.types import UserDefinedType

   Base = declarative_base()

   def slugify(text):
   return SLUG ! + text

   class MySlugType(UserDefinedType):
   def result_processor(self, dialect, coltype):
   return slugify

   class MyModel(Base):
   __tablename__ = testing

   id = Column(Integer, primary_key=True)
   title = Column(Unicode)
   description = Column(Unicode)

   slug = column_property(_UnaryExpression(title,
  type_=MySlugType()))

   engine = create_engine('sqlite://', echo=True)
   Base.metadata.create_all(engine)
   session = sessionmaker(engine)()

   session.add(MyModel(title=u'title', description=u'description'))
   session.commit()

   print session.query(MyModel.title, MyModel.slug).all()

--
You received this message because you are subscribed to the Google
  Groups sqlalchemy group.
To post to this group, send email to sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to
  sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group
  athttp://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 sqlalch...@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.

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@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.



Re: [sqlalchemy] Re: Access property in query.

2010-02-02 Thread Michael Bayer
Andy (Zenom) wrote:
 I got the server side one created in schema cms, function name is
 slugify.

 I am trying to figure out how to let sqlalchemy know about the
 function and the schema its in.  On postgresql I can do like SELECT
 cms.slugify(title) FROM cms.tablename, and it returns the slugified
 title, but to get that in sqlalchemy? Sorry should have been more
 clear.  I was assuming I needed to somehow create my own sqlalchemy
 function, but havn't found the right answer yet.


so that's column_property(func.cms.slugify(title)) .




 On Feb 2, 10:50 am, Michael Bayer mike...@zzzcomputing.com wrote:
 Andy (Zenom) wrote:
  The one thing that is frustrating is it is re-querying the database.
  So if I create a simple server side function how would I do that? I am
  currently using trunk.

 how to create the server side function or how to use it from SQLA ?  the
 column_property() thing is where you'd use func.foo().





  On Feb 2, 8:57 am, Andy andy.hol...@belator.com wrote:
  Thanks, that worked like a charm. Look forward to your PyCon
  presentation.

  On Feb 2, 12:56 am, Michael Bayer mike...@zzzcomputing.com wrote:

   On Feb 1, 2010, at 9:24 PM, Andy (Zenom) wrote:

I don't know if my terminology is correct etc. But the basic idea
 is
the following.

In my model I have something like

from mylib.helpers import slugify

class MyModel(Base):
__tablename__ = testing

id = Column(Integer, primary_key)
title = Column(Unicode)
description = Column(Unicode)

@property
def slug(self):
return slugify(self.title)

Now I want to be able to do something like.
session.query(MyModel.id, MyModel.title, MyModel.slug).all()

The table obviously doesn't have a slug column, I just want to
  return
my title as a pseudo-column named slug, with it passed through
 my
slugify method first.

I tried to do something like the following:

@synonym_for(title)
@property
def slug(self):
return slugify(self.title)

And this did not work. It seems to just return another column
 just
like title (not sent through slugify first). Any idea how I can
 do
what I am looking for?

   part of the approach depends on if slugify can be defined as a
 SQL
  function or if it must be executed in Python. If the latter, you
  probably want MyModel.slug to resolve into a column that also defines
  a custom type.

   Assuming its a Python function, note that your column can't be used
  effectively in a comparison operation, like MyModel.slug == 'foo',
  since the slugify() operation would have to be applied in aggregate.

   Anyway assuming non-SQL function, here's a hack I came up with that
  will do it:

   from sqlalchemy import *
   from sqlalchemy.orm import *
   from sqlalchemy.ext.declarative import declarative_base
   from sqlalchemy.sql.expression import _UnaryExpression
   from sqlalchemy.types import UserDefinedType

   Base = declarative_base()

   def slugify(text):
   return SLUG ! + text

   class MySlugType(UserDefinedType):
   def result_processor(self, dialect, coltype):
   return slugify

   class MyModel(Base):
   __tablename__ = testing

   id = Column(Integer, primary_key=True)
   title = Column(Unicode)
   description = Column(Unicode)

   slug = column_property(_UnaryExpression(title,
  type_=MySlugType()))

   engine = create_engine('sqlite://', echo=True)
   Base.metadata.create_all(engine)
   session = sessionmaker(engine)()

   session.add(MyModel(title=u'title', description=u'description'))
   session.commit()

   print session.query(MyModel.title, MyModel.slug).all()

--
You received this message because you are subscribed to the
 Google
  Groups sqlalchemy group.
To post to this group, send email to sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to
  sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group
  athttp://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 sqlalch...@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.

 --
 You received this message because you are subscribed to the Google Groups
 sqlalchemy group.
 To post to this group, send email to sqlalch...@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.



-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 

[sqlalchemy] Re: Access property in query.

2010-02-02 Thread Andy (Zenom)
I do this, and the query it spits out in the error works fine in the
postgresql command line, but not in sqlalchemy.

Traceback:
http://pylonshq.com/tracebacks/9b322f31095beda23f5d846e43399d21

query:
'SELECT DISTINCT cms.niches.title AS cms_niches_title,
cms.niches.niche_id AS cms_niches_niche_id, cms.slugify
(cms.niches.title) AS slug \nFROM cms.niches JOIN cms.dvd_sites_niches
ON cms.niches.niche_id = cms.dvd_sites_niches.niche_id ORDER BY
cms.niches.title ASC'

Here is my function:
CREATE OR REPLACE FUNCTION cms.slugify(character varying)
  RETURNS character varying AS
$BODY$
import re
import unicodedata

value = unicode(args[0])
value = value.replace(, )
value = value.replace(_, -)
value = unicodedata.normalize(NFKD, value).encode(ascii,
ignore)
value = unicode(re.sub([^\w\s-], , value).strip().lower())
return  re.sub([-\s]+, -, value)

$BODY$
  LANGUAGE 'plpythonu' VOLATILE;

Again the function works in like pgadmin3 etc, but not in sqlalchemy.

On Feb 2, 11:01 am, Michael Bayer mike...@zzzcomputing.com wrote:
 Andy (Zenom) wrote:
  I got the server side one created in schema cms, function name is
  slugify.

  I am trying to figure out how to let sqlalchemy know about the
  function and the schema its in.  On postgresql I can do like SELECT
  cms.slugify(title) FROM cms.tablename, and it returns the slugified
  title, but to get that in sqlalchemy? Sorry should have been more
  clear.  I was assuming I needed to somehow create my own sqlalchemy
  function, but havn't found the right answer yet.

 so that's column_property(func.cms.slugify(title)) .





  On Feb 2, 10:50 am, Michael Bayer mike...@zzzcomputing.com wrote:
  Andy (Zenom) wrote:
   The one thing that is frustrating is it is re-querying the database.
   So if I create a simple server side function how would I do that? I am
   currently using trunk.

  how to create the server side function or how to use it from SQLA ? the
  column_property() thing is where you'd use func.foo().

   On Feb 2, 8:57 am, Andy andy.hol...@belator.com wrote:
   Thanks, that worked like a charm. Look forward to your PyCon
   presentation.

   On Feb 2, 12:56 am, Michael Bayer mike...@zzzcomputing.com wrote:

On Feb 1, 2010, at 9:24 PM, Andy (Zenom) wrote:

 I don't know if my terminology is correct etc. But the basic idea
  is
 the following.

 In my model I have something like

 from mylib.helpers import slugify

 class MyModel(Base):
 __tablename__ = testing

 id = Column(Integer, primary_key)
 title = Column(Unicode)
 description = Column(Unicode)

 @property
 def slug(self):
 return slugify(self.title)

 Now I want to be able to do something like.
 session.query(MyModel.id, MyModel.title, MyModel.slug).all()

 The table obviously doesn't have a slug column, I just want to
   return
 my title as a pseudo-column named slug, with it passed through
  my
 slugify method first.

 I tried to do something like the following:

 @synonym_for(title)
 @property
 def slug(self):
 return slugify(self.title)

 And this did not work. It seems to just return another column
  just
 like title (not sent through slugify first). Any idea how I can
  do
 what I am looking for?

part of the approach depends on if slugify can be defined as a
  SQL
   function or if it must be executed in Python. If the latter, you
   probably want MyModel.slug to resolve into a column that also defines
   a custom type.

Assuming its a Python function, note that your column can't be used
   effectively in a comparison operation, like MyModel.slug == 'foo',
   since the slugify() operation would have to be applied in aggregate.

Anyway assuming non-SQL function, here's a hack I came up with that
   will do it:

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.sql.expression import _UnaryExpression
from sqlalchemy.types import UserDefinedType

Base = declarative_base()

def slugify(text):
return SLUG ! + text

class MySlugType(UserDefinedType):
def result_processor(self, dialect, coltype):
return slugify

class MyModel(Base):
__tablename__ = testing

id = Column(Integer, primary_key=True)
title = Column(Unicode)
description = Column(Unicode)

slug = column_property(_UnaryExpression(title,
   type_=MySlugType()))

engine = create_engine('sqlite://', echo=True)
Base.metadata.create_all(engine)
session = sessionmaker(engine)()

session.add(MyModel(title=u'title', description=u'description'))
session.commit()

print session.query(MyModel.title, MyModel.slug).all()

 --
 You received this message because you are subscribed to the
  Google
   Groups sqlalchemy group.
 To post to this group, send email to sqlalch...@googlegroups.com.
 To unsubscribe from this group, send email 

[sqlalchemy] Re: Access property in query.

2010-02-02 Thread Andy (Zenom)
Scratch the last, helps if I have my development.ini pointed to the
proper database server :) Its working fine. Thanks for all the help :)

On Feb 2, 11:24 am, Andy (Zenom) stress...@gmail.com wrote:
 I do this, and the query it spits out in the error works fine in the
 postgresql command line, but not in sqlalchemy.

 Traceback:http://pylonshq.com/tracebacks/9b322f31095beda23f5d846e43399d21

 query:
 'SELECT DISTINCT cms.niches.title AS cms_niches_title,
 cms.niches.niche_id AS cms_niches_niche_id, cms.slugify
 (cms.niches.title) AS slug \nFROM cms.niches JOIN cms.dvd_sites_niches
 ON cms.niches.niche_id = cms.dvd_sites_niches.niche_id ORDER BY
 cms.niches.title ASC'

 Here is my function:
 CREATE OR REPLACE FUNCTION cms.slugify(character varying)
   RETURNS character varying AS
 $BODY$
     import re
     import unicodedata

     value = unicode(args[0])
     value = value.replace(, )
     value = value.replace(_, -)
     value = unicodedata.normalize(NFKD, value).encode(ascii,
 ignore)
     value = unicode(re.sub([^\w\s-], , value).strip().lower())
     return  re.sub([-\s]+, -, value)

 $BODY$
   LANGUAGE 'plpythonu' VOLATILE;

 Again the function works in like pgadmin3 etc, but not in sqlalchemy.

 On Feb 2, 11:01 am, Michael Bayer mike...@zzzcomputing.com wrote:



  Andy (Zenom) wrote:
   I got the server side one created in schema cms, function name is
   slugify.

   I am trying to figure out how to let sqlalchemy know about the
   function and the schema its in.  On postgresql I can do like SELECT
   cms.slugify(title) FROM cms.tablename, and it returns the slugified
   title, but to get that in sqlalchemy? Sorry should have been more
   clear.  I was assuming I needed to somehow create my own sqlalchemy
   function, but havn't found the right answer yet.

  so that's column_property(func.cms.slugify(title)) .

   On Feb 2, 10:50 am, Michael Bayer mike...@zzzcomputing.com wrote:
   Andy (Zenom) wrote:
The one thing that is frustrating is it is re-querying the database.
So if I create a simple server side function how would I do that? I am
currently using trunk.

   how to create the server side function or how to use it from SQLA ? the
   column_property() thing is where you'd use func.foo().

On Feb 2, 8:57 am, Andy andy.hol...@belator.com wrote:
Thanks, that worked like a charm. Look forward to your PyCon
presentation.

On Feb 2, 12:56 am, Michael Bayer mike...@zzzcomputing.com wrote:

 On Feb 1, 2010, at 9:24 PM, Andy (Zenom) wrote:

  I don't know if my terminology is correct etc. But the basic idea
   is
  the following.

  In my model I have something like

  from mylib.helpers import slugify

  class MyModel(Base):
  __tablename__ = testing

  id = Column(Integer, primary_key)
  title = Column(Unicode)
  description = Column(Unicode)

  @property
  def slug(self):
  return slugify(self.title)

  Now I want to be able to do something like.
  session.query(MyModel.id, MyModel.title, MyModel.slug).all()

  The table obviously doesn't have a slug column, I just want to
return
  my title as a pseudo-column named slug, with it passed through
   my
  slugify method first.

  I tried to do something like the following:

  @synonym_for(title)
  @property
  def slug(self):
  return slugify(self.title)

  And this did not work. It seems to just return another column
   just
  like title (not sent through slugify first). Any idea how I can
   do
  what I am looking for?

 part of the approach depends on if slugify can be defined as a
   SQL
function or if it must be executed in Python. If the latter, you
probably want MyModel.slug to resolve into a column that also defines
a custom type.

 Assuming its a Python function, note that your column can't be used
effectively in a comparison operation, like MyModel.slug == 'foo',
since the slugify() operation would have to be applied in aggregate.

 Anyway assuming non-SQL function, here's a hack I came up with that
will do it:

 from sqlalchemy import *
 from sqlalchemy.orm import *
 from sqlalchemy.ext.declarative import declarative_base
 from sqlalchemy.sql.expression import _UnaryExpression
 from sqlalchemy.types import UserDefinedType

 Base = declarative_base()

 def slugify(text):
 return SLUG ! + text

 class MySlugType(UserDefinedType):
 def result_processor(self, dialect, coltype):
 return slugify

 class MyModel(Base):
 __tablename__ = testing

 id = Column(Integer, primary_key=True)
 title = Column(Unicode)
 description = Column(Unicode)

 slug = column_property(_UnaryExpression(title,
type_=MySlugType()))

 engine = create_engine('sqlite://', echo=True)
 Base.metadata.create_all(engine)
 session = sessionmaker(engine)()

 session.add(MyModel(title=u'title', description=u'description'))
 

Re: [sqlalchemy] Mixing matching connectors and dialects in 0.6

2010-02-02 Thread Bo Shi
Hi Michael,

Thanks for the tip on dialect creation;  I have a working connection
and much of the low level library functionality appears to just
work.

I've just started digging into the internals to begin implementing
introspection support.  One issue I've encountered is that PyODBC
happens to return boolean columns as strings with values 1 and 0.
This confuses the current type system.  I have skimmed the
TypeDecorator documentation but am still confused about how to
associate that with this custom dialect.  Any hints?

I have attached the dialect base.py and a few test cases (not sure
they're useful as Vertica is frustratingly secretive about everything)
if you have time to review and comment.

On Fri, Jan 15, 2010 at 2:57 PM, Bo Shi bs1...@gmail.com wrote:
 That's funny because Oracle and SQL server are utterly, totally different
 from a SQL quirks perspective.   If I were to pick two dialects in SQLA
 that were *most* different from each other and also non-standard, those
 would be the two.

 I was a bit puzzled by this also (granted this was from some early
 press release I dredged up* from google).  I'm still working through
 their documentation and haven't run across any configuration that
 might enable a compatability mode yet.


 * improved compatibility with Oracle and SQLServer SQL dialects
  http://www.vertica.com/company/news_and_events/Vertica-Analytics-Database-2.5-The-Most-Cost-Effective-Way-To-Modernize-Data-Warehousing

  create_engine()
 using 'mssql+pyodbc' seems to work but upon attempting to execute a
 simple select statement, I get a programming error indicating the
 following failed to run:

     'SELECT user_name() as user_name;'


 So it seems the dialect is getting some additional state under the
 hood.  lib/sqlalchemy/dialects/mssql/pyodbc.py appears to be hooking
 PyODBCConnector and MSDialect together.  Is it possible to specify
 another dialect here?  If so, is there any documentation on how to do
 so?

 you'd want to make yourself a vertica dialect module that imports the
 PyODBCConnector and uses it as a mixin.   I'd suggest copying one of the
 existing dialects, and probably not the SQL server one unless you know
 that vertica has a lot of the transact-SQL lineage that SQL server does
 (the PG and SQLite dialects are the most barebones).    To run it, add a
 setup.py which configures your library as a setuptools entry point, in
 this case the name would be vertica+pyodbc:

 from setuptools import setup

 setup(name=SQLAVertica,
      description=...,
      entry_points={
         'sqlalchemy:plugins':
            ['vertica+pyodbc = mypackage.base:VerticaDialect']
      }


 then using create_engine('vertica+pyodbc://user:p...@host/dbname') will load
 in your dialect.

 --
 You received this message because you are subscribed to the Google Groups 
 sqlalchemy group.
 To post to this group, send email to sqlalch...@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.






-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@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.



base.py
Description: Binary data


vertica.py
Description: Binary data


Re: [sqlalchemy] More efficient Insert mechanism

2010-02-02 Thread Michael Bayer
Mati Skiva wrote:
 I believe I took these issues into account.
 But just to be sure, maybe you can highlight something for me.

 I assume the followings about the process of session.add:
 * after session.add is called, the objects are placed in a to-do pool
 (maybe)
 * for self-generating-id objects, a special process is used, one that
 fetches the generated id after the insert
 * for no self-generating-id objects, a regular process of insert is used

 I came to this conclusion, because otherwise, after each insert all the
 data of the row is retrieved and placed inside the object. Which covers
 the newly generated id.

Since you're interested in hacking SQLAlchemy internals, it would helpful
if you could familiarize yourself fully with the SQL expression and
execution API, all of which is public and documented.   id generation is
a standard feature of this system and occurs outside of the ORM.  Fetching
the ID for a new row with the SQLA expression API is a matter of calling a
ResultProxy method which the ORM only calls if it doesn't already know the
full set of primary key columns for a specific object.   The backend
implementation of id fetching varies wildly across all dialects as well
as versions of each database in use.

The flush procedure updates or expires those fields of the object which
were known to be generated by the database.   Fields which are immediately
updated include some or all of the primary key columns.  Fields which are
expired include any other columns which were generated via server-side SQL
expressions or known schema-level defaults - these are fetched when the
object's expired attributes are next accessed, if at all.

The SQL compiler procedure is aware of these columns when it generates an
individual insert() construct, given a list of parameters which are to be
bound literals and others which are to be embedded SQL expressions.   When
executed, the ResultProxy API provides these details fully - you should
familiarize yourself with all of its methods.

I would also point you to http://www.sqlalchemy.org/trac/ticket/1518 ,
which suggests that we should open up Mapper to being subclassable (for
much more exotic purposes than what you have here).  However, this
subclassing is possible now, which is where you can have your insertmany
functionality rolled in a rudimental way for your immediate use case
without burdening SQLAlchemy core with the need to have a fully
tested/supported/performant feature.   See the attached example.

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@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.

from sqlalchemy.orm.mapper import Mapper

class OptimizedInsertMapper(Mapper):

def _save_obj(self, states, uowtransaction, postupdate=False, post_update_cols=None, single=False):
# determine which of the incoming states are inserts
inserts = [s for s in states if not s.key]

# split off into inserts, updates
states = list(set(states).difference(inserts))

# get max ID of the table
max_id = uowtransaction.session.scalar(select([func.max(self.primary_key[0])]))
if not max_id:
max_id = 0

# insertmany().   assume the incoming states are all of the same format.
uowtransaction.session.execute(
self.local_table.insert(),
[s.dict for s in inserts]
)

# guess ids - establish state on the objects.
for i, s in enumerate(inserts):
s.dict['id'] = max_id + i + 1

# send the updates to the regular _save_obj
Mapper._save_obj(self, states, uowtransaction, postupdate=postupdate, post_update_cols=post_update_cols, single=single)

if __name__ == '__main__':
from sqlalchemy import *
from sqlalchemy.orm  import *
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base(mapper=OptimizedInsertMapper)

class Widget(Base):
__tablename__ = 'widget'

id = Column(Integer, primary_key=True)
data = Column(String)
related = relation(Related)

def __init__(self, data):
self.data = data
self.related = [Related() for i in xrange(5)]

class Related(Base):
__tablename__ = 'related'

id = Column(Integer, primary_key=True)
widget_id = Column(Integer, ForeignKey('widget.id'))

e = create_engine('sqlite://', echo=True)
Base.metadata.create_all(e)

sess = sessionmaker(e)()

widgets = [Widget(data=widget %d % i) for i in xrange(10)]
sess.add_all(widgets)
sess.commit()

# assert everything was generated
for w in widgets:
assert w.id
for r in w.related:
assert 

[sqlalchemy] relations and multiple declarative bases

2010-02-02 Thread Chris Withers

Hi All,

The script at the end of this message blows up with:

sqlalchemy.exc.InvalidRequestError: When compiling mapper 
Mapper|Employee|employee, expression 'Organisation' failed to locate a 
name (name 'Organisation' is not defined). If this is a class name, 
consider adding this relation() to the class '__main__.Employee' class 
after both dependent classes have been defined.


...unless the line preceded with #yuk is present.

Why does declarative store this information in its own registry rather 
than using the MetaData to do so?


Is there a nicer way I can achieve this result? I have multiple bases 
since Michael suggested this was the right way to go to have base 
classes for mapped classes that do nothing but contain common field 
definitions and functionality...


cheers,

Chris

from sqlalchemy import create_engine, MetaData
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relation, sessionmaker
from sqlalchemy.schema import Column, ForeignKey
from sqlalchemy.types import Integer, String, DateTime

engine = create_engine('sqlite://')

metadata = MetaData()

Base1 = declarative_base(metadata=metadata)
Base2 = declarative_base(metadata=metadata)

# yuk
Base2._decl_class_registry=Base1._decl_class_registry

class Employee(Base1):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
name = Column(String(1000), nullable=False, index=True)
org = relation(Organisation)
org_id = Column(Integer, ForeignKey('organisation.id'))

class Organisation(Base2):
__tablename__ = 'organisation'
id = Column(Integer, primary_key=True)
name = Column(String(50))
employees = relation(Employee)

metadata.create_all(engine)

o = Organisation(name='SomeOrg')

--
Simplistix - Content Management, Batch Processing  Python Consulting
- http://www.simplistix.co.uk

--
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@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.



Re: [sqlalchemy] any way to pre cook a monster query?

2010-02-02 Thread Chris Withers

Michael Bayer wrote:

Piecing together a select() construct and compiling to a string is a
relatively inexpensive operation.The vast majority of time in Query is
spent about 1/3rd-half on the database side and the rest in fetching rows
and instantiating/populating objects. 


Fair enough.


has to traverse mapped classes to generate.   But its a fraction of what
it takes to fetch rows, and in that area we'd ultimately like to
reimplement that part in C.


I hope the use of the C part always remains thoroughly optional, since C 
extensions cause a world of pain in a lot of situations...


snip

All of that said we are always welcome to patches and new core developer
candidates since a really well designed implementation of such is
certainly something we can look for - particularly if it could be a
pluggable option that people don't have to use, which would allow it to
become mature on its own as its used by people without impacting the
current userbase.


Thanks for the thorough coverage of this, it's verymuch appreciated. Now 
that I understand more about what's going on during the query process, 
I'm in total agreement with you :-)


cheers,

Chris

--
Simplistix - Content Management, Batch Processing  Python Consulting
- http://www.simplistix.co.uk

--
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@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.



[sqlalchemy] insert with scalar select statament

2010-02-02 Thread Manlio Perillo
-BEGIN PGP SIGNED MESSAGE-
Hash: SHA1

Hi.

I have written a small class in order to support PostgreSQL tsearch type:

class TextSearchVector(UserDefinedType):
Support for full-text search
See
http://www.postgresql.org/docs/8.4/static/datatype-textsearch.html


 def get_col_spec(self):
return 'tsvector'


The problem with this code is that a string is converted to a tsearch
type without first normalizing it; this can also cause a syntax error.

The solution is to use the `to_tsearch` function.

In SQL (tested with PostgreSQL and SQLite, at least) I can do:
INSERT INTO test (text) values(to_tsvector('some text'));

That is, it is possible to specify a scalar select statement for each value.


Is this possible to do with SQLAlchemy?

It seems to me that it is not possible.
It is not possible to specify an SQL scalar select statement in a custom
type bind_processor method, and it is not possible to specify an SQL
scalar select statement in an insert statement.

Can this be solved using SQLAlchemy?
Or should I simply use triggers?


Thanks  Manlio
-BEGIN PGP SIGNATURE-
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAktoc0IACgkQscQJ24LbaUQ/EgCeIKThU9dV8DZT0qampIR1iHRx
bP4AoI1/DPoEXRyewZGHLs6LF8DdCRZp
=YKtw
-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 sqlalch...@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.



Re: [sqlalchemy] relations and multiple declarative bases

2010-02-02 Thread Michael Bayer
Chris Withers wrote:
 Hi All,

 The script at the end of this message blows up with:

 sqlalchemy.exc.InvalidRequestError: When compiling mapper
 Mapper|Employee|employee, expression 'Organisation' failed to locate a
 name (name 'Organisation' is not defined). If this is a class name,
 consider adding this relation() to the class '__main__.Employee' class
 after both dependent classes have been defined.

 ...unless the line preceded with #yuk is present.

 Why does declarative store this information in its own registry rather
 than using the MetaData to do so?

MetaData is not an ORM aware object.  it doesn't store class names.


 Is there a nicer way I can achieve this result? I have multiple bases
 since Michael suggested this was the right way to go to have base
 classes for mapped classes that do nothing but contain common field
 definitions and functionality...

der, OK if I did actually say that, its obsolete information.  Use
http://www.sqlalchemy.org/trac/wiki/UsageRecipes/DeclarativeMixins .   Yes
the recipe will probably be built in someday once we have time to cover
all contingencies.

Or reference Organization directly without using a string for its name.



 cheers,

 Chris

 from sqlalchemy import create_engine, MetaData
 from sqlalchemy.ext.declarative import declarative_base
 from sqlalchemy.orm import relation, sessionmaker
 from sqlalchemy.schema import Column, ForeignKey
 from sqlalchemy.types import Integer, String, DateTime

 engine = create_engine('sqlite://')

 metadata = MetaData()

 Base1 = declarative_base(metadata=metadata)
 Base2 = declarative_base(metadata=metadata)

 # yuk
 Base2._decl_class_registry=Base1._decl_class_registry

 class Employee(Base1):
  __tablename__ = 'employee'
  id = Column(Integer, primary_key=True)
  name = Column(String(1000), nullable=False, index=True)
  org = relation(Organisation)
  org_id = Column(Integer, ForeignKey('organisation.id'))

 class Organisation(Base2):
  __tablename__ = 'organisation'
  id = Column(Integer, primary_key=True)
  name = Column(String(50))
  employees = relation(Employee)

 metadata.create_all(engine)

 o = Organisation(name='SomeOrg')

 --
 Simplistix - Content Management, Batch Processing  Python Consulting
  - http://www.simplistix.co.uk

 --
 You received this message because you are subscribed to the Google Groups
 sqlalchemy group.
 To post to this group, send email to sqlalch...@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.



-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@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.



Re: [sqlalchemy] More efficient Insert mechanism

2010-02-02 Thread Mati Skiva

Michael Bayer wrote:

Mati Skiva wrote:
  

I believe I took these issues into account.
But just to be sure, maybe you can highlight something for me.

I assume the followings about the process of session.add:
* after session.add is called, the objects are placed in a to-do pool
(maybe)
* for self-generating-id objects, a special process is used, one that
fetches the generated id after the insert
* for no self-generating-id objects, a regular process of insert is used

I came to this conclusion, because otherwise, after each insert all the
data of the row is retrieved and placed inside the object. Which covers
the newly generated id.



Since you're interested in hacking SQLAlchemy internals, it would helpful
if you could familiarize yourself fully with the SQL expression and
execution API, all of which is public and documented.   id generation is
a standard feature of this system and occurs outside of the ORM.  Fetching
the ID for a new row with the SQLA expression API is a matter of calling a
ResultProxy method which the ORM only calls if it doesn't already know the
full set of primary key columns for a specific object.   The backend
implementation of id fetching varies wildly across all dialects as well
as versions of each database in use.

The flush procedure updates or expires those fields of the object which
were known to be generated by the database.   Fields which are immediately
updated include some or all of the primary key columns.  Fields which are
expired include any other columns which were generated via server-side SQL
expressions or known schema-level defaults - these are fetched when the
object's expired attributes are next accessed, if at all.

The SQL compiler procedure is aware of these columns when it generates an
individual insert() construct, given a list of parameters which are to be
bound literals and others which are to be embedded SQL expressions.   When
executed, the ResultProxy API provides these details fully - you should
familiarize yourself with all of its methods.

I would also point you to http://www.sqlalchemy.org/trac/ticket/1518 ,
which suggests that we should open up Mapper to being subclassable (for
much more exotic purposes than what you have here).  However, this
subclassing is possible now, which is where you can have your insertmany
functionality rolled in a rudimental way for your immediate use case
without burdening SQLAlchemy core with the need to have a fully
tested/supported/performant feature.   See the attached example.

  

Thank you for the pointers, as well as the example.

I attempted using it, however quickly enough I was forced to dig into 
the internals. I shall explain why.


from inspecting mapper.py's _save_obj method, I found that after every 
insert the following items are required:


   * value_params - used by _postfetch
   * params - used by _postfetch
   * ResultProxy.last_inserted_params() - used by _postfetch
   * ResultProxy.postfetch_cols() - used within _postfetch
   * ResultProxy.prefetch_cols() - used within _postfetch
   * ResultProxy.last_inserted_ids() - used by by _save_obj

All of these items shared the same problem, they are all dictionaries or 
lists. One for each insert, making them single-dimension data (in 
respect to the insert).
But when executing many, they became either None or kept their 
single-dimension property (i.e. for two inserts, only one list is 
returned, when I expect a list of lists)


That alone prevented me from overloading _save_obj. Because I am 
required to have these items for every inserted row.



So, I set upon transforming these items into multi-dimensional upon 
execute-many.
It brought me to default.py's __process_defaults where I implemented the 
followings:


   def __process_defaults(self):
   generate default values for compiled insert/update statements,
   and generate last_inserted_ids() collection.
   if self.executemany:
   if len(self.compiled.prefetch):
   drunner = self.dialect.defaultrunner(self)
   params = self.compiled_parameters
   for param in params:
   # assign each dict of params to 
self.compiled_parameters;
   # this allows user-defined default generators to 
access the full

   # set of bind params for the row
   self.compiled_parameters = param
   for c in self.compiled.prefetch:
   if self.isinsert:
   val = drunner.get_column_default(c)
   else:
   val = drunner.get_column_onupdate(c)
   if val is not None:
   param[c.key] = val
   self.compiled_parameters = params

   if self.isinsert:
   self._last_inserted_ids = []
   self._last_inserted_params = []
  
   for compiled_parameters in self.compiled_parameters:

   drunner = 

Re: [sqlalchemy] insert with scalar select statament

2010-02-02 Thread Michael Bayer
Manlio Perillo wrote:
 -BEGIN PGP SIGNED MESSAGE-
 Hash: SHA1

 Hi.

 I have written a small class in order to support PostgreSQL tsearch type:

 class TextSearchVector(UserDefinedType):
 Support for full-text search
 See
 http://www.postgresql.org/docs/8.4/static/datatype-textsearch.html
 

  def get_col_spec(self):
 return 'tsvector'


 The problem with this code is that a string is converted to a tsearch
 type without first normalizing it; this can also cause a syntax error.

 The solution is to use the `to_tsearch` function.

 In SQL (tested with PostgreSQL and SQLite, at least) I can do:
 INSERT INTO test (text) values(to_tsvector('some text'));

 That is, it is possible to specify a scalar select statement for each
 value.


 Is this possible to do with SQLAlchemy?

 It seems to me that it is not possible.
 It is not possible to specify an SQL scalar select statement in a custom
 type bind_processor method, and it is not possible to specify an SQL
 scalar select statement in an insert statement.

 Can this be solved using SQLAlchemy?
 Or should I simply use triggers?

OK you mean SQL expression during compilation.   This is ticket #1534
which is not yet implemented.  Right now you'd have to set attributes to
the to_tsvector() expression directly, note that the ORM and such accept
SQL expressions as values.Which means if you're dealing just with ORM,
you can use a @validates or similar (and maybe a comparator too) that
wraps incoming values into to_tsvector().   The example in
examples/postgis/postgis.py illustrates these techniques.






 Thanks  Manlio
 -BEGIN PGP SIGNATURE-
 Version: GnuPG v1.4.10 (GNU/Linux)
 Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

 iEYEARECAAYFAktoc0IACgkQscQJ24LbaUQ/EgCeIKThU9dV8DZT0qampIR1iHRx
 bP4AoI1/DPoEXRyewZGHLs6LF8DdCRZp
 =YKtw
 -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 sqlalch...@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.



-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@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.



[sqlalchemy] engine.execute() vs text().execute()

2010-02-02 Thread Douglas Alan
Hi. I'm trying to track down a problem, and I'm wondering if the following
two statements are appreciably different? I would have thought they were
equivalent:

(1) result = engine.execute(myQuery)

(2) result = text(myQuery, engine).execute()


myQuery is a string containing a big, hairy SQL query that can take a
couple of hours to run under Oracle 10 before returning a ResultProxy
object. When using the first statement above, I'm always getting this Oracle
error:


  File /swu/lib/python2.6/site-packages/sqlalchemy/engine/base.py, line
931, in _handle_dbapi_exception
raise exc.DBAPIError.instance(statement, parameters, e,
connection_invalidated=is_disconnect)
sqlalchemy.exc.DatabaseError: (DatabaseError) ORA-01652: unable to extend
temp segment by 128 in tablespace TEMP

The query always runs fine, however, when I use the second statement.

|ouglas

P.S. I fully understand that the phenomenon I'm observing could be
completely coincidental, as it's difficult to confirm the correlation when
each attempt takes several hours.

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@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.



Re: [sqlalchemy] More efficient Insert mechanism

2010-02-02 Thread Michael Bayer
Mati Skiva wrote:
 from inspecting mapper.py's _save_obj method, I found that after every
 insert the following items are required:

 * value_params - used by _postfetch
 * params - used by _postfetch
 * ResultProxy.last_inserted_params() - used by _postfetch
 * ResultProxy.postfetch_cols() - used within _postfetch
 * ResultProxy.prefetch_cols() - used within _postfetch
 * ResultProxy.last_inserted_ids() - used by by _save_obj

 All of these items shared the same problem, they are all dictionaries or
 lists. One for each insert, making them single-dimension data (in
 respect to the insert).
 But when executing many, they became either None or kept their
 single-dimension property (i.e. for two inserts, only one list is
 returned, when I expect a list of lists)

the cols() methods return lists of column objects which correspond to the
structure of the insert.  Those apply to executemany() as well as
execute(), since both functions receive a single insert() construct of a
fixed form.   The value_params() similarly are fixed for the single insert
construct and do not change.last_inserted_ids() is not used in your
recipe - you are calculating primary key values en masse - DBAPI has no
way to give you this information.   The only value here that may be of
usage is last_inserted_params().  The only data in that collection which
is not present before the insert is executed are Python side defaults
which you may have configured on your Table.The full list of
everything inserted post-calculation of python-side defaults is present at
resultproxy.context.compiled_parameters.   Use 0.6, the code example you
mention is obsolete 0.5 code, and the compiled_parameters collection is
undisturbed.


 I was forced to make one extra change, for sqlite.py's post_exec method.
 Basically, populating the self._last_inserted_ids attribute. But for
 some reason self.cursor.lastrowid is None for execute-many (while it can

Here is the reason:

http://www.python.org/dev/peps/pep-0249/

Cursor Attribute .lastrowid

This read-only attribute provides the rowid of the last
modified row (most databases return a rowid only when a single
INSERT operation is performed). If the operation does not set
a rowid or if the database does not support rowids, this
attribute should be set to None.

The semantics of .lastrowid are undefined in case the last
executed statement modified more than one row, e.g. when
using INSERT with .executemany().

Also be aware that .lastrowid is not implemented at all for:

psycopg2, pg8000, cx_oracle, kintersbasdb, pyodbc, pymssql, adodbapi, etc.

I'm strongly opposed to forcing a multi-row version of last_inserted_ids()
into dialects.   It cannot work consistently or predictably, and is not
supported by DBAPI.

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@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.



Re: [sqlalchemy] insert with scalar select statament

2010-02-02 Thread Manlio Perillo
-BEGIN PGP SIGNED MESSAGE-
Hash: SHA1

Michael Bayer ha scritto:
 [...]
 In SQL (tested with PostgreSQL and SQLite, at least) I can do:
 INSERT INTO test (text) values(to_tsvector('some text'));
 
 That is, it is possible to specify a scalar select statement for each
 value.
 
 
 Is this possible to do with SQLAlchemy?
 
 [...]
 OK you mean SQL expression during compilation.   This is ticket #1534
 which is not yet implemented.  


After some tests I got something that works
http://paste.pocoo.org/show/173099/

The documentation seems to confirm this:
http://www.sqlalchemy.org/docs/reference/sqlalchemy/expressions.html#sqlalchemy.sql.expression.insert

SQLAlchemy still continues to surprise me!
I need to download the documentation in PDF format, and take some time
study it.

I don't know if an example of this feature is available in the tutorial;
if not, it should be added.


Right now you'd have to set attributes to
 the to_tsvector() expression directly, note that the ORM and such accept
 SQL expressions as values.Which means if you're dealing just with ORM,
 you can use a @validates or similar (and maybe a comparator too) that
 wraps incoming values into to_tsvector().   

It is 4 years that I don't touch the ORM ;-).

The example in
 examples/postgis/postgis.py illustrates these techniques.
 


Thanks  Manlio
-BEGIN PGP SIGNATURE-
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAktogfkACgkQscQJ24LbaUSjwgCfevuSHb0YjMGNMFXhm+imJHqY
YSsAn1wypa/GG86TfGHMIGbFvf9lctVN
=eqiB
-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 sqlalch...@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.



Re: [sqlalchemy] insert with scalar select statament

2010-02-02 Thread Michael Bayer
Manlio Perillo wrote:
 -BEGIN PGP SIGNED MESSAGE-
 Hash: SHA1

 Michael Bayer ha scritto:
 [...]
 In SQL (tested with PostgreSQL and SQLite, at least) I can do:
 INSERT INTO test (text) values(to_tsvector('some text'));

 That is, it is possible to specify a scalar select statement for each
 value.


 Is this possible to do with SQLAlchemy?

 [...]
 OK you mean SQL expression during compilation.   This is ticket #1534
 which is not yet implemented.


 After some tests I got something that works
 http://paste.pocoo.org/show/173099/

 The documentation seems to confirm this:
 http://www.sqlalchemy.org/docs/reference/sqlalchemy/expressions.html#sqlalchemy.sql.expression.insert

 SQLAlchemy still continues to surprise me!
 I need to download the documentation in PDF format, and take some time
 study it.

 I don't know if an example of this feature is available in the tutorial;
 if not, it should be added.

errr, you can put SQL expressions into insert.values(), but not in the
params sent to execute() (that was discontinued after 0.4).   the example
you have is actually executing the sql.select() statement beforehand since
thats what scalar() does.

you're looking for

query = test.insert().values(text=sql.func.to_tsvector(u'some text'))
engine.execute(query)



-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@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.



Re: [sqlalchemy] insert with scalar select statament

2010-02-02 Thread Manlio Perillo
-BEGIN PGP SIGNED MESSAGE-
Hash: SHA1

Michael Bayer ha scritto:
 Manlio Perillo wrote:
 [...]
 OK you mean SQL expression during compilation.   This is ticket #1534
 which is not yet implemented.

 After some tests I got something that works
 http://paste.pocoo.org/show/173099/

 [...]
 
 errr, you can put SQL expressions into insert.values(), but not in the
 params sent to execute() (that was discontinued after 0.4). 


I have never used the values method.
Is this a recent feature?

  the example
 you have is actually executing the sql.select() statement beforehand since
 thats what scalar() does.
 
 you're looking for
 
 query = test.insert().values(text=sql.func.to_tsvector(u'some text'))
 engine.execute(query)


Thanks.

Manlio
-BEGIN PGP SIGNATURE-
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAktolCUACgkQscQJ24LbaURINgCglj+N2JKqkWit1/DFCEBff2Kd
7fsAn0F8Y5mUCYyqWSxydosxk36RzsGZ
=VHYH
-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 sqlalch...@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.



Re: [sqlalchemy] insert with scalar select statament

2010-02-02 Thread Michael Bayer
Manlio Perillo wrote:
 -BEGIN PGP SIGNED MESSAGE-
 Hash: SHA1

 Michael Bayer ha scritto:
 Manlio Perillo wrote:
 [...]
 OK you mean SQL expression during compilation.   This is ticket #1534
 which is not yet implemented.

 After some tests I got something that works
 http://paste.pocoo.org/show/173099/

 [...]

 errr, you can put SQL expressions into insert.values(), but not in the
 params sent to execute() (that was discontinued after 0.4).


 I have never used the values method.
 Is this a recent feature?

couple of years old at this point...goes back to 0.4 at least


  the example
 you have is actually executing the sql.select() statement beforehand
 since
 thats what scalar() does.

 you're looking for

 query = test.insert().values(text=sql.func.to_tsvector(u'some text'))
 engine.execute(query)


 Thanks.

 Manlio
 -BEGIN PGP SIGNATURE-
 Version: GnuPG v1.4.10 (GNU/Linux)
 Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

 iEYEARECAAYFAktolCUACgkQscQJ24LbaURINgCglj+N2JKqkWit1/DFCEBff2Kd
 7fsAn0F8Y5mUCYyqWSxydosxk36RzsGZ
 =VHYH
 -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 sqlalch...@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.



-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@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.



Re: [sqlalchemy] passive updates and concurrent mod error

2010-02-02 Thread Michael Bayer
avdd wrote:
 Something a bit more normal now.

 Combining optimistic concurrency control with cascading PK updates is
 problematic, if you load the child relation, the session issues
 unecessary updates for the children, resulting in
 ConcurrentModificationError


this issue is fixed in trunk as of r6719.  mapper() now has a
passive_updates flag set to True by default.  The caveat for now is that
to run this test script on SQLite or MySQL/MyISAM requires setting the
flag to False, since the mapper has to make a definitive yes/no decision
on if it can assume a PK-FK change must occur via CASCADE or not, which
determines if it has to use the new or old PK value of the row in order to
locate it.   will look into automating this flag in a future release based
on dialect/table options.




 

 import sqlalchemy as sql
 from sqlalchemy import orm
 from sqlalchemy.ext.declarative import declarative_base

 __metaclass__ = type

 engine = sql.create_engine(postgresql:///avdd)
 metadata = sql.MetaData(bind=engine)
 db = orm.create_session(bind=engine, autocommit=False)
 T = declarative_base(metadata=metadata)

 class P(T):
 __tablename__ = 'p'
 id = sql.Column(sql.String, primary_key=True)
 version = sql.Column(sql.Integer, nullable=False, default=1)
 cc = orm.relation('C', backref='parent', passive_updates=True)
 __mapper_args__ = {'version_id_col': version}

 class C(T):
 __tablename__ = 'c'
 i = sql.Column(sql.String, primary_key=True)
 p = sql.Column(sql.String,
sql.ForeignKey('p.id', onupdate='cascade',
 ondelete='cascade'),
primary_key=True)
 version = sql.Column(sql.Integer, nullable=False, default=1)
 __mapper_args__ = {'version_id_col': version}

 metadata.create_all()
 P.__table__.delete().execute()

 with db.transaction:
 p = P(id='P1', cc=[C(i='C.1'), C(i='C.2')])
 db.add(p)

 db.expunge_all()
 p = db.query(P).first()

 with db.transaction:
 p.id = 'P2'
 # ok, no ConcModError

 db.expunge_all()
 p = db.query(P).first()

 with db.transaction:
 p.id = 'P3'
 p.cc
 # issues spurious updates, throws ConcModError

 

 --
 You received this message because you are subscribed to the Google Groups
 sqlalchemy group.
 To post to this group, send email to sqlalch...@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.



-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@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.