Skip to content

Instantly share code, notes, and snippets.

@danielrichman
Last active December 20, 2015 15:39
Show Gist options
  • Save danielrichman/6155810 to your computer and use it in GitHub Desktop.
Save danielrichman/6155810 to your computer and use it in GitHub Desktop.
2 contextmanager helpers to run PostgreSQL queries with savepoints and deferred constraints
@contextlib.contextmanager
def with_savepoint(postgres, name="temp_savepoint"):
"""
A context manager that wraps database queries in a PostgreSQL savepoint
Usage::
with with_savepoint(postgres, name='my_savepoint) as rollback:
do_something()
if something:
rollback() # rolls back to the start of the with block
"""
with postgres.cursor() as cur:
cur.execute("SAVEPOINT " + name)
def rollback():
cur.execute("ROLLBACK TO SAVEPOINT " + name)
try:
yield rollback
except Exception:
raising = True
raise
else:
raising = False
finally:
try:
cur.execute("RELEASE SAVEPOINT " + name)
except Exception:
# don't squash the original exception
if not raising:
raise
else:
logger.exception("suppressing exception")
@contextlib.contextmanager
def with_deferred_constraint(postgres, name):
"""
A context manager that deferrs a constraint within a with: block
Usage::
with with_deferred_constraint(postgres, 'my_constraint'):
some_queries()
Note: assumes the constraints were set to IMMEDIATE beforehand
(the default).
"""
with postgres.cursor() as cur:
cur.execute("SET CONSTRAINTS " + name + " DEFERRED")
try:
yield
except Exception:
raising = True
raise
else:
raising = False
finally:
try:
cur.execute("SET CONSTRAINTS " + name + " IMMEDIATE")
except Exception:
# don't squash the original exception
if not raising:
raise
else:
logger.exception("suppressing exception")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment