Commits

Kirill Simonov  committed c90f27b

Added connection option `charset`.

  • Participants
  • Parent commits 9911e39

Comments (0)

Files changed (3)

File src/htsql/cmd/retrieve.py

                 connect = Connect()
                 connection = connect()
                 cursor = connection.cursor()
-                cursor.execute(plan.sql.encode('utf-8'))
+                cursor.execute(plan.sql)
                 records = []
                 for row in cursor:
                     values = []

File src/htsql/connect.py

         """
         Execute one SQL statement.
         """
+        if isinstance(statement, unicode):
+            charset = 'utf-8'
+            db = context.app.htsql.db
+            if db.options is not None and db.options.get('charset'):
+                charset = db.options['charset']
+            try:
+                statement = statement.encode(charset)
+            except UnicodeEncodeError:
+                raise DBError("cannot encode the query with charset: %s"
+                              % charset)
         with self.guard:
             return self.cursor.execute(statement, *parameters)
 
         except DBError:
             ...
     """
+    valid_options = []
 
     def __init__(self, with_autocommit=False):
         assert isinstance(with_autocommit, bool)
         self.with_autocommit = with_autocommit
+        # Validate connection parameters
+        db = context.app.htsql.db
+        if db.options is not None:
+            for option in sorted(db.options):
+                if option not in self.valid_options:
+                    raise DBError("unexpected connection parameter: %s"
+                                  % option)
 
     def __call__(self):
         """

File src/htsql_engine/pgsql/connect.py

 from htsql.domain import StringDomain, EnumDomain
 from htsql.connect import Connect, DBError, NormalizeError, Normalize
 from htsql.context import context
+import codecs
 import psycopg2, psycopg2.extensions
 
 
     """
     Implementation of the connection adapter for PostgreSQL.
     """
+    valid_options = ['charset']
 
     def open(self):
         # Prepare and execute the `psycopg2.connect()` call.
             parameters['password'] = db.password
         connection = psycopg2.connect(**parameters)
 
-        # All queries are UTF-8 encoded strings regardless of the database
-        # encoding.
-        connection.set_client_encoding('UTF8')
+        encoding = 'UTF8'
+        if db.options is not None and db.options.get('charset'):
+            charset = db.options.get('charset')
+            try:
+                codec = codecs.lookup(charset)
+            except LookupError:
+                raise PGSQLError("unknown charset: %s" % charset)
+            for client_encoding in sorted(psycopg2._psycopg.encodings):
+                client_charset = psycopg2._psycopg.encodings[client_encoding]
+                client_codec = codecs.lookup(client_charset)
+                if client_codec.name == codec.name:
+                    encoding = client_encoding
+                    break
+            else:
+                raise PGSQLError("unknown charset: %s" % charset)
+        connection.set_client_encoding(encoding)
 
         # Make TEXT values return as `unicode` objects.
         psycopg2.extensions.register_type(psycopg2.extensions.UNICODE,
         return super(NormalizePGSQLError, self).__call__()
 
 
+class NormalizePGSQL(Normalize):
+
+    def __init__(self, domain):
+        super(NormalizePGSQL, self).__init__(domain)
+        db = context.app.htsql.db
+        self.charset = 'utf-8'
+        if db.options is not None and db.options.get('charset'):
+            self.charset = db.options['charset']
+
+
 class NormalizePGSQLString(Normalize):
 
     adapts(StringDomain)
 
-    @staticmethod
-    def convert(value):
+    def convert(self, value):
         if isinstance(value, str):
-            value = value.decode('utf-8')
+            value = value.decode(self.charset)
         return value
 
 
 
     adapts(EnumDomain)
 
-    @staticmethod
-    def convert(value):
+    def convert(self, value):
         if isinstance(value, str):
-            value = value.decode('utf-8')
+            value = value.decode(self.charset)
         return value