OCIErrorGet和OCI_ERROR的多个错误处理

Dan*_*rey 6 c++ oracle oracle-call-interface

因为OCIErrorGet()它记录了它可能返回多个错误,我用它来提取以下方法OCI_SUCCESS_WITH_INFO,但目前不适用于OCI_ERROR:

void check_error( sword status )
{
    switch( status ) {
    case OCI_SUCCESS:
        break;

    case OCI_SUCCESS_WITH_INFO:
        {
           ub4 recordno = 1;
           while( status != OCI_NO_DATA ) {
              sb4 errcode = 0;
              text errbuf[ 1024 ];
              status = ::OCIErrorGet( m_err, recordno, (text*)NULL, &errcode, errbuf, sizeof( errbuf ), OCI_HTYPE_ERROR );
              if( status == OCI_SUCCESS ) {
                 std::cout << "oracle info: " << (const char*)errbuf << std::endl;
              }
              else {
                 assert( status == OCI_NO_DATA );
              }
              ++recordno;
           }
        }
        break;

    case OCI_ERROR:
        {
           sb4 errcode = 0;
           text errbuf[ 1024 ];
           // note here: no check of returned value from OCIErrorCode(), no loop!
           ::OCIErrorGet( m_err, 1, (text*)NULL, &errcode, errbuf, sizeof( errbuf ), OCI_HTYPE_ERROR );
           throw my_oracle_error( errcode, (const char*)errbuf );
        }
        break;
    default:
        throw "something else";
    }
}
Run Code Online (Sandbox Code Playgroud)

(当然真正的代码有点不同,但重要部分如上所示).

如果OCI_ERROR(在上面的代码中标有注释),我的问题是:

  • 我是否需要类似的循环或Oracle保证/文档,在这种情况下只能返回一个错误?
  • OCIErrorGet()在这种情况下,我是否需要检查返回的值?
  • 如果可以返回多个错误,errcode我应该将哪个错误用于我抛出的异常?

答案最好应链接到Oracle的文档.

Ben*_*Ben 7

甲骨文保证只有一个错误将被返回每次通话OCIErrorGet()(注意单数):

返回提供的缓冲区中的错误消息和Oracle数据库错误代码.
...
可以通过重复调用OCIErrorGet()来检索多个诊断记录,直到没有更多记录(返回OCI_NO_DATA).OCIErrorGet()最多返回一条诊断记录.

是否需要类似的循环或取决于您正在调用的(PL /)SQL代码.简单的SQL语句通常只返回一个错误代码; 例如:

SQL> select 1/0 from dual;
select 1/0 from dual
        *
ERROR at line 1:
ORA-01476: divisor is equal to zero
Run Code Online (Sandbox Code Playgroud)

但是,如果涉及PL/SQL,可能会返回更多:

SQL> begin
  2     raise_application_error(-20000, 'error');
  3  end;
  4  /
begin
*
ERROR at line 1:
ORA-20000: error
ORA-06512: at line 2
Run Code Online (Sandbox Code Playgroud)

这里你感兴趣的实际错误是ORA-20000.Oracle的异常传播从内部块到外部块工作,因此,假设您没有处理编译错误,则错误的原始原因将是第一个例外.如果你捕获并重新引发异常,则会发生变化.Oracle在文档中给出的示例是:

SQL> begin
  2    dbms_output.put_line(1/0);  -- handled
  3  exception when zero_divide then
  4    dbms_output.put_line(1/0 || ' is undefined');  -- not handled
  5  end;
  6  /
begin
*
ERROR at line 1:
ORA-01476: divisor is equal to zero
ORA-06512: at line 4
ORA-01476: divisor is equal to zero
Run Code Online (Sandbox Code Playgroud)

DBMS_OUTPUT.PUT_LINE是一个程序,因此出现两次同样的例外; 请注意,它仍然是您感兴趣的第一个例外.

回答你的问题:

不需要类似的循环; 如果您想获得多个错误代码,则只应使用一个.

如果返回多个错误,您应该抛出第一个错误代码,因为Oracle传播异常的方法; 这本质上是你需要做出的判断.从文档中不清楚是否首先OCIErrorGet()返回最新或最早的例外; 你可能需要抛出最后一个异常.