Oracle:立即执行和 ORA-01086 中的保存点

Posted

技术标签:

【中文标题】Oracle:立即执行和 ORA-01086 中的保存点【英文标题】:Oracle: Savepoints within execute immediate and ORA-01086 【发布时间】:2018-04-26 07:58:05 【问题描述】:

有人知道,为什么我在以下代码中得到一个ORA-01086: savepoint 'SPX' never established in this session or is invalid

begin 
    rollback; --clear all Transactions
    execute immediate 'begin
                           savepoint SPX;
                           raise no_data_found;  
                       end;';
exception when no_data_found then 
    rollback to savepoint SPX;
end;

如果我不使用立即执行,它就可以工作:

begin 
    rollback; --clear all Transactions
    begin
        savepoint SPX;
        raise no_data_found;  
    end;
exception when no_data_found then 
    rollback to savepoint SPX;
end;

这是预期的行为还是类似于错误?

我正在使用Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production

更新: 以下示例也可以使用,它使用动态 SQL 与 Savepoints 相结合:

begin 
    rollback; --clear all Transactions
    execute immediate 'begin
                           savepoint SPX;
                       end;';
    rollback to savepoint SPX;
end;

【问题讨论】:

【参考方案1】:

问题是在异常传播到外部块之前,会发生隐式 ROLLBACK,这会删除块创建的保存点。

这是一个重现问题但使用静态 SQL 的示例:

begin 
    rollback; --clear all Transactions
    savepoint SPX;
    rollback;
    raise no_data_found;
exception when no_data_found then 
    rollback to savepoint SPX;
end;

ORA-01086: savepoint 'SPX' never established in this session or is invalid ORA-06512: at line 7

不幸的是,您被这种行为所困扰;动态 SQL 必须在其自己的上下文中运行,如果它引发异常(并且不处理它),则会发出 ROLLBACK。

您需要在运行动态 SQL 之前创建保存点;或者,您可以抑制 ORA-01086 错误:

begin 
    rollback; --clear all Transactions
    execute immediate 'begin
                           savepoint SPX;
                           raise no_data_found;  
                       end;';
exception when no_data_found then 
  begin
    rollback to savepoint SPX;
  exception when others then
    if sqlcode != -1086 /*savepoint never established*/ then
      raise;
    end if;
  end;
end;

【讨论】:

【参考方案2】:

在Oracle Doc on the SAVEPOINT statement 中说:

SQL SAVEPOINT 语句可以作为静态 SQL 嵌入到 PL/SQL 中。

所以我认为这可以被认为是一种预期的行为。

【讨论】:

我用一个使用动态 SQL 和保存点的示例更新了我的问题,没有例外。 好主意!似乎在您的第一个示例中,除了引发 EXECUTE 作为一个块失败,破坏了保存点。 SAVEPOINT 在 PL/SQL 中有效这一事实与这个问题无关。 @JeffreyKemp:这里的关键字是 STATIC。最初的问题是静态 SQL 和动态 SQL 之间是否存在差异。

以上是关于Oracle:立即执行和 ORA-01086 中的保存点的主要内容,如果未能解决你的问题,请参考以下文章

对于具有 NULL 值的循环变量

在 Oracle 过程中立即执行

执行立即变量中的单引号 - Oracle PLSQL

CLOB 中的 Oracle 包,长度 > 32767 个字符。如何“立即执行”呢? [关闭]

Oracle 立即执行 DDL 和嵌套表

Oracle SQL:在立即执行的内部循环中使用外部循环标识符