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