Recover from db errors while building insert statements
authorKarl O. Pinc <kop@karlpinc.com>
Tue, 19 Jan 2021 18:42:34 +0000 (12:42 -0600)
committerKarl O. Pinc <kop@karlpinc.com>
Tue, 19 Jan 2021 18:42:34 +0000 (12:42 -0600)
src/pgwui_bulk_upload/exceptions.py
src/pgwui_bulk_upload/views/bulk_upload.py

index d7ee25608f18c6f6efe3f082046ba3fe7f7090aa..08fad4277e4c596bb79ba0fb7e05f8969681e4de 100644 (file)
@@ -97,6 +97,16 @@ class CannotReadError(Error):
             f'The error is: {exp}')
 
 
+class CannotRollbackError(Error):
+    def __init__(self, exp):
+        super().__init__(
+            'Cannot roll back the current transaction',
+            'The transaction has failed and must roll back before '
+            'the database can again be queried about relations and '
+            'their columns',
+            f'The error from psycopg2 is: ({exp})')
+
+
 class BadMapFileError(Error):
     pass
 
index b540297e2b3a2c21e834654157fcabd1acfae528..1043d7f36a4e29b60fc6ce9c50de2bc9c39c330e 100644 (file)
@@ -542,6 +542,7 @@ class BulkTableUploadHandler(BaseTableUploadHandler):
         quotecols = self.quote_columns()
         column_quoter = self.get_column_quoter(quotecols)
 
+        in_trans = True
         i_map = dict()
         errors = []
         for fileinfo in self.data.filedata():
@@ -553,6 +554,20 @@ class BulkTableUploadHandler(BaseTableUploadHandler):
                     map_description(fileinfo.filepath, fileinfo.relation),
                     fileinfo.filepath, fileinfo.relation)
                 errors.append(exp)
+                if in_trans:
+                    # In order to continue to query the db after a db error
+                    # the current transaction must be rolled back.
+                    # Because we know we're going to abort, don't start a
+                    # new transaction.
+                    try:
+                        self.cur.execute('ROLLBACK;')
+                    except psycopg2.DatabaseError as exp:
+                        err = ex.CannotRollbackError(exp)
+                        err.color(map_description(fileinfo.filepath,
+                                                  fileinfo.relation),
+                                  fileinfo.filepath, fileinfo.relation)
+                        errors.append(err)
+                    in_trans = False
             finally:
                 # Limit number of open files, close the file handle until it
                 # is time to read the file