国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

CppSQLite Demo 詳解(翻譯)--已完成

2019-11-08 03:15:44
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

英文原文來(lái)自:https://www.codePRoject.com/articles/6343/cppsqlite-c-wrapper-for-sqlite

CppSqlite 是一個(gè)針對(duì) SQLite 的 c++ 的封裝版本

可以使用sqlite  的 dll 動(dòng)態(tài)或者靜態(tài)編譯,也可以直接在你的工程內(nèi) 添加四個(gè)文件:sqlite3.c  sqlite3.h  CppSQLite3.h 和 CppSQLite3.cpp

官網(wǎng)  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.

下面幾個(gè)簡(jiǎn)單的類定義的 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 兩個(gè)文件內(nèi),需要添加進(jìn)入你的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.

封裝一個(gè)SQLite的錯(cuò)誤代碼和消息。沒(méi)有什么復(fù)雜的東西,這類很容易被納入現(xiàn)有的異常層次結(jié)構(gòu),如果需要的話。

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返回的錯(cuò)誤消息需要有程序員使用 sqlite_freemem()' 釋放,CppSQLite的異常類承擔(dān)了這個(gè)責(zé)任。注意,CppSQLite生成的錯(cuò)誤消息,我們不想釋放內(nèi)存,所以這里有一個(gè)可選的參數(shù),決定CppSQLiteException是否釋放內(nèi)存。

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.

封裝的一個(gè)SQLite數(shù)據(jù)庫(kù)文件。

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確實(shí)提供了參數(shù) mode 給 sqlite_open(),但被證實(shí)是沒(méi)有效果的,所以CppSQLite不提供那個(gè)參數(shù)。

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()是用于執(zhí)行數(shù)據(jù)操作語(yǔ)言(DML)命令,如創(chuàng)建/刪除/插入/更新/刪除語(yǔ)句。它返回受影響的行數(shù)。可以一次性提交多個(gè)由分號(hào)分隔的SQL語(yǔ)句。

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返回受影響的行數(shù)有一個(gè)潛在的問(wèn)題。如果有任何其他un-finalized()操作,返回的受影響的行數(shù)會(huì)累積并包括先前的語(yǔ)句的結(jié)果。所以如果這個(gè)功能對(duì)你很重要,你必須確保在你執(zhí)行execDML()前沒(méi)有任何CppSQLiteQuery CppSQLiteStatement對(duì)象沒(méi)執(zhí)行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()用于執(zhí)行查詢。通過(guò)傳值返回 CppSQLiteQuery對(duì)象,因此使程序員不必刪除它。

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。這是一個(gè)當(dāng)你需要運(yùn)行簡(jiǎn)單的聚合函數(shù)的快捷方式,例如,“select count(*) from emp”或“select max(empno) from emp”。它返回查詢結(jié)果的第一行的第一個(gè)字段的值。其他列和行被忽略。

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特性可以通過(guò)單個(gè)操作獲取整個(gè)表,而不必一次查詢獲取一行。實(shí)際上,也可以通過(guò) where 語(yǔ)句查詢的一個(gè)子集,整個(gè)結(jié)果集一次性返回。再次說(shuō)明,為方便起見(jiàn) CppSQLiteTable對(duì)象通過(guò)傳值返回。

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

compileStatement() 允許實(shí)驗(yàn)SQLite預(yù)編譯特性。請(qǐng)參閱下面的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是無(wú)類型,這意味著所有字段存儲(chǔ)為字符串。唯一的例外是 INTEGER PRIMARY KEY 類型,它允許字段值自增,就像SQL Server的標(biāo)識(shí)列。lastRowId()函數(shù)用于確定最后插入的行的主鍵的值。

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

多線程時(shí)interrupt() 是很有用,它允許一個(gè)線程中斷另一個(gè)線程中正在進(jìn)行的操作。

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() 在多線程時(shí)也很有用,它允許程序員決定當(dāng)另一個(gè)線程鎖住了數(shù)據(jù)庫(kù)時(shí),SQLite等待多久才返回SQLITE_BUSY。默認(rèn)值為60秒,在打開(kāi)數(shù)據(jù)庫(kù)時(shí)設(shè)置。

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

復(fù)制構(gòu)造函數(shù)和operator=()被設(shè)定為private,因?yàn)閺?fù)制一個(gè)CppSQLiteDB對(duì)象是沒(méi)意義的。

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

最后,靜態(tài)方法 SQLiteVersion() 返回底層 SQLite DLL的版本號(hào)。

CppSQLiteQuery

Encapsulates a SQLite query result set.

封裝一個(gè)SQLite的查詢結(jié)果集。

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()允許迭代查詢的結(jié)果集。

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()允許程序員確定字段的數(shù)量、他們的名字、值、類型和是否包含SQL NULL。有重載版本,允許通過(guò)索引或名字指定所需的字段。

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()提供一個(gè)簡(jiǎn)單的方法獲取的字段的值,從不對(duì)SQL NULL返回一個(gè)空指針,他們有一個(gè)默認(rèn)的第二參數(shù),允許程序員指定當(dāng)SQL里面為NULL時(shí)返回的值。

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.

不可能往回遍歷結(jié)果。原因是,CppSQLite 是一個(gè)簡(jiǎn)單封裝,不緩存任何返回的行的數(shù)據(jù)。如果你一定要這么做, 請(qǐng)使用CppSQLiteDB::getTable() ,或者你的應(yīng)用程序可以從這個(gè)類繼承。

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

finalize() 釋放查詢相關(guān)的內(nèi)存,但是析構(gòu)函數(shù)里面自動(dòng)調(diào)用了。

CppSQLiteTable

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

SQLite提供一種方法來(lái)獲得一整張表的內(nèi)容到一塊內(nèi)存,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()  提供了一種在行之間隨機(jī)訪問(wèn)的方法, 可以結(jié)合 numRows() 迭代 表。這樣設(shè)計(jì)是為了當(dāng)你需要bof()eof()first()last()next() and prev() 這些函數(shù)時(shí)簡(jiǎn)化,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提供了一個(gè)類似 C 的 sprintf()的函數(shù)  sqlite_mprintf(),他沒(méi)有緩沖區(qū)溢出的可能,因?yàn)?如sqlite_mprintf()會(huì)使用malloc分配足夠的內(nèi)存。sprintf() 另一好處是 標(biāo)記  %Q標(biāo)記,它跟 %s 一樣,但是忽略了符號(hào),所在創(chuàng)建SQL字符串時(shí)不會(huì)亂七八糟。并且它將空指針轉(zhuǎn)化為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*() 允許程序員將這個(gè)對(duì)象的一個(gè)實(shí)例傳遞給 定義在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將所有數(shù)據(jù)存儲(chǔ)為以NULL結(jié)尾的字符串,所以不可能來(lái)存儲(chǔ)帶有 NULL 的二進(jìn)制數(shù)據(jù)。SQLite提供了兩個(gè)函數(shù) sqlite_encode_binary()和sqlite_decode_binary(),可用于允許二進(jìn)制數(shù)據(jù)的存儲(chǔ)和檢索。CppSQLiteBinary封裝這兩個(gè)函數(shù)。

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.

目前不這兩個(gè)函數(shù)沒(méi)有作為預(yù)編譯DLL的一部分提供出來(lái),所以我從 SQLite 的 encode.c 文件 復(fù)制了所有的代碼到 CppSQLite.cpp 文件。DLL中提供在未來(lái)的某個(gè)時(shí)候,DLL 應(yīng)該會(huì)提供這些函數(shù),他們可以很容易地從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()函數(shù)轉(zhuǎn)換來(lái)的編碼數(shù)據(jù)或者二進(jìn)制數(shù)據(jù)。無(wú)論使用哪個(gè),通常都會(huì)將nulls 和單引號(hào)進(jìn)行轉(zhuǎn)移之后,分配足夠的內(nèi)存總是存儲(chǔ)編碼版本,通常長(zhǎng)null和單引號(hào)必須轉(zhuǎn)義。

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()函數(shù)檢索數(shù)據(jù)。可能需要根據(jù)數(shù)據(jù)進(jìn)入表單中的類進(jìn)行轉(zhuǎn)換。

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

getBinaryLength()返回存儲(chǔ)的二進(jìn)制數(shù)據(jù)的長(zhǎng)度,如果需要的話再?gòu)木幋a到二進(jìn)制進(jìn)行格式轉(zhuǎn)換。

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()可以用來(lái)防止數(shù)據(jù)想文章開(kāi)頭的代碼那樣,通過(guò)臨時(shí)緩沖區(qū)不停的循環(huán)。在下面的示例中,這個(gè)函數(shù)可以用作將數(shù)據(jù)直接從文件中讀入一個(gè)CppSQLiteBinary對(duì)象。

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的預(yù)編譯的實(shí)驗(yàn)性的功能。當(dāng)相同的SQL被一遍又一遍地執(zhí)行而只不過(guò)是有不同的值,預(yù)編譯功能可以通過(guò)一次執(zhí)行,顯著的改進(jìn)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:

通過(guò)包含占位符的  SQL 語(yǔ)句調(diào)用CppSQLiteDB::compileStatement()獲得一個(gè) CppSQLiteStatement 對(duì)象,如下:

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.

然后,在調(diào)用 execDML() 或 execQuery() 之前,使用CppSQLiteStatement::bind() 方法設(shè)置占位符的值。

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() 完成值的設(shè)定后,可以通過(guò)調(diào)用 reset() 方法將語(yǔ)句調(diào)用編譯狀態(tài)。然后CppSQLiteStatement::bind()方法可以被再次使用,然后執(zhí)行 execDML() 或 execQuery()。CppSQLiteDemo 程序演示了一個(gè)在循環(huán)中使用的典型的方法。

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 下默認(rèn)是編譯為線程安全的,CppSQLite 利用一些 SQLite 的特性來(lái)幫助使用多線程。包括在本文附帶的第二個(gè)演示程序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.

在同一時(shí)刻,每個(gè)使用 CppSQLite 訪問(wèn)同一數(shù)據(jù)庫(kù)文件的線程,必須有它自己的CppSQLiteDB對(duì)象,并調(diào)用open()。換一句話來(lái)說(shuō),多個(gè)線程同時(shí)調(diào)用一個(gè)CppSQLiteDB  對(duì)象是錯(cuò)誤的。 CppSQLiteDB::interrupt()是一個(gè)例外,它可在一個(gè)線程中打斷另一個(gè)線程的工作。

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 正對(duì)多線程使用另一個(gè)改變是利用了 sqlite_busy_timeout() 函數(shù),這個(gè)函數(shù)造成 SQLite 等待指定的毫秒數(shù)后才返回SQLITE_BUSY。默認(rèn)情況下,CppSQLite這個(gè)設(shè)置為60000(60秒),但可以使用 CppSQLiteDB::setBusyTimeout() 改成你想要的值。CppSQLiteDemoMT 工程中隨處可見(jiàn)這樣的例子。

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提供了一種機(jī)制,允許應(yīng)用程序開(kāi)發(fā)人員定義可以從SQL語(yǔ)句調(diào)用的存儲(chǔ)的程序和聚合函數(shù)。這些存儲(chǔ)的程序是應(yīng)用程序開(kāi)發(fā)人員用C編寫(xiě)的,能讓 SQLite 通過(guò)函數(shù)指針識(shí)別的。這是SQL內(nèi)建函數(shù)是如何實(shí)現(xiàn)的SQLite,但目前 CppSQLite 沒(méi)有照顧到這個(gè)功能。

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

SQLite 提供了一些其他變異函數(shù)封裝,鼓勵(lì)讀者通過(guò) SQLite 文檔學(xué)習(xí)之。

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 編譯到一個(gè) 托管c++程序中。它能工作。您將需要設(shè)置 CppSQLite.cpp 文件,使它不使用預(yù)編譯頭文件,也不要使用托管擴(kuò)展,即不使用/ clr。

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

CppSQLite下載里包含了一個(gè)托管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.

在撰寫(xiě)本文時(shí),SQLite beta版本3正在醞釀中。詳情見(jiàn) http://www.sqlite.org/。我產(chǎn)生了一個(gè)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.

有一個(gè)新的前綴設(shè)置CppSQLite3,例如CppSQLite3Exception。這允許程序連接各個(gè)版本的 CPPSQLite,跟的SQLite本身使用兩個(gè)版本一樣。

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.

最初沒(méi)有支持utf - 16,因?yàn)槲覜](méi)有使用它的經(jīng)歷,也不知道如何測(cè)試。以后可以添加另一個(gè)類的集合,例如CppSQLite3Exception16等。請(qǐng)注意,一些 sqlite3 的東西比如 sqlite3_exec() 和sqlite3_get_table() 似乎沒(méi)有 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().

現(xiàn)在由  sqlite3_errmsg()返回錯(cuò)誤消息,不需要釋放。為了保持 CppSQLite3  在 SQLite3 返回錯(cuò)誤信息拋出異常時(shí)與 CppSQLite的一致性,CppSQLite3Exception 變?yōu)?帶了一個(gè) DONT_DELETE_MSG 參數(shù)在其參數(shù)列表的最后面。該異常是 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現(xiàn)在直接支持BLOB數(shù)據(jù),因此不需要編碼或解碼,以及 CppSQLiteBinary 似乎是沒(méi)有用的。然而,SQLite版本3的變化意味著看起來(lái)處理BLOB數(shù)據(jù)的唯一方法似乎是使用預(yù)處理語(yǔ)句( CppSQLiteStatement )。不是一個(gè)問(wèn)題,但直到現(xiàn)在,CppSQLiteBinary允許在CppSQLiteDB::execQuery(),CppSQLiteDB:execDML()的調(diào)用里使用(編碼)二進(jìn)制數(shù)據(jù),以及 從CppSQLiteDB::getTable()返回的數(shù)據(jù)。

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介紹改變所使用的數(shù)據(jù)輸入系統(tǒng)。見(jiàn)http://www.sqlite.org/datatype3.html。出于這個(gè)原因,CppSQLiteQuery:FieldType()被另外兩個(gè)函數(shù)取代了:CppSQLiteQuery::FieldDeclType(),返回聲明的數(shù)據(jù)類型的列作為一個(gè)字符串、CppSQLiteQuery::FieldDataType()返回當(dāng)前列的實(shí)際存儲(chǔ)數(shù)據(jù)的在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 版本不同的鎖定行為。見(jiàn)http://www.sqlite.org/lockingv3.html。注意:SQLite 3.0.5版本引入了一個(gè)編譯時(shí)鎖定行為的選項(xiàng),見(jiàn) http://www.sqlite.org/changes.html 了解更多細(xì)節(jié)。

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

SQLite3 可以本文的頂部單獨(dú)下載(下載鏈接請(qǐng)見(jiàn)原文)。

Future Work 未來(lái)的工作(略)

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

Cross Platform Capability 跨平臺(tái)型(略)

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 (總結(jié) 略)

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 2004Renamed 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 pointersUpdated for SQLite 2.8.13Utilized sqlite_busy_timeout() and sqlite_interrupt() to help with multithreaded use2nd demonstration program for multithreaded useAdded support from pre-compiled SQL statementsAdded ability to determine column types from CppSQLiteQueryAdded CppSQLiteDB::execScalar()1.2.1 - 15th Apr 2004Updated article following reviewUse of C++ rather than C standard headers following review1.3 - 21st May 2004Added "BSD Style" License notice to source filesFixed bugs on bind()Added getIntField()getStringField()getFloatField()Added overloaded functions to access fields by nameCppSQLiteDB::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 program1.4 - 30th August 2004Upgraded to SQLite 2.8.15Removed source for sqlite_encode_binary() and sqlite_decode_binary() as there are now exported from the SQLite DLLAdded article section on Managed C++

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

3.0 - 30th August 2004Initial version to work with SQLite version 3.0.63.1 - 26th October 2004Upgraded to vSQLite 3.0.8Added CppSQLiteDB3::tableExists() functionImplemented getXXXXField using SQLite3 functions instead of atoi()atof(), etc.3.2 - 24th June, 2011Bundled with SQLite3 version 3.4.0CppSQLite3DB::SQLiteHeaderVersion()CppSQLite3DB::SQLiteLibraryVersion(),CppSQLite3DB::SQLiteLibraryVersionNumber()Fixed execScalar to handle a NULL resultAdded Int64 functions to CppSQLite3StatementAdded CppSQLite3DB::IsAutoCommitOn(), can be used to test if a transaction is activeThrow exception from CppSQLite3DB::close() on errorTrap above exception in CppSQLite3DB::~CppSQLite3DB()Bigger buffer size 256 in tablesqlite3_prepare replaced with sqlite3_prepare_v2Fix to CppSQLite3DB::compile() as provided by Dave RollinsBinds parameters by name as suggested by Dave Rollins


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 保定市| 遂川县| 嵊泗县| 兴山县| 尚义县| 邢台县| 华池县| 南漳县| 九龙县| 华宁县| 鹿邑县| 鹰潭市| 高阳县| 卓资县| 庄浪县| 麻栗坡县| 南雄市| 沈阳市| 雷山县| 三门峡市| 望奎县| 安仁县| 永康市| 五寨县| 平南县| 文登市| 沅江市| 洪湖市| 西华县| 监利县| 准格尔旗| 江陵县| 汪清县| 珠海市| 邮箱| 卓资县| 谷城县| 天镇县| 惠安县| 闵行区| 姜堰市|