无需查询即可检索 Oracle 数据库名称

Retrieve Oracle database name without querying

我有两个 Oracle 11gR2 数据库(一个用于测试,另一个用于生产)。

通过使用条件编译,我需要创建一个函数,该函数将在测试环境中使用数据库 link,而在生产环境中将 使用数据库 link。

问题是我需要把它放到包体中,它会在两种环境中自动编译。生产环境中不会有这样的数据库link,因此包不会编译

一个解决方案是创建一个虚拟数据库 link,它在生产环境中自行解析(生产 -> 生产),但这肯定不是解决此问题的正确方法。

例如:

DECLARE 
    v_db_name     VARCHAR2(200);
    vt_tbl_data   data_table%ROWTYPE;
BEGIN
    $IF v_db_name = 'TEST' $THEN 
        SELECT tbl.*
          INTO vt_tbl_data
          FROM data_table@otherdb tbl
         WHERE ROWNUM = 1;
    $ELSIF v_db_name = 'PROD' $THEN
        SELECT tbl.*
          INTO vt_tbl_data
          FROM data_table tbl
         WHERE ROWNUM = 1;
    $END
END;
/

包体中没有数据库 link 语法。在两种环境中创建一个同义词,并在您的包主体中引用该同义词。

这样你的包体在两种环境中都是一样的 - 只是同义词的定义不同。

如果您可以更改编译会话 - 在一个或两个环境中 - 您可以使用 a compilation flag via PLSQL_CCFLAGS:

alter session set PLSQL_CCFLAGS = 'has_db_link:TRUE';

DECLARE 
    vt_tbl_data   data_table%ROWTYPE;
BEGIN
    $IF $$has_db_link $THEN 
        SELECT tbl.*
          INTO vt_tbl_data
          FROM data_table@otherdb tbl
         WHERE ROWNUM = 1;
    $ELSE
        SELECT tbl.*
          INTO vt_tbl_data
          FROM data_table tbl
         WHERE ROWNUM = 1;
    $END
END;
/

或重复较少,但可能更难理解:

DECLARE 
    vt_tbl_data   data_table%ROWTYPE;
BEGIN
    SELECT tbl.*
      INTO vt_tbl_data
    $IF $$has_db_link $THEN 
      FROM data_table@otherdb tbl
    $ELSE
      FROM data_table tbl
    $END
     WHERE ROWNUM = 1;
END;
/

如果您将标志设置为 FALSE,或者根本不设置,在生产中它只会编译 $ELSE 分支。

不能将标志设置为字符串,因此不能测试特定名称;但是 true/false 对我来说似乎更直观。

如果您不能改变编译的方式来改变会话,您可以通过登录触发器来实现——在这种情况下可能只在测试环境中,并且可能使用更通用的标志名称像@krokodilko建议的env_test