PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

PostgreSQL:как да задам search_path от функция?

Общо решение

Създадох чиста sql функция с помощта на set_config().

Това решение поддържа задаване на множество схеми в низ, разделен със запетая. По подразбиране промяната се прилага за текущата сесия. Задаването на параметъра "is_local" на true прави промяната приложима само към текущата транзакция, вижте http://www.postgresql.org/docs/9.4/static/functions-admin.html за повече подробности.

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;

Тъй като не изпълняваме динамичен sql, трябва да има по-малък шанс за инжектиране на sql. Само за да съм сигурен, добавих малко наивно дезинфекция на текста, като премахнах всички знаци с изключение на букви, цифри, интервал и запетая. Избягването/цитирането на низа не беше тривиално, но аз не съм експерт, така че.. =)

Не забравяйте, че няма обратна връзка, ако зададете неправилно образуван път.

Ето примерен код за тестване:

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;

Тест, базиран на оригиналния код на OP

Тъй като не знаем схемата за mytable предварително, трябва да използваме динамичен sql. Вградих set_config-oneliner във функцията get_sections() вместо да използвам общата функция.

Забележка: Трябваше да задам is_local=false в set_config(), за да работи това. Това означава, че модифицираният път остава след изпълнението на функцията. Не съм сигурен защо.

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. Как да получите средна стойност на „средните“ стойности в група?

  2. Postgres:цяло число извън диапазона

  3. Как да използвам SQL for цикъл за вмъкване на редове в база данни?

  4. Защо моята заявка, включваща деление и БРОЙ, винаги води до 1?

  5. Как мога да променя името на базата данни в AWS RDS за Postgresql?