Brady Ouren

Postgres savepoint

Postgres savepoint and try/catch

I ran into a simple, but necessary bit of postgres knowledge this week while using a bloom filter to purge outdated database entries. The problem I encountered was within a try/catch block. I was catching a ForeignKeyError if the deletion of a row failed. Since I was doing this transaction within a cursor, I would get an error along the lines of: "Current transaction is aborted, commands ignored until end of transaction block"

The fix

Fortunately, to fix this you just add a savepoint within the try block to rollback to in case of an exception. I’ll give a bit of an example.

query = 'declare myc cursor for select * from tableToCheck'

You need to declare a cursor name (in this case ‘myc’) for the transaction to use.

def purge_filter(postgres_conn, query, del_query, bloom):
''' pass in an initialized bloom filter
and the queries for a smooth postgres transaction'''
def cursor_function(cursor)
cursor.execute('BEGIN')
cursor.execute(query)
while True:
cursor.execute('fetch myc')
row = cursor.fetchall()
if not row:
break
_id = row[0]
if _id not in bloom:
try:
# set the savepoint for rollback in case of exception
cursor.execute('savepoint s1')
cursor.execute(del_query, (_id,)) # id to be deleted
except ForeignKeyError:
cursor.execute('rollback to savepoint s1')
cursor.execute('COMMIT')
# pass the function to psycopg2 to run the transaction
postgres_conn.run(cursor_function)
view raw gistfile1.py hosted with ❤ by GitHub