一尘不染

从PDO准备好的语句获取原始SQL查询字符串

mysql

在准备好的语句上调用PDOStatement :: execute()时,有没有办法使原始SQL字符串执行?对于调试目的,这将非常有用。


阅读 392

收藏
2020-05-17

共1个答案

一尘不染

我假设您的意思是您想要最终的SQL查询,并将参数值插入其中。我知道这对调试很有用,但是它不是准备好的语句的工作方式。参数不会在客户端与预准备的语句组合,因此PDO绝对不能访问与其参数组合的查询字符串。

当您执行prepare()时,SQL语句将发送到数据库服务器,而当您执行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()时发送整个查询。
这不是真正的准备查询。 通过在execute()之前将变量插值到SQL字符串中,可以避免准备查询的好处。


来自@afilina的评论:

否,文本SQL查询在执行期间 不会 与参数组合。因此,PDO没有任何东西可以向您显示。

在内部,如果您使用PDO ::
ATTR_EMULATE_PREPARES,则PDO会在执行准备和执行之前复制SQL查询并向其中插入参数值。但是PDO不会公开此修改后的SQL查询。

PDOStatement对象具有属性$ queryString,但这仅在PDOStatement的构造函数中设置,并且在用参数重写查询时不会更新该属性。

对于PDO来说,要求他们公开重写的查询将是合理的功能请求。但是,除非您使用PDO ::
ATTR_EMULATE_PREPARES,否则即使那样也不会给您“完整”的查询。

这就是为什么我显示了上面使用MySQL服务器的常规查询日志的解决方法的原因,因为在这种情况下,即使是带有参数占位符的准备好的查询也会在服务器上重写,并将参数值回填到查询字符串中。但这仅在日志记录期间完成,而不在查询执行期间完成。

2020-05-17