From 3d47155643e6f34edade6fae5164ae957b8372ca Mon Sep 17 00:00:00 2001 From: Charles Fulton Date: Tue, 11 Aug 2015 12:35:09 +0000 Subject: [PATCH 1/2] MDL-51052 dml: support for sql_like() under utf8_bin --- lib/dml/mysqli_native_moodle_database.php | 7 ++++++- lib/dml/tests/dml_test.php | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/dml/mysqli_native_moodle_database.php b/lib/dml/mysqli_native_moodle_database.php index 9d7b7670c32..8c61536809e 100644 --- a/lib/dml/mysqli_native_moodle_database.php +++ b/lib/dml/mysqli_native_moodle_database.php @@ -1523,7 +1523,12 @@ class mysqli_native_moodle_database extends moodle_database { if ($accentsensitive) { return "LOWER($fieldname) $LIKE LOWER($param) COLLATE utf8_bin ESCAPE '$escapechar'"; } else { - return "$fieldname $LIKE $param ESCAPE '$escapechar'"; + // Set a case sensitive collation if using utf8_bin. + if ($this->get_dbcollation() == 'utf8_bin') { + return "$fieldname $LIKE $param COLLATE utf8_unicode_ci ESCAPE '$escapechar'"; + } else { + return "$fieldname $LIKE $param ESCAPE '$escapechar'"; + } } } } diff --git a/lib/dml/tests/dml_test.php b/lib/dml/tests/dml_test.php index b064d99aa03..8b165652f0b 100644 --- a/lib/dml/tests/dml_test.php +++ b/lib/dml/tests/dml_test.php @@ -3870,6 +3870,11 @@ class core_dml_testcase extends database_driver_testcase { $records = $DB->get_records_sql($sql, array('aui')); $this->assertCount(1, $records); + // Test LIKE under unusual collations. + $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', false, false); + $records = $DB->get_records_sql($sql, array("%dup_r%")); + $this->assertCount(2, $records); + $sql = "SELECT * FROM {{$tablename}} WHERE ".$DB->sql_like('name', '?', true, true, true); // NOT LIKE. $records = $DB->get_records_sql($sql, array("%o%")); $this->assertCount(3, $records); From 2bdeb8ef3026a12daef0f3e4534c101d27c24c57 Mon Sep 17 00:00:00 2001 From: David Monllao Date: Fri, 18 Sep 2015 11:42:12 +0800 Subject: [PATCH 2/2] MDL-51052 dml: More info about mysql and case & accent sensitiveness --- lib/dml/mysqli_native_moodle_database.php | 28 +++++++++++++++-------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/lib/dml/mysqli_native_moodle_database.php b/lib/dml/mysqli_native_moodle_database.php index 8c61536809e..70e8a6ed4bc 100644 --- a/lib/dml/mysqli_native_moodle_database.php +++ b/lib/dml/mysqli_native_moodle_database.php @@ -1502,10 +1502,13 @@ class mysqli_native_moodle_database extends moodle_database { /** * Returns 'LIKE' part of a query. * + * Note that mysql does not support $casesensitive = true and $accentsensitive = false. + * More information in http://bugs.mysql.com/bug.php?id=19567. + * * @param string $fieldname usually name of the table column * @param string $param usually bound query parameter (?, :named) * @param bool $casesensitive use case sensitive search - * @param bool $accensensitive use accent sensitive search (not all databases support accent insensitive) + * @param bool $accensensitive use accent sensitive search (ignored if $casesensitive is true) * @param bool $notlike true means "NOT LIKE" * @param string $escapechar escape char for '%' and '_' * @return string SQL code fragment @@ -1517,19 +1520,24 @@ class mysqli_native_moodle_database extends moodle_database { $escapechar = $this->mysqli->real_escape_string($escapechar); // prevents problems with C-style escapes of enclosing '\' $LIKE = $notlike ? 'NOT LIKE' : 'LIKE'; + if ($casesensitive) { + // Current MySQL versions do not support case sensitive and accent insensitive. return "$fieldname $LIKE $param COLLATE utf8_bin ESCAPE '$escapechar'"; + + } else if ($accentsensitive) { + // Case insensitive and accent sensitive, we can force a binary comparison once all texts are using the same case. + return "LOWER($fieldname) $LIKE LOWER($param) COLLATE utf8_bin ESCAPE '$escapechar'"; + } else { - if ($accentsensitive) { - return "LOWER($fieldname) $LIKE LOWER($param) COLLATE utf8_bin ESCAPE '$escapechar'"; - } else { - // Set a case sensitive collation if using utf8_bin. - if ($this->get_dbcollation() == 'utf8_bin') { - return "$fieldname $LIKE $param COLLATE utf8_unicode_ci ESCAPE '$escapechar'"; - } else { - return "$fieldname $LIKE $param ESCAPE '$escapechar'"; - } + // Case insensitive and accent insensitive. + $collation = ''; + if ($this->get_dbcollation() == 'utf8_bin') { + // Force a case insensitive comparison if using utf8_bin. + $collation = 'COLLATE utf8_unicode_ci'; } + + return "$fieldname $LIKE $param $collation ESCAPE '$escapechar'"; } }