C++封装SQLite实例<三>

前一篇博客中介绍的是怎样依据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);
		}
	}
}
时间: 2024-10-05 05:31:53

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

Linux DNS服务器子域授权、转发器和转发域配置实例(三)

DNS子域授权: 这里我们只演示正向解析的子域授权   父域能够解析子域的A记录(不是权威的,因为不是自身解析的),  子域不能解析父域的A记录,如果非要解析父域中的地址过程是:先去找互联网的根域在层层到下查找.(但是我们可以在子域建立转发,使能够解析父域的A记录) 实例: 说明父域为:ning.com子域1为:ning1.ning.com 子域2为:ning2.ning.com  补充说明:父域和子域只要能通信即可,没有必要在同一网段,我们这里为了方便操作放在一个网段了..小伙伴们明白!  实

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

T - 由此 Class 对象建模的类的类型.例如,String.class 的类型是Class<String>.如果将被建模的类未知,则使用Class<?>. [java] view plain copy print? public final class Class<T> extends Object  implements java.io.Serializable, java.lang.reflect.GenericDeclaration, java.lang.r

功能齐全、效率一流的免费开源数据库导入导出工具(c#开发,支持SQL server、SQLite、ACCESS三种数据库),每月借此处理数据5G以上

软件名:DataPie 功能:支持SQL server.SQLite.ACCESS数据库的导入.导出.存储过程调用,支持EXCEL2007.EXCEL2003.ACCESS2007. CSV文件导入数据库,支持EXCEL.CSV.ZIP.ACCESS文件方式导出,支持数据拆分导出及自定义SQL查询与导出. 开发背景:作者从事财务管理工作,主要是出具集团的内部财务报表,随着公司精细化管理的需求,管理报表的数据量急速增长, 依赖EXCEL加工处理数据已经变得极为困难,因此团队全面转向关系数据库进行数

【转】delphi程序只允许运行一个实例的三种方法:

一.        创建互斥对象 在工程project1.dpr中创建互斥对象 Program project1 Uses Windows,Form, FrmMain in 'FrmMain.pas' {MainForm}; {$R *.res} var hAppMutex: THandle; //声明互斥变量 begin hAppMutex := CreateMutex(nil, false,’projectname’); //创建互斥对象projectname工程名称 if ( (hAppM

获得 LayoutInflater 实例的三种方式

在实际开发中LayoutInflater这个类还是非常有用的,它的作用类似于findViewById().不同点是LayoutInflater是用来找res/layout/下的xml布局文件,并且实例化:而findViewById()是找xml布局文件下的具体widget控件(如Button.TextView等). 具体作用: 1.对于一个没有被载入或者想要动态载入的界面,都需要使用LayoutInflater.inflate()来载入: 2.对于一个已经载入的界面,就可以使用Activiyt.

Flask实例教程三

一:Flask中url的工作方式 # encoding=utf-8 from flask import Flask app = Flask(__name__) @app.route("/task/") def task_list():     return "List of all task" @app.route("/task/<int:task_id>/") def task_detail(task_id):     return

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

原文:一些有用的javascript实例分析(三) 1 10 输入两个数字,比较大小 2 window.onload = function () 3 { 4 var aInput = document.getElementsByTagName("input"); 5 var aSpan = document.getElementsByTagName("span")[0]; 6 for(var i=0;i<aInput.length-1;i++){ 7 aInp

获得 LayoutInflater 实例的三种方式(转)

原文地址:http://www.cnblogs.com/androidez/archive/2013/07/01/3164729.html 在实际开发中LayoutInflater这个类还是非常有用的,它的作用类似于findViewById().不同点是LayoutInflater是用来找res/layout/下的xml布局文件,并且实例化:而findViewById()是找xml布局文件下的具体widget控件(如Button.TextView等). 具体作用: 1.对于一个没有被载入或者想要

类,对象 ,封装,实例变量,类变量,继承,多态

类:对一类事物的抽象.例如:人 ,狗,猫,鸟...这样是一大类的概括.讲人,可以指很多人,狗也可以分很多种狗 对象:具体的某个类的实例.就想 张三-->指的就是人这个类下面的具体的某一个实例.泰迪 就是狗这个类下面的某个实例 面向对象的三个特性: 封装:就是将属性给封装起来,这个是你特有性质,你可以让外界知道,也可以不让外界知道 例如: # Author:zylong class Person: #人都有性别,姓名,身高,体重 def __init__(self,name,sex,heigh,w