/////////////////////////////////////////////////////////////////////////////// // Name: wxsqlite3.cpp // Purpose: Implementation of wxSQLite3 classes // Author: Ulrich Telle // Modified by: // Created: 2005-07-06 // Copyright: (c) Ulrich Telle // Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// /// \file wxsqlite3.cpp Implementation of the wxSQLite3 class #if defined(__GNUG__) && !defined(__APPLE__) #pragma implementation "wxsqlite3.h" #endif // For compilers that support precompilation, includes "wx/wx.h". /*#include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include "wx/wx.h" #endif */ #include "../xvaga/wxinc.h" #include "wx/regex.h" #include "wx/thread.h" #include "wxsqlite3.h" #include "wxsqlite3opt.h" // Suppress some Visual C++ warnings regarding the default constructor // for a C struct used only in SQLite modules #ifdef __VISUALC__ #pragma warning (disable:4510) #pragma warning (disable:4610) #endif #if WXSQLITE3_HAVE_CODEC #define SQLITE_HAS_CODEC 1 #else #define SQLITE_HAS_CODEC 0 #endif #include "../sqlite/sqlite3.h" // Dynamic loading of the SQLite library #if wxUSE_DYNAMIC_SQLITE3_LOAD #include "wx/dynlib.h" #define DYNFUNC(rcode, rtype, fname, farg, farguse) \ typedef rtype (*p##fname) farg ; \ static p##fname s_##fname = NULL; #include "wxsqlite3dyn.h" #undef DYNFUNC static wxDynamicLibrary s_dll; static void InitSQLite3DLL() { if (s_dll.IsLoaded()) { return; } #ifdef __WIN32__ if (! s_dll.Load(wxT("sqlite3"))) #else if (! s_dll.Load(wxT("libsqlite3"))) #endif { throw wxSQLite3Exception(-1, wxT("error loading dynamic library")); } #define DYNFUNC(rcode, rtype, fname, farg, farguse) \ s_##fname = (p##fname) s_dll.GetSymbol(wxT(#fname));\ if (! s_##fname)\ {\ s_dll.Unload();\ throw wxSQLite3Exception(-1, wxT("error getting symbol <") wxT(#fname) wxT(">"));\ } #include "wxsqlite3dyn.h" #undef DYNFUNC }; #define DYNFUNC(rcode, rtype, fname, farg, farguse) \ rtype fname farg \ {\ InitSQLite3DLL();\ rcode s_##fname farguse;\ }; #include "wxsqlite3dyn.h" #undef DYNFUNC #else // Define Windows specific SQLite API functions (not defined in sqlite3.h) #if SQLITE_VERSION_NUMBER >= 3007014 #if defined(__WXMSW__) #ifdef __cplusplus extern "C" { #endif SQLITE_API int sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue); #ifdef __cplusplus } #endif #endif #endif #endif // wxUSE_DYNAMIC_SQLITE3_LOAD // Error messages #if wxCHECK_VERSION(2,9,0) const char* wxERRMSG_NODB = wxTRANSLATE("No Database opened"); const char* wxERRMSG_NOSTMT = wxTRANSLATE("Statement not accessible"); const char* wxERRMSG_NOMEM = wxTRANSLATE("Out of memory"); const char* wxERRMSG_DECODE = wxTRANSLATE("Cannot decode binary"); const char* wxERRMSG_INVALID_INDEX = wxTRANSLATE("Invalid field index"); const char* wxERRMSG_INVALID_NAME = wxTRANSLATE("Invalid field name"); const char* wxERRMSG_INVALID_ROW = wxTRANSLATE("Invalid row index"); const char* wxERRMSG_INVALID_QUERY = wxTRANSLATE("Invalid scalar query"); const char* wxERRMSG_INVALID_BLOB = wxTRANSLATE("Invalid BLOB handle"); const char* wxERRMSG_NORESULT = wxTRANSLATE("Null Results pointer"); const char* wxERRMSG_BIND_STR = wxTRANSLATE("Error binding string param"); const char* wxERRMSG_BIND_INT = wxTRANSLATE("Error binding int param"); const char* wxERRMSG_BIND_INT64 = wxTRANSLATE("Error binding int64 param"); const char* wxERRMSG_BIND_DBL = wxTRANSLATE("Error binding double param"); const char* wxERRMSG_BIND_BLOB = wxTRANSLATE("Error binding blob param"); const char* wxERRMSG_BIND_DATETIME = wxTRANSLATE("Error binding date/time param"); const char* wxERRMSG_BIND_NULL = wxTRANSLATE("Error binding NULL param"); const char* wxERRMSG_BIND_ZEROBLOB = wxTRANSLATE("Error binding zero blob param"); const char* wxERRMSG_BIND_CLEAR = wxTRANSLATE("Error clearing bindings"); const char* wxERRMSG_NOMETADATA = wxTRANSLATE("Meta data support not available"); const char* wxERRMSG_NOCODEC = wxTRANSLATE("Encryption support not available"); const char* wxERRMSG_NOLOADEXT = wxTRANSLATE("Loadable extension support not available"); const char* wxERRMSG_NOINCBLOB = wxTRANSLATE("Incremental BLOB support not available"); const char* wxERRMSG_NOBLOBREBIND = wxTRANSLATE("Rebind BLOB support not available"); const char* wxERRMSG_NOSAVEPOINT = wxTRANSLATE("Savepoint support not available"); const char* wxERRMSG_NOBACKUP = wxTRANSLATE("Backup/restore support not available"); const char* wxERRMSG_NOWAL = wxTRANSLATE("Write Ahead Log support not available"); const char* wxERRMSG_NOCOLLECTIONS = wxTRANSLATE("Named collection support not available"); const char* wxERRMSG_SHARED_CACHE = wxTRANSLATE("Setting SQLite shared cache mode failed"); const char* wxERRMSG_INITIALIZE = wxTRANSLATE("Initialization of SQLite failed"); const char* wxERRMSG_SHUTDOWN = wxTRANSLATE("Shutdown of SQLite failed"); const char* wxERRMSG_TEMPDIR = wxTRANSLATE("Setting temporary directory failed"); const char* wxERRMSG_SOURCEDB_BUSY = wxTRANSLATE("Source database is busy"); const char* wxERRMSG_DBOPEN_FAILED = wxTRANSLATE("Database open failed"); const char* wxERRMSG_DBCLOSE_FAILED = wxTRANSLATE("Database close failed"); const char* wxERRMSG_DBASSIGN_FAILED = wxTRANSLATE("Database assignment failed"); const char* wxERRMSG_FINALIZE_FAILED = wxTRANSLATE("Finalize failed"); #else const wxChar* wxERRMSG_NODB = wxTRANSLATE("No Database opened"); const wxChar* wxERRMSG_NOSTMT = wxTRANSLATE("Statement not accessible"); const wxChar* wxERRMSG_NOMEM = wxTRANSLATE("Out of memory"); const wxChar* wxERRMSG_DECODE = wxTRANSLATE("Cannot decode binary"); const wxChar* wxERRMSG_INVALID_INDEX = wxTRANSLATE("Invalid field index"); const wxChar* wxERRMSG_INVALID_NAME = wxTRANSLATE("Invalid field name"); const wxChar* wxERRMSG_INVALID_ROW = wxTRANSLATE("Invalid row index"); const wxChar* wxERRMSG_INVALID_QUERY = wxTRANSLATE("Invalid scalar query"); const wxChar* wxERRMSG_INVALID_BLOB = wxTRANSLATE("Invalid BLOB handle"); const wxChar* wxERRMSG_NORESULT = wxTRANSLATE("Null Results pointer"); const wxChar* wxERRMSG_BIND_STR = wxTRANSLATE("Error binding string param"); const wxChar* wxERRMSG_BIND_INT = wxTRANSLATE("Error binding int param"); const wxChar* wxERRMSG_BIND_INT64 = wxTRANSLATE("Error binding int64 param"); const wxChar* wxERRMSG_BIND_DBL = wxTRANSLATE("Error binding double param"); const wxChar* wxERRMSG_BIND_BLOB = wxTRANSLATE("Error binding blob param"); const wxChar* wxERRMSG_BIND_DATETIME = wxTRANSLATE("Error binding date/time param"); const wxChar* wxERRMSG_BIND_NULL = wxTRANSLATE("Error binding NULL param"); const wxChar* wxERRMSG_BIND_ZEROBLOB = wxTRANSLATE("Error binding zero blob param"); const wxChar* wxERRMSG_BIND_CLEAR = wxTRANSLATE("Error clearing bindings"); const wxChar* wxERRMSG_NOMETADATA = wxTRANSLATE("Meta data support not available"); const wxChar* wxERRMSG_NOCODEC = wxTRANSLATE("Encryption support not available"); const wxChar* wxERRMSG_NOLOADEXT = wxTRANSLATE("Loadable extension support not available"); const wxChar* wxERRMSG_NOINCBLOB = wxTRANSLATE("Incremental BLOB support not available"); const wxChar* wxERRMSG_NOBLOBREBIND = wxTRANSLATE("Rebind BLOB support not available"); const wxChar* wxERRMSG_NOSAVEPOINT = wxTRANSLATE("Savepoint support not available"); const wxChar* wxERRMSG_NOBACKUP = wxTRANSLATE("Backup/restore support not available"); const wxChar* wxERRMSG_NOWAL = wxTRANSLATE("Write Ahead Log support not available"); const wxChar* wxERRMSG_NOCOLLECTIONS = wxTRANSLATE("Named collection support not available"); const wxChar* wxERRMSG_SHARED_CACHE = wxTRANSLATE("Setting SQLite shared cache mode failed"); const wxChar* wxERRMSG_INITIALIZE = wxTRANSLATE("Initialization of SQLite failed"); const wxChar* wxERRMSG_SHUTDOWN = wxTRANSLATE("Shutdown of SQLite failed"); const wxChar* wxERRMSG_TEMPDIR = wxTRANSLATE("Setting temporary directory failed"); const wxChar* wxERRMSG_SOURCEDB_BUSY = wxTRANSLATE("Source database is busy"); const wxChar* wxERRMSG_DBOPEN_FAILED = wxTRANSLATE("Database open failed"); const wxChar* wxERRMSG_DBCLOSE_FAILED = wxTRANSLATE("Database close failed"); const wxChar* wxERRMSG_DBASSIGN_FAILED = wxTRANSLATE("Database assignment failed"); const wxChar* wxERRMSG_FINALIZE_FAILED = wxTRANSLATE("Finalize failed"); #endif // Critical sections are used to make access to it thread safe if necessary. #if wxUSE_THREADS static wxCriticalSection gs_csDatabase; static wxCriticalSection gs_csStatment; static wxCriticalSection gs_csBlob; #endif class wxSQLite3DatabaseReference { public: /// Default constructor wxSQLite3DatabaseReference(sqlite3* db = NULL) : m_db(db) { m_db = db; if (m_db != NULL) { m_isValid = true; m_refCount = 1; } else { m_isValid = false; m_refCount = 0; } } /// Default destructor virtual ~wxSQLite3DatabaseReference() { } private: /// Thread safe increment of the reference count int IncrementRefCount() { #if wxUSE_THREADS wxCriticalSectionLocker locker(gs_csDatabase); #endif return ++m_refCount; } void Invalidate() { #if wxUSE_THREADS wxCriticalSectionLocker locker(gs_csDatabase); #endif m_isValid = false; } /// Thread safe decrement of the reference count int DecrementRefCount() { #if wxUSE_THREADS wxCriticalSectionLocker locker(gs_csDatabase); #endif if (m_refCount > 0) --m_refCount; return m_refCount; } sqlite3* m_db; ///< SQLite database reference int m_refCount; ///< Reference count bool m_isValid; ///< SQLite database reference is valid friend class WXDLLIMPEXP_FWD_SQLITE3 wxSQLite3Database; friend class WXDLLIMPEXP_FWD_SQLITE3 wxSQLite3ResultSet; friend class WXDLLIMPEXP_FWD_SQLITE3 wxSQLite3Statement; friend class WXDLLIMPEXP_FWD_SQLITE3 wxSQLite3Blob; }; class wxSQLite3StatementReference { public: /// Default constructor wxSQLite3StatementReference(sqlite3_stmt* stmt = NULL) : m_stmt(stmt) { m_stmt = stmt; if (m_stmt != NULL) { m_isValid = true; m_refCount = 0; } else { m_isValid = false; m_refCount = 0; } } /// Default destructor virtual ~wxSQLite3StatementReference() { } private: /// Thread safe increment of the reference count int IncrementRefCount() { #if wxUSE_THREADS wxCriticalSectionLocker locker(gs_csStatment); #endif return ++m_refCount; } /// Thread safe decrement of the reference count int DecrementRefCount() { #if wxUSE_THREADS wxCriticalSectionLocker locker(gs_csStatment); #endif if (m_refCount > 0) --m_refCount; return m_refCount; } void Invalidate() { #if wxUSE_THREADS wxCriticalSectionLocker locker(gs_csStatment); #endif m_isValid = false; } sqlite3_stmt* m_stmt; ///< SQLite statement reference int m_refCount; ///< Reference count bool m_isValid; ///< SQLite statement reference is valid friend class WXDLLIMPEXP_FWD_SQLITE3 wxSQLite3ResultSet; friend class WXDLLIMPEXP_FWD_SQLITE3 wxSQLite3Statement; }; class wxSQLite3BlobReference { public: /// Default constructor wxSQLite3BlobReference(sqlite3_blob* blob = NULL) : m_blob(blob) { m_blob = blob; if (m_blob != NULL) { m_isValid = true; m_refCount = 0; } else { m_isValid = false; m_refCount = 0; } } /// Default destructor virtual ~wxSQLite3BlobReference() { } private: /// Thread safe increment of the reference count int IncrementRefCount() { #if wxUSE_THREADS wxCriticalSectionLocker locker(gs_csBlob); #endif return ++m_refCount; } /// Thread safe decrement of the reference count int DecrementRefCount() { #if wxUSE_THREADS wxCriticalSectionLocker locker(gs_csBlob); #endif if (m_refCount > 0) --m_refCount; return m_refCount; } void Invalidate() { #if wxUSE_THREADS wxCriticalSectionLocker locker(gs_csBlob); #endif m_isValid = false; } sqlite3_blob* m_blob; ///< SQLite blob reference int m_refCount; ///< Reference count bool m_isValid; ///< SQLite statement reference is valid friend class WXDLLIMPEXP_FWD_SQLITE3 wxSQLite3Blob; }; // ---------------------------------------------------------------------------- // inline conversion from wxString to wxLongLong // ---------------------------------------------------------------------------- inline wxLongLong ConvertStringToLongLong(const wxString& str, wxLongLong defValue /*=0*/) { size_t n = str.Length(); size_t j = 0; wxLongLong value = 0; bool negative = false; if (str[j] == '-') { negative = true; j++; } while (j < n) { if (str[j] < '0' || str[j] > '9') { return defValue; } value *= 10; value += (str[j] - '0'); j++; } return negative ? -value : value; } // ---------------------------------------------------------------------------- // wxSQLite3Exception: class // ---------------------------------------------------------------------------- wxSQLite3Exception::wxSQLite3Exception(int errorCode, const wxString& errorMsg) : m_errorCode(errorCode) { m_errorMessage = ErrorCodeAsString(errorCode) + wxT("[") + wxString::Format(wxT("%d"), errorCode) + wxT("]: ") + wxGetTranslation(errorMsg); } wxSQLite3Exception::wxSQLite3Exception(const wxSQLite3Exception& e) : m_errorCode(e.m_errorCode), m_errorMessage(e.m_errorMessage) { } const wxString wxSQLite3Exception::ErrorCodeAsString(int errorCode) { #if SQLITE_VERSION_NUMBER >= 3007015 if (errorCode == WXSQLITE_ERROR) { return wxT("WXSQLITE_ERROR"); } else { const char* errmsg = sqlite3_errstr(errorCode); return wxString::FromUTF8(errmsg); } #else switch (errorCode) { case SQLITE_OK : return wxT("SQLITE_OK"); case SQLITE_ERROR : return wxT("SQLITE_ERROR"); case SQLITE_INTERNAL : return wxT("SQLITE_INTERNAL"); case SQLITE_PERM : return wxT("SQLITE_PERM"); case SQLITE_ABORT : return wxT("SQLITE_ABORT"); case SQLITE_BUSY : return wxT("SQLITE_BUSY"); case SQLITE_LOCKED : return wxT("SQLITE_LOCKED"); case SQLITE_NOMEM : return wxT("SQLITE_NOMEM"); case SQLITE_READONLY : return wxT("SQLITE_READONLY"); case SQLITE_INTERRUPT : return wxT("SQLITE_INTERRUPT"); case SQLITE_IOERR : return wxT("SQLITE_IOERR"); case SQLITE_CORRUPT : return wxT("SQLITE_CORRUPT"); case SQLITE_NOTFOUND : return wxT("SQLITE_NOTFOUND"); case SQLITE_FULL : return wxT("SQLITE_FULL"); case SQLITE_CANTOPEN : return wxT("SQLITE_CANTOPEN"); case SQLITE_PROTOCOL : return wxT("SQLITE_PROTOCOL"); case SQLITE_EMPTY : return wxT("SQLITE_EMPTY"); case SQLITE_SCHEMA : return wxT("SQLITE_SCHEMA"); case SQLITE_TOOBIG : return wxT("SQLITE_TOOBIG"); case SQLITE_CONSTRAINT : return wxT("SQLITE_CONSTRAINT"); case SQLITE_MISMATCH : return wxT("SQLITE_MISMATCH"); case SQLITE_MISUSE : return wxT("SQLITE_MISUSE"); case SQLITE_NOLFS : return wxT("SQLITE_NOLFS"); case SQLITE_AUTH : return wxT("SQLITE_AUTH"); case SQLITE_FORMAT : return wxT("SQLITE_FORMAT"); case SQLITE_RANGE : return wxT("SQLITE_RANGE"); case SQLITE_NOTADB : return wxT("SQLITE_NOTADB"); case SQLITE_ROW : return wxT("SQLITE_ROW"); case SQLITE_DONE : return wxT("SQLITE_DONE"); // Extended error codes case SQLITE_IOERR_READ : return wxT("SQLITE_IOERR_READ"); case SQLITE_IOERR_SHORT_READ : return wxT("SQLITE_IOERR_SHORT_READ"); case SQLITE_IOERR_WRITE : return wxT("SQLITE_IOERR_WRITE"); case SQLITE_IOERR_FSYNC : return wxT("SQLITE_IOERR_FSYNC"); case SQLITE_IOERR_DIR_FSYNC : return wxT("SQLITE_IOERR_DIR_FSYNC"); case SQLITE_IOERR_TRUNCATE : return wxT("SQLITE_IOERR_TRUNCATE"); case SQLITE_IOERR_FSTAT : return wxT("SQLITE_IOERR_FSTAT"); case SQLITE_IOERR_UNLOCK : return wxT("SQLITE_IOERR_UNLOCK"); case SQLITE_IOERR_RDLOCK : return wxT("SQLITE_IOERR_RDLOCK"); case SQLITE_IOERR_DELETE : return wxT("SQLITE_IOERR_DELETE"); #if SQLITE_VERSION_NUMBER >= 3004000 case SQLITE_IOERR_BLOCKED : return wxT("SQLITE_IOERR_BLOCKED"); #endif #if SQLITE_VERSION_NUMBER >= 3005001 case SQLITE_IOERR_NOMEM : return wxT("SQLITE_IOERR_NOMEM"); #endif #if SQLITE_VERSION_NUMBER >= 3006000 case SQLITE_IOERR_ACCESS : return wxT("SQLITE_IOERR_ACCESS"); case SQLITE_IOERR_CHECKRESERVEDLOCK : return wxT("SQLITE_IOERR_CHECKRESERVEDLOCK"); #endif #if SQLITE_VERSION_NUMBER >= 3006002 case SQLITE_IOERR_LOCK : return wxT("SQLITE_IOERR_LOCK"); #endif #if SQLITE_VERSION_NUMBER >= 3006007 case SQLITE_IOERR_CLOSE : return wxT("SQLITE_IOERR_CLOSE"); case SQLITE_IOERR_DIR_CLOSE : return wxT("SQLITE_IOERR_DIR_CLOSE"); #endif #if SQLITE_VERSION_NUMBER >= 3007000 case SQLITE_IOERR_SHMOPEN : return wxT("SQLITE_IOERR_SHMOPEN"); case SQLITE_IOERR_SHMSIZE : return wxT("SQLITE_IOERR_SHMSIZE"); case SQLITE_IOERR_SHMLOCK : return wxT("SQLITE_IOERR_SHMLOCK"); case SQLITE_LOCKED_SHAREDCACHE : return wxT("SQLITE_LOCKED_SHAREDCACHE"); case SQLITE_BUSY_RECOVERY : return wxT("SQLITE_BUSY_RECOVERY"); case SQLITE_CANTOPEN_NOTEMPDIR : return wxT("SQLITE_CANTOPEN_NOTEMPDIR"); #endif #if SQLITE_VERSION_NUMBER >= 3007007 case SQLITE_CORRUPT_VTAB : return wxT("SQLITE_CORRUPT_VTAB"); case SQLITE_READONLY_RECOVERY : return wxT("SQLITE_READONLY_RECOVERY"); case SQLITE_READONLY_CANTLOCK : return wxT("SQLITE_READONLY_CANTLOCK"); #endif case WXSQLITE_ERROR : return wxT("WXSQLITE_ERROR"); default : return wxT("UNKNOWN_ERROR"); } #endif } wxSQLite3Exception::~wxSQLite3Exception() { } // ---------------------------------------------------------------------------- // wxSQLite3StatementBuffer: class providing a statement buffer // for use with the SQLite3 vmprintf function // ---------------------------------------------------------------------------- wxSQLite3StatementBuffer::wxSQLite3StatementBuffer() { m_buffer = 0; } wxSQLite3StatementBuffer::~wxSQLite3StatementBuffer() { Clear(); } void wxSQLite3StatementBuffer::Clear() { if (m_buffer) { sqlite3_free(m_buffer); m_buffer = 0; } } const char* wxSQLite3StatementBuffer::Format(const char* format, ...) { Clear(); va_list va; va_start(va, format); m_buffer = sqlite3_vmprintf(format, va); va_end(va); return m_buffer; } const char* wxSQLite3StatementBuffer::FormatV(const char* format, va_list va) { Clear(); m_buffer = sqlite3_vmprintf(format, va); return m_buffer; } // ---------------------------------------------------------------------------- // wxSQLite3ResultSet: class providing access to the result set of a query // ---------------------------------------------------------------------------- wxSQLite3ResultSet::wxSQLite3ResultSet() { m_db = NULL; m_stmt = NULL; m_eof = true; m_first = true; m_cols = 0; } wxSQLite3ResultSet::wxSQLite3ResultSet(const wxSQLite3ResultSet& resultSet) { m_db = resultSet.m_db; if (m_db != NULL) { m_db->IncrementRefCount(); } m_stmt = resultSet.m_stmt; if (m_stmt != NULL) { m_stmt->IncrementRefCount(); } m_eof = resultSet.m_eof; m_first = resultSet.m_first; m_cols = resultSet.m_cols; } wxSQLite3ResultSet::wxSQLite3ResultSet(wxSQLite3DatabaseReference* db, wxSQLite3StatementReference* stmt, bool eof, bool first) { m_db = db; if (m_db != NULL) { m_db->IncrementRefCount(); } m_stmt = stmt; if (m_stmt != NULL) { m_stmt->IncrementRefCount(); } CheckStmt(); m_eof = eof; m_first = first; m_cols = sqlite3_column_count(m_stmt->m_stmt); } wxSQLite3ResultSet::~wxSQLite3ResultSet() { if (m_stmt != NULL && m_stmt->DecrementRefCount() == 0) { if (m_stmt->m_isValid) { try { Finalize(m_db, m_stmt); } catch (...) { } } delete m_stmt; } if (m_db != NULL && m_db->DecrementRefCount() == 0) { if (m_db->m_isValid) { sqlite3_close(m_db->m_db); } delete m_db; } } wxSQLite3ResultSet& wxSQLite3ResultSet::operator=(const wxSQLite3ResultSet& resultSet) { if (this != &resultSet) { wxSQLite3DatabaseReference* dbPrev = m_db; wxSQLite3StatementReference* stmtPrev = m_stmt; m_db = resultSet.m_db; if (m_db != NULL) { m_db->IncrementRefCount(); } m_stmt = resultSet.m_stmt; if (m_stmt != NULL) { m_stmt->IncrementRefCount(); } m_eof = resultSet.m_eof; m_first = resultSet.m_first; m_cols = resultSet.m_cols; if (stmtPrev != NULL && stmtPrev->DecrementRefCount() == 0) { Finalize(dbPrev, stmtPrev); delete stmtPrev; } if (dbPrev != NULL && dbPrev->DecrementRefCount() == 0) { delete dbPrev; } } return *this; } int wxSQLite3ResultSet::GetColumnCount() { CheckStmt(); return m_cols; } wxString wxSQLite3ResultSet::GetAsString(int columnIndex) { CheckStmt(); if (columnIndex < 0 || columnIndex > m_cols-1) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_INVALID_INDEX); } const char* localValue = (const char*) sqlite3_column_text(m_stmt->m_stmt, columnIndex); return wxString::FromUTF8(localValue); } wxString wxSQLite3ResultSet::GetAsString(const wxString& columnName) { int columnIndex = FindColumnIndex(columnName); const char* localValue = (const char*) sqlite3_column_text(m_stmt->m_stmt, columnIndex); return wxString::FromUTF8(localValue); } int wxSQLite3ResultSet::GetInt(int columnIndex, int nullValue /* = 0 */) { if (GetColumnType(columnIndex) == SQLITE_NULL) { return nullValue; } else { return sqlite3_column_int(m_stmt->m_stmt, columnIndex); } } int wxSQLite3ResultSet::GetInt(const wxString& columnName, int nullValue /* = 0 */) { int columnIndex = FindColumnIndex(columnName); return GetInt(columnIndex, nullValue); } wxLongLong wxSQLite3ResultSet::GetInt64(int columnIndex, wxLongLong nullValue /* = 0 */) { if (GetColumnType(columnIndex) == SQLITE_NULL) { return nullValue; } else { return wxLongLong(sqlite3_column_int64(m_stmt->m_stmt, columnIndex)); } } wxLongLong wxSQLite3ResultSet::GetInt64(const wxString& columnName, wxLongLong nullValue /* = 0 */) { int columnIndex = FindColumnIndex(columnName); return GetInt64(columnIndex, nullValue); } double wxSQLite3ResultSet::GetDouble(int columnIndex, double nullValue /* = 0.0 */) { if (GetColumnType(columnIndex) == SQLITE_NULL) { return nullValue; } else { return sqlite3_column_double(m_stmt->m_stmt, columnIndex); } } double wxSQLite3ResultSet::GetDouble(const wxString& columnName, double nullValue /* = 0.0 */) { int columnIndex = FindColumnIndex(columnName); return GetDouble(columnIndex, nullValue); } wxString wxSQLite3ResultSet::GetString(int columnIndex, const wxString& nullValue /* = wxEmptyString */) { if (GetColumnType(columnIndex) == SQLITE_NULL) { return nullValue; } else { const char* localValue = (const char*) sqlite3_column_text(m_stmt->m_stmt, columnIndex); return wxString::FromUTF8(localValue); } } wxString wxSQLite3ResultSet::GetString(const wxString& columnName, const wxString& nullValue /* = wxEmptyString */) { int columnIndex = FindColumnIndex(columnName); return GetString(columnIndex, nullValue); } const unsigned char* wxSQLite3ResultSet::GetBlob(int columnIndex, int& len) { CheckStmt(); if (columnIndex < 0 || columnIndex > m_cols-1) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_INVALID_INDEX); } len = sqlite3_column_bytes(m_stmt->m_stmt, columnIndex); return (const unsigned char*) sqlite3_column_blob(m_stmt->m_stmt, columnIndex); } const unsigned char* wxSQLite3ResultSet::GetBlob(const wxString& columnName, int& len) { int columnIndex = FindColumnIndex(columnName); return GetBlob(columnIndex, len); } wxMemoryBuffer& wxSQLite3ResultSet::GetBlob(int columnIndex, wxMemoryBuffer& buffer) { CheckStmt(); if (columnIndex < 0 || columnIndex > m_cols-1) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_INVALID_INDEX); } int len = sqlite3_column_bytes(m_stmt->m_stmt, columnIndex); const void* blob = sqlite3_column_blob(m_stmt->m_stmt, columnIndex); buffer.AppendData((void*) blob, (size_t) len); return buffer; } wxMemoryBuffer& wxSQLite3ResultSet::GetBlob(const wxString& columnName, wxMemoryBuffer& buffer) { int columnIndex = FindColumnIndex(columnName); return GetBlob(columnIndex, buffer); } wxDateTime wxSQLite3ResultSet::GetDate(int columnIndex) { if (GetColumnType(columnIndex) == SQLITE_NULL) { return wxInvalidDateTime; } else { wxDateTime date; const wxChar* result = date.ParseDate(GetString(columnIndex)); if (result != NULL) { return date; } else { return wxInvalidDateTime; } } } wxDateTime wxSQLite3ResultSet::GetDate(const wxString& columnName) { int columnIndex = FindColumnIndex(columnName); return GetDate(columnIndex); } wxDateTime wxSQLite3ResultSet::GetTime(int columnIndex) { if (GetColumnType(columnIndex) == SQLITE_NULL) { return wxInvalidDateTime; } else { wxDateTime date; const wxChar* result = date.ParseTime(GetString(columnIndex)); if (result != NULL) { return date; } else { return wxInvalidDateTime; } } } wxDateTime wxSQLite3ResultSet::GetTime(const wxString& columnName) { int columnIndex = FindColumnIndex(columnName); return GetTime(columnIndex); } wxDateTime wxSQLite3ResultSet::GetDateTime(int columnIndex) { if (GetColumnType(columnIndex) == SQLITE_NULL) { return wxInvalidDateTime; } else { wxDateTime date; const wxChar* result = date.ParseDateTime(GetString(columnIndex)); if (result != NULL) { date.SetMillisecond(0); return date; } else { return wxInvalidDateTime; } } } wxDateTime wxSQLite3ResultSet::GetDateTime(const wxString& columnName) { int columnIndex = FindColumnIndex(columnName); return GetDateTime(columnIndex); } wxDateTime wxSQLite3ResultSet::GetTimestamp(int columnIndex) { if (GetColumnType(columnIndex) == SQLITE_NULL) { return wxInvalidDateTime; } else { wxDateTime date; const wxChar* result = date.ParseDateTime(GetString(columnIndex)); if (result != NULL) { return date; } else { return wxInvalidDateTime; } } } wxDateTime wxSQLite3ResultSet::GetTimestamp(const wxString& columnName) { int columnIndex = FindColumnIndex(columnName); return GetTimestamp(columnIndex); } wxDateTime wxSQLite3ResultSet::GetNumericDateTime(int columnIndex) { if (GetColumnType(columnIndex) == SQLITE_NULL) { return wxInvalidDateTime; } else { wxLongLong value = GetInt64(columnIndex); return wxDateTime(value); } } wxDateTime wxSQLite3ResultSet::GetNumericDateTime(const wxString& columnName) { int columnIndex = FindColumnIndex(columnName); return GetNumericDateTime(columnIndex); } wxDateTime wxSQLite3ResultSet::GetUnixDateTime(int columnIndex) { if (GetColumnType(columnIndex) == SQLITE_NULL) { return wxInvalidDateTime; } else { wxLongLong value = GetInt64(columnIndex); return wxDateTime((time_t) value.GetValue()); } } wxDateTime wxSQLite3ResultSet::GetUnixDateTime(const wxString& columnName) { int columnIndex = FindColumnIndex(columnName); return GetUnixDateTime(columnIndex); } wxDateTime wxSQLite3ResultSet::GetJulianDayNumber(int columnIndex) { if (GetColumnType(columnIndex) == SQLITE_NULL) { return wxInvalidDateTime; } else { double value = GetDouble(columnIndex); return wxDateTime(value); } } wxDateTime wxSQLite3ResultSet::GetJulianDayNumber(const wxString& columnName) { int columnIndex = FindColumnIndex(columnName); return GetJulianDayNumber(columnIndex); } bool wxSQLite3ResultSet::GetBool(int columnIndex) { return GetInt(columnIndex) != 0; } wxDateTime wxSQLite3ResultSet::GetAutomaticDateTime(int columnIndex, bool milliSeconds) { wxDateTime result; int columnType = GetColumnType(columnIndex); switch (columnType) { case SQLITE3_TEXT: result = GetDateTime(columnIndex); break; case SQLITE_INTEGER: if (milliSeconds) { wxLongLong value = GetInt64(columnIndex); result = wxDateTime(value); } else { time_t value = GetInt64(columnIndex).GetValue(); result = wxDateTime(value); } break; case SQLITE_FLOAT: result = GetJulianDayNumber(columnIndex); break; case SQLITE_NULL: default: result = wxInvalidDateTime; break; } return result; } wxDateTime wxSQLite3ResultSet::GetAutomaticDateTime(const wxString& columnName, bool milliSeconds) { int columnIndex = FindColumnIndex(columnName); return GetAutomaticDateTime(columnIndex, milliSeconds); } bool wxSQLite3ResultSet::GetBool(const wxString& columnName) { int columnIndex = FindColumnIndex(columnName); return GetBool(columnIndex); } bool wxSQLite3ResultSet::IsNull(int columnIndex) { return (GetColumnType(columnIndex) == SQLITE_NULL); } bool wxSQLite3ResultSet::IsNull(const wxString& columnName) { int columnIndex = FindColumnIndex(columnName); return (GetColumnType(columnIndex) == SQLITE_NULL); } int wxSQLite3ResultSet::FindColumnIndex(const wxString& columnName) { CheckStmt(); wxCharBuffer strColumnName = columnName.ToUTF8(); const char* localColumnName = strColumnName; if (columnName.Len() > 0) { for (int columnIndex = 0; columnIndex < m_cols; columnIndex++) { const char* temp = sqlite3_column_name(m_stmt->m_stmt, columnIndex); if (strcmp(localColumnName, temp) == 0) { return columnIndex; } } } throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_INVALID_INDEX); } wxString wxSQLite3ResultSet::GetColumnName(int columnIndex) { CheckStmt(); if (columnIndex < 0 || columnIndex > m_cols-1) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_INVALID_INDEX); } const char* localValue = sqlite3_column_name(m_stmt->m_stmt, columnIndex); return wxString::FromUTF8(localValue); } wxString wxSQLite3ResultSet::GetDeclaredColumnType(int columnIndex) { CheckStmt(); if (columnIndex < 0 || columnIndex > m_cols-1) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_INVALID_INDEX); } const char* localValue = sqlite3_column_decltype(m_stmt->m_stmt, columnIndex); return wxString::FromUTF8(localValue); } int wxSQLite3ResultSet::GetColumnType(int columnIndex) { CheckStmt(); if (columnIndex < 0 || columnIndex > m_cols-1) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_INVALID_INDEX); } return sqlite3_column_type(m_stmt->m_stmt, columnIndex); } bool wxSQLite3ResultSet::Eof() { CheckStmt(); return m_eof; } bool wxSQLite3ResultSet::CursorMoved() { CheckStmt(); return !m_first; } bool wxSQLite3ResultSet::NextRow() { CheckStmt(); int rc; if (m_first) { m_first = false; rc = (m_eof) ? SQLITE_DONE : SQLITE_ROW; } else { rc = sqlite3_step(m_stmt->m_stmt); } if (rc == SQLITE_DONE) // no more rows { m_eof = true; return false; } else if (rc == SQLITE_ROW) // more rows { return true; } else { rc = sqlite3_finalize(m_stmt->m_stmt); m_stmt->Invalidate(); const char* localError = sqlite3_errmsg(m_db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } } void wxSQLite3ResultSet::Finalize() { Finalize(m_db, m_stmt); if (m_stmt != NULL && m_stmt->DecrementRefCount() == 0) { delete m_stmt; } m_stmt = NULL; if (m_db != NULL && m_db->DecrementRefCount() == 0) { if (m_db->m_isValid) { sqlite3_close(m_db->m_db); } delete m_db; } m_db = NULL; } void wxSQLite3ResultSet::Finalize(wxSQLite3DatabaseReference* db,wxSQLite3StatementReference* stmt) { if (stmt != NULL && stmt->m_isValid) { int rc = sqlite3_finalize(stmt->m_stmt); stmt->Invalidate(); if (rc != SQLITE_OK) { if (db != NULL && db->m_isValid) { const char* localError = sqlite3_errmsg(db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } else { throw wxSQLite3Exception(rc, wxERRMSG_FINALIZE_FAILED); } } } } wxString wxSQLite3ResultSet::GetSQL() { wxString sqlString = wxEmptyString; #if SQLITE_VERSION_NUMBER >= 3005003 CheckStmt(); const char* sqlLocal = sqlite3_sql(m_stmt->m_stmt); if (sqlLocal != NULL) sqlString = wxString::FromUTF8(sqlLocal); #endif return sqlString; } bool wxSQLite3ResultSet::IsOk() { return (m_db != NULL) && (m_db->m_isValid) && (m_stmt != NULL) && (m_stmt->m_isValid); } void wxSQLite3ResultSet::CheckStmt() { if (m_stmt == NULL || m_stmt->m_stmt == NULL || !m_stmt->m_isValid) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOSTMT); } } wxString wxSQLite3ResultSet::GetDatabaseName(int columnIndex) { #if WXSQLITE3_HAVE_METADATA CheckStmt(); if (columnIndex < 0 || columnIndex > m_cols-1) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_INVALID_INDEX); } const char* localValue = sqlite3_column_database_name(m_stmt->m_stmt, columnIndex); if (localValue != NULL) return wxString::FromUTF8(localValue); else return wxEmptyString; #else wxUnusedVar(columnIndex); throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOMETADATA); #endif } wxString wxSQLite3ResultSet::GetTableName(int columnIndex) { #if WXSQLITE3_HAVE_METADATA CheckStmt(); if (columnIndex < 0 || columnIndex > m_cols-1) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_INVALID_INDEX); } const char* localValue = sqlite3_column_table_name(m_stmt->m_stmt, columnIndex); if (localValue != NULL) return wxString::FromUTF8(localValue); else return wxEmptyString; #else wxUnusedVar(columnIndex); throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOMETADATA); #endif } wxString wxSQLite3ResultSet::GetOriginName(int columnIndex) { #if WXSQLITE3_HAVE_METADATA CheckStmt(); if (columnIndex < 0 || columnIndex > m_cols-1) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_INVALID_INDEX); } const char* localValue = sqlite3_column_origin_name(m_stmt->m_stmt, columnIndex); if (localValue != NULL) return wxString::FromUTF8(localValue); else return wxEmptyString; #else wxUnusedVar(columnIndex); throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOMETADATA); #endif } // ---------------------------------------------------------------------------- // wxSQLite3Table: class holding the complete result set of a query // ---------------------------------------------------------------------------- wxSQLite3Table::wxSQLite3Table() { m_results = 0; m_rows = 0; m_cols = 0; m_currentRow = 0; } wxSQLite3Table::wxSQLite3Table(const wxSQLite3Table& table) { m_results = table.m_results; // Only one object can own the results const_cast(table).m_results = 0; m_rows = table.m_rows; m_cols = table.m_cols; m_currentRow = table.m_currentRow; } wxSQLite3Table::wxSQLite3Table(char** results, int rows, int cols) { m_results = results; m_rows = rows; m_cols = cols; m_currentRow = 0; } wxSQLite3Table::~wxSQLite3Table() { try { Finalize(); } catch (...) { } } wxSQLite3Table& wxSQLite3Table::operator=(const wxSQLite3Table& table) { if (this != &table) { try { Finalize(); } catch (...) { } m_results = table.m_results; // Only one object can own the results const_cast(table).m_results = 0; m_rows = table.m_rows; m_cols = table.m_cols; m_currentRow = table.m_currentRow; } return *this; } void wxSQLite3Table::Finalize() { if (m_results) { sqlite3_free_table(m_results); m_results = 0; } } int wxSQLite3Table::GetColumnCount() { CheckResults(); return m_cols; } int wxSQLite3Table::GetRowCount() { CheckResults(); return m_rows; } int wxSQLite3Table::FindColumnIndex(const wxString& columnName) { CheckResults(); wxCharBuffer strColumnName = columnName.ToUTF8(); const char* localColumnName = strColumnName; if (columnName.Len() > 0) { for (int columnIndex = 0; columnIndex < m_cols; columnIndex++) { if (strcmp(localColumnName, m_results[columnIndex]) == 0) { return columnIndex; } } } throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_INVALID_NAME); } wxString wxSQLite3Table::GetAsString(int columnIndex) { if (columnIndex < 0 || columnIndex > m_cols-1) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_INVALID_INDEX); } int nIndex = (m_currentRow*m_cols) + m_cols + columnIndex; const char* localValue = m_results[nIndex]; return wxString::FromUTF8(localValue); } wxString wxSQLite3Table::GetAsString(const wxString& columnName) { int index = FindColumnIndex(columnName); return GetAsString(index); } int wxSQLite3Table::GetInt(int columnIndex, int nullValue /* = 0 */) { if (IsNull(columnIndex)) { return nullValue; } else { long value = nullValue; GetAsString(columnIndex).ToLong(&value); return (int) value; } } int wxSQLite3Table::GetInt(const wxString& columnName, int nullValue /* = 0 */) { if (IsNull(columnName)) { return nullValue; } else { long value = nullValue; GetAsString(columnName).ToLong(&value); return (int) value; } } wxLongLong wxSQLite3Table::GetInt64(int columnIndex, wxLongLong nullValue /* = 0 */) { if (IsNull(columnIndex)) { return nullValue; } else { return ConvertStringToLongLong(GetAsString(columnIndex), nullValue); } } wxLongLong wxSQLite3Table::GetInt64(const wxString& columnName, wxLongLong nullValue /* = 0 */) { if (IsNull(columnName)) { return nullValue; } else { return ConvertStringToLongLong(GetAsString(columnName), nullValue); } } // Since SQLite uses internally a locale independent string representation // of double values, we need to provide our own conversion procedure using // always a point as the decimal separator. // The following code duplicates a SQLite utility function with minor modifications. static double wxSQLite3AtoF(const char *z) { int sign = 1; long double v1 = 0.0; int nSignificant = 0; while (isspace(*(unsigned char*)z)) { ++z; } if (*z == '-') { sign = -1; ++z; } else if (*z == '+') { ++z; } while (*z == '0') { ++z; } while (isdigit(*(unsigned char*)z)) { v1 = v1*10.0 + (*z - '0'); ++z; ++nSignificant; } if (*z == '.') { long double divisor = 1.0; ++z; if (nSignificant == 0) { while (*z == '0') { divisor *= 10.0; ++z; } } while (isdigit(*(unsigned char*)z)) { if (nSignificant < 18) { v1 = v1*10.0 + (*z - '0'); divisor *= 10.0; ++nSignificant; } ++z; } v1 /= divisor; } if (*z=='e' || *z=='E') { int esign = 1; int eval = 0; long double scale = 1.0; ++z; if (*z == '-') { esign = -1; ++z; } else if (*z == '+') { ++z; } while (isdigit(*(unsigned char*)z)) { eval = eval*10 + *z - '0'; ++z; } while (eval >= 64) { scale *= 1.0e+64; eval -= 64; } while (eval >= 16) { scale *= 1.0e+16; eval -= 16; } while (eval >= 4) { scale *= 1.0e+4; eval -= 4; } while (eval >= 1) { scale *= 1.0e+1; eval -= 1; } if (esign < 0) { v1 /= scale; } else { v1 *= scale; } } return (double) ((sign < 0) ? -v1 : v1); } double wxSQLite3Table::GetDouble(int columnIndex, double nullValue /* = 0.0 */) { if (IsNull(columnIndex)) { return nullValue; } else { if (columnIndex < 0 || columnIndex > m_cols-1) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_INVALID_INDEX); } int nIndex = (m_currentRow*m_cols) + m_cols + columnIndex; return wxSQLite3AtoF(m_results[nIndex]); } } double wxSQLite3Table::GetDouble(const wxString& columnName, double nullValue /* = 0.0 */) { int index = FindColumnIndex(columnName); return GetDouble(index, nullValue); } wxString wxSQLite3Table::GetString(int columnIndex, const wxString& nullValue /* = wxEmptyString */) { if (IsNull(columnIndex)) { return nullValue; } else { return GetAsString(columnIndex); } } wxString wxSQLite3Table::GetString(const wxString& columnName, const wxString& nullValue /* = wxEmptyString */) { if (IsNull(columnName)) { return nullValue; } else { return GetAsString(columnName); } } wxDateTime wxSQLite3Table::GetDate(int columnIndex) { wxDateTime date; const wxChar* result = date.ParseDate(GetString(columnIndex)); if (result != NULL) { return date; } else { return wxInvalidDateTime; } } wxDateTime wxSQLite3Table::GetDate(const wxString& columnName) { int columnIndex = FindColumnIndex(columnName); return GetDate(columnIndex); } wxDateTime wxSQLite3Table::GetTime(int columnIndex) { wxDateTime date; const wxChar* result = date.ParseTime(GetString(columnIndex)); if (result != NULL) { return date; } else { return wxInvalidDateTime; } } wxDateTime wxSQLite3Table::GetTime(const wxString& columnName) { int columnIndex = FindColumnIndex(columnName); return GetTime(columnIndex); } wxDateTime wxSQLite3Table::GetDateTime(int columnIndex) { wxDateTime date; const wxChar* result = date.ParseDateTime(GetString(columnIndex)); if (result != NULL) { return date; } else { return wxInvalidDateTime; } } wxDateTime wxSQLite3Table::GetDateTime(const wxString& columnName) { int columnIndex = FindColumnIndex(columnName); return GetDateTime(columnIndex); } bool wxSQLite3Table::GetBool(int columnIndex) { return GetInt(columnIndex) != 0; } bool wxSQLite3Table::GetBool(const wxString& columnName) { int columnIndex = FindColumnIndex(columnName); return GetBool(columnIndex); } bool wxSQLite3Table::IsNull(int columnIndex) { CheckResults(); if (columnIndex < 0 || columnIndex > m_cols-1) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_INVALID_INDEX); } int index = (m_currentRow*m_cols) + m_cols + columnIndex; const char* localValue = m_results[index]; return (localValue == 0); } bool wxSQLite3Table::IsNull(const wxString& columnName) { int index = FindColumnIndex(columnName); return IsNull(index); } wxString wxSQLite3Table::GetColumnName(int columnIndex) { CheckResults(); if (columnIndex < 0 || columnIndex > m_cols-1) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_INVALID_INDEX); } const char* localValue = m_results[columnIndex]; return wxString::FromUTF8(localValue); } void wxSQLite3Table::SetRow(int row) { CheckResults(); if (row < 0 || row > m_rows-1) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_INVALID_ROW); } m_currentRow = row; } bool wxSQLite3Table::IsOk() { return (m_results != 0); } void wxSQLite3Table::CheckResults() { if (m_results == 0) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NORESULT); } } // ---------------------------------------------------------------------------- // wxSQLite3Statement: class holding a prepared statement // ---------------------------------------------------------------------------- wxSQLite3Statement::wxSQLite3Statement() { m_db = 0; m_stmt = 0; } wxSQLite3Statement::wxSQLite3Statement(const wxSQLite3Statement& statement) { m_db = statement.m_db; if (m_db != NULL) { m_db->IncrementRefCount(); } m_stmt = statement.m_stmt; if (m_stmt != NULL) { m_stmt->IncrementRefCount(); } } wxSQLite3Statement::wxSQLite3Statement(wxSQLite3DatabaseReference* db, wxSQLite3StatementReference* stmt) { m_db = db; if (m_db != NULL) { m_db->IncrementRefCount(); } m_stmt = stmt; if (m_stmt != NULL) { m_stmt->IncrementRefCount(); } } wxSQLite3Statement::~wxSQLite3Statement() { if (m_stmt != NULL && m_stmt->DecrementRefCount() == 0) { if (m_stmt->m_isValid) { try { Finalize(m_db, m_stmt); } catch (...) { } } delete m_stmt; } if (m_db != NULL && m_db->DecrementRefCount() == 0) { if (m_db->m_isValid) { sqlite3_close(m_db->m_db); } delete m_db; } } wxSQLite3Statement& wxSQLite3Statement::operator=(const wxSQLite3Statement& statement) { if (this != &statement) { wxSQLite3DatabaseReference* dbPrev = m_db; wxSQLite3StatementReference* stmtPrev = m_stmt; m_db = statement.m_db; if (m_db != NULL) { m_db->IncrementRefCount(); } m_stmt = statement.m_stmt; if (m_stmt != NULL) { m_stmt->IncrementRefCount(); } if (stmtPrev != NULL && stmtPrev->DecrementRefCount() == 0) { Finalize(dbPrev, stmtPrev); delete stmtPrev; } if (dbPrev != NULL && dbPrev->DecrementRefCount() == 0) { delete dbPrev; } } return *this; } int wxSQLite3Statement::ExecuteUpdate() { CheckDatabase(); CheckStmt(); const char* localError=0; int rc = sqlite3_step(m_stmt->m_stmt); if (rc == SQLITE_DONE) { int rowsChanged = sqlite3_changes(m_db->m_db); rc = sqlite3_reset(m_stmt->m_stmt); if (rc != SQLITE_OK) { localError = sqlite3_errmsg(m_db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } return rowsChanged; } else { rc = sqlite3_reset(m_stmt->m_stmt); localError = sqlite3_errmsg(m_db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } } wxSQLite3ResultSet wxSQLite3Statement::ExecuteQuery() { CheckDatabase(); CheckStmt(); int rc = sqlite3_step(m_stmt->m_stmt); if (rc == SQLITE_DONE) // no more rows { return wxSQLite3ResultSet(m_db, m_stmt, true/*eof*/, true/*first*/); } else if (rc == SQLITE_ROW) // one or more rows { return wxSQLite3ResultSet(m_db, m_stmt, false/*eof*/, true/*first*/); } else { rc = sqlite3_reset(m_stmt->m_stmt); const char* localError = sqlite3_errmsg(m_db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } } int wxSQLite3Statement::ExecuteScalar() { wxSQLite3ResultSet resultSet = ExecuteQuery(); if (resultSet.Eof() || resultSet.GetColumnCount() < 1) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_INVALID_QUERY); } long value = 0; resultSet.GetAsString(0).ToLong(&value); return (int) value; } int wxSQLite3Statement::GetParamCount() { CheckStmt(); return sqlite3_bind_parameter_count(m_stmt->m_stmt); } int wxSQLite3Statement::GetParamIndex(const wxString& paramName) { CheckStmt(); wxCharBuffer strParamName = paramName.ToUTF8(); const char* localParamName = strParamName; return sqlite3_bind_parameter_index(m_stmt->m_stmt, localParamName); } wxString wxSQLite3Statement::GetParamName(int paramIndex) { CheckStmt(); const char* localParamName = sqlite3_bind_parameter_name(m_stmt->m_stmt, paramIndex); return wxString::FromUTF8(localParamName); } void wxSQLite3Statement::Bind(int paramIndex, const wxString& stringValue) { CheckStmt(); wxCharBuffer strStringValue = stringValue.ToUTF8(); const char* localStringValue = strStringValue; int rc = sqlite3_bind_text(m_stmt->m_stmt, paramIndex, localStringValue, -1, SQLITE_TRANSIENT); if (rc != SQLITE_OK) { throw wxSQLite3Exception(rc, wxERRMSG_BIND_STR); } } void wxSQLite3Statement::Bind(int paramIndex, int intValue) { CheckStmt(); int rc = sqlite3_bind_int(m_stmt->m_stmt, paramIndex, intValue); if (rc != SQLITE_OK) { throw wxSQLite3Exception(rc, wxERRMSG_BIND_INT); } } void wxSQLite3Statement::Bind(int paramIndex, wxLongLong int64Value) { CheckStmt(); int rc = sqlite3_bind_int64(m_stmt->m_stmt, paramIndex, int64Value.GetValue()); if (rc != SQLITE_OK) { throw wxSQLite3Exception(rc, wxERRMSG_BIND_INT64); } } void wxSQLite3Statement::Bind(int paramIndex, double doubleValue) { CheckStmt(); int rc = sqlite3_bind_double(m_stmt->m_stmt, paramIndex, doubleValue); if (rc != SQLITE_OK) { throw wxSQLite3Exception(rc, wxERRMSG_BIND_DBL); } } void wxSQLite3Statement::Bind(int paramIndex, const char* charValue) { CheckStmt(); int rc = sqlite3_bind_text(m_stmt->m_stmt, paramIndex, charValue, -1, SQLITE_TRANSIENT); if (rc != SQLITE_OK) { throw wxSQLite3Exception(rc, wxERRMSG_BIND_STR); } } void wxSQLite3Statement::Bind(int paramIndex, const unsigned char* blobValue, int blobLen) { CheckStmt(); int rc = sqlite3_bind_blob(m_stmt->m_stmt, paramIndex, (const void*)blobValue, blobLen, SQLITE_TRANSIENT); if (rc != SQLITE_OK) { throw wxSQLite3Exception(rc, wxERRMSG_BIND_BLOB); } } void wxSQLite3Statement::Bind(int paramIndex, const wxMemoryBuffer& blobValue) { CheckStmt(); int blobLen = (int) blobValue.GetDataLen(); int rc = sqlite3_bind_blob(m_stmt->m_stmt, paramIndex, (const void*)blobValue.GetData(), blobLen, SQLITE_TRANSIENT); if (rc != SQLITE_OK) { throw wxSQLite3Exception(rc, wxERRMSG_BIND_BLOB); } } void wxSQLite3Statement::BindDate(int paramIndex, const wxDateTime& date) { if (date.IsValid()) { Bind(paramIndex,date.FormatISODate()); } else { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_BIND_DATETIME); } } void wxSQLite3Statement::BindTime(int paramIndex, const wxDateTime& time) { if (time.IsValid()) { Bind(paramIndex,time.FormatISOTime()); } else { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_BIND_DATETIME); } } void wxSQLite3Statement::BindDateTime(int paramIndex, const wxDateTime& datetime) { if (datetime.IsValid()) { Bind(paramIndex,datetime.Format(wxT("%Y-%m-%d %H:%M:%S"))); } else { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_BIND_DATETIME); } } void wxSQLite3Statement::BindTimestamp(int paramIndex, const wxDateTime& timestamp) { if (timestamp.IsValid()) { Bind(paramIndex,timestamp.Format(wxT("%Y-%m-%d %H:%M:%S.%l"))); } else { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_BIND_DATETIME); } } void wxSQLite3Statement::BindNumericDateTime(int paramIndex, const wxDateTime& datetime) { if (datetime.IsValid()) { Bind(paramIndex, datetime.GetValue()); } else { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_BIND_DATETIME); } } void wxSQLite3Statement::BindUnixDateTime(int paramIndex, const wxDateTime& datetime) { if (datetime.IsValid()) { wxLongLong ticks = datetime.GetTicks(); Bind(paramIndex, ticks); } else { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_BIND_DATETIME); } } void wxSQLite3Statement::BindJulianDayNumber(int paramIndex, const wxDateTime& datetime) { if (datetime.IsValid()) { Bind(paramIndex, datetime.GetJulianDayNumber()); } else { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_BIND_DATETIME); } } void wxSQLite3Statement::BindBool(int paramIndex, bool value) { Bind(paramIndex, value ? 1 : 0); } void wxSQLite3Statement::BindNull(int paramIndex) { CheckStmt(); int rc = sqlite3_bind_null(m_stmt->m_stmt, paramIndex); if (rc != SQLITE_OK) { throw wxSQLite3Exception(rc, wxERRMSG_BIND_NULL); } } void wxSQLite3Statement::BindZeroBlob(int paramIndex, int blobSize) { #if SQLITE_VERSION_NUMBER >= 3004000 CheckStmt(); int rc = sqlite3_bind_zeroblob(m_stmt->m_stmt, paramIndex, blobSize); if (rc != SQLITE_OK) { throw wxSQLite3Exception(rc, wxERRMSG_BIND_ZEROBLOB); } #else wxUnusedVar(paramIndex); wxUnusedVar(blobSize); throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOINCBLOB); #endif } void wxSQLite3Statement::ClearBindings() { CheckStmt(); #if 0 // missing in SQLite DLL int rc = sqlite3_clear_bindings(m_stmt->m_stmt); if (rc != SQLITE_OK) { throw wxSQLite3Exception(rc, wxERRMSG_BIND_CLEAR); } #else for (int paramIndex = 1; paramIndex <= GetParamCount(); paramIndex++) { BindNull(paramIndex); } #endif } wxString wxSQLite3Statement::GetSQL() { wxString sqlString = wxEmptyString; #if SQLITE_VERSION_NUMBER >= 3005003 CheckStmt(); const char* sqlLocal = sqlite3_sql(m_stmt->m_stmt); if (sqlLocal != NULL) sqlString = wxString::FromUTF8(sqlLocal); #endif return sqlString; } void wxSQLite3Statement::Reset() { if (m_stmt != NULL && m_stmt->m_isValid) { int rc = sqlite3_reset(m_stmt->m_stmt); if (rc != SQLITE_OK) { const char* localError = sqlite3_errmsg(m_db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } } } bool wxSQLite3Statement::IsReadOnly() { #if SQLITE_VERSION_NUMBER >= 3007004 CheckStmt(); return sqlite3_stmt_readonly(m_stmt->m_stmt) != 0; #else return false; #endif } void wxSQLite3Statement::Finalize() { Finalize(m_db, m_stmt); if (m_stmt != NULL && m_stmt->DecrementRefCount() == 0) { delete m_stmt; } m_stmt = NULL; if (m_db != NULL && m_db->DecrementRefCount() == 0) { if (m_db->m_isValid) { sqlite3_close(m_db->m_db); } delete m_db; } m_db = NULL; } void wxSQLite3Statement::Finalize(wxSQLite3DatabaseReference* db,wxSQLite3StatementReference* stmt) { if (stmt != NULL && stmt->m_isValid) { int rc = sqlite3_finalize(stmt->m_stmt); stmt->Invalidate(); if (rc != SQLITE_OK) { if (db != NULL && db->m_isValid) { const char* localError = sqlite3_errmsg(db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } else { throw wxSQLite3Exception(rc, wxERRMSG_FINALIZE_FAILED); } } } } bool wxSQLite3Statement::IsOk() { return (m_db != 0) && (m_stmt != 0); } bool wxSQLite3Statement::IsBusy() { #if SQLITE_VERSION_NUMBER >= 3007010 CheckStmt(); int rc = sqlite3_stmt_busy(m_stmt->m_stmt); return (rc != 0); #else return false; #endif } int wxSQLite3Statement::Status(wxSQLite3StatementStatus opCode, bool resetFlag) { int count = 0; #if SQLITE_VERSION_NUMBER >= 3007000 CheckStmt(); count = sqlite3_stmt_status(m_stmt->m_stmt, (int) opCode, (resetFlag) ? 1 : 0 ); #endif return count; } void wxSQLite3Statement::CheckDatabase() { if (m_db == NULL || m_db->m_db == NULL || !m_db->m_isValid) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NODB); } } void wxSQLite3Statement::CheckStmt() { if (m_stmt == NULL || m_stmt->m_stmt == NULL || !m_stmt->m_isValid) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOSTMT); } } // wxSQLite3Blob::wxSQLite3Blob() { m_db = NULL; m_blob = NULL; m_writable = false; } wxSQLite3Blob::wxSQLite3Blob(const wxSQLite3Blob& blob) { m_db = blob.m_db; if (m_db != NULL) { m_db->IncrementRefCount(); } m_blob = blob.m_blob; if (m_blob != NULL) { m_blob->IncrementRefCount(); } m_writable = blob.m_writable; } wxSQLite3Blob& wxSQLite3Blob::operator=(const wxSQLite3Blob& blob) { if (this != &blob) { wxSQLite3DatabaseReference* dbPrev = m_db; wxSQLite3BlobReference* blobPrev = m_blob; m_db = blob.m_db; if (m_db != NULL) { m_db->IncrementRefCount(); } m_blob = blob.m_blob; if (m_blob != NULL) { m_blob->IncrementRefCount(); } m_writable = blob.m_writable; if (blobPrev != NULL && blobPrev->DecrementRefCount() == 0) { Finalize(dbPrev, blobPrev); delete blobPrev; } if (dbPrev != NULL && dbPrev->DecrementRefCount() == 0) { delete dbPrev; } } return *this; } wxSQLite3Blob::wxSQLite3Blob(wxSQLite3DatabaseReference* db, wxSQLite3BlobReference* blob, bool writable) { m_db = db; if (m_db != NULL) { m_db->IncrementRefCount(); } m_blob = blob; if (m_blob != NULL) { m_blob->IncrementRefCount(); } m_writable = writable; } wxSQLite3Blob::~wxSQLite3Blob() { if (m_blob != NULL && m_blob->DecrementRefCount() == 0) { Finalize(m_db, m_blob); delete m_blob; } if (m_db != NULL && m_db->DecrementRefCount() == 0) { if (m_db->m_isValid) { sqlite3_close(m_db->m_db); } delete m_db; } } wxMemoryBuffer& wxSQLite3Blob::Read(wxMemoryBuffer& blobValue, int length, int offset) { #if SQLITE_VERSION_NUMBER >= 3004000 CheckBlob(); char* localBuffer = (char*) blobValue.GetAppendBuf((size_t) length); int rc = sqlite3_blob_read(m_blob->m_blob, localBuffer, length, offset); if (rc != SQLITE_OK) { const char* localError = sqlite3_errmsg(m_db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } blobValue.UngetAppendBuf((size_t) length); #else wxUnusedVar(blobValue); wxUnusedVar(length); wxUnusedVar(offset); throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOINCBLOB); #endif return blobValue; } void wxSQLite3Blob::Write(const wxMemoryBuffer& blobValue, int offset) { #if SQLITE_VERSION_NUMBER >= 3004000 CheckBlob(); if (m_writable) { int blobLen = (int) blobValue.GetDataLen(); int rc = sqlite3_blob_write(m_blob->m_blob, (const void*) blobValue.GetData(), blobLen, offset); if (rc != SQLITE_OK) { const char* localError = sqlite3_errmsg(m_db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } } else { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_INVALID_BLOB); } #else wxUnusedVar(blobValue); wxUnusedVar(offset); throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOINCBLOB); #endif } bool wxSQLite3Blob::IsOk() { return (m_blob != NULL && m_blob->m_isValid); } bool wxSQLite3Blob::IsReadOnly() { return !m_writable; } int wxSQLite3Blob::GetSize() { #if SQLITE_VERSION_NUMBER >= 3004000 CheckBlob(); return sqlite3_blob_bytes(m_blob->m_blob); #else throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOINCBLOB); return 0; #endif } void wxSQLite3Blob::Rebind(wxLongLong rowid) { #if SQLITE_VERSION_NUMBER >= 3007004 CheckBlob(); int rc = sqlite3_blob_reopen(m_blob->m_blob, rowid.GetValue()); if (rc != SQLITE_OK) { const char* localError = sqlite3_errmsg(m_db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } #else wxUnusedVar(rowid); throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOBLOBREBIND); #endif } void wxSQLite3Blob::Finalize() { Finalize(m_db, m_blob); } void wxSQLite3Blob::Finalize(wxSQLite3DatabaseReference* db, wxSQLite3BlobReference* blob) { #if SQLITE_VERSION_NUMBER >= 3004000 if (blob != NULL && blob->m_isValid) { int rc = sqlite3_blob_close(blob->m_blob); blob->Invalidate(); if (rc != SQLITE_OK) { if (db != NULL && db->m_isValid) { const char* localError = sqlite3_errmsg(db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } else { throw wxSQLite3Exception(rc, wxERRMSG_FINALIZE_FAILED); } } } #else throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOINCBLOB); #endif } void wxSQLite3Blob::CheckBlob() { if (m_db == NULL || !m_db->m_isValid || m_blob == NULL || !m_blob->m_isValid) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_INVALID_BLOB); } } // ---------------------------------------------------------------------------- // wxSQLite3Database: class holding a SQLite3 database object // ---------------------------------------------------------------------------- bool wxSQLite3Database::ms_sharedCacheEnabled = false; void wxSQLite3Database::SetSharedCache(bool enable) { int flag = (enable) ? 1 : 0; int rc = sqlite3_enable_shared_cache(flag); if (rc != SQLITE_OK) { throw wxSQLite3Exception(rc, wxERRMSG_SHARED_CACHE); } ms_sharedCacheEnabled = enable; } #if WXSQLITE3_HAVE_CODEC bool wxSQLite3Database::ms_hasEncryptionSupport = true; #else bool wxSQLite3Database::ms_hasEncryptionSupport = false; #endif #if WXSQLITE3_HAVE_METADATA bool wxSQLite3Database::ms_hasMetaDataSupport = true; #else bool wxSQLite3Database::ms_hasMetaDataSupport = false; #endif #if WXSQLITE3_HAVE_LOAD_EXTENSION bool wxSQLite3Database::ms_hasLoadExtSupport = true; #else bool wxSQLite3Database::ms_hasLoadExtSupport = false; #endif #if WXSQLITE3_USE_NAMED_COLLECTIONS bool wxSQLite3Database::ms_hasNamedCollectionSupport = true; #else bool wxSQLite3Database::ms_hasNamedCollectionSupport = false; #endif #if SQLITE_VERSION_NUMBER >= 3004000 bool wxSQLite3Database::ms_hasIncrementalBlobSupport = true; #else bool wxSQLite3Database::ms_hasIncrementalBlobSupport = false; #endif #if SQLITE_VERSION_NUMBER >= 3006008 bool wxSQLite3Database::ms_hasSavepointSupport = true; #else bool wxSQLite3Database::ms_hasSavepointSupport = false; #endif #if SQLITE_VERSION_NUMBER >= 3006011 bool wxSQLite3Database::ms_hasBackupSupport = true; #else bool wxSQLite3Database::ms_hasBackupSupport = false; #endif #if SQLITE_VERSION_NUMBER >= 3007000 bool wxSQLite3Database::ms_hasWriteAheadLogSupport = true; #else bool wxSQLite3Database::ms_hasWriteAheadLogSupport = false; #endif bool wxSQLite3Database::HasEncryptionSupport() { return ms_hasEncryptionSupport; } bool wxSQLite3Database::HasMetaDataSupport() { return ms_hasMetaDataSupport; } bool wxSQLite3Database::HasLoadExtSupport() { return ms_hasLoadExtSupport; } bool wxSQLite3Database::HasNamedCollectionSupport() { return ms_hasNamedCollectionSupport; } bool wxSQLite3Database::HasIncrementalBlobSupport() { return ms_hasIncrementalBlobSupport; } bool wxSQLite3Database::HasSavepointSupport() { return ms_hasSavepointSupport; } bool wxSQLite3Database::HasBackupSupport() { return ms_hasBackupSupport; } bool wxSQLite3Database::HasWriteAheadLogSupport() { return ms_hasWriteAheadLogSupport; } wxSQLite3Database::wxSQLite3Database() { m_db = 0; m_isOpen = false; m_busyTimeoutMs = 60000; // 60 seconds m_isEncrypted = false; m_lastRollbackRC = 0; m_backupPageCount = 10; } wxSQLite3Database::wxSQLite3Database(const wxSQLite3Database& db) { m_db = db.m_db; if (m_db != NULL) { m_db->IncrementRefCount(); } m_isOpen = db.m_isOpen; m_busyTimeoutMs = 60000; // 60 seconds m_isEncrypted = db.m_isEncrypted; m_lastRollbackRC = db.m_lastRollbackRC; m_backupPageCount = db.m_backupPageCount; } wxSQLite3Database::~wxSQLite3Database() { if (m_db != NULL && m_db->DecrementRefCount() == 0) { if (m_db->m_isValid) { Close(m_db); } delete m_db; } } wxSQLite3Database& wxSQLite3Database::operator=(const wxSQLite3Database& db) { if (this != &db) { wxSQLite3DatabaseReference* dbPrev = m_db; m_db = db.m_db; if (m_db != NULL) { m_db->IncrementRefCount(); m_isOpen = db.m_isOpen; m_busyTimeoutMs = 60000; // 60 seconds m_isEncrypted = db.m_isEncrypted; m_lastRollbackRC = db.m_lastRollbackRC; m_backupPageCount = db.m_backupPageCount; } if (dbPrev != NULL && dbPrev->DecrementRefCount() == 0) { Close(dbPrev); delete dbPrev; } if (m_db == NULL) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_DBASSIGN_FAILED); } } return *this; } void wxSQLite3Database::Open(const wxString& fileName, const wxString& key, int flags) { wxCharBuffer strLocalKey = key.ToUTF8(); const char* localKey = strLocalKey; wxMemoryBuffer binaryKey; if (key.Length() > 0) { binaryKey.AppendData((void*) localKey, strlen(localKey)); } Open(fileName, binaryKey, flags); } void wxSQLite3Database::Open(const wxString& fileName, const wxMemoryBuffer& key, int flags) { wxCharBuffer strFileName = fileName.ToUTF8(); const char* localFileName = strFileName; sqlite3* db; int rc = sqlite3_open_v2((const char*) localFileName, &db, flags, NULL); if (rc != SQLITE_OK) { const char* localError = "Out of memory"; if (db != NULL) { localError = sqlite3_errmsg(db); sqlite3_close(db); } throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } rc = sqlite3_extended_result_codes(db, 1); if (rc != SQLITE_OK) { const char* localError = sqlite3_errmsg(db); sqlite3_close(db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } #if WXSQLITE3_HAVE_CODEC if (key.GetDataLen() > 0) { rc = sqlite3_key(db, key.GetData(), (int) key.GetDataLen()); if (rc != SQLITE_OK) { const char* localError = sqlite3_errmsg(db); sqlite3_close(db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } m_isEncrypted = true; } #else wxUnusedVar(key); #endif wxSQLite3DatabaseReference* dbPrev = m_db; m_db = new wxSQLite3DatabaseReference(db); m_isOpen = true; SetBusyTimeout(m_busyTimeoutMs); if (dbPrev != NULL && dbPrev->DecrementRefCount() == 0) { delete dbPrev; } } bool wxSQLite3Database::IsOpen() const { return (m_db != NULL && m_db->m_isValid && m_isOpen); } bool wxSQLite3Database::IsReadOnly(const wxString& databaseName) { #if SQLITE_VERSION_NUMBER >= 3007011 CheckDatabase(); wxCharBuffer strDatabaseName = databaseName.ToUTF8(); const char* localDatabaseName = strDatabaseName; return sqlite3_db_readonly(m_db->m_db, localDatabaseName) > 0; #else return false; #endif } void wxSQLite3Database::Close() { CheckDatabase(); Close(m_db); } void wxSQLite3Database::Close(wxSQLite3DatabaseReference* db) { if (db != NULL && db->m_isValid) { #if SQLITE_VERSION_NUMBER >= 3006000 // Unfortunately the following code leads to a crash if the RTree module is used // therefore it is disabled for now #if 0 // Finalize all unfinalized prepared statements sqlite3_stmt *pStmt; while( (pStmt = sqlite3_next_stmt(db->m_db, 0))!=0 ) { sqlite3_finalize(pStmt); } #endif #endif if (db->m_refCount <= 1) { sqlite3_close(db->m_db); db->Invalidate(); m_isEncrypted = false; } m_isOpen = false; } } static bool BackupRestoreCallback(int total, int remaining, wxSQLite3BackupProgress* progressCallback) { return progressCallback->Progress(total, remaining); } void wxSQLite3Database::Backup(const wxString& targetFileName, const wxString& key, const wxString& sourceDatabaseName) { Backup(NULL, targetFileName, key, sourceDatabaseName); } void wxSQLite3Database::Backup(wxSQLite3BackupProgress* progressCallback, const wxString& targetFileName, const wxString& key, const wxString& sourceDatabaseName) { wxCharBuffer strLocalKey = key.ToUTF8(); const char* localKey = strLocalKey; wxMemoryBuffer binaryKey; if (key.Length() > 0) { binaryKey.AppendData((void*) localKey, strlen(localKey)); } Backup(progressCallback, targetFileName, binaryKey, sourceDatabaseName); } void wxSQLite3Database::Backup(const wxString& targetFileName, const wxMemoryBuffer& key, const wxString& sourceDatabaseName) { Backup(NULL, targetFileName, key, sourceDatabaseName); } void wxSQLite3Database::Backup(wxSQLite3BackupProgress* progressCallback, const wxString& targetFileName, const wxMemoryBuffer& key, const wxString& sourceDatabaseName) { #if SQLITE_VERSION_NUMBER >= 3006011 CheckDatabase(); wxCharBuffer strFileName = targetFileName.ToUTF8(); const char* localTargetFileName = strFileName; wxCharBuffer strDatabaseName = sourceDatabaseName.ToUTF8(); const char* localSourceDatabaseName = strDatabaseName; sqlite3* pDest; sqlite3_backup* pBackup; int rc; rc = sqlite3_open(localTargetFileName, &pDest); if (rc != SQLITE_OK) { sqlite3_close(pDest); throw wxSQLite3Exception(rc, wxERRMSG_DBOPEN_FAILED); } #if WXSQLITE3_HAVE_CODEC if (key.GetDataLen() > 0) { rc = sqlite3_key(pDest, key.GetData(), (int) key.GetDataLen()); if (rc != SQLITE_OK) { const char* localError = sqlite3_errmsg(pDest); sqlite3_close(pDest); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } } #else wxUnusedVar(key); #endif pBackup = sqlite3_backup_init(pDest, "main", m_db->m_db, localSourceDatabaseName); if (pBackup == 0) { const char* localError = sqlite3_errmsg(pDest); sqlite3_close(pDest); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } do { rc = sqlite3_backup_step(pBackup, m_backupPageCount); if (progressCallback != NULL) { if (!BackupRestoreCallback(sqlite3_backup_pagecount(pBackup), sqlite3_backup_remaining(pBackup), progressCallback)) { rc = SQLITE_DONE; } } #if 0 xProgress(sqlite3_backup_remaining(pBackup), sqlite3_backup_pagecount(pBackup)); #endif if (rc == SQLITE_BUSY || rc == SQLITE_LOCKED) { sqlite3_sleep(250); } } while (rc == SQLITE_OK || rc == SQLITE_BUSY || rc == SQLITE_LOCKED); sqlite3_backup_finish(pBackup); if (rc == SQLITE_DONE) { sqlite3_close(pDest); } else { const char* localError = sqlite3_errmsg(pDest); sqlite3_close(pDest); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } #else wxUnusedVar(targetFileName); wxUnusedVar(sourceDatabaseName); throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOBACKUP); #endif } void wxSQLite3Database::Restore(const wxString& sourceFileName, const wxString& key, const wxString& targetDatabaseName) { Restore(NULL, sourceFileName, key, targetDatabaseName); } void wxSQLite3Database::Restore(wxSQLite3BackupProgress* progressCallback, const wxString& sourceFileName, const wxString& key, const wxString& targetDatabaseName) { wxCharBuffer strLocalKey = key.ToUTF8(); const char* localKey = strLocalKey; wxMemoryBuffer binaryKey; if (key.Length() > 0) { binaryKey.AppendData((void*) localKey, strlen(localKey)); } Restore(progressCallback, sourceFileName, binaryKey, targetDatabaseName); } void wxSQLite3Database::Restore(const wxString& sourceFileName, const wxMemoryBuffer& key, const wxString& targetDatabaseName) { Restore(NULL, sourceFileName, key, targetDatabaseName); } void wxSQLite3Database::Restore(wxSQLite3BackupProgress* progressCallback, const wxString& sourceFileName, const wxMemoryBuffer& key, const wxString& targetDatabaseName) { #if SQLITE_VERSION_NUMBER >= 3006011 CheckDatabase(); wxCharBuffer strFileName = sourceFileName.ToUTF8(); const char* localSourceFileName = strFileName; wxCharBuffer strDatabaseName = targetDatabaseName.ToUTF8(); const char* localTargetDatabaseName = strDatabaseName; sqlite3* pSrc; sqlite3_backup* pBackup; int rc; int nTimeout = 0; rc = sqlite3_open(localSourceFileName, &pSrc); if (rc != SQLITE_OK) { sqlite3_close(pSrc); throw wxSQLite3Exception(rc, wxERRMSG_DBOPEN_FAILED); } #if WXSQLITE3_HAVE_CODEC if (key.GetDataLen() > 0) { rc = sqlite3_key(pSrc, key.GetData(), (int) key.GetDataLen()); if (rc != SQLITE_OK) { const char* localError = sqlite3_errmsg(pSrc); sqlite3_close(pSrc); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } } #else wxUnusedVar(key); #endif pBackup = sqlite3_backup_init(m_db->m_db, localTargetDatabaseName, pSrc, "main"); if (pBackup == 0) { const char* localError = sqlite3_errmsg(m_db->m_db); sqlite3_close(pSrc); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } do { rc = sqlite3_backup_step(pBackup, m_backupPageCount); if (progressCallback != NULL) { if (!BackupRestoreCallback(sqlite3_backup_pagecount(pBackup), sqlite3_backup_remaining(pBackup), progressCallback)) { rc = SQLITE_DONE; } } if (rc == SQLITE_BUSY || rc == SQLITE_LOCKED) { if (nTimeout++ >= 20) break; sqlite3_sleep(250); } else { nTimeout = 0; } } while (rc == SQLITE_OK || rc == SQLITE_BUSY || rc == SQLITE_LOCKED); sqlite3_backup_finish(pBackup); if (rc == SQLITE_DONE) { sqlite3_close(pSrc); } else if (rc == SQLITE_BUSY || rc == SQLITE_LOCKED) { sqlite3_close(pSrc); throw wxSQLite3Exception(rc, wxERRMSG_SOURCEDB_BUSY); } else { const char* localError = sqlite3_errmsg(pSrc); sqlite3_close(pSrc); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } #else wxUnusedVar(sourceFileName); wxUnusedVar(targetDatabaseName); throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOBACKUP); #endif } void wxSQLite3Database::SetBackupRestorePageCount(int pageCount) { m_backupPageCount = pageCount; } void wxSQLite3Database::Vacuum() { ExecuteUpdate("vacuum"); } void wxSQLite3Database::Begin(wxSQLite3TransactionType transactionType) { wxString sql; switch (transactionType) { case WXSQLITE_TRANSACTION_DEFERRED: sql << wxT("begin deferred transaction"); break; case WXSQLITE_TRANSACTION_IMMEDIATE: sql << wxT("begin immediate transaction"); break; case WXSQLITE_TRANSACTION_EXCLUSIVE: sql << wxT("begin exclusive transaction"); break; default: sql << wxT("begin transaction"); break; } ExecuteUpdate(sql); } void wxSQLite3Database::Commit() { ExecuteUpdate("commit transaction"); } void wxSQLite3Database::Rollback(const wxString& savepointName) { #if SQLITE_VERSION_NUMBER >= 3006008 if (savepointName.IsEmpty()) { #endif ExecuteUpdate("rollback transaction"); #if SQLITE_VERSION_NUMBER >= 3006008 } else { ExecuteUpdate(wxString(wxT("rollback transaction to savepoint "))+savepointName); } #endif } bool wxSQLite3Database::GetAutoCommit() { CheckDatabase(); return sqlite3_get_autocommit(m_db->m_db) != 0; } int wxSQLite3Database::QueryRollbackState() { return m_lastRollbackRC; } void wxSQLite3Database::Savepoint(const wxString& savepointName) { #if SQLITE_VERSION_NUMBER >= 3006008 ExecuteUpdate(wxString(wxT("savepoint "))+savepointName); #else wxUnusedVar(savepointName); throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOSAVEPOINT); #endif } void wxSQLite3Database::ReleaseSavepoint(const wxString& savepointName) { #if SQLITE_VERSION_NUMBER >= 3006008 ExecuteUpdate(wxString(wxT("release savepoint "))+savepointName); #else wxUnusedVar(savepointName); throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOSAVEPOINT); #endif } wxSQLite3Statement wxSQLite3Database::PrepareStatement(const wxString& sql) { wxCharBuffer strSql = sql.ToUTF8(); const char* localSql = strSql; return PrepareStatement(localSql); } wxSQLite3Statement wxSQLite3Database::PrepareStatement(const wxSQLite3StatementBuffer& sql) { return PrepareStatement((const char*) sql); } wxSQLite3Statement wxSQLite3Database::PrepareStatement(const char* sql) { CheckDatabase(); sqlite3_stmt* stmt = (sqlite3_stmt*) Prepare(sql); wxSQLite3StatementReference* stmtRef = new wxSQLite3StatementReference(stmt); return wxSQLite3Statement(m_db, stmtRef); } bool wxSQLite3Database::TableExists(const wxString& tableName, const wxString& databaseName) { wxString sql; if (databaseName.IsEmpty()) { sql = wxT("select count(*) from sqlite_master where type='table' and name like ?"); } else { sql = wxString(wxT("select count(*) from ")) + databaseName + wxString(wxT(".sqlite_master where type='table' and name like ?")); } wxSQLite3Statement stmt = PrepareStatement(sql); stmt.Bind(1, tableName); wxSQLite3ResultSet resultSet = stmt.ExecuteQuery(); long value = 0; resultSet.GetAsString(0).ToLong(&value); return (value > 0); } bool wxSQLite3Database::TableExists(const wxString& tableName, wxArrayString& databaseNames) { wxArrayString databaseList; GetDatabaseList(databaseList); bool found = false; size_t count = databaseList.GetCount(); if (count > 0) { size_t j; for (j = 0; j < count; j++) { if (TableExists(tableName, databaseList.Item(j))) { found = true; databaseNames.Add(databaseList.Item(j)); } } } return found; } void wxSQLite3Database::GetDatabaseList(wxArrayString& databaseNames) { databaseNames.Empty(); wxSQLite3ResultSet resultSet = ExecuteQuery("PRAGMA database_list;"); while (resultSet.NextRow()) { databaseNames.Add(resultSet.GetString(1)); } } void wxSQLite3Database::GetDatabaseList(wxArrayString& databaseNames, wxArrayString& databaseFiles) { databaseNames.Empty(); databaseFiles.Empty(); wxSQLite3ResultSet resultSet = ExecuteQuery("PRAGMA database_list;"); while (resultSet.NextRow()) { databaseNames.Add(resultSet.GetString(1)); databaseFiles.Add(resultSet.GetString(2)); } } wxString wxSQLite3Database::GetDatabaseFilename(const wxString& databaseName) { #if SQLITE_VERSION_NUMBER >= 3007010 CheckDatabase(); wxCharBuffer strDatabaseName = databaseName.ToUTF8(); const char* localDatabaseName = strDatabaseName; const char* localFilename = sqlite3_db_filename(m_db->m_db, localDatabaseName); return wxString::FromUTF8(localFilename); #else wxUnusedVar(databaseName); return wxEmptyString; #endif } bool wxSQLite3Database::EnableForeignKeySupport(bool enable) { if (enable) { ExecuteUpdate("PRAGMA foreign_keys=ON;"); } else { ExecuteUpdate("PRAGMA foreign_keys=OFF;"); } bool enabled = IsForeignKeySupportEnabled(); return (enable && enabled) || (!enable && !enabled); } bool wxSQLite3Database::IsForeignKeySupportEnabled() { bool enabled = false; wxSQLite3ResultSet resultSet = ExecuteQuery("PRAGMA foreign_keys;"); if (resultSet.NextRow()) { enabled = (resultSet.GetInt(0) == 1); } return enabled; } wxSQLite3JournalMode wxSQLite3Database::SetJournalMode(wxSQLite3JournalMode journalMode, const wxString& database) { wxString mode = ConvertJournalMode(journalMode); wxString query = wxT("PRAGMA "); if (!database.IsEmpty()) { query += database; query += wxT("."); } query += wxT("journal_mode="); query += mode; query += wxT(";"); wxSQLite3ResultSet resultSet = ExecuteQuery(query); if (resultSet.NextRow()) { mode = resultSet.GetString(0); } return ConvertJournalMode(mode); } wxSQLite3JournalMode wxSQLite3Database::GetJournalMode(const wxString& database) { wxString mode = wxT("DELETE"); wxString query = wxT("PRAGMA "); if (!database.IsEmpty()) { query += database; query += wxT("."); } query += wxT("journal_mode;"); wxSQLite3ResultSet resultSet = ExecuteQuery(query); if (resultSet.NextRow()) { mode = resultSet.GetString(0); } return ConvertJournalMode(mode); } /* static */ wxString wxSQLite3Database::ConvertJournalMode(wxSQLite3JournalMode mode) { wxString journalMode; if (mode == WXSQLITE_JOURNALMODE_DELETE) journalMode = wxT("DELETE"); else if (mode == WXSQLITE_JOURNALMODE_PERSIST) journalMode = wxT("PERSIST"); else if (mode == WXSQLITE_JOURNALMODE_OFF) journalMode = wxT("OFF"); else if (mode == WXSQLITE_JOURNALMODE_TRUNCATE) journalMode = wxT("TRUNCATE"); else if (mode == WXSQLITE_JOURNALMODE_MEMORY) journalMode = wxT("MEMORY"); else if (mode == WXSQLITE_JOURNALMODE_WAL) journalMode = wxT("WAL"); else journalMode = wxT("DELETE"); return journalMode; } /* static */ wxSQLite3JournalMode wxSQLite3Database::ConvertJournalMode(const wxString& mode) { wxSQLite3JournalMode journalMode; if (mode.IsSameAs(wxT("DELETE"))) journalMode = WXSQLITE_JOURNALMODE_DELETE; else if (mode.IsSameAs(wxT("PERSIST"))) journalMode = WXSQLITE_JOURNALMODE_PERSIST; else if (mode.IsSameAs(wxT("OFF"))) journalMode = WXSQLITE_JOURNALMODE_OFF; else if (mode.IsSameAs(wxT("TRUNCATE"))) journalMode = WXSQLITE_JOURNALMODE_TRUNCATE; else if (mode.IsSameAs(wxT("MEMORY"))) journalMode = WXSQLITE_JOURNALMODE_MEMORY; else if (mode.IsSameAs(wxT("WAL"))) journalMode = WXSQLITE_JOURNALMODE_WAL; else journalMode = WXSQLITE_JOURNALMODE_DELETE; return journalMode; } bool wxSQLite3Database::CheckSyntax(const wxString& sql) { wxCharBuffer strSql = sql.ToUTF8(); const char* localSql = strSql; return CheckSyntax(localSql); } bool wxSQLite3Database::CheckSyntax(const wxSQLite3StatementBuffer& sql) { return CheckSyntax((const char*) sql); } bool wxSQLite3Database::CheckSyntax(const char* sql) { return sqlite3_complete(sql) != 0; } int wxSQLite3Database::ExecuteUpdate(const wxString& sql) { wxCharBuffer strSql = sql.ToUTF8(); const char* localSql = strSql; return ExecuteUpdate(localSql); } int wxSQLite3Database::ExecuteUpdate(const wxSQLite3StatementBuffer& sql) { return ExecuteUpdate((const char*) sql); } int wxSQLite3Database::ExecuteUpdate(const char* sql, bool saveRC) { CheckDatabase(); char* localError = 0; int rc = sqlite3_exec(m_db->m_db, sql, 0, 0, &localError); if (saveRC) { if (strncmp(sql, "rollback transaction", 20) == 0) { m_lastRollbackRC = rc; } } if (rc == SQLITE_OK) { return sqlite3_changes(m_db->m_db); } else { wxString errmsg = wxString::FromUTF8(localError); sqlite3_free(localError); throw wxSQLite3Exception(rc, errmsg); } } wxSQLite3ResultSet wxSQLite3Database::ExecuteQuery(const wxString& sql) { wxCharBuffer strSql = sql.ToUTF8(); const char* localSql = strSql; return ExecuteQuery(localSql); } wxSQLite3ResultSet wxSQLite3Database::ExecuteQuery(const wxSQLite3StatementBuffer& sql) { return ExecuteQuery((const char*) sql); } wxSQLite3ResultSet wxSQLite3Database::ExecuteQuery(const char* sql) { CheckDatabase(); sqlite3_stmt* stmt = (sqlite3_stmt*) Prepare(sql); int rc = sqlite3_step(stmt); if (rc == SQLITE_DONE) // no rows { wxSQLite3StatementReference* stmtRef = new wxSQLite3StatementReference(stmt); return wxSQLite3ResultSet(m_db, stmtRef, true /* eof */); } else if (rc == SQLITE_ROW) // one or more rows { wxSQLite3StatementReference* stmtRef = new wxSQLite3StatementReference(stmt); return wxSQLite3ResultSet(m_db, stmtRef, false /* eof */); } else { rc = sqlite3_finalize(stmt); const char* localError= sqlite3_errmsg(m_db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } } int wxSQLite3Database::ExecuteScalar(const wxString& sql) { wxCharBuffer strSql = sql.ToUTF8(); const char* localSql = strSql; return ExecuteScalar(localSql); } int wxSQLite3Database::ExecuteScalar(const wxSQLite3StatementBuffer& sql) { return ExecuteScalar((const char*) sql); } int wxSQLite3Database::ExecuteScalar(const char* sql) { wxSQLite3ResultSet resultSet = ExecuteQuery(sql); if (resultSet.Eof() || resultSet.GetColumnCount() < 1) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_INVALID_QUERY); } long value = 0; resultSet.GetAsString(0).ToLong(&value); return (int) value; } wxSQLite3Table wxSQLite3Database::GetTable(const wxString& sql) { wxCharBuffer strSql = sql.ToUTF8(); const char* localSql = strSql; return GetTable(localSql); } wxSQLite3Table wxSQLite3Database::GetTable(const wxSQLite3StatementBuffer& sql) { return GetTable((const char*) sql); } wxSQLite3Table wxSQLite3Database::GetTable(const char* sql) { CheckDatabase(); char* localError=0; char** results=0; int rc; int rows(0); int cols(0); rc = sqlite3_get_table(m_db->m_db, sql, &results, &rows, &cols, &localError); if (rc == SQLITE_OK) { return wxSQLite3Table(results, rows, cols); } else { throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } } wxLongLong wxSQLite3Database::GetLastRowId() { CheckDatabase(); return wxLongLong(sqlite3_last_insert_rowid(m_db->m_db)); } wxSQLite3Blob wxSQLite3Database::GetReadOnlyBlob(wxLongLong rowId, const wxString& columnName, const wxString& tableName, const wxString& dbName) { return GetBlob(rowId, columnName, tableName, dbName, false); } wxSQLite3Blob wxSQLite3Database::GetWritableBlob(wxLongLong rowId, const wxString& columnName, const wxString& tableName, const wxString& dbName) { return GetBlob(rowId, columnName, tableName, dbName, true); } wxSQLite3Blob wxSQLite3Database::GetBlob(wxLongLong rowId, const wxString& columnName, const wxString& tableName, const wxString& dbName, bool writable) { #if SQLITE_VERSION_NUMBER >= 3004000 wxCharBuffer strColumnName = columnName.ToUTF8(); const char* localColumnName = strColumnName; wxCharBuffer strTableName = tableName.ToUTF8(); const char* localTableName = strTableName; wxCharBuffer strDbName = dbName.ToUTF8(); const char* localDbName = (!dbName.IsEmpty()) ? (const char*) strDbName : (const char*) NULL; int flags = (writable) ? 1 : 0; sqlite3_blob* blobHandle; CheckDatabase(); int rc = sqlite3_blob_open(m_db->m_db, localDbName, localTableName, localColumnName, rowId.GetValue(), flags, &blobHandle); if (rc != SQLITE_OK) { const char* localError = sqlite3_errmsg(m_db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } wxSQLite3BlobReference* blobRef = new wxSQLite3BlobReference(blobHandle); return wxSQLite3Blob(m_db, blobRef, writable); #else wxUnusedVar(rowId); wxUnusedVar(columnName); wxUnusedVar(tableName); wxUnusedVar(dbName); wxUnusedVar(writable); throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOINCBLOB); return NULL; #endif } void wxSQLite3Database::Interrupt() { CheckDatabase(); sqlite3_interrupt(m_db->m_db); } void wxSQLite3Database::SetBusyTimeout(int nMillisecs) { CheckDatabase(); m_busyTimeoutMs = nMillisecs; sqlite3_busy_timeout(m_db->m_db, m_busyTimeoutMs); } wxString wxSQLite3Database::GetWrapperVersion() { return wxString(wxSQLITE3_VERSION_STRING); } wxString wxSQLite3Database::GetVersion() { return wxString::FromUTF8(sqlite3_libversion()); } wxString wxSQLite3Database::GetSourceId() { #if SQLITE_VERSION_NUMBER >= 3006018 return wxString::FromUTF8(sqlite3_sourceid()); #else return wxEmptyString; #endif } bool wxSQLite3Database::CompileOptionUsed(const wxString& optionName) { #if SQLITE_VERSION_NUMBER >= 3006023 wxCharBuffer strOption = optionName.ToUTF8(); const char* localOption = strOption; return sqlite3_compileoption_used(localOption) == 1; #else return false; #endif } wxString wxSQLite3Database::GetCompileOptionName(int optionIndex) { #if SQLITE_VERSION_NUMBER >= 3006023 const char* unknownOption = ""; const char* optionName = sqlite3_compileoption_get(optionIndex); if (optionName == NULL) { optionName = unknownOption; } return wxString::FromUTF8(optionName); #else return wxEmptyString; #endif } bool wxSQLite3Database::CreateFunction(const wxString& funcName, int argCount, wxSQLite3ScalarFunction& function, bool isDeterministic) { CheckDatabase(); wxCharBuffer strFuncName = funcName.ToUTF8(); const char* localFuncName = strFuncName; int flags = SQLITE_UTF8; #if SQLITE_VERSION_NUMBER >= 3008003 if (isDeterministic) { flags |= SQLITE_DETERMINISTIC; } #endif int rc = sqlite3_create_function(m_db->m_db, localFuncName, argCount, flags, &function, (void (*)(sqlite3_context*,int,sqlite3_value**)) wxSQLite3FunctionContext::ExecScalarFunction, NULL, NULL); return rc == SQLITE_OK; } bool wxSQLite3Database::CreateFunction(const wxString& funcName, int argCount, wxSQLite3AggregateFunction& function, bool isDeterministic) { CheckDatabase(); wxCharBuffer strFuncName = funcName.ToUTF8(); const char* localFuncName = strFuncName; int flags = SQLITE_UTF8; #if SQLITE_VERSION_NUMBER >= 3008003 if (isDeterministic) { flags |= SQLITE_DETERMINISTIC; } #endif int rc = sqlite3_create_function(m_db->m_db, localFuncName, argCount, flags, &function, NULL, (void (*)(sqlite3_context*,int,sqlite3_value**)) wxSQLite3FunctionContext::ExecAggregateStep, (void (*)(sqlite3_context*)) wxSQLite3FunctionContext::ExecAggregateFinalize); return rc == SQLITE_OK; } bool wxSQLite3Database::SetAuthorizer(wxSQLite3Authorizer& authorizer) { CheckDatabase(); int rc = sqlite3_set_authorizer(m_db->m_db, wxSQLite3FunctionContext::ExecAuthorizer, &authorizer); return rc == SQLITE_OK; } void wxSQLite3Database::SetCommitHook(wxSQLite3Hook* commitHook) { CheckDatabase(); if (commitHook) { sqlite3_commit_hook(m_db->m_db, (int(*)(void*)) wxSQLite3FunctionContext::ExecCommitHook, commitHook); } else { sqlite3_commit_hook(m_db->m_db, (int(*)(void*)) NULL, NULL); } } void wxSQLite3Database::SetRollbackHook(wxSQLite3Hook* rollbackHook) { CheckDatabase(); if (rollbackHook) { sqlite3_rollback_hook(m_db->m_db, (void(*)(void*)) wxSQLite3FunctionContext::ExecRollbackHook, rollbackHook); } else { sqlite3_rollback_hook(m_db->m_db, (void(*)(void*)) NULL, NULL); } } void wxSQLite3Database::SetUpdateHook(wxSQLite3Hook* updateHook) { CheckDatabase(); if (updateHook) { sqlite3_update_hook(m_db->m_db, (void(*)(void*,int,const char*,const char*, wxsqlite_int64)) wxSQLite3FunctionContext::ExecUpdateHook, updateHook); } else { sqlite3_update_hook(m_db->m_db, (void(*)(void*,int,const char*,const char*, wxsqlite_int64)) NULL, NULL); } } void wxSQLite3Database::SetWriteAheadLogHook(wxSQLite3Hook* walHook) { #if SQLITE_VERSION_NUMBER >= 3007000 CheckDatabase(); if (walHook) { walHook->SetDatabase(this); sqlite3_wal_hook(m_db->m_db, (int(*)(void *,sqlite3*,const char*,int)) wxSQLite3FunctionContext::ExecWriteAheadLogHook, walHook); } else { sqlite3_wal_hook(m_db->m_db, (int(*)(void *,sqlite3*,const char*,int)) NULL, NULL); } #else wxUnusedVar(walHook); throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOWAL); #endif } void wxSQLite3Database::WriteAheadLogCheckpoint(const wxString& database, int mode, int* logFrameCount, int* ckptFrameCount) { #if SQLITE_VERSION_NUMBER >= 3007000 CheckDatabase(); wxCharBuffer strDatabase = database.ToUTF8(); const char* localDatabase = strDatabase; #if SQLITE_VERSION_NUMBER >= 3007006 int rc = sqlite3_wal_checkpoint_v2(m_db->m_db, localDatabase, mode, logFrameCount, ckptFrameCount); #else int rc = sqlite3_wal_checkpoint(m_db->m_db, localDatabase); if (logFrameCount != NULL) *logFrameCount = 0; if (ckptFrameCount != NULL) *ckptFrameCount = 0; #endif if (rc != SQLITE_OK) { const char* localError = sqlite3_errmsg(m_db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } #else wxUnusedVar(database); throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOWAL); #endif } void wxSQLite3Database::AutoWriteAheadLogCheckpoint(int frameCount) { #if SQLITE_VERSION_NUMBER >= 3007000 CheckDatabase(); int rc = sqlite3_wal_autocheckpoint(m_db->m_db, frameCount); if (rc != SQLITE_OK) { const char* localError = sqlite3_errmsg(m_db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } #else wxUnusedVar(frameCount); throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOWAL); #endif } void wxSQLite3Database::SetCollation(const wxString& collationName, wxSQLite3Collation* collation) { CheckDatabase(); wxCharBuffer strCollationName = collationName.ToUTF8(); const char* localCollationName = strCollationName; int rc; if (collation) { rc = sqlite3_create_collation(m_db->m_db, localCollationName, SQLITE_UTF8, collation, (int(*)(void*,int,const void*,int,const void*)) wxSQLite3Database::ExecComparisonWithCollation); } else { rc = sqlite3_create_collation(m_db->m_db, localCollationName, SQLITE_UTF8, NULL, (int(*)(void*,int,const void*,int,const void*)) NULL); } } void* wxSQLite3Database::GetDatabaseHandle() { return m_db->m_db; } void wxSQLite3Database::SetCollationNeededCallback() { CheckDatabase(); int rc = sqlite3_collation_needed(m_db->m_db, this, (void(*)(void*,sqlite3*,int,const char*)) wxSQLite3Database::ExecCollationNeeded); if (rc != SQLITE_OK) { const char* localError = sqlite3_errmsg(m_db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } } void wxSQLite3Database::CheckDatabase() { if (m_db == NULL || m_db->m_db == NULL || !m_db->m_isValid || !m_isOpen) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NODB); } } void* wxSQLite3Database::Prepare(const char* sql) { CheckDatabase(); const char* tail=0; sqlite3_stmt* stmt; int rc = sqlite3_prepare_v2(m_db->m_db, sql, -1, &stmt, &tail); if (rc != SQLITE_OK) { const char* localError = sqlite3_errmsg(m_db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } return stmt; } /* static */ int wxSQLite3Database::ExecComparisonWithCollation(void* collation, int len1, const void* text1, int len2, const void* text2) { wxString locText1 = wxString::FromUTF8((const char*) text1, (size_t) len1); wxString locText2 = wxString::FromUTF8((const char*) text2, (size_t) len2); return ((wxSQLite3Collation*) collation)->Compare(locText1, locText2); } void wxSQLite3Database::ExecCollationNeeded(void* db, void*, int, const char* collationName) { wxString locCollation = wxString::FromUTF8((const char*) collationName); ((wxSQLite3Database*) db)->SetNeededCollation(locCollation); } void wxSQLite3Database::GetMetaData(const wxString& databaseName, const wxString& tableName, const wxString& columnName, wxString* dataType, wxString* collation, bool* notNull, bool* primaryKey, bool* autoIncrement) { #if WXSQLITE3_HAVE_METADATA CheckDatabase(); wxCharBuffer strDatabaseName = databaseName.ToUTF8(); const char* localDatabaseName = strDatabaseName; if (databaseName == wxEmptyString) localDatabaseName = NULL; wxCharBuffer strTableName = tableName.ToUTF8(); const char* localTableName = strTableName; wxCharBuffer strColumnName = columnName.ToUTF8(); const char* localColumnName = strColumnName; const char* localDataType; const char* localCollation; int localNotNull; int localPrimaryKey; int localAutoIncrement; int rc = sqlite3_table_column_metadata(m_db->m_db, localDatabaseName, localTableName, localColumnName, &localDataType, &localCollation, &localNotNull, &localPrimaryKey, &localAutoIncrement); if (rc != SQLITE_OK) { const char* localError = sqlite3_errmsg(m_db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } if (dataType != NULL) *dataType = wxString::FromUTF8(localDataType); if (collation != NULL) *collation = wxString::FromUTF8(localCollation); if (notNull != NULL) *notNull = (localNotNull != 0); if (primaryKey != NULL) *primaryKey = (localPrimaryKey != 0); if (autoIncrement != NULL) *autoIncrement = (localAutoIncrement != 0); #else wxUnusedVar(databaseName); wxUnusedVar(tableName); wxUnusedVar(columnName); wxUnusedVar(dataType); wxUnusedVar(collation); wxUnusedVar(notNull); wxUnusedVar(primaryKey); wxUnusedVar(autoIncrement); throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOMETADATA); #endif } void wxSQLite3Database::LoadExtension(const wxString& fileName, const wxString& entryPoint) { #if WXSQLITE3_HAVE_LOAD_EXTENSION CheckDatabase(); wxCharBuffer strFileName = fileName.ToUTF8(); const char* localFileName = strFileName; wxCharBuffer strEntryPoint = entryPoint.ToUTF8(); const char* localEntryPoint = strEntryPoint; int rc = sqlite3_load_extension(m_db->m_db, localFileName, localEntryPoint, NULL); if (rc != SQLITE_OK) { const char* localError = sqlite3_errmsg(m_db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } #else wxUnusedVar(fileName); wxUnusedVar(entryPoint); throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOLOADEXT); #endif } void wxSQLite3Database::EnableLoadExtension(bool enable) { #if WXSQLITE3_HAVE_LOAD_EXTENSION CheckDatabase(); int onoff = (enable) ? 1 : 0; int rc = sqlite3_enable_load_extension(m_db->m_db, onoff); if (rc != SQLITE_OK) { const char* localError = sqlite3_errmsg(m_db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } #else wxUnusedVar(enable); throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOLOADEXT); #endif } void wxSQLite3Database::ReKey(const wxString& newKey) { #if WXSQLITE3_HAVE_CODEC wxCharBuffer strLocalNewKey = newKey.ToUTF8(); const char* localNewKey = strLocalNewKey; wxMemoryBuffer binaryNewKey; if (newKey.Length() > 0) { binaryNewKey.AppendData((void*) localNewKey, strlen(localNewKey)); } ReKey(binaryNewKey); #else wxUnusedVar(newKey); throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOCODEC); #endif } void wxSQLite3Database::ReKey(const wxMemoryBuffer& newKey) { #if WXSQLITE3_HAVE_CODEC CheckDatabase(); int rc = sqlite3_rekey(m_db->m_db, newKey.GetData(), (int) newKey.GetDataLen()); if (rc != SQLITE_OK) { const char* localError = sqlite3_errmsg(m_db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } #else wxUnusedVar(newKey); throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOCODEC); #endif } int wxSQLite3Database::GetLimit(wxSQLite3LimitType id) { int value = -1; #if SQLITE_VERSION_NUMBER >= 3005008 CheckDatabase(); if (id >= WXSQLITE_LIMIT_LENGTH && id <= WXSQLITE_LIMIT_VARIABLE_NUMBER) { value = sqlite3_limit(m_db->m_db, id, -1); } #else wxUnusedVar(id); #endif return value; } int wxSQLite3Database::SetLimit(wxSQLite3LimitType id, int newValue) { int value = -1; #if SQLITE_VERSION_NUMBER >= 3005008 CheckDatabase(); if (id >= WXSQLITE_LIMIT_LENGTH && id <= WXSQLITE_LIMIT_VARIABLE_NUMBER) { value = sqlite3_limit(m_db->m_db, id, newValue); } #else wxUnusedVar(id); wxUnusedVar(newValue); #endif return value; } void wxSQLite3Database::ReleaseMemory() { #if SQLITE_VERSION_NUMBER >= 3007010 CheckDatabase(); int rc = sqlite3_db_release_memory(m_db->m_db); if (rc != SQLITE_OK) { const char* localError = sqlite3_errmsg(m_db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } #endif } static const wxChar* limitCodeString[] = { wxT("SQLITE_LIMIT_LENGTH"), wxT("SQLITE_LIMIT_SQL_LENGTH"), wxT("SQLITE_LIMIT_COLUMN"), wxT("SQLITE_LIMIT_EXPR_DEPTH"), wxT("SQLITE_LIMIT_COMPOUND_SELECT"), wxT("SQLITE_LIMIT_VDBE_OP"), wxT("SQLITE_LIMIT_FUNCTION_ARG"), wxT("SQLITE_LIMIT_ATTACHED"), wxT("SQLITE_LIMIT_LIKE_PATTERN_LENGTH"), wxT("SQLITE_LIMIT_VARIABLE_NUMBER"), wxT("SQLITE_LIMIT_TRIGGER_DEPTH") }; /* static */ wxString wxSQLite3Database::LimitTypeToString(wxSQLite3LimitType type) { const wxChar* limitString = wxT("Unknown"); if (type >= WXSQLITE_LIMIT_LENGTH && type <= WXSQLITE_LIMIT_VARIABLE_NUMBER) { limitString = limitCodeString[type]; } return wxString(limitString); } /* static */ void wxSQLite3Database::InitializeSQLite() { #if SQLITE_VERSION_NUMBER >= 3006000 int rc = sqlite3_initialize(); if (rc != SQLITE_OK) { throw wxSQLite3Exception(rc, wxERRMSG_INITIALIZE); } #endif } /* static */ void wxSQLite3Database::ShutdownSQLite() { #if SQLITE_VERSION_NUMBER >= 3006000 int rc = sqlite3_shutdown(); if (rc != SQLITE_OK) { throw wxSQLite3Exception(rc, wxERRMSG_SHUTDOWN); } #endif } /* static */ bool wxSQLite3Database::SetTemporaryDirectory(const wxString& tempDirectory) { bool ok = false; #if SQLITE_VERSION_NUMBER >= 3007014 #if defined(__WXMSW__) DWORD SQLITE_WIN32_TEMP_DIRECTORY_TYPE = 2; #if wxUSE_UNICODE const wxChar* zValue = tempDirectory.wc_str(); #else const wxWCharBuffer zValue = tempDirectory.wc_str(wxConvLocal); #endif int rc = sqlite3_win32_set_directory(SQLITE_WIN32_TEMP_DIRECTORY_TYPE, zValue); ok = (rc == SQLITE_OK); #if 0 if (rc != SQLITE_OK) { throw wxSQLite3Exception(rc, wxERRMSG_TEMPDIR); } #endif #endif #endif return ok; } /* static */ bool wxSQLite3Database::Randomness(int n, wxMemoryBuffer& random) { bool ok = false; #if SQLITE_VERSION_NUMBER >= 3005008 if (n > 0) { void* buffer = random.GetWriteBuf(n); sqlite3_randomness(n, buffer); random.UngetWriteBuf(n); ok = true; } #else wxUnusedVar(n); wxUnusedVar(random); #endif return ok; } // ---------------------------------------------------------------------------- // wxSQLite3FunctionContext: class providing the function context // for user defined functions // ---------------------------------------------------------------------------- int wxSQLite3FunctionContext::GetArgCount() { return m_argc; } int wxSQLite3FunctionContext::GetArgType(int argIndex) { if (argIndex >= 0 && argIndex < m_argc) { return sqlite3_value_type((sqlite3_value*) m_argv[argIndex]); } else { return SQLITE_NULL; } } bool wxSQLite3FunctionContext::IsNull(int argIndex) { if (argIndex >= 0 && argIndex < m_argc) { return sqlite3_value_type((sqlite3_value*) m_argv[argIndex]) == SQLITE_NULL; } else { return true; } } int wxSQLite3FunctionContext::GetInt(int argIndex, int nullValue) { if (argIndex >= 0 && argIndex < m_argc) { if (!IsNull(argIndex)) { return sqlite3_value_int((sqlite3_value*) m_argv[argIndex]); } else { return nullValue; } } else { return nullValue; } } wxLongLong wxSQLite3FunctionContext::GetInt64(int argIndex, wxLongLong nullValue) { if (argIndex >= 0 && argIndex < m_argc) { if (!IsNull(argIndex)) { return wxLongLong(sqlite3_value_int64((sqlite3_value*) m_argv[argIndex])); } else { return nullValue; } } else { return nullValue; } } double wxSQLite3FunctionContext::GetDouble(int argIndex, double nullValue) { if (argIndex >= 0 && argIndex < m_argc) { if (!IsNull(argIndex)) { return sqlite3_value_double((sqlite3_value*) m_argv[argIndex]); } else { return nullValue; } } else { return nullValue; } } wxString wxSQLite3FunctionContext::GetString(int argIndex, const wxString& nullValue) { if (argIndex >= 0 && argIndex < m_argc) { if (!IsNull(argIndex)) { const char* localValue = (const char*) sqlite3_value_text((sqlite3_value*) m_argv[argIndex]); return wxString::FromUTF8(localValue); } else { return nullValue; } } else { return nullValue; } } wxMemoryBuffer& wxSQLite3FunctionContext::GetBlob(int argIndex, wxMemoryBuffer& buffer) { if (argIndex >= 0 && argIndex < m_argc) { if (!IsNull(argIndex)) { int len = sqlite3_value_bytes((sqlite3_value*) m_argv[argIndex]); const void* blob = sqlite3_value_blob((sqlite3_value*) m_argv[argIndex]); buffer.AppendData((void*) blob, (size_t) len); } } return buffer; } void wxSQLite3FunctionContext::SetResult(int value) { sqlite3_result_int((sqlite3_context*) m_ctx, value); } void wxSQLite3FunctionContext::SetResult(wxLongLong value) { sqlite3_result_int64((sqlite3_context*) m_ctx, value.GetValue()); } void wxSQLite3FunctionContext::SetResult(double value) { sqlite3_result_double((sqlite3_context*) m_ctx, value); } void wxSQLite3FunctionContext::SetResult(const wxString& value) { wxCharBuffer strValue = value.ToUTF8(); const char* localValue = strValue; sqlite3_result_text((sqlite3_context*) m_ctx, localValue, -1, SQLITE_TRANSIENT); } void wxSQLite3FunctionContext::SetResult(unsigned char* value, int len) { sqlite3_result_blob((sqlite3_context*) m_ctx, value, len, SQLITE_TRANSIENT); } void wxSQLite3FunctionContext::SetResult(const wxMemoryBuffer& buffer) { sqlite3_result_blob((sqlite3_context*) m_ctx, buffer.GetData(), (int) buffer.GetDataLen(), SQLITE_TRANSIENT); } void wxSQLite3FunctionContext::SetResultNull() { sqlite3_result_null((sqlite3_context*) m_ctx); } void wxSQLite3FunctionContext::SetResultZeroBlob(int blobSize) { #if SQLITE_VERSION_NUMBER >= 3004000 sqlite3_result_zeroblob((sqlite3_context*) m_ctx, blobSize); #endif } void wxSQLite3FunctionContext::SetResultArg(int argIndex) { if (argIndex >= 0 && argIndex < m_argc) { sqlite3_result_value((sqlite3_context*) m_ctx, (sqlite3_value*) m_argv[argIndex]); } else { sqlite3_result_null((sqlite3_context*) m_ctx); } } void wxSQLite3FunctionContext::SetResultError(const wxString& errmsg) { wxCharBuffer strErrmsg = errmsg.ToUTF8(); const char* localErrmsg = strErrmsg; sqlite3_result_error((sqlite3_context*) m_ctx, localErrmsg, -1); } int wxSQLite3FunctionContext::GetAggregateCount() { if (m_isAggregate) { return m_count; } else { return 0; } } void* wxSQLite3FunctionContext::GetAggregateStruct(int len) { if (m_isAggregate) { return sqlite3_aggregate_context((sqlite3_context*) m_ctx, len); } else { return NULL; } } /* static */ void wxSQLite3FunctionContext::ExecScalarFunction(void* ctx, int argc, void** argv) { wxSQLite3FunctionContext context(ctx, false, argc, argv); wxSQLite3ScalarFunction* func = (wxSQLite3ScalarFunction*) sqlite3_user_data((sqlite3_context*) ctx); func->Execute(context); } /* static */ void wxSQLite3FunctionContext::ExecAggregateStep(void* ctx, int argc, void** argv) { wxSQLite3FunctionContext context(ctx, true, argc, argv); wxSQLite3AggregateFunction* func = (wxSQLite3AggregateFunction*) sqlite3_user_data((sqlite3_context*) ctx); func->m_count++; context.m_count = func->m_count; func->Aggregate(context); } /* static */ void wxSQLite3FunctionContext::ExecAggregateFinalize(void* ctx) { wxSQLite3FunctionContext context(ctx, true, 0, NULL); wxSQLite3AggregateFunction* func = (wxSQLite3AggregateFunction*) sqlite3_user_data((sqlite3_context*) ctx); context.m_count = func->m_count; func->Finalize(context); } /* static */ int wxSQLite3FunctionContext::ExecAuthorizer(void* func, int type, const char* arg1, const char* arg2, const char* arg3, const char* arg4) { wxString locArg1 = wxString::FromUTF8(arg1); wxString locArg2 = wxString::FromUTF8(arg2); wxString locArg3 = wxString::FromUTF8(arg3); wxString locArg4 = wxString::FromUTF8(arg4); wxSQLite3Authorizer::wxAuthorizationCode localType = (wxSQLite3Authorizer::wxAuthorizationCode) type; return (int) ((wxSQLite3Authorizer*) func)->Authorize(localType, locArg1, locArg2, locArg3, locArg3); } /* static */ int wxSQLite3FunctionContext::ExecCommitHook(void* hook) { return (int) ((wxSQLite3Hook*) hook)->CommitCallback(); } /* static */ void wxSQLite3FunctionContext::ExecRollbackHook(void* hook) { ((wxSQLite3Hook*) hook)->RollbackCallback(); } /* static */ void wxSQLite3FunctionContext::ExecUpdateHook(void* hook, int type, const char* database, const char* table, wxsqlite_int64 rowid) { wxString locDatabase = wxString::FromUTF8(database); wxString locTable = wxString::FromUTF8(table); wxSQLite3Hook::wxUpdateType locType = (wxSQLite3Hook::wxUpdateType) type; wxLongLong locRowid = rowid; ((wxSQLite3Hook*) hook)->UpdateCallback(locType, locDatabase, locTable, locRowid); } wxSQLite3FunctionContext::wxSQLite3FunctionContext(void* ctx, bool isAggregate, int argc, void** argv) : m_ctx(ctx), m_isAggregate(isAggregate), m_count(0), m_argc(argc), m_argv(argv) { } /* static */ int wxSQLite3FunctionContext::ExecWriteAheadLogHook(void* hook, void* dbHandle, const char* database, int numPages) { wxString locDatabase = wxString::FromUTF8(database); wxUnusedVar(dbHandle); return (int) ((wxSQLite3Hook*) hook)->WriteAheadLogCallback(locDatabase, numPages); } static const wxChar* authCodeString[] = { wxT("SQLITE_COPY"), wxT("SQLITE_CREATE_INDEX"), wxT("SQLITE_CREATE_TABLE"), wxT("SQLITE_CREATE_TEMP_INDEX"), wxT("SQLITE_CREATE_TEMP_TABLE"), wxT("SQLITE_CREATE_TEMP_TRIGGER"), wxT("SQLITE_CREATE_TEMP_VIEW"), wxT("SQLITE_CREATE_TRIGGER"), wxT("SQLITE_CREATE_VIEW"), wxT("SQLITE_DELETE"), wxT("SQLITE_DROP_INDEX"), wxT("SQLITE_DROP_TABLE"), wxT("SQLITE_DROP_TEMP_INDEX"), wxT("SQLITE_DROP_TEMP_TABLE"), wxT("SQLITE_DROP_TEMP_TRIGGER"), wxT("SQLITE_DROP_TEMP_VIEW"), wxT("SQLITE_DROP_TRIGGER"), wxT("SQLITE_DROP_VIEW"), wxT("SQLITE_INSERT"), wxT("SQLITE_PRAGMA"), wxT("SQLITE_READ"), wxT("SQLITE_SELECT"), wxT("SQLITE_TRANSACTION"), wxT("SQLITE_UPDATE"), wxT("SQLITE_ATTACH"), wxT("SQLITE_DETACH"), wxT("SQLITE_ALTER_TABLE"), wxT("SQLITE_REINDEX"), wxT("SQLITE_ANALYZE"), wxT("SQLITE_CREATE_VTABLE"), wxT("SQLITE_DROP_VTABLE"), wxT("SQLITE_FUNCTION"), wxT("SQLITE_SAVEPOINT"), wxT("SQLITE_RECURSIVE") }; /* static */ wxString wxSQLite3Authorizer::AuthorizationCodeToString(wxSQLite3Authorizer::wxAuthorizationCode type) { const wxChar* authString = wxT("Unknown"); if (type >= SQLITE_COPY && type <= SQLITE_MAX_CODE) { authString = authCodeString[type]; } return wxString(authString); } // ---------------------------------------------------------------------------- // wxSQLite3Transaction // ---------------------------------------------------------------------------- wxSQLite3Transaction::wxSQLite3Transaction(wxSQLite3Database* db, wxSQLite3TransactionType transactionType) { wxASSERT(db != NULL); m_database = db; try { m_database->Begin(transactionType); } catch (...) { m_database = NULL; // Flag that transaction is not active } } wxSQLite3Transaction::~wxSQLite3Transaction() { if (m_database != NULL) { try { m_database->Rollback(); } catch (...) { // Intentionally do nothing } } } void wxSQLite3Transaction::Commit() { try { m_database->Commit(); } catch (...) { m_database->Rollback(); } m_database = NULL; } void wxSQLite3Transaction::Rollback() { try { m_database->Rollback(); } catch (...) { m_database->Rollback(); } m_database = NULL; } // --- User defined function classes #if wxUSE_REGEX wxSQLite3RegExpOperator::wxSQLite3RegExpOperator(int flags) : m_flags(flags) { } wxSQLite3RegExpOperator::~wxSQLite3RegExpOperator() { } void wxSQLite3RegExpOperator::Execute(wxSQLite3FunctionContext& ctx) { int argCount = ctx.GetArgCount(); if (argCount == 2) { wxString exprStr = ctx.GetString(0); wxString textStr = ctx.GetString(1); if (!m_exprStr.IsSameAs(exprStr)) { m_exprStr = exprStr; m_regEx.Compile(m_exprStr, m_flags); } if (m_regEx.IsValid()) { int rc = (m_regEx.Matches(textStr)) ? 1 : 0; ctx.SetResult(rc); } else { ctx.SetResultError(wxString(_("Regular expression invalid: '"))+exprStr+_T("'.")); } } else { ctx.SetResultError(wxString::Format(_("REGEXP called with wrong number of arguments: %d instead of 2."), argCount)); } } #endif // --- Support for named collections #if WXSQLITE3_USE_NAMED_COLLECTIONS // The following code is based on the SQLite test_intarray source code. #include #include /// Definition of the sqlite3_intarray object (internal) struct sqlite3_intarray { int n; // Number of elements in the array sqlite3_int64* a; // Contents of the array void (*xFree)(void*); // Function used to free a[] }; // Objects used internally by the virtual table implementation typedef struct intarray_vtab intarray_vtab; typedef struct intarray_cursor intarray_cursor; /// Definition of intarray table object (internal) struct intarray_vtab { sqlite3_vtab base; // Base class sqlite3_intarray* pContent; // Content of the integer array }; /// Definition of intarray cursor object (internal) struct intarray_cursor { sqlite3_vtab_cursor base; // Base class int i; // Current cursor position }; // Free an sqlite3_intarray object. static void intarrayFree(sqlite3_intarray* p) { if (p->a != NULL && p->xFree) { p->xFree(p->a); } sqlite3_free(p); } // Table destructor for the intarray module. static int intarrayDestroy(sqlite3_vtab* p) { intarray_vtab* pVtab = (intarray_vtab*)p; sqlite3_free(pVtab); return 0; } // Table constructor for the intarray module. static int intarrayCreate(sqlite3* db, // Database where module is created void* pAux, // clientdata for the module int /*argc*/, // Number of arguments const char* const* /*argv*/, // Value for all arguments sqlite3_vtab** ppVtab, // Write the new virtual table object here char** /*pzErr*/) // Put error message text here { int rc = SQLITE_NOMEM; intarray_vtab* pVtab = (intarray_vtab*) sqlite3_malloc(sizeof(intarray_vtab)); if (pVtab) { memset(pVtab, 0, sizeof(intarray_vtab)); pVtab->pContent = (sqlite3_intarray*)pAux; rc = sqlite3_declare_vtab(db, "CREATE TABLE x(value INTEGER PRIMARY KEY)"); } *ppVtab = (sqlite3_vtab*)pVtab; return rc; } // Open a new cursor on the intarray table. static int intarrayOpen(sqlite3_vtab* /*pVTab*/, sqlite3_vtab_cursor** ppCursor) { int rc = SQLITE_NOMEM; intarray_cursor* pCur = (intarray_cursor*) sqlite3_malloc(sizeof(intarray_cursor)); if (pCur) { memset(pCur, 0, sizeof(intarray_cursor)); *ppCursor = (sqlite3_vtab_cursor *)pCur; rc = SQLITE_OK; } return rc; } // Close a intarray table cursor. static int intarrayClose(sqlite3_vtab_cursor* cur) { intarray_cursor* pCur = (intarray_cursor*)cur; sqlite3_free(pCur); return SQLITE_OK; } // Retrieve a column of data. static int intarrayColumn(sqlite3_vtab_cursor* cur, sqlite3_context* ctx, int /*i*/) { intarray_cursor* pCur = (intarray_cursor*)cur; intarray_vtab* pVtab = (intarray_vtab*)cur->pVtab; if (pCur->i >= 0 && pCur->i < pVtab->pContent->n) { sqlite3_result_int64(ctx, pVtab->pContent->a[pCur->i]); } return SQLITE_OK; } // Retrieve the current rowid. static int intarrayRowid(sqlite3_vtab_cursor* cur, sqlite_int64* pRowid) { intarray_cursor* pCur = (intarray_cursor*)cur; *pRowid = pCur->i; return SQLITE_OK; } static int intarrayEof(sqlite3_vtab_cursor* cur) { intarray_cursor* pCur = (intarray_cursor*)cur; intarray_vtab* pVtab = (intarray_vtab*)cur->pVtab; return pCur->i >= pVtab->pContent->n; } // Advance the cursor to the next row. static int intarrayNext(sqlite3_vtab_cursor* cur) { intarray_cursor* pCur = (intarray_cursor*)cur; pCur->i++; return SQLITE_OK; } // Reset a intarray table cursor. static int intarrayFilter(sqlite3_vtab_cursor* pVtabCursor, int /*idxNum*/, const char* /*idxStr*/, int /*argc*/, sqlite3_value** /*argv*/) { intarray_cursor* pCur = (intarray_cursor*) pVtabCursor; pCur->i = 0; return SQLITE_OK; } // Analyse the WHERE condition. static int intarrayBestIndex(sqlite3_vtab* /*tab*/, sqlite3_index_info* /*pIdxInfo*/) { return SQLITE_OK; } // Definition of a virtual table module for integer collections static sqlite3_module intarrayModule = { 0, // iVersion intarrayCreate, // xCreate - create a new virtual table intarrayCreate, // xConnect - connect to an existing vtab intarrayBestIndex, // xBestIndex - find the best query index intarrayDestroy, // xDisconnect - disconnect a vtab intarrayDestroy, // xDestroy - destroy a vtab intarrayOpen, // xOpen - open a cursor intarrayClose, // xClose - close a cursor intarrayFilter, // xFilter - configure scan constraints intarrayNext, // xNext - advance a cursor intarrayEof, // xEof intarrayColumn, // xColumn - read data intarrayRowid, // xRowid - read data 0, // xUpdate 0, // xBegin 0, // xSync 0, // xCommit 0, // xRollback 0, // xFindMethod 0, // xRename #if SQLITE_VERSION_NUMBER >= 3007007 0, // xSavepoint 0, // xRelease 0 // xRollbackTo #endif }; /// Definition of the sqlite3_chararray object (internal) struct sqlite3_chararray { int n; // Number of elements in the array char** a; // Contents of the array void (*xFree)(void*); // Function used to free a[] }; // Objects used internally by the virtual table implementation typedef struct chararray_vtab chararray_vtab; typedef struct chararray_cursor chararray_cursor; /// Definition of chararray table object (internal) struct chararray_vtab { sqlite3_vtab base; // Base class sqlite3_chararray* pContent; // Content of the char array }; /// Definition of chararray cursor object (internal) struct chararray_cursor { sqlite3_vtab_cursor base; // Base class int i; // Current cursor position }; // Free an sqlite3_chararray object. static void chararrayFree(sqlite3_chararray* p) { if (p->a != NULL && p->xFree) { int j; for (j = 0; j < p->n; ++j) { p->xFree(p->a[j]); } p->xFree(p->a); } sqlite3_free(p); } // Table destructor for the chararray module. static int chararrayDestroy(sqlite3_vtab* p) { chararray_vtab* pVtab = (chararray_vtab*)p; sqlite3_free(pVtab); return 0; } // Table constructor for the chararray module. static int chararrayCreate(sqlite3* db, // Database where module is created void* pAux, // clientdata for the module int /*argc*/, // Number of arguments const char* const* /*argv*/, // Value for all arguments sqlite3_vtab** ppVtab, // Write the new virtual table object here char** /*pzErr*/) // Put error message text here { int rc = SQLITE_NOMEM; chararray_vtab* pVtab = (chararray_vtab*) sqlite3_malloc(sizeof(chararray_vtab)); if (pVtab) { memset(pVtab, 0, sizeof(chararray_vtab)); pVtab->pContent = (sqlite3_chararray*) pAux; rc = sqlite3_declare_vtab(db, "CREATE TABLE x(value CHAR PRIMARY KEY)"); } *ppVtab = (sqlite3_vtab*) pVtab; return rc; } // Open a new cursor on the chararray table. static int chararrayOpen(sqlite3_vtab* /*pVTab*/, sqlite3_vtab_cursor** ppCursor) { int rc = SQLITE_NOMEM; chararray_cursor* pCur = (chararray_cursor*) sqlite3_malloc(sizeof(chararray_cursor)); if (pCur) { memset(pCur, 0, sizeof(chararray_cursor)); *ppCursor = (sqlite3_vtab_cursor *)pCur; rc = SQLITE_OK; } return rc; } // Close a chararray table cursor. static int chararrayClose(sqlite3_vtab_cursor* cur) { chararray_cursor* pCur = (chararray_cursor*)cur; sqlite3_free(pCur); return SQLITE_OK; } // Retrieve a column of data. static int chararrayColumn(sqlite3_vtab_cursor* cur, sqlite3_context* ctx, int /*i*/) { chararray_cursor* pCur = (chararray_cursor*)cur; chararray_vtab* pVtab = (chararray_vtab*)cur->pVtab; if (pCur->i >= 0 && pCur->i < pVtab->pContent->n) { sqlite3_result_text(ctx, pVtab->pContent->a[pCur->i], -1, SQLITE_STATIC); } return SQLITE_OK; } // Retrieve the current rowid. static int chararrayRowid(sqlite3_vtab_cursor* cur, sqlite_int64* pRowid) { chararray_cursor* pCur = (chararray_cursor*)cur; *pRowid = pCur->i; return SQLITE_OK; } static int chararrayEof(sqlite3_vtab_cursor* cur) { chararray_cursor* pCur = (chararray_cursor*)cur; chararray_vtab* pVtab = (chararray_vtab*)cur->pVtab; return pCur->i >= pVtab->pContent->n; } // Advance the cursor to the next row. static int chararrayNext(sqlite3_vtab_cursor* cur) { chararray_cursor* pCur = (chararray_cursor*)cur; pCur->i++; return SQLITE_OK; } // Reset a chararray table cursor. static int chararrayFilter(sqlite3_vtab_cursor* pVtabCursor, int /*idxNum*/, const char* /*idxStr*/, int /*argc*/, sqlite3_value** /*argv*/) { chararray_cursor *pCur = (chararray_cursor *)pVtabCursor; pCur->i = 0; return SQLITE_OK; } // Analyse the WHERE condition. static int chararrayBestIndex(sqlite3_vtab* /*tab*/, sqlite3_index_info* /*pIdxInfo*/) { return SQLITE_OK; } // Definition of a virtual table module for string collections static sqlite3_module chararrayModule = { 0, // iVersion chararrayCreate, // xCreate - create a new virtual table chararrayCreate, // xConnect - connect to an existing vtab chararrayBestIndex, // xBestIndex - find the best query index chararrayDestroy, // xDisconnect - disconnect a vtab chararrayDestroy, // xDestroy - destroy a vtab chararrayOpen, // xOpen - open a cursor chararrayClose, // xClose - close a cursor chararrayFilter, // xFilter - configure scan constraints chararrayNext, // xNext - advance a cursor chararrayEof, // xEof chararrayColumn, // xColumn - read data chararrayRowid, // xRowid - read data 0, // xUpdate 0, // xBegin 0, // xSync 0, // xCommit 0, // xRollback 0, // xFindMethod 0, // xRename #if SQLITE_VERSION_NUMBER >= 3007007 0, // xSavepoint 0, // xRelease 0 // xRollbackTo #endif }; #endif // WXSQLITE3_USE_NAMED_COLLECTIONS wxSQLite3NamedCollection::wxSQLite3NamedCollection() { m_name = wxEmptyString; m_data = NULL; } wxSQLite3NamedCollection::wxSQLite3NamedCollection(const wxString& collectionName, void* collectionData) { m_name = collectionName; m_data = collectionData; } wxSQLite3NamedCollection::wxSQLite3NamedCollection(const wxSQLite3NamedCollection& collection) : m_name(collection.m_name), m_data(collection.m_data) { } wxSQLite3NamedCollection& wxSQLite3NamedCollection::operator=(const wxSQLite3NamedCollection& collection) { if (this != &collection) { m_name = collection.m_name; m_data = collection.m_data; } return *this; } wxSQLite3NamedCollection::~wxSQLite3NamedCollection() { } wxSQLite3IntegerCollection::wxSQLite3IntegerCollection() : wxSQLite3NamedCollection(wxEmptyString, NULL) { } wxSQLite3IntegerCollection::wxSQLite3IntegerCollection(const wxSQLite3IntegerCollection& collection) : wxSQLite3NamedCollection(collection) { } wxSQLite3IntegerCollection& wxSQLite3IntegerCollection::operator=(const wxSQLite3IntegerCollection& collection) { if (this != &collection) { wxSQLite3NamedCollection::operator=(collection); } return *this; } wxSQLite3IntegerCollection::wxSQLite3IntegerCollection(const wxString& collectionName, void* collectionData) : wxSQLite3NamedCollection(collectionName, collectionData) { } wxSQLite3IntegerCollection::~wxSQLite3IntegerCollection() { } void wxSQLite3IntegerCollection::Bind(const wxArrayInt& integerCollection) { size_t n = integerCollection.Count(); sqlite3_intarray* pIntArray = (sqlite3_intarray*) m_data; if (m_data != NULL) { if (pIntArray->a != NULL && pIntArray->xFree) { pIntArray->xFree(pIntArray->a); } } pIntArray->n = n; if (n > 0) { pIntArray->a = (sqlite3_int64*) sqlite3_malloc(sizeof(sqlite3_int64)*n); pIntArray->xFree = sqlite3_free; } else { pIntArray->a = NULL; pIntArray->xFree = NULL; } size_t j; for (j = 0; j < n; ++j) { pIntArray->a[j] = integerCollection[j]; } } void wxSQLite3IntegerCollection::Bind(int n, int* integerCollection) { sqlite3_intarray* pIntArray = (sqlite3_intarray*) m_data; if (m_data != NULL) { if (pIntArray->a != NULL && pIntArray->xFree) { pIntArray->xFree(pIntArray->a); } } pIntArray->n = n; if (n > 0) { pIntArray->a = (sqlite3_int64*) sqlite3_malloc(sizeof(sqlite3_int64)*n); pIntArray->xFree = sqlite3_free; } else { pIntArray->a = NULL; pIntArray->xFree = NULL; } int j; for (j = 0; j < n; ++j) { pIntArray->a[j] = integerCollection[j]; } } wxSQLite3IntegerCollection wxSQLite3Database::CreateIntegerCollection(const wxString& collectionName) { #if WXSQLITE3_USE_NAMED_COLLECTIONS CheckDatabase(); int rc = SQLITE_OK; wxCharBuffer strCollectionName = collectionName.ToUTF8(); const char* zName = strCollectionName; sqlite3_intarray* p = (sqlite3_intarray*) sqlite3_malloc( sizeof(*p) ); if (p == 0) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOMEM); } p->n = 0; p->a= NULL; p->xFree = NULL; rc = sqlite3_create_module_v2(m_db->m_db, zName, &intarrayModule, p, (void(*)(void*))intarrayFree); if (rc == SQLITE_OK) { wxSQLite3StatementBuffer zBuffer; const char* zSql = zBuffer.Format("CREATE VIRTUAL TABLE temp.%Q USING %Q", zName, zName); rc = sqlite3_exec(m_db->m_db, zSql, 0, 0, 0); } if (rc != SQLITE_OK) { const char* localError = sqlite3_errmsg(m_db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } return wxSQLite3IntegerCollection(collectionName, p); #else wxUnusedVar(collectionName); throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOCOLLECTIONS); #endif // WXSQLITE3_USE_NAMED_COLLECTIONS } wxSQLite3StringCollection::wxSQLite3StringCollection() : wxSQLite3NamedCollection(wxEmptyString, NULL) { } wxSQLite3StringCollection::wxSQLite3StringCollection(const wxSQLite3StringCollection& collection) : wxSQLite3NamedCollection(collection) { } wxSQLite3StringCollection& wxSQLite3StringCollection::operator=(const wxSQLite3StringCollection& collection) { if (this != &collection) { wxSQLite3StringCollection::operator=(collection); } return *this; } wxSQLite3StringCollection::wxSQLite3StringCollection(const wxString& collectionName, void* collectionData) : wxSQLite3NamedCollection(collectionName, collectionData) { } wxSQLite3StringCollection::~wxSQLite3StringCollection() { } void wxSQLite3StringCollection::Bind(const wxArrayString& stringCollection) { size_t n = stringCollection.Count(); sqlite3_chararray* pCharArray = (sqlite3_chararray*) m_data; if (m_data != NULL) { if (pCharArray->a != NULL && pCharArray->xFree) { pCharArray->xFree(pCharArray->a); } } pCharArray->n = n; if (n > 0) { pCharArray->a = (char**) sqlite3_malloc(sizeof(char*)*n); pCharArray->xFree = sqlite3_free; } else { pCharArray->a = NULL; pCharArray->xFree = NULL; } size_t j; for (j = 0; j < n; ++j) { wxCharBuffer strValue = stringCollection[j].ToUTF8(); const char* zValue = strValue; size_t k = strlen(zValue) + 1; pCharArray->a[j] = (char*) sqlite3_malloc(sizeof(char)*k); strcpy(pCharArray->a[j], zValue); } } wxSQLite3StringCollection wxSQLite3Database::CreateStringCollection(const wxString& collectionName) { #if WXSQLITE3_USE_NAMED_COLLECTIONS CheckDatabase(); int rc = SQLITE_OK; wxCharBuffer strCollectionName = collectionName.ToUTF8(); const char* zName = strCollectionName; sqlite3_chararray* p = (sqlite3_chararray*) sqlite3_malloc( sizeof(*p) ); if (p == 0) { throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOMEM); } p->n = 0; p->a= NULL; p->xFree = NULL; rc = sqlite3_create_module_v2(m_db->m_db, zName, &chararrayModule, p, (void(*)(void*))chararrayFree); if (rc == SQLITE_OK) { wxSQLite3StatementBuffer zBuffer; const char* zSql = zBuffer.Format("CREATE VIRTUAL TABLE temp.%Q USING %Q", zName, zName); rc = sqlite3_exec(m_db->m_db, zSql, 0, 0, 0); } if (rc != SQLITE_OK) { const char* localError = sqlite3_errmsg(m_db->m_db); throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); } return wxSQLite3StringCollection(collectionName, p); #else wxUnusedVar(collectionName); throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_NOCOLLECTIONS); #endif // WXSQLITE3_USE_NAMED_COLLECTIONS }