OCIErrorGet и множественная обработка ошибок для ошибки OCI

на 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.

1 ответов


Oracle гарантирует, что будет возвращена только одна ошибка за вызов of 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() сначала возвращает самое последнее или самое раннее исключение; возможно, Вам понадобится бросить последние исключения.