【原创】4. MYSQL++ 之 SQLTypeAdapter类型、SQLQueryParms类型 与 SQLBuffer
1. mysqlpp::SQLBuffer
该类型其实就是SQLTypeAdapter传入的各种类型(int, string, double, long, String, …) 的包装,包装的结果就是
- 各种类型实例的字符串表示 ( const char* data_; )
- length 长度 ( size_type length_ )
- 类型(由mysqlpp::mysql_type_info定义) ( mysql_type_info type_ )
- 是否是数据库的NULL类型 ( bool is_null_ )
表示类型的类别是 mysql_type_info ,该类型是一个“C++类型”和“SQL 类型”相互映射的utility class。
需要强调的是,该类型实际上是支持BINARY存法的,其实在实现上,就是将length不设定为”\0”的位置,而是整个类型实例的真实长度。以下面的代码为例
SQLBuffer("abc\\0efg", 7, mysql_type_info::string_type, false)
如此一来,上面的四个属性就非常清楚地对号入座了。
同时,该类型回答了传入的类型的各种问题,例如
- 传入实例是否是个string(is_string( ) )
- 传入实例是否是null(is_null( ), 这里的null是数据库中的NULL,即如create table (id int not NULL),必须要区别于字符串“NULL”)
- 传入实例的实例类型是什么(type( ))
- 传入实例的实例是否需要转移escape(escape_q( ))
- 传入实例的实例是否需要quote(quote_q( ))
关于类型信息(type( ), escape_q( ), quote_q( ))都是靠着mysqlpp::mysql_type_info实现。除了在进行quote_q( )的时候,在调用mysql_type_info::quote_q( )之前,先检查如果包装的是一个在TIMESTAMP中的“NOW()”的情况,如果是这种情况,那么就是不需要进行quote。例如,
CREATE TABLE tbl1 ( time TIMESTAMP);
insert into tbl1 values( NOW() ); --注意这里的NOW()是不需要加上引号的
具体的实现代码是
也就是说当前版本的MYSQL++能够识别的MYSQL函数应该只有NOW( )了。其他的都会被认为是普通字符串而被加上quote。
2. mysqlpp::mysql_type_info
这个类型是mysqlpp:: SQLBuffer的灵魂,具体表示类型信息,该类型是一个“C++类型”和“SQL 类型”相互映射的utility class。它是唯一一个需要和MYSQL 原生态的数据结构打交道的,需要硬编码的类型(具体指的是mysql_type_info内部的一个mysql_ti_sql_type_info类型的数组,其中包含了诸如名字、底层类型、MYSQL_Comm.h中的对应的ENUM以及表示是否可以为SQL null、是否是默认类型等信息的flag),它的功能就是在SQL类型和C++类型之间进行相互转换。也就是说,该类型明确了某个C++类型所对应的SQL类型。具体的内容,可以参看抓们解释mysql_type_info类型原理这一节。
3. mysqlpp::SQLTypeAdapter
- 作用
SQLTypeAdapter正如名字所言,是一个“适配器”,也就是说,为了在实现上的方便,很多函数就以他作为中介,来隐藏具体的数据类型(例如int,double,string和mysqlpp::String等)。类似于Query中的use和store等,都有使用SQLTypeAdapter作为参数的方法。使用SQLTypeAdapter就可以省去很多overwrite。
文档上是这样说的
This class provides implicit conversion between many C++ types and SQL-formatted string representations of that data without losing important type information.
第一种用法是在template query中,例如在下面的用法中,可以防止execute的签名过于复杂。例如下面的execute只需要声明两个SQLTypeAdapter即可,而不需要声明为一个string,一个int(其实这样的组合是无穷尽的,所以也只有这一种解决途径)。这个用法是ADAPTER设计模式的典型用法。
// 示意伪代码,不一定准确
mysqlpp::Query query = con.query(
"select * from stock where item = %0q, id = %1q");
query.parse();
query.execute(SQLTypeAdapter("test"), SQLTypeAdapter(1) );
第二种用法是为了方便Quoting和Escaping,其实动机和上面的差不多。
The other major use for this type is the quoting and escaping logic in Query's stream interface: rather than overload the << operators and the manipulators for every single type we know the rules for a priori, we just specialize the manipulators for SQLTypeAdapter. The conversion to SQLTypeAdapter stringizes the data, which we need anyway for stream insertion, and holds enough type information so that the manipulator can decide whether to do automatic quoting and/or escaping.
另外,代码中还实现了两个SQLTypeAdapter的比较( int compare(const SQLTypeAdapter& other) const; ),以及SQLTypeAdapter与string和char*进行比较的重载函数。
这里的比较其实相对比较容易,基本上几个compare函数的最后调用都是如下函数
讲到底就是字符串的比较,需要强调的是,strncmp虽然是str的比较,但是其实这个函数是可以比较含有”\0”的二进制内存段的,这是因为该函数的原型是,
extern int strcmp(char *str1,char * str2,int n),
其中的n表示需要比较的字符(byte)数。
例如,
- 代码实现
成员变量
要看懂SQLTypeAdapter需要先看懂mysqlpp: : SQLBuffer,因为在SQLTypeAdapter中,只有两个成员变量,一个是表示是否已经处理过的flag,以及一个SQLBuffer缓冲(注意,在源代码中是使用的是ref count)
- is_processed_
This flag is used by the template query mechanism, to prevent a string from being re-escaped or re-quoted each time that query is reused. The flag is reset by operator=, to force the new parameter value to be re-processed.
这里所说的process就是为string在SQL语句中加入引号(quote),或者为特殊字符加上“转义”(escape)。 查看整个项目源代码,可以发现,为这个is_processed_设置为true的情况只有在manip.cpp(Implements MySQL++'s various quoting/escaping stream manipulators.)以及 query.cpp 的一些和template query相关的地方。
至于具体的quote和escape是如何封装的,请看专门的章节。
- buffer_
这是一个RefCountedPointer<SQLBuffer>类型的变量,用来保存此SQLTypeAdapter所包含的具体的数据、长度、类型信息等。
重要方法
需要关心的实现方面的具体要素有SQLTypeAdapter的构造函数,通过查看源代码,我们可以大致为SQLTypeAdapter的构造函数分成三类。
- 拷贝构造函数——没什么好多说的
- 以C++数据类型(如int, string, long, float,double)为源的构造函数
- 例子是
让我们仔细来看一下SQLBuffer的构造函数
我刚开始看这段代码的时候有一个疑惑,那就是为什么像上面的例子居然可以编译通过?明明在SQLTypeAdapter(short i)中传入给SQLBuffer的第二个参数是typeid(i) (typeid是C++的关键字,是个RTTI 关键字,结果是std::type_info),给SQLTypeAdapter(char i)中传入给SQLBuffer的第二个参数是enum_field_types( 该enum被定义在了mysql 自带的Develop Toolkit中的与C函数相关的头文件中的mysql_com.h中 ,而mysql_type_info::string_type被定义为MYSQL_TYPE_STRING,它是mysql_com.h中的一个enum_field_types常量)。
后来经过写了个简单的示例的debug,我发现这是C++的一个tricky(说明我的C++基础还是相对比较薄弱的),也就是说编译器自动帮我们找到了最合适的mysql_type_info类型的构造函数,即上下两个例子分别对应的构造函数是
最后,特别需要注意的是关于float和double类型,这两个类型需要考虑infinite 或者 NaN的情况,所以需要特殊处理,下文中的numeric_limits是C++标准库中的一个template class。
- 以mysqlpp自定义的类型为源的构造函数
- mysqlpp::String, mysqlpp::Date, mysqlpp::Time, mysqlpp::DateTime
mysql++处于便于管理和尽可能将C++type与SQL type相互对应,自建了上面的几个类型,其中mysqlpp:: String更是表示BLOB的首选。
其实在sql_type.h中,就有
当我们在看SQLTypeAdapter的构造函数,例如,
我们发现传递给SQLBuffer的第二个参数仍然是typeid(d),为什么对于自定义的mysqlpp:: Data而言,也可以用typeid?其实这个问题本身并没有多大问题,毕竟typeid是个关键字,对于任何类型都是可以使用的,就像sizeof一样。
- mysqlpp::Null<T>
mysqlpp::Null<T>也是一个自定义的类型,他的出现是为了应付“Class for holding data from a SQL column with the NULL attribute.“我们来看一个例子
关于NULL<T>类型的具体介绍,请看相关内容。
- mysqlpp::tiny_int<unsigned char>
为什么要有tiny_int,在给SQLTypeAdapter(char c)进行注释的时候,作者特地说,如果我们需要使用tiny_int,那么不要使用char,而应该是用mysqlpp:: tiny_int,这里也就是为了这个目的而有以下两个版本的SQLTypeAdapter构造函数
SQLTypeAdapter(tiny_int<unsigned char> i);
SQLTypeAdapter(tiny_int<signed char> i);
4. mysqlpp::SQLQueryParms
该类型很简单,其实就是作为template query的参数的集合。其实在mysqlpp:: Query中还用到了同样被定义在Qprams.h中的mysqlpp::SQLParseElement。
例如,如果有类似于这样的sql template 语句(可能和实际的MYSQL++用法不一致)
select * from where id = %d, name = ‘%s’.
则我们可以这样设置SQLQueryParms
SQLQueryParms sqp;
sqp << 1 << "root";
具体的实现细节请参看其他章节
原创作品,转载请注明出处www.cnblogs.com/aicro。
【原创】4. MYSQL++ 之 SQLTypeAdapter类型、SQLQueryParms类型 与 SQLBuffer的更多相关文章
- MySQL日期数据类型、时间类型使用总结
MySQL日期数据类型.时间类型使用总结 MySQL日期数据类型.MySQL时间类型使用总结,需要的朋友可以参考下. MySQL 日期类型:日期格式.所占存储空间.日期范围 比较. 日期类型 ...
- MySQL中怎么对varchar类型排序问题
MySQL中怎么对varchar类型排序问题 在mysql默认order by 只对数字与日期类型可以排序,但对于varchar字符型类型排序好像没有用了,下面我来给各位同学介绍varchar类型排序 ...
- MySQL数据库数据类型之集合类型SET测试总结
MySQL数据库提供针对字符串存储的一种特殊数据类型:集合类型SET,这种数据类型可以给予我们更多提高性能.降低存储容量和降低程序代码理解的技巧,前面介绍了首先介绍了四种数据类型的特性总结,其后又分别 ...
- MySQL的数据库引擎的类型及区别
MySQL的数据库引擎的类型 你能用的数据库引擎取决于mysql在安装的时候是如何被编译的.要添加一个新的引擎,就必须重新编译MYSQL.在缺省情况下,MYSQL支持三个引擎:ISAM.MYISAM和 ...
- mysql语句中把string类型字段转datetime类型
mysql语句中把string类型字段转datetime类型 在mysql里面利用str_to_date()把字符串转换为日期 此处以表h_hotelcontext的Start_time和En ...
- Mysql中查看表的类型InnoDB
问题描述: MySQL 数据表主要支持六种类型 ,分别是:BDB.HEAP.ISAM.MERGE.MYISAM.InnoBDB. 这六种又分为两类,一类是“事务安全型”(transaction-s ...
- mysql 5.7 laravel json类型数据相关操作
2018年10月16日18:14:21 官方文档中文翻译版 原文:https://dev.mysql.com/doc/refman/5.7/en/json.html 最后有部分实例和一个小总结 11. ...
- MySQL数据类型--日期和时间类型
MySQL中的多种时间和格式数据类型 日期和时间类型是为了方便在数据库中存储日期和时间而设计的.MySQL中有多种表示日期和时间的数据类型. 其中,year类型表示时间,date类型表示日期,time ...
- MySQL · 最佳实践 · 分区表基本类型
MySQL · 最佳实践 · 分区表基本类型 MySQL分区表概述 随着MySQL越来越流行,Mysql里面的保存的数据也越来越大.在日常的工作中,我们经常遇到一张表里面保存了上亿甚至过十亿的记录.这 ...
- java和mysql之间的时间日期类型传递
摘自:http://blog.csdn.net/weinianjie1/article/details/6310770 MySQL(版本:5.1.50)的时间日期类型如下: datetime 8byt ...
随机推荐
- Unity在协程(Coroutines)内开启线程(Threading )
孙广东 2017.6.13 http://blog.csdn.NET/u010019717 为什么要在协程中开启线程, 因为很多时候我们是需要线程执行完成后回到主线程的.然后主线程在继续执行后续的操 ...
- angularJs 模拟jQuery中的this
在angularJs中,this指向$scope!可以$event配合使用$(event.target)实现,代码如下: HTML部分: <p ng-click="testClick( ...
- VS2017 Product Key
Enterprise: NJVYC-BMHX2-G77MM-4XJMR-6Q8QF Professional: KBJFW-NXHK6-W4WJM-CRMQB-G3CDH
- MySQL install and setting
Tomorrow is the deadline of DATABASE, I am very nervous because of my project. Today is first day th ...
- 【spring源码学习】spring的IOC容器之BeanFactoryPostProcessor接口学习
[一]org.springframework.beans.factory.config.BeanFactoryPostProcessor接口==>该接口实现方法的执行时机:该接口void pos ...
- TortoiseGit不同分支合并代码2
现在有主分支master和分支day2.现在要把day2上的变更合并到主分支master上! 1.首先切换到目标分支master上. 说明当前分支是master分支. 2.在master分支上查看提交 ...
- gogs docker 安装
1. gogs 镜像 docker pull gogs/gogs 2. mysql docker mysql 3. 本地数据卷配置 mkdir gogs & ...
- IE 9 下的 css 陷阱
IE 9 下的 css 陷阱 今天 Karson 老大的分享. 根据说明 当 css 文件超过一定大小时会被自动截断. http://ju.outofmemory.cn/entry/168599
- bzoj 3779 重组病毒 —— LCT+树状数组(区间修改+区间查询)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3779 RELEASE操作可以对应LCT的 access,RECENTER则是 makeroo ...
- hbase使用中需要注意一些问题
接触hbase已经两年之久,但是真正的在实际项目中使用却只有半年的时间,使用过程中,一方面在在为hbase强大的性能兴奋之余,另一方面却也给我和我的团队造成了很多的麻烦,起初在使用我的水平也就停留在会 ...