2012-09-11 61 views
1

在postgres的存儲函數中運行外部SQL腳本的最佳方式是什麼?postgresql從函數內部運行外部SQL腳本

this question 解釋瞭如何從在psql中運行的腳本中調用外部腳本,但是我需要在該調用周圍包裝邏輯,因此它必須在存儲函數內完成。

EG。

/tmp/scripts$ cat create_db.sql 
CREATE TABLE dbVersion (
     versionNum VARCHAR(10) NOT NULL, 
     applied TIMESTAMP 
     PRIMARY KEY (versionNum) 
); 

/tmp/scripts$ cat upgrade_db.sql 
CREATE OR REPLACE FUNCTION UpgradeDB (dbName VARCHAR) 
RETURN void AS $$ 
DECLARE 
BEGIN 
     IF EXISTS (SELECT datname from pg_database WHERE datname = dbName) THEN 
       --Do upgrade code 
     ELSE 
       --Install Fresh 
       \i /tmp/scripts/create_db.sql; 
     END IF; 
END; 
$$ language plpgsql; 

SELECT UpgradeDB('foo'); 

這(不出所料)給出

錯誤的錯誤:在或接近語法錯誤 「\」

我能叫出使用plsh,沿(未經測試)線的東西.. 。

CREATE FUNCTION callSQLScript(scriptPath text) 
RETURNS void AS $$ 
    #!/bin/sh 
    plsql -f scriptPath 
$$ LANGUAGE plsh; 

SELECT callSQLScript('/tmp/scripts/create_db.sql'); 

但是這看起來很笨拙。

只是用於plsh的RTFM,它指出'shell腳本可以做任何你想做的事情,但你不能訪問數據庫',所以這可能不會工作。

請注意,我無法複製/粘貼這些代碼段,因此可能會出現拼寫錯誤。

+0

其實最新的PL/SH明確支持'psql'呼籲數據庫訪問:https://github.com/petere/plsh#database - 訪問 –

回答

1

我認爲你的plsh腳本會工作,儘管你拼寫錯誤psql。它不訪問數據庫。它正在呼籲另一個計劃來做到這一點。作爲一個大警告,這意味着腳本將在單獨的交易中運行,甚至單獨的會話可能不是您想要的。

如果我這樣做,我想創建一個表:

CREATE TABLE sql_jobs (
     job_id serial not null unique, -- machine key 
     job_name text primary key, 
     sql_to_execute text not null 
); 

然後你可以選擇到一個變量和執行。當然,要警惕保障.....

+0

我不知道我明白如何sql_jobs表會幫助。根本問題是,不知道在初始會議中需要完成哪些步驟。你能詳細解答嗎? – TaninDirect

+0

您必須將您的SQL腳本上傳到sql_to_execute部分。然後你可以選擇一個變量並在PL/PGSQL內執行。事情是,你將能夠運行一個完全外部的SQL腳本的唯一方法就是用你提到的方式用pl/sh來完成,但是這有問題。解決方法是確保它不再是外部存儲在它可以檢索它的數據庫。 –

+0

謝謝@Chris Travers。我正在執行此操作,並且想知道,除了重複執行的效率外,存儲腳本與直接從變量執行腳本還有什麼優勢嗎? – TaninDirect

0

你可以使用命令:

psql -d myDataBase -a -f /tmp/scripts/create_db.sql; 

您else塊內

1

\我不工作的原因是因爲\我是一個PSQL命令不是Postgresql命令,因此您不能在函數中使用\ i,因爲該函數是由服務器評估的。

您的解決方案:

  1. 編寫SQL的功能
  2. 編寫的SQL中的表和使用eval函數
  3. 你的建議的PLSQL(但你應該使用PSQL)。
0

我發現在Fedora上安裝的Postgres的rpm'd版本沒有perl或sh語言擴展名(比如plperlu),所以這個選項已經不存在了。但是,安全執行此操作的關鍵在於使用TO PROGRAM選項的COPY函數將執行命令並將stdin傳遞給它。

  1. 創建您的bash shell腳本來運行預期的外部函數。確保腳本中的第一行是格式「#!/ bin/sh」或「#!/ bin/bash」(這裏是你的偏好,這是將要使用的shell);

2)將shell腳本名稱更改爲單個單詞。 IOW,no trailing「.sh」將權限設置爲:chmod u + x

3)查看你的路徑(echo $ PATH),然後選擇一個系統目錄來複制這個腳本文件。

4)你的腳本現在將是一個「命令」像任何其他。您可以使用TO PROGRAM(commandname here)功能通過COPY功能執行它。

參考:

打開腳本到命令 https://docs.fedoraproject.org/ro/Fedora_Draft_Documentation/0.1/html/RPM_Guide/ch14s04s04.html