时间:2021-07-01 10:21:17 帮助过:11人阅读
CppSQLite3.cpp
////////////////////////////////////////////////////////////////////////////////
// CppSQLite3 - A C++ wrapper around the SQLite3 embedded database library.
//
// Copyright (c) 2004..2007 Rob Groves. All Rights Reserved. rob.groves@btinternet.com
// 
// Permission to use, copy, modify, and distribute this software and its
// documentation for any purpose, without fee, and without a written
// agreement, is hereby granted, provided that the above copyright notice, 
// this paragraph and the following two paragraphs appear in all copies, 
// modifications, and distributions.
//
// IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,
// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
// PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
// EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
// ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". THE AUTHOR HAS NO OBLIGATION
// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
//
// V3.0     03/08/2004  -Initial Version for sqlite3
//
// V3.1     16/09/2004  -Implemented getXXXXField using sqlite3 functions
//                      -Added CppSQLiteDB3::tableExists()
//
// V3.2     01/07/2005  -Fixed execScalar to handle a NULL result
//          12/07/2007  -Added int64 functions to CppSQLite3Query
//                      -Throw exception from CppSQLite3DB::close() if error
//                      -Trap above exception in CppSQLite3DB::~CppSQLite3DB()
//                      -Fix to CppSQLite3DB::compile() as provided by Dave Rollins.
//                      -sqlite3_prepare replaced with sqlite3_prepare_v2
//                      -Added Name based parameter binding to CppSQLite3Statement.
////////////////////////////////////////////////////////////////////////////////
#include "CppSQLite3.h"
#include <cstdlib>
// Named constant for passing to CppSQLite3Exception when passing it a string
// that cannot be deleted.
static const bool DONT_DELETE_MSG=false;
////////////////////////////////////////////////////////////////////////////////
// Prototypes for SQLite functions not included in SQLite DLL, but copied below
// from SQLite encode.c
////////////////////////////////////////////////////////////////////////////////
int sqlite3_encode_binary(const unsigned char *in, int n, unsigned char *out);
int sqlite3_decode_binary(const unsigned char *in, unsigned char *out);
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
CppSQLite3Exception::CppSQLite3Exception(const int nErrCode,
                                    char* szErrMess,
                                    bool bDeleteMsg/*=true*/) :
                                    mnErrCode(nErrCode)
{
    mpszErrMess = sqlite3_mprintf("%s[%d]: %s",
                                errorCodeAsString(nErrCode),
                                nErrCode,
                                szErrMess ? szErrMess : "");
    if (bDeleteMsg && szErrMess)
    {
        sqlite3_free(szErrMess);
    }
}
CppSQLite3Exception::CppSQLite3Exception(const CppSQLite3Exception&  e) :
                                    mnErrCode(e.mnErrCode)
{
    mpszErrMess = 0;
    if (e.mpszErrMess)
    {
        mpszErrMess = sqlite3_mprintf("%s", e.mpszErrMess);
    }
}
const char* CppSQLite3Exception::errorCodeAsString(int nErrCode)
{
    switch (nErrCode)
    {
        case SQLITE_OK          : return "SQLITE_OK";
        case SQLITE_ERROR       : return "SQLITE_ERROR";
        case SQLITE_INTERNAL    : return "SQLITE_INTERNAL";
        case SQLITE_PERM        : return "SQLITE_PERM";
        case SQLITE_ABORT       : return "SQLITE_ABORT";
        case SQLITE_BUSY        : return "SQLITE_BUSY";
        case SQLITE_LOCKED      : return "SQLITE_LOCKED";
        case SQLITE_NOMEM       : return "SQLITE_NOMEM";
        case SQLITE_READONLY    : return "SQLITE_READONLY";
        case SQLITE_INTERRUPT   : return "SQLITE_INTERRUPT";
        case SQLITE_IOERR       : return "SQLITE_IOERR";
        case SQLITE_CORRUPT     : return "SQLITE_CORRUPT";
        case SQLITE_NOTFOUND    : return "SQLITE_NOTFOUND";
        case SQLITE_FULL        : return "SQLITE_FULL";
        case SQLITE_CANTOPEN    : return "SQLITE_CANTOPEN";
        case SQLITE_PROTOCOL    : return "SQLITE_PROTOCOL";
        case SQLITE_EMPTY       : return "SQLITE_EMPTY";
        case SQLITE_SCHEMA      : return "SQLITE_SCHEMA";
        case SQLITE_TOOBIG      : return "SQLITE_TOOBIG";
        case SQLITE_CONSTRAINT  : return "SQLITE_CONSTRAINT";
        case SQLITE_MISMATCH    : return "SQLITE_MISMATCH";
        case SQLITE_MISUSE      : return "SQLITE_MISUSE";
        case SQLITE_NOLFS       : return "SQLITE_NOLFS";
        case SQLITE_AUTH        : return "SQLITE_AUTH";
        case SQLITE_FORMAT      : return "SQLITE_FORMAT";
        case SQLITE_RANGE       : return "SQLITE_RANGE";
        case SQLITE_ROW         : return "SQLITE_ROW";
        case SQLITE_DONE        : return "SQLITE_DONE";
        case CPPSQLITE_ERROR    : return "CPPSQLITE_ERROR";
        default: return "UNKNOWN_ERROR";
    }
}
CppSQLite3Exception::~CppSQLite3Exception()
{
    if (mpszErrMess)
    {
        sqlite3_free(mpszErrMess);
        mpszErrMess = 0;
    }
}
////////////////////////////////////////////////////////////////////////////////
CppSQLite3Buffer::CppSQLite3Buffer()
{
    mpBuf = 0;
}
CppSQLite3Buffer::~CppSQLite3Buffer()
{
    clear();
}
void CppSQLite3Buffer::clear()
{
    if (mpBuf)
    {
        sqlite3_free(mpBuf);
        mpBuf = 0;
    }
}
const char* CppSQLite3Buffer::format(const char* szFormat, ...)
{
    clear();
    va_list va;
    va_start(va, szFormat);
    mpBuf = sqlite3_vmprintf(szFormat, va);
    va_end(va);
    return mpBuf;
}
////////////////////////////////////////////////////////////////////////////////
CppSQLite3Binary::CppSQLite3Binary() :
                        mpBuf(0),
                        mnBinaryLen(0),
                        mnBufferLen(0),
                        mnEncodedLen(0),
                        mbEncoded(false)
{
}
CppSQLite3Binary::~CppSQLite3Binary()
{
    clear();
}
void CppSQLite3Binary::setBinary(const unsigned char* pBuf, int nLen)
{
    mpBuf = allocBuffer(nLen);
    memcpy(mpBuf, pBuf, nLen);
}
void CppSQLite3Binary::setEncoded(const unsigned char* pBuf)
{
    clear();
    mnEncodedLen = strlen((const char*)pBuf);
    mnBufferLen = mnEncodedLen + 1; // Allow for NULL terminator
    mpBuf = (unsigned char*)malloc(mnBufferLen);
    if (!mpBuf)
    {
        throw CppSQLite3Exception(CPPSQLITE_ERROR,
                                "Cannot allocate memory",
                                DONT_DELETE_MSG);
    }
    memcpy(mpBuf, pBuf, mnBufferLen);
    mbEncoded = true;
}
const unsigned char* CppSQLite3Binary::getEncoded()
{
    if (!mbEncoded)
    {
        unsigned char* ptmp = (unsigned char*)malloc(mnBinaryLen);
        memcpy(ptmp, mpBuf, mnBinaryLen);
        mnEncodedLen = sqlite3_encode_binary(ptmp, mnBinaryLen, mpBuf);
        free(ptmp);
        mbEncoded = true;
    }
    return mpBuf;
}
const unsigned char* CppSQLite3Binary::getBinary()
{
    if (mbEncoded)
    {
        // in/out buffers can be the same
        mnBinaryLen = sqlite3_decode_binary(mpBuf, mpBuf);
        if (mnBinaryLen == -1)
        {
            throw CppSQLite3Exception(CPPSQLITE_ERROR,
                                    "Cannot decode binary",
                                    DONT_DELETE_MSG);
        }
        mbEncoded = false;
    }
    return mpBuf;
}
int CppSQLite3Binary::getBinaryLength()
{
    getBinary();
    return mnBinaryLen;
}
unsigned char* CppSQLite3Binary::allocBuffer(int nLen)
{
    clear();
    // Allow extra space for encoded binary as per comments in
    // SQLite encode.c See bottom of this file for implementation
    // of SQLite functions use 3 instead of 2 just to be sure ;-)
    mnBinaryLen = nLen;
    mnBufferLen = 3 + (257*nLen)/254;
    mpBuf = (unsigned char*)malloc(mnBufferLen);
    if (!mpBuf)
    {
        throw CppSQLite3Exception(CPPSQLITE_ERROR,
                                "Cannot allocate memory",
                                DONT_DELETE_MSG);
    }
    mbEncoded = false;
    return mpBuf;
}
void CppSQLite3Binary::clear()
{
    if (mpBuf)
    {
        mnBinaryLen = 0;
        mnBufferLen = 0;
        free(mpBuf);
        mpBuf = 0;
    }
}
////////////////////////////////////////////////////////////////////////////////
CppSQLite3Query::CppSQLite3Query()
{
    mpVM = 0;
    mbEof = true;
    mnCols = 0;
    mbOwnVM = false;
}
CppSQLite3Query::CppSQLite3Query(const CppSQLite3Query& rQuery)
{
    mpVM = rQuery.mpVM;
    // Only one object can own the VM
    const_cast<CppSQLite3Query&>(rQuery).mpVM = 0;
    mbEof = rQuery.mbEof;
    mnCols = rQuery.mnCols;
    mbOwnVM = rQuery.mbOwnVM;
}
CppSQLite3Query::CppSQLite3Query(sqlite3* pDB,
                            sqlite3_stmt* pVM,
                            bool bEof,
                            bool bOwnVM/*=true*/)
{
    mpDB = pDB;
    mpVM = pVM;
    mbEof = bEof;
    mnCols = sqlite3_column_count(mpVM);
    mbOwnVM = bOwnVM;
}
CppSQLite3Query::~CppSQLite3Query()
{
    try
    {
        finalize();
    }
    catch (...)
    {
    }
}
CppSQLite3Query& CppSQLite3Query::operator=(const CppSQLite3Query& rQuery)
{
    try
    {
        finalize();
    }
    catch (...)
    {
    }
    mpVM = rQuery.mpVM;
    // Only one object can own the VM
    const_cast<CppSQLite3Query&>(rQuery).mpVM = 0;
    mbEof = rQuery.mbEof;
    mnCols = rQuery.mnCols;
    mbOwnVM = rQuery.mbOwnVM;
    return *this;
}
int CppSQLite3Query::numFields()
{
    checkVM();
    return mnCols;
}
const char* CppSQLite3Query::fieldValue(int nField)
{
    checkVM();
    if (nField < 0 || nField > mnCols-1)
    {
        throw CppSQLite3Exception(CPPSQLITE_ERROR,
                                "Invalid field index requested",
                                DONT_DELETE_MSG);
    }
    return (const char*)sqlite3_column_text(mpVM, nField);
}
const char* CppSQLite3Query::fieldValue(const char* szField)
{
    int nField = fieldIndex(szField);
    return (const char*)sqlite3_column_text(mpVM, nField);
}
int CppSQLite3Query::getIntField(int nField, int nNullValue/*=0*/)
{
    if (fieldDataType(nField) == SQLITE_NULL)
    {
        return nNullValue;
    }
    else
    {
        return sqlite3_column_int(mpVM, nField);
    }
}
int CppSQLite3Query::getIntField(const char* szField, int nNullValue/*=0*/)
{
    int nField = fieldIndex(szField);
    return getIntField(nField, nNullValue);
}
sqlite_int64 CppSQLite3Query::getInt64Field(int nField, sqlite_int64 nNullValue/*=0*/)
{
    if (fieldDataType(nField) == SQLITE_NULL)
    {
        return nNullValue;
    }
    else
    {
        return sqlite3_column_int64(mpVM, nField);
    }
}
sqlite_int64 CppSQLite3Query::getInt64Field(const char* szField, sqlite_int64 nNullValue/*=0*/)
{
    int nField = fieldIndex(szField);
    return getInt64Field(nField, nNullValue);
}
double CppSQLite3Query::getFloatField(int nField, double fNullValue/*=0.0*/)
{
    if (fieldDataType(nField) == SQLITE_NULL)
    {
        return fNullValue;
    }
    else
    {
        return sqlite3_column_double(mpVM, nField);
    }
}
double CppSQLite3Query::getFloatField(const char* szField, double fNullValue/*=0.0*/)
{
    int nField = fieldIndex(szField);
    return getFloatField(nField, fNullValue);
}
const char* CppSQLite3Query::getStringField(int nField, const char* szNullValue/*=""*/)
{
    if (fieldDataType(nField) == SQLITE_NULL)
    {
        return szNullValue;
    }
    else
    {
        return (const char*)sqlite3_column_text(mpVM, nField);
    }
}
const char* CppSQLite3Query::getStringField(const char* szField, const char* szNullValue/*=""*/)
{
    int nField = fieldIndex(szField);
    return getStringField(nField, szNullValue);
}
const unsigned char* CppSQLite3Query::getBlobField(int nField, int& nLen)
{
    checkVM();
    if (nField < 0 || nField > mnCols-1)
    {
        throw CppSQLite3Exception(CPPSQLITE_ERROR,
                                "Invalid field index requested",
                                DONT_DELETE_MSG);
    }
    nLen = sqlite3_column_bytes(mpVM, nField);
    return (const unsigned char*)sqlite3_column_blob(mpVM, nField);
}
const unsigned char* CppSQLite3Query::getBlobField(const char* szField, int& nLen)
{
    int nField = fieldIndex(szField);
    return getBlobField(nField, nLen);
}
bool CppSQLite3Query::fieldIsNull(int nField)
{
    return (fieldDataType(nField) == SQLITE_NULL);
}
bool CppSQLite3Query::fieldIsNull(const char* szField)
{
    int nField = fieldIndex(szField);
    return (fieldDataType(nField) == SQLITE_NULL);
}
int CppSQLite3Query::fieldIndex(const char* szField)
{
    checkVM();
    if (szField)
    {
        for (int nField = 0; nField < mnCols; nField++)
        {
            const char* szTemp = sqlite3_column_name(mpVM, nField);
            if (strcmp(szField, szTemp) == 0)
            {
                return nField;
            }
        }
    }
    throw CppSQLite3Exception(CPPSQLITE_ERROR,
                            "Invalid field name requested",
                            DONT_DELETE_MSG);
}
const char* CppSQLite3Query::fieldName(int nCol)
{
    checkVM();
    if (nCol < 0 || nCol > mnCols-1)
    {
        throw CppSQLite3Exception(CPPSQLITE_ERROR,
                                "Invalid field index requested",
                                DONT_DELETE_MSG);
    }
    return sqlite3_column_name(mpVM, nCol);
}
const char* CppSQLite3Query::fieldDeclType(int nCol)
{
    checkVM();
    if (nCol < 0 || nCol > mnCols-1)
    {
        throw CppSQLite3Exception(CPPSQLITE_ERROR,
                                "Invalid field index requested",
                                DONT_DELETE_MSG);
    }
    return sqlite3_column_decltype(mpVM, nCol);
}
int CppSQLite3Query::fieldDataType(int nCol)
{
    checkVM();
    if (nCol < 0 || nCol > mnCols-1)
    {
        throw CppSQLite3Exception(CPPSQLITE_ERROR,
                                "Invalid field index requested",
                                DONT_DELETE_MSG);
    }
    return sqlite3_column_type(mpVM, nCol);
}
bool CppSQLite3Query::eof()
{
    checkVM();
    return mbEof;
}
void CppSQLite3Query::nextRow()
{
    checkVM();
    int nRet = sqlite3_step(mpVM);
    if (nRet == SQLITE_DONE)
    {
        // no rows
        mbEof = true;
    }
    else if (nRet == SQLITE_ROW)
    {
        // more rows, nothing to do
    }
    else
    {
        nRet = sqlite3_finalize(mpVM);
        mpVM = 0;
        const char* szError = sqlite3_errmsg(mpDB);
        throw CppSQLite3Exception(nRet,
                                (char*)szError,
                                DONT_DELETE_MSG);
    }
}
void CppSQLite3Query::finalize()
{
    if (mpVM && mbOwnVM)
    {
        int nRet = sqlite3_finalize(mpVM);
        mpVM = 0;
        if (nRet != SQLITE_OK)
        {
            const char* szError = sqlite3_errmsg(mpDB);
            throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
        }
    }
}
void CppSQLite3Query::checkVM()
{
    if (mpVM == 0)
    {
        throw CppSQLite3Exception(CPPSQLITE_ERROR,
                                "Null Virtual Machine pointer",
                                DONT_DELETE_MSG);
    }
}
////////////////////////////////////////////////////////////////////////////////
CppSQLite3Table::CppSQLite3Table()
{
    mpaszResults = 0;
    mnRows = 0;
    mnCols = 0;
    mnCurrentRow = 0;
}
CppSQLite3Table::CppSQLite3Table(const CppSQLite3Table& rTable)
{
    mpaszResults = rTable.mpaszResults;
    // Only one object can own the results
    const_cast<CppSQLite3Table&>(rTable).mpaszResults = 0;
    mnRows = rTable.mnRows;
    mnCols = rTable.mnCols;
    mnCurrentRow = rTable.mnCurrentRow;
}
CppSQLite3Table::CppSQLite3Table(char** paszResults, int nRows, int nCols)
{
    mpaszResults = paszResults;
    mnRows = nRows;
    mnCols = nCols;
    mnCurrentRow = 0;
}
CppSQLite3Table::~CppSQLite3Table()
{
    try
    {
        finalize();
    }
    catch (...)
    {
    }
}
CppSQLite3Table& CppSQLite3Table::operator=(const CppSQLite3Table& rTable)
{
    try
    {
        finalize();
    }
    catch (...)
    {
    }
    mpaszResults = rTable.mpaszResults;
    // Only one object can own the results
    const_cast<CppSQLite3Table&>(rTable).mpaszResults = 0;
    mnRows = rTable.mnRows;
    mnCols = rTable.mnCols;
    mnCurrentRow = rTable.mnCurrentRow;
    return *this;
}
void CppSQLite3Table::finalize()
{
    if (mpaszResults)
    {
        sqlite3_free_table(mpaszResults);
        mpaszResults = 0;
    }
}
int CppSQLite3Table::numFields()
{
    checkResults();
    return mnCols;
}
int CppSQLite3Table::numRows()
{
    checkResults();
    return mnRows;
}
const char* CppSQLite3Table::fieldValue(int nField)
{
    checkResults();
    if (nField < 0 || nField > mnCols-1)
    {
        throw CppSQLite3Exception(CPPSQLITE_ERROR,
                                "Invalid field index requested",