Хорошо, вот сложный... У меня есть сервер разработки с mySQL 5.1.73, на котором я написал функцию для нормализации строки для целей поиска. При перемещении функции в производственную среду та же версия mySQL, та же основная версия ОС (CentOS 6.5), новейшие исправления, та же основная версия ядра и т. д. Функция перестала работать.
Вот функция
CREATE DEFINER=`user`@`%` FUNCTION `normalize`(str VARCHAR(255)) RETURNS varchar(255) CHARSET utf8
BEGIN
DECLARE normstring VARCHAR(255);
DECLARE i INT;
SET i = 0;
SET normstring = '';
SET str = lower(str);
loop1: WHILE i < length(str) DO
CASE substring(str,i,1)
WHEN 'ä' THEN SET normstring = concat(normstring,'ae');
WHEN 'ö' THEN SET normstring = concat(normstring,'oe');
WHEN 'ü' THEN SET normstring = concat(normstring,'ue');
WHEN 'ß' THEN SET normstring = concat(normstring,'ss');
WHEN '/' THEN SET i = i + 1; ITERATE loop1;
WHEN '.' THEN SET i = i + 1; ITERATE loop1;
WHEN '-' THEN SET i = i + 1; ITERATE loop1;
WHEN '(' THEN SET i = i + 1; ITERATE loop1;
WHEN ')' THEN SET i = i + 1; ITERATE loop1;
WHEN ' ' THEN SET i = i + 1; ITERATE loop1;
WHEN '\'' THEN SET i = i + 1; ITERATE loop1;
WHEN '\\' THEN SET i = i + 1; ITERATE loop1;
ELSE SET normstring = concat(normstring,substring(str,i,1));
END CASE;
SET i = i + 1;
END WHILE;
RETURN normstring;
END$$
DELIMITER ;
На сервере разработки это преобразует «Mönßtär» в «moensstaer», а на рабочем сервере — в «mönßtä».
Замена SET i = 0;
и WHILE i < length(str)
на SET i = 1;
и WHILE i <= length(str)
исправляет отсутствующий последний символ, так что результат "mönßtär", но один сервер не должен начинать счет с 0, а другой с 1, верно? И рабочий сервер оставляет все специальные символы нетронутыми.
Я сравнил все глобальные переменные, а не только те, которые явно установлены в my.cnf, и, за исключением настроек часового пояса, пароля и символической ссылки, они равны (да, я должен исправить эти различия, но это не должно иметь ничего общего с моей проблемой, да?)
Есть ли какие-то настройки компиляции, которые могут повлиять на это поведение, или какие-то внешние библиотеки, которые использует mySQL? Вероятно, мне придется найти обходной путь для проблемы - я планирую нормализовать в приложении, а не в базе данных - функция все равно слишком медленная в больших запросах - но было бы неплохо преобразовать существующие данные в базе данных. Но мне действительно любопытно, что вызывает такое странное поведение.
Настройки набора символов на обоих серверах (из работающей среды):
character_set_client........................ utf8
character_set_connection.................... utf8
character_set_database...................... utf8
character_set_filesystem.................... binary
character_set_results....................... utf8
character_set_server........................ utf8
character_set_system........................ utf8
collation_connection........................ utf8_unicode_ci
collation_database.......................... utf8_unicode_ci
collation_server............................ utf8_unicode_ci