sql >> Databáze >  >> RDS >> PostgreSQL

PostgreSQL:jak nastavím search_path zevnitř funkce?

Obecné řešení

Vytvořil jsem čistou funkci SQL pomocí set_config().

Toto řešení podporuje nastavení více schémat v řetězci odděleném čárkou. Ve výchozím nastavení se změna vztahuje na aktuální relaci. Nastavením parametru „is_local“ na hodnotu true se změna použije pouze na aktuální transakci, viz http://www.postgresql.org/docs/9.4/static/functions-admin.html pro více podrobností.

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;

Vzhledem k tomu, že neprovozujeme žádné dynamické sql, měla by být menší šance na vložení SQL. Pro jistotu jsem přidal naivní dezinfekci textu odstraněním všech znaků kromě alfanumerických, mezer a čárek. Únik/citování řetězce nebylo triviální, ale nejsem odborník, takže.. =)

Pamatujte, že pokud nastavíte nesprávnou cestu, nedojde k žádné zpětné vazbě.

Zde je ukázkový kód pro testování:

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 založený na původním kódu OP

Protože předem neznáme schéma pro mytable, musíme použít dynamické sql. Místo použití obecné funkce jsem vložil set_config-oneliner do funkce get_sections()-.

Poznámka: Aby to fungovalo, musel jsem v set_config() nastavit is_local=false. To znamená, že upravená cesta zůstane po spuštění funkce. Nejsem si jistý proč.

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. SQL Server ekvivalent funkce substring_index v MySQL

  2. Funkce MySQL ACOS() – Vrátí úhlový kosinus čísla

  3. MySQL vybírá včerejší datum

  4. Jak zjistíte URL databáze Oracle?