1、Rob Groves原版
CppSQLite封装类下载(CppSQLite 3.2 , source and sqlite3.dll for SQLite 3.4.0 ):
http://download.csdn.net/download/qing666888/10114989
2、github上其他版本
https://github.com/neosmart/CppSQLite 版本:
SQLite3下载地址:http://www.sqlite.org/2017/sqlite-amalgamation-3210000.zip
谷歌翻译的。
介绍
本文介绍CppSQLite
了一个围绕公共领域SQLite数据库库的非常简单的C ++包装器。
提供了如何将应用程序与SQLite关联的说明,然后介绍了一个使用示例程序CppSQLite
,最后对这些CppSQLite
类进行了说明。
要设置场景,这里是来自SQLite作者的引用...
SQLite是一个C库,它实现了一个可嵌入的SQL数据库引擎。与SQLite库链接的程序可以进行SQL数据库访问,而无需运行单独的RDBMS进程。这个发行版带有一个独立的命令行访问程序(SQLite),可以用来管理SQLite数据库,并作为如何使用SQLite库的一个例子。
SQLite不是用于连接到大型数据库服务器的客户端库。SQLite是服务器。SQLite库直接读取和写入磁盘上的数据库文件。
背景
我一直在寻找简单而强大的软件开发工具和想法,SQLite绝对属于这一类。事实上,“Lite”这个名字有点让人误解,因为它实现了SQL标准的一个很大的子集,包括事务处理,而当像PHP这样的项目开始把它作为标准而不是MySQL来捆绑时,你必须看一看。
我认为在C接口上编写一个简单的包装以使其对C ++友好是很有趣的。SQLite网站上已经列出了一些C ++封装器,但其中一个是商业的,另外一个看起来有点复杂,而另外一个则是针对wxWidgets框架的。毕竟,SQLite的作者似乎已经努力保持简单,所以我认为它的C ++包装应该保持简单。
使用SQLite
SQLite在Windows平台上以2个包的形式提供,作为编译的DLL提供,也以源代码形式提供。即使你只是想使用DLL,你仍然需要获得源代码,因为这包含所需的头文件。
如果需要,可以将SQLite源代码编译到一个库(.lib)文件中,以便静态链接到您的应用程序,但这不在本文中讨论。编译指令可以在SQLite网站上找到。
动态链接仍然需要建立一个.lib文件来连接你的应用程序。这可以使用微软的LIB
命令来完成。在我的系统上,它位于D:\ Program Files \ Microsoft Visual Studio \ VC98 \ Bin \ lib.exe。
解压包含sqlite.dll和sqlite.def的sqlite.zip,并执行以下命令生成lib文件。
c:\>lib /def:sqlite.def
在编译时,sqlite.h需要在应用程序中可见,sqlite.lib也是如此。
sqlite.dll需要在运行时可用于您的应用程序。
CppSQLite演示代码
以下代码演示了如何通过CppSQLite
内联注释使用SQLite的主要功能。
#include "CppSQLite.h"
#include <ctime>
#include <iostream>
using namespace std;
const char* gszFile = "C:\\test.db";
int main(int argc, char** argv)
{
try
{
int i, fld;
time_t tmStart, tmEnd;
CppSQLiteDB db;
cout << "SQLite Version: " << db.SQLiteVersion() << endl;
remove(gszFile);
db.open(gszFile);
cout << endl << "Creating emp table" << endl;
db.execDML("create table emp(empno int, empname char(20));");
///////////////////////////////////////////////////////////////
// Execute some DML, and print number of rows affected by each one
///////////////////////////////////////////////////////////////
cout << endl << "DML tests" << endl;
int nRows = db.execDML("insert into emp values (7, 'David Beckham');");
cout << nRows << " rows inserted" << endl;
nRows = db.execDML(
"update emp set empname = 'Christiano Ronaldo' where empno = 7;");
cout << nRows << " rows updated" << endl;
nRows = db.execDML("delete from emp where empno = 7;");
cout << nRows << " rows deleted" << endl;
/////////////////////////////////////////////////////////////////
// Transaction Demo
// The transaction could just as easily have been rolled back
/////////////////////////////////////////////////////////////////
int nRowsToCreate(50000);
cout << endl << "Transaction test, creating " << nRowsToCreate;
cout << " rows please wait..." << endl;
tmStart = time(0);
db.execDML("begin transaction;");
for (i = 0; i < nRowsToCreate; i++)
{
char buf[128];
sprintf(buf, "insert into emp values (%d, 'Empname%06d');", i, i);
db.execDML(buf);
}
db.execDML("commit transaction;");
tmEnd = time(0);
////////////////////////////////////////////////////////////////
// Demonstrate CppSQLiteDB::execScalar()
////////////////////////////////////////////////////////////////
cout << db.execScalar("select count(*) from emp;")
<< " rows in emp table in ";
cout << tmEnd-tmStart << " seconds (that was fast!)" << endl;
////////////////////////////////////////////////////////////////
// Re-create emp table with auto-increment field
////////////////////////////////////////////////////////////////
cout << endl << "Auto increment test" << endl;
db.execDML("drop table emp;");
db.execDML(
"create table emp(empno integer primary key, empname char(20));");
cout << nRows << " rows deleted" << endl;
for (i = 0; i < 5; i++)
{
char buf[128];
sprintf(buf,
"insert into emp (empname) values ('Empname%06d');", i+1);
db.execDML(buf);
cout << " primary key: " << db.lastRowId() << endl;
}
///////////////////////////////////////////////////////////////////
// Query data and also show results of inserts into auto-increment field
//////////////////////////////////////////////////////////////////
cout << endl << "Select statement test" << endl;
CppSQLiteQuery q = db.execQuery("select * from emp order by 1;");
for (fld = 0; fld < q.numFields(); fld++)
{
cout << q.fieldName(fld) << "(" << q.fieldType(fld) << ")|";
}
cout << endl;
while (!q.eof())
{
cout << q.fieldValue(0) << "|";
cout << q.fieldValue(1) << "|" << endl;
q.nextRow();
}
///////////////////////////////////////////////////////////////
// SQLite's printf() functionality. Handles embedded quotes and NULLs
////////////////////////////////////////////////////////////////
cout << endl << "SQLite sprintf test" << endl;
CppSQLiteBuffer bufSQL;
bufSQL.format("insert into emp (empname) values (%Q);", "He's bad");
cout << (const char*)bufSQL << endl;
db.execDML(bufSQL);
bufSQL.format("insert into emp (empname) values (%Q);", NULL);
cout << (const char*)bufSQL << endl;
db.execDML(bufSQL);
////////////////////////////////////////////////////////////////////
// Fetch table at once, and also show how to
// use CppSQLiteTable::setRow() method
//////////////////////////////////////////////////////////////////
cout << endl << "getTable() test" << endl;
CppSQLiteTable t = db.getTable("select * from emp order by 1;");
for (fld = 0; fld < t.numFields(); fld++)
{
cout << t.fieldName(fld) << "|";
}
cout << endl;
for (int row = 0; row < t.numRows(); row++)
{
t.setRow(row);
for (int fld = 0; fld < t.numFields(); fld++)
{
if (!t.fieldIsNull(fld))
cout << t.fieldValue(fld) << "|";
else
cout << "NULL" << "|";
}
cout << endl;
}
////////////////////////////////////////////////////////////////////
// Test CppSQLiteBinary by storing/retrieving some binary data, checking
// it afterwards to make sure it is the same
//////////////////////////////////////////////////////////////////
cout << endl << "Binary data test" << endl;
db.execDML("create table bindata(desc char(10), data blob);");
unsigned char bin[256];
CppSQLiteBinary blob;
for (i = 0; i < sizeof bin; i++)
{
bin[i] = i;
}
blob.setBinary(bin, sizeof bin);
bufSQL.format("insert into bindata values ('testing', %Q);",
blob.getEncoded());
db.execDML(bufSQL);
cout << "Stored binary Length: " << sizeof bin << endl;
q = db.execQuery("select data from bindata where desc = 'testing';");
if (!q.eof())
{
blob.setEncoded((unsigned char*)q.fieldValue("data"));
cout << "Retrieved binary Length: "
<< blob.getBinaryLength() << endl;
}
const unsigned char* pbin = blob.getBinary();
for (i = 0; i < sizeof bin; i++)
{
if (pbin[i] != i)
{
cout << "Problem: i: ," << i << " bin[i]: "
<< pbin[i] << endl;
}
}
/////////////////////////////////////////////////////////
// Pre-compiled Statements Demo
/////////////////////////////////////////////////////////////
cout << endl << "Transaction test, creating " << nRowsToCreate;
cout << " rows please wait..." << endl;
db.execDML("drop table emp;");
db.execDML("create table emp(empno int, empname char(20));");
tmStart = time(0);
db.execDML("begin transaction;");
CppSQLiteStatement stmt = db.compileStatement(
"insert into emp values (?, ?);");
for (i = 0; i < nRowsToCreate; i++)
{
char buf[16];
sprintf(buf, "EmpName%06d", i);
stmt.bind(1, i);
stmt.bind(2, buf);
stmt.execDML();
stmt.reset();
}
db.execDML("commit transaction;");
tmEnd = time(0);
cout << db.execScalar("select count(*) from emp;")
<< " rows in emp table in ";
cout << tmEnd-tmStart << " seconds (that was even faster!)" << endl;
cout << endl << "End of tests" << endl;
}
catch (CppSQLiteException& e)
{
cerr << e.errorCode() << ":" << e.errorMessage() << endl;
}
////////////////////////////////////////////////////////////////
// Loop until user enters q or Q
///////////////////////////////////////////////////////////
char c(' ');
while (c != 'q' && c != 'Q')
{
cout << "Press q then enter to quit: ";
cin >> c;
}
return 0;
}
CppSQLite类
定义了下面的简单类来封装SQLite的功能。
所有的CppSQLite
类都包含在2个文件CppSQLite.h和CppSQLite.cpp中,这些文件将需要添加到您的应用程序中。
CppSQLiteException
封装SQLite错误代码和消息。这里没什么复杂的,如果需要的话,这个类可以很容易的被合并到一个现有的异常层次结构中
SQLite返回的错误消息需要sqlite_freemem()
由程序员来完成,而这个类承担了这个责任。请注意,对于由此生成的错误消息CppSQLite
,我们不想释放内存,所以有一个可选的结尾参数指示是否CppSQLiteException
释放内存。
class CppSQLiteException
{
public:
CppSQLiteException(const int nErrCode,
char* szErrMess,
bool bDeleteMsg=true);
CppSQLiteException(const CppSQLiteException& e);
virtual ~CppSQLiteException();
const int errorCode() { return mnErrCode; }
const char* errorMessage() { return mpszErrMess; }
static const char* errorCodeAsString(int nErrCode);
private:
int mnErrCode;
char* mpszErrMess;
};
CppSQLiteDB
封装一个SQLite数据库文件。
class CppSQLiteDB
{
public:
enum CppSQLiteDBOpenMode
{
openExisting,
createNew,
openOrCreate
};
CppSQLiteDB();
virtual ~CppSQLiteDB();
void open(const char* szFile);
void close();
int execDML(const char* szSQL);
CppSQLiteQuery execQuery(const char* szSQL);
int execScalar(const char* szSQL);
CppSQLiteTable getTable(const char* szSQL);
CppSQLiteStatement compileStatement(const char* szSQL);
int lastRowId();
void interrupt() { sqlite_interrupt(mpDB); }
void setBusyTimeout(int nMillisecs);
static const char* SQLiteVersion() { return SQLITE_VERSION; }
private:
CppSQLiteDB(const CppSQLiteDB& db);
CppSQLiteDB& operator=(const CppSQLiteDB& db);
sqlite_vm* compile(const char* szSQL);
void checkDB();
sqlite* mpDB;
int mnBusyTimeoutMs;
};
open()
和close()
方法是自我解释。SQLite确实提供了一个mode
参数,sqlite_open()
但这被记录为没有效果,所以不提供CppSQLite
。
execDML()
用于执行数据操纵语言(DML)命令,如create
/ drop
/ insert
/ update
/ delete
语句。它返回受影响的行数。以分号分隔的多个SQL语句可以一次提交和执行。注意: CppSQLite返回受影响的行数有一个潜在的问题。如果还有其他未完成的()操作正在进行,受影响的行数将是累积的,并包括前面的语句。所以,如果这个功能对你很重要,你必须确保任何CppSQLiteQuery
与CppSQLiteStatement
尚未破坏的对象已经finalize()
要求他们在你面前execDML()
。
execQuery()
用于执行查询。该CppSQLiteQuery
对象是由值返回,因为这释放了程序员不必删除它。
execScalar()
是我从ADO.NET获得的一个想法。当需要运行一个简单的聚合函数时,这是一个捷径,例如“ select count(*) from emp
”或“ select max(empno) from emp
”。它返回查询结果第一行中第一个字段的值。其他列和行被忽略。
getTable()
允许SQLite功能,可以在一个单一的操作中获取整个表,而不必像查询一样一次获取一行。实际上,可以通过用一个where
子句指定一个查询来获取表行子集,但是整个结果集是一次返回的。同样,CppSQLiteTable
为了方便起见,该对象被返回值。
compileStatement()
允许实验性的SQLite预编译的SQL功能。见CppSQLiteStatement
下文。
SQLite是无类型的,这意味着所有的字段被存储为字符串。一个例外是INTEGER PRIMARY KEY
类型,它允许一个自动增量字段,很像SQL Server的标识列。该lastRowId()
函数用于确定插入的最后一行的主键值。
interrupt()
在多线程中是有用的,并且允许一个线程中断正在进行的另一个线程上的操作。
setBusyTimeout()
在多线程时也是有用的,并且允许程序员在返回之前等待SQLite等待多长时间,SQLITE_BUSY
如果另一个线程锁定了数据库。默认值是60秒,在打开数据库时设置。
复制构造函数operator=()
是私有的,因为复制CppSQLiteDB
对象是没有意义的。
最后,静态方法SQLiteVersion()
返回底层SQLite DLL的版本号。
CppSQLiteQuery
封装一个SQLite查询结果集。
class CppSQLiteQuery
{
public:
CppSQLiteQuery();
CppSQLiteQuery(const CppSQLiteQuery& rQuery);
CppSQLiteQuery(sqlite_vm* pVM,
bool bEof,
int nCols,
const char** paszValues,
const char** paszColNames,
bool bOwnVM=true);
CppSQLiteQuery& operator=(const CppSQLiteQuery& rQuery);
virtual ~CppSQLiteQuery();
int numFields();
const char* fieldName(int nCol);
const char* fieldType(int nCol);
const char* fieldValue(int nField);
const char* fieldValue(const char* szField);
int getIntField(int nField, int nNullValue=0);
int getIntField(const char* szField, int nNullValue=0);
double getFloatField(int nField, double fNullValue=0.0);
double getFloatField(const char* szField, double fNullValue=0.0);
const char* getStringField(int nField, const char* szNullValue="");
const char* getStringField(const char* szField,
const char* szNullValue="");
bool fieldIsNull(int nField);
bool fieldIsNull(const char* szField);
bool eof();
void nextRow();
void finalize();
private:
void checkVM();
sqlite_vm* mpVM;
bool mbEof;
int mnCols;
const char** mpaszValues;
const char** mpaszColNames;
bool mbOwnVM;
};
nextRow()
并eof()
允许迭代查询结果。
numFields()
,fieldValue()
,fieldName()
,fieldType()
并fieldIsNull()
允许程序员确定领域,它们的名称,值类型的数量,以及是否包含SQL NULL
。有重载的版本允许必要的字段由索引或名称指定。
getIntField(),getFloatField()
并getStringField()
提供一个稍微简单的程序获取字段值的方法,永远不会返回SQL的NULL指针,NULL,
并有一个默认的第二个参数,允许程序员指定返回的值。
在结果中不可能迭代。原因是这CppSQLite
是一个薄包装,并不缓存任何返回的行数据。如果这是必需的,CppSQLiteDB::getTable()
应该使用,或者应用程序可以继承这个类。
finalize()
释放与查询相关联的内存,但析构函数会自动调用它。
CppSQLiteTable
SQLite提供了一种方法来获取一个完整的表的内容在一块内存中,CppSQLiteTable
封装了这个功能。
class CppSQLiteTable
{
public:
CppSQLiteTable();
CppSQLiteTable(const CppSQLiteTable& rTable);
CppSQLiteTable(char** paszResults, int nRows, int nCols);
virtual ~CppSQLiteTable();
CppSQLiteTable& operator=(const CppSQLiteTable& rTable);
int numFields();
int numRows();
const char* fieldName(int nCol);
const char* fieldValue(int nField);
const char* fieldValue(const char* szField);
int getIntField(int nField, int nNullValue=0);
int getIntField(const char* szField, int nNullValue=0);
double getFloatField(int nField, double fNullValue=0.0);
double getFloatField(const char* szField, double fNullValue=0.0);
const char* getStringField(int nField, const char* szNullValue="");
const char* getStringField(const char* szField, const char* szNullValue="");
bool fieldIsNull(int nField);
bool fieldIsNull(const char* szField);
void setRow(int nRow);
void finalize();
private:
void checkResults();
int mnCols;
int mnRows;
int mnCurrentRow;
char** mpaszResults;
};
setRow()
为行之间的移动提供了随机访问方法,并且可以结合使用numRows()
来迭代表格。这种设计决定是为了简单制作,是继同型号的CppSQLiteQuery
,将需要功能bof()
,eof()
,first()
,last()
,next()
和prev()
。
numFields()
,fieldValue()
,fieldName()
,fieldIsNull()
,getIntField()
,getFloatField()
,getStringField()
,close()
,和operator=()
提供相同的功能为CppSQLiteQuery
。
CppSQLiteBuffer
封装SQLite“ sprintf
”功能。
SQLite的提供了一个函数sqlite_mprintf()
,其是像C运行sprintf()
除了没有超速缓存提供,如的可能性sqlite_mprintf()
使用malloc
分配足够的内存。另一个好处sprintf()
就是%Q
标签,它的工作方式%s
除了它将按照撇号,使它们不会混淆正在构建的SQL字符串,并且还将NULL
指针转换为SQL NULL
值。
class CppSQLiteBuffer
{
public:
CppSQLiteBuffer();
~CppSQLiteBuffer();
const char* format(const char* szFormat, ...);
operator const char*() { return mpBuf; }
void clear();
private:
char* mpBuf;
};
operator const char*()
允许程序员将此对象的实例传递给定义的函数CppSQLiteDB
。
CppSQLiteBinary
由于SQLite将所有数据存储为已NULL
终止的字符串,因此如果已嵌入二进制数据,则无法存储二进制数据NULL
。SQLite的提供2个功能sqlite_encode_binary()
和sqlite_decode_binary()
可以被用于允许二进制数据的存储和检索。CppSQLiteBinary
封装了这两个功能。
这两个函数当前不是作为预编译DLL的一部分提供的,所以我已经将SQLite的encode.c文件的全部内容复制到CppSQLite.cpp文件中。如果这些函数在未来某个时间点在DLL中提供,可以很容易地从CppSQLite.cpp中删除。
class CppSQLiteBinary
{
public:
CppSQLiteBinary();
~CppSQLiteBinary();
void setBinary(const unsigned char* pBuf, int nLen);
void setEncoded(const unsigned char* pBuf);
const unsigned char* getEncoded();
const unsigned char* getBinary();
int getBinaryLength();
unsigned char* allocBuffer(int nLen);
void clear();
private:
unsigned char* mpBuf;
int mnBinaryLen;
int mnBufferLen;
int mnEncodedLen;
bool mbEncoded;
};
CppSQLiteBinary
可以使用setEncoded()
和setBinary()
函数接受编码或二进制形式的数据。无论使用哪种方式,总是会分配足够的内存来存储编码版本,这通常会更长,因为null
s和单引号必须转义。
使用getEncoded()
和getBinary()
功能检索数据。根据数据当前在班级中的哪种形式,可能需要转换。
getBinaryLength()
返回存储的二进制数据的长度,如果需要,再次将保存的格式从编码转换为二进制。
allocBuffer()
可以用来防止数据必须通过临时缓冲区循环,如本文开始时的示例代码。这个函数可以用在下面的例子中,其中数据从文件直接读入CppSQLiteBinary
对象。
int f = open(gszJpgFile, O_RDONLY|O_BINARY);
int nFileLen = filelength(f);
read(f, blob.allocBuffer(nFileLen), nFileLen);
CppSQLiteStatement
SQLite为使用预编译的SQL提供了一些实验功能。当不同的值一次又一次地执行相同的SQL时,只需编译一次SQL并多次执行,每次使用不同的值,就可以显着提高性能。CppSQLiteStatement
封装了这个功能。
class CppSQLiteStatement
{
public:
CppSQLiteStatement();
CppSQLiteStatement(const CppSQLiteStatement& rStatement);
CppSQLiteStatement(sqlite* pDB, sqlite_vm* pVM);
virtual ~CppSQLiteStatement();
CppSQLiteStatement& operator=(const CppSQLiteStatement& rStatement);
int execDML();
CppSQLiteQuery execQuery();
void bind(int nParam, const char* szValue);
void bind(int nParam, const int nValue);
void bind(int nParam, const double dwValue);
void bindNull(int nParam);
void reset();
void finalize();
private:
void checkDB();
void checkVM();
sqlite* mpDB;
sqlite_vm* mpVM;
};
使用包含占位符的SQL语句CppSQLiteStatement
调用对象CppSQLiteDB::compileStatement()
,如下所示:
CppSQLiteStatement stmt = db.compileStatement("insert into emp values (?, ?);");
stmt.bind(1, 1);
stmt.bind(2, "Emp Name");
stmt.execDML();
stmt.reset();
CppSQLiteStatement::bind()
然后在调用execDML()
或execQuery()
适当的方法之前,方法用于设置占位符的值。
程序员完成任一execDML()
或两者的结果后execQuery()
,reset()
可以调用该方法将语句恢复为编译状态。CppSQLiteStatement::bind()
然后可以再次使用这些方法,其次是execDML()
或execQuery()
。一个典型的用法是在CppSQLiteDemo程序中演示的循环中。
多线程
SQLite在默认情况下在Windows上被编译为线程安全的,并且CppSQLite
使用一些SQLite特性来帮助多线程使用。本文附带的源代码中包含一个名为CppSQLiteDemoMT的第二个演示程序,演示了这些功能。
每个希望在同一个数据库文件上同时使用CppSQLite的线程都必须有自己的CppSQLiteDB
对象和调用open()
。换句话说,多个线程同时调用一个CppSQLiteDB
对象是一个错误。一个例外是CppSQLiteDB::interrupt()
,可以从一个线程使用中断另一个线程的工作。
CppSQLite
多线程使用的另一个变化是使用sqlite_busy_timeout()
导致SQLite在返回之前等待指定的毫秒数的函数SQLITE_BUSY
。默认情况下,CppSQLite
将其设置为60,000(60秒),但可以CppSQLiteDB::setBusyTimeout()
根据需要进行更改。在CppSQLiteDemoMT程序中显示了这样做的各种示例。
SQLite功能目前没有包装
SQLite提供了一种机制,允许应用程序开发人员定义可以从SQL语句中调用的存储过程和聚合函数。这些存储过程由应用程序开发人员用C写成,并通过函数指针让SQLite知道。这就是SQLite构建函数的SQL如何实现的,但是这个功能目前还不能满足CppSQLite
。
SQLite在封装的函数上提供了一些其他的变体,鼓励读者学习SQLite文档。
托管C ++
可以将SQLite和CppSQLite编译为托管的C ++程序It Just Works(IJW)。您将需要设置CppSQLite.cpp文件,以便它不使用预编译头,也不使用托管扩展,即不使用/ clr。
CppSQLite下载包含一个托管C ++演示。
SQLite版本3
在撰写本文时,SQLite版本3正在测试中。有关更多详细信息,请参阅http://www.sqlite.org/。我已经创建了一个CppSQLite
SQLite版本3 的端口,下面的注释解释了这些差异。
有一组新的类的前缀CppSQLite3
,例如CppSQLite3Exception
。这允许程序CppSQLite
与两个版本的SQLite 链接,就像SQLite本身的两个版本一样。
最初并不支持UTF-16,因为这不是我所经历的,也不知道如何测试。这可以在以后用另一组类,称为例如添加CppSQLite3Exception16
等需要注意的是sqlite3的一些东西,如sqlite3_exec()
和sqlite3_get_table()
不似乎有UTF-16版本中,还sqlite3_vmprintf()
,使用CppSQLiteBuffer
。
错误消息现在返回sqlite3_errmsg()
并不需要被释放。为了保持一致性,抛出异常的代码CppSQLite
和CppSQLite3
从SQLite版本3返回的消息已经被改变了,所以它传递了DONT_DELETE_MSG作为最后一个参数CppSQLite3Exception
。这个异常是sqlite3_exec()和返回的消息sqlite3_get_table()
。
SQLite版本3现在直接支持BLOB数据,因此不需要对它进行编码或解码,而且似乎没有工作CppSQLiteBinary
。但是,SQLite版本3的变化意味着处理BLOB数据的唯一方法似乎是使用准备好的语句(CppSQLiteStatement
)。不是一个真正的问题,但到现在为止,CppSQLiteBinary
已经允许使用的呼叫(编码)的二进制数据CppSQLiteDB::execQuery()
,CppSQLiteDB::execDML()
并从返回的数据CppSQLiteDB::getTable()
。
sqlite_encode_binary()
并sqlite_decode_binary()
仍然包含在SQLite版本3源代码发行版中,虽然不清楚这是否是错误,因为它们没有sqlite3前缀,也不是从DLL中导出。CppSQLite3
复制源到这两个函数。在CppSQlite up
1.3版之前的版本中,SQLite的版本是2.8.15,它们不是从DLL中导出的。CppSQLite3Binary
是完全相同的副本CppSQLiteBinary
,与源捆绑sqlite_encode_binary()
和sqlite_decode_binary()
。这将允许CppSQLite
和之间轻松移植CppSQLite3
。希望使用sqlite3 BLOB和其减少的存储空间的程序将不需要使用CppSQLite3Binary
,并且无论如何都需要重写。
SQLite版本3引入了对所使用的数据分类系统的更改。请参阅http://www.sqlite.org/datatype3.html。由于这个原因,CppSQLiteQuery::FieldType()
已被2个函数替换:CppSQLiteQuery::FieldDeclType()
它将字段的声明数据类型作为字符串CppSQLiteQuery::FieldDataType()
返回,并且返回当前行中存储在该列中的数据的实际类型,作为SQLite版本3#定义的价值。
演示程序已经稍微改变,以演示新功能,并解释SQLite版本3的不同锁定行为。请参阅http://www.sqlite.org/lockingv3.html。请注意,SQLite
版本3.0.5引入了一个编译时间选项,用于更改锁定行为,请参阅http://www.sqlite.org/changes.html以获取更多详细信息。
SQLite版本3作为本文顶部的单独下载提供。
未来的工作
我可以添加对剩下的SQLite功能的支持CppSQLite
。目前,这意味着存储过程和聚合函数。
跨平台能力
自从1.2版以来CppSQLite
,我一直努力不去做任何与微软相关的事情,并且已经成功编译并运行了mingw32以及Visual C ++ 的演示程序。
由于mingw32基于GCC,在Linux / Unix上应该没有大的问题,虽然多线程演示程序CppSQLiteDemoMT使用这个_beginthread()
调用,这显然不起作用。这可能很容易解决,例如使用pthreads。
捐款
感谢代码项目成员的建议和修补程序CppSQLite
,也感谢Mateusz Loskot担任审阅者。
结论
CppSQLite
使得SQLite更容易在C ++程序中使用,但不会比平面C接口提供更低的功耗或效率。
如果没有别的,写作CppSQLite
为作者提供了对SQLite的力量和简单性的洞察。希望本文的读者也能从中受益。
CppSQLite的历史(目标SQLite 2.8.n)
- 1.0 - 2004年3月3日 - 初始版本。
-
1.1 - 2004年3月10日
-
重命名
CppSQLiteException::errorMess()
为CppSQLiteException::errorMessage()
。 -
第二个构造函数
CppSQLiteException()
。 -
现在将错误代码解码为字符串
CppSQLiteException
。 -
sqlite_finalize()
遇到问题后立即致电以获取错误详细信息sqlite_step()
。 -
新增
CppSQLiteBinary
课程
-
重命名
-
1.2 - 2004年4月2日 - 未发布。
- 更新文章。
- 删除了使用微软特定的扩展(我希望)
-
检查
NULL
指针 - 更新了SQLite 2.8.13
-
利用
sqlite_busy_timeout()
并sqlite_interrupt()
帮助多线程使用 - 第二个多线程使用演示程序
- 增加了预编译的SQL语句的支持
-
添加了从中确定列类型的功能
CppSQLiteQuery
-
添加
CppSQLiteDB::execScalar()
-
2004年4月12日至12日
- 更新后的文章审查
- 在审查之后使用C ++而不是C标准头文件
-
1.3 - 2004年5月21日
- 添加“BSD样式”许可证通知源文件
- 修正了bind()的bug
-
新增
getIntField()
,getStringField()
,getFloatField()
- 增加了重载函数来按名称访问字段
-
CppSQLiteDB::ExecDML()
与实施sqlite_exec()
使多个语句可以一次执行。 -
在关于潜在的回报价值问题的文章中增加注释
CppSQLiteDB::execDML()
- 增加了托管的C ++示例程序
-
2004年8月14日至30日
- 升级到SQLite 2.8.15
-
删除了sqlite_encode_binary()的源代码,
sqlite_decode_binary()
现在从SQLite DLL中导出 - 添加了有关托管C ++的文章部分
CppSQLite3的历史(目标SQLite 3.nn)
-
2004年8月3日至30日
- 初始版本使用SQLite版本3.0.6
-
2004年10月3.1 - 26日
- 升级到vSQLite 3.0.8
-
新增
CppSQLiteDB3::tableExists()
功能 -
实现使用sqlite3的函数来代替,等。
getXXXXField
atoi()
atof()
-
2011年6月3.2日至24日
- 与SQLite3版本3.4.0捆绑在一起
-
CppSQLite3DB::SQLiteHeaderVersion()
,CppSQLite3DB::SQLiteLibraryVersion()
,CppSQLite3DB::SQLiteLibraryVersionNumber()
-
固定
execScalar
来处理NULL
结果 -
增加了
Int64
功能CppSQLite3Statement
-
新增
CppSQLite3DB::IsAutoCommitOn()
,可用于测试交易是否有效 -
从
CppSQLite3DB::close()
错误中抛出异常 -
在以上例外陷阱
CppSQLite3DB::~CppSQLite3DB()
- 表中较大的缓冲区大小为256
-
sqlite3_prepare
取而代之sqlite3_prepare_v2
-
修复
CppSQLite3DB::compile()
由Dave Rollins提供的 - 按照Dave Rollins建议的名称绑定参数
原文地址:https://www.codeproject.com/Articles/6343/CppSQLite-C-Wrapper-for-SQLite