AS400 嵌入式 SQL 游标处理

AS400 embedded SQL cursor handling

我相信我可能发现了一个导致间歇性问题的生产错误。基本上,我试图了解 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 的关闭。在作业日志中,有 "Cursor T1 already open or allocated." 等信息性消息。我认为这意味着它没有做任何事情,或者甚至可能从前一个游标中获取?我还想知道是否每次都执行 declare 语句,或者它是否只是在第一次执行后跳过那部分代码。我想我需要在 open 语句之前放置一个 close T1 语句,但我想获得第二意见,因为这是一个生产问题,由于测试和生产之间的安全密钥差异,几乎不可能重新创建。

谢谢!

a DECLARE CURSOR实际上是一个编译时语句。

从未在 运行 时执行。

OPEN 在 运行 时间完成时,

:var1 被传递给数据库。这是一个带有详细示例的答案 Using cursor for multiple search conditions

是的,如代码所示,光标将保持打开状态。并可能在下一个 运行 期间读取而不是打开一个新游标。取决于 CLOSQLCUR 选项在编译期间是什么(或使用 EXEC SQL SET OPTION 设置)

您应该在 OPENFETCH

之后检查 SQLSTATE/SQLCODE

另一种常见的做法是在 OPEN 之前做一个 CLOSE,再次确保检查 SQLSTATE/SQLCODE 并在收盘时忽略 CURSOR NOT OPEN

Charles 所说的,而且我相信您在某些情况下甚至可以用这段代码创建一个无限循环!也许您没有给出完整的代码,但如果获取成功 (SQLCOD = 0) 并且 a <> b,那么您将陷入循环。

我喜欢将提取放在子过程中,returns *如果成功读取记录则打开。然后你可以这样做:

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;

这让您可以将所有数据库代码保存在一个地方,只需从您的程序中调用它。数据库过程只是访问数据库并以某种方式报告错误。您的程序逻辑可以通过有时冗长的数据库和错误处理代码保持整洁。

另外一件事,我不检查游标关闭时的错误,因为这里可以返回的唯一错误(语法错误除外)是游标未打开。我不在乎那个,因为这就是我想要的。