Использование типизированных связанных параметров с PHP PDO-ODBC, unixODBC и FreeTDS - PullRequest
6 голосов
/ 30 сентября 2010

Я использую следующую настройку для доступа к базе данных MS-SQL из приложения PHP

  • RedHat Enterprise Linux 5
  • PHP 5.2.14 с PDO и PDO_ODBC
  • unixODBC 2.2.11
  • FreeTDS 0.82.1.dev.20100810

Непараметризованные запросы работают нормально.Единственной проблемой является принудительное закрытие курсора на отдельных операторах результата (с PDOStatment :: closeCursor), чтобы избежать ошибок «0 [FreeTDS] [SQL Server] Недопустимое состояние курсора (SQLSTATE = 24000)».

Но яУ меня есть серьезная проблема с типизированным связанным параметром.При использовании кода, подобного следующему:

$stmt = $PDO->prepare('INSERT INTO table (column1, column2)  VALUES (:foo, :bar');
$stmt->bindValue(':foo', 21, PDO::PARAM_INT);
$stmt->bindValue(':bar', 42, PDO::PARAM_INT);
$stmt->execute():
if (!$stmt->execute()) {
 var_dump($stmt->errorInfo();
}

Где оба столбца INT.Я получаю сообщение об ошибке «206 [FreeTDS] [SQL Server] операнд типа: текст несовместим с int [SQLSTATE = 22018]».

В журнале unixODBC я получаю что-то вроде

[ODBC][26251][SQLDescribeParam.c][175]
              Entry:
                      Statement = 0x2b73c849fb80
                      Parameter Number = 1
                      SQL Type = 0x7fff9c89e15e
                      Param Def = 0x7fff9c89e154
                      Scale = 0x7fff9c89e15c
                      Nullable = 0x7fff9c89e15a
[ODBC][26251][SQLDescribeParam.c][276]Error: IM001
[ODBC][26251][SQLBindParameter.c][193]
              Entry:
                      Statement = 0x2b73c849fb80
                      Param Number = 1
                      Param Type = 1
                      C Type = 1 SQL_C_CHAR
                      SQL Type = -1 SQL_LONGVARCHAR
                      Col Def = 4000
                      Scale = 5
                      Rgb Value = 0x2b73c941f890
                      Value Max = 0
                      StrLen Or Ind = 0x2b73c93fa1b0
[ODBC][26251][SQLBindParameter.c][339]
              Exit:[SQL_SUCCESS]

Мое понимание журнала заключается в том, что unixODBC пытается связать параметры, используя правильный тип.Но FreeTDS не поддерживает эту функцию (IM001: «Драйвер не поддерживает эту функцию»).Так что unixODBC продолжится без правильной типизации.

Может ли кто-нибудь подтвердить этот диагноз или, что лучше, известную проблему с типизированным связанным параметром во FreeTDS?Если да, работают ли они с использованием PHP PDO, и как я могу его настроить?

Ответы [ 3 ]

6 голосов
/ 08 марта 2012

Я знаю, что это старая проблема, но я хотел опубликовать свое решение для тех, у кого есть такая же проблема.

Я смог решить эту проблему, изменив версию TDS с 7.1 на 7.2.У меня больше нет проблем.

Надеюсь, это поможет!

5 голосов
/ 04 октября 2010

В списке рассылки FreeTDS я получил подтверждение того, что SQLDescribeParam не поддерживается в FreeTDS . Но когда SQLDescribeParam не поддерживается, PDO_ODBC виноват в использовании LONGVARCHAR (т.е. текст).

Тот же код работал на рабочей станции Windows с PDO ODBC (PHP версии 5.2.9, библиотека ODBC Win32)

Обходной путь для этой проблемы, чтобы рассматривать каждый параметр как LONGVARCHAR и использовать явное преобразование типов в запросах. MS SQL Server поддерживает только преобразования LONGVARCHAR => * CHAR . Для конвертации мне пришлось использовать такие вещи, как CAST(CAST(:number AS varchar) AS INTEGER) или CAST(CAST(:birthdate AS varchar) AS datetime). Это плохо, некрасиво и, вероятно, подорвать производительность, но работает .

0 голосов
/ 23 сентября 2013

В моем случае у меня был вызов хранимой процедуры, которая возвращает записи ... но с некоторыми вставками в ней ... Мне удалось заставить ее работать, добавив:

SET NOCOUNT ON

Inв вашем случае вставки это может быть аналогично, поскольку MSSQL выводит результат вставки, но PDO его не понимает.

Выполнение приведения, как вы сказали, не сработало для меня.

Пример того, как воспроизвести поведение:

create procedure sptest 
    @var int
as
begin 
    create table #tmp (var int)
    insert into #tmp values (@var)
    select * from #tmp
end

И код PHP:

$query = "exec sptest @var=:var";
$dbh = new PDO (SQLSVR_DRIVER);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$rs = $dbh->prepare($query);
$rs->bindParam('var', 1, PDO::PARAM_INT);
$rs->execute();
while ($row = $rs->fetch(PDO::FETCH_ASSOC))
    var_dump($row);

Исправление:

create procedure sptest 
    @var int
as
begin 
    set nocount on
    create table #tmp (var int)
    insert into #tmp values (@var)
    select * from #tmp
end

Вот и все!

...