PostgreSQL против Oracle: проверка PL/pgSQL во время компиляции
Резюме: PostgreSQL удивителен, но мы сталкиваемся со многими проблемами на работе из-за того, что он откладывает многие проверки кода PL/pgSQL до времени выполнения. Есть ли способ сделать его более похожим на Oracle PL/SQL в этом отношении?
Например...
Попробуйте выполнить это в любой БД Oracle:
create function foo return number as
begin
select a from dual;
return a;
end;
Oracle немедленно (т.е. во время компиляции!) Ответит:
[Error] ORA-00904: invalid identifier
Теперь попробуйте семантически эквивалентную вещь в PostgreSQL:
CREATE OR REPLACE FUNCTION public.foo ()
RETURNS integer AS
$body$
BEGIN
select a;
return a;
END;
$body$
LANGUAGE plpgsql;
Вы увидите это - к сожалению! - выполнить нормально... Об ошибке не сообщается.
Но когда вы попытаетесь вызвать эту функцию (т.е. во время выполнения), вы получите:
ERROR: column "a" does not exist
LINE 1: select a
Есть ли способ заставить PostgreSQL выполнять синтаксический анализ и проверку во время определения функции, а не во время выполнения? У нас есть тонны унаследованного кода PL/SQL в работе, который мы портируем на PostgreSQL, но отсутствие проверок во время компиляции очень болезненно, что заставляет нас выполнять ручную работу - т.е. писать код для проверки всех путей кода во всех функциях / процедуры - это было иначе автоматизировано в Oracle.
2 ответа
Да, это известная проблема.
PL/pgSQL (как и любая другая функция, кроме SQL
) является "черным ящиком" для PostgreSQL, поэтому на самом деле невозможно обнаружить ошибки, кроме как во время выполнения.
Вы можете сделать несколько вещей:
- оберните вашу функцию вызова
SQL
запросы вBEGIN
/COMMIT
заявления для лучшего контроля над ошибками; - добавлять
EXCEPTION
блоки в ваш код, чтобы ловить и отслеживать ошибки. Обратите внимание, что это повлияет на производительность функции; - использование
plpgsql_check
расширение, разработанное Павлом Стехуле, который является одним из основных участников разработки PL/pgSQL. Я полагаю, что в конечном итоге это расширение войдет в ядро PostgreSQL, но это займет некоторое время (сейчас мы находимся в состоянии 9.4beta3); - Вы также можете посмотреть на этот связанный вопрос: проверка синтаксиса postgresql без выполнения запроса
И это действительно выглядит так, как будто вы очень нуждаетесь в модуле модульного тестирования.
Язык Plpgsql разработан без проверки семантики во время компиляции. Я не уверен, как эта функция была намерением или побочным эффектом старой реализации plpgsql, но со временем мы нашли некоторые преимущества (но с упомянутым вами недостатком).
плюс:
- меньше проблем с зависимостью между функциями и другими объектами базы данных. Это простое решение циклической зависимости. Развертывание функций plpgsql проще, потому что вам не нужно уважать зависимость.
- Некоторые шаблоны с временными таблицами возможны из-за ленивой зависимости. Это необходимо, потому что Postgres не поддерживает глобальные временные таблицы.
Пример:
BEGIN
CREATE TEMP TABLE xx(a int);
INSERT INTO xx VALUES(10); -- isn't possible with compile time dependency
END;
Минус:
- Глубокая проверка во время компиляции (проверка идентификаторов) невозможна, хотя иногда это возможно.
Для некоторых крупных проектов следует использовать смесь решений:
- Регресс и модульные тесты - это базовые, потому что некоторая ситуация не может быть проверена статически - например, динамический SQL.
plpgsql_check
- это внешний, но поддерживаемый проект, который используют несколько более крупных компаний и более крупных пользователей plpgsql. Это может обеспечить статическую проверку достоверности идентификаторов SQL. Вы можете применить эту проверку с помощью триггеров DDL.