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.
Built from https://develop.svn.wordpress.org/trunk@53901


git-svn-id: http://core.svn.wordpress.org/trunk@53460 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Sergey Biryukov 2022-08-17 14:00:13 +00:00
parent fa9c62915f
commit d89482b22d
2 changed files with 11 additions and 7 deletions

View File

@ -679,11 +679,13 @@ class WP_Meta_Query {
case 'REGEXP': case 'REGEXP':
$operator = $meta_compare_key; $operator = $meta_compare_key;
if ( isset( $clause['type_key'] ) && 'BINARY' === strtoupper( $clause['type_key'] ) ) { if ( isset( $clause['type_key'] ) && 'BINARY' === strtoupper( $clause['type_key'] ) ) {
$cast = 'BINARY'; $cast = 'BINARY';
$meta_key = "CAST($alias.meta_key AS BINARY)";
} else { } 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; break;
case '!=': case '!=':
@ -705,12 +707,14 @@ class WP_Meta_Query {
case 'NOT REGEXP': case 'NOT REGEXP':
$operator = $meta_compare_key; $operator = $meta_compare_key;
if ( isset( $clause['type_key'] ) && 'BINARY' === strtoupper( $clause['type_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 { } 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 $where = $wpdb->prepare( $meta_compare_string, $clause['key'] ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
break; break;
} }

View File

@ -16,7 +16,7 @@
* *
* @global string $wp_version * @global string $wp_version
*/ */
$wp_version = '6.1-alpha-53900'; $wp_version = '6.1-alpha-53901';
/** /**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.