oci8 driver 버그..
이전까지는 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로 쿼리를 날림
이게 문제였던것 같습니다
stmt_id 이게 뭔지 모르겠네요... Statement ID 즉 쿼리문 ID 인듯 한데..
인서트 문에 쿼리를 포함해서 넣은 건가요?오라클 써본지 워낙에 오래 돼서 기억이 가물 가물 한데... 시퀀스 넘버를 구해와서 인서트를 해서 그런건 아닌가요?
버그가 맞다면 버그레포팅 해주세요. ^^;
검색하다 보니 오라클 관련해 알려진 버그가 있네요. 심각한 버그네요. ㅎㅎㅎ
https://github.com/EllisLab/CodeIgniter/wiki/Oracle:Known-Issues