diff options
Diffstat (limited to 'src/sqlite3_utils.cpp')
| -rw-r--r-- | src/sqlite3_utils.cpp | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/src/sqlite3_utils.cpp b/src/sqlite3_utils.cpp new file mode 100644 index 00000000..673eb89c --- /dev/null +++ b/src/sqlite3_utils.cpp @@ -0,0 +1,194 @@ +/****************************************************************************** + * Project: PROJ + * Purpose: SQLite3 related utilities + * Author: Even Rouault, <even.rouault at spatialys.com> + * + ****************************************************************************** + * Copyright (c) 2019, Even Rouault, <even.rouault at spatialys.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Weffc++" +#endif + +#include "sqlite3_utils.hpp" + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + +#include <cstdlib> +#include <cstring> +#include <sstream> // std::ostringstream + +NS_PROJ_START + +// --------------------------------------------------------------------------- + +SQLite3VFS::SQLite3VFS(sqlite3_vfs *vfs) : vfs_(vfs) {} + +// --------------------------------------------------------------------------- + +SQLite3VFS::~SQLite3VFS() { + if (vfs_) { + sqlite3_vfs_unregister(vfs_); + delete vfs_; + } +} + +// --------------------------------------------------------------------------- + +struct pj_sqlite3_vfs : public sqlite3_vfs { + std::string namePtr{}; + bool fakeSync = false; + bool fakeLock = false; +}; + +// --------------------------------------------------------------------------- + +const char *SQLite3VFS::name() const { + return static_cast<pj_sqlite3_vfs *>(vfs_)->namePtr.c_str(); +} + +// --------------------------------------------------------------------------- + +typedef int (*ClosePtr)(sqlite3_file *); + +// --------------------------------------------------------------------------- + +static int VFSClose(sqlite3_file *file) { + sqlite3_vfs *defaultVFS = sqlite3_vfs_find(nullptr); + assert(defaultVFS); + ClosePtr defaultClosePtr; + std::memcpy(&defaultClosePtr, + reinterpret_cast<char *>(file) + defaultVFS->szOsFile, + sizeof(ClosePtr)); + void *methods = const_cast<sqlite3_io_methods *>(file->pMethods); + int ret = defaultClosePtr(file); + std::free(methods); + return ret; +} + +// --------------------------------------------------------------------------- + +static int VSFNoOpLockUnlockSync(sqlite3_file *, int) { return SQLITE_OK; } + +// --------------------------------------------------------------------------- + +static int VFSCustomOpen(sqlite3_vfs *vfs, const char *name, sqlite3_file *file, + int flags, int *outFlags) { + auto realVFS = static_cast<pj_sqlite3_vfs *>(vfs); + sqlite3_vfs *defaultVFS = static_cast<sqlite3_vfs *>(vfs->pAppData); + int ret = defaultVFS->xOpen(defaultVFS, name, file, flags, outFlags); + if (ret == SQLITE_OK) { + ClosePtr defaultClosePtr = file->pMethods->xClose; + assert(defaultClosePtr); + sqlite3_io_methods *methods = static_cast<sqlite3_io_methods *>( + std::malloc(sizeof(sqlite3_io_methods))); + if (!methods) { + file->pMethods->xClose(file); + return SQLITE_NOMEM; + } + memcpy(methods, file->pMethods, sizeof(sqlite3_io_methods)); + methods->xClose = VFSClose; + if (realVFS->fakeSync) { + // Disable xSync because it can be significantly slow and we don't + // need + // that level of data integrity garanty for the cache. + methods->xSync = VSFNoOpLockUnlockSync; + } + if (realVFS->fakeLock) { + methods->xLock = VSFNoOpLockUnlockSync; + methods->xUnlock = VSFNoOpLockUnlockSync; + } + file->pMethods = methods; + // Save original xClose pointer at end of file structure + std::memcpy(reinterpret_cast<char *>(file) + defaultVFS->szOsFile, + &defaultClosePtr, sizeof(ClosePtr)); + } + return ret; +} + +// --------------------------------------------------------------------------- + +static int VFSCustomAccess(sqlite3_vfs *vfs, const char *zName, int flags, + int *pResOut) { + sqlite3_vfs *defaultVFS = static_cast<sqlite3_vfs *>(vfs->pAppData); + // Do not bother stat'ing for journal or wal files + if (std::strstr(zName, "-journal") || std::strstr(zName, "-wal")) { + *pResOut = false; + return SQLITE_OK; + } + return defaultVFS->xAccess(defaultVFS, zName, flags, pResOut); +} + +// --------------------------------------------------------------------------- + +std::unique_ptr<SQLite3VFS> SQLite3VFS::create(bool fakeSync, bool fakeLock, + bool skipStatJournalAndWAL) { + sqlite3_vfs *defaultVFS = sqlite3_vfs_find(nullptr); + assert(defaultVFS); + + auto vfs = new pj_sqlite3_vfs(); + vfs->fakeSync = fakeSync; + vfs->fakeLock = fakeLock; + + auto vfsUnique = std::unique_ptr<SQLite3VFS>(new SQLite3VFS(vfs)); + + std::ostringstream buffer; + buffer << vfs; + vfs->namePtr = buffer.str(); + + vfs->iVersion = 1; + vfs->szOsFile = defaultVFS->szOsFile + sizeof(ClosePtr); + vfs->mxPathname = defaultVFS->mxPathname; + vfs->zName = vfs->namePtr.c_str(); + vfs->pAppData = defaultVFS; + vfs->xOpen = VFSCustomOpen; + vfs->xDelete = defaultVFS->xDelete; + vfs->xAccess = + skipStatJournalAndWAL ? VFSCustomAccess : defaultVFS->xAccess; + vfs->xFullPathname = defaultVFS->xFullPathname; + vfs->xDlOpen = defaultVFS->xDlOpen; + vfs->xDlError = defaultVFS->xDlError; + vfs->xDlSym = defaultVFS->xDlSym; + vfs->xDlClose = defaultVFS->xDlClose; + vfs->xRandomness = defaultVFS->xRandomness; + vfs->xSleep = defaultVFS->xSleep; + vfs->xCurrentTime = defaultVFS->xCurrentTime; + vfs->xGetLastError = defaultVFS->xGetLastError; + vfs->xCurrentTimeInt64 = defaultVFS->xCurrentTimeInt64; + if (sqlite3_vfs_register(vfs, false) == SQLITE_OK) { + return vfsUnique; + } + delete vfsUnique->vfs_; + vfsUnique->vfs_ = nullptr; + return nullptr; +} + +// --------------------------------------------------------------------------- + +SQLiteStatement::SQLiteStatement(sqlite3_stmt *hStmtIn) : hStmt(hStmtIn) {} + +// --------------------------------------------------------------------------- + +NS_PROJ_END |
