[sqlalchemy] Re: Column to default to itself

2007-04-13 Thread Ants Aasma

On Apr 13, 1:47 pm, "Koen Bok" <[EMAIL PROTECTED]> wrote:
> request_table = Table('request', metadata,
> Column('id', Integer, primary_key=True),
> Column('number', Integer, unique=True, nullable=True,
> default=text('(SELECT coalesce(max(number), 0) + 1 FROM 
> request)')))
>
> This seems to work well. But is  this a good way to do this or can it
> cause complications?

This will start to throw duplicate key errors under heavier load.
There is a window of time between insert and commit when another
insert will get the same duplicate id. It might not be a problem in
your case, but I have had to deal with a similar problem when creating
sequentally hashed database table (for provable temporal ordering and
integrity) which will see very high loads. You'll either occasionally
get duplicate values in the database or you have to serialize all
inserts. The best that can be done, is try to occasionally get holes
and assume that usually transactions succeed and catch rollbacks. That
is a lot harder.

Ants


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



[sqlalchemy] Re: Column to default to itself

2007-04-13 Thread Koen Bok

request_table = Table('request', metadata,
Column('id', Integer, primary_key=True),
Column('number', Integer, unique=True, nullable=True,
default=text('(SELECT coalesce(max(number), 0) + 1 FROM 
request)')))

This seems to work well. But is  this a good way to do this or can it
cause complications?

On Apr 13, 11:23 am, "Koen Bok" <[EMAIL PROTECTED]> wrote:
> Ok, I'd rather handle it on the database level. Is that just a matter
> of creating a function and calling it on insert?
>
> Koen
>
> On Apr 13, 4:47 am, "Ants Aasma" <[EMAIL PROTECTED]> wrote:
>
> > On Apr 13, 2:47 am, Jorge Godoy <[EMAIL PROTECTED]> wrote:
>
> > > IF you insist on doing that at your code, make the column UNIQUE (or a
> > > PK...) and write something like this pseudocode:
>
> > > def save_data():
> > > def insert_data():
> > >try:
> > >unique_column_value = get_max_from_unique_column
> > >Class(unique_column_value + 1, 'other data')
> > >except YourDBExceptionForConstraintViolation:
> > >sleep(random.random())
> > >insert_data()
>
> > > The 'sleep(random.random())' is there to avoid constant clashes and to
> > > be "fair" to all connections that are inserting data on your table.
>
> > To get an uninterrupted number sequence you need to serialize your
> > inserts to that specific entity, for which you basically need locking.
> > The quoted approach is optimistic locking, where you hope that no one
> > tries to insert another row between when you use the
> > get_max_from_unique_column and do the database commit, but are ready
> > to retry if that expectation fails. Another way would be to use
> > pessimistic locking, by doing the get_max_from_unique_column query
> > with lockmode='update'. Then any other thread trying to insert another
> > row while you're busy inserting yours will have to wait.


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



[sqlalchemy] Re: Column to default to itself

2007-04-13 Thread Ants Aasma

On Apr 13, 12:23 pm, "Koen Bok" <[EMAIL PROTECTED]> wrote:
> Ok, I'd rather handle it on the database level. Is that just a matter
> of creating a function and calling it on insert?

You need a sequence that has locks and rolls back on rollback.
Simplest way is to use a table: CREATE TABLE sequences (name
varchar(100) not null primary key, value int not null default 0);
and a stored proc to get the next id, in postgresql that would be
CREATE FUNCTION next_id(varchar) RETURNS int AS $$
DECLARE id int;
BEGIN
UPDATE sequences SET value = value + 1 WHERE name = $1;
SELECT value INTO id FROM sequences WHERE name = $1;
RETURN id;
END
$$ LANGUAGE plpgsql;

Then say you have table bar, you initialize the sequence:
INSERT INTO sequences ('bar', 0);
And create the table:
CREATE TABLE bar (bar_id int NOT NULL DEFAULT next_id('bar') PRIMARY
KEY, ...);
or in SA:
Table('bar',
Column('id', Integer, primary_key=True,
default=func.next_id('bar')), ...
)

Ants


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



[sqlalchemy] Re: Column to default to itself

2007-04-13 Thread Koen Bok

Ok, I'd rather handle it on the database level. Is that just a matter
of creating a function and calling it on insert?

Koen

On Apr 13, 4:47 am, "Ants Aasma" <[EMAIL PROTECTED]> wrote:
> On Apr 13, 2:47 am, Jorge Godoy <[EMAIL PROTECTED]> wrote:
>
> > IF you insist on doing that at your code, make the column UNIQUE (or a
> > PK...) and write something like this pseudocode:
>
> > def save_data():
> > def insert_data():
> >try:
> >unique_column_value = get_max_from_unique_column
> >Class(unique_column_value + 1, 'other data')
> >except YourDBExceptionForConstraintViolation:
> >sleep(random.random())
> >insert_data()
>
> > The 'sleep(random.random())' is there to avoid constant clashes and to
> > be "fair" to all connections that are inserting data on your table.
>
> To get an uninterrupted number sequence you need to serialize your
> inserts to that specific entity, for which you basically need locking.
> The quoted approach is optimistic locking, where you hope that no one
> tries to insert another row between when you use the
> get_max_from_unique_column and do the database commit, but are ready
> to retry if that expectation fails. Another way would be to use
> pessimistic locking, by doing the get_max_from_unique_column query
> with lockmode='update'. Then any other thread trying to insert another
> row while you're busy inserting yours will have to wait.


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



[sqlalchemy] Re: Column to default to itself

2007-04-12 Thread Ants Aasma

On Apr 13, 2:47 am, Jorge Godoy <[EMAIL PROTECTED]> wrote:
> IF you insist on doing that at your code, make the column UNIQUE (or a
> PK...) and write something like this pseudocode:
>
> def save_data():
> def insert_data():
>try:
>unique_column_value = get_max_from_unique_column
>Class(unique_column_value + 1, 'other data')
>except YourDBExceptionForConstraintViolation:
>sleep(random.random())
>insert_data()
>
> The 'sleep(random.random())' is there to avoid constant clashes and to
> be "fair" to all connections that are inserting data on your table.

To get an uninterrupted number sequence you need to serialize your
inserts to that specific entity, for which you basically need locking.
The quoted approach is optimistic locking, where you hope that no one
tries to insert another row between when you use the
get_max_from_unique_column and do the database commit, but are ready
to retry if that expectation fails. Another way would be to use
pessimistic locking, by doing the get_max_from_unique_column query
with lockmode='update'. Then any other thread trying to insert another
row while you're busy inserting yours will have to wait.


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



[sqlalchemy] Re: Column to default to itself

2007-04-12 Thread Jorge Godoy

"Koen Bok" <[EMAIL PROTECTED]> writes:

> I need to have a uninterrupted number sequence in my table for
> invoices. I was trying to do it like this, but I can't get it to work.
> Can anyone give me a hint?

Let your database do the job.  It is always aware of all connections
made to it, their contexts, their priorities, what transaction isolation
level is being used, etc.

It will be better on this task.

IF you insist on doing that at your code, make the column UNIQUE (or a
PK...) and write something like this pseudocode:


def save_data():
def insert_data():
   try:
   unique_column_value = get_max_from_unique_column
   Class(unique_column_value + 1, 'other data')
   except YourDBExceptionForConstraintViolation:
   sleep(random.random())
   insert_data()

The 'sleep(random.random())' is there to avoid constant clashes and to
be "fair" to all connections that are inserting data on your table.



-- 
Jorge Godoy  <[EMAIL PROTECTED]>


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