//////////////////////////////////////////////////////////////////////////////// // CppSQLite3U is a C++ unicode wrapper around the SQLite3 embedded database library. // // Copyright (c) 2006 Tyushkov Nikolay. All Rights Reserved. http://softvoile.com // // // Based on beautiful wrapper written by Rob Groves // (https://secure.codeproject.com/database/CppSQLite.asp). // Very good wrapper, but without unicode support unfortunately. // So, I have reconstructed it for unicode. // // CppSQLite3 wrapper: // Copyright (c) 2004 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. // // If you want to get some documentation look at // https://secure.codeproject.com/database/CppSQLite.asp // Note, not all features from CppSQLite3 were implemented in CppSQLite3U // // V1.0 11/06/2006 - Initial Public Version // // Notes : // I have tested this wrapper only in unicode version, so I have no idea // about its work in ANSI configuration, I think it doesn't work without modification;) // // Home page : http://softvoile.com/development/CppSQLite3U/ // Please send all bug report and comment to mail2@softvoile.com // // //////////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "CppSQLite3U.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif namespace OTSSQLITE { ///////////////////////////////////////////////////////////////////////////// // CppSQLite3Exception CppSQLite3Exception::CppSQLite3Exception(const int nErrCode, LPTSTR a_sErrMess, bool a_bDeleteMsg/*=true*/) : m_nErrCode(nErrCode) { m_sErrMessage.Format(_T("%s[%d]: %s"), GetErrorCodeAsString(nErrCode), nErrCode, a_sErrMess ? a_sErrMess : _T("")); if (a_bDeleteMsg && a_sErrMess) { _sqlite3_free((char*)a_sErrMess); } } CppSQLite3Exception::CppSQLite3Exception(const CppSQLite3Exception& ex) : m_nErrCode(ex.m_nErrCode) , m_sErrMessage(ex.m_sErrMessage) { } LPCTSTR CppSQLite3Exception::GetErrorCodeAsString(int a_nErrCode) { switch (a_nErrCode) { case SQLITE_OK : return _T("SQLITE_OK"); case SQLITE_ERROR : return _T("SQLITE_ERROR"); case SQLITE_INTERNAL : return _T("SQLITE_INTERNAL"); case SQLITE_PERM : return _T("SQLITE_PERM"); case SQLITE_ABORT : return _T("SQLITE_ABORT"); case SQLITE_BUSY : return _T("SQLITE_BUSY"); case SQLITE_LOCKED : return _T("SQLITE_LOCKED"); case SQLITE_NOMEM : return _T("SQLITE_NOMEM"); case SQLITE_READONLY : return _T("SQLITE_READONLY"); case SQLITE_INTERRUPT : return _T("SQLITE_INTERRUPT"); case SQLITE_IOERR : return _T("SQLITE_IOERR"); case SQLITE_CORRUPT : return _T("SQLITE_CORRUPT"); case SQLITE_NOTFOUND : return _T("SQLITE_NOTFOUND"); case SQLITE_FULL : return _T("SQLITE_FULL"); case SQLITE_CANTOPEN : return _T("SQLITE_CANTOPEN"); case SQLITE_PROTOCOL : return _T("SQLITE_PROTOCOL"); case SQLITE_EMPTY : return _T("SQLITE_EMPTY"); case SQLITE_SCHEMA : return _T("SQLITE_SCHEMA"); case SQLITE_TOOBIG : return _T("SQLITE_TOOBIG"); case SQLITE_CONSTRAINT : return _T("SQLITE_CONSTRAINT"); case SQLITE_MISMATCH : return _T("SQLITE_MISMATCH"); case SQLITE_MISUSE : return _T("SQLITE_MISUSE"); case SQLITE_NOLFS : return _T("SQLITE_NOLFS"); case SQLITE_AUTH : return _T("SQLITE_AUTH"); case SQLITE_FORMAT : return _T("SQLITE_FORMAT"); case SQLITE_RANGE : return _T("SQLITE_RANGE"); case SQLITE_ROW : return _T("SQLITE_ROW"); case SQLITE_DONE : return _T("SQLITE_DONE"); case CPPSQLITE_ERROR : return _T("CPPSQLITE_ERROR"); default: return _T("UNKNOWN_ERROR"); } } CppSQLite3Exception::~CppSQLite3Exception() { } ///////////////////////////////////////////////////////////////////////////// // CppSQLite3DB CppSQLite3DB::CppSQLite3DB() { m_pDB = 0; m_nBusyTimeoutMs = 60000; // 60 seconds } CppSQLite3DB::CppSQLite3DB(const CppSQLite3DB& db) { m_pDB = db.m_pDB; m_nBusyTimeoutMs = 60000; // 60 seconds } CppSQLite3DB::~CppSQLite3DB() { close(); } //////////////////////////////////////////////////////////////////////////////// CppSQLite3DB& CppSQLite3DB::operator=(const CppSQLite3DB& db) { m_pDB = db.m_pDB; m_nBusyTimeoutMs = 60000; // 60 seconds return *this; } void CppSQLite3DB::open(LPCTSTR szFile) { int nRet; #if defined(_UNICODE) || defined(UNICODE) nRet = sqlite3_open16(szFile, &m_pDB); // not tested under window 98 #else // For Ansi Version //*************- Added by Begemot szFile must be in unicode- 23/03/06 11:04 - **** /* OSVERSIONINFOEX osvi; ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); GetVersionEx ((OSVERSIONINFO *) &osvi); if ( osvi.dwMajorVersion == 5) { WCHAR pMultiByteStr[MAX_PATH+1]; MultiByteToWideChar( CP_ACP, 0, szFile, _tcslen(szFile)+1, pMultiByteStr, sizeof(pMultiByteStr)/sizeof(pMultiByteStr[0]) ); nRet = sqlite3_open16(pMultiByteStr, &m_pDB); } else*/ //文件路径的编码转换 translate the file path encoding to utf-8 .added by gsp 2019-12-18 int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; int nlen = MultiByteToWideChar(codepage, 0, szFile, -1, NULL, 0); WCHAR wBuf[256]; MultiByteToWideChar(CP_ACP, 0, szFile, -1, wBuf, nlen); CHAR pBuf[256]; nlen = WideCharToMultiByte(CP_UTF8, 0, wBuf, -1, 0, 0, 0, 0); WideCharToMultiByte(CP_UTF8, 0, wBuf, -1, pBuf, nlen, 0, 0); nRet = sqlite3_open(pBuf, &m_pDB); #endif //************************* if (nRet != SQLITE_OK) { LPCTSTR szError = (LPCTSTR) _sqlite3_errmsg(m_pDB); throw CppSQLite3Exception(nRet, (LPTSTR)szError, DONT_DELETE_MSG); } setBusyTimeout(m_nBusyTimeoutMs); } bool CppSQLite3DB::isOpened() { return !!m_pDB; } void CppSQLite3DB::close() { if (m_pDB) { int nRet = _sqlite3_close(m_pDB); if (nRet != SQLITE_OK) { LPCTSTR szError = (LPCTSTR)_sqlite3_errmsg(m_pDB); throw CppSQLite3Exception(nRet, (LPTSTR)szError, DONT_DELETE_MSG); } m_pDB = 0; } } CppSQLite3StatementPtr CppSQLite3DB::compileStatement(LPCTSTR szSQL) { checkDB(); sqlite3_stmt* pVM = compile(szSQL); return CppSQLite3StatementPtr(new CppSQLite3Statement(shared_from_this(), pVM)); } bool CppSQLite3DB::tableExists(LPCTSTR szTable) { CString sSQL; sSQL.Format(_T("select count(*) from sqlite_master where type='table' and name='%s'"), szTable); int nRet = execScalar(sSQL); return (nRet > 0); } int CppSQLite3DB::execDML(LPCTSTR szSQL) { int nRet; sqlite3_stmt* pVM; checkDB(); do{ pVM = compile(szSQL); nRet = _sqlite3_step(pVM); if (nRet == SQLITE_ERROR) { _sqlite3_finalize(pVM); LPCTSTR szError = (LPCTSTR) _sqlite3_errmsg(m_pDB); throw CppSQLite3Exception(nRet, (LPTSTR)szError, DONT_DELETE_MSG); } nRet = _sqlite3_finalize(pVM); } while( nRet == SQLITE_SCHEMA ); return nRet; } CppSQLite3QueryPtr CppSQLite3DB::execQuery(LPCTSTR szSQL) { checkDB(); int nRet; sqlite3_stmt* pVM; do{ pVM = compile(szSQL); nRet = _sqlite3_step(pVM); if (nRet == SQLITE_DONE) { // no rows return CppSQLite3QueryPtr(new CppSQLite3Query(shared_from_this(), pVM, true/*eof*/)); } else if (nRet == SQLITE_ROW) { // at least 1 row return CppSQLite3QueryPtr(new CppSQLite3Query(shared_from_this(), pVM, false/*eof*/)); } nRet = _sqlite3_finalize(pVM); } while( nRet == SQLITE_SCHEMA ); // Edit By Begemot 08/16/06 12:44:35 - read SQLite FAQ // LPCTSTR szError = (LPCTSTR) _sqlite3_errmsg(m_pDB); // throw CppSQLite3Exception(nRet, (LPTSTR)szError, DONT_DELETE_MSG); return NULL; } int CppSQLite3DB::execScalar(LPCTSTR szSQL) { auto q = execQuery(szSQL); if (NULL == q) { return -1; } if (q->eof() || q->numFields() < 1) throw CppSQLite3Exception(CPPSQLITE_ERROR, _T("Invalid scalar query"), DONT_DELETE_MSG); return q->getIntField(0); //return _tstoi(q->fieldValue(0)); } // Added By Begemot, exact as execScalar but return CString 08/06/06 16:30:37 CString CppSQLite3DB::execScalarStr(LPCTSTR szSQL) { auto q = execQuery(szSQL); if (q->eof() || q->numFields() < 1) throw CppSQLite3Exception(CPPSQLITE_ERROR, _T("Invalid scalar query"), DONT_DELETE_MSG); return (CString)q->getStringField(0); } sqlite_int64 CppSQLite3DB::lastRowId() { return sqlite3_last_insert_rowid(m_pDB); } void CppSQLite3DB::setBusyTimeout(int nMillisecs) { m_nBusyTimeoutMs = nMillisecs; auto nRet = sqlite3_busy_timeout(m_pDB, m_nBusyTimeoutMs); if (nRet != SQLITE_OK) { LPCTSTR szError = (LPCTSTR) _sqlite3_errmsg(m_pDB); throw CppSQLite3Exception(nRet, (LPTSTR)szError, DONT_DELETE_MSG); } } void CppSQLite3DB::checkDB() { if (!m_pDB) throw CppSQLite3Exception(CPPSQLITE_ERROR,_T("Database not open"), DONT_DELETE_MSG); } sqlite3_stmt* CppSQLite3DB::compile(LPCTSTR szSQL) { checkDB(); sqlite3_stmt* pVM; int nRet = _sqlite3_prepare(m_pDB, szSQL, -1, &pVM, NULL); if (SQLITE_NOTADB == nRet) { return NULL; } if (nRet != SQLITE_OK) { pVM=NULL; LPCTSTR szError = (LPCTSTR) _sqlite3_errmsg(m_pDB); throw CppSQLite3Exception(nRet, (LPTSTR)szError, DONT_DELETE_MSG); } return pVM; } //////////////////////// CppSQLite3Statement /////////////////////////////////////////// CppSQLite3Statement::CppSQLite3Statement() { m_pDBPtr.reset(); m_pVM = 0; } CppSQLite3Statement::CppSQLite3Statement(const CppSQLite3Statement& rStatement) { m_pDBPtr = rStatement.m_pDBPtr; m_pVM = rStatement.m_pVM; // Only one object can own VM const_cast(rStatement).m_pVM = 0; } CppSQLite3Statement::CppSQLite3Statement(CppSQLite3DBPtr a_pDB, sqlite3_stmt* pVM) { m_pDBPtr = a_pDB; m_pVM = pVM; } CppSQLite3Statement::~CppSQLite3Statement() { try { finalize(); } catch (...) {} } CppSQLite3Statement& CppSQLite3Statement::operator=(const CppSQLite3Statement& rStatement) { m_pDBPtr = rStatement.m_pDBPtr; m_pVM = rStatement.m_pVM; // Only one object can own VM const_cast(rStatement).m_pVM = 0; return *this; } int CppSQLite3Statement::execDML() { checkDB(); checkVM(); int nRet = sqlite3_step(m_pVM); if (nRet == SQLITE_DONE) { int nRowsChanged = sqlite3_changes(m_pDBPtr->m_pDB); nRet = sqlite3_reset(m_pVM); if (nRet != SQLITE_OK) { LPCTSTR szError = (LPCTSTR) _sqlite3_errmsg(m_pDBPtr->m_pDB); throw CppSQLite3Exception(nRet, (LPTSTR)szError, DONT_DELETE_MSG); } return nRowsChanged; } else { nRet = sqlite3_reset(m_pVM); LPCTSTR szError = (LPCTSTR) _sqlite3_errmsg(m_pDBPtr->m_pDB); throw CppSQLite3Exception(nRet, (LPTSTR)szError, DONT_DELETE_MSG); } } void CppSQLite3Statement::bind(int nParam, LPCTSTR szValue) { checkVM(); int nRes = _sqlite3_bind_text(m_pVM, nParam, szValue, -1, SQLITE_TRANSIENT); if (nRes != SQLITE_OK) throw CppSQLite3Exception(nRes,_T("Error binding string param"), DONT_DELETE_MSG); } void CppSQLite3Statement::bind(int nParam, const int nValue) { checkVM(); int nRes = sqlite3_bind_int(m_pVM, nParam, nValue); if (nRes != SQLITE_OK) throw CppSQLite3Exception(nRes,_T("Error binding int param"), DONT_DELETE_MSG); } void CppSQLite3Statement::bind(int nParam, const double dValue) { checkVM(); int nRes = sqlite3_bind_double(m_pVM, nParam, dValue); if (nRes != SQLITE_OK) throw CppSQLite3Exception(nRes, _T("Error binding double param"), DONT_DELETE_MSG); } void CppSQLite3Statement::bind(int nParam, const unsigned char* blobValue, int nLen) { checkVM(); int nRes = sqlite3_bind_blob(m_pVM, nParam,(const void*)blobValue, nLen, SQLITE_TRANSIENT); if (nRes != SQLITE_OK) throw CppSQLite3Exception(nRes,_T("Error binding blob param"),DONT_DELETE_MSG); } void CppSQLite3Statement::bindNull(int nParam) { checkVM(); int nRes = sqlite3_bind_null(m_pVM, nParam); if (nRes != SQLITE_OK) throw CppSQLite3Exception(nRes,_T("Error binding NULL param"),DONT_DELETE_MSG); } void CppSQLite3Statement::reset() { if (m_pVM) { int nRet = sqlite3_reset(m_pVM); if (nRet != SQLITE_OK) { LPCTSTR szError = (LPCTSTR) _sqlite3_errmsg(m_pDBPtr->m_pDB); throw CppSQLite3Exception(nRet, (LPTSTR)szError, DONT_DELETE_MSG); } } } void CppSQLite3Statement::finalize() { if (m_pVM) { int nRet = sqlite3_finalize(m_pVM); m_pVM = 0; if (nRet != SQLITE_OK) { LPCTSTR szError = (LPCTSTR) _sqlite3_errmsg(m_pDBPtr->m_pDB); throw CppSQLite3Exception(nRet, (LPTSTR)szError, DONT_DELETE_MSG); } } } void CppSQLite3Statement::checkDB() { if (!m_pDBPtr) throw CppSQLite3Exception(CPPSQLITE_ERROR,_T("Database not open"), DONT_DELETE_MSG); } void CppSQLite3Statement::checkVM() { if (m_pVM == 0) throw CppSQLite3Exception(CPPSQLITE_ERROR,_T("Null Virtual Machine pointer"), DONT_DELETE_MSG); } ///////////////////// CppSQLite3Query ////////////////////////////////////////////////// CppSQLite3Query::CppSQLite3Query() { m_pVM = 0; m_bEof = true; m_nCols = 0; m_bOwnVM = false; } CppSQLite3Query::CppSQLite3Query(const CppSQLite3Query& rQuery) { m_pVM = rQuery.m_pVM; // Only one object can own the VM const_cast(rQuery).m_pVM = 0; m_bEof = rQuery.m_bEof; m_nCols = rQuery.m_nCols; m_bOwnVM = rQuery.m_bOwnVM; } CppSQLite3Query::CppSQLite3Query(CppSQLite3DBPtr pDB, sqlite3_stmt* pVM, bool bEof, bool bOwnVM/*=true*/) { m_pDBPtr = pDB; m_pVM = pVM; m_bEof = bEof; m_nCols = _sqlite3_column_count(m_pVM); m_bOwnVM = bOwnVM; } CppSQLite3Query::~CppSQLite3Query() { try { finalize(); } catch (...) {} } CppSQLite3Query& CppSQLite3Query::operator=(const CppSQLite3Query& rQuery) { try { finalize(); } catch (...) { } m_pVM = rQuery.m_pVM; // Only one object can own the VM const_cast(rQuery).m_pVM = 0; m_bEof = rQuery.m_bEof; m_nCols = rQuery.m_nCols; m_bOwnVM = rQuery.m_bOwnVM; return *this; } int CppSQLite3Query::numFields() { checkVM(); return m_nCols; } LPCTSTR CppSQLite3Query::fieldValue(int nField) { checkVM(); if (nField < 0 || nField > m_nCols-1) throw CppSQLite3Exception(CPPSQLITE_ERROR,_T("Invalid field index requested"),DONT_DELETE_MSG); return (LPCTSTR)_sqlite3_column_text(m_pVM, nField); } LPCTSTR CppSQLite3Query::fieldValue(LPCTSTR szField) { int nField = fieldIndex(szField); return (LPCTSTR)_sqlite3_column_text(m_pVM, nField); } int CppSQLite3Query::getIntField(int nField, int nNullValue/*=0*/) { if (fieldDataType(nField) == SQLITE_NULL) { return nNullValue; } else { return _sqlite3_column_int(m_pVM, nField); } } int CppSQLite3Query::getIntField(LPCTSTR szField, int nNullValue/*=0*/) { int nField = fieldIndex(szField); return getIntField(nField, nNullValue); } double CppSQLite3Query::getFloatField(int nField, double fNullValue/*=0.0*/) { if (fieldDataType(nField) == SQLITE_NULL) { return fNullValue; } else { return _sqlite3_column_double(m_pVM, nField); } } double CppSQLite3Query::getFloatField(LPCTSTR szField, double fNullValue/*=0.0*/) { int nField = fieldIndex(szField); return getFloatField(nField, fNullValue); } LPCTSTR CppSQLite3Query::getStringField(int nField, LPCTSTR szNullValue/*=""*/) { if (fieldDataType(nField) == SQLITE_NULL) { return szNullValue; } else { return (LPCTSTR)_sqlite3_column_text(m_pVM, nField); } } LPCTSTR CppSQLite3Query::getStringField(LPCTSTR szField, LPCTSTR szNullValue/*=""*/) { int nField = fieldIndex(szField); return getStringField(nField, szNullValue); } const unsigned char* CppSQLite3Query::getBlobField(int nField, int& nLen) { checkVM(); if (nField < 0 || nField > m_nCols-1) throw CppSQLite3Exception(CPPSQLITE_ERROR,_T("Invalid field index requested"),DONT_DELETE_MSG); nLen = _sqlite3_column_bytes(m_pVM, nField); return (const unsigned char*)sqlite3_column_blob(m_pVM, nField); } const unsigned char* CppSQLite3Query::getBlobField(LPCTSTR szField, int& nLen) { int nField = fieldIndex(szField); return getBlobField(nField, nLen); } bool CppSQLite3Query::fieldIsNull(int nField) { return (fieldDataType(nField) == SQLITE_NULL); } bool CppSQLite3Query::fieldIsNull(LPCTSTR szField) { int nField = fieldIndex(szField); return (fieldDataType(nField) == SQLITE_NULL); } int CppSQLite3Query::fieldIndex(LPCTSTR szField) { checkVM(); if (szField) { for (int nField = 0; nField < m_nCols; nField++) { LPCTSTR szTemp = (LPCTSTR)_sqlite3_column_name(m_pVM, nField); if (_tcscmp(szField, szTemp) == 0) { return nField; } } } throw CppSQLite3Exception(CPPSQLITE_ERROR,_T("Invalid field name requested"),DONT_DELETE_MSG); } LPCTSTR CppSQLite3Query::fieldName(int nCol) { checkVM(); if (nCol < 0 || nCol > m_nCols-1) { throw CppSQLite3Exception(CPPSQLITE_ERROR,_T("Invalid field index requested"),DONT_DELETE_MSG); } return (LPCTSTR)_sqlite3_column_name(m_pVM, nCol); } LPCTSTR CppSQLite3Query::fieldDeclType(int nCol) { checkVM(); if (nCol < 0 || nCol > m_nCols-1) { throw CppSQLite3Exception(CPPSQLITE_ERROR,_T("Invalid field index requested"),DONT_DELETE_MSG); } return (LPCTSTR)_sqlite3_column_decltype(m_pVM, nCol); } int CppSQLite3Query::fieldDataType(int nCol) { checkVM(); if (nCol < 0 || nCol > m_nCols-1) { throw CppSQLite3Exception(CPPSQLITE_ERROR,_T("Invalid field index requested"), DONT_DELETE_MSG); } return _sqlite3_column_type(m_pVM, nCol); } bool CppSQLite3Query::eof() { checkVM(); return m_bEof; } void CppSQLite3Query::nextRow() { checkVM(); int nRet = _sqlite3_step(m_pVM); if (nRet == SQLITE_DONE) { // no rows m_bEof = true; } else if (nRet == SQLITE_ROW) { // more rows, nothing to do } else { nRet = _sqlite3_finalize(m_pVM); m_pVM = 0; LPCTSTR szError = (LPCTSTR)_sqlite3_errmsg(m_pDBPtr->m_pDB); throw CppSQLite3Exception(nRet, (LPTSTR)szError, DONT_DELETE_MSG); } } void CppSQLite3Query::finalize() { if (m_pVM && m_bOwnVM) { int nRet = _sqlite3_finalize(m_pVM); m_pVM = 0; if (nRet != SQLITE_OK) { LPCTSTR szError = (LPCTSTR)_sqlite3_errmsg(m_pDBPtr->m_pDB); throw CppSQLite3Exception(nRet, (LPTSTR)szError, DONT_DELETE_MSG); } } } void CppSQLite3Query::checkVM() { if (m_pVM == 0) { throw CppSQLite3Exception(CPPSQLITE_ERROR,_T("Null Virtual Machine pointer"),DONT_DELETE_MSG); } } //////////////////////////////////////////////////////////////////////////////// //************************** //*************- Added By Begemot - 28/02/06 20:25 - **** CString DoubleQuotes(CString in) { in.Replace(_T("\'"),_T("\'\'")); return in; } } // namespace Datastore