Ошибка PostgreSQL 39000: external_routine_invocation_exception — исправление
- Прерывание транзакции с ошибкой
ERROR: external routine invocation exception (SQLSTATE 39000). - Исключение возникает непосредственно в момент передачи аргументов во внешнюю подпрограмму или при возврате результата.
- Сбои при передаче NULL значений в C-функции без проверки макроса
PG_ARGISNULL().
1. Проверка определения внешней функции в PostgreSQL
SELECT p.proname, p.prosrc, p.probin, p.proisstrict
FROM pg_proc p
WHERE p.proname = 'my_custom_c_func';2. Корректная обработка NULL (Атрибут STRICT)
Если внешняя функция не умеет самостоятельно обрабатывать значения NULL, объявите ее с директивой STRICT (в этом случае ядро автоматически вернет NULL без вызова функции):
CREATE OR REPLACE FUNCTION my_custom_c_func(text, integer)
RETURNS text
AS '$libdir/custom_mod', 'my_custom_c_func'
LANGUAGE C STRICT;3. Безопасная работа с аргументами на уровне Си-кода
При написании функций версии V1 всегда используйте стандартные макросы ядра:
PG_FUNCTION_INFO_V1(my_custom_c_func);
Datum my_custom_c_func(PG_FUNCTION_ARGS)
{
if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
PG_RETURN_NULL();
text *arg0 = PG_GETARG_TEXT_PP(0);
int32 arg1 = PG_GETARG_INT32(1);
// Логика функции
PG_RETURN_TEXT_P(arg0);
}4. Проверка совпадения типов SQL и Си
Убедитесь, что int4 соответствует int32, int8 — int64, а строковые типы varchar/text обрабатываются как структуры varlena.
Частые вопросы (FAQ)
Чем ошибка 39000 отличается от 38000?
39000 сигнализирует об ошибке протокола вызова и маршалинга параметров (неверный формат аргументов, стек, переполнение буфера входных данных), тогда как 38000 указывает на общее исключение внутри самой внешней подпрограммы.
Что означает директива RETURNS NULL ON NULL INPUT?
Это синоним директивы STRICT. Она предотвращает вызов внешней функции, если хотя бы один из переданных параметров равен NULL.
Может ли некорректная кодировка строки вызвать 39000?
Да, если внешняя процедура ожидает валидный UTF-8, а клиент передает поврежденные байты в кодировке WIN1251 без предварительной перекодировки.
Как перезагрузить обновленную библиотеку .so в PostgreSQL без рестарта сервера?
Вызовите команду DISCARD ALL или завершите текущую сессию подключения.