Почему максимальный размер запроса отличается, когда запрос заканчивается точкой с запятой? - PullRequest
0 голосов
/ 28 августа 2018

Если вы посмотрите по Интернету (например, Каков максимальный размер запроса для mysql? ), вы обнаружите утверждения, что максимальный размер запроса для MariaDB / MySQL равен значению переменной max_allowed_packet , Но когда вы действительно попробуете это, вы обнаружите, что это не совсем так.

Вот небольшой скрипт Lua, который генерирует тестовый запрос нужного размера:

prefix = "SELECT IF(0,'"
postfix = "',NULL);"
max_allowed_packet = 16777216 -- The value for my setup

function gen_query(size)
    local n = size - string.len(prefix) - string.len(postfix)
    local query = prefix .. string.rep('X', n) .. postfix
    io.open("/tmp/testquery.sql", "w"):write(query):close()
end

gen_query(max_allowed_packet)

/tmp/testquery.sql теперь содержит запрос типа SELECT IF(0,'<a lot of Xs here>',NULL);.

Если мы сейчас попробуем выполнить это, мы получим ошибку:

$ mysql -A -B < /tmp/testquery.sql
ERROR 1153 (08S01) at line 1: Got a packet bigger than 'max_allowed_packet' bytes

Если мы сделаем то же самое, но с gen_query(max_allowed_packet - 1) (генерируя запрос на один байт меньше), сервер успешно выполнит запрос:

$ mysql -uroot -pmysql --protocol=tcp -A -B < /tmp/testquery.sql 
IF(0,'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
NULL

Если мы копаемся с документацией MySQL (не может найти эквивалент для MariaDB), это начинает иметь смысл, так как пакет включает дополнительный байт (0x03), который объявляет пакет как COM_QUERY пакет: https://dev.mysql.com/doc/internals/en/com-query.html

Пока это все имеет смысл для меня, но если мы пойдем дальше и изменим нашу программу lua, чтобы она не включала точку с запятой в конце (установив postfix = "',NULL)"), это неожиданно снова результат:

$ mysql -uroot -pmysql --protocol=tcp -A -B < /tmp/testquery.sql
ERROR 1153 (08S01) at line 1: Got a packet bigger than 'max_allowed_packet' bytes

Тестовый запрос по-прежнему max_allowed_packet - длиной 1 байт:

$ wc -c /tmp/testquery.sql
16777215 /tmp/testquery.sql

max_allowed_packet - запрос длиной 2 байта без точки с запятой снова работает, как и ожидалось.

Что происходит? Вставляет ли клиент командной строки mysql / библиотека mysql автоматически ; в конце? Насколько я могу сказать, это не так, вот выдержка из вывода strace:

$ strace -v -e write=3 mysql -A -B < /tmp/testquery.sql
<<< irrelevant syscalls omitted >>>
sendto(3, "\377\377\377\0\3SELECT IF(0,'XXXXXXXXXXXXXX"..., 16384, 0, NULL, 0) = 16384
 | 00000  ff ff ff 00 03 53 45 4c  45 43 54 20 49 46 28 30  .....SELECT IF(0 |
 | 00010  2c 27 58 58 58 58 58 58  58 58 58 58 58 58 58 58  ,'XXXXXXXXXXXXXX |
<<< lots of hexdump data omitted >>>
 | ffbff0  58 58 58 58 58 58 58 58  58 58 58 58 27 2c 20 4e  XXXXXXXXXXXX', N |
 | ffc000  55 4c 4c                                          ULL              |
sendto(3, "\1\0\0\1)", 5, 0, NULL, 0)   = 5
 | 00000  01 00 00 01 29                                    ....)            |
<<< more irrelevant syscalls omitted >>>

Могу ли я отправить запрос max_allowed_packet - длиной 2 байта и всегда ожидать, что он будет работать (если, конечно, в запросе sql нет ошибок :))? И задокументировано ли это поведение где-нибудь?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...