Есть ли способ выполнить необработанную строку SQL при вызове PDOStatement::execute() для подготовленного оператора? Это было бы чрезвычайно полезно для целей отладки.
Ответ 1
Я предполагаю, что вы имеете в виду, что вам нужен окончательный SQL-запрос с интерполированными в него значениями параметров. Я понимаю, что это было бы полезно для отладки, но это не совсем то, как работают подготовленные операторы. Параметры не объединяются с подготовленным оператором на стороне клиента, поэтому PDO никогда не должен иметь доступ к строке запроса вместе с параметрами. SQL-запрос отправляется на сервер базы данных при выполнении prepare(), а параметры отправляются отдельно при выполнении execute(). Общий журнал запросов MySQL показывает окончательный SQL с интерполированными значениями после выполнения функции execute(). Ниже приведена выдержка из моего общего журнала запросов. Я выполнял запросы из mysql CLI, а не из PDO, но принцип тот же.
081016 16:51:28 2 Query prepare s1 from 'select * from foo where i = ?'
2 Prepare [2] select * from foo where i = ?
081016 16:51:39 2 Query set @a =1
081016 16:51:47 2 Query execute s1 using @a
2 Execute [2] select * from foo where i = 1
Вы также можете получить желаемое, если установите атрибут PDO PDO::ATTR_EMULATE_PREPARES. В этом режиме PDO интерполирует параметры в SQL-запрос и отправляет весь запрос при выполнении execute(). Это не настоящий подготовленный запрос. Вы обойдете преимущества подготовленных запросов, интерполируя переменные в строку SQL перед выполнением execute(). Текстовый SQL-запрос не объединяется с параметрами во время выполнения. Поэтому PDO не сможет вам ничего показать. Внутренне, если вы используете PDO::ATTR_EMULATE_PREPARES, PDO делает копию SQL-запроса и интерполирует в него значения параметров перед выполнением prepare и execute. Но PDO не раскрывает этот измененный SQL-запрос. Объект PDOStatement имеет свойство $queryString, но оно устанавливается только в конструкторе PDOStatement и не обновляется, когда запрос переписывается с параметрами.
Было бы разумным запросить у PDO возможность раскрывать переписанный запрос. Но даже это не даст вам «полный» запрос, если вы не используете PDO::ATTR_EMULATE_PREPARES. Вот почему я показал выше обходной путь использования общего журнала запросов сервера MySQL, потому что в этом случае даже подготовленный запрос с заполнителями параметров переписывается на сервере, а значения параметров подставляются в строку запроса. Но это происходит только во время ведения журнала, а не во время выполнения запроса.
Ответ 2
/**
* Заменяет любые заполнители параметров в запросе на значение этого
* параметра. Полезно для отладки. Предполагает, что анонимные параметры из
* $params расположены в том же порядке, что и в $query.
*
* @param string $query sql-запрос параметров.
* @param array $params Массив параметров подстановки
* @return string Интерполированный запрос
*/
public static function interpolateQuery($query, $params) {
$keys = array();
# построить регулярное выражение для каждого параметра
foreach ($params as $key => $value) {
if (is_string($key)) {
$keys[] = '/:'.$key.'/';
} else {
$keys[] = '/[?]/';
}
}
$query = preg_replace($keys, $params, $query, 1, $count);
#trigger_error('replaced '.$count.' keys');
return $query;
}
Ответ 3
Я модифицировал метод из предыдущего ответа, чтобы включить обработку вывода массивов для операторов типа WHERE IN (?).Также добавил проверку на значение NULL и продублировал $params, чтобы фактические значения $param не изменялись.
/**
* Заменяет любые заполнители параметров в запросе на значение этого
* параметра. Полезно для отладки. Предполагает, что анонимные параметры из
* $params расположены в том же порядке, что и в $query.
*
* @param string $query sql-запрос параметров.
* @param array $params Массив параметров подстановки
* @return string Интерполированный запрос
*/public function interpolateQuery($query, $params) {
$keys = array();
$values = $params;
# построить регулярное выражение для каждого параметра
foreach ($params as $key => $value) {
if (is_string($key)) {
$keys[] = '/:'.$key.'/';
} else {
$keys[] = '/[?]/';
}
if (is_string($value))
$values[$key] = "'" . $value . "'";
if (is_array($value))
$values[$key] = "'" . implode("','", $value) . "'";
if (is_null($value))
$values[$key] = 'NULL';
}
$query = preg_replace($keys, $values, $query);
return $query;
}
Ответ 4
Решение состоит в том, чтобы корректно поместить ошибку в запрос и вывести сообщение об ошибке:
// Соединение с базой данных
$co = new PDO('mysql:dbname=myDB;host=localhost','root','');
// разрешаем выводить ошибки при каждом их появлении
$co->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// создаем наш подготовленный отчет
$stmt = $co->prepare("ELECT * FROM Person WHERE age=:age"); //I removed the 'S' of 'SELECT'
$stmt->bindValue(':age','18',PDO::PARAM_STR);
try {
$stmt->execute();
} catch (PDOException $e) {
echo $e->getMessage();
}
Стандартный вывод:
SQLSTATE[42000]: Syntax error or access violation: [...] near 'ELECT * FROM Person WHERE age=18' at line 1
Важно отметить, что здесь выводятся только первые 80 символов запроса.

Web