]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Emit SET NAMES for all MySQL connections w charset
authorMike Bayer <mike_mp@zzzcomputing.com>
Sun, 11 Aug 2019 21:42:59 +0000 (17:42 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sun, 11 Aug 2019 23:16:38 +0000 (19:16 -0400)
The MySQL dialects will emit "SET NAMES" at the start of a connection when
charset is given to the MySQL driver, to appease an apparent behavior
observed in MySQL 8.0 that raises a collation error when a UNION includes
string columns unioned against columns of the form CAST(NULL AS CHAR(..)),
which is what SQLAlchemy's polymorphic_union function does.   The issue
seems to have affected PyMySQL for at least a year, however has recently
appeared as of mysqlclient 1.4.4 based on changes in how this DBAPI creates
a connection.  As the presence of this directive impacts three separate
MySQL charset settings which each have intricate effects based on their
presense,  SQLAlchemy will now emit the directive on new connections to
ensure correct behavior.

Fixes: #4804
Change-Id: If9d7ee00d0ccaf773972b564fe455e8e9edf6627

doc/build/changelog/unreleased_13/4804.rst [new file with mode: 0644]
lib/sqlalchemy/dialects/mysql/mysqldb.py
lib/sqlalchemy/testing/suite/test_types.py
test/profiles.txt

diff --git a/doc/build/changelog/unreleased_13/4804.rst b/doc/build/changelog/unreleased_13/4804.rst
new file mode 100644 (file)
index 0000000..58f521e
--- /dev/null
@@ -0,0 +1,15 @@
+.. change::
+    :tags: bug, mysql
+    :tickets: 4804
+
+    The MySQL dialects will emit "SET NAMES" at the start of a connection when
+    charset is given to the MySQL driver, to appease an apparent behavior
+    observed in MySQL 8.0 that raises a collation error when a UNION includes
+    string columns unioned against columns of the form CAST(NULL AS CHAR(..)),
+    which is what SQLAlchemy's polymorphic_union function does.   The issue
+    seems to have affected PyMySQL for at least a year, however has recently
+    appeared as of mysqlclient 1.4.4 based on changes in how this DBAPI creates
+    a connection.  As the presence of this directive impacts three separate
+    MySQL charset settings which each have intricate effects based on their
+    presense,  SQLAlchemy will now emit the directive on new connections to
+    ensure correct behavior.
index 744909170a3ed49925e46bd26fda12bc86a2eb1d..1d4dba3c4ed61ba940f3025baec6b999a06a32d1 100644 (file)
@@ -117,6 +117,22 @@ class MySQLDialect_mysqldb(MySQLDialect):
     def dbapi(cls):
         return __import__("MySQLdb")
 
+    def on_connect(self):
+        super_ = super(MySQLDialect_mysqldb, self).on_connect()
+
+        def on_connect(conn):
+            if super_ is not None:
+                super_(conn)
+
+            charset_name = conn.character_set_name()
+
+            if charset_name is not None:
+                cursor = conn.cursor()
+                cursor.execute("SET NAMES %s" % charset_name)
+                cursor.close()
+
+        return on_connect
+
     def do_ping(self, dbapi_connection):
         try:
             dbapi_connection.ping(False)
index 3320dd93c7f52addf4f596ae5a44d3080ad667e9..82a842102cdc79f6c50d61515dd8b66703af0e05 100644 (file)
@@ -733,7 +733,7 @@ class JSONTest(_LiteralRoundTripFixture, fixtures.TablesTest):
 
     def test_round_trip_custom_json(self):
         data_table = self.tables.data_table
-        data_element = self.data1
+        data_element = {"key1": "data1"}
 
         js = mock.Mock(side_effect=json.dumps)
         jd = mock.Mock(side_effect=json.loads)
index 469dac01c3afdc5c43ec5059d35715fa72ab2241..10288669b50242972953d6afff991e879f536433 100644 (file)
@@ -1,15 +1,15 @@
 # /home/classic/dev/sqlalchemy/test/profiles.txt
 # This file is written out on a per-environment basis.
-# For each test in aaa_profiling, the corresponding function and 
+# For each test in aaa_profiling, the corresponding function and
 # environment is located within this file.  If it doesn't exist,
 # the test is skipped.
-# If a callcount does exist, it is compared to what we received. 
+# If a callcount does exist, it is compared to what we received.
 # assertions are raised if the counts do not match.
-# 
-# To add a new callcount test, apply the function_call_count 
-# decorator and re-run the tests using the --write-profiles 
+#
+# To add a new callcount test, apply the function_call_count
+# decorator and re-run the tests using the --write-profiles
 # option - this file will be rewritten including the new count.
-# 
+#
 
 # TEST: test.aaa_profiling.test_compiler.CompileTest.test_insert
 
@@ -487,8 +487,6 @@ test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.
 
 test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_mssql_pyodbc_dbapiunicode_cextensions 1045
 test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_mssql_pyodbc_dbapiunicode_nocextensions 1062
-test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_mysql_mysqldb_dbapiunicode_cextensions 1196
-test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_mysql_mysqldb_dbapiunicode_nocextensions 1213
 test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_oracle_cx_oracle_dbapiunicode_cextensions 1111
 test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 1128
 test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_postgresql_psycopg2_dbapiunicode_cextensions 1143
@@ -508,8 +506,6 @@ test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.7_sqlite_pysqlite_dbapiu
 
 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 2.7_mssql_pyodbc_dbapiunicode_cextensions 93,19
 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 2.7_mssql_pyodbc_dbapiunicode_nocextensions 93,19
-test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 2.7_mysql_mysqldb_dbapiunicode_cextensions 93,19
-test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 2.7_mysql_mysqldb_dbapiunicode_nocextensions 93,19
 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 2.7_oracle_cx_oracle_dbapiunicode_cextensions 93,19
 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 93,19
 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 2.7_postgresql_psycopg2_dbapiunicode_cextensions 100,19