Coverage Report

Created: 2026-09-14 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/proj/src/sqlite3_utils.cpp
Line
Count
Source
1
/******************************************************************************
2
 * Project:  PROJ
3
 * Purpose:  SQLite3 related utilities
4
 * Author:   Even Rouault, <even.rouault at spatialys.com>
5
 *
6
 ******************************************************************************
7
 * Copyright (c) 2019, Even Rouault, <even.rouault at spatialys.com>
8
 *
9
 * Permission is hereby granted, free of charge, to any person obtaining a
10
 * copy of this software and associated documentation files (the "Software"),
11
 * to deal in the Software without restriction, including without limitation
12
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13
 * and/or sell copies of the Software, and to permit persons to whom the
14
 * Software is furnished to do so, subject to the following conditions:
15
 *
16
 * The above copyright notice and this permission notice shall be included
17
 * in all copies or substantial portions of the Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25
 * DEALINGS IN THE SOFTWARE.
26
 *****************************************************************************/
27
28
#ifdef __GNUC__
29
#pragma GCC diagnostic push
30
#pragma GCC diagnostic ignored "-Weffc++"
31
#endif
32
33
#include "sqlite3_utils.hpp"
34
35
#ifdef __GNUC__
36
#pragma GCC diagnostic pop
37
#endif
38
39
#ifdef EMBED_RESOURCE_FILES
40
#include "memvfs.h"
41
#endif
42
43
#include "filemanager.hpp"
44
45
#include <cstdlib>
46
#include <cstring>
47
#include <sstream> // std::ostringstream
48
49
NS_PROJ_START
50
51
// ---------------------------------------------------------------------------
52
53
0
pj_sqlite3_vfs::~pj_sqlite3_vfs() = default;
54
55
// ---------------------------------------------------------------------------
56
57
0
SQLite3VFS::SQLite3VFS(pj_sqlite3_vfs *vfs) : vfs_(vfs) {}
58
59
// ---------------------------------------------------------------------------
60
61
0
SQLite3VFS::~SQLite3VFS() {
62
0
    if (vfs_) {
63
0
        sqlite3_vfs_unregister(&(vfs_->base));
64
0
        delete vfs_;
65
0
    }
66
0
}
67
68
// ---------------------------------------------------------------------------
69
70
0
const char *SQLite3VFS::name() const { return vfs_->namePtr.c_str(); }
71
72
// ---------------------------------------------------------------------------
73
74
typedef int (*ClosePtr)(sqlite3_file *);
75
76
// ---------------------------------------------------------------------------
77
78
0
static int VFSClose(sqlite3_file *file) {
79
0
    sqlite3_vfs *defaultVFS = sqlite3_vfs_find(nullptr);
80
0
    assert(defaultVFS);
81
0
    ClosePtr defaultClosePtr;
82
0
    std::memcpy(&defaultClosePtr,
83
0
                reinterpret_cast<char *>(file) + defaultVFS->szOsFile,
84
0
                sizeof(ClosePtr));
85
0
    void *methods = const_cast<sqlite3_io_methods *>(file->pMethods);
86
0
    int ret = defaultClosePtr(file);
87
0
    std::free(methods);
88
0
    return ret;
89
0
}
90
91
// ---------------------------------------------------------------------------
92
93
0
static int VSFNoOpLockUnlockSync(sqlite3_file *, int) { return SQLITE_OK; }
94
95
// ---------------------------------------------------------------------------
96
97
namespace {
98
99
struct pj_sqlite3_customvfs_appdata {
100
    sqlite3_vfs *defaultVFS = nullptr;
101
    bool fakeSync = false;
102
    bool fakeLock = false;
103
};
104
105
struct pj_sqlite3_customvfs : public pj_sqlite3_vfs {
106
0
    ~pj_sqlite3_customvfs() override {
107
0
        delete static_cast<pj_sqlite3_customvfs_appdata *>(base.pAppData);
108
0
        base.pAppData = nullptr;
109
0
    }
110
};
111
} // namespace
112
113
static int VFSCustomOpen(sqlite3_vfs *vfs, const char *name, sqlite3_file *file,
114
0
                         int flags, int *outFlags) {
115
0
    pj_sqlite3_customvfs_appdata *appdata =
116
0
        static_cast<pj_sqlite3_customvfs_appdata *>(vfs->pAppData);
117
0
    sqlite3_vfs *defaultVFS = appdata->defaultVFS;
118
0
    int ret = defaultVFS->xOpen(defaultVFS, name, file, flags, outFlags);
119
0
    if (ret == SQLITE_OK) {
120
0
        ClosePtr defaultClosePtr = file->pMethods->xClose;
121
0
        assert(defaultClosePtr);
122
0
        sqlite3_io_methods *methods = static_cast<sqlite3_io_methods *>(
123
0
            std::malloc(sizeof(sqlite3_io_methods)));
124
0
        if (!methods) {
125
0
            file->pMethods->xClose(file);
126
0
            return SQLITE_NOMEM;
127
0
        }
128
0
        memcpy(methods, file->pMethods, sizeof(sqlite3_io_methods));
129
0
        methods->xClose = VFSClose;
130
0
        if (appdata->fakeSync) {
131
            // Disable xSync because it can be significantly slow and we don't
132
            // need
133
            // that level of data integrity guarantee for the cache.
134
0
            methods->xSync = VSFNoOpLockUnlockSync;
135
0
        }
136
0
        if (appdata->fakeLock) {
137
0
            methods->xLock = VSFNoOpLockUnlockSync;
138
0
            methods->xUnlock = VSFNoOpLockUnlockSync;
139
0
        }
140
0
        file->pMethods = methods;
141
        // Save original xClose pointer at end of file structure
142
0
        std::memcpy(reinterpret_cast<char *>(file) + defaultVFS->szOsFile,
143
0
                    &defaultClosePtr, sizeof(ClosePtr));
144
0
    }
145
0
    return ret;
146
0
}
147
148
// ---------------------------------------------------------------------------
149
150
static int VFSCustomAccess(sqlite3_vfs *vfs, const char *zName, int flags,
151
0
                           int *pResOut) {
152
0
    sqlite3_vfs *defaultVFS = static_cast<sqlite3_vfs *>(vfs->pAppData);
153
    // Do not bother stat'ing for journal or wal files
154
0
    if (std::strstr(zName, "-journal") || std::strstr(zName, "-wal")) {
155
0
        *pResOut = false;
156
0
        return SQLITE_OK;
157
0
    }
158
0
    return defaultVFS->xAccess(defaultVFS, zName, flags, pResOut);
159
0
}
160
161
// ---------------------------------------------------------------------------
162
163
// SQLite3 logging infrastructure
164
0
static void projSqlite3LogCallback(void *, int iErrCode, const char *zMsg) {
165
0
    fprintf(stderr, "SQLite3 message: (code %d) %s\n", iErrCode, zMsg);
166
0
}
167
168
namespace {
169
struct InstallSqliteLogger {
170
0
    InstallSqliteLogger() {
171
0
        if (getenv("PROJ_LOG_SQLITE3") != nullptr) {
172
0
            sqlite3_config(SQLITE_CONFIG_LOG, projSqlite3LogCallback, nullptr);
173
0
        }
174
0
    }
175
176
0
    static InstallSqliteLogger &GetSingleton() {
177
0
        static InstallSqliteLogger installSqliteLogger;
178
0
        return installSqliteLogger;
179
0
    }
180
};
181
} // namespace
182
183
// ---------------------------------------------------------------------------
184
185
std::unique_ptr<SQLite3VFS> SQLite3VFS::create(bool fakeSync, bool fakeLock,
186
0
                                               bool skipStatJournalAndWAL) {
187
188
    // Install SQLite3 logger if PROJ_LOG_SQLITE3 env var is defined
189
0
    InstallSqliteLogger::GetSingleton();
190
191
    // Call to sqlite3_initialize() is normally not needed, except for
192
    // people building SQLite3 with -DSQLITE_OMIT_AUTOINIT
193
0
    sqlite3_initialize();
194
0
    sqlite3_vfs *defaultVFS = sqlite3_vfs_find(nullptr);
195
0
    assert(defaultVFS);
196
197
0
    auto vfs = new pj_sqlite3_customvfs();
198
199
0
    auto vfsUnique = std::unique_ptr<SQLite3VFS>(new SQLite3VFS(vfs));
200
201
0
    std::ostringstream buffer;
202
0
    buffer << vfs;
203
0
    vfs->namePtr = buffer.str();
204
205
0
    vfs->base.iVersion = 1;
206
0
    vfs->base.szOsFile = defaultVFS->szOsFile + sizeof(ClosePtr);
207
0
    vfs->base.mxPathname = defaultVFS->mxPathname;
208
0
    vfs->base.zName = vfs->namePtr.c_str();
209
0
    pj_sqlite3_customvfs_appdata *appdata = new pj_sqlite3_customvfs_appdata;
210
0
    appdata->fakeSync = fakeSync;
211
0
    appdata->fakeLock = fakeLock;
212
0
    appdata->defaultVFS = defaultVFS;
213
0
    vfs->base.pAppData = appdata;
214
0
    vfs->base.xOpen = VFSCustomOpen;
215
0
    vfs->base.xDelete = defaultVFS->xDelete;
216
0
    vfs->base.xAccess =
217
0
        skipStatJournalAndWAL ? VFSCustomAccess : defaultVFS->xAccess;
218
0
    vfs->base.xFullPathname = defaultVFS->xFullPathname;
219
0
    vfs->base.xDlOpen = defaultVFS->xDlOpen;
220
0
    vfs->base.xDlError = defaultVFS->xDlError;
221
0
    vfs->base.xDlSym = defaultVFS->xDlSym;
222
0
    vfs->base.xDlClose = defaultVFS->xDlClose;
223
0
    vfs->base.xRandomness = defaultVFS->xRandomness;
224
0
    vfs->base.xSleep = defaultVFS->xSleep;
225
0
    vfs->base.xCurrentTime = defaultVFS->xCurrentTime;
226
0
    vfs->base.xGetLastError = defaultVFS->xGetLastError;
227
0
    vfs->base.xCurrentTimeInt64 = defaultVFS->xCurrentTimeInt64;
228
0
    if (sqlite3_vfs_register(&(vfs->base), false) == SQLITE_OK) {
229
0
        return vfsUnique;
230
0
    }
231
0
    delete vfsUnique->vfs_;
232
0
    vfsUnique->vfs_ = nullptr;
233
0
    return nullptr;
234
0
}
235
236
// ---------------------------------------------------------------------------
237
238
0
static int VFSNetworkClose(sqlite3_file *file) {
239
0
    File *pj_file;
240
0
    memcpy(&pj_file, reinterpret_cast<char *>(file) + sizeof(sqlite3_file),
241
0
           sizeof(pj_file));
242
0
    delete pj_file;
243
0
    return SQLITE_OK;
244
0
}
245
246
// ---------------------------------------------------------------------------
247
248
static int VFSNetworkRead(sqlite3_file *file, void *pBuffer, int iAmt,
249
0
                          sqlite3_int64 iOffset) {
250
0
    File *pj_file;
251
0
    memcpy(&pj_file, reinterpret_cast<char *>(file) + sizeof(sqlite3_file),
252
0
           sizeof(pj_file));
253
0
    if (!pj_file->seek(iOffset))
254
0
        return SQLITE_IOERR_READ;
255
0
    const int nRead = static_cast<int>(pj_file->read(pBuffer, iAmt));
256
0
    if (nRead < iAmt) {
257
0
        memset(static_cast<char *>(pBuffer) + nRead, 0, iAmt - nRead);
258
0
        return SQLITE_IOERR_SHORT_READ;
259
0
    }
260
0
    return SQLITE_OK;
261
0
}
262
263
// ---------------------------------------------------------------------------
264
265
0
static int VFSNetworkWrite(sqlite3_file *, const void *, int, sqlite3_int64) {
266
0
    return SQLITE_IOERR_WRITE;
267
0
}
268
269
// ---------------------------------------------------------------------------
270
271
0
static int VFSNetworkFileSize(sqlite3_file *file, sqlite3_int64 *pSize) {
272
0
    File *pj_file;
273
0
    memcpy(&pj_file, reinterpret_cast<char *>(file) + sizeof(sqlite3_file),
274
0
           sizeof(pj_file));
275
0
    pj_file->seek(0, SEEK_END);
276
0
    *pSize = pj_file->tell();
277
0
    return SQLITE_OK;
278
0
}
279
280
// ---------------------------------------------------------------------------
281
282
0
static int VFSNetworkTruncate(sqlite3_file *, sqlite3_int64) {
283
0
    return SQLITE_IOERR_TRUNCATE;
284
0
}
285
286
// ---------------------------------------------------------------------------
287
288
0
static int VFSNetworkSync(sqlite3_file *, int) { return SQLITE_OK; }
289
290
// ---------------------------------------------------------------------------
291
292
0
static int VFSNetworkLock(sqlite3_file *, int) { return SQLITE_OK; }
293
294
// ---------------------------------------------------------------------------
295
296
0
static int VFSNetworkUnlock(sqlite3_file *, int) { return SQLITE_OK; }
297
298
// ---------------------------------------------------------------------------
299
300
0
static int VFSNetworkCheckReservedLock(sqlite3_file *, int *pResOut) {
301
0
    *pResOut = 0;
302
0
    return SQLITE_OK;
303
0
}
304
305
// ---------------------------------------------------------------------------
306
307
0
static int VFSNetworkFileControl(sqlite3_file *, int, void *) {
308
0
    return SQLITE_NOTFOUND;
309
0
}
310
311
// ---------------------------------------------------------------------------
312
313
0
static int VFSNetworkSectorSize(sqlite3_file *) { return 0; }
314
315
// ---------------------------------------------------------------------------
316
317
0
static int VFSNetworkDeviceCharacteristics(sqlite3_file *) { return 0; }
318
319
// ---------------------------------------------------------------------------
320
321
static const sqlite3_io_methods VFSNetworkIOMethods = {
322
    1,
323
    VFSNetworkClose,
324
    VFSNetworkRead,
325
    VFSNetworkWrite,
326
    VFSNetworkTruncate,
327
    VFSNetworkSync,
328
    VFSNetworkFileSize,
329
    VFSNetworkLock,
330
    VFSNetworkUnlock,
331
    VFSNetworkCheckReservedLock,
332
    VFSNetworkFileControl,
333
    VFSNetworkSectorSize,
334
    VFSNetworkDeviceCharacteristics,
335
    nullptr, // xShmMap
336
    nullptr, // xShmLock
337
    nullptr, // xShmBarrier
338
    nullptr, // xShmUnmap
339
    nullptr, // xFetch
340
    nullptr, // xUnfetch
341
};
342
343
static int VFSNetworkOpen(sqlite3_vfs *vfs, const char *name,
344
                          sqlite3_file *file, int /*flags*/,
345
0
                          int * /*outFlags*/) {
346
0
    if (!name)
347
0
        return SQLITE_CANTOPEN;
348
0
    PJ_CONTEXT *ctx = static_cast<PJ_CONTEXT *>(vfs->pAppData);
349
0
    auto pjFile = pj_network_file_open(ctx, name);
350
0
    if (!pjFile)
351
0
        return SQLITE_CANTOPEN;
352
0
    file->pMethods = &VFSNetworkIOMethods;
353
0
    File *pj_file_raw = pjFile.release();
354
0
    memcpy(reinterpret_cast<char *>(file) + sizeof(sqlite3_file), &pj_file_raw,
355
0
           sizeof(pj_file_raw));
356
357
0
    return SQLITE_OK;
358
0
}
359
360
// ---------------------------------------------------------------------------
361
362
static int VFSNetworkFullPathname(sqlite3_vfs *, const char *zName, int nOut,
363
0
                                  char *zOut) {
364
0
    if (static_cast<int>(strlen(zName)) >= nOut) {
365
0
        fprintf(stderr, "Maximum pathname length reserved for SQLite3 VFS "
366
0
                        "isn't large enough.\n");
367
0
        return SQLITE_CANTOPEN;
368
0
    }
369
0
    strncpy(zOut, zName, nOut);
370
0
    zOut[nOut - 1] = '\0';
371
0
    return SQLITE_OK;
372
0
}
373
374
// ---------------------------------------------------------------------------
375
376
0
static int VFSNetworkAccess(sqlite3_vfs *, const char *, int, int *pResOut) {
377
0
    *pResOut = 0;
378
0
    return SQLITE_OK;
379
0
}
380
381
// ---------------------------------------------------------------------------
382
383
0
static int VFSNetworkDelete(sqlite3_vfs *, const char *, int) {
384
0
    return SQLITE_IOERR_DELETE;
385
0
}
386
387
// ---------------------------------------------------------------------------
388
389
/* static */ std::unique_ptr<SQLite3VFS>
390
0
SQLite3VFS::createNetwork(PJ_CONTEXT *ctx) {
391
    // Install SQLite3 logger if PROJ_LOG_SQLITE3 env var is defined
392
0
    InstallSqliteLogger::GetSingleton();
393
394
    // Call to sqlite3_initialize() is normally not needed, except for
395
    // people building SQLite3 with -DSQLITE_OMIT_AUTOINIT
396
0
    sqlite3_initialize();
397
0
    sqlite3_vfs *defaultVFS = sqlite3_vfs_find(nullptr);
398
0
    assert(defaultVFS);
399
400
0
    auto vfs = new pj_sqlite3_vfs();
401
402
0
    std::ostringstream buffer;
403
0
    buffer << vfs;
404
0
    vfs->namePtr = buffer.str();
405
406
0
    vfs->base.iVersion = 1;
407
0
    vfs->base.szOsFile = sizeof(sqlite3_file) + sizeof(File *);
408
0
    vfs->base.mxPathname = defaultVFS->mxPathname;
409
0
    vfs->base.zName = vfs->namePtr.c_str();
410
0
    vfs->base.pAppData = ctx;
411
0
    vfs->base.xOpen = VFSNetworkOpen;
412
0
    vfs->base.xDelete = VFSNetworkDelete;
413
0
    vfs->base.xAccess = VFSNetworkAccess;
414
0
    vfs->base.xFullPathname = VFSNetworkFullPathname;
415
0
    vfs->base.xDlOpen = defaultVFS->xDlOpen;
416
0
    vfs->base.xDlError = defaultVFS->xDlError;
417
0
    vfs->base.xDlSym = defaultVFS->xDlSym;
418
0
    vfs->base.xDlClose = defaultVFS->xDlClose;
419
0
    vfs->base.xRandomness = defaultVFS->xRandomness;
420
0
    vfs->base.xSleep = defaultVFS->xSleep;
421
0
    vfs->base.xCurrentTime = defaultVFS->xCurrentTime;
422
0
    vfs->base.xGetLastError = defaultVFS->xGetLastError;
423
0
    vfs->base.xCurrentTimeInt64 = defaultVFS->xCurrentTimeInt64;
424
0
    if (sqlite3_vfs_register(&(vfs->base), false) == SQLITE_OK) {
425
0
        return std::unique_ptr<SQLite3VFS>(new SQLite3VFS(vfs));
426
0
    }
427
0
    return nullptr;
428
0
}
429
430
// ---------------------------------------------------------------------------
431
432
#ifdef EMBED_RESOURCE_FILES
433
434
struct pj_sqlite3_memvfs : public pj_sqlite3_vfs {
435
    ~pj_sqlite3_memvfs() override;
436
};
437
438
0
pj_sqlite3_memvfs::~pj_sqlite3_memvfs() {
439
0
    pj_sqlite3_memvfs_deallocate_user_data(&base);
440
0
}
441
442
/* static */
443
std::unique_ptr<SQLite3VFS> SQLite3VFS::createMem(const void *membuffer,
444
0
                                                  size_t bufferSize) {
445
    // Install SQLite3 logger if PROJ_LOG_SQLITE3 env var is defined
446
0
    InstallSqliteLogger::GetSingleton();
447
448
    // Call to sqlite3_initialize() is normally not needed, except for
449
    // people building SQLite3 with -DSQLITE_OMIT_AUTOINIT
450
0
    sqlite3_initialize();
451
452
0
    auto vfs = new pj_sqlite3_memvfs();
453
454
0
    auto vfsUnique = std::unique_ptr<SQLite3VFS>(new SQLite3VFS(vfs));
455
456
0
    std::ostringstream buffer;
457
0
    buffer << vfs;
458
0
    vfs->namePtr = buffer.str();
459
0
    if (pj_sqlite3_memvfs_init(&(vfs->base), vfs->namePtr.c_str(), membuffer,
460
0
                               bufferSize) == SQLITE_OK) {
461
0
        return vfsUnique;
462
0
    }
463
0
    delete vfsUnique->vfs_;
464
0
    vfsUnique->vfs_ = nullptr;
465
0
    return nullptr;
466
0
}
467
468
#endif
469
470
// ---------------------------------------------------------------------------
471
472
0
SQLiteStatement::SQLiteStatement(sqlite3_stmt *hStmtIn) : hStmt(hStmtIn) {}
473
474
// ---------------------------------------------------------------------------
475
476
NS_PROJ_END