2010-09-30 4 views
6

Я использую следующие настройки для доступа к базе данных MS-SQL из PHP приложенияИспользуя набранные связанные параметры с PHP PDO-ODBC, UnixODBC и FreeTDS

  • RedHat Enterprise Linux 5
  • PHP 5.2. 14 с ПДО и PDO_ODBC
  • UnixODBC 2.2.11
  • FreeTDS 0.82.1.dev.20100810

Unparametrized запросы работают отлично. Единственная проблема заключается в том, чтобы закрыть курсор на отдельных операторах результата (с помощью 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 «Driver не поддерживает эту функцию»). Таким образом, unixODBC продолжается без правильного ввода.

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

+0

Пока кто-то не сможет дать вам реальное (конкретное) решение, вы можете попробовать '$ PDO-> setAttribute (PDO :: ATTR_EMULATE_PREPARES, true);' как обходной путь, чтобы вы могли хотя бы продолжить разработку ;-) – VolkerK

+0

Печально , при использовании $ PDO-> setAttribute (PDO :: ATTR_EMULATE_PREPARES, true) я получаю еще одну приятную ошибку: «SQLSTATE [IM001]: драйвер не поддерживает эту функцию: драйвер не поддерживает атрибуты установки». –

ответ

5

В списке рассылки FreeTDS я получил confirmation that SQLDescribeParam is not supported in FreeTDS. Но когда SQLDescribeParam не поддерживается, PDO_ODBC is to blame для использования LONGVARCHAR (т. Е. Текст).

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

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

+0

на окнах, используя собственный DSN-клиент pdo-> odbc-> sql и используя литье из varchar в соответствующий тип данных, по-прежнему увеличивает производительность 2x-100x по сравнению с использованием PDO-> ms sqlsrv php-драйверов. – AndrewPK

+0

Если вы используете это решение, имейте в виду, что MS SQL будет правильно обрезать данные длиной 30, если только длина типа данных не указана в 'CAST'. Дополнительную информацию см. На странице https://msdn.microsoft.com/en-ca/library/ms187928.aspx#Anchor_14. – sdsmith

6

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

Мне удалось решить эту проблему, изменив мою версию TDS с 7.1 до 7.2. Я больше не испытываю никаких проблем.

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

+0

Спасибо тонну! : D – Dominick

+0

Огромное вам спасибо ... я уже сдался. Теперь он работает отлично. То, что я делал неправильно, - это версия TDS. У меня было 8.0 в моем tds config, но 7.2 ist последнее. –

0

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

SET NOCOUNT ON 

В вашем это может быть похоже, так как 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 

Вот так!

Смежные вопросы