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, поэтому на самом деле невозможно обнаружить ошибки, кроме как во время выполнения.

Вы можете сделать несколько вещей:

  1. оберните вашу функцию вызова SQL запросы в BEGIN / COMMIT заявления для лучшего контроля над ошибками;
  2. добавлять EXCEPTION блоки в ваш код, чтобы ловить и отслеживать ошибки. Обратите внимание, что это повлияет на производительность функции;
  3. использование plpgsql_check расширение, разработанное Павлом Стехуле, который является одним из основных участников разработки PL/pgSQL. Я полагаю, что в конечном итоге это расширение войдет в ядро ​​PostgreSQL, но это займет некоторое время (сейчас мы находимся в состоянии 9.4beta3);
  4. Вы также можете посмотреть на этот связанный вопрос: проверка синтаксиса 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.
Другие вопросы по тегам