Re: [pysqlite] problems grokking SQL
Gerhard Häring <[email protected]> Tue, 14 Apr 2009 21:59:59 +0200
| Newsgroups | gmane.comp.python.db.pysqlite.user |
|---|---|
| Message-ID | <[email protected]> |
This is a multi-part message in MIME format.
--------------080809050504060206030803
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
Eric S. Johansson wrote:
> [how to do these:]
>
> read/modify/write cycle. how do I do this and guarantee the data will make it
> to the database without locking out others.
>
> read a record, do a calculation in python and then write the record as above.
>
> if record field named state is X, change it to Y
>
> delete all records older than D. (yes,I have an sqlite datestamp record)
>
> modify/insert. modify if record exists, insert if it doesn't. handle race
> condition of multiple processes updating.
See attachment (also in SCM here):
http://oss.itsystementwicklung.de/trac/pysqlite/browser/misc/patterns.py
> we really should build an faq or idioms list for this kind of thing.
Agreed. This could be a start.
-- Gerhard
--------------080809050504060206030803
Content-Type: text/plain; x-mac-type="0"; x-mac-creator="0";
name="patterns.py"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="patterns.py"
from __future__ import with_statement
from pysqlite2 import dbapi2 as sqlite3
from datetime import datetime, timedelta
import time
def read_modify_write():
# Open connection and create example schema and data.
# In reality, open a database file instead of an in-memory database.
con = sqlite3.connect(":memory:")
cur = con.cursor()
cur.executescript("""
create table test(id integer primary key, data);
insert into test(data) values ('foo');
insert into test(data) values ('bar');
insert into test(data) values ('baz');
""")
# The read part. There are two ways for fetching data using pysqlite.
# 1. "Lazy-reading"
# cur.execute("select ...")
# for row in cur:
# ...
#
# Advantage: Low memory consumption, good for large resultsets, data is
# fetched on demand.
# Disadvantage: Dataase locked as long as you iterate over cursor.
#
# 2. "Eager reading"
# cur.fetchone() to fetch one row
# cur.fetchall() to fetch all rows
# Advantage: Locks cleared ASAP.
# Disadvantage: fetchall() may build large lists.
cur.execute("select id, data from test where id=?", (2,))
row = cur.fetchone()
# Stupid way to modify the data column.
lst = list(row)
lst[1] = lst[1] + " & more"
# This is the suggested recipe to modify data using pysqlite. We use
# pysqlite's proprietary API to use the connection object as a context
# manager. This is equivalent to the following code:
#
# try:
# cur.execute("...")
# except:
# con.rollback()
# raise
# finally:
# con.commit()
#
# This makes sure locks are cleared - either by commiting or rolling back
# the transaction.
#
# If the rollback happens because of concurrency issues, you just have to
# try again until it succeeds. Much more likely is that the rollback and
# the raised exception happen because of other reasons, though (constraint
# violation, etc.) - don't forget to roll back on errors.
#
# Or use this recipe. It's useful and gets everything done in two lines of
# code.
with con:
cur.execute("update test set data=? where id=?", (lst[1], lst[0] * 1000))
def delete_older_than():
# Use detect_types if you want to use date/time types in pysqlite.
con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_COLNAMES)
cur = con.cursor()
# With "DEFAULT current_timestamp" we have SQLite fill the timestamp column
# automatically.
cur.executescript("""
create table test(id integer primary key, data, created timestamp default current_timestamp);
""")
with con:
for i in range(3):
cur.execute("insert into test(data) values ('foo')")
time.sleep(1)
# Delete older than certain interval
# SQLite uses UTC time, so we need to create these timestamps in Python, too.
with con:
delete_before = datetime.utcnow() - timedelta(seconds=2)
cur.execute("delete from test where created < ?", (delete_before,))
def modify_insert():
# Use a unique index and the REPLACE command to have the "insert if not
# there, but modify if it is there" pattern. Race conditions are taken care
# of by transactions.
con = sqlite3.connect(":memory:")
cur = con.cursor()
cur.executescript("""
create table test(id integer primary key, name, age);
insert into test(name, age) values ('Adam', 18);
insert into test(name, age) values ('Eve', 21);
create unique index idx_test_data_unique on test(name);
""")
# Modify record 'foo' to have data 'boo'
with con:
# Make Adam age 19
cur.execute("replace into test(name, age) values ('Adam', 19)")
# Create new entry
cur.execute("replace into test(name, age) values ('Abel', 3)")
if __name__ == "__main__":
read_modify_write()
delete_older_than()
modify_insert()
--------------080809050504060206030803
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
_______________________________________________
list-pysqlite mailing list
list-pysqlite-FR6EJeJVuqdwc357pe9rcyQmJico6nz3epZhswDD4dQ@public.gmane.org
http://itsystementwicklung.de/cgi-bin/mailman/listinfo/list-pysqlite
--------------080809050504060206030803--