2012-09-20 25 views
1

我試圖寫一個PL/pgSQL函數將執行存儲在PostgreSQL表內,像這樣的查詢:當我嘗試運行此查詢錯誤:鍵入「執行」不存在

CREATE OR REPLACE FUNCTION evaluate_scenario(scenario_id int) 
RETURNS TABLE(line_item_id int, organization_id int, data_element_id int, value varchar) AS $$ 
BEGIN 
    RETURN QUERY 
    SELECT 
    li.id, 
    li.organization_id, 
    de.id, 
    (EXECUTE 'SELECT ' || de.query)::varchar 
    FROM 
    line_items AS li INNER JOIN 
    summary_files AS sf ON li.summary_file_id = sf.id INNER JOIN 
    scenarios AS s ON s.summary_file_id = sf.id CROSS JOIN 
    data_elements AS de 
    WHERE 
    s.id = 1 AND 
    de.scope = 3 AND (
     de.model_id = s.model_id OR 
     de.scenario_id = s.id OR 
     de.organization_id = s.organization_id 
    ); 
END; 
$$ LANGUAGE plpgsql; 

select line_item_id, data_element_id, value from evaluate_scenario(1)

我收到以下錯誤:

********** Error ********** 

ERROR: type "execute" does not exist 
SQL state: 42704 
Context: PL/pgSQL function "evaluate_scenario" line 3 at RETURN QUERY 

任何幫助將不勝感激。請注意,如果我刪除了「EXECUTE」,只是在那些parens中執行SELECT de.query,我會按預期收到該列的值,但我無法弄清楚如何使de.query成爲「EXECUTE」的可接受查詢字符串」。

回答

4

EXECUTE以查詢字符串作爲參數並執行它,但您不能在查詢中嵌套EXECUTE

plpgsql中有EXECUTE的幾個變種。對於你的情況,RETURN QUERY EXECUTE query可能是最好的。閱讀手冊。

這可能工作 - 我不是想解決所有的混亂,只是演示一個工作的例子。

CREATE OR REPLACE FUNCTION evaluate_scenario(_scenario_id int) 
RETURNS TABLE(line_item_id int, organization_id int, data_element_id int, value varchar) AS 
$func$ 

BEGIN 
    RETURN QUERY EXECUTE ' 
    SELECT li.id, 
     li.organization_id, 
     de.id, 
     (SELECT ' 
|| (SELECT query 
    FROM data_elements 
    WHERE scenario_id = _scenario_id) 
|| ') 
    FROM line_items AS li 
    JOIN summary_files AS sf ON li.summary_file_id = sf.id 
    JOIN scenarios AS s ON s.summary_file_id = sf.id 
    CROSS JOIN data_elements AS de 
    WHERE s.id = 1 
    AND de.scope = 3 
    AND (de.model_id = s.model_id OR 
     de.scenario_id = s.id OR 
     de.organization_id = s.organization_id 
     )'; 

END; 
$func$ LANGUAGE plpgsql; 

需要注意的是固有的不安全執行文本文字作爲代碼。如果有人可以將DROP * FROM tbl或其他類似的東西偷運到data_elements表中,那麼您將面臨很大麻煩。我說的是SQL injection
瞭解更多關於SQLi的信息,在bobby-tables.com

+0

謝謝,我熟悉SQL注入,但這些查詢是由服務器基於Excel的風格的公式生成的,所以可以出現的唯一類型的查詢是由分析代碼的AST散發的,所有這些都是安全的。 –