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++非类型模板参数
对于函数模板与类模板,模板参数并不局限于类型,普通值也可以作为模板参数.在基于类型参数的模板中,你定义了一些具体的细节来加以确定代码,直到代码被调用时这些细节才被真正的确定.但是在这里,我们面对的是这 ...
随机推荐
- python中的构造函数和构造函数和析构函数的作用
构造函数和构造函数和析构函数都属于python中的特殊方法 其中的“__del__”就是一个析构函数了,当使用del 删除对象时,会调用他本身的析构函数,另外当对象在某个作用域中调用完毕,在跳出其作用 ...
- vue.js的package.json相关问题解惑
使用vue-cli创建vue.webpack项目,在项目中用到了iSlider移动端滑动插件,只在本地命令工具中npm install islider.js:提交之后,partner下载代码后一直运行 ...
- WEB网页如何让背景图片跟随可视窗口自适应大小
HTML代码 <body id="body"> <div class="info-wrapper"> <div class=&qu ...
- 融云SDK触达用户数破20亿 王者风范双倍展现
11月1日,融云SDK触达用户数突破20亿,业务增长速度及用户覆盖量再创即时通讯云领域新高.自去年11月10日公布SDK触达用户数破10亿以来,融云仅用了一年时间,便取得了触达用户数翻倍的成绩,迅猛的 ...
- Harvest of Apples
问题 B: Harvest of Apples 时间限制: 1 Sec 内存限制: 128 MB提交: 18 解决: 11[提交] [状态] [讨论版] [命题人:admin] 题目描述 Ther ...
- JavaScript -- 操作符和逻辑运算
算数操作符 + : 加 - : 减 * : 乘 / : 除 %:取余 递增和递减 1.递增 ++a与a++都是对a进行递增的操作 区别 ++a先返回递增之后的a的值 a++先返回a的原值,再返回递增之 ...
- 解决在matplotlib使用中文的问题
原生的matplotlib并不支持直接使用中文,而需要修改一下相应的文件,上网搜了下,找到一个最简洁的办法. NO.1 找到matplotlibrc文件 C:\Python26\Lib\site-pa ...
- MFC中获得各种指针概述(个人觉得是很重要的重点)
前言:这学期学习MFC(有点过时的东西),上课时,老师讲到获取当前活动指针,获取视图指针,文档指针,文档模板指针等(已晕) 后来下来真正写代码的时候发现这些几乎都是需要用到的东西,所以特此记录下,让自 ...
- cocos2dx 单张图片加密
cocos2dx 已经封装好读取加密的prv文件的方法,打开texturepacker,导入一张图片,在content protection中写入密钥,在texture format中选择prv格式 ...
- 解决 viewer.js 动态更新图片导致无法预览的问题
1.viewer.js 使用 Demo http://fengyuanchen.github.io/viewerjs/ 2.viewer.js 下载地址 https://github.com/feng ...