PDA

Просмотр полной версии : [Мануал] Решение проблемы с кодировкой в MySQL | R33+



$continue$
14.03.2016, 19:49
Меня уже долгое время смущал вариант "настройки" кодировки от $continue$, ибо хоть я особо и не интересовался никогда ковырянием кодировки в MySQL (просто нужды не было), но знал, что вот этот запрос:
SET CHARACTER SET 'utf8'
является групповым. То бишь, отправляя этот единственный запрос, Вы, сразу настраиваете три параметра (*документация (https://dev.mysql.com/doc/refman/5.7/en/set-character-set.html)*) и он равносилен таким трём запросам:
SET character_set_client = utf8;
SET character_set_results = utf8;
SET collation_connection = @@collation_database;
И если взглянуть на запросы, которые $continue$ предлагает отправлять, можно заметить там идентичные запросы.

Но если про "SET CHARACTER SET" я узнал совершенно "случайно", то с запросом "SET NAMES" мне так не повезло и до текущего момента я не знал какие запросы он в себе скрывает. В итоге, документация (https://dev.mysql.com/doc/refman/5.7/en/set-names.html) говорит про три таких запроса:
SET character_set_client = utf8;
SET character_set_connection = utf8;
SET character_set_results = utf8;
И вновь мы видим запросы на изменение тех же опций, которые мало того, что содержатся в "SET CHARACTER SET", так ещё и впоследствии изменяются отдельными запросами с "utf8" на "cp1251".

Иными словами, таким вот "решением проблемы с кодировкой", которое дано в теме, Вы каждый раз будете "дёргать" одни и те же опции, изменяя их значение с одного на другое.



На этой ноте можно было бы закончить, но мне стало интересно окончательно закрыть тему кодировки для SA-MP. И я был бы не я, если бы не поделился найденной информацией с Вами :) Заодно, если я вдруг ошибусь, кто-то сможет меня поправить.

Маленькая оговорка касаемо определений:
Сервер - это наш сервер MySQL с базами дарных, блекджеком и всем остальным.
Клиент - это, в нашем случае, сервер SA-MP
Так же стоит понимать, что все опции настраивают именно сервер MySQL. Даже опция, связанная с кодировкой запросов от клиента, влияет именно на сервер, так как именно он будет заниматься конвертированием данных. То бишь, уяснили: все операции с данными происходят не на стороне сервера SA-MP или плагина, а именно на стороне сервера MySQL. И всеми опциями мы лишь сообщаем серверу MySQL нужную информацию для того, чтоб он совершил конвертирование.



Давайте разберёмся с основными опциями, которые нам могут пригодится. В случае с SA-MP нам потребуется всего несколько, так как остальные MySQL либо самостоятельно подстроит под эти запросы, либо они уже настроены как надо по умолчанию.


character_set_client - В этой опции указaывается кодировка, в которой будут поступать данные от клиента к серверу.
character_set_results - В этой опции указывается кодировка, в которую сервер конвертирует данные перед отправкой их клиенту.
character_set_connection - В этой опции указывается кодировка, в которую сервер перекодирует данные, полученные от клиента, перед тем, как начнёт выполнять запрос (клиент->character_set_connection->сервер)


Собственно, всё. Опция collation_connection, которую предлагает настроить $continue$, для каждой кодировки имеет установку по умолчанию, которая, в случае с utf8, будет равна как раз "utf8_general_ci", поэтому определять её самостоятельно нет смысла.
Если кому интересно, посмотреть "настройки по умолчанию" для той или иной кодировки можно при помощи запроса

SHOW COLLATION WHERE charset = 'имя_кодировки';
Результатом запроса будет список всех доступных вариантов представления для указанной кодировке и напротив того представления, которая является представлением по умолчанию, в столбце "Default" будет стоять "Yes".

Вот пример результата для utf8

SHOW COLLATION WHERE charset = 'utf8'


https://i.imgur.com/Im7yKLd.png


Теперь осталось действительно решить все проблемы с кодировкой, дабы всё работало как надо.
В чём заключается проблема? В том, что сервер не знает в какой кодировке работает клиент, из-за чего не может правильно конвертировать данные, пришедшие от клиента и подготовить данные к отправке для клиента. И если Вы взгляните на те 3 опции, что я перечислил выше, то найдёте решение всем проблемам.
Я не зря расписал то, в чём заключается проблема, ибо если Вы сейчас перечитаете составленное мной определение, то увидите, что в обоих случаях фигурирует именно клиент. А с какой кодировкой работает наш клиент? Правильно, cp1251. Поэтому все те свистопляски с 'utf8', которые устроил $continue$ в своём варианте, бессмысленны (можно разве что в character_set_server передавать "utf8", если Вы не уверены в том, что сервер MySQL изначально настроен под эту кодировку).

Этих двух запросов должно целиком и полностью хватить для хранения русского текста в базе (с учётом того, что Вы никак не правили остальные настройки кодировки и они выставлены по умолчанию или же настроены правильно):
mysql_query(var_connection, "SET character_set_client = 'cp1251'", false);// Определяем кодировку для запросов от сервера SA-MP к базе
mysql_query(var_connection, "SET character_set_results = 'cp1251'", false);// Определяем кодировку от базы данных к нашему серверу SA-MP
Как минимум, вся та каша из запросов, что даёт $continue$, точно не нужна.

mysql_query(var_connection, "SET SESSION character_set_server='utf8'", false);// Устанавливаем кодировку, в которой данные будут хранится на сервере MySQL (кодировка самого сервера, иными словами)


P.S. Всё это подкреплено лишь моим маленьким "расследованием" (копанием документации) и простыми тестами на локальном сервере с дефолтными настройками MySQL, так что было бы неплохо проверить все мои доводы в более разных условиях, дабы уже окончательно отшлифовать код, если вдруг я чего-то не учёл.
Засим я откланиваюсь :thank_you: Надеюсь, что у меня получилось понятно объяснить Вам назначение перечисленных опций. Спасибо за внимание



Доброго времени суток! В интернете есть много решение данной проблемы (на форумах по Pawn), но они то не работают, то выбивают ошибку в лог. Пример кода при котором в лог идет ошибка:


mysql_set_charset(!"utf8_bin");
mysql_function_query(MYSQL_ARG, !"SET NAMES 'utf8'", false, "", "");
mysql_function_query(MYSQL_ARG, !"SET CHARACTER SET 'cp1251'", false, "", "");

Ошибка в логах:

http://i.imgur.com/b5egfep.png

Решение данной проблемы я все таки добился. И хочу поделиться с Вами: (до версии R40)


SetMySQLEncoding(var_connection)
{
mysql_function_query(var_connection, !"SET CHARACTER SET 'utf8'", false, "", "");
mysql_function_query(var_connection, !"SET NAMES 'utf8'", false, "", "");
mysql_function_query(var_connection, !"SET character_set_client = 'cp1251'", false, "", "");
mysql_function_query(var_connection, !"SET character_set_connection = 'cp1251'", false, "", "");
mysql_function_query(var_connection, !"SET character_set_results = 'cp1251'", false, "", "");
mysql_function_query(var_connection, !"SET SESSION collation_connection = 'utf8_general_ci'", false, "", "");
}

После версии R40:


SetMySQLEncoding(MySQL:var_connection)
{
mysql_tquery(var_connection, !"SET CHARACTER SET 'utf8'", "", "");
mysql_tquery(var_connection, !"SET NAMES 'utf8'", "", "");
mysql_tquery(var_connection, !"SET character_set_client = 'cp1251'", "", "");
mysql_tquery(var_connection, !"SET character_set_connection = 'cp1251'", "", "");
mysql_tquery(var_connection, !"SET character_set_results = 'cp1251'", "", "");
mysql_tquery(var_connection, !"SET SESSION collation_connection = 'utf8_general_ci'", "", "");
}

Пример использование (сразу после mysql_connect):


SetMySQLEncoding(mysql_connect_ID); // Где mysql_connect_ID - Подключение к базе данных

Почитать о character_set (https://habrahabr.ru/post/10983/).
Возможно у Вас есть более простое решение данной проблемы. Я буду рад если Вы поделитесь решением.

DmX
14.03.2016, 19:52
Очень полезный урок, Данил очень помог мне :)

DeimoS
17.03.2016, 10:45
SetEncodingMySQL(var_connection)
{
mysql_function_query(var_connection, !"SET CHARACTER SET 'utf8'", false, "", "");
mysql_function_query(var_connection, !"SET NAMES 'utf8'", false, "", "")
mysql_function_query(var_connection, !"SET character_set_client = 'cp1251'", false, "", "");
mysql_function_query(var_connection, !"SET character_set_connection = 'cp1251'", false, "", "");
mysql_function_query(var_connection, !"SET character_set_results = 'cp1251'", false, "", "");
mysql_function_query(var_connection, !"SET SESSION collation_connection = 'utf8_general_ci'", false, "", "");
}
Точки с запятой нет в конце :)

mysql_function_query(var_connection, !"SET NAMES 'utf8'", false, "", "")

$continue$
17.03.2016, 11:39
Thank, DeimoS. Fix, update.

Daniel_Cortez
17.03.2016, 13:19
Thank, DeimoS. Fix, update.
"Благодарить, DeimoS. Исправлять, обновлять."
Lol'd.

DeimoS
17.03.2016, 13:31
"Благодарить, DeimoS. Исправлять, обновлять."
Lol'd.


http://fandea.ru/upload/000/u1/008/7f7dc00e.jpg

$continue$
17.03.2016, 16:15
Да, да ты опять поймал меня с плохим знанием English/Russian Language :(

"Благодарить, DeimoS. Исправлять, обновлять."
Lol'd.

seriu
03.06.2016, 21:31
Уже давно как-то сделал только это:

mysql_function_query(base, !"SET NAMES cp1251", false, "", "" );
И никаких "???????" нету.

$continue$
03.06.2016, 21:47
Включи полное логирование (HTML формат) и скинь логи. Вот только сервер под управлением Linux

Уже давно как-то сделал только это:

mysql_function_query(base, !"SET NAMES cp1251", false, "", "" );
И никаких "???????" нету.

seriu
04.06.2016, 11:48
Включи полное логирование (HTML формат) и скинь логи. Вот только сервер под управлением Linux

http://i.imgur.com/MofrHLe.png
https://yadi.sk/d/r2ZnXERmsF9rW
хостинг: myarena ( linux )
п.с я сделал отдельную таблицу для команды "/su" т.е записывается в бд "wanted" причину
"11:41:05 CMySQLResult::GetRowDataByName OK row: '0', field: "Reason0", data: "ÒÅÑÒ ïàì ïàì "
Но, на сервере все отображается как нужно.
http://i.imgur.com/vdmKQgW.png

$continue$
04.06.2016, 11:52
Когда я логировал были ошибки.

seriu
04.06.2016, 12:05
Когда я логировал были ошибки.

Мистика какая-то :awesome:

$continue$
20.10.2016, 15:29
Обновлено.

HarrWe
26.10.2016, 08:09
Жаль этот способ не решает проблем с кодировкой логов mysql

[20:10:45] [ERROR] h| (C:\Users\harrw\Desktop\samp_ser\gamemodes\xx.pwn:2715)
[21:43:00] [ERROR] Hѕr (C:\Users\harrw\Desktop\samp_ser\gamemodes\xx.pwn:2714)
[22:21:52] [ERROR] *B| (C:\Users\harrw\Desktop\samp_ser\gamemodes\xx.pwn:5707)
[22:25:05] [ERROR] @№_ (C:\Users\harrw\Desktop\samp_ser\gamemodes\xx.pwn:5707)
[07:08:31] [ERROR] ˜кy (C:\Users\harrw\Desktop\samp_ser\gamemodes\xx.pwn:5717)

$continue$
16.01.2017, 00:20
Будет время - проверю.

Жаль этот способ не решает проблем с кодировкой логов mysql

[20:10:45] [ERROR] h| (C:\Users\harrw\Desktop\samp_ser\gamemodes\xx.pwn:2715)
[21:43:00] [ERROR] Hѕr (C:\Users\harrw\Desktop\samp_ser\gamemodes\xx.pwn:2714)
[22:21:52] [ERROR] *B| (C:\Users\harrw\Desktop\samp_ser\gamemodes\xx.pwn:5707)
[22:25:05] [ERROR] @№_ (C:\Users\harrw\Desktop\samp_ser\gamemodes\xx.pwn:5707)
[07:08:31] [ERROR] ˜кy (C:\Users\harrw\Desktop\samp_ser\gamemodes\xx.pwn:5717)

Skyline
23.01.2017, 21:36
MySQL R5
Добавил и ошибки.

error 017: undefined symbol "SetMySQLEncoding"
error 017: undefined symbol "var_connection"
error 017: undefined symbol "var_connection"
error 017: undefined symbol "var_connection"
error 017: undefined symbol "var_connection"
error 017: undefined symbol "var_connection"
error 017: undefined symbol "var_connection"

$continue$
24.01.2017, 16:25
И что я должен сделать? Гадать по коду? Что Вы не так сделали?

MySQL R5
Добавил и ошибки.

error 017: undefined symbol "SetMySQLEncoding"
error 017: undefined symbol "var_connection"
error 017: undefined symbol "var_connection"
error 017: undefined symbol "var_connection"
error 017: undefined symbol "var_connection"
error 017: undefined symbol "var_connection"
error 017: undefined symbol "var_connection"

Skyline
24.01.2017, 22:56
И что я должен сделать? Гадать по коду? Что Вы не так сделали?
Разобрался.

vasyok28
31.01.2017, 23:36
Иногда выскакивает такое ×èòåðc
а иногда ?? ?????? ))

Может быть за сравнение в БД utf8_general_ci ?

vasyok28
03.02.2017, 04:09
Подниму вопрос

$continue$
02.07.2017, 16:21
Сравнение в базе должно стоять utf8_general_ci

Иногда выскакивает такое ×èòåðc
а иногда ?? ?????? ))

Может быть за сравнение в БД utf8_general_ci ?

DeimoS
29.03.2018, 09:40
У многих (уже где-то 8 человек ко мне обращались с подобными вопросами), даже на новых версиях плагина, возникают проблемы с кодировкой при использовании этого кода. И решаются эти проблемы отправкой запросов через mysql_query.
В причины появления подобного я не вникал, но подразумеваю, что такое случается, когда один запрос обрабатывается быстрее другого и, вероятно, некоторые изменяемые параметры зависимы от других, из-за чего и происходит слёт.

Вот, если что, пример такой проблемы, где я более подробно описал возможную причину
https://i.imgur.com/8Gctpsl.png


https://i.imgur.com/JhRt7Uy.png

$continue$
29.03.2018, 13:25
Было бы не плохо, узнать какая версия MySQL? (потому, что когда писал под R33-R39, оно работало). Вчера на сервере с онлайном фиксил проблему с кодировкой. Там версия R39-2 и тут уже появляются не явные проблемы. Решил так:


mysql_tquery(sql_connection, !"SET CHARACTERSET 'utf8'","","");
mysql_tquery(sql_connection, !"SET NAMES 'cp1251'","","");
mysql_tquery(sql_connection, !"SET character_set_client = 'cp1251'","","");
mysql_tquery(sql_connection, !"SET character_set_connection= 'cp1251'","","");
mysql_tquery(sql_connection, !"SET character_set_results= 'cp1251'","","");
mysql_tquery(sql_connection, !"SET SESSION character_set_server= 'utf8'","","");
mysql_tquery(sql_connection, !"SET SESSION collation_connection= 'utf8_general_ci'","","");


Если, кто-то не понял, то SET NAMES = cp1251. Правда, я не сторонник Windows1251. (адовая кодировка, которая под другими ОСями не живет). Нужно проверять метод от @DeimoS

DeimoS
29.03.2018, 13:49
Версия плагина последняя. Я и сам подобным страдал на локальном сервере, но я тогда и кодировки по всякому пробовал менять (как в базе, так и в твоих запросах), и потом перешёл на mysql_query (при этом, отвлекаясь периодически), так что точно не смог определить закономерность, которая помогла решить проблему.

$continue$
29.03.2018, 14:01
Ну вот, выше запросы точно работают. Нужно будет проверить твой вариант, но пока нет особо лишнего времени.

так что точно не смог определить закономерность, которая помогла решить проблему.

Fallen A.
29.03.2018, 16:19
Было бы не плохо, узнать какая версия MySQL? (потому, что когда писал под R33-R39, оно работало). Вчера на сервере с онлайном фиксил проблему с кодировкой. Там версия R39-2 и тут уже появляются не явные проблемы. Решил так:


mysql_tquery(sql_connection, !"SET CHARACTERSET 'utf8'","","");
mysql_tquery(sql_connection, !"SET NAMES 'cp1251'","","");
mysql_tquery(sql_connection, !"SET character_set_client = 'cp1251'","","");
mysql_tquery(sql_connection, !"SET character_set_connection= 'cp1251'","","");
mysql_tquery(sql_connection, !"SET character_set_results= 'cp1251'","","");
mysql_tquery(sql_connection, !"SET SESSION character_set_server= 'utf8'","","");
mysql_tquery(sql_connection, !"SET SESSION collation_connection= 'utf8_general_ci'","","");


Если, кто-то не понял, то SET NAMES = cp1251. Правда, я не сторонник Windows1251. (адовая кодировка, которая под другими ОСями не живет). Нужно проверять метод от @DeimoS

Весь мод сохранен в 1251 и благополучно запускается. Работает так же на *nix системах. Кодировка базы utf8_general_ci.

Вот все мои настройки:


mysql_debug(true);
mysql_set_charset("cp1251");
mysql_function_query(mysql_connect_id, "SET NAMES cp1251", false, "", "" ) ;

DeimoS
29.03.2018, 16:34
Весь мод сохранен в 1251 и благополучно запускается. Работает так же на *nix системах. Кодировка базы utf8_general_ci.

Вот все мои настройки:


mysql_debug(true);
mysql_set_charset("cp1251");
mysql_function_query(mysql_connect_id, "SET NAMES cp1251", false, "", "" ) ;


Такое пройдёт только в случае, если сам MySQL сервер перед этим настроен нормально (настройка заключается не только в том, что ты в базе прописал кодировку). Уж лучше перестраховаться и отправить пару лишних запросов, чем потом страдать :)

Fallen A.
29.03.2018, 17:11
Такое пройдёт только в случае, если сам MySQL сервер перед этим настроен нормально (настройка заключается не только в том, что ты в базе прописал кодировку). Уж лучше перестраховаться и отправить пару лишних запросов, чем потом страдать :)

Ну так нормальные люди изначально все нормально настраивают. Или не так?

П.С. И да, я знаю, как настраивается сервер БД.

DeimoS
29.03.2018, 17:15
Ну так нормальные люди изначально все нормально настраивают. Или не так?

П.С. И да, я знаю, как настраивается сервер БД.

Ну далеко не все хостинги позволяют настраивать подобные вещи :) Да и, опять же, если слетят настройки, ничего хорошего не получится. Лучше уж перестраховаться и сделать систему защищенной, чем потом фиксить всё в кротчайшие сроки

Fallen A.
31.03.2018, 11:20
Ну далеко не все хостинги позволяют настраивать подобные вещи :) Да и, опять же, если слетят настройки, ничего хорошего не получится. Лучше уж перестраховаться и сделать систему защищенной, чем потом фиксить всё в кротчайшие сроки

С хостингами не знаком в принципе :) У меня своя серверная.

DeimoS
31.03.2018, 12:53
С хостингами не знаком в принципе :) У меня своя серверная.

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

DeimoS
07.06.2018, 18:43
Меня уже долгое время смущал вариант "настройки" кодировки от $continue$, ибо хоть я особо и не интересовался никогда ковырянием кодировки в MySQL (просто нужды не было), но знал, что вот этот запрос:
SET CHARACTER SET 'utf8'
является групповым. То бишь, отправляя этот единственный запрос, Вы, сразу настраиваете три параметра (*документация (https://dev.mysql.com/doc/refman/5.7/en/set-character-set.html)*) и он равносилен таким трём запросам:
SET character_set_client = utf8;
SET character_set_results = utf8;
SET collation_connection = @@collation_database;
И если взглянуть на запросы, которые $continue$ предлагает отправлять, можно заметить там идентичные запросы.

Но если про "SET CHARACTER SET" я узнал совершенно "случайно", то с запросом "SET NAMES" мне так не повезло и до текущего момента я не знал какие запросы он в себе скрывает. В итоге, документация (https://dev.mysql.com/doc/refman/5.7/en/set-names.html) говорит про три таких запроса:
SET character_set_client = utf8;
SET character_set_connection = utf8;
SET character_set_results = utf8;
И вновь мы видим запросы на изменение тех же опций, которые мало того, что содержатся в "SET CHARACTER SET", так ещё и впоследствии изменяются отдельными запросами с "utf8" на "cp1251".

Иными словами, таким вот "решением проблемы с кодировкой", которое дано в теме, Вы каждый раз будете "дёргать" одни и те же опции, изменяя их значение с одного на другое.



На этой ноте можно было бы закончить, но мне стало интересно окончательно закрыть тему кодировки для SA-MP. И я был бы не я, если бы не поделился найденной информацией с Вами :) Заодно, если я вдруг ошибусь, кто-то сможет меня поправить.

Маленькая оговорка касаемо определений:
Сервер - это наш сервер MySQL с базами дарных, блекджеком и всем остальным.
Клиент - это, в нашем случае, сервер SA-MP
Так же стоит понимать, что все опции настраивают именно сервер MySQL. Даже опция, связанная с кодировкой запросов от клиента, влияет именно на сервер, так как именно он будет заниматься конвертированием данных. То бишь, уяснили: все операции с данными происходят не на стороне сервера SA-MP или плагина, а именно на стороне сервера MySQL. И всеми опциями мы лишь сообщаем серверу MySQL нужную информацию для того, чтоб он совершил конвертирование.



Давайте разберёмся с основными опциями, которые нам могут пригодится. В случае с SA-MP нам потребуется всего несколько, так как остальные MySQL либо самостоятельно подстроит под эти запросы, либо они уже настроены как надо по умолчанию.


character_set_client - В этой опции указaывается кодировка, в которой будут поступать данные от клиента к серверу.
character_set_results - В этой опции указывается кодировка, в которую сервер конвертирует данные перед отправкой их клиенту.
character_set_connection - В этой опции указывается кодировка, в которую сервер перекодирует данные, полученные от клиента, перед тем, как начнёт выполнять запрос (клиент->character_set_connection->сервер)


Собственно, всё. Опция collation_connection, которую предлагает настроить $continue$, для каждой кодировки имеет установку по умолчанию, которая, в случае с utf8, будет равна как раз "utf8_general_ci", поэтому определять её самостоятельно нет смысла.
Если кому интересно, посмотреть "настройки по умолчанию" для той или иной кодировки можно при помощи запроса

SHOW COLLATION WHERE charset = 'имя_кодировки';
Результатом запроса будет список всех доступных вариантов представления для указанной кодировке и напротив того представления, которая является представлением по умолчанию, в столбце "Default" будет стоять "Yes".

Вот пример результата для utf8

SHOW COLLATION WHERE charset = 'utf8'


https://i.imgur.com/Im7yKLd.png


Теперь осталось действительно решить все проблемы с кодировкой, дабы всё работало как надо.
В чём заключается проблема? В том, что сервер не знает в какой кодировке работает клиент, из-за чего не может правильно конвертировать данные, пришедшие от клиента и подготовить данные к отправке для клиента. И если Вы взгляните на те 3 опции, что я перечислил выше, то найдёте решение всем проблемам.
Я не зря расписал то, в чём заключается проблема, ибо если Вы сейчас перечитаете составленное мной определение, то увидите, что в обоих случаях фигурирует именно клиент. А с какой кодировкой работает наш клиент? Правильно, cp1251. Поэтому все те свистопляски с 'utf8', которые устроил $continue$ в своём варианте, бессмысленны (можно разве что в character_set_server передавать "utf8", если Вы не уверены в том, что сервер MySQL изначально настроен под эту кодировку).

Этих двух запросов должно целиком и полностью хватить для хранения русского текста в базе (с учётом того, что Вы никак не правили остальные настройки кодировки и они выставлены по умолчанию или же настроены правильно):
mysql_query(var_connection, "SET character_set_client = 'cp1251'", false);// Определяем кодировку для запросов от сервера SA-MP к базе
mysql_query(var_connection, "SET character_set_results = 'cp1251'", false);// Определяем кодировку от базы данных к нашему серверу SA-MP
Как минимум, вся та каша из запросов, что даёт $continue$, точно не нужна.

mysql_query(var_connection, "SET SESSION character_set_server='utf8'", false);// Устанавливаем кодировку, в которой данные будут хранится на сервере MySQL (кодировка самого сервера, иными словами)


P.S. Всё это подкреплено лишь моим маленьким "расследованием" (копанием документации) и простыми тестами на локальном сервере с дефолтными настройками MySQL, так что было бы неплохо проверить все мои доводы в более разных условиях, дабы уже окончательно отшлифовать код, если вдруг я чего-то не учёл.
Засим я откланиваюсь :thank_you: Надеюсь, что у меня получилось понятно объяснить Вам назначение перечисленных опций. Спасибо за внимание

miron.prod
18.01.2021, 03:02
Не могу разобраться с кодировкой.
Если использовать такой вариант:



mysql_tquery(dbHandle, "SET character_set_client = 'cp1251'");
mysql_tquery(dbHandle, "SET character_set_results = 'cp1251'");


То в БД русские символы записываются без проблем, но при запросах к БД - русские символы в виде иероглифов.

Если использовать такой вариант:



mysql_query(dbHandle, "SET character_set_client = 'cp1251'", false);
mysql_query(dbHandle, "SET character_set_results = 'cp1251'", false);


То если записываем в БД русские символы - они просто отсутствуют вообще, но если запрос идёт на получение данных с БД - то всё в порядке.
Требуется помощь, пожалуйста.
Версия: R41-4

DeimoS
18.01.2021, 16:42
Не могу разобраться с кодировкой.
Если использовать такой вариант:



mysql_tquery(dbHandle, "SET character_set_client = 'cp1251'");
mysql_tquery(dbHandle, "SET character_set_results = 'cp1251'");


То в БД русские символы записываются без проблем, но при запросах к БД - русские символы в виде иероглифов.

Если использовать такой вариант:



mysql_query(dbHandle, "SET character_set_client = 'cp1251'", false);
mysql_query(dbHandle, "SET character_set_results = 'cp1251'", false);


То если записываем в БД русские символы - они просто отсутствуют вообще, но если запрос идёт на получение данных с БД - то всё в порядке.
Требуется помощь, пожалуйста.
Версия: R41-4

Для начала убедись, что у столбцов, куда ты записываешь данные, стоит кодировка utf8_general_ci

miron.prod
18.01.2021, 16:57
Для начала убедись, что у столбцов, куда ты записываешь данные, стоит кодировка utf8_general_ci

Кодировка и у столбцов и у бд utf8_general_ci.
При этом я заметил, что если я устанавливаю настройки, используя mysql_query и затем отправляю запрос, используя эту же функцию - то всё работает, русские символы записываются в бд. Но если отправить запрос используя mysql_tquery (если настройки установлены с использованием mysql_query) - то русские символы уже не пишутся. Это только у меня такой бред или зависимость есть какая то?

DeimoS
20.01.2021, 03:18
Кодировка и у столбцов и у бд utf8_general_ci.
При этом я заметил, что если я устанавливаю настройки, используя mysql_query и затем отправляю запрос, используя эту же функцию - то всё работает, русские символы записываются в бд. Но если отправить запрос используя mysql_tquery (если настройки установлены с использованием mysql_query) - то русские символы уже не пишутся. Это только у меня такой бред или зависимость есть какая то?

Удали файл с логами MySQL, пропиши в OnGameModeInit
mysql_log(ALL);
После запусти сервер и скинь содержимое логов сюда.

$continue$
03.06.2021, 15:56
Меня уже долгое время смущал вариант "настройки" кодировки от $continue$, ибо хоть я особо и не интересовался никогда ковырянием кодировки в MySQL (просто нужды не было), но знал, что вот этот запрос:
SET CHARACTER SET 'utf8'
является групповым. То бишь, отправляя этот единственный запрос, Вы, сразу настраиваете три параметра (*документация (https://dev.mysql.com/doc/refman/5.7/en/set-character-set.html)*) и он равносилен таким трём запросам:
SET character_set_client = utf8;
SET character_set_results = utf8;
SET collation_connection = @@collation_database;
И если взглянуть на запросы, которые $continue$ предлагает отправлять, можно заметить там идентичные запросы.

Но если про "SET CHARACTER SET" я узнал совершенно "случайно", то с запросом "SET NAMES" мне так не повезло и до текущего момента я не знал какие запросы он в себе скрывает. В итоге, документация (https://dev.mysql.com/doc/refman/5.7/en/set-names.html) говорит про три таких запроса:
SET character_set_client = utf8;
SET character_set_connection = utf8;
SET character_set_results = utf8;
И вновь мы видим запросы на изменение тех же опций, которые мало того, что содержатся в "SET CHARACTER SET", так ещё и впоследствии изменяются отдельными запросами с "utf8" на "cp1251".

Иными словами, таким вот "решением проблемы с кодировкой", которое дано в теме, Вы каждый раз будете "дёргать" одни и те же опции, изменяя их значение с одного на другое.



На этой ноте можно было бы закончить, но мне стало интересно окончательно закрыть тему кодировки для SA-MP. И я был бы не я, если бы не поделился найденной информацией с Вами :) Заодно, если я вдруг ошибусь, кто-то сможет меня поправить.

Маленькая оговорка касаемо определений:
Сервер - это наш сервер MySQL с базами дарных, блекджеком и всем остальным.
Клиент - это, в нашем случае, сервер SA-MP
Так же стоит понимать, что все опции настраивают именно сервер MySQL. Даже опция, связанная с кодировкой запросов от клиента, влияет именно на сервер, так как именно он будет заниматься конвертированием данных. То бишь, уяснили: все операции с данными происходят не на стороне сервера SA-MP или плагина, а именно на стороне сервера MySQL. И всеми опциями мы лишь сообщаем серверу MySQL нужную информацию для того, чтоб он совершил конвертирование.



Давайте разберёмся с основными опциями, которые нам могут пригодится. В случае с SA-MP нам потребуется всего несколько, так как остальные MySQL либо самостоятельно подстроит под эти запросы, либо они уже настроены как надо по умолчанию.


character_set_client - В этой опции указaывается кодировка, в которой будут поступать данные от клиента к серверу.
character_set_results - В этой опции указывается кодировка, в которую сервер конвертирует данные перед отправкой их клиенту.
character_set_connection - В этой опции указывается кодировка, в которую сервер перекодирует данные, полученные от клиента, перед тем, как начнёт выполнять запрос (клиент->character_set_connection->сервер)


Собственно, всё. Опция collation_connection, которую предлагает настроить $continue$, для каждой кодировки имеет установку по умолчанию, которая, в случае с utf8, будет равна как раз "utf8_general_ci", поэтому определять её самостоятельно нет смысла.
Если кому интересно, посмотреть "настройки по умолчанию" для той или иной кодировки можно при помощи запроса

SHOW COLLATION WHERE charset = 'имя_кодировки';
Результатом запроса будет список всех доступных вариантов представления для указанной кодировке и напротив того представления, которая является представлением по умолчанию, в столбце "Default" будет стоять "Yes".

Вот пример результата для utf8

SHOW COLLATION WHERE charset = 'utf8'


https://i.imgur.com/Im7yKLd.png


Теперь осталось действительно решить все проблемы с кодировкой, дабы всё работало как надо.
В чём заключается проблема? В том, что сервер не знает в какой кодировке работает клиент, из-за чего не может правильно конвертировать данные, пришедшие от клиента и подготовить данные к отправке для клиента. И если Вы взгляните на те 3 опции, что я перечислил выше, то найдёте решение всем проблемам.
Я не зря расписал то, в чём заключается проблема, ибо если Вы сейчас перечитаете составленное мной определение, то увидите, что в обоих случаях фигурирует именно клиент. А с какой кодировкой работает наш клиент? Правильно, cp1251. Поэтому все те свистопляски с 'utf8', которые устроил $continue$ в своём варианте, бессмысленны (можно разве что в character_set_server передавать "utf8", если Вы не уверены в том, что сервер MySQL изначально настроен под эту кодировку).

Этих двух запросов должно целиком и полностью хватить для хранения русского текста в базе (с учётом того, что Вы никак не правили остальные настройки кодировки и они выставлены по умолчанию или же настроены правильно):
mysql_query(var_connection, "SET character_set_client = 'cp1251'", false);// Определяем кодировку для запросов от сервера SA-MP к базе
mysql_query(var_connection, "SET character_set_results = 'cp1251'", false);// Определяем кодировку от базы данных к нашему серверу SA-MP
Как минимум, вся та каша из запросов, что даёт $continue$, точно не нужна.

mysql_query(var_connection, "SET SESSION character_set_server='utf8'", false);// Устанавливаем кодировку, в которой данные будут хранится на сервере MySQL (кодировка самого сервера, иными словами)


P.S. Всё это подкреплено лишь моим маленьким "расследованием" (копанием документации) и простыми тестами на локальном сервере с дефолтными настройками MySQL, так что было бы неплохо проверить все мои доводы в более разных условиях, дабы уже окончательно отшлифовать код, если вдруг я чего-то не учёл.
Засим я откланиваюсь :thank_you: Надеюсь, что у меня получилось понятно объяснить Вам назначение перечисленных опций. Спасибо за внимание

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

DeimoS
03.06.2021, 16:20
Ничего не трогая, не настраивая сервер у меня все равно не работали русские символы. В том методе, что давал я - все работало. Не знаю с чем это связано, наверное где-то подкрутить настройки mysql сервера нужно.

Ты можешь сам нагуглить описание всех запросов и посмотреть как они воспринимаются БД :) От того, что ты по несколько раз одни и те же опции перезапишешь, БД лучше работать точно не станет.

У тебя проблема могла быть в том, что ты сначала записал текст в кривой кодировке, после уже этими запросами настроил кодировку правильно, но данные остались в кривой кодировке и БД, пытаясь их конвертировать из utf8 в cp1251, естественно выдавала бы кашу.

$continue$
03.06.2021, 16:46
У тебя проблема могла быть в том, что ты сначала записал текст в кривой кодировке
Точно нет. Данные записываются динамично. (оффлайн сообщения). Т.е создаются прямо сейчас.

UPD: Видимо последний раз, когда проверял твое решение, не использовал доп.запрос. Сейчас проверил, все работает :)