Добро пожаловать!
Здесь вы можете найти ответ на интересующий вас вопрос в отрасли сайтостроения, познакомится ближе с web технологиями и web стандартами.

Статьи

Перенос базы из mysql ранних версий в mysql-4.1 без проблем с кодировкой

Автор: nmind . konstantin kalachev / http://tutorial.ru

При обновлении базы mysql с ранних версии до версии 4.1 многие сталкиваются с проблемой битой кодировки. Происходит это потому,что в 4.1 используется только utf-8 и все символы из дампов конвертируются в него. То есть, если у вас был дамп в кодировке windows-1251, то при импортировании его в базу mysql-4.1 он переведется в utf-8 и восстановить текст будет уже невозможно.

Решение - говорить mysql о том в какой кодировке ему будет импортироваться текст. Для того, чтобы лучше понять как это делается приведу пример для базы, к которой у вас нет другого доступа, кроме как mysql интерфейс. Например, это может быть зарубежный хостинг.

Предположим, что у нас есть sql-дамп таблицы my_win1251_table. Его кодировка windows-1251. Добавляем в начало файла строки, которые будут менять значение переменных для mysql-сессии. Получается:

SET collation_connection = cp1251_general_ci;
SET collation_database = cp1251_general_ci;
SET collation_server = cp1251_general_ci;
SET character_set_client = cp1251;
SET character_set_connection = cp1251;
SET character_set_database = cp1251;
SET character_set_results = cp1251;
SET character_set_server = cp1251;

DROP TABLE IF EXISTS `my_win1251_table`;

CREATE TABLE `my_win1251_table` (
  `content` varchar(100) NOT NULL default ''
) TYPE=MyISAM;

INSERT INTO `my_win1251_table` VALUES ('Текст на русском из базы mysql-4.0.15a');

Теперь заливаем дамп в базу mysql-4.1

mysql -usomeuser -psomepasswd somedb < dump.sql

Если теперь посмотреть на дамп из базы mysql-4.1 то он будет выглядеть вот так:

DROP TABLE IF EXISTS `my_win1251_table`;

CREATE TABLE `my_win1251_table` (
  `content` varchar(100) NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=cp1251;

LOCK TABLES `my_win1251_table` WRITE;
INSERT INTO `my_win1251_table` VALUES ('Текст на русском из базы mysql-4.0.15a');
UNLOCK TABLES;

Обратите внимание, что в INSERT текст поля теперь в формате utf-8. И он длиннее чем оригинал, потому что utf-8 тратит два байта на один символ. Именно поэтому при выводе этого текста на html-страницу будут появляться знаки вопроса.

Так же стоит обратить внимание на текст нового дампа CREATE TABLE ... DEFAULT CHARSET=cp1251;. В mysql-4.1 появился параметр charset, который присваивается как базе, так и каждой таблице в отдельности.

Для того, чтобы добиться не только правильного ввода данных, но и вывода нужно сказать mysql базе о том, что мы хотим получить от нее данные в кодировке windows-1251, в чем нам поможет команда "SET NAMES cp1251;".

mysql -usomeuser -psomepasswd somedb

mysql> SET NAMES cp1251;
mysql> SELECT * FROM my_win1251_table;

+----------------------------------------+
| content                                |
+----------------------------------------+
| Текст на русском из базы mysql-4.0.15a |
+----------------------------------------+

1 row in set (0.00 sec)

Глобальные способы решения проблемы

Пример, приведеный выше доступен всем, у кого есть доступ к mysql инерфейсу. Но если у вас есть права root на сервере, то можно постараться заранее предугадать проблему с кодировками.

Для этого в файле /etc/my.cnf можно прописать следующее

[client]
default-character-set = cp1251

[mysqld]
default-character-set = cp1251

init-connect = 'SET NAMES cp1251'

Причем, у меня все заработало правильно и без указания init-connect, но многим помогает именно эта строчка.

Так же можно скомпилировать mysql с указанием параметров configure
"--with-charset=cp1251 --with-collaption=cp1251_general_ci"

Переменные mysql-4.1 и странное поведение команды "SET NAMES cp1251;" и "SET CHARACTER SET cp1251;"

Если у вас все получилось и больше ничего не нужно от базы эту часть читать не обязательно.

В интернете громадное количество информации по этой проблеме, но почти каждый ответ заключается в совете задавать команды SET NAMES cp1251; и SET CHARACTER SET cp1251; после соединения. Вот пример mysql-сессии, по которой явно видно, что mysql-4.1 меняет только часть переменных при выполнении этих команд.

mysql> SET NAMES cp1251;
Query OK, 0 rows affected (0.00 sec)

mysql> SET CHARACTER SET cp1251;
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW VARIABLES LIKE 'character_set%';

+--------------------------+----------------------------------------+
| Variable_name            | Value                                  |
+--------------------------+----------------------------------------+
| character_set_client     | cp1251                                 |
| character_set_connection | latin1                                 |
| character_set_database   | latin1                                 |
| character_set_results    | cp1251                                 |
| character_set_server     | latin1                                 |
| character_set_system     | utf8                                   |
| character_sets_dir       | /usr/local/mysql/share/mysql/charsets/ |
+--------------------------+----------------------------------------+

7 rows in set (0.00 sec)

mysql> SHOW VARIABLES LIKE 'collation%';
+----------------------+-------------------+
| Variable_name        | Value             |
+----------------------+-------------------+
| collation_connection | latin1_swedish_ci |
| collation_database   | latin1_swedish_ci |
| collation_server     | latin1_swedish_ci |
+----------------------+-------------------+

3 rows in set (0.01 sec)

В документации написано, что SET NAMES меняет переменные character_set_client, character_set_results, character_set_connection, но на деле переменная character_set_connection остается прежней. Так же там написано, что SET CHARACTER SET меняет переменные character_set_client, character_set_results, collation_connection, но на самом деле collation_connection остается прежней.

А вот пример ручной замены всех возможных переменных:

mysql> SHOW VARIABLES LIKE 'character_set%';

+--------------------------+----------------------------------------+
| Variable_name            | Value                                  |
+--------------------------+----------------------------------------+
| character_set_client     | latin1                                 |
| character_set_connection | latin1                                 |
| character_set_database   | latin1                                 |
| character_set_results    | latin1                                 |
| character_set_server     | latin1                                 |
| character_set_system     | utf8                                   |
| character_sets_dir       | /usr/local/mysql/share/mysql/charsets/ |
+--------------------------+----------------------------------------+

7 rows in set (0.00 sec)

mysql> SHOW VARIABLES LIKE 'collation%';

+----------------------+-------------------+
| Variable_name        | Value             |
+----------------------+-------------------+
| collation_connection | latin1_swedish_ci |
| collation_database   | latin1_swedish_ci |
| collation_server     | latin1_swedish_ci |
+----------------------+-------------------+

3 rows in set (0.00 sec)

mysql> SET collation_connection = cp1251_general_ci;
Query OK, 0 rows affected (0.00 sec)

mysql> SET collation_database = cp1251_general_ci;
Query OK, 0 rows affected (0.00 sec)

mysql> SET collation_server = cp1251_general_ci;
Query OK, 0 rows affected (0.00 sec)

mysql> SET character_set_client = cp1251;
Query OK, 0 rows affected (0.00 sec)

mysql> SET character_set_connection = cp1251;
Query OK, 0 rows affected (0.00 sec)

mysql> SET character_set_database = cp1251;
Query OK, 0 rows affected (0.00 sec)

mysql> SET character_set_results = cp1251;
Query OK, 0 rows affected (0.00 sec)

mysql> SET character_set_server = cp1251;
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW VARIABLES LIKE 'character_set%';

+--------------------------+----------------------------------------+
| Variable_name            | Value                                  |
+--------------------------+----------------------------------------+
| character_set_client     | cp1251                                 |
| character_set_connection | cp1251                                 |
| character_set_database   | cp1251                                 |
| character_set_results    | cp1251                                 |
| character_set_server     | cp1251                                 |
| character_set_system     | utf8                                   |
| character_sets_dir       | /usr/local/mysql/share/mysql/charsets/ |
+--------------------------+----------------------------------------+

7 rows in set (0.00 sec)

mysql> SHOW VARIABLES LIKE 'collation%';

+----------------------+-------------------+
| Variable_name        | Value             |
+----------------------+-------------------+
| collation_connection | cp1251_general_ci |
| collation_database   | cp1251_general_ci |
| collation_server     | cp1251_general_ci |
+----------------------+-------------------+

3 rows in set (0.00 sec)

Как видите, теперь все нормально. Не стоит заменять переменную "character_set_system" , она отвечает за внутренюю кодировку базы и всегда будет utf-подобной.