前一篇博客中介绍的是怎样依据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. grails一对一关联关系

    一对一关联关系开发中用的没有一对多那么广泛.可是我认为掌握以下还是有必要的.一对一关联关系有一张表存在外键,引用的通常是主表的主键.grails也对一对一关联关系提供了非常好的支持.配置也是简单的不得 ...

  2. Android 高仿 频道管理----网易、今日头条、腾讯视频 (可以拖动的GridView)附源码DEMO

    距离上次发布(android高仿系列)今日头条 --新闻阅读器 (二) 相关的内容已经半个月了,最近利用空闲时间,把今日头条客户端完善了下.完善的功能一个一个全部实现后,就放整个源码.开发的进度就是按 ...

  3. JSP的学习(1)——基本知识与底层原理

    通过之前的学习,我们已经对Servlet有所了解,现在我们先来学习JSP,当能使用JSP进行友好的页面显示之后,再回去学习Servlet的其他高级特性会将整个学习很好的融入进来. JSP,即Java ...

  4. Extract Datasets

    *&---------------------------------------------------------------------* *& Report ZTEST2013 ...

  5. CSS中float属性和clear属性的一些笔记

    在学习CSS的最后一部分内容中,float属性和clear属性比较难以用语言描述,因此在笔记本中无法准确的记录这两个属性的用法.所以在博客园上以图文的形式记录这两种属性的特征,以备以后查阅. 首先,定 ...

  6. Guava学习笔记:EventBus(转)

    EventBus是Guava的事件处理机制,是设计模式中的观察者模式(生产/消费者编程模型)的优雅实现.对于事件监听和发布订阅模式,EventBus是一个非常优雅和简单解决方案,我们不用创建复杂的类和 ...

  7. MVP模式在Android开发中的应用

    一.MVP介绍      随着UI创建技术的功能日益增强,UI层也履行着越来越多的职责.为了更好地细分视图(View)与模型(Model)的功能,让View专注于处理数据的可视化以及与用户的交互.同一 ...

  8. go语言初体验

    go下载地址: http://code.google.com/p/go/downloads/list go官方安装地址: http://golang.org/doc/install 另外收集一些关于g ...

  9. (三)----使用HttpClient发送HTTP请求(分别通过GET和POST方法发送数据)

    文章来源:http://www.cnblogs.com/smyhvae/p/4006009.html 一.GET和POST的对比: 在漫长的时间当中,其他的方法逐渐的退出了历史舞台,最常用的只剩下GE ...

  10. 学习android内核 -- 内存管理相关

    Android内存管理: 1.当应用程序关闭以后,后台对应的进程并没有真正的退出(处于休眠状态,一般不占用系统CPU的资源),这是为了下次再启动的时候能快速启动. 2.当系统内存不够时,AmS会主动根 ...