@@ -7587,3 +7587,83 @@ def test_set_compress_cext_false(self):
7587
7587
"""Test setting `compress=False` in the C extension directly."""
7588
7588
res = self ._test_compression_status_cext (False )
7589
7589
self .assertEqual (res , ("Compression" , "OFF" ))
7590
+
7591
+
7592
+ class BugOra35278365 (tests .MySQLConnectorTests ):
7593
+ """BUG#35278365: Fix UnicodeDecodeError with a long field name alias (c-ext)
7594
+
7595
+ An UnicodeDecodeError is raised when using a complex query that produces
7596
+ a long field name alias.
7597
+ It fails to create an Unicode object using `PyUnicode_Decode()` from the
7598
+ resulting `MYSQL_FIELD.name` returned by `mysql_fetch_fields()` MySQL
7599
+ C API.
7600
+
7601
+ This patch uses "replace" in `PyUnicode_Decode()` to set how decoding
7602
+ errors are handled, which uses a replace marker.
7603
+ """
7604
+
7605
+ tbl_prefix = "BugOra35278365"
7606
+
7607
+ def setUp (self ):
7608
+ config = tests .get_mysql_config ()
7609
+ with mysql .connector .connect (** config ) as cnx :
7610
+ with cnx .cursor () as cur :
7611
+ cnx .cmd_query (f"DROP TABLE IF EXISTS { self .tbl_prefix } _table1" )
7612
+ cnx .cmd_query (f"DROP TABLE IF EXISTS { self .tbl_prefix } _table2" )
7613
+ cnx .cmd_query (f"DROP TABLE IF EXISTS { self .tbl_prefix } _table3" )
7614
+ cur .execute (
7615
+ f"""
7616
+ CREATE TABLE { self .tbl_prefix } _table1 (
7617
+ id int(11) NOT NULL,
7618
+ ort_id int(11) DEFAULT NULL
7619
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
7620
+ """
7621
+ )
7622
+ cur .execute (
7623
+ f"""
7624
+ CREATE TABLE { self .tbl_prefix } _table2 (
7625
+ id int(11) NOT NULL
7626
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
7627
+ """
7628
+ )
7629
+ cur .execute (
7630
+ f"""
7631
+ CREATE TABLE { self .tbl_prefix } _table3 (
7632
+ besuch_id int(11) NOT NULL,
7633
+ taxon varchar(30) NOT NULL,
7634
+ epitheton varchar(30) DEFAULT NULL,
7635
+ rang int(1) NOT NULL
7636
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
7637
+ """
7638
+ )
7639
+ cnx .commit ()
7640
+
7641
+ def tearDown (self ):
7642
+ config = tests .get_mysql_config ()
7643
+ with mysql .connector .connect (** config ) as cnx :
7644
+ cnx .cmd_query (f"DROP TABLE IF EXISTS { self .tbl_prefix } _table1" )
7645
+ cnx .cmd_query (f"DROP TABLE IF EXISTS { self .tbl_prefix } _table2" )
7646
+ cnx .cmd_query (f"DROP TABLE IF EXISTS { self .tbl_prefix } _table3" )
7647
+ cnx .commit ()
7648
+
7649
+ @foreach_cnx ()
7650
+ def test_long_field_names (self ):
7651
+ with mysql .connector .connect (** tests .get_mysql_config ()) as cnx :
7652
+ with cnx .cursor () as cur :
7653
+ query = f"""
7654
+ SELECT (SELECT Group_concat(DISTINCT Concat_ws(' ', taxon,
7655
+ Ifnull(t3.epitheton, 'sp.'))
7656
+ ORDER BY
7657
+ t3.taxon, Isnull(t3.epitheton), t3.epitheton SEPARATOR ', ')
7658
+ FROM { self .tbl_prefix } _table3 t3
7659
+ WHERE t3.besuch_id = { self .tbl_prefix } _table1.id
7660
+ AND t3.rang IN (1, 2)
7661
+ AND NOT EXISTS(
7662
+ SELECT 0 FROM { self .tbl_prefix } _table3 b3)), 1, 1
7663
+ FROM { self .tbl_prefix } _table1,{ self .tbl_prefix } _table2
7664
+ WHERE { self .tbl_prefix } _table2.id = { self .tbl_prefix } _table1.ort_id
7665
+ ORDER BY { self .tbl_prefix } _table1.id
7666
+ """
7667
+ cur .execute (query ) # No error is success
7668
+ res = cur .fetchall ()
7669
+ self .assertEqual (res , [])
0 commit comments