Gentle Breeze

[Oracle] ORA-01002: fetch out of sequence 본문

⑨ 직무역량강화/Oracle

[Oracle] ORA-01002: fetch out of sequence

재령 2011. 1. 25. 13:39


이 상황에서 자주 발생하는 Oracle Error Code


원문 - http://scruz.tistory.com/18


ORA-01002: fetch out of sequence


ORACLE에서 제공하는 문서상의 원인과 해결방법은 아래와 같다.


Cause: This error means that a fetch has been attempted from a cursor


       which is no longer vaild. Note that a PL/SQL cursor loop

       implicitly does fetches, and thus may also cause this error.
       There are a number of possible causes for this error, including:
       1) Fetching from a cursor after the last row has been retrieved
          and the ORA-01403 error returned.
       2) If the cursor has been opened with the FOR UPDATE clause,
          fetching after a COMMIT has been issued will return the error.
       3) Rebinding any placeholders in the SQL statement, then issuing
          a fetch before reexecuting the statement.


Action: 1) Do not issue a fetch statement after the last row has been
           retrieved - there are no more rows to fetch.
        2) Do not issue a COMMIT inside a fetch loop for a cursor
           that has been opened FOR UPDATE.
        3) Reexecute the statement after rebinding, the attempt to
           fetch again.

          

1) CURSOR를 이용해 어느 테이블의 데이터를 FETCH를 할 때, 그 해당 결과값들이 모두
   FETCH되어 더 이상 FETCH될 데이터가 없을 때 ORACLE은 ORA-01403에러를 발생시켜 
   더 이상 FETCH될 데이터가 없다는 걸 알린다.

   하지만 프로그래머의 실수로 FETCH받는 부분의 LOOP제어가 잘 못되어 ORA-01403이
   발생했는데도 FETCH를 시도하게 되면 ORA-01002를 발생시킨다. 
   
    while(1) {
        EXEC SQL FETCH _CURSOR
        INTO :data_basket;

        pFetch += nFetch;
        nFetch  = sqlca.sqlerrd[2] - pFetch;
           
        if(sqlca.sqlcode == 0)
            (void)put_in_file(data_basket, nFetch);
            
        if(sqlca.sqlcode == 1403) {
            if(nFetch > 0)
                (void)put_in_file(data_basket, nFetch);
                
            break; <-- 이 부분이 없으면 ORA-01403이 발생했는데도 FETCH를 시도하기 
                       때문에 ORA-01002가 발생된다.
        }
        
        if(sqlca.sqlcode != 0 && sqlca.sqlcode != 1403) { 
            printf("%s\n", sqlca.sqlerrm.sqlerrmc);
            
            exit(1);
        }
    }


2) SAMPLE_TABLE이란 이름의 테이블이 있다.

   a세션은 SAMPLE_TABLE에서 UPDATE를 하고 COMMIT or ROLLBACK을 하지 않은 상태이다.
   이때 b세션에서 
   
   SELECT * FROM SAMPLE_TABLE;
   위의 쿼리를 조회하게 되면 a세션의 UPDATE 쿼리가 반영되지 않은 결과값이 리턴된다.
   
   SELECT * FROM SAMPLE_TABLE FOR UPDATE;
   위의 쿼리를 조회하게 되면 a세션의 UPDATE 쿼리에 대한 COMMIT or ROLLBACK이 될 때까지 
   대기하게 된다.
   
   SELECT * FROM SAMPLE_TABLE FOR UPDATE WAIT 10;
   위의 쿼리를 조회하게 되면 a세션의 UPDATE 쿼리에 대한 COMMIT or ROLLBACK이 되지 않은 
   상태이기 때문에 10초 동안 COMMIT or ROLLBACK 여부를 확인한 뒤 COMMIT or ROLLBACK되지 
   않았으면 ORA-01002에러를 발생시킨다.  
    
   SELECT * FROM SAMPLE_TABLE FOR UPDATE NOWAIT;
   위의 쿼리를 조회하게 되면 a세션의 UPDATE 쿼리에 대한 COMMIT or ROLLBACK이 되지 않은 
   상태이기 때문에 대기하지 않고 ORA-01002에러를 발생시킨다.


3) CURSOR로 선언된 SELECT문의 GROUP BY절이 잘 못되어서 발생하는 경우이다.

   Sample_Table)
   +-----+---------+------------+---------+
   | SEQ | PROD_NO | PROD_NAME  | PRICE   |
   +-----+---------+------------+---------+
   |   1 |    1001 | Nikon F6   | 3000000 |
   |   2 |    1002 | Nikon F5   | 2500000 |
   |   3 |    1003 | Nikon F4s  | 2000000 |
   |   4 |    1004 | Nikon F4h  | 2000000 |
   |   5 |    1005 | Nikon F3Ti | 1500000 |
   |   6 |    1006 | Nikon F3hp | 1500000 |
   |   7 |    1007 | Nikon F3AF | 1500000 |
   |   8 |    1008 | Nikon F3   | 1500000 |
   +-----+---------+------------+---------+
   
   Query)
   SELECT
       SEQ,
       PROD_NO,
       PROD_NAME,
       PRICE
   FROM
       SAMPLE_TABLE
   GROUP BY        -+
       SEQ,         | GROUP BY절이 잘 못되어 있다.
       PROD_NAME,   | 이 경우 ORA-01002에러가 발생한다.
       PRICE;      -+
       


4) 실제로 겪어본 케이스는 아니지만
   DB Link를 통해 Remote Database에서 Fetch를 받는 중에
   Remote Database가 Shutdown되면 ORA-01002에러가 발생된다고 한다.

Comments