Skip to content

Commit 304e391

Browse files
committed
simplify SQLite version check
1 parent a37c605 commit 304e391

3 files changed

Lines changed: 69 additions & 27 deletions

File tree

bindings/python/genomicsqlite.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ def _execute1(conn, sql, params=None):
2525
return next(conn.execute(sql, params) if params else conn.execute(sql))[0]
2626

2727

28-
# check SQLite version
29-
__version__ = _execute1(_MEMCONN, "SELECT genomicsqlite_version_check()")
3028
# load default configuration
3129
_DEFAULT_CONFIG = json.loads(_execute1(_MEMCONN, "SELECT genomicsqlite_default_config_json()"))
3230

@@ -197,7 +195,7 @@ def _cli():
197195
"-cmd",
198196
".databases",
199197
"-cmd",
200-
'SELECT "GenomicSQLite " || genomicsqlite_version_check()',
198+
'SELECT "GenomicSQLite " || genomicsqlite_version()',
201199
"-cmd",
202200
'.prompt "GenomicSQLite> "',
203201
]

include/genomicsqlite.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ extern "C" {
1818
#endif
1919

2020
/*
21-
* Return the GenomicSQLite version. Also checks the SQLite version, failing if it's incompatible.
21+
* Return the GenomicSQLite version.
2222
*/
23-
char *genomicsqlite_version_check();
23+
char *genomicsqlite_version();
2424

2525
/*
2626
* Get configuration defaults.
@@ -31,7 +31,8 @@ char *genomicsqlite_default_config_json();
3131
* Wrap sqlite3_open() and initialize the "connection" for use with GenomicSQLite. config_json if
3232
* supplied, will be merged into defaults (i.e. it's not necessary to include defaults)
3333
*/
34-
int genomicsqlite_open(const char *dbfile, sqlite3 **ppDb, int flags, const char *config_json);
34+
int genomicsqlite_open(const char *dbfile, sqlite3 **ppDb, char **pzErrMsg, int flags,
35+
const char *config_json);
3536

3637
/*
3738
* Generate SQL script to run on existing SQLite database (not necessarily GenomicSQLite) to cause
@@ -87,11 +88,11 @@ char *put_genomic_reference_sequence_sql(const char *name, sqlite3_int64 length,
8788
#include <map>
8889
#include <string>
8990

90-
std::string GenomicSQLiteVersionCheck();
91+
std::string GenomicSQLiteVersion();
9192
std::string GenomicSQLiteDefaultConfigJSON();
9293

93-
int GenomicSQLiteOpen(const std::string &dbfile, sqlite3 **ppDb, int flags,
94-
const std::string &config_json = "{}") noexcept;
94+
int GenomicSQLiteOpen(const std::string &dbfile, sqlite3 **ppDb, std::string &errmsg_out,
95+
int flags = 0, const std::string &config_json = "{}") noexcept;
9596
#ifdef SQLITECPP_VERSION
9697
/*
9798
* For use with SQLiteCpp -- https://github.com/SRombauts/SQLiteCpp

src/genomicsqlite.cc

Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ using namespace std;
2222
* connection & tuning helpers
2323
**************************************************************************************************/
2424

25-
std::string GenomicSQLiteVersionCheck() {
25+
std::string GenomicSQLiteVersion() {
2626
// The newest SQLite feature currently required is "Generated Columns"
2727
const int MIN_SQLITE_VERSION_NUMBER = 3031000;
2828
const string MIN_SQLITE_VERSION = "3.31.0";
@@ -50,7 +50,7 @@ std::string GenomicSQLiteVersionCheck() {
5050
} \
5151
return copy;
5252

53-
extern "C" char *genomicsqlite_version_check() { C_WRAPPER(GenomicSQLiteVersionCheck()) }
53+
extern "C" char *genomicsqlite_version() { C_WRAPPER(GenomicSQLiteVersion()) }
5454

5555
#define SQL_WRAPPER(invocation) \
5656
try { \
@@ -62,8 +62,8 @@ extern "C" char *genomicsqlite_version_check() { C_WRAPPER(GenomicSQLiteVersionC
6262
sqlite3_result_error(ctx, exn.what(), -1); \
6363
}
6464

65-
static void sqlfn_genomicsqlite_version_check(sqlite3_context *ctx, int argc, sqlite3_value **argv){
66-
SQL_WRAPPER(GenomicSQLiteVersionCheck())}
65+
static void sqlfn_genomicsqlite_version(sqlite3_context *ctx, int argc,
66+
sqlite3_value **argv){SQL_WRAPPER(GenomicSQLiteVersion())}
6767

6868
std::string GenomicSQLiteDefaultConfigJSON() {
6969
return R"({
@@ -79,7 +79,7 @@ std::string GenomicSQLiteDefaultConfigJSON() {
7979
static unique_ptr<SQLite::Statement> ConfigExtractor(SQLite::Database &tmpdb,
8080
const string &config_json) {
8181
string merged_json = GenomicSQLiteDefaultConfigJSON();
82-
if (!config_json.empty()) {
82+
if (config_json.size() > 2) { // "{}"
8383
SQLite::Statement patch(tmpdb, "SELECT json_patch(?,?)");
8484
patch.bind(1, merged_json);
8585
patch.bind(2, config_json);
@@ -266,31 +266,38 @@ static void sqlfn_genomicsqlite_tuning_sql(sqlite3_context *ctx, int argc, sqlit
266266
}
267267

268268
bool _ext_loaded = false;
269-
int GenomicSQLiteOpen(const string &dbfile, sqlite3 **ppDb, int flags,
269+
int GenomicSQLiteOpen(const string &dbfile, sqlite3 **ppDb, string &errmsg_out, int flags,
270270
const string &config_json) noexcept {
271271
// ensure extension is registered
272272
int ret;
273+
char *zErrmsg = nullptr;
273274
*ppDb = nullptr;
274275
if (!_ext_loaded) {
275276
ret =
276277
sqlite3_open_v2(":memory:", ppDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr);
277278
if (ret != SQLITE_OK) {
279+
errmsg_out = sqlite3_errstr(ret);
278280
return ret;
279281
}
280-
ret = sqlite3_load_extension(*ppDb, "libgenomicsqlite", nullptr, nullptr);
282+
ret = sqlite3_load_extension(*ppDb, "libgenomicsqlite", nullptr, &zErrmsg);
281283
if (ret != SQLITE_OK) {
284+
errmsg_out = "failed loading libgenomicsqlite shared library: ";
285+
if (zErrmsg) {
286+
errmsg_out += zErrmsg;
287+
sqlite3_free(zErrmsg);
288+
} else {
289+
errmsg_out += sqlite3_errmsg(*ppDb);
290+
}
291+
sqlite3_close_v2(*ppDb);
292+
*ppDb = nullptr;
282293
return ret;
283294
}
284295
ret = sqlite3_close_v2(*ppDb);
285296
*ppDb = nullptr;
286297
if (ret != SQLITE_OK) {
298+
errmsg_out = sqlite3_errstr(ret);
287299
return ret;
288300
}
289-
try {
290-
GenomicSQLiteVersionCheck();
291-
} catch (std::exception &exn) {
292-
return SQLITE_RANGE;
293-
}
294301
_ext_loaded = true;
295302
}
296303

@@ -299,20 +306,40 @@ int GenomicSQLiteOpen(const string &dbfile, sqlite3 **ppDb, int flags,
299306
ret = sqlite3_open_v2(GenomicSQLiteURI(dbfile, config_json).c_str(), ppDb,
300307
SQLITE_OPEN_URI | flags, nullptr);
301308
if (ret != SQLITE_OK) {
309+
errmsg_out = sqlite3_errstr(ret);
310+
return ret;
311+
}
312+
ret = sqlite3_exec(*ppDb, GenomicSQLiteTuningSQL(config_json).c_str(), nullptr, nullptr,
313+
&zErrmsg);
314+
if (ret != SQLITE_OK) {
315+
if (zErrmsg) {
316+
errmsg_out = zErrmsg;
317+
sqlite3_free(zErrmsg);
318+
} else {
319+
errmsg_out = sqlite3_errmsg(*ppDb);
320+
}
321+
sqlite3_close_v2(*ppDb);
322+
*ppDb = nullptr;
302323
return ret;
303324
}
304-
return sqlite3_exec(*ppDb, GenomicSQLiteTuningSQL(config_json).c_str(), nullptr, nullptr,
305-
nullptr);
325+
return SQLITE_OK;
306326
} catch (SQLite::Exception &exn) {
307327
return exn.getErrorCode();
308328
} catch (std::exception &exn) {
309329
return SQLITE_ERROR;
310330
}
311331
}
312332

313-
extern "C" int genomicsqlite_open(const char *filename, sqlite3 **ppDb, int flags,
333+
extern "C" int genomicsqlite_open(const char *filename, sqlite3 **ppDb, char **pzErrMsg, int flags,
314334
const char *config_json) {
315-
return GenomicSQLiteOpen(string(filename), ppDb, flags, config_json ? config_json : "");
335+
string errmsg;
336+
int ret =
337+
GenomicSQLiteOpen(string(filename), ppDb, errmsg, flags, config_json ? config_json : "");
338+
if (ret && !errmsg.empty() && pzErrMsg) {
339+
*pzErrMsg = (char *)sqlite3_malloc(errmsg.size());
340+
strcpy(*pzErrMsg, errmsg.c_str());
341+
}
342+
return ret;
316343
}
317344

318345
unique_ptr<SQLite::Database> GenomicSQLiteOpen(const string &dbfile, int flags,
@@ -326,7 +353,6 @@ unique_ptr<SQLite::Database> GenomicSQLiteOpen(const string &dbfile, int flags,
326353
throw std::runtime_error("failed loading libgenomicsqlite shared library: " +
327354
string(exn.what()));
328355
}
329-
GenomicSQLiteVersionCheck();
330356
_ext_loaded = true;
331357
}
332358
db.reset(new SQLite::Database(GenomicSQLiteURI(dbfile, config_json), SQLITE_OPEN_URI | flags));
@@ -1037,7 +1063,7 @@ static int register_genomicsqlite_functions(sqlite3 *db, const char **pzErrMsg,
10371063
int flags;
10381064
} fntab[] = {{FPNM(genomic_range_bin), 2, SQLITE_DETERMINISTIC},
10391065
{FPNM(genomic_range_bin), 3, SQLITE_DETERMINISTIC},
1040-
{FPNM(genomicsqlite_version_check), 0, 0},
1066+
{FPNM(genomicsqlite_version), 0, 0},
10411067
{FPNM(genomicsqlite_default_config_json), 0, 0},
10421068
{FPNM(genomicsqlite_uri), 1, 0},
10431069
{FPNM(genomicsqlite_uri), 2, 0},
@@ -1081,6 +1107,23 @@ static int register_genomicsqlite_functions(sqlite3 *db, const char **pzErrMsg,
10811107
extern "C" int sqlite3_genomicsqlite_init(sqlite3 *db, char **pzErrMsg,
10821108
const sqlite3_api_routines *pApi) {
10831109
SQLITE_EXTENSION_INIT2(pApi);
1110+
1111+
// The newest SQLite feature currently required is "Generated Columns"
1112+
const int MIN_SQLITE_VERSION_NUMBER = 3031000;
1113+
const string MIN_SQLITE_VERSION = "3.31.0";
1114+
if (sqlite3_libversion_number() < MIN_SQLITE_VERSION_NUMBER) {
1115+
if (pzErrMsg) {
1116+
string version_msg = "SQLite library version " + string(sqlite3_libversion()) +
1117+
" is older than " + MIN_SQLITE_VERSION +
1118+
" which is required by Genomics Extension " GIT_REVISION;
1119+
*pzErrMsg = (char *)sqlite3_malloc(version_msg.size() + 1);
1120+
if (*pzErrMsg) {
1121+
strcpy(*pzErrMsg, version_msg.c_str());
1122+
}
1123+
}
1124+
return SQLITE_ERROR;
1125+
}
1126+
10841127
int rc = (new ZstdVFS())->Register("zstd");
10851128
if (rc != SQLITE_OK)
10861129
return rc;

0 commit comments

Comments
 (0)