Особенность использования расширения pg_variables в PostgreSQL 18

Расширение pg_variables в PostgreSQL часто позволяет избежать использования временных таблиц. Я его использовал, и поэтому, при тестировании PostgreSQL 18 так же установил и его из репозитория на github. Я не проверял на PostgreSQL 16 и 17, поэтому описываемая ниже проблема может возникать и там. В PostgreSQL 15 и более ранних версиях эта проблема не проявлялась.

По умолчанию pg_variables может сам определять тип констант, передаваемых ему. Это управляется конфигурационной переменной pg_variables.convert_unknownoid. Если она не задана, то её значение 1 (true).

На PostgreSQL 18 при тестировании это привело к очень странным последствиям. Попробуем вставить запись, содержащую два текстовых поля:

CREATE EXTENSION IF NOT EXISTS pg_variables;
SELECT pgv_insert('var1', 'rec1', ('value1','value2'));

pgv_insert|
----------+
          |

Пока всё нормально. Теперь попробует её прочитать:

SELECT pgv_select('var1', 'rec1');

SQL Error [XX000]: ERROR: invalid memory alloc request size 18446744073709551613

Уже само это сообщение заставляет насторожиться. Немного изменим нашу запись:

SELECT pgv_insert('var1', 'rec2', ('value1'::varchar,'value2'));

pgv_insert|
----------+
          |

SELECT pgv_select('var1', 'rec2');

pgv_select |
-----------+
(value1,"")|

Значение второго поля записи вообще пропало.

Теперь попробуем явно указать типы констант и запросить результат:

SELECT pgv_insert('var1', 'rec3', ('value1'::text,'value2'::text));

pgv_insert|
----------+
          |

SELECT pgv_select('var1', 'rec3');

pgv_select     |
---------------+
(value1,value2)|

Никаких проблем.

Могу предположить, что при указании строковых констант расширение pg_variables некорректно определяет их тип, если он явно не указан. Запретить распознавание типа, как я уже указывал выше, можно конфигурационной переменной:

ALTER SYSTEM SET pg_variables.convert_unknownoid = 0;
SELECT pg_reload_conf();

Теперь установить значение записи вообще без указания типа строковых констант pgv_insert не даст:

SELECT pgv_insert('var1', 'rec1', ('value1','value2'));

SQL Error [42883]: ERROR: could not identify a hash function for type unknown

Что интересно, но запись, у которой указан тип только первой константы вставлять позволяется:

SELECT pgv_insert('var1', 'rec5', ('value1'::varchar,'value2'));

pgv_insert|
----------+
          |

SELECT pgv_select('var1', 'rec5');

pgv_select     |
---------------+
(value1,value2)|

При этом запись возвращается в корректном виде. Однако, я бы всё равно не рекомендовал не указывать тип строковых констант внутри записей при вызове pgv_insert.

А вот задание конфигурационной переменной pg_variables.convert_unknownoid = 0 настоятельно рекомендую.

@ptr128
22.12.2025 01:08 UTC
Первоисточник

Комментарии

@anyafit
22.12.2025 03:56 UTC
0

Вы собирали расширение из https://github.com/postgrespro/pg_variables?

Там нет изменений 2 года, вполне логично, что не работает на PostgreSQL 18

@ptr128
22.12.2025 06:34 UTC
0

Во-первых, другого источника для этого расширения я не знаю. Во-вторых, с чего Вы взяли, что не работает? В статье я лишь указал, что следует сделать, чтобы избежать рисков, возникающих, если типы строковых констант явно не указываются.

23.12.2025 08:06 UTC
0

Хорошо, работает некорректно.

В целом там могут и другие проблемы быть, так как в расширении никаких изменений нет, а в СУБД есть.

23.12.2025 08:34 UTC
0

работает некорректно

Только в достаточно специфичных случаях. И как это избежать я указал.

могут и другие проблемы быть

Тоже самое можно сказать не только про расширения, но и про сам PostgreSQL. В последнем обновлении от 13 ноября 2025 года в PostgreSQL 14-18 было исправлено почти по полсотни ошибки для каждой версии. А судя по принятым исправлениям ошибок в последующих commintfest, в следующем обновлении их будет столько же.

Следует понимать, что механизм вызова пользовательских функций, написанных на C, официально не менялся, примерно, с PostgreSQL 9.4. А обращений к БД pg_variables не требует.

Если Вы считаете, что произведенное мной тестирование недостаточно для Вашего планирования рисков, то проведите собственное.