[mod] make ViolatedConstraint actually display useful information
authorLaurent Peuch <cortex@worlddomination.be>
Thu, 16 May 2019 04:42:59 +0200
changeset 12614 8ac9ac8d9143
parent 12613 703a263dd618
child 12619 48a010b35af2
[mod] make ViolatedConstraint actually display useful information Move from: (Pdb++) raise some_exception *** ViolatedConstraint: To: (Pdb++) raise some_exception *** ViolatedConstraint: constraint 'cstr56c2ab4b3154f21d08b067742ce5bd9d' is being violated by the query 'ALTER TABLE cw_Bibliography ADD CONSTRAINT cstr56c2ab4b3154f21d08b067742ce5bd9d CHECK(cw_item_type IN ('journalArticle', 'note', 'book', 'thesis', 'film', 'web page', 'manuscrit', 'tapuscrit'))'. You can run the inverted constraint on the database to list the problematic rows. And save hours of debugging to actually understand what is going on.
cubicweb/_exceptions.py
cubicweb/server/sources/native.py
--- a/cubicweb/_exceptions.py	Thu May 16 09:40:28 2019 +0200
+++ b/cubicweb/_exceptions.py	Thu May 16 04:42:59 2019 +0200
@@ -107,9 +107,14 @@
 
 
 class ViolatedConstraint(RepositoryError):
-    def __init__(self, cnx, cstrname):
+    def __init__(self, cnx, cstrname, query):
         self.cnx = cnx
         self.cstrname = cstrname
+        message = (
+            "constraint '%s' is being violated by the query '%s'. "
+            "You can run the inverted constraint on the database to list the problematic rows."
+        ) % (cstrname, query)
+        super(ViolatedConstraint, self).__init__(message)
 
 
 # security exceptions #########################################################
--- a/cubicweb/server/sources/native.py	Thu May 16 09:40:28 2019 +0200
+++ b/cubicweb/server/sources/native.py	Thu May 16 04:42:59 2019 +0200
@@ -716,14 +716,17 @@
                     mo = re.search(r'\bcstr[a-f0-9]{32}\b', arg)
                     if mo is not None:
                         # postgresql
-                        raise ViolatedConstraint(cnx, cstrname=mo.group(0))
+                        raise ViolatedConstraint(cnx, cstrname=mo.group(0),
+                                                 query=query)
                     if arg.startswith('CHECK constraint failed:'):
                         # sqlite3 (new)
-                        raise ViolatedConstraint(cnx, cstrname=arg.split(':', 1)[1].strip())
+                        raise ViolatedConstraint(cnx, cstrname=arg.split(':', 1)[1].strip(),
+                                                 query=query)
                     mo = re.match('^constraint (cstr.*) failed$', arg)
                     if mo is not None:
                         # sqlite3 (old)
-                        raise ViolatedConstraint(cnx, cstrname=mo.group(1))
+                        raise ViolatedConstraint(cnx, cstrname=mo.group(1),
+                                                 query=query)
             raise
         return cursor