1. 程式人生 > >【轉】使用 PL/SQL 條件編譯

【轉】使用 PL/SQL 條件編譯

前處理器指令

指令由指令控制標記“$”和普通的 PL/SQL 文字組成。條件編譯使用三個指令:選擇、查詢和錯誤。特殊的觸發器字元“$”代表條件編譯指令。選擇指令是條件編譯機制的重要組成部分,而查詢和錯誤指令支援有用的附加功能。

選擇指令

選擇指令對條件編譯表示式進行評估,並根據評估的結果選擇要包含在該編譯中的程式碼。完全忽略未選中的程式碼。這不會干擾到現有程式,因為這些程式並未使用條件編譯。條件選擇指令以 $if 開始並使用常規語法:

$if $then? $elsif $then? …$else? $end

其中, 表示靜態布林表示式。靜態布林表示式是一個或多個程式包常量或一個或多個查詢指令的任意組合。以下是選擇指令將程式包常量用作靜態布林

表示式的示例:

$if Trace_Pkg.Trace > 2 $then ?$end

其中,Trace_pkg 是程式包的名稱,Trace 是宣告為 PLS_INTEGER 的常量。請注意,如果 PL/SQL 編譯單元 U內的選擇指令中使用了在程式包 Trace_pkg 內宣告的常量,那麼,U 將在 Trace_pkg 上具有一個依賴項,就好像 Trace_pkg 已經在常規 PL/SQL 程式碼中進行了引用。

查詢指令

查詢指令允許訪問編譯環境,以便將選擇基於當前環境。查詢指令的形式為 $$ 開頭,例如:

$if $$debug_level > 3 $then … $end

識別符號 debug_level 是使用 plsql_ccflags 初始化引數(Oracle 資料庫 10g 第 2 版中的新增內容)定義的,因此:

...plsql_ccflags = 'debug_level:4, ...'

錯誤指令

錯誤指令的形式如下所示

$error $end。

它可以使編譯器報告編譯錯誤,包括 VARCHAR2 表示式中提供的訊息。

Oracle 資料庫 10g 第 2 版提供了以下可以在條件查詢指令中使用的 PL/SQL 編譯器引數:

使用 <wbr>PL/SQL <wbr>條件編譯

PLSQL_CCFLAGS

使用 <wbr>PL/SQL <wbr>條件編譯

PLSQL_DEBUG

使用 <wbr>PL/SQL <wbr>條件編譯

PLSQL_OPTIMIZE_LEVEL

使用 <wbr>PL/SQL <wbr>條件編譯

PLSQL_CODE_TYPE

使用 <wbr>PL/SQL <wbr>條件編譯

PLSQL_WARNINGS

使用 <wbr>PL/SQL <wbr>條件編譯

NLS_LENGTH_SEMANTICS

編譯時,PL/SQL 編譯器引數的值儲存在編譯單元中,並可以使用 all_plsql_object_settings 系列檢視進行檢視。此外,還提供了預定義的查詢指令 $$PLSQL_UNIT$$PLSQL_LINE。有關條件編譯指令語法的詳細資訊,請參閱 PL/SQL 使用者指南和參考 手冊。

使用指令

示例 1:使用程式包常量進行跟蹤和除錯

在條件編譯指令中使用程式包常量為通過單一機制控制一個或多個 PL/SQL 編譯單元提供了一種方法。例如,假設應用程式由許多 PL/SQL 編譯單元組成。在該應用程式內,已嵌入了執行除錯或跟蹤的 ed 方法。這些方法可以通過使用程式包常量的條件編譯指令啟用。因此,可以通過隨時重新編譯該程式包來更改該常量的值。在重新編譯程式包時,所有的相關物件都將自動重新編譯,以接受該程式包常量的新值。這可以用於在整個應用程式中啟用跟蹤和除錯功能。在進行跟蹤和除錯時,利用保護跟蹤和除錯程式碼的新常量值重新編譯程式包規範。這將使所有相關 PL/SQL 單元無效,以便下一次使用時,將不會選中跟蹤和除錯程式碼進行編譯。程式包常量的使用是一種控制所有相關 PL/SQL 單元的有效機制,這些單元在選擇指令內使用打包常量進行條件處理。以下示例演示了這一用法。

1.

開啟一個終端視窗,執行以下命令:

cd /home/oracle/wkdir sqlplus hr/hr
2.

建立程式包 STATIC_CONSTANTS 以宣告可用在條件編譯中的程式包常量。從 SQL*Plus 會話中,執行以下指令碼:

@static_constants

static_constants.sql 指令碼包含以下內容:

CREATE OR REPLACE PACKAGE static_constants is
debug CONSTANT BOOLEAN := FALSE; 
trace CONSTANT BOOLEAN := FALSE;
END ; 
/
3.

建立兩個過程:CHECK_DEBUG(用於檢查程式包常量除錯的值是否是 TRUE)和 CHECK_TRACE(用於檢查程式包跟蹤的值是否是 TRUE)。從 SQL*Plus 會話中,執行以下指令碼:

@debug_trc

debug_trc.sql 指令碼包含以下內容:

CREATE OR REPLACE PROCEDURE check_Debug IS
BEGIN
$IF static_constants.debug $THEN DBMS_OUTPUT.put_line('Debugging ON'); 
$ELSE DBMS_OUTPUT.put_line('Debugging OFF'); $END
END;
/
CREATE or REPLACE PROCEDURE Check_trace IS
BEGIN
$IF static_constants.trace $THEN DBMS_OUTPUT.put_line('Tracing ON'); 
$ELSE DBMS_OUTPUT.put_line('Tracing OFF'); $END
END;
/
4.

Set serveroutput on  using the new SIZE UNLIMITED syntax available in Oracle Database 10g Release 2. Now execute both the procedures.您將看到它顯示跟蹤和除錯均被關閉。

注意:可以將每一行單獨地複製到 sqlplus 中,但不要一起復制這 3 個語句。

set serveroutput on size unlimited exec check_debug exec check_trace
5.

現在,將更改程式包常量的值。從 SQL*Plus 會話中,執行以下指令碼

@reset_const

reset_const.sql 指令碼包含以下內容:

CREATE OR REPLACE PACKAGE static_constants is
debug CONSTANT BOOLEAN := TRUE; 
trace CONSTANT BOOLEAN := TRUE;
END ; 
/
6.

現在,再次執行這兩個過程。您將看到除錯和跟蹤自動啟用了。在重新編譯程式包時,所有相關的物件都變為無效,並在下一次執行時重新編譯。因此,程式包常量的新值可即刻適用於所有相關物件。

exec check_debug exec check_trace

這可以擴充套件至任意數量的相關程式。在需要通過單一機制控制大量程式時,使用這個方法最為有效。用例的其他示例包括針對同一應用程式按州更改賦稅,或根據許可選項更改軟體特性等等。

通過設定 ALTER COMPILE 命令隻影響正在編譯的程式。利用 CREATE or REPLACE 重新編譯這些程式,GET_RECORD 的過程,以接受 employee_id 的值,並顯示相應的記錄。為了保持良好的程式設計實踐,該過程將呼叫

請注意,已刪除了所有條件編譯指令。

2.

建立 SEND_MESSAGE_TO_DBA 和 CHECK_UNIQUE 過程。CHECK_UNIQUE 過程包含兩個不同的程式碼段,一個用於開發中的測試,另一個部署在最終生產環境中。開發程式碼使用條件編譯指令,而生產程式碼使用傳統的 IF-THEN-ELSE 邏輯檢查重複的記錄。從 SQL*Plus 會話中,執行以下指令碼:

@dba_email @chk_unq show errors

dba_email.sql 指令碼包含以下內容:

CREATE OR REPLACE PROCEDURE send_message_to_DBA(emp_id number)
IS
mailhost VARCHAR2(64) := 'mailhost.fictional-domain.com';
sender VARCHAR2(64) := '[email protected]';
recipient VARCHAR2(64) := '[email protected]';
mail_conn utl_smtp.connection;
BEGIN
mail_conn := utl_smtp.open_connection(mailhost, 25);
utl_smtp.helo(mail_conn, mailhost);
utl_smtp.mail(mail_conn, sender);
utl_smtp.rcpt(mail_conn, recipient);
-- open_data(), write_data(), and close_data() into a single call to data().
utl_smtp.open_data(mail_conn);
utl_smtp.write_data(mail_conn, 'A primary key violation has occured for record '||
emp_id || 'in the EMPLOYEES table.This is an automatically generated e-mail message.Please do not respond to this, this is an alert.'|| chr(13));
utl_smtp.write_data(mail_conn, 'This is line 2.'|| chr(13));
utl_smtp.close_data(mail_conn);
utl_smtp.quit(mail_conn);
EXCEPTION
WHEN OTHERS THEN 
NULL;
END;
/

chk_unq.sql 指令碼包含以下內容:

Create or replace Procedure check_unique(emp_id NUMBER) is
v_num number;
force_pk_violation exception;
Begin
Select count(*) into v_num from employees where employee_id = emp_id;
-- production code
If v_num > 1 
then SEND_MESSAGE_TO_DBA(emp_id);
raise force_pk_violation; 
END IF ;
-- Development code 
$if $$FORCE 
$then SEND_MESSAGE_TO_DBA(emp_id);
raise force_pk_violation;
$end
END; 
/
3.

現在,更改會話將 $$force 的值設為 FALSE。從 SQL*Plus 執行以下命令。

ALTER SESSION SET PLSQL_CCFLAGS='force:FALSE';

4.

現在,再次執行 chk_unq.sql

因為變數 $$force 現在的值是 FALSE,所以沒有出現警告;

5.

建立 GET_RECORD 過程。該過程接受 employee id 並返回員工記錄。如果 CHECK_UNIQUE 過程檢查出存在重複記錄,則會顯示一個友好訊息。從 SQL*Plus 會話執行以下指令碼:

@get_record

get_record.sql 指令碼包含以下內容:

Create or replace procedure get_record(emp_id IN NUMBER)
as
emp_record employees%rowtype;
Begin
check_unique(emp_id);
Select * into emp_record from employees where employee_id =emp_id;
Dbms_output.put_line ( 'Name:'|| emp_record.first_name||' '||emp_record.last_name||' '||'Hiredate: ' ||emp_record.hire_date||'
'||'Job:'||' '||emp_record.job_id);
Exception
When others then 
DBMS_OUTPUT.PUT_LINE('We are unable to process your request at this time.
Please try again later.We apologize for any inconvenience');
End;
/
6.

現在,執行 GET_RECORD 過程,傳入 100 作為引數。

exec GET_RECORD(100)

因為沒有重複記錄,所以該過程成功執行。

7.

現在,測試是否在出現重複記錄時顯示訊息。更改會話將 $$force 的值設為 TRUE,並再次執行 GET_RECORD。從 SQL*Plus 會話執行以下命令:

ALTER SESSION SET PLSQL_CCFLAGS='force:TRUE'; exec GET_RECORD(100)

由於未重新編譯該過程,因此它不會受到影響。

8.

使用 ALTER...COMPILE 語句重新編譯 CHECK_UNIQUE 過程,併為 PLSQL_CCFLAGS 引數提供新值。使用 REUSE SETTINGS選項。然後,以值 100 再次執行 GET_RECORD。從 SQL*Plus 會話執行以下命令。

ALTER PROCEDURE CHECK_UNIQUE compile plsql_ccflags = 'force:TRUE' REUSE SETTINGS; exec GET_RECORD(100)

現在,PLSQL_CCFLAGS 值生效,因而程式發出訊息。該方法可以用於影響會話內的特定程式,比如後生產除錯。然而,每個需要新設定的程式都必須使用 CREATE OR REPLACE 或 ALTER...COMPILE 語句進行重新編譯。

返回子主題

示例 3:使用 DBMS_PREPROCESSOR 過程列印或檢索源文字

DBMS_PREPROCESSOR 子程式會在處理條件編譯指令後,列印或檢索 PL/SQL 單元的處理後源文字。這個處理後文本是用於編譯有效 PL/SQL 單元的實際源。執行以下步驟:

1.

Execute the following command to see the actual source code used to compile a valid PL/SQL program: 

EXEC DBMS_PREPROCESSOR.PRINT_POST_PROCESSED_SOURCE('PROCEDURE', 'HR', 'CHECK_UNIQUE');

請注意,已刪除了所有條件編譯指令。

示例 4:使用條件編譯分支程式碼確定最佳效能版本

Oracle 資料庫 10g 引入了 BINARY_DOUBLE 資料型別,該資料型別可用於演算法密集的操作。本例中,將對 BINARY_DOUBLE 資料型別與 NUMBER 資料型別進行比較。需要在兩個不同版本中建立同樣的程式碼,一個使用NUMBER,另一個使用 BINARY_DOUBLE。然後,可將兩個版本包含在同一過程中,以使用 PLSQL_CCFLAGS 進行測試。執行以下步驟:

1.

啟用 ALTER SESSION 以設定標記,從而在兩個版本之間進行選擇。首先,選擇使用 NUMBER 資料型別。從 SQL*Plus 會話中,執行以下命令:

ALTER SESSION SET PLSQL_CCFLAGS = ' numversion:TRUE';

2.

您希望知道哪個程式碼執行速度更快。建立一個 CALC_CIRCLE 過程計算給定半徑的圓的周長和麵積。從 SQL*Plus 會話中,執行以下指令碼:

@num_bdbl

num_bdbl.sql 指令碼包含以下內容:

CREATE or REPLACE PROCEDURE Calc_circle( RADIUS $IF $$NUMVERSION $THEN NUMBER 
$ELSE BINARY_DOUBLE $END)
as 
SUBTYPE my_real IS
$IF $$numversion $THEN 
NUMBER; 
$ELSE 
BINARY_DOUBLE;
$END
num_circ my_real;
num_area my_real;
BDBL_circ my_real;
BDBL_AREA my_real;
BEGIN
num_CIRC:= (3.14016408289008292431940027343666863227 * 2 * RADIUS); 
NUM_AREA := (3.14016408289008292431940027343666863227*radius*radius);
DBMS_OUTPUT.PUT_LINE('The circumference is:'||num_circ);
DBMS_OUTPUT.PUT_LINE('The area is:'||num_area);
END ;
/

3.

執行 CALC_CIRCLE 過程,使用數字 1234567890 作為半徑

set timing on exec calc_circle(1234567890)

4.

使用 ALTER COMPILE 命令將 $$numversion 的值更改為 FALSE 來編譯 CALC_CIRCLE,並使用相同的引數再次執行 CALC_CIRCLE

ALTER PROCEDURE calc_circle COMPILE plsql_ccflags = 'numversion :false' REUSE SETTINGS;exec calc_circle(1234567890) set timing off

您可以看出二者效能間的差異。本例闡明瞭可以使用條件編譯在相同程式內有選擇地測試兩個版本的程式碼。

示例 5:將條件編譯與不同的 Oracle 資料庫版本結合使用

以下示例演示了 DBMS_DB_VERSION 常量與條件編譯的結合使用。其中對 Oracle 資料庫版本和釋出均進行了檢查。這個 CHECK_VERSIONS 過程使用 COMMIT WRITE IMMEDIATE NOWAIT 命令(已在 Oracle 資料庫 10g 第 2 版中引入)。如果在 Oracle 資料庫早期版本中執行該過程,則無法識別該命令。因此,該過程DBMS_DB_VERSION 程式包檢查資料庫的版本。 如果返回的版本低於 10.2,那麼將使用常規的 COMMIT 提交事務。當在版本為 10.2 或更高版本的資料庫中執行該過程時,將使用 COMMIT WRITE IMMEDIATE NOWAIT 命令完成該事務。

1.

現在可以測試 Oracle 資料庫版本了。從終端視窗中執行以下指令碼:

@check_version

check_version.sql 指令碼包含以下內容:

CREATE OR REPLACE PROCEDURE check_version AS
BEGIN
-- some code which performs transaction processing ...
$if DBMS_DB_VERSION.VER_LE_10_2 $then 
-- traditional commit
COMMIT;
DBMS_OUTPUT.PUT_LINE ('The transaction has been successfully committed.');
$else 
-- faster COMMIT supported in 10.2
COMMIT WRITE IMMEDIATE NOWAIT;
DBMS_OUTPUT.PUT_LINE ('The transaction has been successfully committed.');
$end
END;
/
2.

現在,在 SQL*Plus 視窗中執行以下命令來執行 check_version 過程。

exec check_version

check_version 的輸出說明:無論版本如何,該過程都能成功完成而且對終端使用者而言是透明的。因此,沒有理由在不同的資料庫版本中使用不同的程式單元

相關推薦

使用 PL/SQL 條件編譯

前處理器指令 指令由指令控制標記“$”和普通的 PL/SQL 文字組成。條件編譯使用三個指令:選擇、查詢和錯誤。特殊的觸發器字元“$”代表條件編譯指令。選擇指令是條件編譯機制的重要組成部分,而查詢和錯誤指令支援有用的附加功能。 選擇指令 選擇指令對條件編譯表示式進

通俗理解條件

前面我們總結了資訊熵的概念通俗理解資訊熵 - 知乎專欄,這次我們來理解一下條件熵。 我們首先知道資訊熵是考慮該隨機變數的所有可能取值,即所有可能發生事件所帶來的資訊量的期望。公式如下:   我們的條件熵的定義是:定義為X給定條件下,Y的條件概率分佈的熵對X的數學期望

OraclePL/SQL 儲存過程 顯式遊標、隱式遊標、動態遊標

  【Oracle】PL/SQL 顯式遊標、隱式遊標、動態遊標 2013年06月17日 09:02:51 AlphaWang 閱讀數:13009更多 個人分類: 【Database】 在PL/SQL塊中執行SELECT、INSERT、DELET

Oracle——pl/sql中文亂碼,顯示“?”

前提      最近的專案都是Oracle,雖然小編對oracle資料庫一直是一竅不懂,但是要去學習啊!也是剛剛開始學習使用,問題就不斷啊。就說這個最有可能遇到的亂碼的問題,第一反應,編碼格式的問題

gcc/g++常用編譯選項和gdb常用除錯命令

  gcc/g++編譯器是我們寫編譯C/C++程式時離不開的編譯工具,而gdb又是除錯C/C++程式的利器,這一篇文章我們記錄一下它們的慣常用法。 gcc/g++常用編譯選項 選項 作

C# Sql連線池

使用連線池 連線到資料庫伺服器通常由幾個需要軟長時間的步驟組成。必須建立物理通道(例如套接字或命名管道),必須與伺服器進行初次連線,必須分析連線字串資訊,必須由伺服器對連線進行身份驗證,等等。 實際上,大部份的應用程式都是使用一個或幾個不同的連線配置。當應用程式的資料量和訪問

OraclePL/SQL實現列印1-100中的素數

--方法一 declare     i number(4);--儲存1-100中所有的數(用作被除數)     j number(4) := 1;--儲存除數     z number(4) := 0

導致SQL執行慢的原因

設置 cga pic 閾值 定義 日誌 iyu 搜索 實操 索引對大數據的查詢速度的提升是非常大的,Explain可以幫你分析SQL語句是否用到相關索引。 索引類似大學圖書館建書目索引,可以提高數據檢索的效率,降低數據庫的IO成本。MySQL在300萬條記錄左右性能

Spark SQL編程指南(Python)

res 平臺 per 它的 split 執行 文件的 分組 不同 轉自:http://www.cnblogs.com/yurunmiao/p/4685310.html 前言 Spark SQL允許我們在Spark環境中使用SQL或者Hive SQL執行關系型查詢。它的核

SQL模糊查詢

使用 模式 正則表達 bcd 一個 長度 排除 lsp [] 在進行數據庫查詢時,有完整查詢和模糊查詢之分。一般模糊查詢語句如下: SELECT 字段 FROM 表 WHERE 某字段 Like 條件 其中關於條件,SQL提供了四種匹

SQL Server 數據庫定時自動備份

c盤 name 命令 管理 toolbar eight 管理員 小紅叉 spa 在SQL Server中出於數據安全的考慮,所以需要定期的備份數據庫。而備份數據庫一般又是在淩晨時間基本沒有數據庫操作的時候進行,所以我們不可能要求管理員每天守到晚上1點去備份數據庫。要

通過編譯函數庫來學習GCC

說了 代碼段 必須 () com 意義 同進程 變量 主程 轉自:http://blog.csdn.net/u012365926/article/details/51446295 基本概念 什麽是庫 在windows平臺和linux平臺下都大量存在著庫。 本質上

編寫高質量代碼改善C#程序的157個建議——建議134:有條件地使用前綴

劃線 set 嘗試 開發 amp 保持 規則 bsp ask 建議134:有條件地使用前綴 在.NET的設計規範中,不建議使用前綴。但是,即便是微軟自己依然廣泛的使用這前綴。 最典型的前綴是m_,這種命名一方面是考慮到歷史沿革中的習慣問題,另一方面也許我們確實有必要這

SQL中的取整函數FLOOR、ROUND、CEIL、TRUNC、SIGN

log rec 截取 符號 floor 個數 clas 絕對值 sign --------------------------------------------------------------------------1 trunc(value,precision)按精

hibernate打印SQL及參數

orm comment binder version engine .org inf 相關 bin 在Hibernate的配置文件hibernate.cfg.xml中有3個設置項跟顯示SQL語句相關,他們的值都是boolean值:1、show_sql:是否顯示SQL語句2、

MySQL SQL 多個Join on(表連線) 和Where間的執行順序(nest loop join機制)

版權宣告:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/qq_27529917/article/details/78447882 在mysql中,多表連線採用nest loop join,即迴圈巢狀連

MySQL使用者管理及SQL語句詳解

【轉】MySQL使用者管理及SQL語句詳解 1.1 MySQL使用者管理 1.1.1 使用者的定義   使用者名稱+主機域 mysql> select user,host,password from mysql.user; +--------+------------+---------

PL\SQL developer 一PL\SQL developer - Oracle的客戶端工具安裝

注意:oracle客戶端和pl/sql developer 是相同的位數,32位都是32位,64位都是64位,不然會報錯。 一.SQL*PLUS客戶端工具 1.下載,網址為:http://www.oracle.com/technetwork/database/features/in

Oracle SQL Loader 使用指南

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

APK反編譯

exce class文件 可執行jar包 bat tails .bat 新版 升級 文本編輯器 學習和開發Android應用有一段時間了,今天寫一篇博客總結一下Android的apk文件反編譯。我們知道,Android應用開發完成之後,我們最終都會將應用打包成一個apk文件