Тип
regclass
может содержать только одну идентификацию некоторого объекта базы данных (описывается одной строкой системной таблицы pg_class
).Вы не можете использовать тип regclass
для передачи имен столбцов, потому что только столбцы не являются таблицами.Тип regclass
является специальным и проверяет значение по системным таблицам.
postgres=# select 'xxx'::regclass;
ERROR: relation "xxx" does not exist
LINE 1: select 'xxx'::regclass;
^
В Postgres есть специальный тип для идентификаторов SQL - name
.И если вы хотите передать больше значений, вы должны использовать массив имен - name[]
.Но для ввода извне лучше использовать обычный тип text
и обрабатывать необходимые операции внутри функции.Использование типа name
не помогает нам в этом контексте.
Что необходимо?Побег - это дезинфекция от синтаксических ошибок или SQL-инъекций.Например - идентификаторы: fubu, boo-boo, AA
должны быть переведены в безопасный список идентификаторов: fubi, "boo-boo", "AA"
.Этот шаг очень важен
В Postgres нет никаких функций для этого форка для списка, но мы можем написать собственную функцию:
CREATE OR REPLACE FUNCTION sanitize_identifiers(text)
RETURNS text AS $$
SELECT string_agg(quote_ident(v), ',')
FROM unnest(string_to_array($1, ',')) g(v)
$$ LANGUAGE sql;
Теперь мы можем написать такую функцию:
CREATE OR REPLACE FUNCTION foo(tablename regclass,
columns text)
RETURNS void AS $$
BEGIN
-- should to print valid SQL
RAISE NOTICE '%',
FORMAT('INSERT INTO %s SELECT %s FROM tab',
tablename,
sanitize_identifiers(columns));
END;
$$ LANGUAGE plpgsql;
Результат:
postgres=# select foo('Test','a,b,c,C');
NOTICE: INSERT INTO test SELECT a,b,c,"C" FROM tab