Я считаю, что, возможно, обнаружил производственную ошибку, которая вызывает периодические проблемы. По сути, я пытаюсь понять, что делает AS400 при работе со встроенным SQL и курсорами. Я думаю, что в некоторых случаях курсор не закрывается, что приводит к сбою в следующем случае, поскольку курсор все еще открыт.
Вот снимок кода:
begsr checkfile;
exec sql
declare T1 cursor for
select * from FILE1
where field1 = :var1;
exec sql
open T1;
exec sql
fetch next from T1 into :vrDS;
dow SQLCOD = *zeros;
if a=b;
eval found = 'Y';
leavesr;
endif;
enddo;
exec sql
close T1;
endsr;
Меня беспокоит очередь листьев. Если условие выполнено, он выходит из подпрограммы, которая пропускает закрытие курсора T1. В журнале заданий есть информационные сообщения типа «Курсор T1 уже открыт или назначен». Я полагаю, это означает, что он ничего не сделал или, может быть, даже был получен из предыдущего курсора? Мне также интересно, выполняется ли оператор declare каждый раз или он просто пропускает эту часть кода после его первого выполнения. Я думаю, что мне нужно поместить оператор close T1 перед оператором open, но я хотел получить второе мнение, поскольку это производственная проблема, которую практически невозможно воссоздать из-за различий в ключах безопасности между тестированием и производством.
Спасибо!
@ danny117, если у вас есть лучший ответ, который может научить нового пользователя эффективному использованию курсоров, поделитесь им, иначе ваши комментарии бесполезны.
@jmarkmurphy ошибка - это leavesr. это как goto в розовом платье, используйте с осторожностью. Смотрите, что курсор не закрыт. В следующий раз, когда код запускается, курсор все еще открыт, он завершится ошибкой. На это можно было ответить комментарием.
@ danny117 Да, это очевидно для любого случайного наблюдателя, Чарльз осветил это в своем ответе, где он сказал, что «курсор будет оставлен открытым», я расширил ответ Чарльза. Видите часть, где прямо впереди написано «Что сказал Чарльз»? У вас есть проблемы с предоставлением лучшего способа?
@ danny117 на самом деле вопрос был (перефразирован) "У меня проблемы с логикой обработки этого курсора, похоже, что leavesr заставляет его оставаться открытым, но не совсем уверен, как с этим справиться". Комментарий, в котором говорится, что «проблема в листьях», на самом деле не отвечает на вопрос, он просто подтверждает опасения OP.


DECLARE CURSOR на самом деле является оператором времени компиляции.
Он никогда не выполняется во время выполнения.
:var1 передается в базу данных, когда OPEN завершается во время выполнения. Вот ответ с подробным примером Использование курсора для нескольких условий поиска
Да, как показано на рисунке, курсор останется открытым. И, возможно, читать, а не открывать новый курсор во время следующего запуска. Зависит от того, какой параметр CLOSQLCUR установлен во время компиляции (или установлен с помощью EXEC SQL SET OPTION)
Вы должны проверять SQLSTATE / SQLCODE после OPEN и FETCH
Другой распространенной практикой является выполнение CLOSE перед OPEN, снова обязательно проверьте SQLSTATE / SQLCODE и проигнорируйте CURSOR NOT OPEN при закрытии.
Спасибо, после дальнейшего обзора я думаю, что вместо листа мне просто нужно сделать отпуск, чтобы он завершил группу do вместо подпрограммы, гарантируя, что курсор каждый раз закрывается. Спасибо за информацию. Намного понятнее, как сейчас работает AS400 в этом отношении. :)
Что сказал Чарльз, и я также считаю, что в некоторых случаях вы можете даже создать бесконечный цикл с помощью этого кода! Возможно, вы не даете весь код, но если выборка прошла успешно (SQLCOD = 0) и a <> b, то вы застряли в цикле.
Мне нравится помещать выборку в подпроцедуру, которая возвращает * On, если запись успешно прочитана. Тогда вы можете сделать что-то вроде этого:
dcl-proc MyProc;
dcl-pi *n;
... parameters ...
end-pi;
C1_OpenCursor(parameters);
dow C1_FetchCursor(record);
... do something with the record ...
enddo;
C1_CloseCursor();
end-proc;
// ------------------------
// SQL Open the cursor
dcl-proc C1_OpenCursor;
dcl-pi *n;
... parameters ...
end-pi;
exec sql
declare C1 cursor for ...
exec sql
open C1;
if SQLCOD < 0;
.. error processing ...
endif;
end-proc;
// ------------------------
// SQL Read the cursor
dcl-proc C1_FetchCursor;
dcl-pi *n Ind;
... parameters ...
end-pi;
exec sql
fetch C1 into ...
if SQLCOD = 100;
return *Off;
elseif SQLCOD < 0;
... error handling ...
return *Off;
endif;
return *On;
end-proc;
// ------------------------
// SQL Close the cursor
dcl-proc C1_CloseCursor;
exec sql close C1;
end-proc;
Это позволяет вам хранить весь код базы данных в одном месте и просто вызывать его из своей программы. Процедуры базы данных просто обращаются к базе данных и каким-то образом сообщают об ошибках. Логика вашей программы может оставаться незагроможденной иногда многословной базой данных и кодом обработки ошибок.
Еще одна вещь: я не проверяю ошибки при закрытии курсора, потому что единственная ошибка (кроме синтаксических ошибок), которая может быть возвращена здесь, - это то, что курсор не открыт. Меня это не волнует, потому что я все равно этого хочу.
Привет, jmark, спасибо за ответ! Да вы правы. Я просто вставил эту строку в качестве примера. Фактический код имеет проверки, чтобы он не застревал в цикле. Однако мне нравится подпроцедура, о которой вы упомянули. Я обязательно попробую это сделать в следующем девелоперском проекте!
листья перед закрытием. Выполнено.
плохой код плохие ответы. листья перед закрытием. И у нас есть ответ, который этого не признает.