sql >> Databasteknik >  >> RDS >> PostgreSQL

PostgreSQL:hur ställer jag in sökvägen inifrån en funktion?

Allmän lösning

Jag skapade en ren sql-funktion genom att använda set_config().

Den här lösningen stöder inställning av flera scheman i en kommaseparerad sträng. Som standard gäller ändringen den aktuella sessionen. Om du ställer in parametern "is_local" till sant gör att ändringen endast gäller den aktuella transaktionen, se http://www.postgresql.org/docs/9.4/static/functions-admin.html för mer information.

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;

Eftersom vi inte kör någon dynamisk sql borde det vara mindre chans för sql-injektion. Bara för att vara säker har jag lagt till lite naiv sanering av texten genom att ta bort alla tecken utom alfanumeriska tecken, mellanslag och kommatecken. Att fly/citera strängen var inte trivialt, men jag är ingen expert, så.. =)

Kom ihåg att det inte finns någon feedback om du ställer in en felaktig sökväg.

Här är några exempelkoder för testning:

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;

Ett test baserat på OP:s ursprungliga kod

Eftersom vi inte känner till schemat för mytable i förväg måste vi använda dynamisk sql. Jag bäddade in set_config-oneliner i get_sections()-funktionen istället för att använda den generiska funktionen.

Obs! Jag var tvungen att ställa in is_local=false i set_config() för att detta skulle fungera. Det betyder att den ändrade sökvägen finns kvar efter att funktionen har körts. Jag är inte säker på varför.

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. Uppdatera tidsstämpel när raden uppdateras i PostgreSQL

  2. Hur man löser problem med Oracle DBMS_LOB

  3. Hur man skriver migrering för att ändra primärnyckeln för modellen med ManyToManyField

  4. Hur kan jag ställa in en anslutningssträng för SQL Server?