스토어드 프로시저로부터 결과 세트를 수신하도록 프로그램 또는 SQL 프로시저 작성

내용을 알고 있는 고정된 개수의 결과 세트 또는 내용을 모르는 가변 개수의 결과 세트에 대해 스토어드 프로시저로부터 결과 세트를 수신하도록 프로그램을 작성할 수 있습니다.

알려진 개수의 결과 세트를 리턴하는 것은 작성하기 간단하지만, 가변 개수의 결과 세트를 처리하도록 코드를 작성하는 경우에는 스토어드 프로시저가 변경되더라도 프로그램의 주요 부분을 수정하지 않아도 됩니다.

결과 세트 수신 기본 단계는 다음과 같습니다.

  1. 리턴될 각 결과 세트에 대해 위치 지정자 변수를 선언하십시오.

    몇 개의 결과 세트가 리턴될지 모르는 경우, 리턴될 수 있는 최대 결과 세트 수에 대해 충분한 결과 세트 위치 지정자를 선언하십시오.

  2. 스토어드 프로시저를 호출하고 SQL 리턴 코드를 검사하십시오.

    CALL문의 SQLCODE가 +466인 경우, 스토어드 프로시저가 결과 세트를 리턴한 것입니다.

  3. 스토어드 프로시저가 리턴하는 결과 세트 수를 판별하십시오.

    스토어드 프로시저가 리턴하는 결과 세트 수를 이미 알고 있으면 이 단계를 건너뛸 수 있습니다.

    DESCRIBE PROCEDURE SQL문을 사용하여 결과 세트 수를 판별하십시오. DESCRIBE PROCEDURE는 SQLDA 또는 SQL 설명자에 결과 세트에 대한 정보를 배치합니다.

    SQL 설명자의 경우, DESCRIBE PROCEDURE문이 완료되면 다음 값을 검색할 수 있습니다.

    • DB2_RESULT_SETS_COUNT에는 스토어드 프로시저가 리턴하는 결과 세트 수가 포함됩니다.
    • 각 결과 세트에 대해 하나의 설명자 영역 항목이 리턴됩니다.
      • DB2_CURSOR_NAME에는 스토어드 프로시저가 결과 세트를 리턴하는 데 사용하는 커서명이 포함됩니다.
      • DB2_RESULT_SET_ROWS에는 결과 세트의 추정 행 수가 포함됩니다. 값 -1은 결과 세트의 행 수 추정값을 사용할 수 없음을 표시합니다.
      • DB2_RESULT_SET_LOCATOR에는 결과 세트와 연관된 결과 세트 위치 지정자 값이 포함됩니다.

    SQLDA의 경우, 스토어드 프로시저가 리턴할 수 있는 최대 결과 세트 수를 보유할 수 있도록 SQLDA를 충분히 할당하십시오. DESCRIBE PROCEDUREE문이 완료되면 SQLDA의 필드에 다음 값이 포함됩니다.

    • SQLD에는 스토어드 프로시저가 리턴하는 결과 세트 수가 포함됩니다.
    • 각 SQLVAR 항목은 결과 세트에 대한 정보를 제공합니다. SQLVAR 항목에서,
      • SQLNAME 필드에는 스토어드 프로시저가 결과 세트를 리턴하는 데 사용하는 커서명이 포함됩니다.
      • SQLIND 필드에는 결과 세트의 추정 행 수가 포함됩니다. 값 -1은 결과 세트의 행 수 추정값을 사용할 수 없음을 표시합니다.
      • SQLDATA 필드에는 결과 세트의 주소인 결과 세트 위치 지정자 값이 포함됩니다.
  4. 결과 세트 위치 지정자를 결과 세트에 링크하십시오.

    ASSOCIATE LOCATORS SQL문을 사용하여 결과 세트 위치 지정자를 결과 세트에 링크할 수 있습니다. ASSOCIATE LOCATORS문은 결과 세트 위치 지정자 변수에 값을 할당합니다. 리턴되는 결과 세트 수보다 위치 지정자를 많이 지정하는 경우, 추가 위치 지정자는 무시됩니다.

    이전에 DESCRIBE PROCEDURE문을 실행한 경우, SQL 설명자의 DB2_RESULT_SET_LOCATOR에서 또는 SQLDA의 SQLDATA 필드에서 결과 세트 위치 지정자 값을 검색할 수 있습니다. 이러한 필드에서 결과 세트 위치 지정자 변수로 값을 수동으로 복사하거나 ASSOCIATE LOCATORS문을 실행하여 이를 수행할 수 있습니다.

    ASSOCIATE LOCATORS 또는 DESCRIBE PROCEDURE문에 지정하는 스토어드 프로시저명은 결과 세트를 리턴하는 CALL문에서 이미 사용된 프로시저명이어야 합니다.

  5. 결과 세트에서 행을 페치하기 위해 커서를 할당하십시오.

    ALLOCATE CURSOR SQL문을 사용하여 각 결과 세트를 커서와 링크하십시오. 각 결과 세트에 대해 하나의 ALLOCATE CURSOR문을 실행하십시오. 커서명은 스토어드 프로시저의 커서명과 다를 수 있습니다.

  6. 결과 세트의 내용을 판별하십시오.

    결과 세트의 형식을 이미 알고 있으면 이 단계를 건너뛸 수 있습니다.

    DESCRIBE CURSOR SQL문을 사용하여 결과 세트의 형식을 판별하고 SQL 설명자 또는 SQLDA에 이 정보를 배치하십시오. 각 결과 세트에 대해 결과 세트의 모든 열에 대한 설명을 보유할 수 있을 만큼 SQLDA가 충분해야 합니다.

    이전에 ALLOCATE CURSOR를 실행한 커서에 대해서만 DESCRIBE CURSOR를 사용할 수 있습니다.

    DESCRIBE CURSOR를 실행한 후에는 결과 세트에 대한 커서가 WITH HOLD로 선언된 경우 SQL 설명자에 대해 DB2_CURSOR_HOLD를 검사할 수 있습니다. SQLDA의 경우, SQLDA에서 SQLDAID 필드의 8번째 바이트의 최상위 비트는 1로 설정됩니다.

  7. ALLOCATE CURSOR문을 사용하여 할당한 커서를 사용하여 결과 세트에서 호스트 변수로 행을 페치하십시오.

    DESCRIBE CURSOR문을 실행한 경우, 행을 페치하기 전에 다음 단계를 수행하십시오.

    1. 호스트 변수 및 인디케이터 변수에 대해 기억장치를 할당하십시오. DESCRIBE CURSOR문의 SQL 설명자 또는 SQLDA의 내용을 사용하여 각 호스트 변수에 필요한 기억장치 양을 판별하십시오.
    2. 각 호스트 변수의 기억장치 주소를 SQLDA의 해당 SQLDATA 필드에 배치하십시오.
    3. 각 인디케이터 변수의 기억장치 주소를 SQLDA의 해당 SQLIND 필드에 배치하십시오.

    결과 세트에서 행을 페치하는 것은 테이블에서 행을 페치하는 것과 동일합니다.

다음 예제는 이러한 각 단계를 수행하는 C 언어를 표시합니다. 기타 언어의 경우 코딩은 유사합니다.

다음 예제는 리턴되는 결과 세트 수 및 결과 세트의 내용을 알고 있는 경우 결과 세트 수신 방법을 설명합니다.

/*************************************************************/
/* Declare result set locators.  For this example,           */
/* assume you know that two result sets will be returned.    */
/* Also, assume that you know the format of each result set. */
/*************************************************************/
  EXEC SQL BEGIN DECLARE SECTION;
   static volatile SQL TYPE IS RESULT_SET_LOCATOR loc1, loc2;
  EXEC SQL END DECLARE SECTION;
  ⋮
/*************************************************************/
/* Call stored procedure P1. */
/* Check for SQLCODE +466, which indicates that result sets  */
/* were returned. */
/*************************************************************/
  EXEC SQL CALL P1(:parm1, :parm2, ...);
  if(SQLCODE==+466)
  {
  /*************************************************************/
  /* Establish a link between each result set and its          */
  /* locator using the ASSOCIATE LOCATORS. */
  /*************************************************************/
    EXEC SQL ASSOCIATE LOCATORS (:loc1, :loc2) WITH PROCEDURE P1;
    ⋮
  /*************************************************************/
  /* Associate a cursor with each result set. */
  /*************************************************************/
    EXEC SQL ALLOCATE C1 CURSOR FOR RESULT SET :loc1;
    EXEC SQL ALLOCATE C2 CURSOR FOR RESULT SET :loc2;
  /*************************************************************/
  /* Fetch the result set rows into host variables. */
  /*************************************************************/
    while(SQLCODE==0)
    {
      EXEC SQL FETCH C1 INTO :order_no, :cust_no;
    ⋮
    }
    while(SQLCODE==0)
    {
      EXEC SQL FETCH C2 :order_no, :item_no, :quantity;
    ⋮
    }
  }

다음 예제는 리턴되는 결과 세트 수 또는 결과 세트의 내용을 모르는 경우 결과 세트 수신 방법을 설명합니다.

/*************************************************************/
/* Declare result set locators.  For this example,           */
/* assume that no more than three result sets will be        */
/* returned, so declare three locators.  Also, assume        */
/* that you do not know the format of the result sets. */
/*************************************************************/
  EXEC SQL BEGIN DECLARE SECTION;
   static volatile SQL TYPE IS RESULT_SET_LOCATOR loc1, loc2, loc3;
  EXEC SQL END DECLARE SECTION;
  ⋮
/*************************************************************/
/* Call stored procedure P2. */
/* Check for SQLCODE +466, which indicates that result sets  */
/* were returned. */
/*************************************************************/
  EXEC SQL CALL P2(:parm1, :parm2, ...);
  if(SQLCODE==+466)
  {
  /*************************************************************/
  /* Determine how many result sets P2 returned, using the     */
  /* statement DESCRIBE PROCEDURE.  :proc_da is an SQLDA       */
  /* with enough storage to accommodate up to three SQLVAR     */
  /* entries. */
  /*************************************************************/
    EXEC SQL DESCRIBE PROCEDURE P2 INTO :proc_da;
    ⋮
  /*************************************************************/
  /* Now that you know how many result sets were returned,     */
  /* establish a link between each result set and its          */
  /* locator using the ASSOCIATE LOCATORS.  For this example,  */
  /* we assume that three result sets are returned. */
  /*************************************************************/
    EXEC SQL ASSOCIATE LOCATORS (:loc1, :loc2, :loc3) WITH PROCEDURE P2;
    ⋮
  /*************************************************************/
  /* Associate a cursor with each result set. */
  /*************************************************************/
    EXEC SQL ALLOCATE C1 CURSOR FOR RESULT SET :loc1;
    EXEC SQL ALLOCATE C2 CURSOR FOR RESULT SET :loc2;
    EXEC SQL ALLOCATE C3 CURSOR FOR RESULT SET :loc3;

  /*************************************************************/
  /* Use the statement DESCRIBE CURSOR to determine the        */
  /* format of each result set. */
  /*************************************************************/
    EXEC SQL DESCRIBE CURSOR C1 INTO :res_da1;
    EXEC SQL DESCRIBE CURSOR C2 INTO :res_da2;
    EXEC SQL DESCRIBE CURSOR C3 INTO :res_da3;
    ⋮
  /*************************************************************/
  /* Assign values to the SQLDATA and SQLIND fields of the     */
  /* SQLDAs that you used in the DESCRIBE CURSOR statements.   */
  /* These values are the addresses of the host variables and  */
  /* indicator variables into which DB2 will put result set    */
  /* rows. */
  /*************************************************************/
    ⋮
  /*************************************************************/
  /* Fetch the result set rows into the storage areas          */
  /* that the SQLDAs point to. */
  /*************************************************************/
    while(SQLCODE==0)
    {
      EXEC SQL FETCH C1 USING :res_da1;
    ⋮
    }
    while(SQLCODE==0)
    {
      EXEC SQL FETCH C2 USING :res_da2;
    ⋮
    }
    while(SQLCODE==0)
    {
      EXEC SQL FETCH C3 USING :res_da3;
    ⋮
    }
  }

다음 예제는 SQL 설명자를 사용하여 결과 세트를 수신하는 방법을 설명합니다.

호출될 SQL 프로시저는 다음과 같습니다.

create procedure owntbl()  
  dynamic result sets 1                         
  begin                                         
    declare c1 cursor for                       
      select name, dbname from qsys2.systables  
        where creator = system_user ;           
    open c1 ;                                   
    return ;                                    
  end                                           
결과 세트를 처리할 프로그램은 다음과 같습니다.
#include <string.h> 
#include <stdio.h>
#include <stdlib.h>

EXEC SQL INCLUDE SQLCA;
/*************************************************************/
/* Declare result set locators.  For this example,           */
/* you know that only one result set will be returned,       */
/* so only one locator is declared. */
/*************************************************************/
EXEC SQL BEGIN DECLARE SECTION;
 static volatile SQL TYPE IS RESULT_SET_LOCATOR loc1;
 struct {
   short len;
   char  data[128];
 } tblName;   /* table name  */

 struct {
   short len;
   char  data[128];
 } schName;   /* schema name */
EXEC SQL END DECLARE SECTION;

void main(int argc, char* argv[])
{
/*************************************************************/
/* Call the procedure that might return a result set.  Check */
/* the returned SQLCODE to see if result sets were returned. */
/*************************************************************/
  int noMoreData = 0;
  EXEC SQL WHENEVER SQLERROR GOTO error;
  EXEC SQL CALL OWNTBL ;
  if (SQLCODE != 466) {
    goto error;
  }
/*************************************************************/
/* Since you know only one result set can be returned from   */
/* this procedure, associate a locator with the result set   */
/* and define a cursor to be used with it. */
/*************************************************************/
  EXEC SQL ASSOCIATE LOCATORS (:loc1) WITH PROCEDUREOWNTBL ;
  EXEC SQL ALLOCATE C1 CURSOR FOR RESULT SET :loc1 ;
/*************************************************************/
/* Define the descriptor to use for fetching data from the   */
/* cursor. */
/*************************************************************/
  EXEC SQL ALLOCATE DESCRIPTOR 'desc' WITH MAX 10 ;
  EXEC SQL DESCRIBE CURSOR C1 USING SQL DESCRIPTOR 'desc' ;
  EXEC SQL WHENEVER NOT FOUND GOTO enddata;
  while ( noMoreData == 0 ) {
    EXEC SQL FETCH C1 INTO SQL DESCRIPTOR 'desc' ;
    memset(tblName.data,0x00,sizeof(tblName.data));
    memset(schName.data,0x00,sizeof(schName.data));
    EXEC SQL GET DESCRIPTOR 'desc' VALUE 1 :tblName = DATA;
    EXEC SQL GET DESCRIPTOR 'desc' VALUE 2 :schName = DATA;
    printf("Table: %s   Schema: %s \n",
           tblName.data,schName.data);
  }

enddata:
  printf("All rows fetched.\n");
  return;

error:
  printf("Unexpected error, SQLCODE = %d \n", SQLCODE);
  return;
}

다음 예제는 SQL 프로시저를 사용하여 결과 세트를 수신하는 방법을 설명합니다. 이는 대형 SQL 프로시저의 단편일 뿐입니다.

DECLARE RESULT1 RESULT_SET_LOCATOR VARYING;           
DECLARE RESULT2 RESULT_SET_LOCATOR VARYING;           
⋮
CALL TARGETPROCEDURE();

ASSOCIATE RESULT SET LOCATORS(RESULT1,RESULT2)
  WITH PROCEDURE TARGETPROCEDURE;                     
ALLOCATE RSCUR1 CURSOR FOR RESULT1;                   
ALLOCATE RSCUR2 CURSOR FOR RESULT2;                   

WHILE AT_END = 0 DO                                 
  FETCH RSCUR1 INTO VAR1;                   
  SET TOTAL1 = TOTAL1 + VAR1;                         
END WHILE;                                             

WHILE AT_END = 0 DO                                 
  FETCH RSCUR2 INTO VAR2;                   
  SET TOTAL2 = TOTAL2 + VAR2;                         
END WHILE;                                             
⋮