diff --git a/lib/dml/moodle_database.php b/lib/dml/moodle_database.php index 4621c731ed3..d8179f403c3 100644 --- a/lib/dml/moodle_database.php +++ b/lib/dml/moodle_database.php @@ -2483,6 +2483,30 @@ abstract class moodle_database { return ''; } + /** + * Returns the word-beginning boundary marker if this database driver supports regex syntax when searching. + * @return string The word-beginning boundary marker. Otherwise, an empty string. + */ + public function sql_regex_get_word_beginning_boundary_marker() { + if ($this->sql_regex_supported()) { + return '[[:<:]]'; + } + + return ''; + } + + /** + * Returns the word-end boundary marker if this database driver supports regex syntax when searching. + * @return string The word-end boundary marker. Otherwise, an empty string. + */ + public function sql_regex_get_word_end_boundary_marker() { + if ($this->sql_regex_supported()) { + return '[[:>:]]'; + } + + return ''; + } + /** * Returns the SQL that allows to find intersection of two or more queries * diff --git a/lib/dml/mysqli_native_moodle_database.php b/lib/dml/mysqli_native_moodle_database.php index a02e9b9d1ae..3e1c41ffbca 100644 --- a/lib/dml/mysqli_native_moodle_database.php +++ b/lib/dml/mysqli_native_moodle_database.php @@ -1876,6 +1876,38 @@ class mysqli_native_moodle_database extends moodle_database { return $collation . ($positivematch ? 'REGEXP' : 'NOT REGEXP'); } + /** + * Returns the word-beginning boundary marker based on MySQL version. + * @return string The word-beginning boundary marker. + */ + public function sql_regex_get_word_beginning_boundary_marker() { + $ismysql = ($this->get_dbtype() == 'mysqli' || $this->get_dbtype() == 'auroramysql'); + $ismysqlge8d0d4 = ($ismysql && version_compare($this->get_server_info()['version'], '8.0.4', '>=')); + if ($ismysqlge8d0d4) { + return '\\b'; + } + // Prior to MySQL 8.0.4, MySQL used the Henry Spencer regular expression library to support regular expression operations, + // rather than International Components for Unicode (ICU). + // MariaDB still supports the "old marker" (MDEV-5357). + return '[[:<:]]'; + } + + /** + * Returns the word-end boundary marker based on MySQL version. + * @return string The word-end boundary marker. + */ + public function sql_regex_get_word_end_boundary_marker() { + $ismysql = ($this->get_dbtype() == 'mysqli' || $this->get_dbtype() == 'auroramysql'); + $ismysqlge8d0d4 = ($ismysql && version_compare($this->get_server_info()['version'], '8.0.4', '>=')); + if ($ismysqlge8d0d4) { + return '\\b'; + } + // Prior to MySQL 8.0.4, MySQL used the Henry Spencer regular expression library to support regular expression operations, + // rather than International Components for Unicode (ICU). + // MariaDB still supports the "old marker" (MDEV-5357). + return '[[:>:]]'; + } + /** * Returns the SQL to be used in order to an UNSIGNED INTEGER column to SIGNED. * diff --git a/lib/searchlib.php b/lib/searchlib.php index 440eb4b9f29..0cb47a510e4 100644 --- a/lib/searchlib.php +++ b/lib/searchlib.php @@ -418,6 +418,8 @@ function search_generate_SQL($parsetree, $datafield, $metafield, $mainidfield, $ if ($DB->sql_regex_supported()) { $REGEXP = $DB->sql_regex(true); $NOTREGEXP = $DB->sql_regex(false); + $regexwordbegin = $DB->sql_regex_get_word_beginning_boundary_marker(); + $regexwordend = $DB->sql_regex_get_word_end_boundary_marker(); } $params = array(); @@ -456,8 +458,8 @@ function search_generate_SQL($parsetree, $datafield, $metafield, $mainidfield, $ break; case TOKEN_EXACT: $SQLString .= "(($datafield $REGEXP :$name1) OR ($metafield $REGEXP :$name2))"; - $params[$name1] = "[[:<:]]".$value."[[:>:]]"; - $params[$name2] = "[[:<:]]".$value."[[:>:]]"; + $params[$name1] = $regexwordbegin.$value.$regexwordend; + $params[$name2] = $regexwordbegin.$value.$regexwordend; break; case TOKEN_META: if ($metafield != '') { diff --git a/lib/upgrade.txt b/lib/upgrade.txt index 29d3dcdef75..367b0f7b4e1 100644 --- a/lib/upgrade.txt +++ b/lib/upgrade.txt @@ -1,6 +1,10 @@ This files describes API changes in core libraries and APIs, information provided here is intended especially for developers. +=== 3.11.11 === +* New DML driver methods `$DB->sql_regex_get_word_beginning_boundary_marker` and `$DB->sql_regex_get_word_end_boundary_marker` + for managing word boundary markers in a database driver supporting regex syntax when searching. + === 3.11.8 === * The check for $plugin->incompatible was found to be incorrect. The $plugin->incompatible attribute is meant to define the minimum Moodle version the plugin is incompatible with but the implemented logic for the check was the opposite. Plugins declaring this