PDO 使用prepared statement 预处理LIMIT等非表字段参数
由于一些驱动不支持原生的预处理语句,因此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等非表字段参数的更多相关文章
- java-mysql(2) Prepared statement
上一篇学习了java如何链接配置mysql,这篇学习下java如何处理sql预处理语句(PreparedStatement),首先是一个sql预处理的例子: package core; import ...
- cannot insert multiple commands into a prepared statement问题原因及解决办法
问题是这样,我在对数据库进行写操作(添加.删除.修改)时,我想同时删除两个表中的两条关联数据,像这样 let sql = ` DELETE FROM bridge_parts WHERE id = $ ...
- Postgre cannot insert multiple commands into a prepared statement
悲剧... FireDAC连接Postgre数据库, 使用默认的属性, 一次执行多条SQL的时候, 会报"cannot insert multiple commands into a pre ...
- Postgresql:prepared statement "S_1" already exists
近期由于业务需要和一些json的存储查询需要,把新的应用切到pgsql上来,刚刚切好,是可以正常使用的,但是偶尔会来一下 java连接pgsql 偶尔出现 这个错. org.postgresql. ...
- 对PostgreSQL的prepared statement的深入理解
看官方文档: http://www.postgresql.org/docs/current/static/sql-prepare.html PREPARE creates a prepared sta ...
- 对Prepared Statement 是否可以防止 SQL Injection 的实验
代码: import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; im ...
- Java向PostgreSQL发送prepared statement 与 libpq 向PostgreSQL发送prepared statement之比较:
Java 代码,在数据库端,并没有当成 prepared statetment 被处理. C代码通过libpq 访问数据库端,被当成了 prepared statement 处理.也许是因Postgr ...
- mysql 执行存储过程报错Prepared statement needs to be re-prepared
今日思语:不喜欢再见 说再见,因为有时明知道下一次再见已是遥遥无期或是不再见 错误如下: ERROR 1615 (HY000) at line 406 in file: 'update-mysql.s ...
- C++非类型模板参数
对于函数模板与类模板,模板参数并不局限于类型,普通值也可以作为模板参数.在基于类型参数的模板中,你定义了一些具体的细节来加以确定代码,直到代码被调用时这些细节才被真正的确定.但是在这里,我们面对的是这 ...
随机推荐
- 51nod 1431 快乐排队
题目来源: CodeForces 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 收藏 关注 有一群人在排队,如果某个人想排到前面去,可以花一元钱给直接站在他前 ...
- Java异常之RuntimeException
人生不如意十有八九.在打Core Java里面的例子的时候总是一遍就过,但是实际上只要是自己想着动手去打造自己想要的东西,异常的状况也是十有八九的. 在Java中会使用异常处理的错误捕获机制处理这些异 ...
- python——动态类型
1.变量,对象,引用 变量是一个系统表的元素,拥有指向对象的连接的空间: 对象是分配的一块内存: 引用是自动形成的从变量到对象的指针: 类型属于对象,而不是变量 a=3; 变量a变成对象3的一个引用 ...
- UVA 1623 Enther the Dragon 神龙喝水 (贪心)
贪心,每次遇到一个满水的湖要下暴雨的时候,就往前找之前最后一次满水之后的第一个没有下雨的且没有被用掉天day1. 因为如果不选这day1,那么之后的湖不一定能选上这一天.如果这一天后面还有没有下雨的天 ...
- Collatz Conjecture
4981: Collatz Conjecture 时间限制: 6 Sec 内存限制: 128 MB提交: 213 解决: 23[提交][状态][讨论版][命题人:admin] 题目描述 In 19 ...
- CPP-网络/通信:用CMarkup类操纵XML
首先到http://www.firstobject.com/下载CMarkup教学版,解压后里面是一个DEMO,将Markup.h .cpp拷贝并添加到工程中,第一次编译可能会出现预编译错误,解决 ...
- 两个对象值转换的方法(BeanUtils.copyProperties与JSONObject.parseObject对比)
将源对象赋值到目标对象方法: 方法一:BeanUtils.copyProperties(源对象, 目标对象); //org.springframework.beans.BeanUtils 方法二:目标 ...
- 用户价值模型 CITE :https://www.jianshu.com/p/34199b13ffbc
RFM用户价值模型的原理和应用 ▌定义 在众多的用户价值分析模型中,RFM模型是被广泛被应用的:RFM模型是衡量客户价值和客户创利能力的重要工具和手段,在RFM模式中,R(Recency)表示客户购 ...
- (71)Received empty response from Zabbix Agent问题解决
刚接触zabbix新手少部分会出现如下错误: Received empty response from Zabbix Agent at [192.168.1.2]. Assuming that age ...
- linux的一些权限的操作 chmod
u ---属主 g ---用户组 o ---其他组 + ----赋予权限 - ----取消权限 = ----赋予权限并取消以前的权限 r = 4 //读 w =2 //写 x =1 //执 ...