6

因为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";
    }
}

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

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

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

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

4

2 回答 2

8

Oracle 保证每次调用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

但是,如果涉及 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

这里您感兴趣的实际错误是 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

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

要回答您的问题:

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

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

于 2013-09-11T07:48:34.540 回答
0

我解决了这个问题:

std::string checkOciErr( OCIError* errhp, sword status ){

    std::stringstream ss;
    text errbuf[10240];
    sb4  errcode;
    bool ret_code = true;// 


    switch (status) {
     case OCI_SUCCESS:
         ret_code = false;
         break;
     case OCI_SUCCESS_WITH_INFO:
         OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR);
         ss <<  " Error: OCI_SUCCESS_WITH_INFO; Info: " << errbuf << endl;
         ret_code = (errcode == 436 || errcode == 437 || errcode == 438 || errcode == 439);
         break;
     case OCI_NEED_DATA:
         ss <<  " Error: OCI_NEED_DATA"<< endl;
         break;
     case OCI_NO_DATA:
         ss <<  " Error: OCI_NO_DATA"<< endl;
         break;
     case OCI_ERROR:{
            int rc_l = 0;
            int recordno = 1;
            ss <<  " Error: ";
            while (  rc_l !=OCI_NO_DATA){
                text errbuf1[10240];
                rc_l = OCIErrorGet ((dvoid *) errhp, (ub4) recordno, (text *) NULL, &errcode, errbuf1, (ub4) sizeof(errbuf1), (ub4) OCI_HTYPE_ERROR);
                ss << errbuf1 << endl;
                recordno++;
            }
        }
         break;
     case OCI_INVALID_HANDLE:
         ss <<  " Error: OCI_INVALID_HANDLE" << endl;
         break;
     case OCI_STILL_EXECUTING:
         ss <<  " Error: OCI_STILL_EXECUTE"<< endl;
         break;
     case OCI_CONTINUE:
         ss <<  " Error: OCI_CONTINUE" << endl;
         break;
     default:
         ss <<  " Error: UNKNOWN(" << status << ")" << endl;
         break;
    }

    return ss.str();

}

输出:

Error: ORA-20000: My Raise!!!
ORA-06512: at "OWNER.RAISEERROR", line 7
ORA-06512: at "OWNER.MYPACKAGE", line 214
ORA-06512: at line 1
于 2019-05-08T09:57:50.383 回答