]> 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:53 +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
(cherry picked from commit f5e57f7c311288d892894edcc44d901b5bfbb3d1)

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 165c6750cfb0b343b6109b9ff6c591ad807fbb57..67f7c337fa940b429dc4a84121edeb007022bd74 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
 
@@ -467,8 +467,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 1137
@@ -488,8 +486,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 93,19