CppSQLite Demo 详解(翻译)--已完成

来源:互联网 发布:淘宝买家怎么开通直播 编辑:程序博客网 时间:2024/05/03 07:28

英文原文来自:https://www.codeproject.com/articles/6343/cppsqlite-c-wrapper-for-sqlite

CppSqlite 是一个针对 SQLite 的 c++ 的封装版本

可以使用sqlite  的 dll 动态或者静态编译,也可以直接在你的工程内 添加四个文件:sqlite3.c  sqlite3.h  CppSQLite3.h 和 CppSQLite3.cpp


官网  Demo 示例代码如下:

#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 Classes

The following simple classes are defined to encapsulate the functionality of SQLite.

下面几个简单的类定义的 SQLite 的功能

All the CppSQLite classes are contained in 2 files CppSQLite.h and CppSQLite.cpp, which will need to be added to your application.

所有的CppSqlite 类都包含在 CppSQLite.h 和 CppSQLite.cpp 两个文件内,需要添加进入你的app。


CppSQLiteException 异常类

Encapsulates a SQLite error code and message. Nothing complicated here, and this class could easily be incorporated into an existing exception hierarchy, if required.

封装一个SQLite的错误代码和消息。没有什么复杂的东西,这类很容易被纳入现有的异常层次结构,如果需要的话。

Error messages returned by SQLite need to be sqlite_freemem()'d by the programmer, and this class takes on that responsibility. Note that for error messages generated by CppSQLite, we don't want to free the memory, so there is an optional trailing parameter that dictates whether CppSQLiteException frees the memory.

SQLite返回的错误消息需要有程序员使用 sqlite_freemem()' 释放,CppSQLite的异常类承担了这个责任。注意,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

Encapsulates a SQLite database file.

封装的一个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() and close() methods are self explanatory. SQLite does provide a mode argument to sqlite_open()but this is documented as having no effect, so is not provided for in CppSQLite.

open()和close()方法是自解释的。SQLite确实提供了参数 mode 给 sqlite_open(),但被证实是没有效果的,所以CppSQLite不提供那个参数

execDML() is used to execute Data Manipulation Language (DML) commands such ascreate/drop/insert/update/delete statements. It returns the number of rows affected. Multiple SQL statements separated by semi-colons can be submitted and executed all at once. 

execDML()是用于执行数据操作语言(DML)命令,如创建/删除/插入/更新/删除语句。它返回受影响的行数。可以一次性提交多个由分号分隔的SQL语句。

Note: there is a potential problem with the way that CppSQLite returns the number of rows affected. If there are any other un-finalized() operations in progress the number of rows affected will be cumulative and include those from previous statements. So if this feature is important to you, you have to make sure that any CppSQLiteQuery andCppSQLiteStatement objects that have not destructed yet have finalize() called on them before you execDML().

注意:CppSQLite返回受影响的行数有一个潜在的问题。如果有任何其他un-finalized()操作,返回的受影响的行数会累积并包括先前的语句的结果。所以如果这个功能对你很重要,你必须确保在你执行execDML()前没有任何CppSQLiteQuery CppSQLiteStatement对象没执行finalize()就被销毁了。

execQuery() is used to execute queries. The CppSQLiteQuery object is returned by value, as this frees the programmer from having to delete it.

execQuery()用于执行查询。通过传值返回 CppSQLiteQuery对象,因此使程序员不必删除它。

execScalar() is an idea I got from ADO.NET. It is a shortcut for when you need to run a simple aggregate function, for example, "select count(*) from emp" or "select max(empno) from emp". It returns the value of the first field in the first row of the query result. Other columns and rows are ignored.

execScalar()是我从ADO.NET得到的idea。这是一个当你需要运行简单的聚合函数的快捷方式,例如,“select count(*) from emp”或“select max(empno) from emp”。它返回查询结果的第一行的第一个字段的值。其他列和行被忽略。

getTable() allows for the SQLite feature which can fetch a whole table in a single operation, rather than having to fetch one row at a time as with a query. Actually, subsets of table rows can be fetched by specifying a query with a where clause, but the whole result set is returned at once. Again, the CppSQLiteTable object is returned by value for convenience.

getTable()允许SQLite特性可以通过单个操作获取整个表,而不必一次查询获取一行。实际上,也可以通过 where 语句查询的一个子集,整个结果集一次性返回。再次说明,为方便起见 CppSQLiteTable对象通过传值返回。

compileStatement() allows for the experimental SQLite pre-compiled SQL feature. SeeCppSQLiteStatement below.

compileStatement() 允许实验SQLite预编译特性。请参阅下面的CppSQLiteStatement。

SQLite is typeless, which means all fields are stored as strings. The one exception to this is the INTEGER PRIMARY KEY type, which allows an auto increment field, much like the SQL Server's identity columns. ThelastRowId() function is used to determine the value of the primary key from the last row inserted.

SQLite是无类型,这意味着所有字段存储为字符串。唯一的例外是 INTEGER PRIMARY KEY 类型,它允许字段值自增,就像SQL Server的标识列。lastRowId()函数用于确定最后插入的行的主键的值。

interrupt() is useful when multithreading, and allows one thread to interrupt an operation in progress on another thread.

多线程时interrupt() 是很有用,它允许一个线程中断另一个线程中正在进行的操作。

setBusyTimeout() can also be useful when multithreading, and allows the programmer to dictate how long SQLite waits before returning SQLITE_BUSY if another thread has a lock on the database. The default value is 60 seconds, set when the database is opened.

setBusyTimeout() 在多线程时也很有用,它允许程序员决定当另一个线程锁住了数据库时,SQLite等待多久才返回SQLITE_BUSY。默认值为60秒,在打开数据库时设置。

The copy constructor and operator=() are made private, as it does not make sense to copy a CppSQLiteDBobject.

复制构造函数和operator=()被设定为private,因为复制一个CppSQLiteDB对象是没意义的。

Finally, the static method SQLiteVersion() returns the version number of the underlying SQLite DLL.

最后,静态方法 SQLiteVersion() 返回底层 SQLite DLL的版本号。

CppSQLiteQuery

Encapsulates a SQLite query result set.

封装一个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() and eof() allow iteration of the query results.

nextRow()和eof()允许迭代查询的结果集。

numFields()fieldValue()fieldName()fieldType() and fieldIsNull() allow the programmer to determine the number of fields, their names, values, types and whether they contain a SQL NULL. There are overloaded versions allowing the required field to be either specified by index or name.

numFields()fieldValue()fieldName()fieldType() 和 fieldIsNull()允许程序员确定字段的数量、他们的名字、值、类型和是否包含SQL NULL。有重载版本,允许通过索引或名字指定所需的字段

getIntField(), getFloatField() and getStringField() provide a slightly easier to program way of getting field values, by never returning a NULL pointer for SQL NULL, and there is a default 2nd parameter that allows the programmer to specify which value to return instead.

getIntField(), getFloatField() and getStringField()提供一个简单的方法获取的字段的值,从不对SQL NULL返回一个空指针,他们有一个默认的第二参数,允许程序员指定当SQL里面为NULL时返回的值。

It is not possible to iterate backwards through the results. The reason for this is that CppSQLite is a thin wrapper and does not cache any returned row data. If this is required, CppSQLiteDB::getTable() should be used, or the application could inherit from this class.

不可能往回遍历结果。原因是,CppSQLite 是一个简单封装,不缓存任何返回的行的数据。如果你一定要这么做, 请使用CppSQLiteDB::getTable() ,或者你的应用程序可以从这个类继承。

finalize() frees the memory associated with the query, but the destructor automatically calls this.

finalize() 释放查询相关的内存,但是析构函数里面自动调用了。

CppSQLiteTable

SQLite provides a method to obtain a complete table's contents in a single block of memory, CppSQLiteTableencapsulates this functionality.

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() provides a random access method for movement between rows, and can be used in conjunction withnumRows() to iterate the table. This design decision was made for simplicity, as following the same model as forCppSQLiteQuery, would have required functions for bof()eof()first()last()next() and prev().

setRow()  提供了一种在行之间随机访问的方法, 可以结合 numRows() 迭代 表。这样设计是为了当你需要bof()eof()first()last()next() and prev() 这些函数时简化,CppSQLiteQuery 有同样的功能。

numFields()fieldValue()fieldName()fieldIsNull()getIntField()getFloatField(),getStringField()close(), and operator=() provide the same functionality as for CppSQLiteQuery.

numFields()fieldValue()fieldName()fieldIsNull()getIntField()getFloatField(),getStringField()close(),和 赋值=()跟 CppSQLiteQuery提供一样的功能。

CppSQLiteBuffer

Encapsulates SQLite "sprintf" functionality.

封装SQLite“sprintf”功能。

SQLite provides a function sqlite_mprintf() which is like the C runtime sprintf() except there is no possibility of overrunning the buffer supplied, as sqlite_mprintf() uses malloc to allocate enough memory. The other benefit over sprintf() is the %Q tag, which works like %s except that it will massage apostrophes so that they don't mess up the SQL string being built, and also translate NULL pointers into SQL NULL values.

SQLite提供了一个类似 C 的 sprintf()的函数  sqlite_mprintf(),他没有缓冲区溢出的可能,因为 如sqlite_mprintf()会使用malloc分配足够的内存。sprintf() 另一好处是 标记  %Q标记,它跟 %s 一样,但是忽略了符号,所在创建SQL字符串时不会乱七八糟。并且它将空指针转化为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*() allows the programmer to pass an instance of this object to the functions defined on CppSQLiteDB.

操作  const char*() 允许程序员将这个对象的一个实例传递给 定义在CppSQLiteDB。

CppSQLiteBinary

Because SQLite stores all data as NULL terminated strings, it is not possible to store binary data if it has embedded NULLs. SQLite provides 2 functions sqlite_encode_binary() and sqlite_decode_binary()that can be used to allow storage and retrieval of binary data. CppSQLiteBinary encapsulates these 2 functions.

由于SQLite将所有数据存储为以NULL结尾的字符串,所以不可能来存储带有 NULL 的二进制数据。SQLite提供了两个函数 sqlite_encode_binary()和sqlite_decode_binary(),可用于允许二进制数据的存储和检索。CppSQLiteBinary封装这两个函数。

These two functions are not currently provided as part of the pre-compiled DLL, so I have copied the entire contents of SQLite's encode.c file into the CppSQLite.cpp file. Should these functions be provided in the DLL at some future point, they can easily be removed from CppSQLite.cpp.

目前不这两个函数没有作为预编译DLL的一部分提供出来,所以我从 SQLite 的 encode.c 文件 复制了所有的代码到 CppSQLite.cpp 文件。DLL中提供在未来的某个时候,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 can accept data in either encoded or binary form using the setEncoded() andsetBinary() functions. Whichever is used, enough memory is always allocated to store the encoded version, which is usually longer as nulls and single quotes have to be escaped.

CppSQLiteBinary可以接受使用setEncoded()和setBinary()函数转换来的编码数据或者二进制数据。无论使用哪个,通常都会将nulls 和单引号进行转移之后,分配足够的内存总是存储编码版本,通常长null和单引号必须转义。

Data is retrieved using the getEncoded() and getBinary() functions. Depending on which form the data is currently in within the class, it may need to be converted.

使用getEncoded()和getBinary()函数检索数据。可能需要根据数据进入表单中的类进行转换。

getBinaryLength() returns the length of the binary data stored, again converting the held format from encoded to binary, if required.

getBinaryLength()返回存储的二进制数据的长度,如果需要的话再从编码到二进制进行格式转换。

allocBuffer() can be used to prevent data having to be cycled via a temporary buffer like in the example code at the start of this article. This function could be used as in the following example where data is read straight from a file into a CppSQLiteBinary object.

allocBuffer()可以用来防止数据想文章开头的代码那样,通过临时缓冲区不停的循环。在下面的示例中,这个函数可以用作将数据直接从文件中读入一个CppSQLiteBinary对象。

int f = open(gszJpgFile, O_RDONLY|O_BINARY);int nFileLen = filelength(f);read(f, blob.allocBuffer(nFileLen), nFileLen);

CppSQLiteStatement

SQLite provides some experimental functionality for working with pre-compiled SQL. When the same SQL is being executed over and over again with different values, a significant performance improvement can be had by only compiling the SQL once, and executing it multiple times, each time with different values.CppSQLiteStatement encapsulates this functionality.

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;};

CppSQLiteStatement object is obtained by calling CppSQLiteDB::compileStatement() with a SQL statement containing placeholders, as follows:

通过包含占位符的  SQL 语句调用CppSQLiteDB::compileStatement()获得一个 CppSQLiteStatement 对象,如下:

CppSQLiteStatement stmt = db.compileStatement("insert into emp values (?, ?);");stmt.bind(1, 1);stmt.bind(2, "Emp Name");stmt.execDML();stmt.reset();

The CppSQLiteStatement::bind() methods are then used to set the values of the placeholders, before calling either execDML() or execQuery() as appropriate.

然后,在调用 execDML() 或 execQuery() 之前,使用CppSQLiteStatement::bind() 方法设置占位符的值。

After the programmer has finished with the result from either execDML() or execQuery(), the reset()method can be called to put the statement back to a compiled state. The CppSQLiteStatement::bind()methods can then be used again, followed by execDML() or execQuery(). A typical use would be in a loop as demonstrated in the CppSQLiteDemo program.

程序员使用 execDML() execQuery() 完成值的设定后,可以通过调用 reset() 方法将语句调用编译状态。然后CppSQLiteStatement::bind()方法可以被再次使用,然后执行 execDML() execQuery()。CppSQLiteDemo 程序演示了一个在循环中使用的典型的方法。

Multithreading 多线程

SQLite is compiled as thread-safe on Windows by default, and CppSQLite makes use of some SQLite features to help with multithreaded use. Included in the source code accompanying this article is a 2nd demo program calledCppSQLiteDemoMT, which demonstrates these features.

SQLite 在 Windows 下默认是编译为线程安全的,CppSQLite 利用一些 SQLite 的特性来帮助使用多线程。包括在本文附带的第二个演示程序CppSQLiteDemoMT 的源代码中展示了这些特性。

Each thread wishing to utilize CppSQLite on the same database file at the same time must have its ownCppSQLiteDB object, and call open(). To put this another way, it is an error for more than 1 thread to call into aCppSQLiteDB object at the same time. The one exception to this is CppSQLiteDB::interrupt(), which can be used from one thread to interrupt the work of another thread.

在同一时刻,每个使用 CppSQLite 访问同一数据库文件的线程,必须有它自己的CppSQLiteDB对象,并调用open()。换一句话来说,多个线程同时调用一个CppSQLiteDB  对象是错误的。 CppSQLiteDB::interrupt()一个例外,它可在一个线程中打断另一个线程的工作。

The other change to CppSQLite for multithreaded use is to make use of the sqlite_busy_timeout() function which causes SQLite to wait up to the specified number of milliseconds before returning SQLITE_BUSY. By default, CppSQLite sets this to 60,000 (60 seconds), but this can be changed usingCppSQLiteDB::setBusyTimeout() as required. Various examples of doing this are shown in theCppSQLiteDemoMT program.

CppSQLite 正对多线程使用另一个改变是利用了 sqlite_busy_timeout() 函数,这个函数造成 SQLite 等待指定的毫秒数后才返回SQLITE_BUSY。默认情况下,CppSQLite这个设置为60000(60秒),但可以使用 CppSQLiteDB::setBusyTimeout() 改成你想要的值。CppSQLiteDemoMT 工程中随处可见这样的例子。

SQLite Functionality Not Currently Wrapped 未封装的SQLite功能

SQLite provides a mechanism that allows the application developer to define stored procedures and aggregate functions that can be called from SQL statements. These stored procedures are written in C by the application developer, and made known to SQLite via function pointers. This is how the SQL built in functions are implemented by SQLite, but this functionality is not currently catered for in CppSQLite.

SQLite提供了一种机制,允许应用程序开发人员定义可以从SQL语句调用的存储的程序和聚合函数。这些存储的程序是应用程序开发人员用C编写的,能让 SQLite 通过函数指针识别的。这是SQL内建函数是如何实现的SQLite,但目前 CppSQLite 没有照顾到这个功能。

SQLite provides some other variations on the functions wrapped, and the reader is encouraged to study the SQLite documentation.

SQLite 提供了一些其他变异函数封装,鼓励读者通过 SQLite 文档学习之。

Managed C++

It is possible to compile SQLite and CppSQLite into a managed C++ program, It Just Works (IJW). You will need to set the CppSQLite.cpp file so that it does not use pre-compiled headers and also not to use Managed extensions, i.e. don't use /clr.

可以将 SQLite 和 CppSQLite 编译到一个 托管c++程序中。它能工作。您将需要设置 CppSQLite.cpp 文件,使它不使用预编译头文件,也不要使用托管扩展,即不使用/ clr。

There is a Managed C++ demo included with the CppSQLite downloads.

CppSQLite下载里包含了一个托管c++演示

SQLite Version 3 版本SQLite3

At the time of writing, SQLite version 3 is in beta. See http://www.sqlite.org/ for further details. I have produced a port of CppSQLite to SQLite version 3, and the following notes explain the differences.

在撰写本文时,SQLite beta版本3正在酝酿中。详情见 http://www.sqlite.org/。我产生了一个CppSQLite SQLite版本3 的接口,下面的注释解释差异。

There are a new set of classes with the prefix CppSQLite3, for example CppSQLite3Exception. This allows programs to link with both versions of CppSQLite, as is possible with both versions of SQLite itself.

有一个新的前缀设置CppSQLite3,例如CppSQLite3Exception。这允许程序连接各个版本的 CPPSQLite,跟的SQLite本身使用两个版本一样

There is not support for UTF-16 initially, as it is not something I have experience of, and wouldn't know how to test. This can be added later with another set of classes, called for example CppSQLite3Exception16 etc. Note that some sqlite3 stuff such as sqlite3_exec() and sqlite3_get_table() do not appear to have UTF-16 versions, also sqlite3_vmprintf(), used by CppSQLiteBuffer.

最初没有支持utf - 16,因为我没有使用它的经历,也不知道如何测试。以后可以添加另一个类的集合,例如CppSQLite3Exception16等。请注意,一些 sqlite3 的东西比如 sqlite3_exec() 和sqlite3_get_table() 似乎没有 utf - 16版本,CppSQLiteBuffer 中使用 的sqlite3_vmprintf()也是。

Error messages are now returned by sqlite3_errmsg() and do not need to be freed. To keep consistency between CppSQLite and CppSQLite3 the code that throws exceptions with messages returned from SQLite version 3 has been changed so that it passes DONT_DELETE_MSG as the final parameter toCppSQLite3Exception. The exception to this is the messages returned by sqlite3_exec() andsqlite3_get_table().

现在由  sqlite3_errmsg()返回错误消息,不需要释放。为了保持 CppSQLite3  在 SQLite3 返回错误信息抛出异常时与 CppSQLite的一致性,CppSQLite3Exception 变为 带了一个 DONT_DELETE_MSG 参数在其参数列表的最后面。该异常是 sqlite3_exec() 和sqlite3_get_table() 返回的。

SQLite version 3 now has direct support for BLOB data, and therefore no need to encode or decode it, and there would seem to be no job for CppSQLiteBinary. However, the SQLite version 3 change means that the only way to work with BLOB data would seem to be using prepared statements (CppSQLiteStatement). Not really a problem, but up until now, CppSQLiteBinary had allowed use of (encoded) binary data in calls toCppSQLiteDB::execQuery()CppSQLiteDB::execDML() and on data returned fromCppSQLiteDB::getTable().

SQLite版本3现在直接支持BLOB数据,因此不需要编码或解码,以及 CppSQLiteBinary 似乎是没有用的。然而,SQLite版本3的变化意味着看起来处理BLOB数据的唯一方法似乎是使用预处理语句( CppSQLiteStatement )。不是一个问题,但直到现在,CppSQLiteBinary允许在CppSQLiteDB::execQuery(),CppSQLiteDB:execDML()的调用里使用(编码)二进制数据,以及 CppSQLiteDB::getTable()返回的数据

sqlite_encode_binary() and sqlite_decode_binary() are still included in the SQLite version 3 source distribution, although it is not clear whether this is an error as they do not have the sqlite3 prefix, nor are they exported from the DLL. CppSQLite3 replicates the source to these 2 functions. This used to be the case withCppSQlite up to version 1.3 as up until version 2.8.15 of SQLite, they were not exported from the DLL.CppSQLite3Binary is an exact copy of CppSQLiteBinary, bundled with the source tosqlite_encode_binary() and sqlite_decode_binary(). This will allow easy porting between CppSQLiteand CppSQLite3. Programs wishing to use sqlite3 BLOBs and their reduced storage space will not need to useCppSQLite3Binary, and will need to be rewritten anyway.

SQLite version 3 introduces changes to the data typing system used. See http://www.sqlite.org/datatype3.html . For this reason, CppSQLiteQuery::FieldType() has been replaced with 2 functions:CppSQLiteQuery::FieldDeclType() which returns the declared data type for the column as a string, and andCppSQLiteQuery::FieldDataType() whhich returns the actual type of the data stored in that column for the current row as one of the SQLite version 3 #defined vallues.

SQLite版本3介绍改变所使用的数据输入系统。见http://www.sqlite.org/datatype3.html。出于这个原因,CppSQLiteQuery:FieldType()被另外两个函数取代了:CppSQLiteQuery::FieldDeclType(),返回声明的数据类型的列作为一个字符串、CppSQLiteQuery::FieldDataType()返回当前列的实际存储数据的在SQLite版本3 里定义的类型。

The demo programs have been changed slightly to demonstrate the new features, and also to account for SQLite version 3's different locking behaviour. See http://www.sqlite.org/lockingv3.html. Note that SQLite version 3.0.5 introduced a compile time option which changes locking behaviour, see http://www.sqlite.org/changes.html for more details.

演示程序稍有改变展示的新特性,并解释SQLite3 版本不同的锁定行为。见http://www.sqlite.org/lockingv3.html。注意:SQLite 3.0.5版本引入了一个编译时锁定行为的选项,见 http://www.sqlite.org/changes.html 了解更多细节。

The SQLite version 3 is available as a separate download at the top of this article.

SQLite3 可以本文的顶部单独下载(下载链接请见原文)

Future Work 未来的工作(略)

I may add support for the remaining SQLite features to CppSQLite. At the moment, this means stored procedures and aggregate functions.

Cross Platform Capability 跨平台型(略)

Since version 1.2 of CppSQLite, I have tried hard not to do anything which is Microsoft specific, and have successfully compiled and run the demo programs on mingw32, as well as with Visual C++.

As mingw32 is based on GCC, there should be no major problems on Linux/Unix, although the multi threaded demo program CppSQLiteDemoMT uses the _beginthread() call, which will obviously not work. This can probably be easily fixed, using pthreads for example.

Contributions (鸣谢 略)

Thanks to fellow Code Project members for suggestions and buf fixes for CppSQLite, and also to Mateusz Loskot for acting as a reviewer.

Conclusion (总结 略)

CppSQLite makes SQLite easier to use within a C++ program, yet doesn't provide significantly less power or efficiency than the flat C interface.

If nothing else, writing CppSQLite has provided the author with an insight into the power and simplicity of SQLite. It is hoped that readers of this article also benefit in some way.

History for CppSQLite (Targets SQLite 2.8.n) (历史版本 略)

  • 1.0 - 3rd Mar 2004 - Initial version.
  • 1.1 - 10th Mar 2004
    • Renamed CppSQLiteException::errorMess() to CppSQLiteException::errorMessage().
    • 2nd constructor to CppSQLiteException().
    • Now decodes error codes to strings in CppSQLiteException.
    • Call sqlite_finalize() immediately to get error details after problems with sqlite_step().
    • Added CppSQLiteBinary class.
  • 1.2 - 2nd Apr 2004 - Not released.
    • Updated article.
    • Removed use of Microsoft specific extensions (I hope)
    • Check for NULL pointers
    • Updated for SQLite 2.8.13
    • Utilized sqlite_busy_timeout() and sqlite_interrupt() to help with multithreaded use
    • 2nd demonstration program for multithreaded use
    • Added support from pre-compiled SQL statements
    • Added ability to determine column types from CppSQLiteQuery
    • Added CppSQLiteDB::execScalar()
  • 1.2.1 - 15th Apr 2004
    • Updated article following review
    • Use of C++ rather than C standard headers following review
  • 1.3 - 21st May 2004
    • Added "BSD Style" License notice to source files
    • Fixed bugs on bind()
    • Added getIntField()getStringField()getFloatField()
    • Added overloaded functions to access fields by name
    • CppSQLiteDB::ExecDML() implemented with sqlite_exec() so multiple statements can be executed at once.
    • Added note in article about potential problem with return value from CppSQLiteDB::execDML()
    • Added managed C++ example program
  • 1.4 - 30th August 2004
    • Upgraded to SQLite 2.8.15
    • Removed source for sqlite_encode_binary() and sqlite_decode_binary() as there are now exported from the SQLite DLL
    • Added article section on Managed C++

History for CppSQLite3 (Targets SQLite 3.n.n) (历史版本 略)

  • 3.0 - 30th August 2004
    • Initial version to work with SQLite version 3.0.6
  • 3.1 - 26th October 2004
    • Upgraded to vSQLite 3.0.8
    • Added CppSQLiteDB3::tableExists() function
    • Implemented getXXXXField using SQLite3 functions instead of atoi()atof(), etc.
  • 3.2 - 24th June, 2011
    • Bundled with SQLite3 version 3.4.0
    • CppSQLite3DB::SQLiteHeaderVersion()CppSQLite3DB::SQLiteLibraryVersion(),CppSQLite3DB::SQLiteLibraryVersionNumber()
    • Fixed execScalar to handle a NULL result
    • Added Int64 functions to CppSQLite3Statement
    • Added CppSQLite3DB::IsAutoCommitOn(), can be used to test if a transaction is active
    • Throw exception from CppSQLite3DB::close() on error
    • Trap above exception in CppSQLite3DB::~CppSQLite3DB()
    • Bigger buffer size 256 in table
    • sqlite3_prepare replaced with sqlite3_prepare_v2
    • Fix to CppSQLite3DB::compile() as provided by Dave Rollins
    • Binds parameters by name as suggested by Dave Rollins



0 0
原创粉丝点击