Вставить список столбцов с хранимой процедурой - PullRequest
0 голосов
/ 15 февраля 2019

У меня есть скрипт Matlab, где я хотел бы использовать хранимые процедуры вместо отправки всех инструкций на сервер.Проблема в том, что мне приходится иметь дело со строковыми переменными, содержащими разные столбцы, например, например:

listColumns = '(column1, column2, column3, ... columnN)';

То, что я хотел бы знать, - как создать хранимую процедуру с использованием динамического SQLсделать вставки со списком столбцов в качестве входного аргумента строки?Возможно ли это или мне нужно изменить свой сценарий, чтобы сделать его более простым?

Это довольно ново для меня, я пробовал более упрощенные хранимые процедуры, где мне нужен только один столбец, и он работал хорошо, но яЯ застрял с этим на данный момент:

CREATE OR REPLACE FUNCTION myfunction(
    tablename regclass, 
    listColumns regclass,
    listColumnsTarget regclass)
    RETURNS void
    LANGUAGE = 'plpgsql'
AS $$
BEGIN
    EXECUTE format('INSERT INTO ' %s %s '(SELECT ' %s ' FROM anotherTable)',
    tablename, listeColumns, listColumnsTarget);
END
$$;

Я ожидал заставить хранимую процедуру работать, но она не удалась, и я получил синтаксическую ошибку ...

1 Ответ

0 голосов
/ 16 февраля 2019
Тип

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
...