oracle 闪回关于触发器的bug

SQL> create table test1 (cola varchar2(10) );

表已创建。

 

SQL> create table test2 (colb varchar2(10));

表已创建。

 

SQL> select * from test1;

未选定行

 

SQL> select * from test2;

未选定行

 

SQL> create or replace trigger trigger1

  2    before insert on test1

  3    for each row

  4  declare

  5  begin

  6    insert into test2(colb) values('trigger1');

  7  end trigger1;

  8  /

触发器已创建

 

SQL> select object_name,object_id from user_objects where object_name in ('TRIGGER1','TEST1');

 

OBJECT_NAME                                                                     

--------------------------------------------------------------------------------

 OBJECT_ID                                                                     

----------                                                                      

TEST1                                                                          

    101621                                                                     

                                                                                

TRIGGER1                                                                       

    101623                                                                     

                                                                               

 

SQL> col object_name for a20

SQL> /

OBJECT_NAME           OBJECT_ID                                                

-------------------- ----------                                                

TEST1                    101621                                                 

TRIGGER1                 101623                                                 

 

SQL> insert into test1(cola) values('no1');

已创建 1 行。

SQL> commit;

提交完成。

 

SQL> select * from test1;

COLA                                                                            

--------------------                                                           

no1                                                                            

SQL> select * from test2;

COLB                                                                            

--------------------                                                           

trigger1                                                                       

--到这里,表现一切正常。下面开始删除恢复。

 

SQL> drop table test1;

表已删除。

 

SQL> select object_name,object_id from user_objects

  2  where object_name in ('TRIGGER1','TEST1');

未选定行

--如果没加purge选项,则两者都被删除到回收站,虽然user_object视图看不到,在底层表obj$中能看到。

 

 

SQL> flashback table TEST1 to before drop;

闪回完成。

 

SQL> select object_name,object_id from user_objects

  2  where object_name in ('TRIGGER1','TEST1');

OBJECT_NAME           OBJECT_ID                                                

-------------------- ----------                                                 

TEST1                    101621                                                

--闪回成功后,在视图中,正常对象只能看到表TEST1,不能看到触发器。

 

SQL> grant select on obj$ to ncoadev;

授权成功。

--切换到sys用户,授权访问指定对象。

 

SQL> select name,obj# from sys.obj$ where obj# in (101621,101623);

NAME                                                               OBJ#        

------------------------------------------------------------ ----------        

TEST1                                                            101621        

BIN$mlTKEo1FAGjgQ38AAAEAaA==$0                                   101623        

 

--obj$表中,能看到 ID101623的触发器还在,但名字被oracle打了内部标记。此时,用pl/sql dev等工具是看不到那个触发器的。

 

SQL> select * from test2;

COLB                                                                           

--------------------                                                            

trigger1   

                                                                   

SQL> insert into test1(cola) values('no2');

已创建 1 行。

SQL> commit;

提交完成。

 

SQL> select * from test2;

COLB                                                                            

--------------------                                                           

trigger1                                                                       

trigger1    

--又插入了一条记录,证明触发器还是生效的,但很难管理了。更麻烦的是后面:

 

SQL> create or replace trigger trigger1

  2    before insert on test1

  3    for each row

  4  declare

  5  begin

  6    insert into test2(colb) values('trigger2');

  7  end trigger1;

  8  /

触发器已创建

--如果开发人员看不到触发器了,认为触发器丢失,又建立了一个新的同名触发器trigger1,仍然能建立。

 

SQL> select * from test2;

COLB                                                                            

--------------------                                                           

trigger1                                                                       

trigger1                                                                        

SQL> insert into test1(cola) values('no3');

已创建 1 行。

SQL> commit;

提交完成。

 

SQL> select * from test2;

 

COLB                                                                           

--------------------                                                           

trigger1                                                                       

trigger1                                                                       

trigger2                                                                        

trigger1    

 

--此时,两个触发器都生效了,都作用在这个表上,会给系统带来什么影响呢??算不算oraclebug呢?                        

                                                                

<think>好的,我现在需要解决用户在使用Oracle的impdp工具时,触发器没有被正确remap_schema的问题。首先,我得先理解用户的问题。用户提到在使用impdp导入数据时,虽然使用了REMAP_SCHEMA参数,但触发器仍然没有被正确地映射到目标schema。这可能是什么原因呢? 根据已有的引用内容,特别是引用[1]和引用[3],我们知道REMAP_SCHEMA参数是用来将对象的属主从源schema转换到目标schema的。例如,把A用户的对象转移到B用户。但是,用户发现触发器没有被正确映射。这可能意味着impdp在处理触发器的时候,没有应用这个参数,或者触发器本身的定义中有硬编码的schema名称,导致即使属主改变了,定义里还是引用了原来的schema。 接下来,我需要考虑Oracle的impdp在处理不同对象类型时,REMAP_SCHEMA的行为是否一致。比如,表、视图、存储过程等可能都能正确映射,但触发器可能存在特殊情况。根据引用[5],用户提到可能需要解析生成的SQL文件或者动态更正CREATE语句,这说明impdp可能在生成触发器的DDL时,没有替换掉内部的schema名称。 可能的解决方案有几个方向:一是检查触发器定义中是否确实存在源schema的名称,比如在触发器的动作中引用了其他对象,而没有使用同义词或者不带schema的名称。二是使用其他impdp的参数或工具来替换这些硬编码的名称,比如使用SQLFILE参数生成DDL脚本,手动修改后再执行。三是使用Oracle提供的其他方法,比如数据泵的EXCLUDE和INCLUDE参数结合手动处理触发器。 另外,引用[3]提到数据泵支持通过REMAP_SCHEMA、REMAP_DATAFILE、REMAP_TABLESPACE等参数自动修改对象属性,但可能触发器的某些部分没有被这些参数覆盖。例如,触发器内部可能调用了其他属于源schema的存储过程,或者引用了表名时带上了schema,这时候REMAP_SCHEMA可能不会处理这些内部的引用。 因此,解决步骤可能包括: 1. 使用SQLFILE参数导出DDL,检查触发器的定义,确认是否有源schema的硬编码。 2. 如果存在硬编码,手动修改DDL脚本中的schema名称,然后单独执行这些脚本。 3. 在导入数据时,使用EXCLUDE参数排除触发器,导入后再手动创建修改后的触发器。 4. 或者,使用第三方工具或脚本在导入后批量替换触发器中的schema名称。 5. 另外,可能需要在导入前确保目标schema有正确的权限和同义词,避免触发器引用其他对象时出错。 同时,需要验证这些步骤的可行性。比如,使用SQLFILE导出DDL是否真的能捕获触发器的定义,手动修改是否会影响其他部分,以及如何确保在导入过程中不影响其他对象的正确映射。此外,用户可能需要了解Oracle的版本是否有相关bug,或者是否有官方补丁可以应用。 在回答时,还需要引用相关的引用内容,比如引用[1]和引用[3]提到的REMAP_SCHEMA功能,以及引用[5]中提到的可能需要手动处理或拦截DDL的方法。同时,要确保回答结构清晰,步骤明确,帮助用户逐步解决问题。</think>在Oracle中使用`impdp`进行数据泵导入时,若触发器(Triggers)未正确应用`REMAP_SCHEMA`参数,通常是由于触发器定义中硬编码了源Schema名称或Oracle的固有限制。以下是逐步解决方案: --- ### **问题原因分析** 1. **触发器定义硬编码** 触发器内部可能直接引用了源Schema名称(如`A.TABLE_NAME`),导致`REMAP_SCHEMA`仅修改对象属主,但未替换触发器代码中的Schema名称[^1][^3]。 2. **数据泵的限制** `impdp`的`REMAP_SCHEMA`参数主要作用于对象属主,但对PL/SQL代码中的硬编码Schema名称无法自动替换[^5]。 --- ### **解决方案** #### **方法1:导出DDL手动修改** 1. **生成DDL脚本** 使用`impdp`的`SQLFILE`参数导出元数据SQL脚本: ```bash impdp system/password DIRECTORY=dpump_dir DUMPFILE=source.dmp SQLFILE=triggers.sql REMAP_SCHEMA=A:B ``` 此命令会生成包含触发器定义的`triggers.sql`文件,但不会执行导入[^3]。 2. **手动替换Schema名称** 在`triggers.sql`中全局替换所有`A.`为`B.`: ```sql -- 示例修改前 CREATE TRIGGER A.trigger_name ... -- 修改后 CREATE TRIGGER B.trigger_name ... ``` 3. **重新执行DDL脚本** 在目标数据库中以用户`B`身份执行修改后的脚本: ```sql conn B/password @triggers.sql ``` --- #### **方法2:排除触发器后单独导入** 1. **导入时排除触发器** 使用`EXCLUDE`参数跳过触发器导入: ```bash impdp system/password DIRECTORY=dpump_dir DUMPFILE=source.dmp REMAP_SCHEMA=A:B EXCLUDE=TRIGGER ``` 2. **手动导出并导入触发器** 通过`DBMS_METADATA`获取触发器定义,替换Schema后重新创建: ```sql -- 导出触发器DDL SELECT DBMS_METADATA.GET_DDL('TRIGGER', 'TRIGGER_NAME', 'A') FROM DUAL; -- 修改并执行 CREATE TRIGGER B.trigger_name ... ``` --- #### **方法3:使用正则表达式动态替换** 若需自动化,可通过脚本处理DMP文件(需谨慎操作): ```bash # 示例:替换DMP文件中的Schema名称(仅适用于小型DMP) sed -i 's/A\./B\./g' source.dmp impdp system/password DIRECTORY=dpump_dir DUMPFILE=source.dmp ``` **警告**:直接修改DMP文件可能破坏二进制结构,建议先备份。 --- ### **验证与预防措施** 1. **检查触发器属主** 确认触发器属主已更新为`B`: ```sql SELECT OWNER, TRIGGER_NAME FROM ALL_TRIGGERS WHERE OWNER = 'B'; ``` 2. **避免硬编码Schema** 在开发阶段,使用同义词(Synonyms)或省略Schema名称(如`TABLE_NAME`代替`A.TABLE_NAME`)以提高可移植性。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值