Эта тема на forum.dklab.ru


Dmitry Simerzin: MySQL - переход с 3.23.xx на 4.1.7
Поделитесь впечатлениями, плз... Особенно на счет кодировок.

Вопрос, собственно, вот в чем: как, "чисто теоретически", правильно "обновиться"? Неужели только "перезаливом" базы?

Ситуация такая: был MySQL 3.23.xx - стал 4.1.7 (всё это апгрейдил хостер, и с этим всё нормально). Таблицы получили свои умолчательные "шведские" collation'ы, и чисто внешне вроде бы ничего не изменилось. Ну, разве что сортировка по русскому тексту неправильно работала, или ещё кое-где мелькали ???? вместо "тема"..

Проблема (была) в том, что MySQL 4.1.7 заменяет русский текст на ???? для VARCHAR, если вы просто меняете collation. Причем, это не происходит для полей типа TEXT.

Это так и должно быть?
Дмитрий Котеров:
Проблемы две:
1. Формат паролей изменился. Чтобы поддерживались старые, надо запускать сервер с ключом --old-passwords (или что-то вроде того).
2. Удалилась кодировка win1251, вместо нее теперь cp1251. Но она имеет другой номер! Соответственно, все, что было в win1251, работать перестанет. Я вылечил это так: в /usr/local/mysql/share/mysql/charsets.Index.xml добавил в блок для cp1251:

<collation name="cp1251_general_ci" id="17">
<order>Russian</order>
<order>Belarusian</order>
<order>Bulgarian</order>
<order>Macedonian</order>
<order>Serbian</order>
<order>Mongolian</order>
<order>Ukrainian</order>
</collation>

и затем в cp1251.xml скопировал контейнер <collation name="cp1251_general_ci"/> в <collation name="cp1251_general_ci"/>. В результате старые таблицы стали поддерживаться.

Еще набольшой ликбез:
- charset - неупорядоченный набор символов алфавита. Может быть один и тот же сразу у нескольких языков (например, латинский и английский).
- collation - правила сравнения символов в рамках конкретного charset-а. Вот тут могут быть различия! Например, в одном языка буква X идет до буквы Y, а в другом - после. Также правила перевода в верхний и нижний регистр.

См. документацию MySQL.
Dmitry Simerzin:
Я немного иначе сформулирую вопрос.

В 4.1.7 создаем таблицу:

CREATE TABLE `t1` (
`f1` varchar(10),
`f2` char(3),
`f3` text
) ENGINE=MyISAM DEFAULT CHARSET=cp1251;

INSERT INTO `t1` VALUES ('рус', 'рус', 'рус');


Теперь выполняем:

ALTER TABLE `t1` CHANGE `f1` `f1` VARCHAR(10) CHARACTER SET latin1 COLLATE latin1_swedish_ci
ALTER TABLE `t1` CHANGE `f2` `f2` CHAR(3) CHARACTER SET latin1 COLLATE latin1_swedish_ci
ALTER TABLE `t1` CHANGE `f3` `f3` TEXT CHARACTER SET latin1 COLLATE latin1_swedish_ci

и получаем: `t1` VALUES ('???', '???', 'рус')

Зачем MySQL меняет содержимое таблицы? И если этому есть объяснение, то почему только для CHAR ?
Дмитрий Котеров:
А зачем Вы пытаетесь шведскую локаль поставить, да еще и latin1? У Вас там что, на шведском текст?
Используйте либо UTF-8, либо cp1251. Ипрямо при создании таблицы, конечно.
Dmitry Simerzin:
У Вас там что, на шведском текст?
Текст русский (такой же форум, как и здесь).

Для latin1, collation по умолчанию - latin1_swedish_ci. После того, как хостер обновил MySQL, все таблицы получили именно этот CharacterSet и Collation. Как их можно было по-простому переключить на cp1251?

А зачем Вы пытаетесь шведскую локаль поставить, да еще и latin1?
Это для примера, можете сделать наоборот, результат будет одинаковый - ?? ??? ?????.

Кстати, у Вас здесь четверка стоит, или тройка (в смысле, версия MySQL)?
Дмитрий Котеров:
После того, как хостер обновил MySQL, все таблицы получили именно этот CharacterSet и Collation.
А по голове настучать такому хостеру не пробовали? Еще не поздно, попробуйте. Точно поможет.

Как их можно было по-простому переключить на cp1251?
Вот это интересный вопрос. Лично я не знаю, как. Попробуйте как-нибудь через BINARY сделать, что ли... Или - сохранить дамп старых таблиц, затем поменять прямо в дампе названия подировок, и загрузить дамп назад.

Вопросики он ставит, потому что не может найти соответствующих символов в другой локали. Там же при конвертировании все проходит через Unicode. Естественно, он не видит соответствий.

Здесь стоит 4.1, и, чтобы все заработало, я проделывал действия, описанные выше.
Dmitry Simerzin:
Или - сохранить дамп старых таблиц, затем поменять прямо в дампе названия подировок, и загрузить дамп назад.
Да, пришлось сделать именно так. Тут тоже не всё оказалось просто, с вытаскиванием и кодировками.

Точно поможет.
Да бог с ним (не на таких я там условиях хостаюсь, чтобы из-за этого ругаться, тем более, что все закончилось благополучно). Все эти проблемы зато заставили поглубже поковыряться.

Вопросики он ставит, потому что не может найти соответствующих символов в другой локали.
Хорошо, почему тогда это не происходит с TEXT, а только с CHAR? Странно.

Еще не очень понятна разница между
SET NAMES
и
SET CHARACTER SET

Я пока что сделал по аналогии с phpMyAdmin (только без ошибки, которая в оригинале :-).

в config.php добавил:
$mysql_charset = 'cp1251';
$collation_connection = 'cp1251_general_ci';

в includes\db.php (сразу после подключения)

// Set connection charset & collation for MySQL (based on phpMyAdmin)
if( preg_match("/^mysql/i", SQL_LAYER) )
{
$sql = 'SELECT VERSION() AS mysql_version';

$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$match = explode('.', $row['mysql_version']);

if (!isset($row))
{
define('MYSQL_INT_VERSION', 32332);
define('MYSQL_STR_VERSION', '3.23.32');
}
else
{
define('MYSQL_INT_VERSION', (int)sprintf('%d%02d%02d', $match[0], $match[1], intval($match[2])));
define('MYSQL_STR_VERSION', $row['mysql_version']);
}
unset($result, $row, $match);

if ( MYSQL_INT_VERSION >= 40100 && isset($mysql_charset) )
{
if (empty($collation_connection) || ( strpos($collation_connection, '_') ? substr($collation_connection, 0, strpos($collation_connection, '_')) : $collation_connection) == $mysql_charset )
{
$sql = "SET NAMES $mysql_charset";

if ( !($db->sql_query($sql)) )
{
message_die(CRITICAL_ERROR, 'Could not set MySQL charset', '', __LINE__, __FILE__, $sql);
}
}
else
{
$sql = "SET CHARACTER SET $mysql_charset";

if ( !($db->sql_query($sql)) )
{
message_die(CRITICAL_ERROR, 'Could not set MySQL charset', '', __LINE__, __FILE__, $sql);
}
}
if ( !empty($collation_connection) )
{
$sql = "SET collation_connection = '$collation_connection'";

if ( !($db->sql_query($sql)) )
{
message_die(CRITICAL_ERROR, 'Could not set MySQL collation connection', '', __LINE__, __FILE__, $sql);
}
}
}
}

Это для phpBB.

Эта тема на forum.dklab.ru