impdp导入dump报ORA-39083与ORA-04079无效触发器规范错误
问题根因
- 核心原因是ODP.NET和System.Data.OracleClient在执行多行字符串格式的DDL时,会自动将语句中的Windows风格换行符(CR+LF)替换为单个空格,或者直接丢弃换行符,导致触发器定义存储到Oracle数据字典
ALL_SOURCE/DBA_SOURCE时,WHEN (OLD.VERREKENINGFACTUURREGELID IS NOT NULL)和后面的DECLARE关键字之间没有换行分隔,变成了连续的字符串。 - Oracle 11g的数据泵导出逻辑在解析触发器源码时,无法识别无换行分隔的WHEN子句和触发体声明部分,会错误地截断触发器定义,把DECLARE及之后的变量声明部分直接丢弃,导致导入时执行的SQL只有WHEN子句加执行逻辑,缺少DECLARE声明块,触发ORA-04079无效触发器定义错误。
- 而DBForge这类数据库客户端提交DDL时会保留原始换行符,所以数据泵能正常解析导出的触发器定义。
解决方案
方案1:修改C#中触发器SQL的换行处理
在C#的SQL字符串中,明确在WHEN子句后拼接Unix风格换行符(LF),避免ODP.NET吞掉换行导致源码格式错误:
// 手动强制保留WHEN子句和DECLARE之间的换行 private const string SQL = @"CREATE OR REPLACE TRIGGER T_FIN_BETALING_DELETE BEFORE DELETE ON FIN_BETALING FOR EACH ROW WHEN (OLD.VERREKENINGFACTUURREGELID IS NOT NULL) " + "\n" + @"DECLARE V_AFREKENINGID NUMBER; V_BOVK VARCHAR2(50 CHAR); V_MSG VARCHAR2(255 CHAR); BEGIN SELECT A.PRG_AFREKENINGID, C.CONTRACTNRSTR INTO V_AFREKENINGID, V_BOVK FROM FIN_FACTUURREGEL FR JOIN FIN_FACTUUR F on FR.FIN_FACTUURID = F.FIN_FACTUURID JOIN PRG_CONTRACT C ON C.PRG_CONTRACTID = F.PRG_CONTRACTID JOIN PRG_AFREKENING A on F.BEHFACTAFREKENINGID = A.PRG_AFREKENINGID WHERE FR.FIN_FACTUURREGELID = :OLD.VERREKENINGFACTUURREGELID; V_MSG := 'De betaling-id ' || TO_CHAR(:OLD.FIN_BETALINGID) || ' is reeds doorgestort en kan derhalve niet verwijderd worden'; IF V_AFREKENINGID IS NOT NULL THEN V_MSG := V_MSG || ' (afrekening-id ' || TO_CHAR(V_AFREKENINGID) || ', beheerovereenkomst ' || V_BOVK || ')'; END IF; RAISE_APPLICATION_ERROR(-20500, V_MSG); END;";
方案2:导入时跳过触发器,导入完成后手动重建
如果已经有导出的dump文件,可以在导入时添加参数EXCLUDE=TRIGGER,导入完所有对象后,手动执行正确的触发器创建语句即可:
# 导入命令示例 impdp VBSDB2/********@XE directory=VBS dumpFILE=20211027_164212_$VBSDB.DPDMP logfile=imp.log schemas=VBSDB remap_schema=VBSDB:VBSDB2 transform=oid:n EXCLUDE=TRIGGER
方案3:升级数据库或ODP.NET版本
该问题是Oracle 11g XE的已知bug,在12c及以上数据库版本中已经修复。如果业务允许,升级数据库版本或者将ODP.NET升级到19c及以上版本,也可以避免该问题。
验证方法
触发器创建完成后,可以执行以下SQL检查数据字典中存储的触发器源码是否有正确换行:
SELECT TEXT FROM ALL_SOURCE WHERE NAME = 'T_FIN_BETALING_DELETE' AND TYPE = 'TRIGGER' ORDER BY LINE;
如果查询结果中WHEN子句行之后的下一行是DECLARE,说明换行符正确保留,导出导入就不会有问题。
内容的提问来源于stack exchange,提问作者J. Ouwehand
相关产品推荐
相关产品推荐

