【原创】11. MYSQL++ 之 Quoting 与 Escaping
1. 综述
其实一看到这两个单词的时候我有点莫名其妙,可能英语没有学好,我的理解就是quoting是“引用”的意思,而Escaping是“逃脱”的意思。后来在看到了作者的TUTORIAL之后才大致明白了两者的意思。
QUOTING大白话就是为SQL语句打上单引号。考虑如下的情况
- SELECT * FROM stock WHERE item = 'Hotdog Buns'
由于中间有一个空格,所以这个单引号必不可少。
ESCAPING大白话就是转义。例如在C的printf中,为了打出引号(“),我们需要使用”\””的方式。在SQL语句中,这种情况仍然存在,下文节选自MYSQL C API中的mysql_real_escape_string的说明。
Characters encoded are NUL(ASCII 0), “\n”, “\r”, “\”, “'”, “"”, and Control-Z . (Strictly speaking, MySQL requires only that backslash and the quote character used to quote the string in the query be escaped. This function quotes the other characters to make them easier to read in log files.)
例如,下面的语句显然不行
- SELECT * FROM stock WHERE item = 'Frank's Brand Hotdog Buns'
需要改成
- SELECT * FROM stock WHERE item = 'Frank''s Brand Hotdog Buns'
在MYSQL++中,Quoting和Escaping工作都是通过mysqlpp:: Query在建立SQL语句的时候自动化生成的,而且具体的操作都被定义在了manip.h和manip.cpp中。
同时,在下文中我们可以发现,MYSQL++其实非常的聪明,他可以自动检测出哪些类型是需要进行QUOTING和ESCAPING,哪些是不需要的。即使你为他加入了“建议”QUOTING或者ESCAPING的标志,MYSQL++在内部仍然会自己选择到底做不做QUOTING和ESCAPING。
2. MYSQL++中的Quoting和Escaping的用法
先来看一下到底该怎么用这些功能
- string s = "Hotdog Buns";
- query << "SELECT * FROM stock WHERE item = " << mysqlpp::quote_only << s;
- query << "SELECT * FROM stock WHERE item = " << mysqlpp::quote << s;
可以看到,我们可以通过流式操作来生成SQL串,在需要的地方加上特殊的标志(比如上文中的mysqlpp:: quote_only和mysqlpp:: quote等,具体下文中再说)。大家可能会有疑问,为什么一定要通过这种看似ugly的方法来生成SQL串,为什么不能够直接implicit地为我们把quoting和escaping的事情做完?我在看作者的注释的时候,有这些一句话(摘自,http://tangentsoft.net/mysql++/doc/html/userman/tutorial.html#qescape)
You must use manipulators and template query flags as necessary to tell MySQL++ where quoting and escaping is necessary. It would be nice if MySQL++ could do quoting and escaping implicitly based on data type, but this isn’t possible in all cases. Since MySQL++ can’t reliably guess when quoting and escaping is appropriate, and the programmer doesn’t need to, MySQL++ makes you tell it.
在深入源代码之前,我们先来看一下MYSQL++支持哪些QUOTING和ESCAPING方式(即上面代码中的表示加载quoting和escaping的ENUM到底有多少。
类型 |
代码中的说明 |
备注 |
quote |
insert into a Query stream to single-quote and escape next item |
需要时为后一项加入必要的单引号和转义 |
quote_only |
insert into a std::ostream to single-quote next item |
需要时为后一项加入必要的单引号 |
quote_double_only |
insert into a std::ostream to double-quote next item |
需要时为后一项加入必要的双引号 |
escape |
需要时为后一项加入必要的转义 |
|
do_nothing |
insert into a std::ostream to override manipulation of next item |
下一项什么额外操作都不要做了。该操作在Template Query中有一定的作用。When used with SQLQueryParms it will make sure that it does not get formatted in any way, overriding any setting set by the template query. 具体请参看template Query相关章节。 |
ignore |
insert into a std::ostream as a dummy manipulator |
效果和do_nothing类似,只是it will not override formatting set by the template query. It is simply ignored. 具体请参看template Query相关章节。 |
3. MYSQL++中的Quoting和Escaping的实现
通过查看代码,我们可以看到上述几个选项的做法其实都差不多,所以我们主要关注最麻烦的quote,至于有一点点特殊的do_nothing与ignore放到相关章节去做吧。
再来回顾一下QUOTING和ESCAPING怎么用。
- mysqlpp:: Query query = …;
- query << "SELECT * FROM stock WHERE item = ";
- query << mysqlpp::quote << “Hotdog’s Buns”;
我的第一反应是去查看有没有mysql:: Query:: operator<<( ) 的重载方法,通过查看query.h,我发现根本没有这样的方法重载,很可惜,我没有找到
(在query.h中确实有一个全局函数
std::ostream& operator <<(std::ostream& os, Query& q) ,但是从签名和作者的注释中我们可以看到这个函数其实就是为了方便用cout 等进行输出,如cout << query;在通过这个全局函数之后的作用等效于cout << query.str();)
那么这句话为什么能够被编译通过?
原来mysqlpp:: Query继承自std::ostream,说实话,可能是因为我编程经验不够,这种用法我没有怎么见到过,更多的是利用一个delegate,然后自己手动去重载operator << 来实现类似的功能。
言归正传,有了这条线索我们可以继续向下。很显然,上述代码中的query << “SELECT …”这句,其实就是普通的ostream流处理,也就是把字符串放入到ostream自己的缓存中。那么第二句,query << mysqlpp::quote又是在做什么呢?
全局搜了一下quote是什么?
原来是个enum,所以针对query << mysqlpp::quote的用法,找到了如下的代码
又出现了一个神奇的东西——quote_type1,再去看
注意到mysqlpp:: Query继承自std::ostream,所以对于query << mysqlpp:: quote的用法,在operator << (ostream, quote_type0)中,直接就把这个query给保存在了quote_type1的ostr中。那么这个又是做什么?
注意到基本用法中的第二行query << mysqlpp::quote << “Hotdog’s Buns”,刚才说了前半段调用的是operator << (ostream, quote_type0)这个全局方法,他返回的是什么?quote_type1!所以这一行代码接下去的动作一定就是会调用operator << (quote_type1, …)。查了一下果然有!
我应该在介绍SQLTypeAdapter的时候说过,这个类型就是为了做为一个适配器来减少公共函数的数量,他还可以包罗万象,把各种数据类型都包进去。所以对于query << mysqlpp::quote << “Hotdog’s Buns”,显然还会有一步“把Hotdog’s Buns”放入到SQLTypeAdapter中的过程,具体的过程请查看相关章节。
然后就简单了,看上面的代码。
首先,看到了两个强制转换,用的都是dynamic_cast。这里先来补一下dynamic_cast和static_cast的区别。简单理解就是这两者都可以在父类和子类指针或者引用之间相互转化(即父类指针转换为子类指针,或者反之),但是static_cast一定能够成功(即使两者根本就不知父子关系,在后续调用时才会报运行时错),而dynamic_cast则会多一步检查,即检查相互转换的两者是否是可以转换的,如果不能就会返回NULL。也就是说dynamic_cast很像C#关键字as。
第二点需要关注的是SQLStream,这是一个MYSQL++自定义的类型,但是从全局搜索的结果来看,这个类型更多的是用来做测试(因为只出现在了test/manip.cpp中),所以我们可以先忽略这个类型,当然61行的操作也可以仍然psqls结果为NULL。
第三点是怎么做的quoting?显然上述代码片段的65和85行告诉了我们答案(其实就是在需要quoting的item的两边加上了 \’ 而已)。那关键是这里的mysqlpp:: SQLTypeAdapter:: quote_q()做了什么(65行)?
其中buffer_是个SQLBuffer
这个SQLBuffer:: quote_q( )主要要对一个表示timestamp的NOW()进行过滤,主要原因是,下面的SQL语句是合法的Insert into tbl(col_time_stamp) values(NOW()); 此时的NOW()表示的是aggregate函数。然后就交给mysql_type_info:: quote_q( )进行检测。
然后需要关注的就是68行和73行,其中68行的作用是检测输入的内容是否需要被escapte。检测方法其实和上面很类似,也就是利用SQLBuffer:: escape_q()
第73行 pq->escape_string(&escaped, in.data(), in.length());
这一行其实就是就是调用了mysqlpp:: Query:: escape_string()方法,
然后直接调用DbDriver的escape_string方法,该方法其实就是对mysql_real_escape_string的包装而已(该函数在官网上的说法很简单,This function is used to create a legal SQL string that you can use in an SQL statement)。
原创作品,转载请注明出处www.cnblogs.com/aicro。
【原创】11. MYSQL++ 之 Quoting 与 Escaping的更多相关文章
- 【原创】MYSQL++源码剖析——前言与目录
终于完成了! 从第一次想写到现在真的写好大概花了我3个月时间.原来一直读人家的系列文章,总感慨作者的用心良苦和无私奉献,自己在心里总是会觉得有那么些冲动也来写一个. 最开始的麻烦是犹豫该选哪个主题.其 ...
- 【原创】MySQL(Innodb)索引的原理
引言 回想四年前,我在学习mysql的索引这块的时候,老师在讲索引的时候,是像下面这么说的 索引就像一本书的目录.而当用户通过索引查找数据时,就好比用户通过目录查询某章节的某个知识点.这样就帮助用户有 ...
- 11.Mysql视图
11.视图11.1 什么是视图 视图view是一张虚拟表,它不存储数据,数据仍在表里,视图由一条查询表的select语句创建,视图只存储select语句. 可以将复杂的查询语句封装成视图,用户可以从视 ...
- 【原创】MySQL Can't create a new thread报错分析
今天有两台服务器都出现了Can't create a new thread报错. [故障处理过程] 故障发生后登录服务器,检查mysql进程正常,但登录mysql报下面错误 ERROR 1135 (H ...
- centos7 + Nginx+ HTTPS + uwsgi + python3.6 + Docker + Django1.11 + mysql 5.6 + virtualenv 环境搭建
环境搭建: 系统: centos7.2 x64 开发环境: python3.6 Django 1.11 虚拟环境: [Docker](https://www.runoob.com/dock ...
- 【Vegas原创】Mysql绿色版安装方法
所谓的绿色版,就是没有installer的MySQL,完全需要靠人工来操作,好处是,重装系统后,只要再做一次本次配置,即可使用. 具体操作方法: 1,设置系统环境变量, 在Path中添加 D:\mys ...
- 【原创】MySql 数据库导入导出(备份)
啥不说了,两周前刚刚做过mysql导入导出的结果现在又忘了.. 更可悲的是竟然同样的三篇blog,现在看起来还是如当初一样费劲,里面的内容..所以自己写个记录一下 环境:*nix 权限:有相关表的写读 ...
- MySQL学习11 - MySQL创建用户和授权
权限管理 权限管理 我们知道我们的最高权限管理者是root用户,它拥有着最高的权限操作.包括select.update.delete.update.grant等操作.那么一般情况在公司之后DBA工程师 ...
- 【原创】Mysql中select的正确姿势
引言 大家在开发中,还有很多童鞋在写查询语句的时候,习惯写下面这种不规范sql select * from table 而不写成下面的这种规范方式 select col1,col2,...,coln ...
随机推荐
- HTTP浅析
引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展.目前在WWW中使用的是HTTP/1. ...
- 我所常用的git命令
说明公司向用git来管理项目的代码,我以前只是在eclipse中使用菜单来操作git,现在,学习一下命令,这样也不用安装各种git客户端软件了.git安装在官网上下载git,安装完成之后,在命令行中输 ...
- N位N进制里有多少个N
32位二进制里有多少个1 https://blog.csdn.net/zhangsj1007/article/details/81411063 有这样一道计算机问题"32位二进制里面有多少个 ...
- linux离线搭建Python环境及安装numpy、pandas
1.安装python2.7.3 Cent OS 6.5默认装的有python2.6.6,需要重新安装python2.7.3下载地址:https://www.python.org/downloads/s ...
- eclipse share project到svn时显示不被信任的证书,暂时接受也不行
svn: 方法 OPTIONS 失败于 “https://eping.net/svn/testproject”: SSL handshake failed: SSL 错误:在证书中检测到违规的密钥用法 ...
- (转)TextView 设置背景和文本颜色的问题
在做一个项目,突然遇到如下问题 比如:在color.xml中定义了几个颜色 <color name="white">#FFFFFF</color> < ...
- IE兼容模式与非兼容模式下jq的写法
1. $("#LabelRepeatType").removeAttr("disabled"); $("#LabelF ...
- redis1
1. redis持久化有两种方式 ① RDB:就是周期性(比如5s)将内存中的数据放到硬盘 ② AOF:就是增删改操作写入日志,根据日志恢复等 2. redis三种分布式 ①主从 ②哨兵 ③集群 3. ...
- Linux Skills
++实现RedHat非正常关机的自动磁盘修复先登录到服务器,然后在/etc/sysconfig里增加一个文件autofsck,内容如下:AUTOFSCK_DEF_CHECK=yesPROMPT=yes ...
- apache 2 修改虚拟目录
准备好环境,就要开始进行开发了.这一篇,我们在Ubuntu Apache上配置虚拟目录. 知识准备: 区别于Windows 下apache,配置文件通常只有一个,就是httpd.conf. Linux ...