在介绍Result之前,先熟悉几个类

Field  用来存储SQL字段信息,主要是关于表字段列属性的判断和获取

class Field
{
public:
...............................
private:
std::string name_; // the field's name
std::string table_; // name of table field comes from
std::string db_;    // name of database field comes from
mysql_type_info type_; // info about the field's type
size_t length_; // creation size of column(指数据类型的长度varchar(30) length_=30)
size_t max_length_;    // size of largest item in column in result set
unsigned int flags_; // DB engine-specific set of bit flags(就是数据表中列的属性:自增,主键,时间戳,枚举,二进制类型,BLOB类型,默认值等)
}

typedef std::vector<Field> Fields;

Row 一个对象表示一行数据

class MYSQLPP_EXPORT Row : public OptionalExceptions
{
   .......................................// 创建一个Row对象
Row::Row(MYSQL_ROW row, const ResultBase* res,
const unsigned long* lengths, bool throw_exceptions) :
     OptionalExceptions(throw_exceptions),
     initialized_(false)
   {
  if (row) {
  if (res) {
  size_type size = res->num_fields(); //表字段的数量
   data_.reserve(size);
for (size_type i = ; i < size; ++i) {
  bool is_null = row[i] == ;
          //将数据存储到data_中
  data_.push_back(value_type(is_null ? "NULL" : row[i], is_null ? : lengths[i], res->field_type(int(i)), is_null));
} field_names_ = res->field_names(); //所有字段名称
initialized_ = true;
} else if (throw_exceptions) {
throw ObjectNotInitialized("RES is NULL");
}
 } else if (throw_exceptions) {
throw ObjectNotInitialized("ROW is NULL");
}
  } ............................................... private:
list_type data_; //用来存储一行的数据,一行5列则data_.size()=5
RefCountedPointer<FieldNames> field_names_; //用来存储表列名称,表有3列则field_names_.size()=3
bool initialized_;
};

ResultBase

这个类型是StoreQueryResult和UseQueryResult的父类型,该类型其实没有特别的含义,只是作为一个common methods的container而已。但是该类型提供的几乎所有的public methods都是和fields有关的,包括了

  • 根据index查找field;
  • 根据name查找field;
  • 根据index查找到field的名字和属性类型;
  • 获取当前所在的field(ResultBase内部会有一个mutable的index名为current_field_用于指明当前fetch_field的是哪一个field,在fetch_field中该index会自增)

该类型的核心成员有如下几个

  • Fields(std::vector<Field>) 类型的 fields_
  • FieldNames (继承自std::vector<std:: string>)类型的 names_
  • FieldTypes ( 继承自std::vector<mysql_type_info>)类型的types_

其中FieldNames和FieldTypes都是被RefCountedPointer包裹着,估计这样做能够节省空间。关于Field类型在后续进行介绍。至于刚才说的几个找field的操作,看着这几个核心成员的类型还是比较好理解的。不就是在vector中不找。

需要额外关注的是以下这个最主要的构造函数

ResultBase::ResultBase(MYSQL_RES* res, DBDriver* dbd, bool te) :
OptionalExceptions(te),
driver_(res ? dbd : ),
fields_(Fields::size_type(res ? dbd->num_fields(res) : )),
current_field_()
{
if (res) {
Fields::size_type i = ;
const MYSQL_FIELD* pf;
     //直接通过DBDriver的fetch_field方法进行获取到一个MYSQL_FIELD*,然后直接就仍给了fields_(fields_是一个Fields类型,他是一个typedef std::vector<Field>)
while ((i < fields_.size()) && (pf = dbd->fetch_field(res))) {
fields_[i++] = pf;
}
dbd->field_seek(res, ); // semantics break otherwise! names_ = new FieldNames(this);
types_ = new FieldTypes(this);
}
}

以下几点需要注意,

  • names_和types_在new出来之后是不需要显式delete的,因为他们都在智能指针RefCountedPointer包裹着。
  • 成员初始化列表中的 fields_(Fields:: size_type(…)) 这一句其实调用的是
explicit std::vector::vector (size_type n, const value_type& val = value_type(), const allocator_type& alloc = allocator_type());
  • 从以上构造函数可以看到,其实关于Field的信息还是从DBDriver中拿到的,然后关于FieldNames和FieldTypes的信息,则是通过这两个类型自身的构造函数给实现的(其实就是收到ResultBase*,然后遍历其中的成员变量 fields_ 再各求所需罢了。
  • 为什么要有重新将指示field_当前index的指针重置的过程(dbd->field_seek(res, 0))?这是因为方便这个DBDriver再次循环访问这些fields。

查看Query源码发现,Query执行操作返回值不外乎就是:bool, SimpleResult, UseQueryResult, StoreQueryResult

1.bool

标识操作执行成功失败,如update, delete,insert,不关心有多少rows被touch的情况

2.SimpleResult

这个类型非常简单,没有父类,主要的成员变量有3个,分别是:

ulonglong insert_id_;    //Get the last value used for an AUTO_INCREMENT field
ulonglong rows_;     //query操作影响的行数
std::string info_;    //获取从server返回的query操作附加信息

3.UseQueryResult

UseQueryResule适用于For these large result sets,a “use” query tells the database server to send the results back one row at a time, to be processed linearly。use的语义类似于使用游标,也就是支持一行一行地拉出内容,所以UseQueryResult 也就自然而然地支持一些关于fetch row的功能。

该类型的方法比StoreQueryResult丰富多了,主要体现在:

  • 可以顺序读取行(mysqlpp::Row fetch_row() const;或者MYSQL_ROW fetch_raw_row() const;)
  • 可以获取当前行的各个field的信息(const Field& fetch_field() const; const Field& fetch_field(Fields::size_type i) const)
  • 可以获取当前行的所有fields的长度(const unsigned long* fetch_lengths() const;)
Row UseQueryResult::fetch_row() const
{
if (!result_) {
if (throw_exceptions()) {
throw UseQueryError("Results not fetched");
}else {
return Row();
}
} MYSQL_ROW row = driver_->fetch_row(result_.raw());
if (row) {
const unsigned long* lengths = fetch_lengths();
if (lengths) {
return Row(row, this, lengths, throw_exceptions());    //根据返回的数据构建一个Row对象返回
}else {
if (throw_exceptions()) {
throw UseQueryError("Failed to get field lengths");
}else {
return Row();
}
}
}else {
return Row();
}
}

4.StoreQueryResult

StoreQueryResult继承与std::vector<Row>,所以它也就是vector,拥有vector的所有操作。用来装载SQL操作返回的结果,所以程序可以直接使用下标的形式来对ROW操作。

StoreQueryResult::StoreQueryResult(MYSQL_RES* res, DBDriver* dbd, bool te) :
ResultBase(res, dbd, te),list_type(list_type::size_type(res && dbd ? dbd->num_rows(res) : )),
copacetic_(res && dbd)
{
if (copacetic_) {
iterator it = begin();
while (MYSQL_ROW row = dbd->fetch_row(res)) {    //从res中提取一行数据
if (const unsigned long* lengths = dbd->fetch_lengths(res)) {
*it = Row(row, this, lengths, throw_exceptions());      //StoreQueryResult继承std::vector<Row>,在这里将取出的每一行数据存储到自身对象中
++it;
}
} dbd->free_result(res);  //数据拷贝完后释放res内存
}
} Row中如下:
Row::Row(MYSQL_ROW row, const ResultBase* res, const unsigned long* lengths, bool throw_exceptions) :
OptionalExceptions(throw_exceptions),
initialized_(false)
{
if (row) {
if (res) {
size_type size = res->num_fields();    //提取当前行的所有列的数量
data_.reserve(size);
for (size_type i = ; i < size; ++i) {
data_.push_back(value_type(is_null ? "NULL" : row[i], is_null ? : lengths[i], res->field_type(int(i)), is_null));  //
        }
       field_names = res->field_names();      //将表的列名称赋值给field_names;
       initialized = true;
     ............................
}

通过以上分析:通过DBDriver拿到数据,调用StoreQueryResult构建数据集,首先执行的是父类ResultBase的构造函数(从C结构中获取列字段属性及类型),在通过DBDriver一行一行的获取数据初始化Row(将数据存放到vector data_中),StoreQueryResult继承自Row,自此StoreQueryResult对象对象中包含了数据集合和列名称及属性

    // Establish the connection to the database server.
mysqlpp::Connection con(db_name.c_str(), db_ip.c_str(), db_user.c_str(), db_passwd.c_str(), db_port); mysqlpp::Query query = con.query("select * from student");
mysqlpp::StoreQueryResult res = query.store();
if (res)
{
// Display header
cout.setf(ios::left);
for (size_t i = ; i < res.fields().size(); i++)
{
cout << setw() << res.field_name(i);
} cout << endl;
// Get each row in result set, and print its contents
for (size_t i = ; i < res.num_rows(); ++i) {
cout << setw() << res[i]["id"] << ' ' <<
setw() << res[i]["name"] << ' ' <<
setw() << res[i]["age"] << ' ' <<
setw() << res[i]["home"] << ' ' <<
endl;
}
} else {
cerr << "Failed to get stock table: " << query.error() << endl;
return ;
}

通过DBDriver拿到数据,调用UseQueryResult构建数据,首先执行的是父类ResultBase的构造函数(从C结构中获取列字段属性及类型),等到调用fetch_row时在构造一行数据(调用Row的构造函数)

   mysqlpp::Connection con(db_name.c_str(), db_ip.c_str(), db_user.c_str(), db_passwd.c_str(), db_port);

    mysqlpp::Query query = con.query("select * from student");
mysqlpp::UseQueryResult res = query.use(); cout.setf(ios::left);
for (size_t i = ; i < res.fields().size(); i++)
{
cout << setw() << res.field_name(i);
} cout << endl;
while (mysqlpp::Row row = res.fetch_row())
{
cout << setw() << row["id"] << ' ' <<
setw() << row["name"] << ' ' <<
setw() << row["age"] << ' ' <<
setw() << row["home"] << ' ' <<
endl;
}

mysql++ result的更多相关文章

  1. Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result

    Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in 解决方案:$sql = ...

  2. php错误 mysql_query():supplied argument is not a valid MySQL result resource

    出现这种错误,原因是出现该错误的函数的参数出现了问题 参数出现问题有多种情况: 1.sql查询语句有问题,可能多了一个逗号,少了一个逗号,多了括号之类的: 2.与数据库连接的参数有问题,用户名.密码. ...

  3. mysql源码包手动安装、配置以及测试(亲测可行)

    笔记编者:小波/qq463431476博客首页:http://www.cnblogs.com/xiaobo-Linux/ 记下这篇mysql笔记,望日后有用! redhat6采用centos yum源 ...

  4. PHP+MYSQL网站SQL Injection攻防

    程序员们写代码的时候讲究TDD(测试驱动开发):在实现一个功能前,会先写一个测试用例,然后再编写代码使之运行通过.其实当黑客SQL Injection时,同样是一个TDD的过程:他们会先尝试着让程序报 ...

  5. HP+MYSQL网站SQL Injection攻防

    WebjxCom提示:程序员们写代码的时候讲究TDD(测试驱动开发):在实现一个功能前,会先写一个测试用例,然后再编写代码使之运行通过.其实当黑客SQL Injection时,同样是一个TDD的过程: ...

  6. PHP基础Mysql扩展库

    mysql扩展库操作步骤如下: 1.连接数据库 2.选择数据库 3.设置操作编码 4.发送指令sql,并返回结果集     ddl:数据定义语句     dml:数据操作语句     dql:数据查询 ...

  7. php基础知识【函数】(6)mysql数据库

    一.连接和关闭 1.mysql_connect('example.com:3307', 'root', '123456') --打开一个到 MySQL 服务器的非永久连接 2.mysql_pconne ...

  8. PHP Mysql类【转】

    前几天没事在网上转发现了一个类,记录下来: <?php Class DB { private $link_id; private $handle; private $is_log; privat ...

  9. PHP MySql数据库访问

    PHP MySql数据库访问 计应134   凌豪 1.MySql数据库的连接 要操作MySql数据库,首先必须与MySQl数据库建立连接,连接MySQL服务器的语句如下: <?php$link ...

随机推荐

  1. 用FireBreath来编写跨浏览器插件

    这是对于公司某个需求的临时研究,最后经过简单实验放弃了这个方案,因为编写插件不能满足需求. 下面着重讲一下FireBreath编译. 首先根据文档,用git clone下载Firebreath源码(不 ...

  2. 阿里云设置CDN加速访问OSS文件

    快速配置OSS:https://help.aliyun.com/document_detail/31885.html?spm=5176.doc31886.6.97.8iuJo5 快速配置CDN:htt ...

  3. ajax done和always区别

    jQuery中Ajax有done和always这两个回调方法:done:成功时执行,异常时不会执行.always:不论成功与否都会执行.

  4. find -exec 与xargs 区别

    find . -name "*.txt" -exec rm {} \;find . -name "*.txt" | xargs rm {} -exec    1 ...

  5. 安装apr报错rm: cannot remove `libtoolT': No such file or directory

    直接打开/usr/local/src/apr-1.4.6/configure  把 $RM“$cfgfile” 那行删除掉 $RM“$cfgfile” 大约在 42302行 然后再重新运行  ./co ...

  6. IP概念盛行的背后:资本在狂欢,电影想哭泣 IP,英文“Intellectual Property”的缩写,直译为“知识产权”。它的存在方式很多元,可以是一个故事,也可以是某一个形象,运营成功的IP可以在漫画、小说、电影、玩具、手游等不同的媒介形式中转换。

    IP概念盛行的背后:资本在狂欢,电影想哭泣 IP容易拉投资.谈合作,甚至还能简化宣发途径,越来越多的人涌入了电影这个产业,争抢IP成为他们进入行业的最快捷的方法.IP盛行暴露出的另一个问题是国产电影原 ...

  7. java结合使用Jsonp的例子

    更多:js跨域问题解释 解决方案值使用jsonp或jQuery Jsonp和java操作例子 介绍JSONP之前,先简单的介绍一些JSON.JSON是JavaScript Object Notatio ...

  8. git学习笔记(三)—— 远程仓库

    一.gitHub&&SSH Key 为git仓库提供托管服务的,所以注册一个github账号,就可以免费获得git远程仓库. 本地Git仓库和GitHub仓库之间的传输是通过SSH加密 ...

  9. SQL表之间复制数据、选出随机几条数据、删除重复数据、取得自增长列等操作

    --表之间数据复制 SELECT* INTO yozhu FROM yo --复制一份表 SELECT* INTO yozhu1 FROM yo where 1<>1 --只复制表结构,无 ...

  10. WCF入门教程(四)通过Host代码方式来承载服务 一个WCF使用TCP协议进行通协的例子 jquery ajax调用WCF,采用System.ServiceModel.WebHttpBinding System.ServiceModel.WSHttpBinding协议 学习WCF笔记之二 无废话WCF入门教程一[什么是WCF]

    WCF入门教程(四)通过Host代码方式来承载服务 Posted on 2014-05-15 13:03 停留的风 阅读(7681) 评论(0) 编辑 收藏 WCF入门教程(四)通过Host代码方式来 ...