4.7Kпросмотров
2 февраля 2026 г.
Score: 5.1K
Почему из PG_TRY нельзя «просто продолжить» Продолжение рассказа про исключения в PostgreSQL. Начало тут. После того как стало ясно, что мои ожидания от исключений в PostgreSQL не совпадают с реальностью, я полез разбираться глубже. Сначала, как это часто бывает, кажется, что всё объясняется одной деталью: в основе исключений лежит longjmp, а значит, это не привычный unwind стека, а резкий прыжок управления. Уже этого достаточно, чтобы насторожиться. Но довольно быстро выясняется, что longjmp — лишь вершина айсберга. Ключевая особенность PostgreSQL в том, что при ошибке с уровнем elevel >= ERROR меняется глобальное состояние процесса. Причём не в одном месте и не в виде какого-то аккуратного, локального эффекта, а сразу в нескольких важных точках. Сбрасывается текущий memory context, трогаются счётчики вроде HoldOffCount, меняются глобальные переменные. Всё это происходит ещё до того, как управление вообще попадёт в PG_CATCH. В результате, даже если вы формально «поймали» исключение, вы уже находитесь в другом логическом состоянии процесса. Это больше не тот мир, в котором код начал выполняться внутри PG_TRY. И если попытаться вести себя так, будто ничего не случилось, начинаются очень тонкие и неприятные проблемы. Отсюда вытекают правила, которые без знания потрохов выглядят совершенно неочевидно. Например, изнутри PG_TRY нельзя делать return. Не потому, что «так не принято», а потому что это ломает инварианты глобального состояния. Процесс оказывается в полусобранном виде: часть состояния уже изменена механизмом ошибки, а часть — нет. В лучшем случае это приведёт к странным багам, в худшем — к падениям в местах, которые вообще не связаны с исходной ошибкой. И вот здесь становится понятно, почему PostgreSQL принципиально не поддерживает модель «поймал ошибку, восстановился и продолжил работу как ни в чём не бывало». Чтобы это действительно заработало, обработчик ошибки должен был бы вручную восстанавливать memory contexts, возвращать счётчики и флаги в согласованное состояние и, по сути, знать внутренние инварианты исполнительного механизма. А это уже прямое протекание деталей реализации наружу и грубое нарушение инкапсуляции. Важно, что всё это — не баг и не недоработка. PostgreSQL — это СУБД с очень чётким приоритетом: при серьёзной ошибке как можно быстрее и безопаснее прекратить обработку запроса. Исключения здесь — это не инструмент управления потоком, а аварийная кнопка. Они отлично справляются со своей задачей, но эта задача совсем не та, которую мы привыкли ассоциировать со словом «исключения». И именно поэтому мой главный вывод за всё это время не в том, что «нужно внимательнее читать документацию» или «глубже разбираться во внутренних деталях». Иногда на такие грабли просто невозможно не наступить, особенно когда API выглядит знакомо и дружелюбно. Проблема в другом: нейминг PG_TRY / PG_CATCH / PG_FINALLY в 2026 году создаёт ложное ощущение знакомой абстракции и почти неизбежно вводит в заблуждение. Синтаксис выглядит правильно. Ощущение — тоже. А вот семантика у этого механизма совсем другая. А у вас было ощущение, что интерфейс будто обещает одно, а под капотом делает совсем другое?
4.7K
просмотров
3162
символов
Нет
эмодзи
Нет
медиа

Другие посты @imhired

Все посты канала →
Почему из PG_TRY нельзя «просто продолжить» Продолжение расс — @imhired | PostSniper