exceptable
DESCRIPTION
Exceptable - Useful database stored procedure exceptions in your application layer.TRANSCRIPT
Exceptable
Tuesday, October 20, 2009
Exception Propagation, in PostgreSQL and PythonAurynn Shaw, Commandprompt, Inc.
PostgreSQL Conference West, 2009
Tuesday, October 20, 2009
Background
• Large, enterprise Python + Pylons application
• Simpycity ORM utilizes significant stored procedures
• Strong procedural interfaces
Tuesday, October 20, 2009
Stored Procedures are Rare
• Most people don’t use Stored Procedures.
Tuesday, October 20, 2009
The Present SystemWherein
• A Database Query
• A Stored Procedure
• Or, A Database Query
• Exceptions Galore
Tuesday, October 20, 2009
A Database Query
•The App queries the Database
Tuesday, October 20, 2009
A Database Query
• The App queries the Database
• Any variety of query
Tuesday, October 20, 2009
A Database Query
>>> c.Raw("SELECT * FROM auth_only")()
Traceback (most recent call last):
... <SNIP> ...
psycopg2.ProgrammingError: permission denied for relation auth_only
Tuesday, October 20, 2009
A Database Query
• The App queries the Database
• Any variety of query
• Or A Stored Procedure
Tuesday, October 20, 2009
Or a Stored Procedure
CREATE OR REPLACE FUNCTION except_test() RETURNS VOID AS $$
BEGIN
RAISE EXCEPTION 'Test!';
END;
$$ LANGUAGE PLPGSQL;
>>> c.Function("except_test")()
Traceback (most recent call last):
... <SNIP> ...
psycopg2.InternalError: Test!
Tuesday, October 20, 2009
Beget an Exception
• Stored procedures raise InternalErrors
• Every procedural exception becomes this
• Permissions violations raise ProgrammingErrors
• I haven’t tested if this is all PG exceptions.
Tuesday, October 20, 2009
Seriously?
• This is what we have to work with?
Tuesday, October 20, 2009
Why this is ImportantWherein
• Why?
• Defining your APIs
• Separation of Concerns
• Procedural Spaghetti
Tuesday, October 20, 2009
Why?
• Limited information to propagate upwards
• Stored Procedures are Harder to use
• Permissions violations are difficult to detect
Tuesday, October 20, 2009
API Undefined
• Exceptions are part of your API
Tuesday, October 20, 2009
API Undefined
• Exceptions are part of your API
• Easily overlooked
Tuesday, October 20, 2009
API Undefined
• Exceptions are part of your API
• Easily overlooked
• Delineations will make life easier
Tuesday, October 20, 2009
Separation of Concerns
• The Database is for Database Logic
Tuesday, October 20, 2009
Separation of Concerns
• The Database is for Database Logic
• Harder to write Data Logic
Tuesday, October 20, 2009
Spaghetti
• InternalErrors everywhere
Early version of our app didn’t have Exceptable - we were left catching InternalErrors and guessing at what the error was, based on timing.
Tuesday, October 20, 2009
Spaghetti
• InternalErrors everywhere
• Insufficiency of Information
Tuesday, October 20, 2009
Spaghetti
• InternalErrors everywhere
• Insufficiency of Information
• Considerable Repeated Code
Tuesday, October 20, 2009
A Saving Grace
• Violating Procedure Signatures -> Python DataError
Tuesday, October 20, 2009
A Better DealWherein
• Database API
• Easy Python implementation
• Universality
• Exceptable
Tuesday, October 20, 2009
Database API
• Easier to define an API
Tuesday, October 20, 2009
Database API
• Easier to define an API
• The DB becomes part of that API
Tuesday, October 20, 2009
Database API
• Easier to define an API
• The DB becomes part of that API
• Simple Stored Procedure interface
Tuesday, October 20, 2009
Database API
• Easier to define an API
• The DB becomes part of that API
• Simple Stored Procedure interface
• Easily declare new Exceptions
Tuesday, October 20, 2009
Wonderfully Python
• A Simple Decorator
Tuesday, October 20, 2009
Simply Decorated
from exceptable.exceptable import Except
base = Except()
@base
def db_function():
pass
Tuesday, October 20, 2009
Wonderfully Python
• A Simple Decorator
• Catches and re-emits Exceptions
• The core of Exceptable
• Easy to Integrate - 2 lines, in Simpycity
Tuesday, October 20, 2009
Universality
• Exceptable Procedures never change
• DB logic doesn’t change
• Application support is Easy
Tuesday, October 20, 2009
Exceptable
• More Pythonic Database Access
• Better exceptions means better app flow
Tuesday, October 20, 2009
Example CodeWherein
• The DB Library
• The Application Implementation
• Catching Permissions Violations
• PostgreSQL 8.4
Tuesday, October 20, 2009
To Start,
CREATE TABLE exceptions (
name text primary key,
description text not null,
parent text references exceptions(name)
);
INSERT INTO exceptions VALUES ('Exception', 'Base exception',NULL);
INSERT INTO exceptions VALUES ('NotFoundException', 'Could not find specified record', 'Exception');
Tuesday, October 20, 2009
Which leads to
CREATE OR REPLACE FUNCTION not_found ( in_reason TEXT) RETURNS VOID as $body$
SELECT exceptaple.raise( 'NotFoundException', $1 );
$body$ LANGUAGE SQL;
Tuesday, October 20, 2009
Application Level
• Easy to Query the Exception tables
Tuesday, October 20, 2009
Application Level
• Easy to Query the Exception tables
• Easy to set up a new library
• Python took 50 lines
Tuesday, October 20, 2009
Our Python Example
• The Exceptable decorator is easy to set up
• Designed for DB-API integration
Tuesday, October 20, 2009
In the Application
base = Except(InternalError, { 'Exception': Exception, 'NotFoundException': NotFoundError,})
Tuesday, October 20, 2009
Our Python Example
• The Exceptable decorator is easy to set up
• Designed for DB-API integration
• User-defined
Tuesday, October 20, 2009
User Definitions
base = Except(InternalError, {
'PermissionError': PermissionError,
'UnknownUser': UnknownUserError,
'NotFoundException': NotFoundError,
})
Tuesday, October 20, 2009
Our Python Example
• The Exceptable decorator is easy to set up
• Designed for DB-API integration
• User-defined, and soon, table introspection
Tuesday, October 20, 2009
base is a decorator
@basedef db_api(query): con = db.connect(conn_string) cur = con.cursor() return cur(query)
Tuesday, October 20, 2009
Which leads to
try: rs = db_api(‘select * from test_api()’)except NotFoundError, e: # A hah! A usable error! pass
Tuesday, October 20, 2009
As Opposed To
try: rs = db_api(‘select * from test_api()’)except InternalError, e: if “NotFoundException” in str(e): raise NotFoundError(str(e)) elif “PermissionsError” in str(e): raise PermissionsError(str(e))
Tuesday, October 20, 2009
Our Python Example
• The Exceptable decorator is easy to set up
• Designed for DB-API integration
• User-defined, and soon, table introspection
• Existing decorators can be expanded easily
Tuesday, October 20, 2009
Grow, my Pretties!
class NotNullError(BaseException): passclass SCE(BaseException): pass
base.add({‘NotNullException’: NotNullError,‘SufficientCoffeeException’: SCE
})
Tuesday, October 20, 2009
Permission Denied
• Exceptable.py also wraps the base permission denied
• DB permissions violations work at the app level
Tuesday, October 20, 2009
Vertically Challenged
a = c.Function(‘test_auth’);try: result = a()except PermissionDenied, e: abort(403)except NoSuchUser, e: abort(401)
Tuesday, October 20, 2009
AND THUSQuestions?
Tuesday, October 20, 2009
Get It!
https://projects.commandprompt.com/public/exceptable/
Tuesday, October 20, 2009
THANK YOU!
Tuesday, October 20, 2009