Trap and do basic reporting on encoding exceptions, both client and server-side
authorKarl O. Pinc <kop@karlpinc.com>
Tue, 5 Mar 2024 21:07:35 +0000 (15:07 -0600)
committerKarl O. Pinc <kop@karlpinc.com>
Tue, 5 Mar 2024 21:07:35 +0000 (15:07 -0600)
src/pgwui_core/core.py
src/pgwui_core/exceptions.py

index e08a098e56c3ed9bc43cac71d623e2b6a16ce825..41e141a03b90ea57a8009b6bf271562247d36f02 100644 (file)
@@ -669,6 +669,25 @@ class SQLCommand():
     args = attrs.field()
     ec = attrs.field(default=None)
 
+    def _explain_encoding_error(self, ex):
+        '''Return a SQLEncodingError instance
+        '''
+        if isinstance(ex, UnicodeEncodeError):
+            return core_ex.SQLEncodingError(
+                ex,
+                ("Data cannot be represented in the database"
+                 " connection's client-side character encoding"),
+                (f'The SQL statement is ({self.stmt}) and the data supplied'
+                 f' is ({self.tupl})'))
+        if isinstance(ex, psycopg.errors.UntranslatableCharacter):
+            return core_ex.SQLEncodingError(
+                ex,
+                ("Data cannot be represented in the"
+                 " character encoding of the database"),
+                (f'The SQL statement is ({self.stmt}) and the data supplied'
+                 f' is ({self.tupl})'))
+        return ex
+
     def execute(self, cur):
         '''
         Execute the sql statement.
@@ -682,11 +701,18 @@ class SQLCommand():
         '''
         try:
             cur.execute(self.stmt, self.args)
+        except UnicodeEncodeError as ex:
+            if self.ec is None:
+                raise self._explain_encoding_error(ex)
+            raise self.ec(self._explain_encoding_error(ex))
+        except psycopg.errors.UntranslatableCharacter as ex:
+            if self.ec is None:
+                raise self._explain_encoding_error(ex)
+            raise self.ec(self._explain_encoding_error(ex))
         except psycopg.DatabaseError as ex:
             if self.ec is None:
                 raise ex
-            else:
-                raise self.ec(ex)
+            raise self.ec(ex)
 
 
 @attrs.define(slots=False)
index 02c8af68d5afc3ace193217b47ff00032feea256..d6d7c2a95f5c35396a7c0af3ff72914c7cce5468 100644 (file)
@@ -180,6 +180,13 @@ class DataInconsistencyError(SetupError):
         super(DataInconsistencyError, self).__init__(e, descr, detail)
 
 
+class SQLEncodingError(SetupError):
+    '''There was an encoding error processing a SQL statement
+    '''
+    def __init__(self, e, descr='', detail=''):
+        super().__init__(e, descr, detail)
+
+
 class DBError(SetupError):
     '''psycopg3 raised an error'''
     def __init__(self, pgexc, e='process your request'):