PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

PostgreSQL:jak ustawić search_path z wnętrza funkcji?

Ogólne rozwiązanie

Stworzyłem czystą funkcję sql za pomocą set_config().

To rozwiązanie obsługuje ustawianie wielu schematów w ciągu oddzielonym przecinkami. Domyślnie zmiana dotyczy bieżącej sesji. Ustawienie parametru „is_local” na true powoduje, że zmiana dotyczy tylko bieżącej transakcji, patrz http://www.postgresql.org/docs/9.4/static/functions-admin.html po więcej szczegółów.

CREATE OR REPLACE FUNCTION public.set_search_path(path TEXT, is_local BOOLEAN DEFAULT false) RETURNS TEXT AS $$
    SELECT set_config('search_path', regexp_replace(path, '[^\w ,]', '', 'g'), is_local);
$$ LANGUAGE sql;

Ponieważ nie uruchamiamy żadnego dynamicznego sql, prawdopodobieństwo wstrzyknięcia sql powinno być mniejsze. Dla pewności dodałem trochę naiwnego oczyszczenia tekstu poprzez usunięcie wszystkich znaków z wyjątkiem znaków alfanumerycznych, spacji i przecinka. Ucieczka/cytowanie ciągu znaków nie było trywialne, ale nie jestem ekspertem, więc... =)

Pamiętaj, że nie ma informacji zwrotnej, jeśli ustawisz nieprawidłową ścieżkę.

Oto przykładowy kod do testowania:

DROP SCHEMA IF EXISTS testschema CASCADE;
CREATE SCHEMA testschema;
CREATE TABLE testschema.mytable ( id INTEGER );

SELECT set_search_path('testschema, public');
SHOW search_path;

INSERT INTO mytable VALUES(123);
SELECT * FROM mytable;

Test oparty na oryginalnym kodzie OP

Ponieważ nie znamy z góry schematu mytable, musimy użyć dynamicznego sql. Umieściłem set_config-oneliner w funkcji get_sections() zamiast używać funkcji generic.

Uwaga: Musiałem ustawić is_local=false w set_config(), aby to zadziałało. Oznacza to, że zmodyfikowana ścieżka pozostaje po uruchomieniu funkcji. Nie wiem dlaczego.

DROP SCHEMA IF EXISTS testschema CASCADE;
CREATE SCHEMA testschema;
SET search_path TO public;

CREATE TABLE testschema.mytable ( id INTEGER, name varchar, type varchar );
INSERT INTO testschema.mytable VALUES (123,'name', 'some-type');
INSERT INTO testschema.mytable VALUES (567,'name2', 'beer');

CREATE OR REPLACE FUNCTION get_sections(schema_name TEXT) RETURNS 
TABLE(id integer, name varchar, type varchar) AS $$
BEGIN
    PERFORM set_config('search_path', regexp_replace(schema_name||', public', '[^\w ,]', '', 'g'), true);
    EXECUTE 'SELECT id, name, type FROM mytable';
END;
$$ LANGUAGE plpgsql;

SET search_path TO public;
SELECT * FROM get_sections('testschema');
SHOW search_path;  -- Unfortunately this has modified the search_path for the whole session.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Laravel 5 + PostgreSQL:Baza danych [postgres] nieskonfigurowana. Błąd

  2. Java JDBC ignoruje setFetchSize?

  3. Postgres:zaktualizuj sekwencję klawiszy podstawowych dla wszystkich tabel

  4. Jak określić ziarno klucza podstawowego dla tabeli postgres?

  5. Dodaj sekundy do znacznika czasu