2013-10-10 3 views
0

Я создаю функцию в postgres и получаю странную ошибку. Что я делаю не так? Я также хотел бы видеть ваши варианты, как сделать этоОшибка функции Postgres

CREATE OR REPLACE FUNCTION export_csv(request TEXT, filename VARCHAR(255)) 
RETURNS VOID AS 
$$ 
BEGIN 
    EXECUTE 'COPY (' || request || ') TO "/home/r90t/work/study/etl/postgres_etl/export/' || filename || '" WITH CSV;'; 
END 
$$ 
LANGUAGE plpgsql; 

ЗАПРОС:

SELECT export_csv('SELECT * FROM orders', 'orders.csv') 

ОШИБКА:

psql:/tmp/vUp267V/dbext.sql:2: ERROR: syntax error at or near ""/home/r90t/work/study/etl/postgres_etl/export/orders.csv"" 
LINE 1: COPY (SELECT * FROM orders) TO "/home/r90t/work/study/etl/po... 
            ^$ 
QUERY: COPY (SELECT * FROM orders) TO "/home/r90t/work/study/etl/postgres_etl/export/orders.csv" WITH CSV; 
CONTEXT: PL/pgSQL function export_csv(text,character varying) line 3 at EXECUTE statement 
+2

Строковые литералы должны быть заключены в одинарные кавычки, а не в двойные кавычки. –

ответ

0

О мальчик .....

Первое, потому что вы COPY TO FILE, ваша функция должна работать как суперпользователь, и вы вставляете SQL-запрос, предоставленный пользователем в этот файл. По крайней мере, вы должны запустить запрос как суперпользователь, и вы не задали над ним ОПЕРАТИВНОСТЬ БЕЗОПАСНОСТИ. Но весь смысл вашей функции - SQL-инъекция и очень мало выгоды. Я понимаю, что это немного для личного исследования, но нечего делать, делая это таким образом, чтобы в будущем данные бизнеса подвергались риску.

В частности, интересно, что случилось бы, если бы я сделать что-то вроде:

SELECT export_csv('SELECT * FROM ORDERS TO STDOUT; DROP DATABASE critical_db; --', 'foo'); 

или

SELECT export_csv('SELECT * FROM ORDERS', '../../../../../../../var/lib/pgsql/data/log/postgresql-Tue.log'); 

Действительно, действительно, действительно плохие вещи возможны с вашей функцией. Не делай этого. они содержатся в настоящее время, но как только кто-то делает следующее, вы полностью:

ALTER FUNCTION export_csv SET SECURITY DEFINER; 

Лучше было бы взять один аргумент, который может быть цитируемым и обработан на месте. Что-то вроде:

CREATE OR REPLACE FUNCTION export_csv(relation name, columns name[]) 
RETURNS VOID AS 
$$ 
DECLARE column_list text; 
BEGIN 
    SELECT array_to_string(cols, ', ') INTO column_list 
    FROM (SELECT array_agg(quote_literal(col)) as cols 
      FROM unnest(columns) col 
     ) a; 

    EXECUTE 'COPY (SELECT ' || column_list || ' FROM ' || quote_ident(relation) || ') 
      TO ' || quote_literal('/home/r90t/work/study/etl/postgres_etl/export/' || relation) || ' WITH CSV;'; 
END 
$$ 
LANGUAGE plpgsql; 

Это даст вам защиту от SQL-инъекции, и если вам нужна дата добавляемой к концу, вы можете сделать это с чем-то внутри quote_literal вызова.

Смежные вопросы