Blog JSystems - uwalniamy wiedzę!

Szukaj

PostgreSQL

Zapytanie nie widzi tabeli - jak działa search_path

W skrócie

  • Problem: tabela na pewno istnieje, a zapytanie zwraca ERROR: relation "..." does not exist.
  • Dlaczego: tabela leży w innym schemacie niż te wypisane w search_path, więc serwer nie znajduje jej po samej nazwie.
  • Rozwiązanie: odwołujemy się do tabeli z nazwą schematu albo poprawiamy search_path roli lub bazy.

To klasyczne zaskoczenie - \dt pokazuje tabelę, a SELECT twierdzi, że jej nie ma. Winowajcą jest niemal zawsze search_path, czyli lista schematów, w których PostgreSQL szuka obiektów podanych bez nazwy schematu. Schemat to logiczny pojemnik na tabele i inne obiekty wewnątrz jednej bazy. Problem dotyczy każdego, kto rozdziela dane na schematy albo pracuje na kilku rolach. Pokazujemy, jak działa rozwiązywanie nazw i jak ustawić search_path tak, by zapytania trafiały tam, gdzie trzeba.

Jak to wygląda w praktyce

Zapytanie po samej nazwie tabeli kończy się błędem, choć tabela istnieje:

sklep=> SELECT * FROM klienci;
ERROR:  relation "klienci" does not exist
LINE 1: SELECT * FROM klienci;
                      ^

Gdy jednak podasz nazwę schematu wprost, to samo zapytanie działa bez problemu:

sklep=> SELECT * FROM crm.klienci;
 id | nazwa
----+-------
  1 | Kowalski

To najczystszy dowód, że tabela istnieje, tylko leży w schemacie crm, którego nie ma na liście search_path. Serwer szukał klienci w innych schematach i jej tam nie znalazł.

Dlaczego tak się dzieje

Gdy odwołujesz się do obiektu bez nazwy schematu (na przykład klienci zamiast crm.klienci), PostgreSQL przechodzi kolejno przez schematy wypisane w parametrze search_path i bierze pierwszy, w którym znajdzie obiekt o tej nazwie. Domyślny search_path to "$user", public - najpierw schemat o nazwie równej nazwie bieżącej roli, a potem public. Jeśli Twoja tabela jest w schemacie crm, którego nie ma na tej liście, serwer po prostu jej nie zobaczy i zgłosi relation does not exist - mimo że obiekt fizycznie istnieje. To nie problem uprawnień (tamten daje permission denied), tylko rozwiązywania nazw. Ta sama nazwa tabeli może zresztą występować w kilku schematach naraz, a search_path rozstrzyga, którą z nich widzisz bez kwalifikacji.

Jak to rozwiązać krok po kroku

  1. Ustal, w którym schemacie jest tabela: SELECT schemaname, tablename FROM pg_tables WHERE tablename = 'klienci';.
  2. Sprawdź bieżący search_path w swojej sesji: SHOW search_path;.
  3. Doraźnie w zapytaniu odwołuj się do tabeli z nazwą schematu: SELECT * FROM crm.klienci; - to zawsze zadziała niezależnie od search_path.
  4. Aby zmienić to na czas sesji: SET search_path = crm, public;. Ustawienie znika po rozłączeniu.
  5. Aby zmiana była trwała dla roli: ALTER ROLE app SET search_path = crm, public; - zadziała przy kolejnych logowaniach tej roli.
  6. Aby ustawić domyślny schemat dla całej bazy: ALTER DATABASE sklep SET search_path = crm, public;. Kolejność ma znaczenie - pierwszy schemat z listy jest przeszukiwany najpierw.

Jak sprawdzić, że zadziałało

Po zmianie potwierdź, że search_path ma właściwe schematy - a przede wszystkim, że serwer rozwiązuje nazwę do konkretnego obiektu:

SHOW search_path;
SELECT to_regclass('klienci') AS znaleziona_tabela;

Funkcja to_regclass zwróci pełną nazwę tabeli (na przykład crm.klienci), jeśli nazwa jest rozwiązywalna w bieżącym search_path, albo NULL, jeśli nadal nie jest widoczna. Gdy zwraca właściwą tabelę, zapytania po samej nazwie zaczną działać.

Wróć do listy: 100 najczęstszych pytań i problemów z PostgreSQL

Szkolenie Administracja, replikacja i tuning baz danych PostgreSQL

Sprawdź szkolenie: Administracja, replikacja i tuning baz danych PostgreSQL

To szkolenie może być dofinansowane z KFS lub BUR.

★★★★★Średnia ocena naszych szkoleń w Google: 5/5

Szkolenie Zaawansowana administracja PostgreSQL - HA, DR, monitoring, skalowanie

Sprawdź szkolenie: Zaawansowana administracja PostgreSQL (HA, DR, monitoring, skalowanie)

To szkolenie może być dofinansowane z KFS lub BUR.

★★★★★Średnia ocena naszych szkoleń w Google: 5/5

Najczęściej zadawane pytania

Dlaczego dostaję relation does not exist, skoro tabela na pewno istnieje?
Bo odwołujesz się do niej bez nazwy schematu, a schemat, w którym leży, nie jest wpisany w search_path. PostgreSQL szuka obiektu tylko w schematach z tej listy i jeśli go tam nie ma, zgłasza relation does not exist. To nie brak tabeli ani brak uprawnień, tylko kwestia rozwiązywania nazw. Odwołanie z nazwą schematu, na przykład crm.klienci, od razu to potwierdzi.
Co dokładnie robi parametr search_path?
Określa listę schematów, które PostgreSQL przeszukuje po kolei, gdy odwołujesz się do obiektu bez podania schematu. Bierze pierwszy schemat z listy, w którym znajdzie obiekt o danej nazwie. Domyślnie search_path to $user oraz public. Dodanie własnego schematu na tę listę sprawia, że tabele z niego stają się widoczne bez konieczności kwalifikowania ich pełną nazwą.
Jak ustawić search_path na stałe dla roli lub bazy?
Dla roli poleceniem ALTER ROLE nazwa SET search_path = schemat, public, które zadziała przy kolejnych logowaniach tej roli. Dla całej bazy poleceniem ALTER DATABASE nazwa SET search_path = schemat, public. Ustawienie przez SET obowiazuje tylko w bieżącej sesji i znika po rozłączeniu, dlatego do trwałej konfiguracji używa się wariantów ALTER ROLE albo ALTER DATABASE.
Czy dwie tabele o tej samej nazwie mogą istnieć w jednej bazie?
Tak, o ile leżą w różnych schematach - na przykład crm.klienci i public.klienci to dwie odrębne tabele. Przy odwołaniu bez nazwy schematu o tym, którą zobaczysz, decyduje kolejność w search_path. To potężny mechanizm, ale bywa źródłem pomyłek, dlatego w kodzie produkcyjnym warto kwalifikować nazwy schematem, gdy nazwa tabeli mogłaby być niejednoznaczna.

Komentarze (0)

Musisz być zalogowany by móc dodać komentarz. Zaloguj się przez Google

Brak komentarzy...