PDO не выбрасывает исключение с несвязанными параметрами (и без переменных в запросе)
так что я понятия не имею, что здесь происходит
$link = new PDO('pgsql: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 s.*, d.invalid_column FROM students s ORDER BY s.student_id");
$stmt->execute(array(1));
}
catch (PDOException $e) {
print $e->getMessage();
}
когда я запускаю этот небольшой пример кода, я ожидаю, что будет создано исключение (как d.invalid_column не является реальным столбцом, и я передаю параметры, которые не могут быть связаны), но единственное, что происходит, - это то, что execute возвращает false и ничего больше. Кроме того,$stmt->errorInfo()
пусто, а код 00000
что затрудняет добавление правильного исключения за пределы чего-то супер общего с ничем другим для журналов помогите мне в отслеживании ошибок, когда некоторые конечные пользователи сообщают об ошибке.
если я добавлю один'?"где-то к запросу брошено правильное выполнение (это d.invalid_column
не является допустимым столбцом), даже если я добавляю больше параметров, которые ни к чему не привязываются.
Итак, способы заставить этот запрос правильно ошибиться:
1) Избавиться от всех параметров
2) Добавить '? на запрос
это просто ошибка в PDO или что?
изменить: Установки, которые будут бросать исключение (недопустимый столбец):
$stmt = $link->prepare("SELECT s.*, d.invalid_column, ? FROM students s ORDER BY s.student_id");
$stmt->execute(array(1));
$stmt = $link->prepare("SELECT s.*, d.invalid_column, ? FROM students s ORDER BY s.student_id");
$stmt->execute(array(1,2,3));
$stmt = $link->prepare("SELECT s.*, d.invalid_column, ? FROM students s ORDER BY s.student_id");
$stmt->execute();
$stmt = $link->prepare("SELECT s.*, d.invalid_column FROM students s ORDER BY s.student_id");
$stmt->execute();
это только тогда, когда у меня нет ?
в моем запросе и передать что-то execute()
что вещи просто терпят неудачу молча и без объяснения от PDO.
1 ответов
это поведение воспроизводимо с текущим PHP (5.6.13), и запрос даже не отправляется на сервер.
ваш случай описан в док as:
вы не можете связать больше значений, чем указано; если существует больше ключей в input_parameters, чем в SQL, указанном в PDO:: prepare (), затем оператор завершится ошибкой, и будет выдана ошибка.
ожидается значение 0, задано значение 1, и утверждение не выполняется,false
возвращается. Пока работает, как документировано.
вы можете возразить, что "выдается ошибка " означало бы, что когда ERRMODE_EXCEPTION
включено, будет создано исключение. Это аргумент, но не очевидно, что разработчики PDO согласятся с ним.
обновление:
почему SQLCode
не установлен?
глядя на исходный код PDO, в частности static PHP_METHOD(PDOStatement, execute)
что ручками PDO:: execute (), вы можете видеть, что все ошибки обрабатываются макросом: 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); }
дело в том, что при передаче связанного параметра, когда PDO не ожидал none, запрос никогда не попадает в SQL engine, поэтому SQL engine никогда не имеет возможности сообщить об ошибке, сопровождаемой SQLSTATE
PDO сам по себе не создает подделку SQLSTATE
самостоятельно, по крайней мере, нет в этом случае, так чтоstmt->error_code
остается PDO_ERR_NONE
что это "00000"
.
это понятно, что вы предпочли бы исключение, но тогда вы должны предложить это https://bugs.php.net
то же самое с MySQL ?
да, поведение корня такое же, за исключением того, что с драйвером MySQL prepare
отправляется немедленно в SQL engine, поэтому, если это неверно из-за плохого столбца, он терпит неудачу раньше и с реальной ошибкой SQL. С другой стороны, драйвер PgSQL имеет другая реализация, которая заставляет его отложить серверную сторону prepare
. Это конкретное поведение подробно обсуждается в драйвер PHP Postgres PDO не поддерживает подготовленный оператор?
во всяком случае, вот случай с MySQL, который демонстрирует мое объяснение, то есть:
- запрос ожидает 0 параметр, 1 задается
-
$stmt->execute
возвращает false - никаких исключений не возникает
- PDO:: код ошибки
00000
код:
$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();
}
результат:
ошибка запроса, errorCode=00000
что происходит под капотом, что prepare
отправляется на сервер и успешно, но execute
шаг отменяется PDO из-за несоответствия параметров.
вот случай, который отличается тем, что запрос ссылается на несуществующий столбец. Я добавляю печать, чтобы показать, что $stmt->execute
даже не называется, Как исключения $stmt->prepare
код:
$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();
}
результат:
A PDOException has occurredSQLSTATE[42S22]: столбец не найден: 1054 Неизвестный столбец "несуществующий" в "списке полей"
обратите внимание, как шаг "выполнение запроса" никогда не происходит, потому что это prepare
это не удается, на стороне сервера.
вывод
при отправке запроса сервер, будь то в prepare () или execute (), и это сервер, который генерирует ошибку, тогда мы можем ожидать, что будет вызвано исключение PDOException.
когда запрос не отправляется на сервер для выполнения шага, то PDO execute () может завершиться ошибкой (возвращает false), но исключение не создается и
errorCode()
остается00000