Ошибка PostgreSQL 42P14: invalid_prepared_statement_definition — Prepared Statements
- Ошибка
ERROR: invalid prepared statement definition: ... (SQLSTATE 42P14). - Попытка подготовки запроса, содержащего несовместимые команды управления транзакциями (
PREPARE stmt AS BEGIN ...). - Сбои в работе ORM или пулеров соединений при повторной подготовке подготовленных выражений с измененными типами аргументов.
1. Анализ недопустимых выражений внутри PREPARE
Команда PREPARE может использоваться только для запросов SELECT, INSERT, UPDATE, DELETE, MERGE и VALUES. Вызовы DDL или транзакционных команд запрещены:
-- Неверно:
PREPARE p_trans AS COMMIT; -- Ошибка 42P14
-- Корректно:
PREPARE p_get_user(bigint) AS
SELECT id, login, is_active FROM users WHERE id = $1;
-- Выполнение:
EXECUTE p_get_user(1001);2. Проверка типов параметров в подготовленном выражении
PREPARE search_docs(text, timestamp with time zone) AS
SELECT * FROM documents
WHERE doc_number = $1 AND created_at >= $2;3. Освобождение подготовленных выражений при переподключении
-- Удаление конкретного стейтмента:
DEALLOCATE search_docs;
-- Очистка всех выражений текущей сессии:
DEALLOCATE ALL; Частые вопросы (FAQ)
Как работают Generic Plan и Custom Plan в Prepared Statements?
Первые 5 запусков планировщик строит индивидуальные планы (Custom Plan) под конкретные параметры. Начиная с 6-го запуска, ядро оценивает универсальный план (Generic Plan) и переключается на него, если он не уступает по стоимости.
Почему нельзя использовать PREPARE в PgBouncer с Transaction Pooling?
В режиме Transaction Pooling разные запросы одного клиента выполняются в разных сессиях бэкенда PostgreSQL, где подготовленное выражение не существует (ошибка 26000/42P14).
В чем преимущество подготовленных выражений?
Они устраняют накладные расходы на парсинг и синтаксический анализ SQL-запроса при его многократном выполнении и гарантируют 100% защиту от SQL-инъекций.
Где посмотреть список активных подготовленных выражений сессии?
Сделайте запрос к системному представлению pg_prepared_statements: SELECT * FROM pg_prepared_statements;