forked from openslide/openslide
-
Notifications
You must be signed in to change notification settings - Fork 4
/
openslide-decode-sqlite.c
138 lines (118 loc) · 4.12 KB
/
openslide-decode-sqlite.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
* OpenSlide, a library for reading whole slide image files
*
* Copyright (c) 2013 Carnegie Mellon University
* Copyright (c) 2022 Benjamin Gilbert
* All rights reserved.
*
* OpenSlide is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, version 2.1.
*
* OpenSlide is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with OpenSlide. If not, see
* <https://www.gnu.org/licenses/>.
*
*/
#include <string.h>
#include "openslide-decode-sqlite.h"
#include "openslide-private.h"
#define BUSY_TIMEOUT 500 // ms
/* Can only use API supported in SQLite 3.26.0 for RHEL 8 compatibility */
typedef char sqlite_char;
G_DEFINE_AUTOPTR_CLEANUP_FUNC(sqlite_char, sqlite3_free)
static int profile_callback(unsigned trace_type G_GNUC_UNUSED,
void *ctx G_GNUC_UNUSED,
void *stmt,
void *ns) {
sqlite3_stmt *stmtp = stmt;
sqlite3_int64 *nsp = ns;
uint64_t ms = *nsp / 1e6;
g_autoptr(sqlite_char) sql = sqlite3_expanded_sql(stmtp);
g_debug("%s --> %"PRIu64" ms", sql, ms);
return 0;
}
static sqlite3 *do_open(const char *filename, int flags, GError **err) {
sqlite3 *db;
int ret = sqlite3_initialize();
if (ret) {
g_set_error(err, OPENSLIDE_ERROR, OPENSLIDE_ERROR_FAILED,
"Couldn't initialize SQLite: %d", ret);
return NULL;
}
ret = sqlite3_open_v2(filename, &db, flags, NULL); // ci-allow
if (ret) {
if (db) {
_openslide_sqlite_propagate_error(db, err);
} else {
g_set_error(err, OPENSLIDE_ERROR, OPENSLIDE_ERROR_FAILED,
"Couldn't open %s: %d", filename, ret);
}
_openslide_sqlite_close(db);
return NULL;
}
sqlite3_busy_timeout(db, BUSY_TIMEOUT);
if (_openslide_debug(OPENSLIDE_DEBUG_SQL)) {
sqlite3_trace_v2(db, SQLITE_TRACE_PROFILE, profile_callback, NULL);
}
return db;
}
sqlite3 *_openslide_sqlite_open(const char *filename, GError **err) {
// ":" filename prefix is reserved.
// "file:" prefix invokes URI filename interpretation if enabled, which
// might have been done globally.
g_autofree char *path = NULL;
if (g_str_has_prefix(filename, ":") || g_str_has_prefix(filename, "file:")) {
path = g_strdup_printf("./%s", filename);
} else {
path = g_strdup(filename);
}
sqlite3 *db = do_open(path, SQLITE_OPEN_READONLY, err);
return db;
}
sqlite3_stmt *_openslide_sqlite_prepare(sqlite3 *db, const char *sql,
GError **err) {
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(db, sql, strlen(sql) + 1, &stmt, NULL)) {
_openslide_sqlite_propagate_error(db, err);
}
return stmt;
}
bool _openslide_sqlite_step(sqlite3_stmt *stmt, GError **err) {
switch (sqlite3_step(stmt)) {
case SQLITE_ROW:
return true;
case SQLITE_DONE:
g_set_error(err, OPENSLIDE_ERROR, OPENSLIDE_ERROR_NO_VALUE,
"Query returned no value: %s", sqlite3_sql(stmt));
return false;
default:
_openslide_sqlite_propagate_stmt_error(stmt, err);
return false;
}
}
// wrapper that returns void for g_autoptr
void _openslide_sqlite_finalize(sqlite3_stmt *stmt) {
sqlite3_finalize(stmt);
}
// only legal if an error occurred
void _openslide_sqlite_propagate_error(sqlite3 *db, GError **err) {
g_set_error(err, OPENSLIDE_ERROR, OPENSLIDE_ERROR_FAILED,
"SQLite error: %s", sqlite3_errmsg(db));
}
// only legal if an error occurred
void _openslide_sqlite_propagate_stmt_error(sqlite3_stmt *stmt, GError **err) {
_openslide_sqlite_propagate_error(sqlite3_db_handle(stmt), err);
}
void _openslide_sqlite_close(sqlite3 *db) {
// sqlite3_close failures indicate a leaked resource, probably a
// prepared statement.
if (sqlite3_close(db)) { // ci-allow
g_warning("SQLite error: %s", sqlite3_errmsg(db));
}
}