2010-09-30 12 views
6

estoy usando la siguiente configuración para acceder a una base de datos MS-SQL desde una aplicación PHPEl uso de parámetros con destino mecanografiadas con PHP DOP-ODBC, unixODBC y FreeTDS

  • RedHat Enterprise Linux 5
  • PHP 5.2. 14 con DOP y PDO_ODBC
  • unixODBC 2.2.11
  • FreeTDS 0.82.1.dev.20100810

consultas Unparametrized funcionan bien. El único problema es forzarlo a cerrar el cursor en sentencias de resultados individuales (con PDOStatment :: closeCursor) para evitar los errores "0 [FreeTDS] [SQL Server] Estado del cursor no válido (SQLSTATE = 24000)".

Pero estoy teniendo un problema importante con el parámetro vinculado escrito. Al usar código como este:

$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(); 
} 

Donde ambas columnas son INT. Obtengo el tipo "206 [FreeTDS] [SQL Server] Choque del tipo de operando: el texto no es compatible con el error int [SQLSTATE = 22018]".

En el registro de unixODBC, me sale algo así como

[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] 

Mi comprensión del registro es que unixODBC está tratando de obligar a los parámetros utilizando el tipo correcto. Pero el FreeTDS no admite la función (IM001 es 'El controlador no admite esta función'). Entonces unixODBC continúa sin tipear correctamente.

¿Alguien puede confirmar este diagnóstico o, mejor, un problema conocido con el parámetro enlazado escrito en FreeTDS? En caso afirmativo, ¿funcionan con PHP PDO y puedo configurarlo?

+0

Hasta que alguien pueda darle una solución real (específica), puede intentar '$ PDO-> setAttribute (PDO :: ATTR_EMULATE_PREPARES, true);' como solución alternativa para que al menos pueda continuar desarrollando ;-) – VolkerK

+0

Lamentablemente , cuando uso $ PDO-> setAttribute (PDO :: ATTR_EMULATE_PREPARES, true), aparece otro bonito error: "SQLSTATE [IM001]: el controlador no admite esta función: el controlador no admite atributos de configuración". –

Respuesta

5

En la lista de distribución de FreeTDS, obtuve el confirmation that SQLDescribeParam is not supported in FreeTDS. Pero cuando SQLDescribeParam no es compatible, PDO_ODBC is to blame para usar LONGVARCHAR (es decir, texto).

El mismo código trabajó en una estación de trabajo de Windows con DOP ODBC (PHP versión 5.2.9, ODBC biblioteca Win32)

Una solución para este problema a tratar a cada parámetro como LONGVARCHAR y utilizar la conversión de tipo explícita en las consultas. MS SQL Server only supports LONGVARCHAR => *CHAR conversions. Para convertir, tuve que usar algo como CAST(CAST(:number AS varchar) AS INTEGER) o CAST(CAST(:birthdate AS varchar) AS datetime). Es malo, feo y probablemente un cerdo de rendimiento, pero funciona.

+0

en windows, usando el DSN del cliente nativo pdo-> odbc-> sql y usando casting desde varchar al tipo de datos apropiado sigue siendo un aumento del rendimiento de 2x-100x sobre el uso de controladores php PDO-> ms sqlsrv. – AndrewPK

+0

Si está utilizando esta solución, tenga en cuenta que MS SQL truncará datos a una longitud de 30 a menos que se especifique una longitud de tipo de datos en el 'CAST'. Consulte https://msdn.microsoft.com/en-ca/library/ms187928.aspx#Anchor_14 para obtener más información. – sdsmith

6

Sé que este es un problema antiguo, pero quería publicar mi solución para cualquier persona que tenga el mismo problema.

Pude resolver este problema cambiando mi versión de TDS de 7.1 a 7.2. Ya no tengo problemas.

¡Espero que esto ayude!

+0

¡Muchas gracias! : D – Dominick

+0

Muchas gracias ... ya me he dado por vencido. Ahora funciona perfectamente. Lo que estaba haciendo mal fue la versión TDS. He tenido 8.0 en mi configuración de tds, pero 7.2 es la última. –

0

En mi caso, tuve una llamada a un procedimiento almacenado, que devuelve registros ... pero con algunos insertos en ella ... me las arreglé para conseguir que funcione mediante la adición:

SET NOCOUNT ON 

En su insertar caso, esto podría ser similar, ya que MSSQL genera el resultado del inserto, pero PDO no lo entiende.

Hacer el yeso como dijiste no funcionó para mí.

Un ejemplo de cómo reproducir el comportamiento:

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

Y el código 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); 

La solución es:

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

Eso es todo!

Cuestiones relacionadas