@@ -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
6868std::string GenomicSQLiteDefaultConfigJSON () {
6969 return R"( {
@@ -79,7 +79,7 @@ std::string GenomicSQLiteDefaultConfigJSON() {
7979static 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
268268bool _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
318345unique_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,
10811107extern " 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