[PLSQL] Conditional Compilation

在维护数据库安装脚本的时候发现一个很恶心的问题,就是为了考虑用户有没有安装某一个产品模块,需要安装不同版本的package (trigger),或者是有些package压根在某个版本中不用安装。这样老是维护两套脚本,但是两套脚本的差别又不是很大,维护的成本有点高而且相当的boring. 

想到是否可以利用plsql 的conditional compilation的特性来将不同版本的package合并成一个文件,只需要在不同的“编译环境”下生成“不同版本”的package就可以了。

一不做二不休,开工试试看.....

首先创建一个package,用来定义一个全局的常量开关,如下.....

CREATE OR REPLACE PACKAGE PACK_CONSTANT_FLAGS
IS

-- ALTER SESSION SET PLSQL_CCFLAGS='IS_PROD_INSTALLED:TRUE';
--
ALTER SYSTEM SET PLSQL_CCFLAGS='IS_PROD_INSTALLED:TRUE';
--
SELECT plsql_ccflags FROM user_plsql_object_settings WHERE name = 'PACK_CONSTANT_FLAGS'
--
select * from v$parameter where name='plsql_ccflags';
--
set serveroutput on size unlimited
--
begin
--
DBMS_PREPROCESSOR.PRINT_POST_PROCESSED_SOURCE('PACKAGE', user, 'PACK_CONSTANT_FLAGS');
--
end;

$
IF $$IS_PROD_INSTALLED
$
THEN
C_IS_PROD_INSTALLED CONSTANT BOOLEAN :
= TRUE;
$
ELSE
C_IS_PROD_INSTALLED CONSTANT BOOLEAN :
= FALSE;
$
END

END PACK_CONSTANT_FLAGS;
/

 

这样我就定义了一个编译开关常量PACK_CONSTANT_FLAGS.C_IS_PROD_INSTALLED用来标识有没有安装某个产品。这一这里面用了一个$$IS_PROD_INSTALLED这样一个自定义的PLSQL_CCFLAGS。 当然我可以不用这个ccflags, 只要手动去修改这个package中的变量C_IS_PROD_INSTALLED值,然后重新compile这个package就可以了。但是这样感觉老是修改一个package不是很方便。不用通过设置PLSQL_CCFLAGS来得方便,具体什么时候来set这个$$IS_PROD_INSTALLED呢,很显然在安装产品的时候是很合适的。在安装产品的时候,可以通过

ALTER SYSTEM  SET PLSQL_CCFLAGS='IS_PROD_INSTALLED:TRUE'



来设置ccflags, 显然alter system比alter session更加保险,一般用户不会闲着没事去修改这么一个自定义的ccflags的,当然也不排除这种可能性。如果这样的话,就杯具了..... 而且如果用户环境中已经设置了某些PLSQL_CCFLGS, 这样直接设置这个参数也可能会覆盖掉之前的设置,这个也是个问题!!


 

OK, 剩下的事情就是对相关的Package, Trigger进行修改,比如说.....

create or replace
PACKAGE PACK_LOAD_INIT_DATA
AS

PROCEDURE LOAD_PROD_INIT_DATA(VV_CONTEXT_ID IN NUMBER);

END PACK_LOAD_INIT_DATA;
/

  

这个package只需要在安装了某个产品的时候才需要,那么如果用户没有选择装这个产品,那么我就可以修改package的定义如下....

create or replace
PACKAGE PACK_LOAD_INIT_DATA
AS

$
IF PACK_CONSTANT_FLAGS.C_IS_PROD_INSTALLED
$
THEN
PROCEDURE LOAD_PROD_INIT_DATA(VV_CONTEXT_ID IN NUMBER);
$
END

END PACK_LOAD_INIT_DATA;
/

  

这样当用户没有选装这个product的时候,这个package实质上就是空的。 那么怎么查看package的经过preprocessor处理后的“真实面目“呢,可以通过调 用DBMS_PREPROCESSOR.PRINT_POST_PROCESSED_SOURCE。。。

set serveroutput on size unlimited
begin
DBMS_PREPROCESSOR.PRINT_POST_PROCESSED_SOURCE(
'PACKAGE', user, 'PACK_LOAD_INIT_DATA');
end;


类似的Trigger也可以这么做,但是View就不可以了,需要想其他的方法,可以将View的DDL语句放到一个存储过程中来创建,在安装的时候来调用这个存储过程,当然如果没有选择安装某个产品,可能这个procedure是”不可见“的, 这个view也是不应该创建的,那么很显然需要动态去调用存储过程....


BEGIN
EXECUTE IMMEDIATE 'begin PACK_UTIL.CREATE_SOME_VIEW; end;';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -6550 -- create_some_view is not declared when some product is not installed
THEN NULL;
END IF;
END;
/

 
 

 

  

posted @ 2011-09-02 15:27  FangwenYu  阅读(409)  评论(0编辑  收藏  举报