幾年前,當Oracle放棄客戶端的Forms的時候,隨之消失的那些內置的函數中有一項是關於向警告消息函數(alert message function)傳遞參數。如果你處理錯誤或者缺失的輸入參數(你應該這麼做),Forms遷移過程的一部分是將這個內置的函數從6i版本改成9i版本。復雜的應用可能包含有上千條警告消息,並且一個主要的應用(即Forms)的變化會導致上千條改變。做這樣的改變的確是一件討人嫌的行為。
另一方面,作為一個使用PL/SQL的DBA和程序員,你到底寫過多少次DBMS_OUTPUT.PUT_LINE('')?必須寫的或者敲入的DBMS_OUTPUT.PUT_LINE變得非常無聊,使用方便的、內置的短小的代碼不是更好嗎?可能並不是經過深思熟慮,但是更多的歸咎於好運或者意識到同樣的東西必須敲一遍又一遍的現實,機靈的Forms程序員們創建了自己的內置函數,采用了過程的方式來產生警告消息。相同的原理可以被用在你日常的PL/SQL代碼中。事實上,你可以創建一個小的消息庫管理很多類型的輸出消息。讓我們看看一些這樣的可能性。
一個簡單的警告消息過程
就像在這一章節標題中表示的那樣,第一個方法是非常簡單的。假設你有一個常見的需求要輸出某個過程、函數或者代碼塊更新的記錄個數。讓我們假定被更新行的個數是46。使用下面的過程之後,一個簡單的“am(46);”語句就可以你需要的輸出:
CREATE OR REPLACE procedure am (msg number) as
begin
dbms_output.put_line('Records updated: '||msg);
end;
/
另一個版本可以處理字符串類型,因此對 “ams('your message here');”的調用顯著的降低了你敲入的次數。當調試或者解決問題的代碼中,有這樣一個簡單的內置函數對輸出“where am I in the code”的語句是非常寶貴的。位置報告可以確認,比如,你進入了IF-THEN-ELSE語句中哪個分支。假如你的問題代碼調用了很多次其他的對象(過程、函數等等),輸出像“calling function X”或者“returned from function X”這樣的狀態信息可以確認過程流。最終,另外一種使用情況是報告數值。你可以報告或者跟蹤一個變量的值是如何被改變的。
建立一個警告消息庫
當然,你的消息庫的復雜性和靈活性完全取決於你。假如你的(輸出)消息是簡單的,那麼保持函數過程簡單。更准確的講,保持函數過程的個數是最少的。只要兩個簡單的過程,ams和amn,就可以用來輸出基於字符串和數值的消息了。
假如你需要讓輸出的文字內容根據運算的輸出有所變化,比如DML語句的輸出,那麼你可能需要三個新的內置過程(插入、更新和刪除運算各一個)。可能你想說明刪除的類型或者原因。比如一個批處理作業的某一步是計算重復記錄的個數。那麼像“Records counted: 46” 這樣的輸出是足夠有用的,但是在這種情況下,“Duplicates counted: 46”會顯得更有效。因此,我們增加了2個新的內置過程。
這樣,我們現在有了至少6個不同的過程。現在,管理性的問題應該比較明顯了。我們尋找一些簡單的,但是同時又是健壯的過程。至少有兩種方式可以用於重新簡化需要的功能。一種方法是讓警告消息過程能夠接收兩個輸入參數。另外一種方法,正是我准備介紹的,是把這些過程打包。
增加輸入參數的個數
再說一遍,假如前面的簡單方法可以滿足了你的要求,那麼就沒必要繼續深入了。創建有兩個輸入參數的過程,第一個參數是消息文字或者說基礎,第二個參數可以是輸出、位置、狀態或者數值。如果你關注數據類型的轉化,那麼這兩個輸入參數的組合text/text和text/number都可以統一成text/text類型。你的確必須做這樣的轉換嗎?不,但是為了和你已有的保持一致,如果你在別的地方做了類型映射,那麼這裡也進行類型映射。不管這些,下面的例子顯示了第一種方法的靈活性。
CREATE OR REPLACE procedure am (msg1 varchar2, msg2 varchar2) as
begin
dbms_output.put_line(msg1||msg2);
end;
/
編譯之後,下面是使用的例子。
SQL> set serveroutput on
SQL> exec am('Here I am',46);
Here I am46
PL/SQL procedure successfully completed.