sql >> Database >  >> RDS >> PostgreSQL

PostgreSQL:hoe stel ik het zoekpad in vanuit een functie?

Algemene oplossing

Ik heb een pure sql-functie gemaakt met set_config().

Deze oplossing ondersteunt het instellen van meerdere schema's in een door komma's gescheiden tekenreeks. Standaard is de wijziging van toepassing op de huidige sessie. Als u de parameter "is_local" instelt op true, is de wijziging alleen van toepassing op de huidige transactie, zie http://www.postgresql.org/docs/9.4/static/functions-admin.html voor meer details.

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;

Aangezien we geen dynamische sql gebruiken, zou er minder kans moeten zijn op sql-injectie. Voor de zekerheid heb ik wat naïeve opschoning van de tekst toegevoegd door alle tekens te verwijderen, behalve alfanumeriek, spatie en komma. Ontsnappen/citeren van de string was niet triviaal, maar ik ben geen expert, dus.. =)

Onthoud dat er geen feedback is als je een verkeerd opgemaakt pad instelt.

Hier is wat voorbeeldcode om te testen:

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;

Een test gebaseerd op de originele code van OP

Omdat we het schema voor mytable niet van tevoren kennen, moeten we dynamische sql gebruiken. Ik heb de set_config-oneliner ingesloten in de get_sections()-functie in plaats van de generic'ish-functie te gebruiken.

Opmerking: Ik moest is_local=false instellen in set_config() om dit te laten werken. Dat betekent dat het gewijzigde pad blijft bestaan ​​nadat de functie is uitgevoerd. Ik weet niet zeker waarom.

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. Vind de meest recente dubbele ID met MySQL

  2. Hoe u herhalende datums opslaat, rekening houdend met de zomertijd

  3. Java:CLOB invoegen in de Oracle-database

  4. bundel mislukt - Kan de PostgreSQL-clientbibliotheek (libpq) niet vinden