2014-09-22 4 views
1

Я ищу пути быстрый для синтаксического анализа, проверки и вставки данных в таблице (Postgresql 9,3).PostgreSQL: предотвращение SQL Injection на multiinsertion

Данные представляют собой json-массив, который содержит элементы 1..N.

[{"name":"a","value":"1"},{"name":"b","value":"2"}] 

таблица выглядит следующим образом:

CREATE TABLE logs 
(
    id serial NOT NULL, 
    name text , 
    value text, 
    CONSTRAINT "log_Pkey" PRIMARY KEY (id) 
); 

Для этого я хранимую процедуру:

CREATE OR REPLACE FUNCTION insert_logs(v json) 
    RETURNS integer AS 
$BODY$ 
DECLARE 
    sql text; 
    i json; 
    logs_part_id int; 
BEGIN 
    SELECT INTO logs_part_id id from another_table_with_that_id where some_condition. 

    sql = ''; 
    FOR i IN SELECT * FROM json_array_elements(v) 
     LOOP 
     sql = sql||'insert into logs_'||logs_part_id ||' 
     (name, value) 
     values(' ||quote_literal(i->>'name')||' , ' ||quote_literal(i->>'value')||');'; 

     END LOOP; 
    raise notice '%',sql; 

    EXECUTE sql; 
    return 1; 

END 
$BODY$ 
    LANGUAGE plpgsql VOLATILE 
    COST 100; 

(функция возвращает целое число как статус ответа)

Функция вызова:

select * from insert_logs('[{"name":"a","value":"1"},{"name":"b","value":"2"}]'::json); 

Фактически оператор «insert ..» довольно большой - 15 столбцов для вставки, и, возможно, некоторые из них должны быть проверены, чтобы предотвратить инъекцию sql.

Вопрос: Есть ли способ переписать эту хранимую процедуру для повышения производительности? Должен ли я использовать подготовленные заявления?

EDIT.

Причина, по которой я строю sql строку, потому что имя таблицы неизвестно из-за разбиения таблиц. Формат имени таблицы: logs_ id где id - int, который получается непосредственно перед вставкой.

ответ

1

Почему вы создаете строку с несколькими операторами SQL, а затем EXECUTE И вообще?

Просто:

insert into logs (name, value) 
    values(i->>name , i->>value); 

Там нет необходимости явно цитировать, потому что i->>name является text значение, которое вставлено в качестве связанного параметра в insert по PL/PgSQL. Он никогда не анализируется как SQL.

Если вы должны построить оператор динамически (например изменение имени таблицы, за комментарий) использовать EXECUTE ... USING с format:

EXECUTE format('insert into %I (name, value) values($1, $2);', 'logs_'||log_partition_id) 
    USING i->>name , i->>value; 

в вашем случае

+0

Unfortunatelly Мне нужно построить multistatement строку, так как имя таблицы не фиксировано. Это зависит от некоторого параметра.Я отредактировал мое 1-е сообщение – xardas

+0

@ xardas Хорошая деталь, чтобы включить первый раз, тем более, что ваша функция фактически не показывала это вообще. См. Править. –

2

Если вам нужно ускорить ваш запрос, json_populate_recordset() делает именно то, что вам нужно:

insert into logs 
select * from json_populate_recordset(null::logs, '[...]') 

Как для SQL-инъекций: вы всегда должны использовать подготовленные заявления, или по крайней мере выполнить свой SQL с параметрами, посланных отдельно (f.ex. с PQexecParams(), если вы используете libpq напрямую).