TIP게시판

제목 oci8 driver 버그..
글쓴이 jyp 작성시각 2013/08/29 19:39:31
댓글 : 4 추천 : 0 스크랩 : 0 조회수 : 12893   RSS
 이전까지는 CI에서 mysql만 사용하다가 얼마전에 오라클을 처음으로 연동해서 사용해 봤는데요

다른부분은 문제가 없었는데 오라클에서 sequence number를 가져오는 쿼리를 실행하면

sequence number가 항상 +2가 되어서 리턴되더라구요.

그래서 CI코드를 봤는데 완전 코어단 까지는 잘 모르겠고 

DB_driver.php 파일의 query() 함수에서 기본적으로 

// Run the Query
        if (FALSE === ($this->result_id = $this->simple_query($sql)))
        {
에서 simple_query()를 호출하여 먼저 쿼리를 한번 날리고 

function simple_query($sql)
    {           
        if ( ! $this->conn_id)
        {
            $this->initialize();
        }   
 
        return $this->_execute($sql);
    }

여기서 _execute() 부분이 실제 쿼리를 날리는 부분 같습니다.

암튼 여기서 쿼리가 한번 실행되면 $this 객체의 result_id, stmt_id 에 모두 값이 세팅 되더군요.

그런데 문제는 

$driver         = $this->load_rdriver();
        $RES            = new $driver();
        $RES->conn_id   = $this->conn_id;
        $RES->result_id = $this->result_id;
 
        if ($this->dbdriver == 'oci8')
        {
            $RES->stmt_id       = $this->stmt_id;
            $RES->curs_id       = NULL;
            $RES->limit_used    = $this->limit_used;
            $this->stmt_id      = FALSE;
        }

위 코드와 같이 oci8드라이버를 사용할 경우 $RES객체에 simple_query()로 받아온 결과를

그대로 세팅을 하는데 바로 아래에서 

$RES->num_rows    = $RES->num_rows();

위와 같은 코드가 한번 더 싱행이 되더군요...

이 num_rows()라는 함수는 drivers/oci8/oci8_result.php 여기에 있는 함수로 

    public function num_rows()
    {       
        if ($this->num_rows === 0 && count($this->result_array()) > 0)
        {                       
            $this->num_rows = count($this->result_array());
            @oci_execute($this->stmt_id);
        
            if ($this->curs_id)
            {
                @oci_execute($this->curs_id);
            }
        }
 
        return $this->num_rows;
    }

위와 같은 기능을 하더라구요....

이전 코드에서 $RES객체에 따로 num_rows를 세팅하지 않았고, 이미 simple_query()

함수를 통해서 result를 받아온 상황이라 첫번째 if문에서 바로 걸리게 되죠.

그래서 if문으로 들어와서 @oci_execute($this->stmt_id); 를 실행하는데

이때 쿼리를 한번 더 날리는것 같습니다.

그래서 sequence_number가 항상 +2가 됐던것 같구요..

 
그래서 기존의 코드를 주석 처리 하고

//$RES->num_rows    = $RES->num_rows();
        $RES->result_array();
        $RES->num_rows = count($RES->result_array);

이렇게 수정 했습니다. $RES->result_array(); 이 함수를 호출하는 이유는 

simple_query() 함수를 호출했을때 $RES의 result_array 프로퍼티에 실제

결과값이 저장되는게 아니라 객체(?)로 결과값을 가지고 있어서 저 함수를 실행해야

result_array 프로퍼티에 값이 세팅 되더군요..

 
그래서 핵심은

simple_query()로 한번 결과를 가져오고, 하지만 result_array()에는 결과가 실제로 저장돼있지는 않음

result_array 프로퍼티에 결과저장 및 row_num 을 구하기 위해 row_nums() 함수를 호출

여기서 @oci_execute() 함수로 한번더 DB로 쿼리를 날림

이게 문제였던것 같습니다

 

 

 
 다음글 화면이 작아서 고생하시는 분들 (3)
 이전글 helper에서 세션 객체 접근 (2)

댓글

들국화 / 2013/08/30 11:53:05 / 추천 0
어렵네요.... 2.1.0 과도 소스가 좀 틀리네요. 보다 보니 이상해서 보니 버전이 틀리다는...ㅋㅋㅋ

stmt_id 이게 뭔지 모르겠네요... Statement ID 즉 쿼리문 ID 인듯 한데..

오라클 써본지 워낙에 오래 돼서 기억이 가물 가물 한데... 시퀀스 넘버를 구해와서 인서트를 해서 그런건 아닌가요?

인서트 문에 쿼리를 포함해서 넣은 건가요?

버그가 맞다면 버그레포팅 해주세요. ^^;

검색하다 보니 오라클 관련해 알려진 버그가 있네요. 심각한 버그네요. ㅎㅎㅎ

https://github.com/EllisLab/CodeIgniter/wiki/Oracle:Known-Issues
jyp / 2013/08/30 11:57:35 / 추천 0
 $this->db->query(); 로 바로 쿼리를 날립니다. insert를 하는건 없네요

sequence number가 항상 +2로 리턴이 된다는것은 실제로 oracle에 쿼리가 두번 날라갔다는 의미 아닌가요?

curval을 가져올때 마다 자동으로 +1이 되니까요
들국화 / 2013/08/30 12:09:10 / 추천 0
jyp/ 실제 쿼리 문이 궁금 하네요.
 INSERT INTO MYTABLE VALUES( SEQ_ID.NEXTVAL, '홍길동');
이런 형태로 넣는거 아닌가요?

curval 은 몇번을 하던 +1이 안되는거 아닌가요?

머 어쨌든 버그가의심되면 버그래포팅 해서 한국개발자도 CI발전에 동참을.. ^^
jyp / 2013/08/30 12:12:37 / 추천 0
아 네 nextval 입니다 ㅎㅎ