前一篇博客中介绍的是怎样依据sqlite3_get_table()函数来获取一张表的内容,就是一股脑的把表中的内容所有存储起来放在一个一维数组中,这其中的规则已经介绍过了。接下来讲的是怎样依据一个SQL查询语句来挑选出合乎选择条件的记录,被挑选出的记录事先是不知道的。你不知道这个查询的结果中有几行更不知道每一行中详细的记录值是什么,所以没办法用给定行值和列值的方式来获取数据,所有之前的用数组存储表的方式即可不通了。想要灵活的管理一个查询返回的结果这就会复杂多了,用到的SQLite原生函数也非常多。

这个CppSQLite3Query类中有四个字段,各自是

	sqlite3 *mpDB;
sqlite3_stmt *mpStmt;
bool mbEof; //因为查询的结果须要一行一行的訪问,所以设置一个bool值来表示是否达到最后一行的结尾
int mnCols; //表示这个查询结果的列数,行数是无法得知的

第一个參数:查询要连接的数据库

第二个參数:

** CAPI3REF: SQL Statement Object
** KEYWORDS: {prepared statement} {prepared statements}
**
** An instance of this object represents a single SQL statement.
** This object is variously known as a "prepared statement" or a
** "compiled SQL statement" or simply as a "statement".
**
** The life of a statement object goes something like this:
**
** <ol>
** <li> Create the object using [sqlite3_prepare_v2()] or a related
** function.
** <li> Bind values to [host parameters] using the sqlite3_bind_*()
** interfaces.
** <li> Run the SQL by calling [sqlite3_step()] one or more times.
** <li> Reset the statement using [sqlite3_reset()] then go back
** to step 2. Do this zero or more times.
** <li> Destroy the object using [sqlite3_finalize()].
** </ol>

是一个SQL语句对象,或是说一条原生的SQL查询语句select * from XXX;经过SQLite处理后就生成了一个sqlite3_stmt对象。以后就能够不用原生的语句来做查询,就直接使用这个sqlite3_stmt*就能够查询了,当查询结束后,要将sqlite3_stmt*指针对象释放掉。

释放函数sqlite3_finalize()和sqlite3_free();函数功能类似,仅仅只是后者是释放sqlite3*对象的,而前者是释放sqlite3_stmt*对象的。

函数原型   SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);

函数说明:

/*
** CAPI3REF: Destroy A Prepared Statement Object
**
** ^The sqlite3_finalize() function is called to delete a [prepared statement].
** ^If the most recent evaluation of the statement encountered no errors
** or if the statement is never been evaluated, then sqlite3_finalize() returns
** SQLITE_OK. ^If the most recent evaluation of statement S failed, then
** sqlite3_finalize(S) returns the appropriate [error code] or
** [extended error code].
**
** ^The sqlite3_finalize(S) routine can be called at any point during
** the life cycle of [prepared statement] S:
** before statement S is ever evaluated, after
** one or more calls to [sqlite3_reset()], or after any call
** to [sqlite3_step()] regardless of whether or not the statement has
** completed execution.
**
** ^Invoking sqlite3_finalize() on a NULL pointer is a harmless no-op.
**
** The application must finalize every [prepared statement] in order to avoid
** resource leaks. It is a grievous error for the application to try to use
** a prepared statement after it has been finalized. Any use of a prepared
** statement after it has been finalized can result in undefined and
** undesirable behavior such as segfaults and heap corruption.
*/

用来初始化mnCols字段的函数是:

SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt);

函数说明:

/*
** CAPI3REF: Number Of Columns In A Result Set
**
** ^Return the number of columns in the result set returned by the
** [prepared statement]. ^This routine returns 0 if pStmt is an SQL
** statement that does not return data (for example an [UPDATE]).
**
** See also: [sqlite3_data_count()]
*/

在依据列索引值获取当前列的列名用到的函数:

函数原型:SQLITE_API const char *sqlite3_column_name(sqlite3_stmt*, int N);

在推断数据是否为空的时候要用到检測数据类型的函数:

函数原型:SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);

这个函数返回的是一个整型,当中不同的数值代表不同的已定义好的宏,以下是各种类型:

#define SQLITE_INTEGER  1
#define SQLITE_FLOAT 2
#define SQLITE_BLOB 4
#define SQLITE_NULL 5
#ifdef SQLITE_TEXT
# undef SQLITE_TEXT
#else
# define SQLITE_TEXT 3
#endif
#define SQLITE3_TEXT 3

另一种查询数据类型的函数

SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt*,int);

他返回的直接是类型名称。

在获取各种不同类型数据的时候用到各种函数,他们返回不同的数据类型的值:

SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol);
SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol);
SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);
SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);

上面的一些函数可能没有出如今这个封装的C++类中。

以下直接贴代码:

class CppSQLite3Query
{
private:
sqlite3 *mpDB;
sqlite3_stmt *mpStmt;
bool mbEof;
int mnCols; void CheckStmt();
public:
CppSQLite3Query();
CppSQLite3Query(sqlite3 *pdb, sqlite3_stmt *pStmt, bool bEof);
CppSQLite3Query(const CppSQLite3Query &rQuery);
CppSQLite3Query& operator= (const CppSQLite3Query &rQuery);
~CppSQLite3Query(); int FieldNums(); int FieldIndex(const char* szField);
const char* FieldName(int nField); int FieldDataType(int nField);
const char* FieldDeclType(int nField); const char* FieldValue(int nField);
const char* FieldValue(const char *szField); bool FieldIsNull(int nField);
bool FieldIsNull(const char *szField); bool GetIntValue(int nField, int &rDest);
bool GetIntValue(const char *szField, int &rDest); bool GetFloatValue(int nField, double &rDest);
bool GetFloatValue(const char *szField, double &rDest); bool GetStringValue(int nField, char *&rDest);
bool GetStringValue(const char *szField, char *&rDest); bool Eof(); void NextRow(); void Finalize();
};
CppSQLite3Query::CppSQLite3Query()
{
mpDB = 0;
mpStmt = 0;
mnCols = 0;
mbEof = true;
} CppSQLite3Query::CppSQLite3Query(sqlite3 *pdb, sqlite3_stmt *pStmt, bool bEof)
{
mpDB = pdb;
mpStmt = pStmt;
mbEof = bEof;
mnCols = sqlite3_column_count(pStmt);
} CppSQLite3Query::CppSQLite3Query(const CppSQLite3Query &rQuery)
{
mpStmt = rQuery.mpStmt;
const_cast<CppSQLite3Query &>(rQuery).mpStmt = 0;
mnCols = rQuery.mnCols;
mbEof = rQuery.mbEof;
} CppSQLite3Query& CppSQLite3Query::operator =(const CppSQLite3Query &rQuery)
{
mpStmt = rQuery.mpStmt;
const_cast<CppSQLite3Query &>(rQuery).mpStmt = 0;
mnCols = rQuery.mnCols;
mbEof = rQuery.mbEof; return *this;
} CppSQLite3Query::~CppSQLite3Query()
{
Finalize();
} void CppSQLite3Query::CheckStmt()
{
if (mpStmt == 0)
{
throw CppSQLite3Exception(CPPSQLITE_ERROR,
"Invalid Stmt Pointer",
DONT_DELETE_MSG);
}
} int CppSQLite3Query::FieldNums()
{
CheckStmt(); return mnCols;
} //依据字段名返回列索引
int CppSQLite3Query::FieldIndex(const char* szField)
{
CheckStmt(); if (szField)
{
for (int nField = 0; nField < mnCols; nField++)
{
//后面还有非常多相似的函数,參数差点儿相同,须要一个sqlite3_stmt*和列索引值,这应该是内部查询了之后返回的结果,而不是事先保存的
const char *szTemp = sqlite3_column_name(mpStmt, nField);
if (strcmp(szTemp, szField) == 0)
{
return nField;
}
}
} throw CppSQLite3Exception(CPPSQLITE_ERROR,
"Invalid field name requested",
DONT_DELETE_MSG);
}
const char* CppSQLite3Query::FieldName(int nField)
{
CheckStmt(); if (nField < 0 || nField > mnCols-1)
{
throw CppSQLite3Exception(CPPSQLITE_ERROR,
"Invalid field index requested",
DONT_DELETE_MSG);
} return sqlite3_column_name(mpStmt, nField);
} int CppSQLite3Query::FieldDataType(int nField)
{
CheckStmt(); if (nField < 0 || nField > mnCols-1)
{
throw CppSQLite3Exception(CPPSQLITE_ERROR,
"Invalid field index requested",
DONT_DELETE_MSG);
} return sqlite3_column_type(mpStmt, nField);
}
const char* CppSQLite3Query::FieldDeclType(int nField)
{
CheckStmt(); if (nField < 0 || nField > mnCols-1)
{
throw CppSQLite3Exception(CPPSQLITE_ERROR,
"Invalid field index requested",
DONT_DELETE_MSG);
} return sqlite3_column_decltype(mpStmt, nField);
} const char* CppSQLite3Query::FieldValue(int nField)
{
CheckStmt(); if (nField < 0 || nField > mnCols-1)
{
throw CppSQLite3Exception(CPPSQLITE_ERROR,
"Invalid field index requested",
DONT_DELETE_MSG);
} return (const char*)sqlite3_column_text(mpStmt, nField); } const char* CppSQLite3Query::FieldValue(const char *szField)
{
int nField = FieldIndex(szField);
return FieldValue(nField);
} bool CppSQLite3Query::FieldIsNull(int nField)
{
return (FieldDataType(nField) == SQLITE_NULL);
} bool CppSQLite3Query::FieldIsNull(const char *szField)
{
int nField = FieldIndex(szField);
return (FieldDataType(nField) == SQLITE_NULL);
} bool CppSQLite3Query::GetIntValue(int nField, int &rDest)
{
if (FieldDataType(nField) == SQLITE_NULL)
{
return false;
}
else
{
rDest = sqlite3_column_int(mpStmt, nField);
return true;
}
} bool CppSQLite3Query::GetIntValue(const char *szField, int &rDest)
{
int nField = FieldIndex(szField);
return GetIntValue(nField, rDest);
} bool CppSQLite3Query::GetFloatValue(int nField, double &rDest)
{
if (FieldDataType(nField) == SQLITE_NULL)
{
return false;
}
else
{
rDest = sqlite3_column_double(mpStmt, nField);
return true;
}
}
bool CppSQLite3Query::GetFloatValue(const char *szField, double &rDest)
{
int nField = FieldIndex(szField);
return GetFloatValue(nField, rDest);
} bool CppSQLite3Query::GetStringValue(int nField, char *&rDest)
{
if (FieldDataType(nField) == SQLITE_NULL)
{
return false;
}
else
{
rDest = const_cast<char *>((const char*)sqlite3_column_text(mpStmt, nField));
return true;
}
}
bool CppSQLite3Query::GetStringValue(const char *szField, char *&rDest)
{
int nField = FieldIndex(szField);
return GetStringValue(nField, rDest);
} bool CppSQLite3Query::Eof()
{
CheckStmt(); return mbEof;
} void CppSQLite3Query::NextRow()
{
CheckStmt(); int nRet = sqlite3_step(mpStmt); if (nRet == SQLITE_DONE)
{
// no rows
mbEof = true;
}
else if (nRet == SQLITE_ROW)
{
// more rows, nothing to do
}
else
{
nRet = sqlite3_finalize(mpStmt);
mpStmt = 0;
const char* szError = sqlite3_errmsg(mpDB);
throw CppSQLite3Exception(nRet, szError, DONT_DELETE_MSG);
}
} void CppSQLite3Query::Finalize()
{
if (mpStmt)
{
int nRet = sqlite3_finalize(mpStmt);
mpStmt = 0;
if (nRet != SQLITE_OK)
{
const char* szError = sqlite3_errmsg(mpDB);
throw CppSQLite3Exception(nRet, szError, DONT_DELETE_MSG);
}
}
}

C++封装SQLite实例&lt;三&gt;的更多相关文章

  1. Java项目案例之--封装的实例

    Java项目案例之---封装的实例 有一个专业类,有一个专业对象,专业名称:计算机科学与技术,专业编号:J001,专业年限:4,对年限添加约束,如果输入小于0,则默认为0,否则显示输入的值 有一个学生 ...

  2. 获得 LayoutInflater 实例的三种方式

    在实际开发中LayoutInflater这个类还是非常有用的,它的作用类似于findViewById().不同点是LayoutInflater是用来找res/layout/下的xml布局文件,并且实例 ...

  3. [转]获得 LayoutInflater 实例的三种方式

    转自:http://www.cnblogs.com/androidez/archive/2013/07/01/3164729.html 获得 LayoutInflater 实例的三种方式   在实际开 ...

  4. 浅谈学习C++时用到的【封装继承多态】三个概念

    封装继承多态这三个概念不是C++特有的,而是所有OOP具有的特性. 由于C++语言支持这三个特性,所以学习C++时不可避免的要理解这些概念. 而在大部分C++教材中这些概念是作为铺垫,接下来就花大部分 ...

  5. ASP 调用dll(VB)及封装dll实例

    ASP调用dll及封装dll实例,封装为dll可以提供运行效率,加密代码. 打开VB6,新建ActiveX DLL 2.在工程引用中加入Microsoft Active Server Pages Ob ...

  6. IoC容器Autofac之实例优化(三)

    回顾之前的代码 //这个类的作用是筛选出MPG类型的电影 public class MPGMovieLister { public Movie[] GetMPG() { var finder = Mo ...

  7. Java Class类以及获取Class实例的三种方式

    T - 由此 Class 对象建模的类的类型.例如,String.class 的类型是Class<String>.如果将被建模的类未知,则使用Class<?>.   publi ...

  8. 一些有用的javascript实例分析(三)

    原文:一些有用的javascript实例分析(三) 10 输入两个数字,比较大小 window.onload = function () { var aInput = document.getElem ...

  9. WCF小实例以及三种宿主

    WCF小实例以及三种宿主 最近一直在学习WCF相关知识,下面将通过一个小实例对所学的知识进行简单的回顾:本实例是一个简单三层操作数据库,并且也简单实现的三种宿主(控制台宿主,IIS宿主以及Window ...

随机推荐

  1. LintCode 二叉树的层次遍历 II

    中等 二叉树的层次遍历 II 查看执行结果 42% 通过 给出一棵二叉树,返回其节点值从底向上的层次序遍历(按从叶节点所在层到根节点所在的层遍历,然后逐层从左往右遍历) 您在真实的面试中是否遇到过这个 ...

  2. Swift - 常用文件目录路径获取(Home目录,文档目录,缓存目录等)

    当前位置: 首页 > 编程社区 > Swift > Swift - 常用文件目录路径获取(Home目录,文档目录,缓存目录等) Swift - 常用文件目录路径获取(Home目录,文 ...

  3. Android 保存用户偏好设置

    很多情况下都允许用户根据自己的习惯和爱好去设置软件,而我们需要保存这些设置,可以用一个专业保存用户偏好的类:SharedPreferences. 这个类是实现方法其实也就是创建和修改 XML 文件, ...

  4. TWinControl.DefaultHandler处理WM_CTLCOLORMSGBOX..WM_CTLCOLORSTATIC消息的两个参数很有意思,两个都是传递句柄

    procedure TWinControl.DefaultHandler(var Message); begin then begin with TMessage(Message) do begin ...

  5. python处理中文字符

    1.在py文件中使用中文字符 unicode.py文件内容如下所示: # -*- coding:utf-8 -*- str_ch = '我们women' uni_ch = u'我们women' pri ...

  6. ABP启动配置

    ABP启动配置   返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行 ...

  7. jfinal框架教程-学习笔记

    jfinal框架教程-学习笔记 JFinal  是基于 Java  语言的极速  WEB  + ORM  开发框架,其核心设计目标是开发迅速.代码量少.学习简单.功能强大.轻量级.易扩展.Restfu ...

  8. xvfb 初步探究

    有时候我们不关注程序是否有界面(比如自动化测试),只要程序在运行就可以了 很感谢 xvfb 这个工具给我们提供了相关的功能 比如在没有 X server 的机器上运行 gedit, 可以用下面的命令 ...

  9. UVA 11054 Wine trading in Gergovia 葡萄酒交易 贪心+模拟

    题意:一题街道上很多酒店,交易葡萄酒,正数为卖出葡萄酒,负数为需要葡萄酒,总需求量和总售出量是相等的,从一家店到另外一家店需要路费(路费=距离×运算量),假设每家店线性排列且相邻两店之间距离都是1,求 ...

  10. Android显示GIF图片

    今天我们研究一下怎样在Android手机上显示GIF动态图片 首先须要在src文件夹下新建一个自己定义的View.代码例如以下: </pre><pre name="code ...