Я получаю ошибки «Строковые данные, правильное усечение» из PHP с использованием ODBC и подключением к экземпляру Microsoft SQL Server 2008R2
Я использую PHP 5.3.3 на коробке CentOS 6.2, подключаясь к экземпляру Microsoft SQL Server 2008R2. Соединение работает, и я могу получать данные, если мои запросы не содержат параметров. Когда я добавляю параметры, я получаю сообщение об ошибке «Строковые данные, правильное усечение».
Вот пример кода:
<?php
$dbh = new PDO("odbc:myDSN", 'myUsername', 'myPassword');
$testCase = 1;
switch ($testCase) {
case 1:
// This case fails with this error:
// Error 22001: [Microsoft][ODBC Driver 11 for SQL Server]String data, right truncation (SQLExecute[0] at /builddir/build/BUILD/php-5.3.3/ext/pdo_odbc/odbc_stmt.c:254)
$query = "select * from [myDatabase].[sys].[objects] WHERE (([name]=?))";
$stmt = $dbh->prepare($query);
$param1 = 'testtable1';
$stmt->bindParam(1, $param1, PDO::PARAM_STR); // Note: '1' is correct; it should not be '0'
break;
case 2:
// This case works properly
$query = "select * from [myDatabase].[sys].[objects] WHERE (([name]='testtable1'))";
$stmt = $dbh->prepare($query);
break;
}
$execResult = $stmt->execute();
if ($execResult) {
print "Success!\n";
} else {
$errorInfo = $stmt->errorInfo();
print "Error " . $stmt->errorCode() . ": " . $errorInfo[2] . "\n";
}
$rowCount = 0;
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo "Row " . $rowCount . ":\n";
foreach ($row as $key => $value) {
printf(" %-20s %s\n", $key, $value);
}
$rowCount++;
}
Обратите внимание, что оба тестовых примера в приведенном выше коде должны выполнять одно и то же. В тестовом примере 1 используются параметры (как должен делать весь код), а в тестовом примере 2 явно указывается соответствующее значение в запросе SQL. Тестовый пример 2 работает. Контрольный пример 1 не делает. Я попытался заменить «bindParam ()» на «bindValue ()», но это не имеет никакого эффекта. Я также пытался использовать именованные параметры (например,:name
) вместо позиционных параметров, но это также не имеет никакого эффекта. Я попытался добавить явный аргумент длины в bindParam () (используяstrlen($param1)
в качестве значения), но это дает действительно странное сообщение об ошибке (Incorrect syntax near 'OUTPUT'
), и я могу только предположить, что я делаю это неправильно. Целочисленные параметры работают правильно. Сбой только строковых параметров.
Есть идеи, почему это не работает?
Конечно, возможно, что есть ошибка в драйвере ODBC, или что он не совместим с моей версией PHP, или какое-то количество подобных проблем, но я надеюсь, что я просто неправильно использую API.
Редактировать:
По предложению Анды Янку я углубился в SQL Server Profiler. При отслеживании случай 1 дает две почти идентичные записи, одну из классаSQL:BatchStarting
и один из классаSQL:BatchCompleted
оба содержат текст:
set fmtonly on select [name] from [myDatabase].[sys].[objects] where 1=2 set fmtonly off
Случай 2 дает две записи, обе из класса "RPC: Завершено". Первый содержит текст:
declare @p1 int
set @p1=1
exec sp_prepexec @p1 output,NULL,N'select * from [myDatabase].[sys].[objects] WHERE (([name]=''testtable1''))'
select @p1
а второй содержит текст:
exec sp_unprepare 1
Обновить:
В отчаянном шаге, надеясь, что может быть какая-то проблема с переносом новой версии unixODBC в существующую версию PHP, я перекомпилировал PHP из исходного кода. На CentOS это оказывается сложнее, чем вы думаете. К сожалению, это не имело никакого эффекта. Все те же ошибки.