2010-09-30 6 views
6

ich das folgende Setup bin mit 5.2 eine MS-SQL-Datenbank zuzugreifen aus einer PHP-AnwendungMit getippt gebunden Parameter mit PHP PDO-ODBC, unixODBC und FreeTDS

  • RedHat Enterprise Linux 5
  • PHP. 14 mit PDO und PDO_ODBC
  • unixODBC 2.2.11
  • FreeTDS 0.82.1.dev.20100810

Unparametrized Abfragen funktionieren. Das einzige Problem besteht darin, den Cursor auf einzelne Ergebnisanweisungen zu schließen (mit PDOStatment :: closeCursor), um Fehler "0 [FreeTDS] [SQL Server] Ungültiger Cursor (SQLSTATE = 24000)" zu vermeiden.

Aber ich habe ein großes Problem mit typisierten gebundenen Parameter. Bei Verwendung von Code wie folgt:

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

Wo beide Spalten INT sind. Ich erhalte den Fehler "206 [FreeTDS] [SQL Server] Operand type": text ist nicht kompatibel mit int [SQLSTATE = 22018] "error.

Im unixODBC log, erhalte ich so etwas wie

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

Mein Verständnis des Stammes ist, dass unixODBC versucht, die Parameter zu binden, um die richtige Art verwenden. Aber die FreeTDS unterstützt die Funktion nicht (IM001 ist 'Treiber unterstützt diese Funktion nicht'). Also unixODBC weiter ohne richtig tippen.

Kann jemand diese Diagnose bestätigen oder, besser, ein bekanntes Problem mit typisierten gebundenen Parametern in FreeTDS? Wenn ja, funktionieren sie mit PHP-PDO und wo kann ich es konfigurieren?

+0

Bis jemand Ihnen eine echte (spezifische) Lösung geben kann, sollten Sie '$ PDO-> setAttribute (PDO :: ATTR_EMULATE_PREPARES, true);' als Workaround versuchen, damit Sie zumindest weiter entwickeln können ;-) – VolkerK

+0

Leider Wenn ich $ PDO-> setAttribute (PDO :: ATTR_EMULATE_PREPARES, true) benutze, erhalte ich einen weiteren schönen Fehler: "SQLSTATE [IM001]: Treiber unterstützt diese Funktion nicht: Treiber unterstützt die Einstellung von Attributen nicht". –

Antwort

5

Auf der FreeTDS Mailingliste habe ich die confirmation that SQLDescribeParam is not supported in FreeTDS. Aber wenn SQLDescribeParam nicht unterstützt wird, PDO_ODBC is to blame für die Verwendung von LONGVARCHAR (dh Text).

Der gleiche Code arbeitete auf einer Windows-Workstation mit PDO ODBC (PHP Version 5.2.9, ODBC-Bibliothek Win32)

Eine Abhilfe für dieses Problem jeden Parameter als LONGVARCHAR zu behandeln und explizite Typumwandlung in Abfragen verwenden. MS SQL Server only supports LONGVARCHAR => *CHAR conversions. Um zu konvertieren, musste ich etwas wie CAST(CAST(:number AS varchar) AS INTEGER) oder CAST(CAST(:birthdate AS varchar) AS datetime) verwenden. Es ist schlecht, hässlich und wahrscheinlich ein Performance-Schwein, aber es funktioniert.

+0

auf Windows, mit pdo-> odbc-> sql nativen Client DSN und die Umwandlung von Varchar auf den entsprechenden Datentyp ist immer noch eine 2x-100x Leistungssteigerung gegenüber PDO-> ms sqlsrv php Treiber. – AndrewPK

+0

Wenn Sie diese Lösung verwenden, beachten Sie, dass MS SQL die Daten mit einer Länge von 30 abschneidet, es sei denn, eine Datentypenlänge ist in "CAST" angegeben. Weitere Informationen finden Sie unter https://msdn.microsoft.com/en-ca/library/ms187928.aspx#Anchor_14. – sdsmith

6

Ich weiß, dass dies ein altes Problem ist, aber ich wollte meine Lösung für jeden mit dem gleichen Problem posten.

Ich konnte dieses Problem beheben, indem ich meine TDS-Version von 7.1 zu 7.2 änderte. Ich habe keine Probleme mehr.

Hoffentlich hilft das!

+0

Vielen Dank! : D – Dominick

+0

Vielen Dank ... Ich wurde bereits aufgegeben. Jetzt funktioniert es perfekt. Was ich falsch gemacht habe, war die TDS-Version. Ich habe 8.0 in meiner tds Config gehabt, aber 7.2 ist das späteste. –

0

In meinem Fall hatte ich einen Anruf an eine gespeicherte Prozedur, die Datensätze zurückgibt ... aber mit einigen Einsätzen in ihm ... Ich konnte es Arbeit erhalten durch Zugabe von:

SET NOCOUNT ON 

In Ihrem Insert Case, dies könnte ähnlich sein, da MSSQL das Ergebnis der Einfügung ausgibt, aber PDO es nicht versteht.

Die Besetzung, wie Sie gesagt haben, funktionierte nicht für mich.

Ein Beispiel dafür, wie das Verhalten zu reproduzieren:

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

Und den PHP-Code:

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

Das Update ist:

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

Das ist es!