Build in Python rather than banging your head against PL/PGSQL • Utilize PyPi packages • Use a network connection (ZMQ anyone?) • Retrofit features on a large/complex/ proprietary system Tuesday, March 13, 12
You can log directly to PostgreSQL’s log file with: plpy.notice(“<msg>”) plpy.debug(“<msg>”) plpy.error(“<msg>”) plpy.fatal(“<msg>”) Tuesday, March 13, 12
and debug • Can easily confuse your DBA (if that isn’t you) • Not exactly slow, but definitely not free • Use with caution: This should be in your back of tricks if you need it, but use sparingly • Requires superuser privs and no virtualenvs Tuesday, March 13, 12
Enforce constraints across teams/devs/ languages • Protect data integrity from ad hoc queries • Change/Add features at the DB level when you can’t at the app level Tuesday, March 13, 12
OR REPLACE FUNCTION check_active() returns trigger AS $$ class NotActive(Exception): pass if not TD["old"]["is_active"]: raise NotActive $$ LANGUAGE plpythonu; Tuesday, March 13, 12
returns trigger AS $$ class NotActive(Exception): pass if not TD["old"]["is_active"] and not TD["new"]["is_active"]: raise NotActive $$ LANGUAGE plpythonu; Tuesday, March 13, 12
AFTER, or INSTEAD OF TD[“level”] ROW or STATEMENT TD[“new”]/TD[“old”] New and Old data TD[“name”] Name of trigger TD[“table_name”] Table trigger called on TD[“table_schema”] Schema table is in TD[“args”] Arguments to trigger function Tuesday, March 13, 12
returns boolean AS $$ sum = 0 num_digits = len(ccnum) for count in range(0, num_digits): digit = int(card_number[count]) if not (( count & 1 ) ^ oddeven ): digit = digit * 2 if digit > 9: digit = digit - 9 sum = sum + digit if sum & 10 == 0: return True else: return False $$ LANGUAGE plpythonu; Tuesday, March 13, 12
redis to_user = TD["new"]["to_user"] unread_key = "unread-%s" % to_user r = redis.Redis() if not TD["old"]["read"] and TD["new"]["read"]: r.decr(unread_count_key) else: r.incr(unread_count_key) $$ LANGUAGE plpythonu; For UPDATEs... Tuesday, March 13, 12
ON msgs FOR EACH ROW EXECUTE PROCEDURE handle_insert(); CREATE TRIGGER counter_update AFTER UPDATE ON msgs FOR EACH ROW EXECUTE PROCEDURE handle_update(); CREATE TRIGGER counter_delete AFTER DELETE ON msgs FOR EACH ROW EXECUTE PROCEDURE handle_delete(); Tuesday, March 13, 12
AS $$ if TD[“new”][“active”] == False: plpy.execute( “INSERT INTO finished_tickets (ticket_id) VALUES (%d)” % TD[“new”] [“id”] $$ LANGUAGE plpythonu; Tuesday, March 13, 12
the DB to avoid round trips • Build and maintain materialized views • Regenerate expensive reports only when the underlying data changes enough to warrant it Tuesday, March 13, 12
• Expire/repopulate caches • Fire off celery tasks • Trigger backups based on % of data changed • Hit external APIs based on conditions • Lots of fun to be had with ZeroMQ... Tuesday, March 13, 12
your system with data based on INSERTs in another • Want an SMS when your boss adds a ticket to Trac, but don’t want to dive into the code? Tuesday, March 13, 12