Browse files

Override tiddler_put to deal with mysql warnings.

mysql, in its infinite wisdom, will truncate a field that doesn't
fit in a column and raise a warning.

We don't want this. We want it to fail. Otherwise two tiddlers with
titles that are the same for the first N (where N is around 128)
characters will overwrite one another.

This violates principle of least surprise, so we error. It is up to the
client to either a) protect against the error happening in the first or
b) deal with it when it happens.

This code raises a TypeError which the `put` web handler will deal
with and make into an HTTP 400.
  • Loading branch information...
1 parent afab597 commit e359739232607255d36e3ac4642a8bf953d698dd @cdent cdent committed Jun 21, 2012
Showing with 30 additions and 1 deletion.
  1. +13 −0 test/test_gamut.py
  2. +17 −1 tiddlywebplugins/mysql3.py
View
13 test/test_gamut.py
@@ -412,3 +412,16 @@ def test_multi_role_user():
user2 = store.get(User(u'cdent'))
assert list(user2.roles) == ['cow']
+
+def test_long_tiddler_title():
+ long_title = 'I would not do that if I were you, it might have consequences more than dire than you could possibly imagine. So dire you might have an oh no moment something severe.'
+ tiddler1 = Tiddler(long_title + '1', 'holder')
+ tiddler1.text = 'tiddler1'
+ tiddler2 = Tiddler(long_title + '1', 'holder')
+ tiddler2.text = 'tiddler2'
+
+ py.test.raises(TypeError, 'store.put(tiddler1)')
+ py.test.raises(TypeError, 'store.put(tiddler2)')
+
+ py.test.raises(NoTiddlerError, 'store.get(tiddler1)')
+ py.test.raises(NoTiddlerError, 'store.get(tiddler2)')
View
18 tiddlywebplugins/mysql3.py
@@ -7,7 +7,10 @@
http://tiddlyweb.com/
"""
-from __future__ import absolute_import
+from __future__ import absolute_import, with_statement
+
+import warnings
+import MySQLdb
from sqlalchemy import event
from sqlalchemy.engine import create_engine
@@ -122,6 +125,19 @@ def _init_store(self):
Base.metadata.create_all(ENGINE)
MAPPED = True
+ def tiddler_put(self, tiddler):
+ """
+ Override the super to trap MySQLdb.Warning which is raised
+ when mysqld would truncate a field during an insert. We
+ want to not store the tiddler, and report a useful error.
+ """
+ with warnings.catch_warnings():
+ warnings.simplefilter('error', MySQLdb.Warning)
+ try:
+ SQLStore.tiddler_put(self, tiddler)
+ except MySQLdb.Warning, exc:
+ raise TypeError('mysql refuses to store tiddler: %s' % exc)
+
def search(self, search_query=''):
query = self.session.query(sTiddler).join('current')
if '_limit:' not in search_query:

0 comments on commit e359739

Please sign in to comment.