Расширение Yii 1.1 oci8Pdo и бинд параметров CLOB/BLOB

от автора

В моей компании есть проект который построен на Yii 1.1 и использует базу данных Oracle 9g. Для работы с бызой используется разширение oci8Pdo.

Недавно появилась задача загрузки сканов в базу в поле BLOB. Т.к. автор расширения пишет:

The goal of this PDO class is to simulate 99% of the PDO functions that you use in an application.

то причин сомневаться в реализации данного функционала было мало.

Пробуем загрузить скан:

<?php     $doc_scan = file_get_contents($file);     $db = Yii::app()->dbOracle;     $stmt = $db->createCommand("update scan_document set DOCUM_SCAN=:doc_xml, DOC_SCAN=:doc_scan where DOCUM_ID=:docum_id");     $stmt->bindParam(':doc_xml', $doc_xml, PDO::PARAM_LOB);     $stmt->bindParam(':doc_scan', $doc_scan, PDO::PARAM_LOB);     $stmt->bindValue(':docum_id', $add->DOCUM_ID);     $stmt->query(); ?> 

Но не тут то было: ORA-01465: invalid hex number.

Стали раскуривать проблему и наткнулись на реализацию метода bindParam в классе Oci8PDO_Statement вышеописанного расширения:

<?php public function bindParam(     $parameter,     &$variable,     $data_type = PDO::PARAM_STR,     $length = -1,     $driver_options = null ) { 	//Not checking for $data_type === PDO::PARAM_INT, because this gives problems when inserting/updating integers into a VARCHAR column.     if ($driver_options !== null) {         throw new PDOException('$driver_options is not implemented for Oci8PDO_Statement::bindParam()');     }          if (is_array($variable)) {         return oci_bind_array_by_name(             $this->_sth,             $parameter,             $variable,             count($variable),             $length         );     } else {         if ($length == -1) {             $length = strlen((string)$variable);         }          return oci_bind_by_name($this->_sth, $parameter, $variable, $length);     } } ?> 

Аргумент $data_type принимается, но нигде не обрабатывается. Так и получается что CLOB или BLOB записать у нас не выйдет. Деваться было некуда, пришлось допиливать oci8Pdo.

В класс Oci8PDO который наследуется от PDO добавили константы и метод вытаскивающий ресурс подключения к ДБ:

<?php 	/**      * Ananalog constant OCI_B_CLOB      *      * @const int      */     const PARAM_CLOB = 112;     /**      * Ananalog constant OCI_B_BLOB      *      * @const int      */     const PARAM_BLOB = 113;       // ..............       /**      * Return the resource connection      *      * @return mixed      */     public function getDbh() {         return $this->_dbh;     } ?>  

И немного допилили метод bindParam в классе Oci8PDO_Statement:

<?php 	public function bindParam(         $parameter,         &$variable,         $data_type = PDO::PARAM_STR,         $length = -1,         $driver_options = null     ) {     	     	// ................      	if ($data_type == Oci8PDO::PARAM_BLOB) {             $clob = oci_new_descriptor($this->_pdoOci8->getDbh(), OCI_D_LOB);             $res = oci_bind_by_name($this->_sth, $parameter, $clob, -1, OCI_B_BLOB);             $clob->writeTemporary($variable, OCI_TEMP_BLOB);             return $res;         } else if ($data_type == Oci8PDO::PARAM_CLOB) {             $clob = oci_new_descriptor($this->_pdoOci8->getDbh(), OCI_D_LOB);             $res = oci_bind_by_name($this->_sth, $parameter, $clob, -1, OCI_B_CLOB);             $clob->writeTemporary($variable, OCI_TEMP_CLOB);             return $res;         }         else {             return oci_bind_by_name($this->_sth, $parameter, $variable, $length);         }      } ?> 

Теперь обработка CLOB/BLOB проходит успешно:

<?php  $doc_scan = file_get_contents($file); $db = Yii::app()->dbOracle; $stmt = $db->createCommand("update scan_document set DOCUM_SCAN=:doc_xml, DOC_SCAN=:doc_scan where DOCUM_ID=:docum_id");  $stmt->bindParam(':doc_xml', $doc_xml, Oci8PDO::PARAM_CLOB); // Используем наши константы $stmt->bindParam(':doc_scan', $doc_scan, Oci8PDO::PARAM_BLOB); // Используем наши константы $stmt->bindValue(':docum_id', $add->DOCUM_ID); $stmt->query();  ?> 

Итог:

Допил был организовани в пулреквест и отправлен разработчику oci8Pdo yjeroen. Когда гуглилась проблема, было замечено много не решенных вопросов на эту тему. Надеюсь мой опыт кому нибудь поможет.

P.S.: Буду рад критике и конструктивным замечаниям в комментах.

ссылка на оригинал статьи http://habrahabr.ru/post/267609/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *