【问题标题】:Error (ORA-21700) with Table Operator after updating to Oracle 12.2 from 12.1 [duplicate]从 12.1 更新到 Oracle 12.2 后,表运算符出现错误 (ORA-21700) [重复]
【发布时间】:2018-11-22 02:14:30
【问题描述】:

我们的 Oracle 数据库最近从 12.1.0.2 更新到 12.2.0.1 + 补丁集更新 20180417。

自从更新以来,我们在调用 plsql 过程时收到以下错误: ORA-21700: 对象不存在或被标记为删除

我们已经缩小了这个问题的范围,它似乎是由在包中定义的关联数组上使用 table 运算符 引起的。我所有的研究表明,我们正在做的事情是在 12.1 中引入的,并且应该在 12.2 中仍然有效。

以下是失败的过程的简化版本以及相关的类型定义。它是使用托管数据访问从 c# 代码调用的。

这里是包中的关联数组类型定义:

TYPE NUMBER_ARRAY IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;

这是一个失败的过程:

PROCEDURE GetReadingStatus(
  STATUSID_ARR IN NUMBER_ARRAY,
  P_RETURNS OUT SYS_REFCURSOR    
)
BEGIN
  OPEN P_RETURNS FOR
    SELECT * FROM READINGSTATUS rs
    WHERE rs.statusID IN (select * from table(STATUSID_ARR));
END;

如果select * from table(STATUSID_ARR) 部分被删除,它就会运行。

在 12.2 中对关联数组使用表运算符有问题吗?问题可能源于其他原因吗?

【问题讨论】:

  • 你使用的是定义者权限还是调用者权限?没关系,但是,你永远不会知道......另外,做一个show parameter compatible,看看它是否以某种方式设置为
  • 在 12.2 中为我工作。如果您发布端到端演示,可能会出现一些差异。
  • @MarkStewart 我检查了兼容性并将其设置为 12.1,所以这似乎不是问题。我相信它正在使用定义者的权利。我的理解是,如果它明确告诉它,它只会在 plsql 中使用调用者权限(如果我错了,请纠正我)。
  • 使用以下查询检查任何奇怪、无效或丢弃的类型:select * from dba_types where type_name like 'SYS%';select * from dba_objects where status <> 'VALID';select * from dba_recyclebin;。 Oracle 有时会创建系统生成的类型来支持表运算符之类的东西。但是在以后的版本中,它有时不再需要它们了。也许其中一种类型在不需要时被转换了,这让 Oracle 感到困惑?
  • 由于您可以应用补丁集,因此您似乎拥有 Oracle 支持合同。所以我建议你在 MOS 上提出这个问题,因为它看起来更像是一个错误,而不是我们可以提供的任何帮助。

标签: sql oracle plsql oracle12c oracle-manageddataaccess


【解决方案1】:

从 Oracle 12c 升级到 19c 后,我遇到了相同或类似的问题。我不确定为什么 Oracle 升级会导致问题,而且我也不太明白为什么我的修复有效!

在我的存储过程中,Oracle 的 TABLE 函数应用于某些存储过程输入,我收到错误:“ORA-21700:对象不存在或被标记为删除”。

但是,如果将 Oracle 的 TABLE 函数应用于存储过程中的局部变量,则没有错误。所以我的解决方法是在使用 TABLE 函数之前简单地将存储过程输入分配给局部变量,并且以某种方式解决了这个问题!

CREATE OR REPLACE PACKAGE my_types IS
  TYPE integers IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
  TYPE reals    IS TABLE OF FLOAT INDEX BY BINARY_INTEGER;
END my_types;
/

CREATE OR REPLACE PROCEDURE order_list
(
  i_order_numbers  IN  my_types.integers,
  o_order_numbers  OUT my_types.integers,
  o_order_values   OUT my_types.reals
)
IS

  r_order_numbers  my_types.integers;

  CURSOR order_list_cur (p_order_numbers my_types.integers)
      IS
  SELECT order_number, order_value
    FROM orders
   WHERE order_number IN (SELECT * FROM TABLE(p_order_numbers))
  ;
  order_list_rec  order_list_cur%ROWTYPE;

  rec_no BINARY_INTEGER;

BEGIN

  r_order_numbers := i_order_numbers;

  rec_no := 0;

  OPEN order_list_cur(r_order_numbers);
  LOOP
    FETCH order_list_cur INTO order_list_rec;
    EXIT WHEN order_list_cur%NOTFOUND;
      rec_no := rec_no + 1;
       o_order_numbers(rec_no) := order_list_rec.order_number;
       o_order_values(rec_no) := order_list_rec.order_value;
  END LOOP;
  CLOSE order_list_cur;

END order_list;

【讨论】:

    【解决方案2】:

    我的所有研究表明,我们正在做的事情是在 12.1 中引入的 并且应该在 12.2 中仍然可以工作。

    是的这是真的。在Oracle 12c 之前,您不能在PLSQL 块内的SQL 语句范围内使用关联数组。但是,Oracle 确保在引入新版本时,旧版本不会受到影响。我试图测试你的代码,并在我的最后工作正常。看起来问题在其他地方,在使用 C# 时可能是一些问题。请看下面的演示:

    我的 Oracle 版本:

    SQL> select * from v$version;
    
    BANNER
    ------     
    Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
    

    表格数据:

    SQL>SELECT * from TEST;
      col
      ---
       1
       2
       3
    

    包装:

    --Package Specification
    CREATE OR REPLACE PACKAGE TESTTT
    AS
    TYPE NUMBER_ARRAY IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
    
    Procedure GetReadingStatus (
                              STATUSID_ARR IN NUMBER_ARRAY,
                              P_RETURNS OUT SYS_REFCURSOR    
                            );
    END;
    /
    --Package Body
    CREATE OR REPLACE PACKAGE BODY TESTTT
    AS
    PROCEDURE GetReadingStatus(
                              STATUSID_ARR IN NUMBER_ARRAY,
                              P_RETURNS OUT SYS_REFCURSOR    
                            )
    Is                        
    BEGIN
      OPEN P_RETURNS FOR
        SELECT * 
        FROM TEST 
        where col IN (SELECT * FROM TABLE(STATUSID_ARR));
    END;
    END TESTTT;
    

    调用:

    DECLARE
    var  TESTTT.NUMBER_ARRAY;
    v_out sys_refcursor;
    num  NUMBER;
    
    BEGIN
    
    var(1):= '1';
    var(2):= '2';
    
     TESTTT.GetReadingStatus(STATUSID_ARR=>var,
                             P_RETURNS =>v_out);
    
     Loop
     fetch v_out INTO num;
     exit WHEN v_out%notfound;
     dbms_output.put_line('Return From Procdure--'||num);
     end loop;
    
    end;
    

    输出:

    Return From Procdure--1
    Return From Procdure--2
    

    【讨论】:

    • 是的,问题似乎只在从 C# 代码调用该过程时出现,该代码在 Oracle 版本更新之前工作。奇怪的是,如果不在 C# 的 plsql 关联数组上使用 TABLE 运算符,它就可以正常工作。 (我们有同时使用 ManagedDataAccess 和 ODAC 的应用程序都有相同的问题)
    【解决方案3】:

    这个问题很像我在 12.2 但不是 12.1 时遇到相同错误时的情况。我已经发布了我的答案here,因为该答案使用的是包而不是模式定义的类型。也许这个问题可以用同样的方式解决。只需尝试添加一个相同类型的临时变量并将参数分配给它。

    【讨论】:

      猜你喜欢
      • 2018-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多