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++非类型模板参数
对于函数模板与类模板,模板参数并不局限于类型,普通值也可以作为模板参数.在基于类型参数的模板中,你定义了一些具体的细节来加以确定代码,直到代码被调用时这些细节才被真正的确定.但是在这里,我们面对的是这 ...
随机推荐
- sshd_config配置注释
# $OpenBSD: sshd_config,v 1.80 2008/07/02 02:24:18 djm Exp $ # This is the sshd server system-wide c ...
- python+selenium之中类/函数/模块的简单介绍和方法调用
# coding=utf-8 class ClassA (object): string1 = "这是一个字符串." def instancefunc(self): print ( ...
- Iterator中的next()
DBExchangeMoney类: 1 package com.ch.test15; import java.sql.DriverManager; import java.sql.ResultSet; ...
- UVALive 4329 Ping pong (BIT)
枚举中间的人,只要知道在这个人前面的技能值比他小的人数和后面技能值比他小的人数就能计算方案数了,技能值大的可有小的推出. 因此可以利用树状数组,从左到右往树上插点,每个点询问sum(a[i]-1)就是 ...
- Python XML 解析
什么是 XML? XML 指可扩展标记语言(eXtensible Markup Language). XML 被设计用来传输和存储数据. XML 是一套定义语义标记的规则,这些标记将文档分成许多部件并 ...
- ReactiveCocoa入门-part1
作为一个iOS开发者,你写的每一行代码几乎都是在响应某个事件,例如按钮的点击,收到网络消息,属性的变化(通过KVO)或者用户位置的变化(通过CoreLocation).但是这些事件都用不同的方式来处理 ...
- 学习笔记(五): Feature Crosses
目录 Feature Crosses Encoding Nonlinearity Kinds of feature crosses Glossay Crossing One-Hot Vectors P ...
- cppoop作业:Inheritance+Composition 關係下的構造和析構
Inheritance+Composition 關係下的構造和析構 哪个的ctor先被调用. 父类先于组件类调用 构造函数
- CentOS7下Mysql5.7主从数据库配置
本文配置主从使用的操作系统是Centos7,数据库版本是mysql5.7. 准备好两台安装有mysql的机器(mysql安装教程链接) 主数据库配置 每个从数据库会使用一个MySQL账号来连接主数据库 ...
- python并发编程之线程(创建线程,锁(死锁现象,递归锁),GIL锁)
什么是线程 进程:资源分配单位 线程:cpu执行单位(实体),每一个py文件中就是一个进程,一个进程中至少有一个线程 线程的两种创建方式: 一 from threading import Thread ...