使用 WITH HOLD 关键字创建保持游标

使用 WITH HOLD 关键字创建 hold 游标。Hold 游标允许跨多个事务对行的集合进行不中断的访问。

通常,所有的游标在事务结束时关闭。Hold 游标不会关闭;它在事务结束之后仍保持打开状态。

Hold 游标可以是一个顺序游标或(在 ESQL/C 中)滚动游标。

在 SPL 例程中 WITH HOLD 关键字只对 Select 游标有效。有关 DECLARE 语句在 SPL 例程中的语法,请参阅 在 SPL 例程中声明动态游标

在 ESQL/C 中,可以使用 WITH HOLD 关键字声明 Select 和函数游标(具有顺序和滚动属性)也可以声明 Insert 游标。这些关键字在 DECLARE 语句中跟在 CURSOR 关键字之后。以下示例为 SELECT 创建了一个顺序 Hold 游标:
DECLARE hld_cur CURSOR WITH HOLD FOR
        SELECT customer_num, lname, city FROM customer;

您可以如下面的 GBase 8s ESQL/C 代码示例所示使用选择保持游标。此代码段使用一个 Hold 游标作为主游标来扫描一个记录集合,使用一个顺序游标作为细节游标俩指向位于不同表中的记录。主游标扫描的记录是更新细节游标指向的记录的基础。在第一个 WHILE 循环的每个迭代的结束处的 COMMIT WORK 语句将 Hold 游标 c_master 保留为打开状态,但关闭顺序游标 c_detail 并释放所有锁。这种技术最小化了数据库服务器必须分配给锁和未完成的事务的资源,并且它使其它用户能够立即访问更新的行。

EXEC SQL BEGIN DECLARE SECTION;
      int p_custnum, int save_status; long p_orddate;
      EXEC SQL END DECLARE SECTION;
      
      EXEC SQL prepare st_1 from
      'select order_date from orders where customer_num = ? for update';
      EXEC SQL declare c_detail cursor for st_1;
      EXEC SQL declare c_master cursor with hold for
      select customer_num from customer where city = 'Pittsburgh';
      
      EXEC SQL open c_master;
      if(SQLCODE==0) /* the open worked */
      EXEC SQL fetch c_master into :p_custnum; /* discover first customer */
      while(SQLCODE==0) /* while no errors and not end of pittsburgh customers */
      {
      EXEC SQL begin work; /* start transaction for customer p_custnum */
      EXEC SQL open c_detail using :p_custnum;
      if(SQLCODE==0) /* detail open succeeded */
      EXEC SQL fetch c_detail into :p_orddate; /* get first order */
      while(SQLCODE==0) /* while no errors and not end of orders */
      {
      EXEC SQL update orders set order_date = '08/15/94'
      where current of c_detail;
      if(status==0) /* update was ok */
      EXEC SQL fetch c_detail into :p_orddate; /* next order */
      }
      if(SQLCODE==SQLNOTFOUND) /* correctly updated all found orders */
      EXEC SQL commit work; /* make updates permanent, set status */
      else /* some failure in an update */
      {
      save_status = SQLCODE; /* save error for loop control */
      EXEC SQL rollback work;
      SQLCODE = save_status; /* force loop to end */
      }
      if(SQLCODE==0) /* all updates, and the commit, worked ok */
      EXEC SQL fetch c_master into :p_custnum; /* next customer? */
      }
      EXEC SQL close c_master;

使用 CLOSE 语句显式地关闭 Hold 游标,或使用 CLOSE DATABASE 或 DISCONNECT 语句隐式地关闭 Hold 游标。CLOSE DATABASE 语句关闭所有游标。