PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

PDO non genera eccezioni con parametri non associati (e nessuna variabile nella query)

Questo comportamento è riproducibile con l'attuale PHP (5.6.13) e la query non viene nemmeno inviata al server.

Il tuo caso è descritto in il documento come:

È previsto un valore 0, viene fornito un valore 1 e l'istruzione non riesce, false essere restituito. Finora, funziona come documentato.

Potresti obiettare che "viene emesso un errore " implicherebbe che quando ERRMODE_EXCEPTION è attivo, verrebbe generata un'eccezione. Questo è un argomento, ma non è ovvio che gli sviluppatori PDO sarebbero d'accordo con esso.

Aggiornamento:

Perché SQLCode non è impostato?

Osservando il codice sorgente PDO, in particolare static PHP_METHOD(PDOStatement, execute) che gestisce PDO::execute(), puoi vedere che tutti gli errori sono gestiti da una macro: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); }

Il punto è che, quando si passa un parametro legato quando PDO non ne prevedeva nessuno, la query non arriva mai al motore SQL, quindi il motore SQL non ha mai l'opportunità di segnalare un errore accompagnato da un SQLSTATE

PDO stesso non crea un falso SQLSTATE da solo, almeno no in quel caso, quindistmt->error_code rimane a PDO_ERR_NONE che è "00000" .

È comprensibile che tu preferisca che venga sollevata un'eccezione, ma dovresti suggerirlo a https://bugs.php. netto

È lo stesso con MySQL?

Sì, il comportamento di root è lo stesso tranne che con il driver MySQL, il prepare viene inviato immediatamente al motore SQL, quindi se non è corretto a causa di una colonna danneggiata, fallisce prima e con un vero errore SQL. D'altra parte, il driver PgSQL ha una diversa implementazione che fa rinviare la prepare lato server . Questo comportamento particolare è discusso in dettaglio in Il driver PHP Postgres PDO non supporta l'istruzione preparata?

Ad ogni modo, ecco un caso con MySQL che dimostra la mia spiegazione, ovvero:

  • la query prevede 0 parametro, viene fornito 1
  • $stmt->execute restituisce falso
  • nessuna eccezione viene sollevata
  • PDO::errorCode è 00000

Codice:

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

Risultato:

Quello che succede sotto il cofano è che il prepare viene inviato al server e riesce, ma execute il passaggio viene annullato da PDO a causa della mancata corrispondenza dei parametri.

Ecco un caso che si differenzia per il fatto che la query fa riferimento a una colonna inesistente. Sto aggiungendo una stampa per mostrare che $stmt->execute non viene nemmeno chiamato, poiché l'eccezione viene sollevata da $stmt->prepare

Codice:

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

Risultato:

Nota come il passaggio "Esecuzione della query" non si verifica mai, perché è il prepare che non riesce, lato server.

Conclusione

  • quando la query viene inviata al server, sia in prepare() che in execute(), ed è il server che genera un errore, allora possiamo aspettarci che venga sollevata una PDOException.

  • quando la query non viene inviata al server per un passaggio di esecuzione, PDO execute() può fallire (restituisce false) ma non viene generata alcuna eccezione e errorCode() rimane a 00000