Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Бинарный протокол для аргументов и строки / 12 сообщений из 12, страница 1 из 1
15.03.2016, 20:23
    #39192720
Weed
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Бинарный протокол для аргументов и строки
В prepared выражение:

SELECT $1::text

отправляю в бинарном формате(!) аргумент типа Int8 (число 123) - в ответ приходит не обычная ошибка типа "неверный формат двоичных данных в параметре Вind 1", а такая:

ОШИБКА: неверная последовательность байт для кодировки \"UTF8\": 0x00\n

Примерно понятно откуда Постгрес берёт этот нулевой байт (в сетевом порядке байтов число 123 начинается с него), но непонятно почему он не проверяет сначала тип аргумента. Эдак ведь можно "удачно" заслать число, которое будет воспринято как корректная строка со всеми вытекающими.

Это баг или фича? Для других типов такой проблемы не замечено.
...
Рейтинг: 0 / 0
15.03.2016, 20:27
    #39192724
Vladimir Sitnikov
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Бинарный протокол для аргументов и строки
Weed, пример передаваемых данных в студию (bind command и особенно "The result-column format codes. Each must presently be zero (text) or one (binary)." её часть).
Скорее всего, вы передаёте-таки в текстовом режиме.
...
Рейтинг: 0 / 0
15.03.2016, 20:32
    #39192727
Weed
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Бинарный протокол для аргументов и строки
Vladimir SitnikovWeed, пример передаваемых данных в студию (bind command


Что такое bind command?

и особенно "The result-column format codes. Each must presently be zero (text) or one (binary)." её часть).
Скорее всего, вы передаёте-таки в текстовом режиме.

Если бы это было так то замена ::text в приведённом выше примере на какой-нибудь ::int4 давала бы аналогичный результат, однако сервер начинает отвечать уже про несоответствие типов.
...
Рейтинг: 0 / 0
15.03.2016, 20:36
    #39192731
Vladimir Sitnikov
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Бинарный протокол для аргументов и строки
Weed,

WeedЧто такое bind command?
http://www.postgresql.org/docs/9.5/static/protocol-message-formats.html -> "Bind command"

Weedотправляю в бинарном формате(!)
Откуда уверенность, что формат именно бинарный?
Где код, которым производится отправка?
...
Рейтинг: 0 / 0
15.03.2016, 20:44
    #39192739
Weed
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Бинарный протокол для аргументов и строки
Vladimir SitnikovWeed,

WeedЧто такое bind command?
http://www.postgresql.org/docs/9.5/static/protocol-message-formats.html -> "Bind command"


Это вот не оно? Делается через вызов libpq trace

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
To backend> Msg B
To backend> ""
To backend> "echo"
To backend (2#)> 1
To backend (2#)> 1
To backend (2#)> 1
To backend (4#)> 8
To backend> ^@^@^@^@^@^@^@{
To backend (2#)> 1
To backend (2#)> 1
To backend> Msg complete, length 33
To backend> Msg D
To backend> P
To backend> ""
To backend> Msg complete, length 7
To backend> Msg E
To backend> ""
To backend (4#)> 0
To backend> Msg complete, length 10
To backend> Msg S
To backend> Msg complete, length 5
From backend> E
From backend (#4)> 169
From backend> S
From backend> "ОШИБКА"
From backend> C
From backend> "22021"
From backend> M
From backend> "неверная последовательность байт для кодировки "UTF8": 0x00"
From backend> F
From backend> "wchar.c"
From backend> L
From backend> "2017"
From backend> R
From backend> "report_invalid_encoding"
From backend> ^@
From backend> Z
From backend (#4)> 5
From backend> Z
From backend (#4)> 5
From backend> I

Weedотправляю в бинарном формате(!)
Откуда уверенность, что формат именно бинарный?
Где код, которым производится отправка?[/quot]

https://github.com/denizzzka/dpq2
...
Рейтинг: 0 / 0
15.03.2016, 20:54
    #39192746
Weed
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Бинарный протокол для аргументов и строки
Код: plaintext
To backend> ^@^@^@^@^@^@^@{

Вот тут как раз крыжики это, видимо, нули, а скобка в конце это 0x7b == 123
...
Рейтинг: 0 / 0
15.03.2016, 21:44
    #39192765
Vladimir Sitnikov
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Бинарный протокол для аргументов и строки
WeedЭто вот не оно? Делается через вызов libpq trace
Да, похоже на то.

Возможно, стоит wireshark'ом посмотреть какие конкретно байты ходят.
Или в самом libpq как-то больше логов включать.

С D-драйвером можно только пожелать "счастливой отладки". Непростое это занятие делать клиенты к базам.
...
Рейтинг: 0 / 0
15.03.2016, 21:46
    #39192767
Vladimir Sitnikov
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Бинарный протокол для аргументов и строки
Одно могу сказать: запрос SELECT $1::text с int8 параметром в binary режиме точно работает.
Проверял на pgjdbc.
...
Рейтинг: 0 / 0
16.03.2016, 03:28
    #39192850
Weed
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Бинарный протокол для аргументов и строки
Wireshark показывает то же самое:
(Возможно, хитрость в том, что я для prepare не передаю типы параметров и их количество. Но документация это разрешает, да и для других типов правильная ошибка выводится.)



Vladimir SitnikovОдно могу сказать: запрос SELECT $1::text с int8 параметром в binary режиме точно работает.
Проверял на pgjdbc.

Давно? Могли же и сломать... Моя версия постгреса из Debian 9.5.1-1 (64 битная)
А что подразумевается под "работает"? (Работать не должно ведь - ошибка типов должна быть показана)
...
Рейтинг: 0 / 0
16.03.2016, 09:04
    #39192908
Vladimir Sitnikov
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Бинарный протокол для аргументов и строки
Weed Возможно, хитрость в том, что я для prepare не передаю типы параметров и их количество
Так делать точно не стоит.
Текущая версия PostgreSQL не умеет приводить типы параметров.

Ваша проблема в том, что при parse не указан тип $1 и PG решает, что это должен быть varchar.
Дальше выполняете bind/exec, передавая int8, и, разумеется, оно падает, т.к. PG ожидает varchar.

Выход только один -- при parse передавать типы параметров.

Ещё один случай когда нужны типы при parse -- это когда есть функции/процедуры с одинаковым названием, но разными типами.
Для того, чтобы база поняла какую функцию вызывать, нужен тип на этапе parse.
...
Рейтинг: 0 / 0
16.03.2016, 11:00
    #39193036
Weed
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Бинарный протокол для аргументов и строки
Vladimir SitnikovWeed Возможно, хитрость в том, что я для prepare не передаю типы параметров и их количество
Так делать точно не стоит.
Текущая версия PostgreSQL не умеет приводить типы параметров.

Ваша проблема в том, что при parse не указан тип $1 и PG решает, что это должен быть varchar.
Дальше выполняете bind/exec, передавая int8, и, разумеется, оно падает, т.к. PG ожидает varchar.
Я именно этого и добиваюсь. Проблема в том, что падает он не с той ошибкой, что должна быть.

Выход только один -- при parse передавать типы параметров.
nParams is the number of parameters for which types are pre-specified in the array paramTypes[]. (The array pointer can be NULL when nParams is zero.) paramTypes[] specifies, by OID, the data types to be assigned to the parameter symbols. If paramTypes is NULL, or any particular element in the array is zero, the server assigns a data type to the parameter symbol in the same way it would do for an untyped literal string. Also, the query can use parameter symbols with numbers higher than nParams; data types will be inferred for these symbols as well. (See PQdescribePrepared for a means to find out what data types were inferred.)

То есть, оно должно само определять их типы в выражении (и оно таки их определяет!)

Кажется, я нашёл в чём проблема тут. Если посмотреть на переданные на сервер данные:



то видно, что тип данных Int8 (его десятичный номер 20) там не фигурирует. То есть, функция

Код: plaintext
1.
2.
3.
4.
5.
6.
int PQsendQueryPrepared(PGconn *conn,
                        const char *stmtName,
                        int nParams,
                        const char * const *paramValues,
                        const int *paramLengths,
                        const int *paramFormats,
                        int resultFormat);

не отправляет типы передаваемых данных, хотя и принимает их. Для аргумента она отправляет только длину и сами данные.

И поэтому с другими типами всё хорошо у меня - они отличаются по размерам и постгрес это сразу может увидеть. А типы переменной длины типа текста пытаются принимать значения любой длины, в том числе и 8-байтные. Отсюда и такая ошибка.

Зачем тогда PQsendQueryPrepared принимает paramFormats? Очень загадочная багофича!
...
Рейтинг: 0 / 0
16.03.2016, 11:05
    #39193045
Weed
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Бинарный протокол для аргументов и строки
WeedЗачем тогда PQsendQueryPrepared принимает paramFormats?

Отвечаю сам себе: это формат данных (текстовый или бинарный). Форматы же аргументов Oid вообще не передаются при запросе на сервер.

Хех, вот так открытие! Очень чуднО.

(Вопрос закрыт.)
...
Рейтинг: 0 / 0
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Бинарный протокол для аргументов и строки / 12 сообщений из 12, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]