Php pdo unixOBDC для sqlserver 2008: строковые данные, несоответствие длины при выполнении подготовленного stmt

У меня следующая установка: Apache/php 5.3/pdo с odbc с установленным драйвером ODBC Microsoft SQL Server 1.0 для Linux на сервере.

Мой сценарий вызывает ошибку со следующей трассировкой стека при попытке выполнить оператор:

(UTC) 2013-12-16 12:07:40: Thrown exception log ->
'Error message: SQLSTATE[22026]: String data, length mismatch: 0 [Microsoft][SQL Server Native Client 11.0]String data, length mismatch (SQLExecute[0] at /tmp/pear/temp/PDO_ODBC/odbc_stmt.c:133)
 Arisen in Core_Db->select(array (
      0 =>
         'SELECT  *
          FROM    TMS.dbo.TEST_user
          WHERE   email = ? AND status_id = ?',
      1 => 
         array (
             0 => '[email protected]',
             1 => 2
         ),
))

Для тестирования я использую php 5.3 на окнах с pdo sqlsrv, и там ничего не пошло не так.

Код подключения

        // for unixODBC (production)
        if (DB_DRIVER == 'odbc') {
            $this->_link = new PDO(
                "odbc:DRIVER={SQL Server Native Client 11.0};SERVER=" . DB_HOST . ";"
                . "PORT=" . DB_PORT . ";DATABASE=" . DB_NAME . ";PROTOCOL=TCPIP;UID=" . DB_LOGIN . ";"
                . "PWD=" . DB_PASSWD . ";"
            );
        // for sqlsrv (development)
        } else {
            $this->_link = new PDO(
                "sqlsrv:Server=" . DB_HOST . "," . DB_PORT . ";Database=" . DB_NAME,
                DB_LOGIN,
                DB_PASSWD
            );
        }
        $this->_link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Есть некоторые рекомендации по этой проблеме: ODBC и SQL Server 2008: Нельзя использовать подготовленные операторы?. Но я не могу это проверить. Когда я пытаюсь добавить атрибут в производство, скрипт выдает следующую ошибку:

(UTC) 2013-12-16 13:19:44: SQLSTATE[IM001]: Driver does not support this function: driver does not support setting attributes

Кто-нибудь знает, как решить эту проблему?

ОБНОВЛЕНО 18 декабря 2013 г.

// unixODBC connection
$this->_link = new PDO(
    "odbc:DRIVER={SQL Server Native Client 11.0};SERVER=xxx.xxx.xxx.xxx;"
    . "PORT=1433;DATABASE=TMS;PROTOCOL=TCPIP;",
    DB_LOGIN,
    DB_PASSWD,
    array(
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // this attr is recognized by ODBC
        PDO::ATTR_EMULATE_PREPARES => false // but if this is added ODBC throws PDOException with message "driver does not support setting attributes"
    )
 );

Передача строки из ODBC в клиент приводит к повреждению строки при использовании подготовленного оператора. Так что я только предполагаю, что дело в PDO::ATTR_EMULATE_PREPARES.


person Eugeny    schedule 16.12.2013    source источник


Ответы (1)


Ошибка

(UTC) 16.12.2013, 13:19:44: SQLSTATE[IM001]: драйвер не поддерживает эту функцию: драйвер не поддерживает установку атрибутов

говорит вам, что эта строка:

$this->_link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

является недействительным. Вместо этого сделайте следующее:

$driver_options = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                        PDO::ATTR_EMULATE_PREPARES => FALSE);

if (DB_DRIVER == 'odbc'){ // for unixODBC (production)
    $dsn = 'odbc:DRIVER={SQL Server Native Client 11.0};SERVER='. DB_HOST .';PORT='. DB_PORT .';DATABASE='. DB_NAME .';PROTOCOL=TCPIP;';
    $this->_link = new PDO($dsn, DB_LOGIN, DB_PASSWD, $driver_options);
}else{ // for sqlsrv (development)
    $this->_link = new PDO(
        "sqlsrv:Server=" . DB_HOST . "," . DB_PORT . ";Database=" . DB_NAME,
        DB_LOGIN,
        DB_PASSWD
    );
}
person Benny Hill    schedule 16.12.2013
comment
Нет, ошибка возникает только тогда, когда я применяю $pdo-›setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE); - person Eugeny; 16.12.2013
comment
@ Евгений - я обновил свой ответ. Вы не можете использовать функцию setAttribute(), вы должны установить эту опцию при создании объекта PDO. - person Benny Hill; 16.12.2013
comment
К сожалению, та же ошибка. Он не позволяет установить какой-либо атрибут, кроме PDO::ATTR_ERRMODE, даже при создании PDO. - person Eugeny; 16.12.2013
comment
@Eugeny, вы можете отредактировать свой вопрос и показать обновленный код? Пожалуйста, включите ту часть, где вы пытаетесь установить PDO::ATTR_EMULATE_PREPARES. - person Benny Hill; 16.12.2013
comment
Относительно этого ссылка и эта ссылка и другие - это драйвер ошибка. - person Eugeny; 18.12.2013
comment
@Евгений - А, спасибо за ссылки. Если драйвер Microsoft не будет работать для вас, можно ли использовать FreeTDS? - person Benny Hill; 18.12.2013
comment
У нас есть некоторые проблемы/ограничения при создании php с pdo_dblib на сервере. Также мы попробовали решение EasySoft sql odbc, но оно тоже имеет неожиданные баги с выполнением подготовленных запросов. Я думаю, что я должен изменить базу данных - person Eugeny; 19.12.2013
comment
Мне позвонили из EasySoft по этому поводу. Похоже, во всем виновато 64-битное приложение php, которое запускается на 64-битном Debian. PHP не справляется с размерами SQLLEN/SQLULEN, создавая их как 32-битные. Таким образом, выходные строки (от php до драйвера) будут повреждены. - person Eugeny; 20.12.2013
comment
@ Евгений, спасибо, что сообщили мне, в чем проблема. Надеюсь, вы сможете найти решение (возможно, перейти на 32-битную среду?). - person Benny Hill; 20.12.2013