Uh-oh! Driver-specific exceptions are not abstracted....

Matthew Bogosian <[email protected]> Mon, 15 Aug 2005 18:00:46 -0700
Newsgroups gmane.comp.web.skunkweb
Message-ID <[email protected]>
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

I just tried to violate an integrity constraint using PyDO with MySQL 
and I received a MySQLdb.IntegrityError (which is an ancestor of 
MySQLdb.MySQLError). For abstraction purposes, this is probably bad. I 
should probably receive that error wrapped in a PyDOError. Better yet, 
I should receive that error wrapped in the PyDO equivalent of an 
integrity constraint violation, perferably as an ancestor of PyDOError 
(e.g., PyDOIntegrityError).

If I'm writing code where I don't know (or I don't want to know) the 
underlying implementation of the database, then I should only have to 
worry about PyDOErrors. Code like this is worrysome:

try:
	myTableClass.new(unique_property = 'blah')
except MySQLdb.IntegrityError:
	...
except OraclesEquivalentIntegrityError:
	...
except PostgreSQLsEquivalentIntegrityError:
	...

Instead, one should only have to write something like:

try:
	myTableClass.new(unique_property = 'blah')
except pydo.exceptions.PyDOIntegrityError:
	...

In my mind there are two groups of errors which are ciritical to 
separate (rather than just wrap in the generic PyDOError). These are 
integrity constraint violations and deadlock errors (in MySQL, I 
believe these errors are represented by error codes 1022, 1060, 1061, 
1062, 1169, 1213, 1216, and 1217). With the exception of the deadlock 
error (1213 in MySQL), these could be represented by either 
PyDOIntegrityError (or equivalent), or perhaps there should be several 
children of PyDOError (or PyDOIntegrityError) that represent the 
different kinds of integrity constraint violation errors (duplicate 
key, foreign key constraint violation, etc.).

One way to do this is to have DBIBase subclasses 'wrap' the execute() 
method:

class MysqlDBI(DBIBase):
	...
	def execute(self, sql, values=(), qualified=False):
		try:
			DBIBase.execute(self, sql, values, qualified)
		except MySQLdb.MySQLError, e:
			err_code = e.args[0]

			if err_code == 1062:
				raise PyDODuplicateKeyError(*e.args)

			if err_code == 1213:
				raise PyDODeadlockError(*e.args)

			...

			raise PyDOError(*e.args)

This is just a thought. If people think this is worthwhile, I can 
submit a patch which addresses this for the MySQL abstraction.

	-- Matt

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.0 (Darwin)

iD8DBQFDATrDnLpDzL5I7l8RArjYAKCIVh+Z55mBS0utIIiiQbkkTeZQmQCfT+3v
3Og12BVMGalF1dc69xghBi0=
=ORAK
-----END PGP SIGNATURE-----



-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf