PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

PDO wirft keine Ausnahme mit ungebundenen Parametern (und keine Variablen in der Abfrage)

Dieses Verhalten ist mit dem aktuellen PHP (5.6.13) reproduzierbar, und die Abfrage wird nicht einmal an den Server gesendet.

Ihr Fall wird in dem Dokument beschrieben als:

0 Wert wird erwartet, 1 Wert wird gegeben und die Anweisung schlägt fehl, false zurückgegeben wird. Funktioniert bisher wie dokumentiert.

Sie können argumentieren, dass "ein Fehler ausgegeben wird " würde bedeuten, dass wenn ERRMODE_EXCEPTION eingeschaltet ist, wird eine Ausnahme ausgelöst. Das ist ein Argument, aber es ist nicht offensichtlich, dass die PDO-Entwickler dem zustimmen würden.

Aktualisieren:

Warum ist SQLCode nicht gesetzt?

Blick auf den PDO-Quellcode, insbesondere static PHP_METHOD(PDOStatement, execute) das PDO::execute() behandelt, können Sie sehen, dass alle Fehler von einem Makro behandelt werden:PDO_HANDLE_STMT_ERR()

#define PDO_HANDLE_STMT_ERR()   if (strcmp(stmt->error_code, PDO_ERR_NONE)) { pdo_handle_error(stmt->dbh, stmt TSRMLS_CC); }

Der Punkt ist, dass beim Übergeben eines gebundenen Parameters, wenn PDO keinen erwartet, die Abfrage nie an die SQL-Engine gelangt, sodass die SQL-Engine niemals die Möglichkeit hat, einen Fehler zusammen mit einem SQLSTATE

zu melden

PDO selbst erstellt keinen gefälschten SQLSTATE alleine, zumindest nein in diesem Fall, also stmt->error_code bleibt bei PDO_ERR_NONE das ist "00000" .

Es ist verständlich, dass Sie es vorziehen würden, wenn eine Ausnahme ausgelöst wird, aber dann sollten Sie dies https://bugs.php vorschlagen. Netz

Ist es dasselbe mit MySQL?

Ja, das Root-Verhalten ist dasselbe, außer dass beim MySQL-Treiber das prepare wird sofort an die SQL-Engine gesendet. Wenn es also aufgrund einer fehlerhaften Spalte falsch ist, schlägt es früher und mit einem echten SQL-Fehler fehl. Andererseits hat der PgSQL-Treiber eine andere Implementierung, die dazu führt, dass er das serverseitige prepare aufschiebt . Dieses spezielle Verhalten wird ausführlich unter PHP Postgres PDO driver does not support Prepared Statement? besprochen

Wie auch immer, hier ist ein Fall mit MySQL, der meine Erklärung demonstriert, nämlich:

  • Die Abfrage erwartet 0 Parameter, 1 wird übergeben
  • $stmt->execute gibt false zurück
  • es wird keine Ausnahme ausgelöst
  • PDO::errorCode ist 00000

Code:

$link = new PDO('mysql:dbname=' . $name . ';host=' . $host, $user, $password);
$link->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

try {
    $stmt = $link->prepare("SELECT 1");
    $rc=$stmt->execute(array(1));
   if ($rc===false)
    echo "query failed, errorCode=", $link->errorCode(), "\n";
   else
    echo "query succeeded, errorCode=", $link->errorCode(), "\n";
}
catch (PDOException $e) {
    print "A PDOException has occurred";
    print $e->getMessage();
}

Ergebnis:

Was unter der Haube passiert, ist die prepare wird an den Server gesendet und ist erfolgreich, aber execute Schritt wird von PDO aufgrund der Nichtübereinstimmung der Parameter abgebrochen.

Hier ist ein Fall, der sich dadurch unterscheidet, dass sich die Abfrage auf eine nicht vorhandene Spalte bezieht. Ich füge einen Druck hinzu, um zu zeigen, dass $stmt->execute wird nicht einmal aufgerufen, da die Ausnahme von $stmt->prepare ausgelöst wird

Code:

$link = new PDO('mysql:dbname=' . $name . ';host=' . $host, $user, $password);
$link->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

try {
    $stmt = $link->prepare("SELECT nonexisting");
    echo "Executing query\n";
    $rc=$stmt->execute(array(1));
   if ($rc===false)
    echo "query failed, errorCode=", $link->errorCode(), "\n";
   else
    echo "query succeeded, errorCode=", $link->errorCode(), "\n";
}
catch (PDOException $e) {
  print "A PDOException has occurred";
    print $e->getMessage();
}

Ergebnis:

Beachten Sie, dass der Schritt „Abfrage wird ausgeführt“ nie stattfindet, da es sich um die prepare handelt das schlägt serverseitig fehl.

Fazit

  • Wenn die Abfrage an den Server gesendet wird, sei es in "prepare()" oder "execute()", und es ist der Server, der einen Fehler generiert, dann können wir damit rechnen, dass eine PDOException ausgelöst wird.

  • Wenn die Abfrage für einen Ausführungsschritt nicht an den Server gesendet wird, kann PDO execute() fehlschlagen (gibt false zurück), aber es wird keine Ausnahme ausgelöst und errorCode() bleibt auf 00000