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的更多相关文章

  1. MySQL日期数据类型、时间类型使用总结

    MySQL日期数据类型.时间类型使用总结 MySQL日期数据类型.MySQL时间类型使用总结,需要的朋友可以参考下.   MySQL 日期类型:日期格式.所占存储空间.日期范围 比较. 日期类型    ...

  2. MySQL中怎么对varchar类型排序问题

    MySQL中怎么对varchar类型排序问题 在mysql默认order by 只对数字与日期类型可以排序,但对于varchar字符型类型排序好像没有用了,下面我来给各位同学介绍varchar类型排序 ...

  3. MySQL数据库数据类型之集合类型SET测试总结

    MySQL数据库提供针对字符串存储的一种特殊数据类型:集合类型SET,这种数据类型可以给予我们更多提高性能.降低存储容量和降低程序代码理解的技巧,前面介绍了首先介绍了四种数据类型的特性总结,其后又分别 ...

  4. MySQL的数据库引擎的类型及区别

    MySQL的数据库引擎的类型 你能用的数据库引擎取决于mysql在安装的时候是如何被编译的.要添加一个新的引擎,就必须重新编译MYSQL.在缺省情况下,MYSQL支持三个引擎:ISAM.MYISAM和 ...

  5. mysql语句中把string类型字段转datetime类型

    mysql语句中把string类型字段转datetime类型   在mysql里面利用str_to_date()把字符串转换为日期   此处以表h_hotelcontext的Start_time和En ...

  6. Mysql中查看表的类型InnoDB

    问题描述:   MySQL 数据表主要支持六种类型 ,分别是:BDB.HEAP.ISAM.MERGE.MYISAM.InnoBDB. 这六种又分为两类,一类是“事务安全型”(transaction-s ...

  7. mysql 5.7 laravel json类型数据相关操作

    2018年10月16日18:14:21 官方文档中文翻译版 原文:https://dev.mysql.com/doc/refman/5.7/en/json.html 最后有部分实例和一个小总结 11. ...

  8. MySQL数据类型--日期和时间类型

    MySQL中的多种时间和格式数据类型 日期和时间类型是为了方便在数据库中存储日期和时间而设计的.MySQL中有多种表示日期和时间的数据类型. 其中,year类型表示时间,date类型表示日期,time ...

  9. MySQL · 最佳实践 · 分区表基本类型

    MySQL · 最佳实践 · 分区表基本类型 MySQL分区表概述 随着MySQL越来越流行,Mysql里面的保存的数据也越来越大.在日常的工作中,我们经常遇到一张表里面保存了上亿甚至过十亿的记录.这 ...

  10. java和mysql之间的时间日期类型传递

    摘自:http://blog.csdn.net/weinianjie1/article/details/6310770 MySQL(版本:5.1.50)的时间日期类型如下: datetime 8byt ...

随机推荐

  1. Tinker爬坑之路

    目的 热修复去年年底出的时候,变成了今年最火的技术之一.依旧记得去年面试的时候统一的MVP,然而今年却变成了RN,热修复.这不得不导致我们需要随时掌握最新的技术.不然可能随时会被淘汰.记得刚进公司,技 ...

  2. 你必须知道的495个C语言问题,学习体会二

    这是本主题的第二篇文章,主要就结构体,枚举.联合体做一些解释 1.结构体 现代C语言编程 结构化的基石,diy时代的最好代言人,是面向对象编程中类的老祖宗. 我们很容易定义一个结构体,比如学生: st ...

  3. web service(转载)

    原文引自:http://blog.csdn.net/wooshn/article/details/8069087 WebService到底是什么? 一言以蔽之:WebService是一种跨编程语言和跨 ...

  4. 剑指Offer面试题:11.调整数组顺序使奇数位于偶数前面

    一 题目:调整数组顺序使奇数位于偶数前面 题目:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分. 二 解题思路 如果不考虑时间复杂度 ...

  5. Python之functools库

    functools库用于高阶函数,指那些作用于函数或者返回其他函数的函数 functools提供方法如下: cmp_to_key 将一个比较函数转换关键字函数 partial 针对函数起作用,并且是部 ...

  6. 系列文章--WCF后传学习文章

    WCF后传系列(10):消息处理功能核心 摘要: WCF是一个通信框架,同时也可以将它看成是一个消息处理或者传递的基础框架,它可以接收消息.对消息做处理,或者根据客户端给定的数据构造消息并将消息发送到 ...

  7. 从如何优化SQL入手,提高数据仓库的ETL效率

    1        引言数据仓库建设中的ETL(Extract, Transform, Load)是数据抽取.转换和装载到模型的过程,整个过程基本是通过控制用SQL语句编写的存储过程和函数的方式来实现对 ...

  8. 并发问题 关于Redis

    并发问题 关于Redis [吐槽]Jimesembria 付费请人解这个BUG , 有没有php同学有兴趣,(问题原因是理论上是5分钟内不生产同样金额的订单, 但是由于并发原因没控制好) 10:34: ...

  9. Dell 12G服务器 手动安装RedHat 6.X

    12代服务器,是DELL目前最新产品,有R720,R520,R620,R420,M420 等产品 以下是光盘直接安装Red Hat 6.X 的方法步骤: 1,选择安装盘对应的启动设备 开机按F11,选 ...

  10. AGC006 C Rabbit Exercise——思路(置换)

    题目:https://agc006.contest.atcoder.jp/tasks/agc006_c 选了 i 位置后 x[ i ] = x[ i-1 ] + x[ i+1 ] - x[ i ] . ...