2016-10-11 29 views
6

我想在PL/pgSQL中用一對嵌套(或內部)函數創建一個函數。通過這種方式,我可以將問題分解爲更小的部分,但不能在此功能外部訪問我的小部分。如何在PL/pgSQL中創建嵌套函數?

在PL/pgSQL中可以這樣做嗎?如果是這樣,怎麼樣?

+0

你爲什麼要那樣做?對我來說似乎不切實際。你可以將這個問題分解成沒有很多功能的小塊,或者你真的需要它 - 調整它們的權限。 –

回答

2

PLpgSQL不支持嵌套函數。仿效沒有任何意義,並且不具有生產力。

+1

初看獼猴桃描述的模擬工作。我在較小的數據集上進行了測試,看起來不錯。但是,在處理較大的日期時,它總是失敗,出現非常奇怪的鎖定錯誤。我想任何讀這個的人最好不要強迫嵌套函數在PL/pgSQL中工作。 –

+0

@GregoryArenius:我做了一些演示,它每次調用函數「outer」時都會創建/替換函數「inner」(與「outer」函數在同一範圍內),因此會出現奇怪的錯誤。它根本不是一個「內部功能」,它也無法訪問「外部」的內部範圍。 –

7

試試:

CREATE OR REPLACE FUNCTION outer() RETURNS void AS $outer$ 
DECLARE s text; 
BEGIN 
    CREATE OR REPLACE FUNCTION inner() RETURNS text AS $inner$ 
    BEGIN 
    RETURN 'inner'; 
    END; 
    $inner$ language plpgsql; 

    SELECT inner() INTO s; 
    RAISE NOTICE '%', s; 

    DROP FUNCTION inner(); 
END; 
$outer$ language plpgsql; 

了在Postgres 9.5 SELECT outer();輸出

psql:/vagrant/f.sql:14: NOTICE: inner 

編輯:如果你沒有在外部函數的末尾落內 功能將仍然可見數據庫的其餘部分。

+2

有幾件事要指出其他任何嘗試這樣做的人:你不能僅僅爲內部函數和外部函數使用'AS $$'。另外,如果你的函數有參數,當你放棄這個函數時你必須傳遞這些類型。而且你不能在外函數的'DECLARE'部分調用你的函數,因爲它們還沒有被創建。只需創建變量並在創建嵌套函數後爲其賦值。 –

+2

@Gregory:更重要的一點:如果兩個併發事務試圖調用這個函數,那麼第二個事務會阻塞內部的'CREATE',直到第一個事務提交爲止,這是由於數據庫對函數名的唯一性約束。您可以通過將內部函數放入會話的臨時模式中,即使用CREATE FUNCTION pg_temp.inner()來解決此問題。額外的好處是內部函數永遠不會在外部可見,並且在會話之後自動清理。 –

+2

@Gregory:順便說一下,'DECLARE ... BEGIN ... END'塊可以嵌套,所以你可以在創建內部函數後做你的聲明 –