Как правильно проверить состояние sql в ILE RPG?

При работе со встроенным SQL в RPG вы часто сталкиваетесь с курсором и циклом dow для обработки всех строк в вашем результате. Условие в цикле каким-то образом зависит от SQLCOD и/или SQLSTT, каких-то глобально доступных переменных в SQLRPGLE-программе?

Но как правильно проверить эти значения? Некоторые предлагают SQLCOD = 0 другие not (SQLCOD = +100 or SQLSTT = '02000'). Один не работает со всеми предупреждениями, другой не дает сбоев при некоторых ошибках, поэтому я не доволен.

Чтобы проиллюстрировать, что я делаю с некоторым кодом:

Pmain             B
D                 PI
Dmy_ds          E DS                  extname(SOME_TABLE)
D                                     qualified
 /free
  exec sql
    DECLARE cur CURSOR FOR
      SELECT *
      FROM some_table;
  exec sql 
    OPEN cur;
  exec sql
    FETCH cur
     INTO :my_ds;
  dow sql_found();
      exec sql
        FETCH cur
         INTO :my_ds;
  enddo;
  exec sql
    CLOSE cur;
 /end-free
Pmain             E


Psql_found        B
D                 PI              N
 /free
  // insert return statement here...
 /end-free
Psql_found        E

Я ищу здесь правильный оператор возврата, который заставит меня просмотреть все строки, если не произойдет ошибки, и позволит мне уйти, когда произойдет ошибка. Бонусные баллы за достойный способ проверки на наличие ошибок.


person kratenko    schedule 13.03.2013    source источник


Ответы (3)


SQLSTATE лучше и рекомендуется IBM.

Из IBM InfoCenter Справочник по SQL-сообщениям и кодам : понятия SQLCODE и SQLSTATE

SQLSTATE является предпочтительным стандартным кодом возврата.

SQLSTATE состоит из 5 символов, причем первые два байта идентифицируют класс условий.

  • '00' = неквалифицированное успешное завершение
  • '01' = Предупреждение
  • '02' = нет данных

Все остальное - ошибка. Обычно я проверяю только «00».

Простой. Легкий. Более портативный.

Использование SQLCODE часто включает в себя списки кодов, которые, ИМХО, менее удобны для разработчиков.

Пример:

Лично я обычно включаю такие определения и код:

 D xSQLState@      s               *   inz( %addr(SQLState) )
 D xSQLState       ds             5    based(xSQLState@)
 D  xSQLState2                    2a
 D   
 D Success_On_SQL  C                   const('00')
 D Warning_On_SQL  C                   const('01')
 D NoData_On_SQL   C                   const('02')

Затем после любой операции SQL я обычно проверяю

   if xSQLState2 <> Success_On_Sql;
     someflag = true;
   endif;
person WarrenT    schedule 13.03.2013
comment
Небольшое примечание... не совсем верно, что Anything else является ошибкой для классов SQLSTATE. Только классы, зарезервированные для DB2 (и определенные как ошибки), обязательно являются ошибками. Например, сигнализация «K1001» будет ошибкой только в том случае, если приложение обработает ее как ошибку. - person user2338816; 16.04.2014

Лучшей практикой является обработка ожидаемых SQLCODE (как часть ожидаемой обработки) и добавление кода исключения для обработки тех, которые вам не нужны. Одна реализация:

  dow 1=1;  // forever
      exec sql
        FETCH cur
         INTO :my_ds;
  // normal exit         
  if sqlstt = SQL_NODATA;
    SFLEND = *on;        
    leave;               
  endif;                 

  // can't CAST a value
  if sqlstt = SQL_CAST;         // CAST error                               
    ... tell user there's an error and read another
    iter;                                                                  
  endif;                                                                   

  // decimal data error
  if sqlstt = SQL_DDE;
    tell user to call IT and stop reading
    leave;                                      
  endif;                                        


  // whoops! not expected at all.  Dump for post-mortem
  if sqlstt <> SQL_NORMAL;                             
    ... tell user to call IT and stop reading
    dump(a);                             
    leave;                                              
  endif;                                               

  // test for end of loop
  // filled subfile page?
  enddo;  // forever

С этим типом реализации вы должны намеренно выйти из цикла; независимо от того, заполнили ли вы страницу подфайла, загрузили самый высокий элемент в массиве или столкнулись с ошибкой. Я не уверен, что существует единая общая реализация, которая будет обрабатывать все обстоятельства. Иногда вы можете захотеть выйти из цикла чтения, если у вас есть блокировка записи, а иногда вы хотите выдать сообщение и повторить попытку (например).

person Buck Calabro    schedule 13.03.2013
comment
Имена, начинающиеся с SQL, зарезервированы прекомпилятором. См. Имена в приложениях ILE RPG, которые использовать SQL - person WarrenT; 14.03.2013

Я провел еще несколько поисков по этой теме и нашел что-то на сайте IBM (цитата):

The SQLCODE is also set by the database manager after each SQL 
statement is executed as follows: 
  - If SQLCODE = 0 and SQLWARN0 is blank, execution was successful.
  - If SQLCODE = 100, no data was found. For example, a FETCH 
    statement returned no data, because the cursor was positioned 
    after the last row of the result table.
  - If SQLCODE > 0 and not = 100, execution was successful with a 
    warning.
  - If SQLCODE = 0 and SQLWARN0 = 'W', execution was successful 
    with a warning.
  - If SQLCODE < 0, execution was not successful.

Что привело бы меня к такому sql_found():

Pfound_sql        B
D                 PI              N
 /free
  return (SQLCOD >= 0) and (SQLCOD<>100);
 /end-free
Pfound_sql        E

Это должно позаботиться об условии End of Data и завершиться ошибкой при всех ошибках. Я не уверен, есть ли какие-то предупреждения, о которых я должен позаботиться (не хочу попасть в бесконечный цикл, если есть предупреждение, которое приводит к отказу от чтения).

person kratenko    schedule 13.03.2013
comment
1) Я бы не советовал использовать глобальные переменные (например, SQLCOD) в подпроцедуре. Что происходит, когда вам нужно вложить цикл FETCH в другой? Когда внутренний цикл достигает EOF, он также непреднамеренно отключит выход во внешнем цикле. Передайте SQLCOD в качестве параметра, и эта проблема исчезнет. - person Buck Calabro; 13.03.2013
comment
2) Проглатывание ошибок (типа SQLCOD‹›100) нецелесообразно. Что произойдет, если это ошибка CAST и вы потеряете данные? - person Buck Calabro; 13.03.2013
comment
Возможным преимуществом определения процедуры для этой цели является то, что можно было бы также включить общую логику для обработки непредвиденных ошибок, таких как CAST, если вы не предоставили конкретную логику для их обработки в противном случае. А? - person WarrenT; 15.03.2013