C++打包SQLite实例<二>
C++封装SQLite实例<二>
这一篇博客主要讲如何使用SQLite有关库函数去管理数据库中的一张表。
主要用到的函数:
SQLITE_API int sqlite3_get_table
( sqlite3 *db, /* The database on which the SQL executes */ const char *zSql, /* The SQL to be executed */ char ***pazResult, /* Write the result table here */ int *pnRow, /* Write the number of rows in the result here */ int *pnColumn, /* Write the number of columns of result here */ char **pzErrMsg /* Write error messages here */ )比较难理解的是第三个参数,是一个三重指针。pazResult指向的是一个一维指针数组,char*result[Num];在SQLite中所有的字段都是被解释为字符串类型存储的,采用的是UTF8编码方式。并且将一个二维表存储在了一维数组中,就是将一个一维数组分割成了mnRows个段,每一段代表二维表中的一行,一行有mnCols个元素。只要给出确切的行值与列值,就能根据公式算出在一位数组中的索引下标。
class CppSQLite3Table { private: int mnCurrentRow; int mnRows; int mnCols; char **mpaszResults; void CheckResluts(); public: CppSQLite3Table(); CppSQLite3Table(const CppSQLite3Table &rTable); CppSQLite3Table(char **paszResults, int nRows, int nCols); ~CppSQLite3Table(); CppSQLite3Table& operator= (const CppSQLite3Table &rTable); int NumOfFields(); int NumOfRows(); const char* NameOfField(int nField); const char* ValueOfField(int nField); const char* ValueOfField(const char *szField); bool FieldIsNull(int nField); bool FieldIsNull(const char *szField); bool GetIntField(int nField, int &rDest); bool GetIntField(const char *szField, int &rDest); bool GetFloatField(int nField, double &rDest); bool GetFloatField(const char *szField, double &rDest); bool GetStringField(int nField, char *&rDest); bool GetStringField(const char *szField, char *&rDset); void SetRow(int nRow); void finalize(); };
CppSQLite3Table::CppSQLite3Table() { mnCols = 0; mnRows = 0; mnCurrentRow = 0; mpaszResults = 0; } CppSQLite3Table::CppSQLite3Table(const CppSQLite3Table &rTable) { mnCols = rTable.mnCols; mnRows = rTable.mnRows; mnCurrentRow = rTable.mnCurrentRow; mpaszResults = rTable.mpaszResults; const_cast<CppSQLite3Table&>(rTable).mpaszResults = 0; //当表复制时,销毁原来的表,防止丢失修改 } CppSQLite3Table::CppSQLite3Table(char **paszResults, int nRows, int nCols) { mpaszResults = paszResults; //给出一个一维指针数组,初始化一个表 mnCols = nCols; mnRows = nRows; mnCurrentRow = 0; } CppSQLite3Table::~CppSQLite3Table() { finalize(); } CppSQLite3Table& CppSQLite3Table::operator= (const CppSQLite3Table &rTable) { finalize(); mpaszResults = rTable.mpaszResults; const_cast<CppSQLite3Table &>(rTable).mpaszResults = 0; mnCols = rTable.mnCols; mnRows = rTable.mnRows; mnCurrentRow = rTable.mnCurrentRow; return *this; } void CppSQLite3Table::finalize() { if (mpaszResults) { sqlite3_free_table(mpaszResults); //利用库函数销毁表存储内容 mpaszResults = 0; } } int CppSQLite3Table::NumOfFields() { CheckResluts(); return mnCols; } int CppSQLite3Table::NumOfRows() { CheckResluts(); return mnRows; } const char* CppSQLite3Table::NameOfField(int nField) { CheckResluts(); if (nField < 0 || nField > mnCols-1) { throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field index requested", DONT_DELETE_MSG); } return mpaszResults[nField]; //一位数组的头mnCols个元素存放的是表的字段名称,存储具体位置是mpaszResults[0,,,mnCols-1]。 } const char* CppSQLite3Table::ValueOfField(int nField) { CheckResluts(); if (nField < 0 || nField > mnCols-1) { throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field index requested", DONT_DELETE_MSG); } //根据要查询的当前行与列值算出在一位数组中的索引下标,额外加一个mnCols是第一行存储的是字段名 int nIndex = mnCurrentRow*mnCols + mnCols + nField; return mpaszResults[nIndex]; } //根据字段名称来访问某一列的数据 const char* CppSQLite3Table::ValueOfField(const char *szField) { CheckResluts(); if (szField) { for (int nField = 0; nField < mnCols; nField++) { if (strcmp(szField, mpaszResults[nField]) == 0) { int nIndex = mnCurrentRow*mnCols + mnCols + nField; return mpaszResults[nIndex]; } } } throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field name requested", DONT_DELETE_MSG); } bool CppSQLite3Table::FieldIsNull(int nField) { CheckResluts(); return (ValueOfField(nField) == 0); } bool CppSQLite3Table::FieldIsNull(const char* szField) { CheckResluts(); return (ValueOfField(szField) == 0); } //这里的获取具体类型数值函数,需要用户对数据库中的表有一定的了解,知道哪些字段存储的是什么内容 //并且使用的是外部传递引用的形式 bool CppSQLite3Table::GetIntField(int nField, int &rDest) { if (FieldIsNull(nField)) { return false; } else { //atoi()函数是C库函数,讲数值型字符串转换为整型值 rDest = atoi(ValueOfField(nField)); return true; } } bool CppSQLite3Table::GetIntField(const char *szField, int &rDest) { if (FieldIsNull(szField)) { return false; } else { rDest = atoi(ValueOfField(szField)); return true; } } bool CppSQLite3Table::GetFloatField(int nField, double &rDest) { if (FieldIsNull(nField)) { return false; } else { //C库函数,将数值型字符串转换为浮点数 rDest = atof(ValueOfField(nField)); return true; } } bool CppSQLite3Table::GetFloatField(const char *szField, double &rDest) { if (FieldIsNull(szField)) { return false; } else { rDest = atof(ValueOfField(szField)); return true; } } bool CppSQLite3Table::GetStringField(int nField, char *&rDest) { if (FieldIsNull(nField)) { return false; } else { rDest = const_cast<char *>(ValueOfField(nField)); return true; } } bool CppSQLite3Table::GetStringField(const char *szField, char *&rDset) { if (FieldIsNull(szField)) { return false; } else { rDset = const_cast<char *>(ValueOfField(szField)); return true; } } //在每一次需要获取数据的时候都要设置要访问的行值 void CppSQLite3Table::SetRow(int nRow) { CheckResluts(); if (nRow < 0 || nRow > mnCols-1) { throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid row index requested", DONT_DELETE_MSG); } mnCurrentRow = nRow; } void CppSQLite3Table::CheckResluts() { if (mpaszResults == 0) { throw CppSQLite3Exception(CPPSQLITE_ERROR, "Null Results pointer", DONT_DELETE_MSG); } }
与select查询相比,获取并维护一整张表会容易很多,对表的访问全转化为对一位数组的访问了,只需要做一个简单的逻辑地址(就是下标)转化。后面会讲如何获取一个查询并维护这个查询的结果,这个结果可能只有一条记录,也可能有很多条记录。