From 4a2130228f1dce0308035eab5c47b70e4f35f659 Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Wed, 17 Aug 2022 13:58:22 +0000 Subject: [PATCH] Query: Cast the meta key to `BINARY` for case-sensitive key comparisons in `WP_Meta_Query`. This addresses an error on MySQL 8.0.22 or later: {{{ Character set 'utf8mb4_unicode_520_ci' cannot be used in conjunction with 'binary' in call to regexp_like }}} From the [https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-22.html MySQL 8.0.22 changelog]: > Regular expression functions such as `REGEXP_LIKE()` yielded inconsistent results with binary string arguments. These functions now reject binary strings with an error. ([https://bugs.mysql.com/bug.php?id=98951 Bug #98951], [https://bugs.mysql.com/bug.php?id=98950 Bug #98950]) WordPress meta queries use the `BINARY` data type for case-sensitive meta key comparisons using regular expressions. By explicitly casting the meta key to `BINARY`, we can make sure the values being compared use the same character set and produce consistent results. The change is covered by existing meta query unit tests: three tests which previously failed on MySQL 8.0.22 or later now pass. References: * [https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-22.html MySQL 8.0.22 changelog] * [https://bugs.mysql.com/bug.php?id=104387 Bug #104387 CHARACTER_SET_MISMATCH issue with regex comparisons] Follow-up to [46188]. Fixes #51740. git-svn-id: https://develop.svn.wordpress.org/trunk@53901 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/class-wp-meta-query.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/wp-includes/class-wp-meta-query.php b/src/wp-includes/class-wp-meta-query.php index ac1da7d1f6..f66b2fac5f 100644 --- a/src/wp-includes/class-wp-meta-query.php +++ b/src/wp-includes/class-wp-meta-query.php @@ -679,11 +679,13 @@ class WP_Meta_Query { case 'REGEXP': $operator = $meta_compare_key; if ( isset( $clause['type_key'] ) && 'BINARY' === strtoupper( $clause['type_key'] ) ) { - $cast = 'BINARY'; + $cast = 'BINARY'; + $meta_key = "CAST($alias.meta_key AS BINARY)"; } else { - $cast = ''; + $cast = ''; + $meta_key = "$alias.meta_key"; } - $where = $wpdb->prepare( "$alias.meta_key $operator $cast %s", trim( $clause['key'] ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared + $where = $wpdb->prepare( "$meta_key $operator $cast %s", trim( $clause['key'] ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared break; case '!=': @@ -705,12 +707,14 @@ class WP_Meta_Query { case 'NOT REGEXP': $operator = $meta_compare_key; if ( isset( $clause['type_key'] ) && 'BINARY' === strtoupper( $clause['type_key'] ) ) { - $cast = 'BINARY'; + $cast = 'BINARY'; + $meta_key = "CAST($subquery_alias.meta_key AS BINARY)"; } else { - $cast = ''; + $cast = ''; + $meta_key = "$subquery_alias.meta_key"; } - $meta_compare_string = $meta_compare_string_start . "AND $subquery_alias.meta_key REGEXP $cast %s " . $meta_compare_string_end; + $meta_compare_string = $meta_compare_string_start . "AND $meta_key REGEXP $cast %s " . $meta_compare_string_end; $where = $wpdb->prepare( $meta_compare_string, $clause['key'] ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared break; }