Обозначение атрибута для вызова функции дает ошибку

Вызов функции записи атрибутов приводит к ошибке, если текущая схема отличается от схемы функции.

Я создал функцию

CREATE FUNCTION pub.FullName(pub.reps)
  RETURNS text AS
$func$
       select ($1.fname || ' ' || $1.lname)
$func$ LANGUAGE SQL;

Я пытаюсь вызвать функцию с обозначением атрибута, как описано в docs):

select r.fullname from pub.reps r;

Но получите сообщение об ошибке:

ERROR:  column "fullname" does not exist

Запрос с функциональной нотацией работает нормально:

select pub.fullname(r.*) from pub.reps r;

База данных была перенесена из PostgreSQL 10 с резервным копированием/восстановлением.

Select version() дает: PostgreSQL 11.3, compiled by Visual C++ build 1914, 64-bit

UPD. Выяснил, что если установить схему pub по умолчанию, то select r.fullname from pub.reps r работает без ошибок.


person Leo    schedule 29.06.2019    source источник
comment
тестовая база данных на каком сервере? почему смешанное написание? вы где-нибудь использовали двойные кавычки?   -  person Erwin Brandstetter    schedule 29.06.2019
comment
Смешанный регистр только для удобства чтения. На результат это не влияет. Сервер такой же, как и для первой базы данных - мой собственный ноутбук.   -  person Leo    schedule 29.06.2019
comment
Я узнал, что это зависит от текущей схемы. Если я настрою схему паба по умолчанию, то select r.FullName from pub.reps r будет работать. В противном случае я получаю ошибку.   -  person Leo    schedule 29.06.2019
comment
@ErwinBrandstetter, спасибо за подробный ответ и за улучшение моего поста. Теперь он выглядит намного лучше. Также для ссылки db‹›fiddle. Который должен быть хорошим инструментом. Насколько я понимаю, невозможно использовать функциональность атрибута без изменения пути поиска (например, с явным использованием схемы в запросе). Так что лучше дождусь Postgres 12.   -  person Leo    schedule 30.06.2019
comment
Схема функции должна находиться в пути поиска, так как нет возможности квалифицировать атрибут по схеме (превращенный в функцию). Строго говоря, вам не обязано изменять search_path: вы всегда можете создать функцию в уже существующей схеме, pg_catalog в крайнем случае. (Хотя я бы предпочел не помещать туда пользовательские объекты.)   -  person Erwin Brandstetter    schedule 01.07.2019


Ответы (1)


Вы сами нашли корень проблемы. Чтобы быть точным: схема функции pub должна быть указана в любом месте в текущем search_path, не обязательно должна быть схемой "по умолчанию" или "текущей" (схема первый в списке). Связанный:

Итак, Postgres не нашел функцию. В этом отношении Postgres 11 ничем не отличается от Postgres 10. Тем не менее, есть некоторые примечательные, связанные события. Ты упомянул:

База данных была перенесена из PostgreSQL 10 с резервным копированием/восстановлением.

Обратите внимание на это тонкое изменение, указанное в примечаниях к выпуску. для Postgres 11:

  • Учитывайте синтаксическую форму при устранении неоднозначности ссылок на функции и столбцы (Том Лейн)

    Когда x является именем таблицы или составным столбцом, PostgreSQL традиционно рассматривает синтаксические формы f(x) и x.f должны быть эквивалентны, что позволяет использовать такие приемы, как написание функции и ее последующее использование, как если бы это был столбец, вычисляемый по запросу. Однако, если обе интерпретации возможны, всегда выбиралась интерпретация столбца, что приводило к неожиданным результатам, если пользователь намеревался интерпретировать функцию. Теперь, если есть двусмысленность, выбирается интерпретация, соответствующая синтаксической форме.

Таким образом, если в таблице reps есть столбец fullname, а также отображаемая вами функция pub.fullname(pub.reps), Postgres 10, даже с функциональной нотацией, все равно выберет column< /эм>:

SELECT fullname(r) FROM reps r;  -- resolves to column if it exists, ignoring function

db‹>fiddle здесь для Postgres 10

Postgres 11 (более разумно) выбирает функцию:

db‹>fiddle здесь для Postgres 11

Postgres 12 (в настоящее время бета-версия) в конечном итоге реализует настоящие сгенерированные столбцы. Примечания к выпуску:

  • Добавлена ​​поддержка сгенерированных столбцов (Питер Эйзентраут)

Содержимое сгенерированных столбцов вычисляется из выражений (включая ссылки на другие столбцы в той же таблице), а не задается командами INSERT или UPDATE.

Однако в этот выпуск вошли только сгенерированные столбцы STORED. (более интересный ИМО) VIRTUAL вариант был отложен для более позднего выпуска. (Пока нет в Postgres 13.)

Ваша таблица может выглядеть так:

CREATE TABLE pub.reps (
  reps_id  int GENERATED ALWAYS AS IDENTITY PRIMARY KEY 
, fname    text NOT NULL
, lname    text NOT NULL
, fullname text GENERATED ALWAYS AS (fname || ' ' || lname) STORED
);

db‹>скрипка здесь

Я объявил столбцы fname и lname NOT NULL. В противном случае ваша простая конкатенация (fname || ' ' || lname) является ловушкой. Видеть:

person Erwin Brandstetter    schedule 29.06.2019