Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

document how to use super_user #44

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -374,3 +374,89 @@ To mark a migration as deferred means to ignore a migration when running ``migra
20151217170514_add_id_to_ deferred None
20151218145832_add_karen_ False
20160107200351_blah False

Super_user
----------

Note the template for migrations mentions a second cursor context manager available for running steps as a
database superuser, be default `postgres`. This is useful if you want to use a less priviliged user for most
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"be default" => "by default"

DB interactions, but occasionally need a db_superuser, to do something like create a function in an untrusted
language.


For example, with best practice would be to use two migrations:

``migrations/20170905134614_create_py_update_sha1.py``::

def up(cursor):
with super_user() as super_cursor:
super_cursor.execute("""
CREATE OR REPLACE FUNCTION update_sha1()
RETURNS TRIGGER
AS $$
import hashlib

TD['new']['sha1'] = hashlib.new('sha1', TD['new']['file']).hexdigest()
return 'MODIFY'
$$ LANGUAGE plpythonu;
""")


def down(cursor):
with super_user() as super_cursor:
super_cursor.execute("""DROP FUNCTION update_sha1()""")

and

``migrations/20170905134722_create_update_sha1_trigger.py``::

def up(cursor):
cursor.execute("""CREATE TRIGGER files_update_sha1
BEFORE INSERT OR UPDATE OF file ON files
FOR EACH ROW EXECUTE PROCEDURE update_sha1()
""")


def down(cursor):
cursor.execute("""DROP TRIGGER files_update_sha1 ON files""")

By seperating into two migrations, the function created by the super_user connection is
available to the less priviliged user to create the trigger on the table owned by them.

If you wish to combine these into a single migration, it is necessary to call `commit`
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was not necessary for me. See #43 (comment)

on the connection of any cursor that needs to have its results visible to another cursor
in the same migration function:

``migrations/20170905134722_create_update_sha1_trigger.py``::

def up(cursor):
with super_user() as super_cursor:
super_cursor.execute("""
CREATE OR REPLACE FUNCTION update_sha1()
RETURNS TRIGGER
AS $$
import hashlib

TD['new']['sha1'] = hashlib.new('sha1', TD['new']['file']).hexdigest()
return 'MODIFY'
$$ LANGUAGE plpythonu;
""")

super_cursor.connection.commit()

# Would error with "no such function"
cursor.execute("""CREATE TRIGGER files_update_sha1
BEFORE INSERT OR UPDATE OF file ON files
FOR EACH ROW EXECUTE PROCEDURE update_sha1()
""")


def down(cursor):
cursor.execute("""DROP TRIGGER files_update_sha1 ON files""")

cursor.connection.commit()

# Would error w/ "cannot drop other object depend on it"
with super_user() as super_cursor:
super_cursor.execute("""DROP FUNCTION update_sha1()""")