zoukankan      html  css  js  c++  java
  • [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;
    /

     
     

      

  • 相关阅读:
    SQL Server中的执行引擎入门
    SQL Server复制入门(一)复制简介
    Django 代码片断收集(持续更新)
    今天思路有点乱,随便记一点关于 xmlrpc 的
    PIL 学习笔记(1)
    Django newforms
    在 Django 的 View 中利用 function decorator 可实现一定程度的代码重用
    今天在 Linux 上顺利编译 PIL 1.1.6 成功
    用 PIL 写了个简单的缩略图生成程序
    [转贴] 中药内外合治急慢性鼻窦炎
  • 原文地址:https://www.cnblogs.com/fangwenyu/p/2163826.html
Copyright © 2011-2022 走看看