diff options
-rw-r--r-- | doc/build/changelog/unreleased_13/4804.rst | 15 | ||||
-rw-r--r-- | lib/sqlalchemy/dialects/mysql/mysqldb.py | 16 | ||||
-rw-r--r-- | lib/sqlalchemy/testing/suite/test_types.py | 2 | ||||
-rw-r--r-- | test/profiles.txt | 16 |
4 files changed, 38 insertions, 11 deletions
diff --git a/doc/build/changelog/unreleased_13/4804.rst b/doc/build/changelog/unreleased_13/4804.rst new file mode 100644 index 000000000..58f521e5b --- /dev/null +++ b/doc/build/changelog/unreleased_13/4804.rst @@ -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. diff --git a/lib/sqlalchemy/dialects/mysql/mysqldb.py b/lib/sqlalchemy/dialects/mysql/mysqldb.py index 744909170..1d4dba3c4 100644 --- a/lib/sqlalchemy/dialects/mysql/mysqldb.py +++ b/lib/sqlalchemy/dialects/mysql/mysqldb.py @@ -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) diff --git a/lib/sqlalchemy/testing/suite/test_types.py b/lib/sqlalchemy/testing/suite/test_types.py index 3320dd93c..82a842102 100644 --- a/lib/sqlalchemy/testing/suite/test_types.py +++ b/lib/sqlalchemy/testing/suite/test_types.py @@ -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) diff --git a/test/profiles.txt b/test/profiles.txt index 469dac01c..10288669b 100644 --- a/test/profiles.txt +++ b/test/profiles.txt @@ -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 |