LINUX.ORG.RU
ФорумAdmin

Как посмотреть с какой кодировкой подключился клиент MySQL?

 ,


0

1

К серверу MySQL подключен клиент, висит постоянно, можно спокойно узнать о нём всё, что нужно.

Но не знаю, собственно, как это сделать.

Клиентом является бинарник, который что-то внутри у себя не так переварил и стал вместо UTF8 отправлять строки в Latin-1.

Нужно убедиться в том, что действительно кодировка на стороне клиента некорректна, пользуясь, скажем, учётной записью root.

Как это сделать?

Спасибо!

★★★★★

и стал вместо UTF8 отправлять строки в Latin-1.

Большинство mysql-клиентов, ЕМНИП, по умолчанию настроены на latin1. Просто измени значение --default-character-set, или после каждого соединения устанавливай принудительно через SET.

Нужно убедиться в том, что действительно кодировка на стороне клиента некорректна,

Дак ты уверен или нет? Ты же только что писал:

и стал вместо UTF8 отправлять строки в Latin-1.

Как это сделать?

Даже не представляю что именно тебе нужно? Сделать детект кодировки данных от клиента? По мне дак никак, ну если только не брать большой кусок данных и не делать частотный анализ :) Шучу, конечно.
А если серьезно, то ответил в первом абзаце.

znenyegvkby
()
Ответ на: комментарий от Stanson

Так ты увидишь переменные _своего_ соединения. А ТСу надо посмотреть переменные чужого.

+100500 Именно так!

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от znenyegvkby

Ну как бы есть тот же MySQL Workbench, в нём много всякого полезного можно узнать о текущих соединениях с сервером: какие запросы выполняются, топ самых длительных запросов от того или иного клиента и т.д.

Внутри себя MySQL-сервер точно знает, в какой кодировке ему отдаёт данные клиент - как минимум он должен «прозрачно» преобразовать из кодировки клиента в кодировку сервера, если первая и вторая не совпадают.

Вот как «вытащить» из сервера эту полезную информацию?

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от DRVTiny

Т.е. ты не клиент и не сервер. Тебе нужна информация о _чужом_ клиент-серверном соединении, причем _чужие_ в твоем случае и клиент, и сервер, я правильно понял?

znenyegvkby
()
Ответ на: комментарий от znenyegvkby

Сервер - мой! Кто сказал, что сервер-то чужой?

Он мало того, что мой, так ещё и вполне себе MySQL Enterprise.

DRVTiny ★★★★★
() автор топика
Последнее исправление: DRVTiny (всего исправлений: 1)
Ответ на: комментарий от znenyegvkby

Кстати, не знаете, как применить опцию в my.cnf: skip-character-set-client-handshake - без перезапуска mysqld? У меня mysqld при останове только дропать соединения будет минут 15-ть...

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от DRVTiny

Ведь это опция, вы либо с предустановленной стартуете, либо приложение тянет ее из конфигов.

znenyegvkby
()
Последнее исправление: znenyegvkby (всего исправлений: 1)
Ответ на: комментарий от DRVTiny

Сервер - мой! Кто сказал, что сервер-то чужой?

Ну дак если сервер ваш, в чем проблема стартануть с опцией --default-character-set или установить через SET после соединения клиента, не понимаю?

znenyegvkby
()
Ответ на: комментарий от znenyegvkby

Как это всё поможет мне выяснить, корректно ли работает клиент и не пытается ли использовать latin1?

Положим, я понимаю, как создать трешовую ситуацию с клиентом, отправляющим данные в однобайтовой кодировке и сервером, игнорирующим этот факт и упорно пихающим однобайтовые строки в utf-ные поля. Собственно, потому и спросил об установке skip-character-set-client-handshake в онлайн: так можно считать всех клиентов utf-ными, даже если это совсем не так.

Но я бы всё же хотел отдебажить ситуацию и понять, что делает клиент какую кодировку выставляет. Может, вовсе и не в latin1 дело, вполне вероятно, кстати. Этот же клиент раньше всё делал правильно, ему башню снесло вообще непонятно в какой момент...

DRVTiny ★★★★★
() автор топика
Последнее исправление: DRVTiny (всего исправлений: 1)
Ответ на: комментарий от DRVTiny

Как это всё поможет мне выяснить, корректно ли работает клиент и не пытается ли использовать latin1?

Еще раз – если ты установишь опцию – ничего выяснять не нужно будет – клиент будет работать _корректно_. Тебе шашечки или ехать?

Но я бы всё же хотел отдебажить ситуацию и понять, что делает клиент какую кодировку выставляет.

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

znenyegvkby
()
Последнее исправление: znenyegvkby (всего исправлений: 1)
Ответ на: комментарий от znenyegvkby

Ну блин, откуда этой информации взяться на сервере-то?

А слово «handshake» в названии приведённой выше опции ни о чём не говорит?

Да, MySQL-сервер знает, в какой кодировке ему шлёт данные клиент и в какой кодировке ему нужно отправлять данные клиенту.

Если же MySQL-сервер игнорирует попытки клиента установить кодировку, а она несовместима с UTF-8 (например, тот же cp1251), то клиент будет слать бинарные данные в однобайтовой кодировке, а сервер будет считать, что принял UTF-8 - со всеми вытекающими отсюда последствиями в виде кракозяблов и прочих прелестей.

Ну и ещё хреновее, если MySQL-сервер преобразует данные, отправляемые SELECT'ом, в кодировку клиента (кириллица в UTF -> latin1 = "?" вместо русских буковок), а клиент потом эти данные возвращает серверу - например, при UPDATE'е. Но только принудительной установкой «всё в UTF8» такие траблы не решаются по-моему.

DRVTiny ★★★★★
() автор топика

На тебе аццкий hack:

в конфиге mysql можно прописать команды которые будут выполняться при коннекте.

[mysqld]
init_connect='SET collation_connection = utf8_general_ci'
init_connect='SET NAMES utf8'

Проблема в том, что клиент может игнорировать это всё.

Поэтому надо выдрать variables. Например прописав в init_connect='show variables ....'

Но show variables не подразумевает способа сохранить как-то результат. Однако, позволяет использовать WHERE, а в WHERE можно expr, в том числе и присваивание.

Поэтому нужен финт ушами:

SET @uservars := ";
SHOW VARIABLES WHERE ( @uservars := CONCAT( @uservars, Variable_name, '=', Value , '\n' ) ) IS NULL;
SHOW VARIABLES WHERE ( @uservars := CONCAT( @uservars, Variable_name, '=', Value , '\n' ) ) IS NULL;
SELECT @uservars INTO OUTFILE '/tmp/uservars';

Почему-то нужно 2 раза show variables, чтобы все переменные попали в @uservars. Первый раз только одна последняя переменная попадает. И \n нифига не работает, но тем не менее, в файле /tmp/uservars окажутся переменные и значения юзверя из-под которого это запустили.

А запустить из-под юзера можно посредством init_connect

Ну и вот эту всю бодягу оформить в виде процедуры, или прямо запускать из init_connect. Логично ещё имя файла согласно юзерскому имени давать. Через CURRENT_USER() и prepared statement, т.е. как обычно через жопу.

Stanson ★★★★★
()
Последнее исправление: Stanson (всего исправлений: 2)
Ответ на: комментарий от Stanson

Проблема в том, что клиент может игнорировать это всё.

Я бы сказал даже по-другому: клиент может не то, чтобы игнорировать, клиент (код клиента) может вообще не учитывать тот факт, что сервер его к чему-то форсит. В реальности я не видел ни одного клиентского куска кода под мускуль, который бы проверял, что устанавливаемая им кодировка действительно «установилась», а не была зафорсена сервером.

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от DRVTiny

Если же MySQL-сервер игнорирует попытки клиента установить кодировку, а она несовместима с UTF-8 (например, тот же cp1251), то клиент будет слать бинарные данные в однобайтовой кодировке, а сервер будет считать, что принял UTF-8

Да, MySQL-сервер знает, в какой кодировке ему шлёт данные клиент

Ты вроде запутался, не?

Но только принудительной установкой «всё в UTF8» такие траблы не решаются по-моему.

Именно так и решается.

znenyegvkby
()
Ответ на: комментарий от DRVTiny

В реальности я не видел ни одного клиентского куска кода под мускуль, который бы проверял, что устанавливаемая им кодировка действительно «установилась», а не была зафорсена сервером.

Как ты себе это представляешь? Он _не может_, и _не должен_ этого проверять. Завтра отвечу более детально, к сожалению сейчас нужно бежать.

znenyegvkby
()
Ответ на: комментарий от Stanson

Поэтому нужен финт ушами:

Эх... ещё бы IP клиента в имя файла добавлять... Нельзя ли так, случаем?

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от DRVTiny

CURRENT_USER() тебе вернёт 'user@hostname'. Так что и так всё есть.

Stanson ★★★★★
()
Ответ на: комментарий от Stanson

Просто клиентов-то много, и они по злому недоразумению коннектятся под одним пользователем. Хотя можно в общем и самостоятельного юзера завести с такими же правами.

Как отфильтровать вывод «Финта» по пользователю или IP-шнику чтобы файл с переменными писать только для нужного клиента? :)

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от DRVTiny

CURRENT_USER() всё выдаст. Можно даже извратиться чтобы для каждого user@hostname свой файл был. Но есть ещё другая засада - mysql не умеет удалять или перезаписывать файлы. Т.е. файл должен отсутствовать перед SELECT ... INTO OUTFILE.

Stanson ★★★★★
()
Ответ на: комментарий от znenyegvkby

Ты вроде запутался, не?

«Знать» и «принимать во внимание» - 2 сильно разные вещи, не?

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от DRVTiny

Да щаз. Это ж SQL.

SET @var = CONCAT('SELECT @uservars INTO OUTFILE "/tmp/uservars-', CURRENT_USER(), '"' );
PREPARE stmt FROM @var;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

ЗЫ: СРАНЫЕ, СЦУКО, КАВЫЧКО-НА-ЭТИ-ВАШИ-ЭМОДЗИ-ЗАМЕНЯТЕЛИ!!! Хотя бы в [ pre ] можно же было не заниматься этим дебилизмом? Приходится [ code ] дурацкий пользовать

Stanson ★★★★★
()
Последнее исправление: Stanson (всего исправлений: 4)
Ответ на: комментарий от znenyegvkby

Отвечаю как и обещал.

Но только принудительной установкой «всё в UTF8» такие траблы не решаются по-моему.

Если ты хочешь, чтобы _клиенты использовали установленную тобой_ кодировку через --default-charset-set, стартуй сразу сервер с опцией --skip-character-set-client-handshake. После этого серверу станет откровенно пофиг на информацию о кодировках, посылаемую клиентом. Он эти данные будет просто _игнорировать_. Т.е. соединение _гарантированно_ будет установлено в той кодировке, которая тебе необходима.

Далее, что касается описанной тобой ситуации:

Если же MySQL-сервер игнорирует попытки клиента установить кодировку, а она несовместима с UTF-8 (например, тот же cp1251), то клиент будет слать бинарные данные в однобайтовой кодировке, а сервер будет считать, что принял UTF-8

Для этого и существует SET NAMES, который укажет серверу, в какой кодировке данные будет слать _клиент_. Естественно, что это будет работать только на current-connection. И это означает, что данные от клиента могут идти в одной кодировке, сервер отдавать их клиенту может в другой, а хранить в базе вообще в третьей. Чтобы избежать этого зоопарка – переходи уже на одну :)

znenyegvkby
()
Последнее исправление: znenyegvkby (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.