PDO 使用prepared statement 预处理LIMIT等非表字段参数

时间:2022-09-06 11:53:03

由于一些驱动不支持原生的预处理语句,因此PDO可以完全模拟预处理。PDO的模拟预处理是默认打开的,即便MYSQL驱动本身支持预处理,在默认打开的状态下,PDO是不会用到MYSQL本身提供的预处理功能。PDO会把SQL语句进行模拟预处理之后会发送给MYSQL一个原始的SQL语句。

而这种方式很诡异的是如果预处理的SQL语句中需要处理的字段不是表中的字段时,PDO会对绑定的参数无脑添加单引号,因而导致了异常或查询不到结果。

解决这种问题的方法是设置PDO不去模拟预处理,而是交给MYSQL本身去做。方法是设置PDO的参数 ATTR_EMULATE_PREPARES 为 false

或者,在绑定参数时,显式的把参数类型传递给绑定方法。

原文 http://jpauli.github.io/2014/07/21/php-and-mysql-communication-mysqlnd.html

PDO is different from mysql/mysqli because it has been designed to support other RDBMS than MySQL. In this fact, this extension is imperfect and tries to guess many things from the user, which could lead to strange behaviors. Let me explain.

PDO ships with an SQL parser which is to emulate prepared statements if the underlying RDBMS doesn't support them. The problem is that this layer behaves differently from the RDBMS' one, when present. If you take the MySQL case, the PDO emulation layer is active by default when you prepare a query, and this one will never hit MySQL prepared statement layer which is probably not what you want. In fact, PDO's code will parse and build your query, never communicating with MySQL about this (by default). This is weird. Turn this emulation layer off as soon as you can :

/* Disable PDO prepared statements emulation */
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0); /* This is exactly the same, take care, we really pass 0 here and not 1 */
$pdo->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);

When the emulation layer is disabled, you rely with a true prepared statement. When it is enabled, PDO will take care of constructing the query for you, and will send a traditionnal normal query to the RDBMS. This has lots of drawbacks and can lead to strange behaviors. As PDO doesn't know anything about tables' columns, its emulation layer will quote every parameter when bound to an emulated prepared statement, even the parameter of integer type, which don't need such quoting. This leads to errors :

$stmt = $pdo->prepare("SELECT user_id FROM users LIMIT :limit");
$stmt->bindValue('limit', 10);
$stmt->execute(); $result = $stmt->fetch();
var_dump($result); /*
PHP Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for the right syntax to use near ''10''
*/

We see from this error message that PDO escaped my 'limit' parameter quoting it wrongly, as it is an integer and doesn't need that. Let's try again with no emulation layer, relying only on the RDBMS layer (MySQL here):

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0); /* Disable prepared statement emulation layer */
$stmt = $pdo->prepare("SELECT user_id FROM users LIMIT :limit"); /* A true prepare() will be sent to the RDBMS, it has to support it */
$stmt->bindValue('limit', 10);
$stmt->execute(); $result = $stmt->fetch();
var_dump($result);
/*
array(4) {
["user_id"]=>
string(7) "18"
[0]=>
string(7) "18"
}
*/

Things now work. If you would want to still use the emulation layer, you'd then need to precise to PDO that your parameter is of type integer, like this :

/* Tells the PDO prepared statement emulation layer that this column is of type integer (SQL type) */
$stmt->bindValue('limit', 10, PDO::PARAM_INT);

PDO 使用prepared statement 预处理LIMIT等非表字段参数的更多相关文章

  1. java-mysql(2) Prepared statement

    上一篇学习了java如何链接配置mysql,这篇学习下java如何处理sql预处理语句(PreparedStatement),首先是一个sql预处理的例子: package core; import ...

  2. cannot insert multiple commands into a prepared statement问题原因及解决办法

    问题是这样,我在对数据库进行写操作(添加.删除.修改)时,我想同时删除两个表中的两条关联数据,像这样 let sql = ` DELETE FROM bridge_parts WHERE id = $ ...

  3. Postgre cannot insert multiple commands into a prepared statement

    悲剧... FireDAC连接Postgre数据库, 使用默认的属性, 一次执行多条SQL的时候, 会报"cannot insert multiple commands into a pre ...

  4. Postgresql:prepared statement "S_1" already exists

    近期由于业务需要和一些json的存储查询需要,把新的应用切到pgsql上来,刚刚切好,是可以正常使用的,但是偶尔会来一下 java连接pgsql 偶尔出现 这个错.   org.postgresql. ...

  5. 对PostgreSQL的prepared statement的深入理解

    看官方文档: http://www.postgresql.org/docs/current/static/sql-prepare.html PREPARE creates a prepared sta ...

  6. 对Prepared Statement 是否可以防止 SQL Injection 的实验

    代码: import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; im ...

  7. Java向PostgreSQL发送prepared statement 与 libpq 向PostgreSQL发送prepared statement之比较:

    Java 代码,在数据库端,并没有当成 prepared statetment 被处理. C代码通过libpq 访问数据库端,被当成了 prepared statement 处理.也许是因Postgr ...

  8. mysql 执行存储过程报错Prepared statement needs to be re-prepared

    今日思语:不喜欢再见 说再见,因为有时明知道下一次再见已是遥遥无期或是不再见 错误如下: ERROR 1615 (HY000) at line 406 in file: 'update-mysql.s ...

  9. C++非类型模板参数

    对于函数模板与类模板,模板参数并不局限于类型,普通值也可以作为模板参数.在基于类型参数的模板中,你定义了一些具体的细节来加以确定代码,直到代码被调用时这些细节才被真正的确定.但是在这里,我们面对的是这 ...

随机推荐

  1. Sublime Text 2下搭建Python环境常见错误

    Sublime Text 2下搭建Python环境时,最容易出的错误就是Python环境配置错误,导致build(Ctrl+B)后没有任何反应. 关于Python编程环境的配置,网上很容易搜索到.先默 ...

  2. excel、csv、txt文件数据读取

    /// <summary> /// 读取Excel表每一行第一列的字符串集合 /// </summary> /// <param name="filePath& ...

  3. Fidder模拟Post请求

    背景 最近想用fidder模拟post请求,怎么都传值失败,发现写Composer => Request Body中写的内容,总是无法映射到mvc的action参数上.百度一番,发现如下解决方案 ...

  4. Linux基本操作命令总结

    1.命令基本格式     root用户:[root@localhost ~] # 或者普通用户:[hadoop@localhost ~] $     用户@主机名 目录 [#|$]管理员类型     ...

  5. 网站不能访问(httperrLog【Timer&lowbar;MinBytesPerSecond】【Timer&lowbar;ConnectionIdle】)(转载)

    在\LogFiles\HTTPERR的日志(C:\Windows\System32\LogFiles\HTTPERR)中发现了大量Timer_MinBytesPerSecond,Timer_Conne ...

  6. 1064&period; Complete Binary Search Tree

    二叉排序树: http://www.patest.cn/contests/pat-a-practise/1064 #include <iostream> #include <vect ...

  7. 深入剖析Java编程中的中文问题及建议最优解决方法

    摘录自:http://fafeng.blogbus.com/logs/3062998.html http://www.blogbus.com/fafeng-logs/3063006.html 深入剖析 ...

  8. LeetCode算法题-Reverse Bits(Java实现)

    这是悦乐书的第185次更新,第187篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第44题(顺位题号是190).给定32位无符号整数,求它的反转位.例如: 输入:4326 ...

  9. CuratorBarrier

    一.DistributedDoubleBarrier 同时开始,同时结束 package bjsxt.curator.barrier; import java.util.Random; import ...

  10. js里面的全局属性 全局对象 全局函数

    1)全局属性 Infinity   typeof Infinity        //number NaN typeof NaN           //number undefined       ...