Определить имена таблиц и столбцов в качестве аргументов в функции plpgsql?
Это должно быть просто, но я делаю свои первые шаги в функции Postgres, и я не могу найти ничего, что работает...
Я хотел бы создать функцию, которая будет изменять таблицу и / или столбец, и я не могу найти правильный способ указания моих таблиц и столбцов в качестве аргументов в моей функции.
Что-то вроде:
CREATE OR REPLACE FUNCTION foo(t table)
RETURNS void AS $$
BEGIN
alter table t add column c1 varchar(20);
alter table t add column c2 varchar(20);
alter table t add column c3 varchar(20);
alter table t add column c4 varchar(20);
END;
$$ LANGUAGE PLPGSQL;
select foo(some_table)
В другом случае я хотел бы иметь функцию, которая изменяет определенный столбец из определенной таблицы:
CREATE OR REPLACE FUNCTION foo(t table, c column)
RETURNS void AS $$
BEGIN
UPDATE t SET c = "This is a test";
END;
$$ LANGUAGE PLPGSQL;
Возможно ли это сделать?
1 ответ:
Вы должны защищаться от инъекция SQL всякий раз, когда вы превращаете пользовательский ввод в код. Это включает в себя имена таблиц и столбцов, поступающие из системных каталогов или из непосредственного пользовательского ввода. Таким образом, вы также предотвратите тривиальные исключения с нестандартными идентификаторами. Есть в основном три встроенные методы:
1.
format()
1-й запрос, обработано:
CREATE OR REPLACE FUNCTION foo(_t text) RETURNS void AS $func$ BEGIN EXECUTE format(' ALTER TABLE %I ADD COLUMN c1 varchar(20) , ADD COLUMN c2 varchar(20)', _t); END $func$ LANGUAGE plpgsql;
format()
требуется Postgres 9.1 или более поздняя версия. Используйте его с%I
спецификатор формата.Одно только имя таблицы может быть неоднозначным. Возможно, вам придется указать имя схемы, чтобы избежать случайного изменения неправильной таблицы. Связанные:
- вставка с динамическим именем таблицы в триггерной функции
- Как search_path влияет на разрешение идентификатора и "текущую схему"
В сторону: добавление несколько столбцов С одной командой
ALTER TABLE
- это более дешевый.2.
regclass
Можно также использовать приведение к зарегистрированному классу (
regclass
) для частного случая существующие имена таблиц. Необязательно с оговоркой схемы. Это происходит немедленно и изящно для имен таблиц, которые не являются допустимыми и видимыми для вызывающего пользователя. 1-й запрос санирован с приведением кregclass
:CREATE OR REPLACE FUNCTION foo(_t regclass) RETURNS void AS $func$ BEGIN EXECUTE 'ALTER TABLE '|| _t ||' ADD COLUMN c1 varchar(20) , ADD COLUMN c2 varchar(20)'; END $func$ LANGUAGE plpgsql;
Вызов:
SELECT foo('table_name');
Или:
SELECT foo('my_schema.table_name'::regclass);
В сторону: рассмотрите возможность использования just
text
вместо того, чтобыvarchar(20)
.3.
quote_ident()
2-й запрос санирован:
CREATE OR REPLACE FUNCTION foo(_t regclass, _c text) RETURNS void AS $func$ BEGIN EXECUTE 'UPDATE '|| _t ||' -- sanitized with regclass SET '|| quote_ident(_c) ||' = ''This is a test'''; END $func$ LANGUAGE plpgsql;
Для множественных конкатенаций / интерполяций,
format()
чище ...Соответствующие ответы:
Регистр чувствителен!
Имейте в виду, что некотируемые идентификаторы здесь не приведены к нижнему регистру. При использовании в качестве идентификатор в SQL Postgres автоматически переводится в нижний регистр . Но здесь мы передаем строки для динамического SQL. При экранировании, как показано, идентификаторы CaMel-case (например,
UserS
) будут сохранены путем удвоения ("UserS"
), как и другие нестандартные имена, такие как"name with space"
"SELECT"
и т.д. Следовательно, имена чувствительны к регистру в этом контексте.мой постоянный совет - использовать исключительно юридические идентификаторы нижнего регистра и никогда не беспокоиться об этом.
В сторону: одинарные кавычки для значений, двойные кавычки для идентификаторов .