2013-10-10 45 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

哦,孩子.....

首先,由於您複製到文件,您的函數必須以超級用戶身份運行,並且您正在將用戶提供的SQL查詢內聯到該文件中。至少您必須以超級用戶身份運行查詢,並且您尚未設置SECURITY DEFINER。但是你的函數的全部重點是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_nullable電話裏面的東西。