Вы сами набрали ключевое предложение в руководстве сами:
Все тело функции SQL анализируется перед выполнением любой из них.
Также читайте о Этап парсера в руководстве .
Он состоит из двух основных частей: парсер и процесс преобразования . Цитирование руководства:
процесс преобразования возвращает дерево, переданное анализатором, как
вход и делает семантическую интерпретацию, необходимую для понимания,
на таблицы, функции и операторы ссылается запрос.
Если функция SQL содержит следующие команды:
CREATE TABLE foo (...);
INSERT INTO foo VALUES(...);
Оба оператора планируются практически в одно и то же время (на основе одного и того же снимка системных каталогов). Следовательно, INSERT
не может видеть таблицу "foo", предположительно созданную с помощью предыдущей команды CREATE
. Это создает одну из следующих проблем :
Если в вашем search_patch
(пока что) нет таблицы other с именем "foo" (пока), Postgres жалуется при попытке создать функция:
ERROR: relation "foo" does not exist
Если в вашем search_patch
уже существует другая таблица с именем "foo" (и вы не используете конфликтующие имена столбцов), Postgres планирует INSERT
на основе этой ранее существующей таблицы. Обычно это приводит к ошибке во время выполнения , если какие-либо значения вызывают конфликты в (неправильной!) Таблице. Или, если повезет, он может даже записать в эту таблицу без сообщения об ошибке! Очень подлый баг.
Этого не может быть с PL / pgSQL функцией, потому что она обрабатывает команды SQL как подготовленные операторы, запланированные и выполненные последовательно . Таким образом, каждый оператор может видеть объекты, созданные в предыдущих операторах.
Следовательно, операторы, которые никогда не посещаются, никогда даже не планируются - в отличие от функций SQL. И план выполнения для операторов может быть кэширован в том же сеансе - также в отличие от функций SQL. Подробнее о кэшировании плана в функциях PL / pgSQL см. Здесь.
Каждый подход имеет преимущества для некоторых случаев использования. Дальнейшее чтение: